diff --git a/.gitattributes b/.gitattributes index b223c8ac5fb84..f0b1c67bd0fdd 100644 --- a/.gitattributes +++ b/.gitattributes @@ -9,3 +9,7 @@ src/etc/installer/gfx/* binary *.woff binary src/vendor/** -text Cargo.lock -merge linguist-generated=false + +# Older git versions try to fix line endings on images, this prevents it. +*.png binary +*.ico binary diff --git a/.gitmodules b/.gitmodules index c4763612dbf3c..b75e312dedf73 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,7 +1,3 @@ -[submodule "src/llvm"] - path = src/llvm - url = https://github.com/rust-lang/llvm.git - branch = master [submodule "src/rust-installer"] path = src/tools/rust-installer url = https://github.com/rust-lang/rust-installer.git @@ -28,7 +24,7 @@ url = https://github.com/rust-lang-nursery/rustfmt.git [submodule "src/tools/miri"] path = src/tools/miri - url = https://github.com/solson/miri.git + url = https://github.com/rust-lang/miri.git [submodule "src/doc/rust-by-example"] path = src/doc/rust-by-example url = https://github.com/rust-lang/rust-by-example.git @@ -38,20 +34,16 @@ [submodule "src/stdsimd"] path = src/stdsimd url = https://github.com/rust-lang-nursery/stdsimd.git -[submodule "src/tools/lld"] - path = src/tools/lld - url = https://github.com/rust-lang/lld.git -[submodule "src/tools/lldb"] - path = src/tools/lldb - url = https://github.com/rust-lang-nursery/lldb.git - branch = rust-release-80-v2 -[submodule "src/tools/clang"] - path = src/tools/clang - url = https://github.com/rust-lang-nursery/clang.git - branch = rust-release-80-v2 [submodule "src/doc/rustc-guide"] path = src/doc/rustc-guide url = https://github.com/rust-lang/rustc-guide.git [submodule "src/doc/edition-guide"] path = src/doc/edition-guide - url = https://github.com/rust-lang-nursery/edition-guide + url = https://github.com/rust-lang-nursery/edition-guide.git +[submodule "src/llvm-project"] + path = src/llvm-project + url = https://github.com/rust-lang/llvm-project.git + branch = rustc/8.0-2019-01-16 +[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 a928606b693e5..d265f45c5cafa 100644 --- a/.mailmap +++ b/.mailmap @@ -155,6 +155,7 @@ Matt Brubeck Matthew Auld Matthew McPherrin Matthijs Hofstra +Melody Horn Michael Williams Michael Woerister Mickaël Raybaud-Roig m-r-r diff --git a/.travis.yml b/.travis.yml index c4efa88460325..7985b6c0e191f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -168,7 +168,7 @@ matrix: if: branch = auto - env: IMAGE=i686-gnu-nopt if: branch = auto - - env: IMAGE=wasm32-unknown + - env: IMAGE=test-various if: branch = auto - env: IMAGE=x86_64-gnu if: branch = auto diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 65cdfe67b5b08..e785f03d7de2b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -19,9 +19,16 @@ hop on [#rust-internals][pound-rust-internals]. As a reminder, all contributors are expected to follow our [Code of Conduct][coc]. +The [rustc-guide] is your friend! It describes how the compiler works and how +to contribute to it in more detail than this document. + +If this is your first time contributing, the [walkthrough] chapter of the guide +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 [coc]: https://www.rust-lang.org/conduct.html +[walkthrough]: https://rust-lang.github.io/rustc-guide/walkthrough.html ## Feature Requests [feature-requests]: #feature-requests @@ -89,222 +96,14 @@ $ RUST_BACKTRACE=1 rustc ... ``` ## The Build System -[the-build-system]: #the-build-system - -Rust's build system allows you to bootstrap the compiler, run tests & -benchmarks, generate documentation, install a fresh build of Rust, and more. -It's your best friend when working on Rust, allowing you to compile & test -your contributions before submission. - -The build system lives in [the `src/bootstrap` directory][bootstrap] in the -project root. Our build system is itself written in Rust and is based on Cargo -to actually build all the compiler's crates. If you have questions on the build -system internals, try asking in [`#rust-internals`][pound-rust-internals]. - -[bootstrap]: https://github.com/rust-lang/rust/tree/master/src/bootstrap/ - -### Configuration -[configuration]: #configuration - -Before you can start building the compiler you need to configure the build for -your system. In most cases, that will just mean using the defaults provided -for Rust. - -To change configuration, you must copy the file `config.toml.example` -to `config.toml` in the directory from which you will be running the build, and -change the settings provided. - -There are large number of options provided in this config file that will alter the -configuration used in the build process. Some options to note: - -#### `[llvm]`: -- `assertions = true` = This enables LLVM assertions, which makes LLVM misuse cause an assertion failure instead of weird misbehavior. This also slows down the compiler's runtime by ~20%. -- `ccache = true` - Use ccache when building llvm - -#### `[build]`: -- `compiler-docs = true` - Build compiler documentation - -#### `[rust]`: -- `debuginfo = true` - Build a compiler with debuginfo. Makes building rustc slower, but then you can use a debugger to debug `rustc`. -- `debuginfo-lines = true` - An alternative to `debuginfo = true` that doesn't let you use a debugger, but doesn't make building rustc slower and still gives you line numbers in backtraces. -- `debuginfo-tools = true` - Build the extended tools with debuginfo. -- `debug-assertions = true` - Makes the log output of `debug!` work. -- `optimize = false` - Disable optimizations to speed up compilation of stage1 rust, but makes the stage1 compiler x100 slower. - -For more options, the `config.toml` file contains commented out defaults, with -descriptions of what each option will do. - -Note: Previously the `./configure` script was used to configure this -project. It can still be used, but it's recommended to use a `config.toml` -file. If you still have a `config.mk` file in your directory - from -`./configure` - you may need to delete it for `config.toml` to work. - -### Building -[building]: #building - -A default configuration requires around 3.5 GB of disk space, whereas building a debug configuration may require more than 30 GB. -Dependencies -- [build dependencies](README.md#building-from-source) -- `gdb` 6.2.0 minimum, 7.1 or later recommended for test builds +For info on how to configure and build the compiler, please see [this +chapter][rustcguidebuild] of the rustc-guide. This chapter contains info for +contributions to the compiler and the standard library. It also lists some +really useful commands to the build system (`./x.py`), which could save you a +lot of time. -The build system uses the `x.py` script to control the build process. This script -is used to build, test, and document various parts of the compiler. You can -execute it as: - -```sh -python x.py build -``` - -On some systems you can also use the shorter version: - -```sh -./x.py build -``` - -To learn more about the driver and top-level targets, you can execute: - -```sh -python x.py --help -``` - -The general format for the driver script is: - -```sh -python x.py [] -``` - -Some example commands are `build`, `test`, and `doc`. These will build, test, -and document the specified directory. The second argument, ``, is -optional and defaults to working over the entire compiler. If specified, -however, only that specific directory will be built. For example: - -```sh -# build the entire compiler -python x.py build - -# build all documentation -python x.py doc - -# run all test suites -python x.py test - -# build only the standard library -python x.py build src/libstd - -# test only one particular test suite -python x.py test src/test/rustdoc - -# build only the stage0 libcore library -python x.py build src/libcore --stage 0 -``` - -You can explore the build system through the various `--help` pages for each -subcommand. For example to learn more about a command you can run: - -``` -python x.py build --help -``` - -To learn about all possible rules you can execute, run: - -``` -python x.py build --help --verbose -``` - -Note: Previously `./configure` and `make` were used to build this project. -They are still available, but `x.py` is the recommended build system. - -### Useful commands -[useful-commands]: #useful-commands - -Some common invocations of `x.py` are: - -- `x.py build --help` - show the help message and explain the subcommand -- `x.py build src/libtest --stage 1` - build up to (and including) the first - stage. For most cases we don't need to build the stage2 compiler, so we can - save time by not building it. The stage1 compiler is a fully functioning - compiler and (probably) will be enough to determine if your change works as - expected. -- `x.py build src/rustc --stage 1` - This will build just rustc, without libstd. - This is the fastest way to recompile after you changed only rustc source code. - Note however that the resulting rustc binary won't have a stdlib to link - against by default. You can build libstd once with `x.py build src/libstd`, - but it is only guaranteed to work if recompiled, so if there are any issues - recompile it. -- `x.py test` - build the full compiler & run all tests (takes a while). This - is what gets run by the continuous integration system against your pull - request. You should run this before submitting to make sure your tests pass - & everything builds in the correct manner. -- `x.py test src/libstd --stage 1` - test the standard library without - recompiling stage 2. -- `x.py test src/test/run-pass --test-args TESTNAME` - Run a matching set of - tests. - - `TESTNAME` should be a substring of the tests to match against e.g. it could - be the fully qualified test name, or just a part of it. - `TESTNAME=collections::hash::map::test_map::test_capacity_not_less_than_len` - or `TESTNAME=test_capacity_not_less_than_len`. -- `x.py test src/test/run-pass --stage 1 --test-args ` - - Run a single rpass test with the stage1 compiler (this will be quicker than - running the command above as we only build the stage1 compiler, not the entire - thing). You can also leave off the directory argument to run all stage1 test - types. -- `x.py test src/libcore --stage 1` - Run stage1 tests in `libcore`. -- `x.py test src/tools/tidy` - Check that the source code is in compliance with - Rust's style guidelines. There is no official document describing Rust's full - guidelines as of yet, but basic rules like 4 spaces for indentation and no - more than 99 characters in a single line should be kept in mind when writing - code. - -### Using your local build -[using-local-build]: #using-local-build - -If you use Rustup to manage your rust install, it has a feature called ["custom -toolchains"][toolchain-link] that you can use to access your newly-built compiler -without having to install it to your system or user PATH. If you've run `python -x.py build`, then you can add your custom rustc to a new toolchain like this: - -[toolchain-link]: https://github.com/rust-lang-nursery/rustup.rs#working-with-custom-toolchains-and-local-builds - -``` -rustup toolchain link build//stage2 -``` - -Where `` is the build triple for the host (the triple of your -computer, by default), and `` is the name for your custom toolchain. (If you -added `--stage 1` to your build command, the compiler will be in the `stage1` -folder instead.) You'll only need to do this once - it will automatically point -to the latest build you've done. - -Once this is set up, you can use your custom toolchain just like any other. For -example, if you've named your toolchain `local`, running `cargo +local build` will -compile a project with your custom rustc, setting `rustup override set local` will -override the toolchain for your current directory, and `cargo +local doc` will use -your custom rustc and rustdoc to generate docs. (If you do this with a `--stage 1` -build, you'll need to build rustdoc specially, since it's not normally built in -stage 1. `python x.py build --stage 1 src/libstd src/tools/rustdoc` will build -rustdoc and libstd, which will allow rustdoc to be run with that toolchain.) - -### Out-of-tree builds -[out-of-tree-builds]: #out-of-tree-builds - -Rust's `x.py` script fully supports out-of-tree builds - it looks for -the Rust source code from the directory `x.py` was found in, but it -reads the `config.toml` configuration file from the directory it's -run in, and places all build artifacts within a subdirectory named `build`. - -This means that if you want to do an out-of-tree build, you can just do it: -``` -$ cd my/build/dir -$ cp ~/my-config.toml config.toml # Or fill in config.toml otherwise -$ path/to/rust/x.py build -... -$ # This will use the Rust source code in `path/to/rust`, but build -$ # artifacts will now be in ./build -``` - -It's absolutely fine to have multiple build directories with different -`config.toml` configurations using the same code. +[rustcguidebuild]: https://rust-lang.github.io/rustc-guide/how-to-build-and-run.html ## Pull Requests [pull-requests]: #pull-requests @@ -320,26 +119,13 @@ bring those changes into the source repository. Please make pull requests against the `master` branch. -Compiling all of `./x.py test` can take a while. When testing your pull request, -consider using one of the more specialized `./x.py` targets to cut down on the -amount of time you have to wait. You need to have built the compiler at least -once before running these will work, but that’s only one full build rather than -one each time. - - $ python x.py test --stage 1 - -is one such example, which builds just `rustc`, and then runs the tests. If -you’re adding something to the standard library, try - - $ python x.py test src/libstd --stage 1 - Please make sure your pull request is in compliance with Rust's style guidelines by running $ python x.py test src/tools/tidy Make this check before every pull request (and every new commit in a pull -request) ; you can add [git hooks](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks) +request); you can add [git hooks](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks) 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, @@ -375,10 +161,10 @@ it can be found [here][rctd]. Currently building Rust will also build the following external projects: -* [clippy](https://github.com/rust-lang-nursery/rust-clippy) -* [miri](https://github.com/solson/miri) -* [rustfmt](https://github.com/rust-lang-nursery/rustfmt) -* [rls](https://github.com/rust-lang-nursery/rls/) +* [clippy](https://github.com/rust-lang/rust-clippy) +* [miri](https://github.com/rust-lang/miri) +* [rustfmt](https://github.com/rust-lang/rustfmt) +* [rls](https://github.com/rust-lang/rls/) We allow breakage of these tools in the nightly channel. Maintainers of these projects will be notified of the breakages and should fix them as soon as @@ -405,9 +191,9 @@ before the PR is merged. Rust's build system builds a number of tools that make use of the internals of the compiler. This includes -[Clippy](https://github.com/rust-lang-nursery/rust-clippy), -[RLS](https://github.com/rust-lang-nursery/rls) and -[rustfmt](https://github.com/rust-lang-nursery/rustfmt). If these tools +[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 break because of your changes, you may run into a sort of "chicken and egg" problem. These tools rely on the latest compiler to be built so you can't update them to reflect your changes to the compiler until those changes are merged into @@ -467,10 +253,10 @@ to complete a few more steps which are outlined with their rationale below. *(This error may change in the future to include more information.)* ``` -error: failed to resolve patches for `https://github.com/rust-lang-nursery/rustfmt` +error: failed to resolve patches for `https://github.com/rust-lang/rustfmt` Caused by: - patch for `rustfmt-nightly` in `https://github.com/rust-lang-nursery/rustfmt` did not resolve to any crates + patch for `rustfmt-nightly` in `https://github.com/rust-lang/rustfmt` did not resolve to any crates failed to run: ~/rust/build/x86_64-unknown-linux-gnu/stage0/bin/cargo build --manifest-path ~/rust/src/bootstrap/Cargo.toml ``` @@ -532,6 +318,12 @@ to check small fixes. For example, `rustdoc src/doc/reference.md` will render reference to `doc/reference.html`. The CSS might be messed up, but you can verify that the HTML is right. +Additionally, contributions to the [rustc-guide] are always welcome. Contributions +can be made directly at [the +rust-lang/rustc-guide](https://github.com/rust-lang/rustc-guide) repo. The issue +tracker in that repo is also a great way to find things that need doing. There +are issues for beginners and advanced compiler devs alike! + ## Issue Triage [issue-triage]: #issue-triage @@ -627,7 +419,7 @@ For people new to Rust, and just starting to contribute, or even for more seasoned developers, some useful places to look for information are: -* The [rustc guide] contains information about how various parts of the compiler work +* The [rustc guide] contains information about how various parts of the compiler work and how to contribute to the compiler * [Rust Forge][rustforge] contains additional documentation, including write-ups of how to achieve common tasks * The [Rust Internals forum][rif], a place to ask questions and discuss Rust's internals diff --git a/COPYRIGHT b/COPYRIGHT index 6596c5a3d9aff..dc9abf84b8e5a 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -23,7 +23,7 @@ The Rust Project includes packages written by third parties. The following third party packages are included, and carry their own copyright notices and license terms: -* LLVM. Code for this package is found in src/llvm. +* LLVM. Code for this package is found in src/llvm-project. Copyright (c) 2003-2013 University of Illinois at Urbana-Champaign. All rights reserved. @@ -73,8 +73,8 @@ their own copyright notices and license terms: OTHER DEALINGS WITH THE SOFTWARE. * Additional libraries included in LLVM carry separate - BSD-compatible licenses. See src/llvm/LICENSE.txt for - details. + BSD-compatible licenses. See src/llvm-project/llvm/LICENSE.TXT + for details. * compiler-rt, in src/compiler-rt is dual licensed under LLVM's license and MIT: diff --git a/Cargo.lock b/Cargo.lock index d4593c1ad234b..b93eaade65d61 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,3 +1,5 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. [[package]] name = "adler32" version = "1.0.3" @@ -15,7 +17,7 @@ dependencies = [ name = "alloc" version = "0.0.0" dependencies = [ - "compiler_builtins 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.5 (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)", @@ -42,6 +44,11 @@ dependencies = [ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "arc-swap" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "arena" version = "0.0.0" @@ -50,24 +57,25 @@ dependencies = [ ] [[package]] -name = "arrayvec" -version = "0.4.7" +name = "argon2rs" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", + "scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "assert_cli" -version = "0.6.2" +name = "arrayref" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "arrayvec" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "colored 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "environment 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "failure_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", + "nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -98,7 +106,7 @@ 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.4 (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)", "rustc-std-workspace-core 1.0.0", ] @@ -126,6 +134,24 @@ name = "bitflags" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "blake2-rfc" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "block-buffer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "bootstrap" version = "0.0.0" @@ -170,9 +196,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "build_helper" version = "0.1.0" +[[package]] +name = "byte-tools" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "bytecount" -version = "0.4.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "packed_simd 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -183,6 +214,15 @@ name = "byteorder" version = "1.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "bytes" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "bytesize" version = "1.0.0" @@ -190,7 +230,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cargo" -version = "0.34.0" +version = "0.35.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)", @@ -198,13 +238,13 @@ dependencies = [ "bytesize 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "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.22.0", + "crates-io 0.23.0", "crossbeam-utils 0.6.2 (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)", "env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.3 (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)", @@ -215,7 +255,7 @@ dependencies = [ "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.4 (registry+https://github.com/rust-lang/crates.io-index)", - "im-rc 12.2.0 (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)", "lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -258,6 +298,18 @@ dependencies = [ "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "cargo_metadata" +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_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 = "cargotest2" version = "0.1.0" @@ -318,7 +370,7 @@ dependencies = [ name = "clippy" version = "0.0.212" dependencies = [ - "cargo_metadata 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "cargo_metadata 0.7.1 (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", @@ -342,7 +394,7 @@ name = "clippy_dev" version = "0.0.1" dependencies = [ "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", - "itertools 0.7.8 (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)", @@ -352,9 +404,9 @@ dependencies = [ name = "clippy_lints" version = "0.0.212" dependencies = [ - "cargo_metadata 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "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)", - "itertools 0.7.8 (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)", "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)", @@ -411,7 +463,7 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", @@ -459,6 +511,11 @@ dependencies = [ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "constant_time_eq" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "core" version = "0.0.0" @@ -482,10 +539,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "crates-io" -version = "0.22.0" +version = "0.23.0" dependencies = [ "curl 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.3 (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)", "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)", @@ -520,6 +577,18 @@ dependencies = [ "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "crossbeam-channel" +version = "0.3.4" +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)", +] + [[package]] name = "crossbeam-deque" version = "0.2.0" @@ -529,6 +598,15 @@ dependencies = [ "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "crossbeam-deque" +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)", +] + [[package]] name = "crossbeam-epoch" version = "0.3.1" @@ -556,6 +634,19 @@ dependencies = [ "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "crossbeam-epoch" +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)", + "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)", +] + [[package]] name = "crossbeam-utils" version = "0.2.2" @@ -654,6 +745,14 @@ name = "difference" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "digest" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "directories" version = "1.0.2" @@ -663,12 +762,22 @@ dependencies = [ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "dirs" +version = "1.0.4" +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)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "dlmalloc" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "compiler_builtins 0.1.4 (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)", "rustc-std-workspace-core 1.0.0", ] @@ -724,11 +833,6 @@ dependencies = [ "termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "environment" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "error-chain" version = "0.11.0" @@ -754,16 +858,16 @@ dependencies = [ [[package]] name = "failure" -version = "0.1.3" +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)", - "failure_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "failure_derive" -version = "0.1.3" +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)", @@ -772,6 +876,11 @@ dependencies = [ "synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "fake-simd" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "filetime" version = "0.2.4" @@ -826,7 +935,7 @@ name = "fortanix-sgx-abi" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "compiler_builtins 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-std-workspace-core 1.0.0", ] @@ -889,6 +998,14 @@ dependencies = [ "termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "generic-array" +version = "0.9.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 = "getopts" version = "0.2.17" @@ -955,6 +1072,22 @@ dependencies = [ "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +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)", + "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)", + "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 = "heck" version = "0.3.0" @@ -1032,7 +1165,7 @@ dependencies = [ [[package]] name = "im-rc" -version = "12.2.0" +version = "12.3.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)", @@ -1054,6 +1187,15 @@ dependencies = [ "xz2 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +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)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "is-match" version = "0.1.0" @@ -1067,6 +1209,14 @@ dependencies = [ "either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "itertools" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "itoa" version = "0.4.3" @@ -1099,7 +1249,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "jsonrpc-core" -version = "9.0.0" +version = "10.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1118,21 +1268,6 @@ dependencies = [ "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "languageserver-types" -version = "0.51.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)", - "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_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)", - "url_serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "lazy_static" version = "0.2.11" @@ -1232,6 +1367,31 @@ dependencies = [ "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "lsp-codec" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "lsp-types" +version = "0.55.4" +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_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)", + "url_serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "lzma-sys" version = "0.1.10" @@ -1306,6 +1466,34 @@ dependencies = [ "toml-query 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "mdbook" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ammonia 1.1.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)", + "env_logger 0.5.13 (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)", + "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)", + "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)", + "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)", +] + [[package]] name = "memchr" version = "2.1.1" @@ -1332,7 +1520,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "minifier" -version = "0.0.26" +version = "0.0.28" 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)", @@ -1366,6 +1554,56 @@ dependencies = [ "miniz_oxide 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "mio" +version = "0.6.16" +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)", + "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "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)", + "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)", + "slab 0.4.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 = "mio-named-pipes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "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)", + "miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "mio-uds" +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)", + "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "miow" +version = "0.2.1" +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)", + "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "miow" version = "0.3.3" @@ -1388,9 +1626,20 @@ dependencies = [ "log 0.4.6 (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)", "vergen 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +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)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "new_debug_unreachable" version = "1.0.1" @@ -1446,8 +1695,8 @@ name = "opener" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "failure_derive 0.1.3 (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)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1519,7 +1768,7 @@ dependencies = [ name = "panic_abort" version = "0.0.0" dependencies = [ - "compiler_builtins 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.5 (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)", ] @@ -1529,7 +1778,7 @@ name = "panic_unwind" version = "0.0.0" dependencies = [ "alloc 0.0.0", - "compiler_builtins 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.5 (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)", "unwind 0.0.0", @@ -1544,6 +1793,15 @@ dependencies = [ "parking_lot_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "parking_lot" +version = "0.7.1" +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.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "parking_lot_core" version = "0.3.0" @@ -1555,6 +1813,18 @@ dependencies = [ "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)", + "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)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "percent-encoding" version = "1.0.1" @@ -1565,6 +1835,14 @@ name = "pest" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "pest" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ucd-trie 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "pest_derive" version = "1.0.8" @@ -1575,6 +1853,37 @@ dependencies = [ "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "pest_derive" +version = "2.1.0" +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_generator 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "pest_generator" +version = "2.1.0" +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)", +] + +[[package]] +name = "pest_meta" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "maplit 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "pest 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "sha-1 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "petgraph" version = "0.4.13" @@ -1682,7 +1991,7 @@ 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.4 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", ] @@ -1754,7 +2063,7 @@ dependencies = [ [[package]] name = "racer" -version = "2.1.16" +version = "2.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1764,8 +2073,8 @@ dependencies = [ "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)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-syntax 306.0.0 (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]] @@ -1897,6 +2206,17 @@ dependencies = [ "redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "redox_users" +version = "0.2.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)", + "redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "regex" version = "0.2.11" @@ -1955,41 +2275,48 @@ dependencies = [ [[package]] name = "rls" -version = "1.31.6" +version = "1.34.0" dependencies = [ - "cargo 0.34.0", - "cargo_metadata 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "cargo 0.35.0", + "cargo_metadata 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "clippy_lints 0.0.212", - "crossbeam-channel 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-channel 0.3.4 (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.5.13 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.3 (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)", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "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.7.8 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-core 9.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "languageserver-types 0.51.1 (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)", "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)", "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.16 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "racer 2.1.19 (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.10 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-analysis 0.16.12 (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.1 (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.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)", "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.1", + "rustfmt-nightly 1.0.3", "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_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)", "tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "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)", "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)", @@ -1997,7 +2324,7 @@ dependencies = [ [[package]] name = "rls-analysis" -version = "0.16.10" +version = "0.16.12" 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)", @@ -2005,8 +2332,8 @@ 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.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-span 0.4.0 (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)", ] @@ -2017,10 +2344,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rls-data" -version = "0.18.1" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rls-span 0.4.0 (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)", "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)", @@ -2033,7 +2360,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rls-span" -version = "0.4.0" +version = "0.4.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)", @@ -2047,7 +2374,7 @@ version = "0.7.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.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-span 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2056,6 +2383,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)", ] [[package]] @@ -2073,6 +2401,7 @@ dependencies = [ "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)", "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)", "parking_lot 0.6.4 (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.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2092,20 +2421,20 @@ dependencies = [ [[package]] name = "rustc-ap-arena" -version = "306.0.0" +version = "373.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rustc-ap-rustc_data_structures 306.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)", ] [[package]] name = "rustc-ap-graphviz" -version = "306.0.0" +version = "373.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rustc-ap-rustc_cratesio_shim" -version = "306.0.0" +version = "373.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)", @@ -2115,16 +2444,16 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_data_structures" -version = "306.0.0" +version = "373.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)", "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 306.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-rustc_cratesio_shim 306.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-serialize 306.0.0 (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)", "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-rayon 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-rayon-core 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2134,34 +2463,34 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_errors" -version = "306.0.0" +version = "373.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "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 306.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-rustc_data_structures 306.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-serialize 306.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-syntax_pos 306.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-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)", "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_target" -version = "306.0.0" +version = "373.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 306.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-rustc_data_structures 306.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-serialize 306.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-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)", ] [[package]] name = "rustc-ap-serialize" -version = "306.0.0" +version = "373.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)", @@ -2169,29 +2498,29 @@ dependencies = [ [[package]] name = "rustc-ap-syntax" -version = "306.0.0" +version = "373.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_data_structures 306.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-rustc_errors 306.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-rustc_target 306.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-serialize 306.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-syntax_pos 306.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-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)", ] [[package]] name = "rustc-ap-syntax_pos" -version = "306.0.0" +version = "373.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 306.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-rustc_data_structures 306.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-serialize 306.0.0 (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)", "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2201,7 +2530,7 @@ name = "rustc-demangle" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "compiler_builtins 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-std-workspace-core 1.0.0", ] @@ -2301,7 +2630,7 @@ 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.4 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", ] @@ -2495,7 +2824,7 @@ 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.4 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", ] @@ -2522,7 +2851,6 @@ name = "rustc_mir" version = "0.0.0" dependencies = [ "arena 0.0.0", - "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)", "either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "graphviz 0.0.0", @@ -2547,7 +2875,7 @@ 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.4 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", ] @@ -2561,6 +2889,7 @@ dependencies = [ "rustc_errors 0.0.0", "rustc_mir 0.0.0", "syntax 0.0.0", + "syntax_ext 0.0.0", "syntax_pos 0.0.0", ] @@ -2579,6 +2908,7 @@ dependencies = [ name = "rustc_privacy" version = "0.0.0" dependencies = [ + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_data_structures 0.0.0", "rustc_typeck 0.0.0", @@ -2606,8 +2936,8 @@ 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.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-span 0.4.0 (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 0.0.0", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_codegen_utils 0.0.0", @@ -2661,7 +2991,7 @@ 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.4 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", ] @@ -2692,7 +3022,7 @@ dependencies = [ name = "rustdoc" version = "0.0.0" dependencies = [ - "minifier 0.0.26 (registry+https://github.com/rust-lang/crates.io-index)", + "minifier 0.0.28 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", "pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2714,7 +3044,7 @@ name = "rustfix" version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "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_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2723,24 +3053,24 @@ dependencies = [ [[package]] name = "rustfmt-nightly" -version = "1.0.1" +version = "1.0.3" dependencies = [ - "assert_cli 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "bytecount 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cargo_metadata 0.6.2 (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)", - "env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "dirs 1.0.4 (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)", - "itertools 0.7.8 (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)", "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 306.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-syntax 306.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-syntax_pos 306.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-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)", "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)", @@ -2748,6 +3078,8 @@ dependencies = [ "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)", "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]] @@ -2788,6 +3120,11 @@ name = "scoped-tls" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "scoped_threadpool" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "scopeguard" version = "0.3.3" @@ -2850,6 +3187,17 @@ dependencies = [ "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "sha-1" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "block-buffer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "digest 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", + "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "shell-escape" version = "0.1.4" @@ -2860,11 +3208,25 @@ name = "shlex" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "signal-hook" +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)", +] + [[package]] name = "siphasher" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "slab" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "smallvec" version = "0.6.7" @@ -2896,9 +3258,9 @@ 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.4 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", - "dlmalloc 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "dlmalloc 0.1.2 (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)", "panic_abort 0.0.0", @@ -3154,6 +3516,194 @@ dependencies = [ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "tokio" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +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)", + "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)", + "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-current-thread 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-fs 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-threadpool 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-timer 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-udp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-codec" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +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)", + "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-current-thread" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +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)", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-fs" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-threadpool 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-io" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +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)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-process" +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)", + "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)", + "tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-signal 0.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 = "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)", + "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)", + "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)", + "parking_lot 0.7.1 (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)", + "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-signal" +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)", + "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)", + "tokio-executor 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)", + "tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-tcp" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +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)", + "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +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-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)", + "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)", + "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +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)", + "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)", +] + +[[package]] +name = "tokio-udp" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +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)", + "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)", + "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-uds" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +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)", + "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)", + "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "toml" version = "0.4.10" @@ -3174,11 +3724,28 @@ dependencies = [ "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "toml-query" +version = "0.7.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)", + "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)", +] + [[package]] name = "typenum" version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "ucd-trie" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "ucd-util" version = "0.1.3" @@ -3217,6 +3784,11 @@ name = "unicode-xid" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "unicode_categories" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "unreachable" version = "1.0.0" @@ -3237,7 +3809,7 @@ dependencies = [ name = "unwind" version = "0.0.0" dependencies = [ - "compiler_builtins 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.5 (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)", ] @@ -3288,7 +3860,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3365,6 +3937,15 @@ dependencies = [ "winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ws2_32-sys" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "xattr" version = "0.2.2" @@ -3391,8 +3972,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "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 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 assert_cli 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "98589b0e465a6c510d95fceebd365bb79bedece7f6e18a480897f2015f85ec51" "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 backtrace-sys 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)" = "6ea90dd7b012b3d1a2cb6bec16670a0db2c95d4e931e84f4047e0460c1b34c8d" @@ -3400,12 +3983,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "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 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 bytecount 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b92204551573580e078dc80017f36a213eb77a0450e4ddd8cfa0f3f2d1f0178f" +"checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40" +"checksum bytecount 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "be0fdd54b507df8f22012890aadd099979befdba27713c767993f8380112ca7c" "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 chalk-engine 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17ec698a6f053a23bfbe646d9f2fde4b02abc19125595270a99e6f44ae0bdd1a" @@ -3417,16 +4005,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "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.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bd14d75a16b6c836c62350e2e8c85495ed8e13df30a7298c574cb1ee4cdac7bc" +"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 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.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7b85741761b7f160bc5e7e0c14986ef685b7f8bf9b7ad081c60c604bb4649827" +"checksum crossbeam-channel 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5b2a9ea8f77c7f9efd317a8a5645f515d903a2d86ee14d2337a5facd1bd52c12" "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.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9c90f1474584f38e270b5b613e898c8c328aa4f3dea85e0a27ac2e642f009416" +"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.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "677d453a17e8bd2b913fa38e8b9cf04bcdbb5be790aa294f2389661d72036015" "checksum crossbeam-utils 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e07fc155212827475223f0bcfae57e945e694fc90950ddf3f6695bbfd5555c72" @@ -3438,18 +4030,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "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 dlmalloc 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4c46c65de42b063004b31c67a98abe071089b289ff0919c660ed7ff4f59317f8" +"checksum dirs 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "88972de891f6118092b643d85a0b28e0678e0f948d7f879aa32f2d5aafe97d2a" +"checksum dlmalloc 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d56ad71b31043818d0ee10a7fb9664882f8e45849c81647585e6a3124f185517" "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 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 environment 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1f4b14e20978669064c33b4c1e0fb4083412e40fe56cbea2eae80fd7591503ee" "checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3" "checksum error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "07e791d3be96241c77c43846b665ef1384606da2cd2a48730abe606a12906e02" -"checksum failure 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6dd377bcc1b1b7ce911967e3ec24fa19c3224394ec05b54aa7b083d498341ac7" -"checksum failure_derive 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "64c2d913fe8ed3b6c6518eedf4538255b989945c14c2a7d5cbff62a5e2120596" +"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" +"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" +"checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" "checksum filetime 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a2df5c1a8c4be27e7707789dc42ae65976e60b394afd293d1419ab915833e646" "checksum fixedbitset 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "86d4de0081402f5e88cdac65c8dcdcc73118c1a7a465e2a05f0da05843a8ea33" "checksum flate2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2291c165c8e703ee54ef3055ad6188e3d51108e2ded18e9f2476e774fc5ad3d4" @@ -3465,12 +4059,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "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 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 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" @@ -3479,16 +4075,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "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.4 (registry+https://github.com/rust-lang/crates.io-index)" = "36ecfc5ad80f0b1226df948c562e2cddd446096be3f644c95106400eae8a5e01" -"checksum im-rc 12.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d4591152fd573cf453a890b5f9fdc5c328a751a0785539316739d5f85e5c468c" +"checksum im-rc 12.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9460397452f537fd51808056ff209f4c4c4c9d20d42ae952f517708726284972" +"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 json 0.11.13 (registry+https://github.com/rust-lang/crates.io-index)" = "9ad0485404155f45cce53a40d4b2d6ac356418300daed05273d9e26f91c390be" -"checksum jsonrpc-core 9.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4e9cbeda300803d381390fb65e8158437728c39e6987ed23bee82728b73511a7" +"checksum jsonrpc-core 10.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a5152c3fda235dfd68341b3edf4121bc4428642c93acbd6de88c26bf95fc5d7" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -"checksum languageserver-types 0.51.1 (registry+https://github.com/rust-lang/crates.io-index)" = "68de833188ada4e175d04a028f03f244f6370eedbcc75a05604d47d925933f69" "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 lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f" @@ -3500,6 +4097,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "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 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" @@ -3507,14 +4106,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum markup5ever 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfedc97d5a503e96816d10fedcd5b42f760b2e525ce2f7ec71f6a41780548475" "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 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.26 (registry+https://github.com/rust-lang/crates.io-index)" = "f299df45afd73332044ea9f717c816a84fc90c8b631409abf339ba93642a7985" +"checksum minifier 0.0.28 (registry+https://github.com/rust-lang/crates.io-index)" = "3a2898502751dcc9d66b6fff57f3cf63cc91605e83e1a33515396f5027f8e4ca" "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" +"checksum mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)" = "71646331f2619b1026cc302f87a2b8b648d5c6dd6937846a16cc8ce0f347f432" +"checksum mio-named-pipes 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f5e374eff525ce1c5b7687c4cef63943e7686524a387933ad27ca7ec43779cb3" +"checksum mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "966257a94e196b11bb43aca423754d87429960a768de9414f3691d6957abf125" +"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 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" @@ -3532,10 +4137,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "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" +"checksum pest 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "54f0c72a98d8ab3c99560bfd16df8059cc10e1f9a8e83e6e3b97718dd766e9c3" "checksum pest_derive 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3294f437119209b084c797604295f40227cffa35c57220b1e99a6ff3bf8ee4" +"checksum pest_derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "833d1ae558dc601e9a60366421196a8d94bc0ac980476d0b67e1d0988d72b2d0" +"checksum pest_generator 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "63120576c4efd69615b5537d3d052257328a4ca82876771d6944424ccfd9f646" +"checksum pest_meta 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f5a3492a4ed208ffc247adcdcc7ba2a95be3104f58877d0d02f0df39bf3efb5e" "checksum petgraph 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3659d1ee90221741f65dd128d9998311b0e40c5d3c23a62445938214abce4f" "checksum phf 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)" = "7d37a244c75a9748e049225155f56dbcb98fe71b192fd25fd23cb914b5ad62f2" "checksum phf_codegen 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)" = "4e4048fe7dd7a06b8127ecd6d3803149126e9b33c7558879846da3a63f734f2b" @@ -3556,7 +4167,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" "checksum quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9949cfe66888ffe1d53e6ec9d9f3b70714083854be20fd5e271b232a017401e8" "checksum quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "53fa22a1994bd0f9372d7a816207d8a2677ad0325b073f5c5332760f0fb62b5c" -"checksum racer 2.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "fbfcf2686b50f75a279cb42d9c6d253a1e68a475b415ea4baf7fb177ce94839a" +"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 rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ae9d223d52ae411a33cf7e54ec6034ec165df296ccd23533d671a28252b6f66a" @@ -3571,26 +4182,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rayon-core 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9d24ad214285a7729b174ed6d3bcfcb80177807f959d95fafd5bfc5c4f201ac8" "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 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-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 remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" -"checksum rls-analysis 0.16.10 (registry+https://github.com/rust-lang/crates.io-index)" = "2de1187cceaf16d7642cc78835a2890b55b35ed9e8a8e3c6348a6297d8dd0fb1" +"checksum rls-analysis 0.16.12 (registry+https://github.com/rust-lang/crates.io-index)" = "ae18d8ad01dec3b2014f4d7ae3c607d7adbcff79e5d3b48ea42ea71c10d43a71" "checksum rls-blacklist 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b8ce1fdac03e138c4617ff87b194e1ff57a39bb985a044ccbd8673d30701e411" -"checksum rls-data 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a209ce46bb52813cbe0786a7baadc0c1a3f5543ef93f179eda3b841ed72cf2e" +"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.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d7c7046dc6a92f2ae02ed302746db4382e75131b9ce20ce967259f6b5867a6a" +"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 306.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cbfb540c1347a3993060896b18e0d64084203fa37aaffdc5e5c31264f275d476" -"checksum rustc-ap-graphviz 306.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "790ac657d5bf69be9ef56f6810e8a0238b07e8460a88526e11d41f8214eb6c4e" -"checksum rustc-ap-rustc_cratesio_shim 306.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b721cf32b543f3ee90240d7b757ca4a45930fe9981458a50678b4ccd75c472e2" -"checksum rustc-ap-rustc_data_structures 306.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4fa11df199d45ce948b07792ca593f59c1d19d2cb05d35c6b0a02271e772a416" -"checksum rustc-ap-rustc_errors 306.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b7ead3163ef995bbba520b88739e1d60f9ccf74fdacdda985067644c8134e827" -"checksum rustc-ap-rustc_target 306.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "688fef9cc27837755019b72b4f13e7a3d3e5012473475f377b75dbb1f07beb5f" -"checksum rustc-ap-serialize 306.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b2c0e8161e956647592a737074736e6ce05ea36b70c770ea8cca3eb9cb33737" -"checksum rustc-ap-syntax 306.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1adc189e5e4500a4167b9afa04e67067f40d0039e0e05870c977bebb561f065a" -"checksum rustc-ap-syntax_pos 306.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4d42c430dbb0be4377bfe6aa5099074c63ac8796b24098562c2e2154aecc5652" +"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 rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7540fc8b0c49f096ee9c961cda096467dce8084bec6bdca2fc83895fd9b28cb8" "checksum rustc-rayon 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c6d5a683c6ba4ed37959097e88d71c9e8e26659a3cb5be8b389078e7ad45306" @@ -3604,6 +4216,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "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_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" @@ -3611,9 +4224,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "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" +"checksum sha-1 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "51b9d1f3b5de8a167ab06834a7c883bd197f2191e1dda1a22d9ccfeedbf9aded" "checksum shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "170a13e64f2a51b77a45702ba77287f5c6829375b04a69cf2222acd17d0cfab9" "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 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 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" @@ -3636,9 +4252,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "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" +"checksum tokio 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "4790d0be6f4ba6ae4f48190efa2ed7780c9e3567796abdb285003cf39840d9c5" +"checksum tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5c501eceaf96f0e1793cf26beb63da3d11c738c4a943fdf3746d81d64684c39f" +"checksum tokio-current-thread 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "331c8acc267855ec06eb0c94618dcbbfea45bed2d20b77252940095273fb58f6" +"checksum tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "30c6dbf2d1ad1de300b393910e8a3aa272b724a400b6531da03eed99e329fbf0" +"checksum tokio-fs 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0e9cbbc8a3698b7ab652340f46633364f9eaa928ddaaee79d8b8f356dd79a09d" +"checksum tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b53aeb9d3f5ccf2ebb29e19788f96987fa1355f8fe45ea193928eaaaf3ae820f" +"checksum tokio-process 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "88e1281e412013f1ff5787def044a9577a0bed059f451e835f1643201f8b777d" +"checksum tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "afbcdb0f0d2a1e4c440af82d7bbf0bf91a8a8c0575bcd20c05d15be7e9d3a02f" +"checksum tokio-signal 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "dd6dc5276ea05ce379a16de90083ec80836440d5ef8a6a39545a3207373b8296" +"checksum tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1d14b10654be682ac43efee27401d792507e30fd8d26389e1da3b185de2e4119" +"checksum tokio-threadpool 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "17465013014410310f9f61fa10bf4724803c149ea1d51efece131c38efca93aa" +"checksum tokio-timer 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "4f37f0111d76cc5da132fe9bc0590b9b9cfd079bc7e75ac3846278430a299ff8" +"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-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 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 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" @@ -3646,6 +4278,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" "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" @@ -3665,6 +4298,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "afc5508759c5bf4285e61feb862b6083c8480aec864fa17a81fdec6f69b461ab" "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" "checksum xattr 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "244c3741f4240ef46274860397c7c74e50eb23624996930e484c16679633a54c" "checksum xz2 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "df8bf41d3030c3577c9458fd6640a05afbf43b150d0b531b16bd77d3f794f27a" "checksum yaml-rust 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e66366e18dc58b46801afbf2ca7661a9f59cc8c5962c29892b6039b4f86fa992" diff --git a/README.md b/README.md index cb1f06257ed15..514e420ca457c 100644 --- a/README.md +++ b/README.md @@ -13,9 +13,13 @@ Read ["Installation"] from [The Book]. ["Installation"]: https://doc.rust-lang.org/book/ch01-01-installation.html [The Book]: https://doc.rust-lang.org/book/index.html -## Building from Source +## Installing from Source [building-from-source]: #building-from-source +_Note: If you wish to contribute to the compiler, you should read +[this chapter](https://rust-lang.github.io/rustc-guide/how-to-build-and-run.html) +of the rustc-guide instead._ + ### Building on *nix 1. Make sure you have installed the dependencies: diff --git a/appveyor.yml b/appveyor.yml index f043b8bfefca7..3a0cb8b4fceea 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -5,10 +5,9 @@ environment: # server goes down presumably. See #43333 for more info CARGO_HTTP_CHECK_REVOKE: false - # Recommended by AppVeyor this moves our builds to GCE which incurs a 3-4 - # minute startup overhead, but that's paltry compared to our overall build - # times so we're will to eat the cost. This is intended to give us better - # performance I believe! + # 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: diff --git a/config.toml.example b/config.toml.example index 23943d34b7ca8..f45db37c33b86 100644 --- a/config.toml.example +++ b/config.toml.example @@ -90,12 +90,21 @@ # with clang-cl, so this is special in that it only compiles LLVM with clang-cl #clang-cl = '/path/to/clang-cl.exe' +# Pass extra compiler and linker flags to the LLVM CMake build. +#cflags = "-fextra-flag" +#cxxflags = "-fextra-flag" +#ldflags = "-Wl,extra-flag" + # Use libc++ when building LLVM instead of libstdc++. This is the default on # platforms already use libc++ as the default C++ library, but this option # allows you to use libc++ even on platforms when it's not. You need to ensure # that your host compiler ships with libc++. #use-libcxx = true +# The value specified here will be passed as `-DLLVM_USE_LINKER` to CMake. +#use-linker = "lld" + + # ============================================================================= # General build configuration options # ============================================================================= @@ -312,8 +321,8 @@ # Whether to always use incremental compilation when building rustc #incremental = false -# Build rustc with experimental parallelization -#experimental-parallel-queries = false +# Build a multi-threaded rustc +#parallel-compiler = false # The default linker that will be hard-coded into the generated compiler for # targets that don't specify linker explicitly in their target specifications. diff --git a/src/README.md b/src/README.md index 65228915866ea..14e773286bc6a 100644 --- a/src/README.md +++ b/src/README.md @@ -8,7 +8,6 @@ For more information on how various parts of the compiler work, see the [rustc g There is also useful content in the following READMEs, which are gradually being moved over to the guide: - https://github.com/rust-lang/rust/tree/master/src/librustc/ty/query - https://github.com/rust-lang/rust/tree/master/src/librustc/dep_graph -- https://github.com/rust-lang/rust/blob/master/src/librustc/infer/region_constraints - https://github.com/rust-lang/rust/tree/master/src/librustc/infer/higher_ranked - https://github.com/rust-lang/rust/tree/master/src/librustc/infer/lexical_region_resolve diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index a0c75cd9e9476..7a765973e20f8 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -284,8 +284,8 @@ fn main() { } } - if env::var_os("RUSTC_PARALLEL_QUERIES").is_some() { - cmd.arg("--cfg").arg("parallel_queries"); + if env::var_os("RUSTC_PARALLEL_COMPILER").is_some() { + cmd.arg("--cfg").arg("parallel_compiler"); } if env::var_os("RUSTC_DENY_WARNINGS").is_some() && env::var_os("RUSTC_EXTERNAL_TOOL").is_none() diff --git a/src/bootstrap/bin/rustdoc.rs b/src/bootstrap/bin/rustdoc.rs index dec74e60c71f3..aeb15821b0bb7 100644 --- a/src/bootstrap/bin/rustdoc.rs +++ b/src/bootstrap/bin/rustdoc.rs @@ -16,6 +16,7 @@ fn main() { let libdir = env::var_os("RUSTDOC_LIBDIR").expect("RUSTDOC_LIBDIR was not set"); let stage = env::var("RUSTC_STAGE").expect("RUSTC_STAGE was not set"); let sysroot = env::var_os("RUSTC_SYSROOT").expect("RUSTC_SYSROOT was not set"); + let mut has_unstable = false; use std::str::FromStr; @@ -54,9 +55,22 @@ fn main() { // it up so we can make rustdoc print this into the docs if let Some(version) = env::var_os("RUSTDOC_CRATE_VERSION") { // This "unstable-options" can be removed when `--crate-version` is stabilized - cmd.arg("-Z") - .arg("unstable-options") - .arg("--crate-version").arg(version); + if !has_unstable { + cmd.arg("-Z") + .arg("unstable-options"); + } + cmd.arg("--crate-version").arg(version); + has_unstable = true; + } + + // Needed to be able to run all rustdoc tests. + if let Some(_) = env::var_os("RUSTDOC_GENERATE_REDIRECT_PAGES") { + // This "unstable-options" can be removed when `--generate-redirect-pages` is stabilized + if !has_unstable { + cmd.arg("-Z") + .arg("unstable-options"); + } + cmd.arg("--generate-redirect-pages"); } if verbose > 1 { diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index f3dbae6909a4d..119b38bcc99dc 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -230,6 +230,9 @@ def default_build_triple(): err = "unknown OS type: {}".format(ostype) sys.exit(err) + if cputype == 'powerpc' and ostype == 'unknown-freebsd': + cputype = subprocess.check_output( + ['uname', '-p']).strip().decode(default_encoding) cputype_mapper = { 'BePC': 'i686', 'aarch64': 'aarch64', @@ -698,21 +701,13 @@ def update_submodules(self): filtered_submodules = [] submodules_names = [] for module in submodules: - if module.endswith("llvm"): - if self.get_toml('llvm-config'): + if module.endswith("llvm-project"): + if self.get_toml('llvm-config') and self.get_toml('lld') != 'true': continue if module.endswith("llvm-emscripten"): backends = self.get_toml('codegen-backends') if backends is None or not 'emscripten' in backends: continue - if module.endswith("lld"): - config = self.get_toml('lld') - if config is None or config == 'false': - continue - if module.endswith("lldb") or module.endswith("clang"): - config = self.get_toml('lldb') - if config is None or config == 'false': - continue check = self.check_submodule(module, slow_submodules) filtered_submodules.append((module, check)) submodules_names.append(module) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 9c58f5b179fd8..9d037dad9ccbd 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -21,7 +21,7 @@ use crate::install; use crate::native; use crate::test; use crate::tool; -use crate::util::{add_lib_path, exe, libdir}; +use crate::util::{self, add_lib_path, exe, libdir}; use crate::{Build, DocTests, Mode, GitRepo}; pub use crate::Compiler; @@ -60,17 +60,17 @@ pub trait Step: 'static + Clone + Debug + PartialEq + Eq + Hash { /// Run this rule for all hosts without cross compiling. const ONLY_HOSTS: bool = false; - /// Primary function to execute this rule. Can call `builder.ensure(...)` + /// Primary function to execute this rule. Can call `builder.ensure()` /// with other steps to run those. fn run(self, builder: &Builder) -> Self::Output; /// When bootstrap is passed a set of paths, this controls whether this rule /// will execute. However, it does not get called in a "default" context - /// when we are not passed any paths; in that case, make_run is called + /// when we are not passed any paths; in that case, `make_run` is called /// directly. fn should_run(run: ShouldRun) -> ShouldRun; - /// Build up a "root" rule, either as a default rule or from a path passed + /// Builds up a "root" rule, either as a default rule or from a path passed /// to us. /// /// When path is `None`, we are executing in a context where no paths were @@ -378,14 +378,11 @@ impl<'a> Builder<'a> { test::Debuginfo, test::UiFullDeps, test::RunPassFullDeps, - test::RunFailFullDeps, test::Rustdoc, test::Pretty, test::RunPassPretty, test::RunFailPretty, test::RunPassValgrindPretty, - test::RunPassFullDepsPretty, - test::RunFailFullDepsPretty, test::Crate, test::CrateLibrustc, test::CrateRustdoc, @@ -403,6 +400,7 @@ impl<'a> Builder<'a> { test::TheBook, test::UnstableBook, test::RustcBook, + test::EmbeddedBook, test::Rustfmt, test::Miri, test::Clippy, @@ -433,6 +431,7 @@ impl<'a> Builder<'a> { doc::RustByExample, doc::RustcBook, doc::CargoBook, + doc::EmbeddedBook, doc::EditionGuide, ), Kind::Dist => describe!( @@ -649,7 +648,7 @@ impl<'a> Builder<'a> { add_lib_path(vec![self.rustc_libdir(compiler)], cmd); } - /// Get a path to the compiler specified. + /// Gets a path to the compiler specified. pub fn rustc(&self, compiler: Compiler) -> PathBuf { if compiler.is_snapshot(self) { self.initial_rustc.clone() @@ -660,6 +659,15 @@ impl<'a> Builder<'a> { } } + /// Gets the paths to all of the compiler's codegen backends. + fn codegen_backends(&self, compiler: Compiler) -> impl Iterator { + fs::read_dir(self.sysroot_codegen_backends(compiler)) + .into_iter() + .flatten() + .filter_map(Result::ok) + .map(|entry| entry.path()) + } + pub fn rustdoc(&self, host: Interned) -> PathBuf { self.ensure(tool::Rustdoc { host }) } @@ -669,10 +677,9 @@ impl<'a> Builder<'a> { let compiler = self.compiler(self.top_stage, host); cmd.env("RUSTC_STAGE", compiler.stage.to_string()) .env("RUSTC_SYSROOT", self.sysroot(compiler)) - .env( - "RUSTDOC_LIBDIR", - self.sysroot_libdir(compiler, self.config.build), - ) + // 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_CRATE_VERSION", self.rust_version()) @@ -750,6 +757,9 @@ impl<'a> Builder<'a> { match mode { Mode::Std => { self.clear_if_dirty(&my_out, &self.rustc(compiler)); + for backend in self.codegen_backends(compiler) { + self.clear_if_dirty(&my_out, &backend); + } }, Mode::Test => { self.clear_if_dirty(&my_out, &libstd_stamp); @@ -782,6 +792,13 @@ impl<'a> Builder<'a> { .env("CARGO_TARGET_DIR", out_dir) .arg(cmd); + // See comment in librustc_llvm/build.rs for why this is necessary, largely llvm-config + // needs to not accidentally link to libLLVM in stage0/lib. + cargo.env("REAL_LIBRARY_PATH_VAR", &util::dylib_path_var()); + if let Some(e) = env::var_os(util::dylib_path_var()) { + cargo.env("REAL_LIBRARY_PATH", e); + } + if cmd != "install" { cargo.arg("--target") .arg(target); @@ -856,7 +873,7 @@ impl<'a> Builder<'a> { } else { &maybe_sysroot }; - let libdir = sysroot.join(libdir(&compiler.host)); + let libdir = self.rustc_libdir(compiler); // Customize the compiler we're running. Specify the compiler to cargo // as our shim and then pass it some various options used to configure @@ -898,7 +915,7 @@ impl<'a> Builder<'a> { cargo.env("RUSTC_ERROR_FORMAT", error_format); } if cmd != "build" && cmd != "check" && cmd != "rustc" && want_rustdoc { - cargo.env("RUSTDOC_LIBDIR", self.sysroot_libdir(compiler, self.config.build)); + cargo.env("RUSTDOC_LIBDIR", self.rustc_libdir(compiler)); } if mode.is_tool() { @@ -982,6 +999,9 @@ impl<'a> Builder<'a> { if self.config.incremental { cargo.env("CARGO_INCREMENTAL", "1"); + } else { + // Don't rely on any default setting for incr. comp. in Cargo + cargo.env("CARGO_INCREMENTAL", "0"); } if let Some(ref on_fail) = self.config.on_fail { @@ -998,8 +1018,7 @@ impl<'a> Builder<'a> { cargo.env("RUSTC_VERBOSE", self.verbosity.to_string()); - // in std, we want to avoid denying warnings for stage 0 as that makes cfg's painful. - if self.config.deny_warnings && !(mode == Mode::Std && stage == 0) { + if self.config.deny_warnings { cargo.env("RUSTC_DENY_WARNINGS", "1"); } @@ -1032,29 +1051,24 @@ impl<'a> Builder<'a> { } }; let cc = ccacheify(&self.cc(target)); - cargo.env(format!("CC_{}", target), &cc).env("CC", &cc); + cargo.env(format!("CC_{}", target), &cc); let cflags = self.cflags(target, GitRepo::Rustc).join(" "); cargo - .env(format!("CFLAGS_{}", target), cflags.clone()) - .env("CFLAGS", cflags.clone()); + .env(format!("CFLAGS_{}", target), cflags.clone()); if let Some(ar) = self.ar(target) { let ranlib = format!("{} s", ar.display()); cargo .env(format!("AR_{}", target), ar) - .env("AR", ar) - .env(format!("RANLIB_{}", target), ranlib.clone()) - .env("RANLIB", ranlib); + .env(format!("RANLIB_{}", target), ranlib); } if let Ok(cxx) = self.cxx(target) { let cxx = ccacheify(&cxx); cargo .env(format!("CXX_{}", target), &cxx) - .env("CXX", &cxx) - .env(format!("CXXFLAGS_{}", target), cflags.clone()) - .env("CXXFLAGS", cflags); + .env(format!("CXXFLAGS_{}", target), cflags); } } diff --git a/src/bootstrap/cache.rs b/src/bootstrap/cache.rs index ea8bc657a57aa..5f84816789a68 100644 --- a/src/bootstrap/cache.rs +++ b/src/bootstrap/cache.rs @@ -227,10 +227,10 @@ lazy_static! { pub static ref INTERNER: Interner = Interner::default(); } -/// This is essentially a HashMap which allows storing any type in its input and +/// This is essentially a `HashMap` which allows storing any type in its input and /// any type in its output. It is a write-once cache; values are never evicted, /// which means that references to the value can safely be returned from the -/// get() method. +/// `get()` method. #[derive(Debug)] pub struct Cache( RefCell, diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index cc539d4c89571..2a2533a3c1407 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -66,7 +66,7 @@ impl Step for Rustc { }); } - /// Build the compiler. + /// Builds the compiler. /// /// This will build the compiler for a particular stage of the build using /// the `compiler` targeting the `target` architecture. The artifacts diff --git a/src/bootstrap/clean.rs b/src/bootstrap/clean.rs index 74a2b7e4aa98b..b52e1a7b0e681 100644 --- a/src/bootstrap/clean.rs +++ b/src/bootstrap/clean.rs @@ -3,7 +3,7 @@ //! Responsible for cleaning out a build directory of all old and stale //! artifacts to prepare for a fresh build. Currently doesn't remove the //! `build/cache` directory (download cache) or the `build/$target/llvm` -//! directory unless the --all flag is present. +//! directory unless the `--all` flag is present. use std::fs; use std::io::{self, ErrorKind}; diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index b581271663e7e..8fabb8c3fd08f 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -48,7 +48,7 @@ impl Step for Std { }); } - /// Build the standard library. + /// Builds the standard library. /// /// This will build the standard library for a particular stage of the build /// using the `compiler` targeting the `target` architecture. The artifacts @@ -269,7 +269,7 @@ impl Step for StartupObjects { }); } - /// Build and prepare startup objects like rsbegin.o and rsend.o + /// Builds and prepare startup objects like rsbegin.o and rsend.o /// /// These are primarily used on Windows right now for linking executables/dlls. /// They don't require any library support as they're just plain old object @@ -334,7 +334,7 @@ impl Step for Test { }); } - /// Build libtest. + /// Builds libtest. /// /// This will build libtest and supporting libraries for a particular stage of /// the build using the `compiler` targeting the `target` architecture. The @@ -455,7 +455,7 @@ impl Step for Rustc { }); } - /// Build the compiler. + /// Builds the compiler. /// /// This will build the compiler for a particular stage of the build using /// the `compiler` targeting the `target` architecture. The artifacts @@ -554,8 +554,8 @@ pub fn rustc_cargo_env(builder: &Builder, cargo: &mut Command) { if let Some(ref s) = builder.config.rustc_default_linker { cargo.env("CFG_DEFAULT_LINKER", s); } - if builder.config.rustc_parallel_queries { - cargo.env("RUSTC_PARALLEL_QUERIES", "1"); + if builder.config.rustc_parallel { + cargo.env("RUSTC_PARALLEL_COMPILER", "1"); } if builder.config.rust_verify_llvm_ir { cargo.env("RUSTC_VERIFY_LLVM_IR", "1"); @@ -712,6 +712,7 @@ pub fn build_codegen_backend(builder: &Builder, if builder.is_rust_llvm(target) && backend != "emscripten" { cargo.env("LLVM_RUSTLLVM", "1"); } + cargo.env("LLVM_CONFIG", &llvm_config); if backend != "emscripten" { let target_config = builder.config.target_config.get(&target); diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 9421817ae6d8e..7d3e584f1a6fa 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -77,11 +77,15 @@ pub struct Config { pub llvm_experimental_targets: String, pub llvm_link_jobs: Option, pub llvm_version_suffix: Option, + pub llvm_use_linker: Option, pub lld_enabled: bool, pub lldb_enabled: bool, pub llvm_tools_enabled: bool, + pub llvm_cflags: Option, + pub llvm_cxxflags: Option, + pub llvm_ldflags: Option, pub llvm_use_libcxx: bool, // rust codegen options @@ -94,7 +98,7 @@ pub struct Config { pub rust_debuginfo_only_std: bool, pub rust_debuginfo_tools: bool, pub rust_rpath: bool, - pub rustc_parallel_queries: bool, + pub rustc_parallel: bool, pub rustc_default_linker: Option, pub rust_optimize_tests: bool, pub rust_debuginfo_tests: bool, @@ -254,7 +258,11 @@ struct Llvm { link_shared: Option, version_suffix: Option, clang_cl: Option, + cflags: Option, + cxxflags: Option, + ldflags: Option, use_libcxx: Option, + use_linker: Option, } #[derive(Deserialize, Default, Clone)] @@ -292,7 +300,7 @@ struct Rust { debuginfo_lines: Option, debuginfo_only_std: Option, debuginfo_tools: Option, - experimental_parallel_queries: Option, + parallel_compiler: Option, backtrace: Option, default_linker: Option, channel: Option, @@ -516,7 +524,12 @@ impl Config { config.llvm_link_jobs = llvm.link_jobs; config.llvm_version_suffix = llvm.version_suffix.clone(); config.llvm_clang_cl = llvm.clang_cl.clone(); + + config.llvm_cflags = llvm.cflags.clone(); + config.llvm_cxxflags = llvm.cxxflags.clone(); + config.llvm_ldflags = llvm.ldflags.clone(); set(&mut config.llvm_use_libcxx, llvm.use_libcxx); + config.llvm_use_linker = llvm.use_linker.clone(); } if let Some(ref rust) = toml.rust { @@ -547,7 +560,7 @@ impl Config { set(&mut config.lld_enabled, rust.lld); set(&mut config.lldb_enabled, rust.lldb); set(&mut config.llvm_tools_enabled, rust.llvm_tools); - config.rustc_parallel_queries = rust.experimental_parallel_queries.unwrap_or(false); + config.rustc_parallel = rust.parallel_compiler.unwrap_or(false); config.rustc_default_linker = rust.default_linker.clone(); config.musl_root = rust.musl_root.clone().map(PathBuf::from); config.save_toolstates = rust.save_toolstates.clone().map(PathBuf::from); diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py index b0c3c9702498d..b2d8f2d8ebfcf 100755 --- a/src/bootstrap/configure.py +++ b/src/bootstrap/configure.py @@ -35,7 +35,7 @@ def v(*args): o("docs", "build.docs", "build standard library documentation") o("compiler-docs", "build.compiler-docs", "build compiler documentation") o("optimize-tests", "rust.optimize-tests", "build tests with optimizations") -o("experimental-parallel-queries", "rust.experimental-parallel-queries", "build rustc with experimental parallelization") +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") @@ -64,6 +64,10 @@ def v(*args): o("missing-tools", "dist.missing-tools", "allow failures when building tools") o("use-libcxx", "llvm.use_libcxx", "build LLVM with libc++") +o("cflags", "llvm.cflags", "build LLVM with these extra compiler flags") +o("cxxflags", "llvm.cxxflags", "build LLVM with these extra compiler flags") +o("ldflags", "llvm.ldflags", "build LLVM with these extra linker flags") + # Optimization and debugging options. These may be overridden by the release # channel, etc. o("optimize", "rust.optimize", "build optimized rust code") diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index df34dfe4544ae..bc1fdad356be3 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -23,7 +23,7 @@ use crate::builder::{Builder, RunConfig, ShouldRun, Step}; use crate::compile; use crate::tool::{self, Tool}; use crate::cache::{INTERNER, Interned}; -use time; +use time::{self, Timespec}; pub fn pkgname(builder: &Builder, component: &str) -> String { if component == "cargo" { @@ -226,7 +226,7 @@ fn make_win_dist( let trim_chars: &[_] = &[' ', '=']; let value = line[(idx + 1)..] - .trim_left_matches(trim_chars) + .trim_start_matches(trim_chars) .split(';') .map(PathBuf::from); @@ -342,7 +342,7 @@ impl Step for Mingw { run.builder.ensure(Mingw { host: run.target }); } - /// Build the `rust-mingw` installer component. + /// Builds the `rust-mingw` installer component. /// /// This contains all the bits and pieces to run the MinGW Windows targets /// without any extra installed software (e.g., we bundle gcc, libraries, etc). @@ -528,7 +528,19 @@ impl Step for Rustc { t!(fs::create_dir_all(image.join("share/man/man1"))); let man_src = builder.src.join("src/doc/man"); let man_dst = image.join("share/man/man1"); - let month_year = t!(time::strftime("%B %Y", &time::now())); + + // Reproducible builds: If SOURCE_DATE_EPOCH is set, use that as the time. + let time = env::var("SOURCE_DATE_EPOCH") + .map(|timestamp| { + let epoch = timestamp.parse().map_err(|err| { + format!("could not parse SOURCE_DATE_EPOCH: {}", err) + }).unwrap(); + + time::at(Timespec::new(epoch, 0)) + }) + .unwrap_or_else(|_| time::now()); + + let month_year = t!(time::strftime("%B %Y", &time)); // don't use our `bootstrap::util::{copy, cp_r}`, because those try // to hardlink, and we don't want to edit the source templates for file_entry in builder.read_dir(&man_src) { @@ -602,6 +614,8 @@ impl Step for DebuggerScripts { // gdb debugger scripts builder.install(&builder.src.join("src/etc/rust-gdb"), &sysroot.join("bin"), 0o755); + builder.install(&builder.src.join("src/etc/rust-gdbgui"), &sysroot.join("bin"), + 0o755); cp_debugger_script("gdb_load_rust_pretty_printers.py"); cp_debugger_script("gdb_rust_pretty_printing.py"); @@ -786,7 +800,24 @@ fn copy_src_dirs(builder: &Builder, src_dirs: &[&str], exclude_dirs: &[&str], ds if spath.ends_with("~") || spath.ends_with(".pyc") { return false } - if (spath.contains("llvm/test") || spath.contains("llvm\\test")) && + + const LLVM_PROJECTS: &[&str] = &[ + "llvm-project/clang", "llvm-project\\clang", + "llvm-project/lld", "llvm-project\\lld", + "llvm-project/lldb", "llvm-project\\lldb", + "llvm-project/llvm", "llvm-project\\llvm", + ]; + if spath.contains("llvm-project") && !spath.ends_with("llvm-project") + && !LLVM_PROJECTS.iter().any(|path| spath.contains(path)) + { + return false; + } + + const LLVM_TEST: &[&str] = &[ + "llvm-project/llvm/test", "llvm-project\\llvm\\test", + "llvm-emscripten/test", "llvm-emscripten\\test", + ]; + if LLVM_TEST.iter().any(|path| spath.contains(path)) && (spath.ends_with(".ll") || spath.ends_with(".td") || spath.ends_with(".s")) { @@ -2074,7 +2105,7 @@ impl Step for LlvmTools { } builder.info(&format!("Dist LlvmTools stage{} ({})", stage, target)); - let src = builder.src.join("src/llvm"); + let src = builder.src.join("src/llvm-project/llvm"); let name = pkgname(builder, "llvm-tools"); let tmp = tmpdir(builder); @@ -2133,7 +2164,7 @@ impl Step for Lldb { const DEFAULT: bool = true; fn should_run(run: ShouldRun) -> ShouldRun { - run.path("src/tools/lldb") + run.path("src/llvm-project/lldb").path("src/tools/lldb") } fn make_run(run: RunConfig) { @@ -2158,7 +2189,7 @@ impl Step for Lldb { } builder.info(&format!("Dist Lldb ({})", target)); - let src = builder.src.join("src/tools/lldb"); + let src = builder.src.join("src/llvm-project/lldb"); let name = pkgname(builder, "lldb"); let tmp = tmpdir(builder); diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index eec193c21f5db..660f9b9ef578a 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -23,7 +23,7 @@ use crate::cache::{INTERNER, Interned}; use crate::config::Config; macro_rules! book { - ($($name:ident, $path:expr, $book_name:expr;)+) => { + ($($name:ident, $path:expr, $book_name:expr, $book_ver:expr;)+) => { $( #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct $name { @@ -49,6 +49,7 @@ macro_rules! book { builder.ensure(Rustbook { target: self.target, name: INTERNER.intern_str($book_name), + version: $book_ver, }) } } @@ -56,19 +57,29 @@ 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!( - Nomicon, "src/doc/nomicon", "nomicon"; - Reference, "src/doc/reference", "reference"; - EditionGuide, "src/doc/edition-guide", "edition-guide"; - RustdocBook, "src/doc/rustdoc", "rustdoc"; - RustcBook, "src/doc/rustc", "rustc"; - RustByExample, "src/doc/rust-by-example", "rust-by-example"; + EditionGuide, "src/doc/edition-guide", "edition-guide", RustbookVersion::MdBook1; + EmbeddedBook, "src/doc/embedded-book", "embedded-book", RustbookVersion::MdBook2; + Nomicon, "src/doc/nomicon", "nomicon", RustbookVersion::MdBook1; + Reference, "src/doc/reference", "reference", RustbookVersion::MdBook1; + RustByExample, "src/doc/rust-by-example", "rust-by-example", RustbookVersion::MdBook1; + RustcBook, "src/doc/rustc", "rustc", RustbookVersion::MdBook1; + RustdocBook, "src/doc/rustdoc", "rustdoc", RustbookVersion::MdBook1; ); +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +enum RustbookVersion { + MdBook1, + MdBook2, +} + #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] struct Rustbook { target: Interned, name: Interned, + version: RustbookVersion, } impl Step for Rustbook { @@ -90,6 +101,7 @@ impl Step for Rustbook { target: self.target, name: self.name, src: INTERNER.intern_path(src), + version: self.version, }); } } @@ -122,6 +134,7 @@ impl Step for UnstableBook { target: self.target, name: INTERNER.intern_str("unstable-book"), src: builder.md_doc_out(self.target), + version: RustbookVersion::MdBook1, }) } } @@ -175,6 +188,7 @@ struct RustbookSrc { target: Interned, name: Interned, src: Interned, + version: RustbookVersion, } impl Step for RustbookSrc { @@ -205,11 +219,19 @@ impl Step for RustbookSrc { } builder.info(&format!("Rustbook ({}) - {}", target, name)); let _ = fs::remove_dir_all(&out); + + let vers = match self.version { + RustbookVersion::MdBook1 => "1", + RustbookVersion::MdBook2 => "2", + }; + builder.run(rustbook_cmd .arg("build") .arg(&src) .arg("-d") - .arg(out)); + .arg(out) + .arg("-m") + .arg(vers)); } } @@ -237,7 +259,7 @@ impl Step for TheBook { }); } - /// Build the book and associated stuff. + /// Builds the book and associated stuff. /// /// We need to build: /// @@ -255,6 +277,7 @@ impl Step for TheBook { builder.ensure(Rustbook { target, name: INTERNER.intern_string(name.to_string()), + version: RustbookVersion::MdBook1, }); // building older edition redirects @@ -263,18 +286,21 @@ impl Step for TheBook { builder.ensure(Rustbook { target, name: INTERNER.intern_string(source_name), + version: RustbookVersion::MdBook1, }); let source_name = format!("{}/second-edition", name); builder.ensure(Rustbook { target, name: INTERNER.intern_string(source_name), + version: RustbookVersion::MdBook1, }); let source_name = format!("{}/2018-edition", name); builder.ensure(Rustbook { target, name: INTERNER.intern_string(source_name), + version: RustbookVersion::MdBook1, }); // build the version info page and CSS @@ -491,6 +517,7 @@ impl Step for Std { cargo.arg("--") .arg("--markdown-css").arg("rust.css") .arg("--markdown-no-toc") + .arg("--generate-redirect-pages") .arg("--index-page").arg(&builder.src.join("src/doc/index.md")); builder.run(&mut cargo); @@ -555,7 +582,9 @@ impl Step for Test { let mut cargo = builder.cargo(compiler, Mode::Test, target, "doc"); compile::test_cargo(builder, &compiler, target, &mut cargo); - cargo.arg("--no-deps").arg("-p").arg("test"); + cargo.arg("--no-deps") + .arg("-p").arg("test") + .env("RUSTDOC_GENERATE_REDIRECT_PAGES", "1"); builder.run(&mut cargo); builder.cp_r(&my_out, &out); @@ -585,7 +614,7 @@ impl Step for WhitelistedRustc { }); } - /// Generate whitelisted compiler crate documentation. + /// Generates whitelisted compiler crate documentation. /// /// This will generate all documentation for crates that are whitelisted /// to be included in the standard documentation. This documentation is @@ -624,9 +653,9 @@ impl Step for WhitelistedRustc { // We don't want to build docs for internal compiler dependencies in this // step (there is another step for that). Therefore, we whitelist the crates // for which docs must be built. - cargo.arg("--no-deps"); for krate in &["proc_macro"] { - cargo.arg("-p").arg(krate); + cargo.arg("-p").arg(krate) + .env("RUSTDOC_GENERATE_REDIRECT_PAGES", "1"); } builder.run(&mut cargo); @@ -657,7 +686,7 @@ impl Step for Rustc { }); } - /// Generate compiler documentation. + /// Generates compiler documentation. /// /// This will generate all documentation for compiler and dependencies. /// Compiler documentation is distributed separately, so we make sure @@ -758,7 +787,7 @@ impl Step for Rustdoc { }); } - /// Generate compiler documentation. + /// Generates compiler documentation. /// /// This will generate all documentation for compiler and dependencies. /// Compiler documentation is distributed separately, so we make sure diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index bddc6362389ad..6a93c95c3d97f 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -69,7 +69,7 @@ //! ## Copying stage0 {std,test,rustc} //! //! This copies the build output from Cargo into -//! `build/$HOST/stage0-sysroot/lib/rustlib/$ARCH/lib`. FIXME: This step's +//! `build/$HOST/stage0-sysroot/lib/rustlib/$ARCH/lib`. FIXME: this step's //! documentation should be expanded -- the information already here may be //! incorrect. //! @@ -135,7 +135,7 @@ use std::cell::{RefCell, Cell}; use std::collections::{HashSet, HashMap}; use std::env; use std::fs::{self, OpenOptions, File}; -use std::io::{self, Seek, SeekFrom, Write, Read}; +use std::io::{Seek, SeekFrom, Write, Read}; use std::path::{PathBuf, Path}; use std::process::{self, Command}; use std::slice; @@ -423,7 +423,7 @@ impl Build { Command::new(&build.initial_rustc).arg("--version").arg("--verbose")); let local_release = local_version_verbose .lines().filter(|x| x.starts_with("release:")) - .next().unwrap().trim_left_matches("release:").trim(); + .next().unwrap().trim_start_matches("release:").trim(); let my_version = channel::CFG_RELEASE_NUM; if local_release.split('.').take(2).eq(my_version.split('.').take(2)) { build.verbose(&format!("auto-detected local-rebuild {}", local_release)); @@ -504,7 +504,7 @@ impl Build { cleared } - /// Get the space-separated set of activated features for the standard + /// Gets the space-separated set of activated features for the standard /// library. fn std_features(&self) -> String { let mut features = "panic-unwind".to_string(); @@ -521,7 +521,7 @@ impl Build { features } - /// Get the space-separated set of activated features for the compiler. + /// Gets the space-separated set of activated features for the compiler. fn rustc_features(&self) -> String { let mut features = String::new(); if self.config.jemalloc { @@ -609,7 +609,7 @@ impl Build { self.out.join(&*target).join("crate-docs") } - /// Returns true if no custom `llvm-config` is set for the specified target. + /// Returns `true` if no custom `llvm-config` is set for the specified target. /// /// If no custom `llvm-config` was specified then Rust's llvm will be used. fn is_rust_llvm(&self, target: Interned) -> bool { @@ -831,6 +831,7 @@ impl Build { !target.contains("msvc") && !target.contains("emscripten") && !target.contains("wasm32") && + !target.contains("nvptx") && !target.contains("fuchsia") { Some(self.cc(target)) } else { @@ -856,13 +857,13 @@ impl Build { .map(|p| &**p) } - /// Returns true if this is a no-std `target`, if defined + /// Returns `true` if this is a no-std `target`, if defined fn no_std(&self, target: Interned) -> Option { self.config.target_config.get(&target) .map(|t| t.no_std) } - /// Returns whether the target will be tested using the `remote-test-client` + /// Returns `true` if the target will be tested using the `remote-test-client` /// and `remote-test-server` binaries. fn remote_tested(&self, target: Interned) -> bool { self.qemu_rootfs(target).is_some() || target.contains("android") || @@ -1058,7 +1059,7 @@ impl Build { self.rust_info.version(self, channel::CFG_RELEASE_NUM) } - /// Return the full commit hash + /// Returns the full commit hash. fn rust_sha(&self) -> Option<&str> { self.rust_info.sha() } @@ -1078,7 +1079,7 @@ impl Build { panic!("failed to find version in {}'s Cargo.toml", package) } - /// Returns whether unstable features should be enabled for the compiler + /// Returns `true` if unstable features should be enabled for the compiler /// we're building. fn unstable_features(&self) -> bool { match &self.config.channel[..] { @@ -1263,9 +1264,15 @@ impl Build { if !src.exists() { panic!("Error: File \"{}\" not found!", src.display()); } - let mut s = t!(fs::File::open(&src)); - let mut d = t!(fs::File::create(&dst)); - io::copy(&mut s, &mut d).expect("failed to copy"); + let metadata = t!(src.symlink_metadata()); + if let Err(e) = fs::copy(&src, &dst) { + panic!("failed to copy `{}` to `{}`: {}", src.display(), + dst.display(), e) + } + t!(fs::set_permissions(&dst, metadata.permissions())); + let atime = FileTime::from_last_access_time(&metadata); + let mtime = FileTime::from_last_modification_time(&metadata); + t!(filetime::set_file_times(&dst, atime, mtime)); } chmod(&dst, perms); } @@ -1320,7 +1327,7 @@ impl<'a> Compiler { self } - /// Returns whether this is a snapshot compiler for `build`'s configuration + /// Returns `true` if this is a snapshot compiler for `build`'s configuration pub fn is_snapshot(&self, build: &Build) -> bool { self.stage == 0 && self.host == build.build } diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in index 8ff1456f0f47c..1c27cf3909b1a 100644 --- a/src/bootstrap/mk/Makefile.in +++ b/src/bootstrap/mk/Makefile.in @@ -53,7 +53,6 @@ check-aux: src/test/run-fail/pretty \ src/test/run-pass-valgrind/pretty \ src/test/run-pass-fulldeps/pretty \ - src/test/run-fail-fulldeps/pretty \ $(AUX_ARGS) \ $(BOOTSTRAP_ARGS) check-bootstrap: diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index cb9c86df55080..f48f9ee752e93 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -36,7 +36,10 @@ impl Step for Llvm { const ONLY_HOSTS: bool = true; fn should_run(run: ShouldRun) -> ShouldRun { - run.path("src/llvm").path("src/llvm-emscripten") + run.path("src/llvm-project") + .path("src/llvm-project/llvm") + .path("src/llvm") + .path("src/llvm-emscripten") } fn make_run(run: RunConfig) { @@ -97,7 +100,7 @@ impl Step for Llvm { t!(fs::create_dir_all(&out_dir)); // http://llvm.org/docs/CMake.html - let root = if self.emscripten { "src/llvm-emscripten" } else { "src/llvm" }; + let root = if self.emscripten { "src/llvm-emscripten" } else { "src/llvm-project/llvm" }; let mut cfg = cmake::Config::new(builder.src.join(root)); let profile = match (builder.config.llvm_optimize, builder.config.llvm_release_debuginfo) { @@ -189,10 +192,10 @@ impl Step for Llvm { } if want_lldb { - cfg.define("LLVM_EXTERNAL_CLANG_SOURCE_DIR", builder.src.join("src/tools/clang")); - cfg.define("LLVM_EXTERNAL_LLDB_SOURCE_DIR", builder.src.join("src/tools/lldb")); + cfg.define("LLVM_ENABLE_PROJECTS", "clang;lldb"); // For the time being, disable code signing. cfg.define("LLDB_CODESIGN_IDENTITY", ""); + cfg.define("LLDB_NO_DEBUGSERVER", "ON"); } else { // LLDB requires libxml2; but otherwise we want it to be disabled. // See https://github.com/rust-lang/rust/pull/50104 @@ -231,6 +234,10 @@ impl Step for Llvm { cfg.define("LLVM_VERSION_SUFFIX", suffix); } + if let Some(ref linker) = builder.config.llvm_use_linker { + cfg.define("LLVM_USE_LINKER", linker); + } + if let Some(ref python) = builder.config.python { cfg.define("PYTHON_EXECUTABLE", python); } @@ -358,7 +365,11 @@ fn configure_cmake(builder: &Builder, } cfg.build_arg("-j").build_arg(builder.jobs().to_string()); - cfg.define("CMAKE_C_FLAGS", builder.cflags(target, GitRepo::Llvm).join(" ")); + let mut cflags = builder.cflags(target, GitRepo::Llvm).join(" "); + if let Some(ref s) = builder.config.llvm_cxxflags { + cflags.push_str(&format!(" {}", s)); + } + cfg.define("CMAKE_C_FLAGS", cflags); let mut cxxflags = builder.cflags(target, GitRepo::Llvm).join(" "); if builder.config.llvm_static_stdcpp && !target.contains("windows") && @@ -366,6 +377,9 @@ fn configure_cmake(builder: &Builder, { cxxflags.push_str(" -static-libstdc++"); } + if let Some(ref s) = builder.config.llvm_cxxflags { + cxxflags.push_str(&format!(" {}", s)); + } cfg.define("CMAKE_CXX_FLAGS", cxxflags); if let Some(ar) = builder.ar(target) { if ar.is_absolute() { @@ -383,6 +397,12 @@ fn configure_cmake(builder: &Builder, } } + if let Some(ref s) = builder.config.llvm_ldflags { + cfg.define("CMAKE_SHARED_LINKER_FLAGS", s); + cfg.define("CMAKE_MODULE_LINKER_FLAGS", s); + cfg.define("CMAKE_EXE_LINKER_FLAGS", s); + } + if env::var_os("SCCACHE_ERROR_LOG").is_some() { cfg.env("RUST_LOG", "sccache=warn"); } @@ -398,7 +418,7 @@ impl Step for Lld { const ONLY_HOSTS: bool = true; fn should_run(run: ShouldRun) -> ShouldRun { - run.path("src/tools/lld") + run.path("src/llvm-project/lld").path("src/tools/lld") } fn make_run(run: RunConfig) { @@ -428,7 +448,7 @@ impl Step for Lld { let _time = util::timeit(&builder); t!(fs::create_dir_all(&out_dir)); - let mut cfg = cmake::Config::new(builder.src.join("src/tools/lld")); + let mut cfg = cmake::Config::new(builder.src.join("src/llvm-project/lld")); configure_cmake(builder, target, &mut cfg); // This is an awful, awful hack. Discovered when we migrated to using diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index fe547a6b151c2..ff4fb85bbfad3 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -156,7 +156,7 @@ pub fn check(build: &mut Build) { panic!("the iOS target is only supported on macOS"); } - if target.contains("-none-") { + if target.contains("-none-") || target.contains("nvptx") { if build.no_std(*target).is_none() { let target = build.config.target_config.entry(target.clone()) .or_default(); @@ -165,7 +165,7 @@ pub fn check(build: &mut Build) { } if build.no_std(*target) == Some(false) { - panic!("All the *-none-* targets are no-std targets") + panic!("All the *-none-* and nvptx* targets are no-std targets") } } diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 2edc78ebaa94f..a882550f734f4 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -30,9 +30,9 @@ const ADB_TEST_DIR: &str = "/data/tmp/work"; /// The two modes of the test runner; tests or benchmarks. #[derive(Debug, PartialEq, Eq, Hash, Copy, Clone, PartialOrd, Ord)] pub enum TestKind { - /// Run `cargo test` + /// Run `cargo test`. Test, - /// Run `cargo bench` + /// Run `cargo bench`. Bench, } @@ -848,12 +848,6 @@ host_test!(RunPassFullDeps { suite: "run-pass-fulldeps" }); -host_test!(RunFailFullDeps { - path: "src/test/run-fail-fulldeps", - mode: "run-fail", - suite: "run-fail-fulldeps" -}); - host_test!(Rustdoc { path: "src/test/rustdoc", mode: "rustdoc", @@ -888,20 +882,6 @@ test!(RunPassValgrindPretty { default: false, host: true }); -test!(RunPassFullDepsPretty { - path: "src/test/run-pass-fulldeps/pretty", - mode: "pretty", - suite: "run-pass-fulldeps", - default: false, - host: true -}); -test!(RunFailFullDepsPretty { - path: "src/test/run-fail-fulldeps/pretty", - mode: "pretty", - suite: "run-fail-fulldeps", - default: false, - host: true -}); default_test!(RunMake { path: "src/test/run-make", @@ -1108,9 +1088,7 @@ impl Step for Compiletest { }; let lldb_exe = if builder.config.lldb_enabled && !target.contains("emscripten") { // Test against the lldb that was just built. - builder.llvm_out(target) - .join("bin") - .join("lldb") + builder.llvm_out(target).join("bin").join("lldb") } else { PathBuf::from("lldb") }; @@ -1127,6 +1105,26 @@ 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); + } + } + } + // Get paths from cmd args let paths = match &builder.config.cmd { Subcommand::Test { ref paths, .. } => &paths[..], @@ -1290,7 +1288,7 @@ impl Step for DocTest { run.never() } - /// Run `rustdoc --test` for all documentation in `src/doc`. + /// Runs `rustdoc --test` for all documentation in `src/doc`. /// /// This will run all tests in our markdown documentation (e.g., the book) /// located in `src/doc`. The `rustdoc` that's run is the one that sits next to @@ -1385,6 +1383,7 @@ test_book!( RustdocBook, "src/doc/rustdoc", "rustdoc", default=true; RustcBook, "src/doc/rustc", "rustc", default=true; RustByExample, "src/doc/rust-by-example", "rust-by-example", default=false; + 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; ); @@ -1409,7 +1408,7 @@ impl Step for ErrorIndex { }); } - /// Run the error index generator tool to execute the tests located in the error + /// Runs the error index generator tool to execute the tests located in the error /// index. /// /// The `error_index_generator` tool lives in `src/tools` and is used to @@ -1615,7 +1614,7 @@ impl Step for Crate { } } - /// Run all unit tests plus documentation tests for a given crate defined + /// Runs all unit tests plus documentation tests for a given crate defined /// by a `Cargo.toml` (single manifest) /// /// This is what runs tests for crates like the standard library, compiler, etc. @@ -1834,7 +1833,7 @@ fn envify(s: &str) -> String { /// the standard library and such to the emulator ahead of time. This step /// represents this and is a dependency of all test suites. /// -/// Most of the time this is a noop. For some steps such as shipping data to +/// Most of the time this is a no-op. For some steps such as shipping data to /// QEMU we have to build our own tools so we've got conditional dependencies /// on those programs as well. Note that the remote test client is built for /// the build target (us) and the server is built for the target. @@ -1905,7 +1904,7 @@ impl Step for Distcheck { run.builder.ensure(Distcheck); } - /// Run "distcheck", a 'make check' from a tarball + /// Runs "distcheck", a 'make check' from a tarball fn run(self, builder: &Builder) { builder.info("Distcheck"); let dir = builder.out.join("tmp").join("distcheck"); @@ -1966,7 +1965,7 @@ impl Step for Bootstrap { const DEFAULT: bool = true; const ONLY_HOSTS: bool = true; - /// Test the build system itself + /// Tests the build system itself. fn run(self, builder: &Builder) { let mut cmd = Command::new(&builder.initial_cargo); cmd.arg("test") diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 9f6db73e6f713..6383a2ecc7583 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -1,6 +1,5 @@ use std::fs; use std::env; -use std::iter; use std::path::PathBuf; use std::process::{Command, exit}; use std::collections::HashSet; @@ -41,7 +40,7 @@ impl Step for ToolBuild { run.never() } - /// Build a tool in `src/tools` + /// Builds a tool in `src/tools` /// /// This will build the specified tool with the specified `host` compiler in /// `stage` into the normal cargo output directory. @@ -419,25 +418,25 @@ impl Step for Rustdoc { fn run(self, builder: &Builder) -> PathBuf { let target_compiler = builder.compiler(builder.top_stage, self.host); + if target_compiler.stage == 0 { + if !target_compiler.is_snapshot(builder) { + panic!("rustdoc in stage 0 must be snapshot rustdoc"); + } + return builder.initial_rustc.with_file_name(exe("rustdoc", &target_compiler.host)); + } let target = target_compiler.host; - let build_compiler = if target_compiler.stage == 0 { - builder.compiler(0, builder.config.build) - } else if target_compiler.stage >= 2 { - // Past stage 2, we consider the compiler to be ABI-compatible and hence capable of - // building rustdoc itself. - builder.compiler(target_compiler.stage, builder.config.build) - } else { - // Similar to `compile::Assemble`, build with the previous stage's compiler. Otherwise - // we'd have stageN/bin/rustc and stageN/bin/rustdoc be effectively different stage - // compilers, which isn't what we want. - builder.compiler(target_compiler.stage - 1, builder.config.build) - }; - - builder.ensure(compile::Rustc { compiler: build_compiler, target }); - builder.ensure(compile::Rustc { - compiler: build_compiler, - target: builder.config.build, - }); + // Similar to `compile::Assemble`, build with the previous stage's compiler. Otherwise + // we'd have stageN/bin/rustc and stageN/bin/rustdoc be effectively different stage + // compilers, which isn't what we want. Rustdoc should be linked in the same way as the + // rustc compiler it's paired with, so it must be built with the previous stage compiler. + let build_compiler = builder.compiler(target_compiler.stage - 1, builder.config.build); + + // The presence of `target_compiler` ensures that the necessary libraries (codegen backends, + // compiler libraries, ...) are built. Rustdoc does not require the presence of any + // libraries within sysroot_libdir (i.e., rustlib), though doctests may want it (since + // they'll be linked to those libraries). As such, don't explicitly `ensure` any additional + // libraries here. The intuition here is that If we've built a compiler, we should be able + // to build rustdoc. let mut cargo = prepare_tool_cargo( builder, @@ -622,7 +621,7 @@ tool_extended!((self, builder), ); impl<'a> Builder<'a> { - /// Get a `Command` which is ready to run `tool` in `stage` built for + /// Gets a `Command` which is ready to run `tool` in `stage` built for /// `host`. pub fn tool_cmd(&self, tool: Tool) -> Command { let mut cmd = Command::new(self.tool_exe(tool)); @@ -666,19 +665,33 @@ 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() { + if tool.uses_llvm_tools() && !self.config.dry_run { + let mut additional_paths = vec![]; + if let Some(llvm_bin_path) = self.llvm_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.push(llvm_bin_path); - } else { - let old_path = env::var_os("PATH").unwrap_or_default(); - let new_path = env::join_paths(iter::once(llvm_bin_path) - .chain(env::split_paths(&old_path))) - .expect("Could not add LLVM bin path to PATH"); - cmd.env("PATH", new_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); } } @@ -686,7 +699,7 @@ impl<'a> Builder<'a> { } fn llvm_bin_path(&self) -> Option { - if self.config.llvm_enabled && !self.config.dry_run { + if self.config.llvm_enabled { let llvm_config = self.ensure(native::Llvm { target: self.config.build, emscripten: false, diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs index 2880f1a084be0..29aa98971fb56 100644 --- a/src/bootstrap/util.rs +++ b/src/bootstrap/util.rs @@ -33,7 +33,7 @@ pub fn exe(name: &str, target: &str) -> String { } } -/// Returns whether the file name given looks like a dynamic library. +/// Returns `true` if the file name given looks like a dynamic library. pub fn is_dylib(name: &str) -> bool { name.ends_with(".dylib") || name.ends_with(".so") || name.ends_with(".dll") } @@ -70,7 +70,11 @@ pub fn dylib_path_var() -> &'static str { /// Parses the `dylib_path_var()` environment variable, returning a list of /// paths that are members of this lookup path. pub fn dylib_path() -> Vec { - env::split_paths(&env::var_os(dylib_path_var()).unwrap_or_default()).collect() + let var = match env::var_os(dylib_path_var()) { + Some(v) => v, + None => return vec![], + }; + env::split_paths(&var).collect() } /// `push` all components to `buf`. On windows, append `.exe` to the last component. diff --git a/src/build_helper/Cargo.toml b/src/build_helper/Cargo.toml index 01d704f816bbc..04c7820b45665 100644 --- a/src/build_helper/Cargo.toml +++ b/src/build_helper/Cargo.toml @@ -2,6 +2,7 @@ name = "build_helper" version = "0.1.0" authors = ["The Rust Project Developers"] +edition = "2018" [lib] name = "build_helper" diff --git a/src/build_helper/lib.rs b/src/build_helper/lib.rs index 5a704e557751d..bd99dc118e66a 100644 --- a/src/build_helper/lib.rs +++ b/src/build_helper/lib.rs @@ -1,3 +1,5 @@ +#![deny(rust_2018_idioms)] + use std::fs::File; use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; @@ -23,6 +25,25 @@ macro_rules! t { }; } +// Because Cargo adds the compiler's dylib path to our library search path, llvm-config may +// break: the dylib path for the compiler, as of this writing, contains a copy of the LLVM +// shared library, which means that when our freshly built llvm-config goes to load it's +// associated LLVM, it actually loads the compiler's LLVM. In particular when building the first +// compiler (i.e., in stage 0) that's a problem, as the compiler's LLVM is likely different from +// the one we want to use. As such, we restore the environment to what bootstrap saw. This isn't +// perfect -- we might actually want to see something from Cargo's added library paths -- but +// for now it works. +pub fn restore_library_path() { + println!("cargo:rerun-if-env-changed=REAL_LIBRARY_PATH_VAR"); + println!("cargo:rerun-if-env-changed=REAL_LIBRARY_PATH"); + let key = env::var_os("REAL_LIBRARY_PATH_VAR").expect("REAL_LIBRARY_PATH_VAR"); + if let Some(env) = env::var_os("REAL_LIBRARY_PATH") { + env::set_var(&key, &env); + } else { + env::remove_var(&key); + } +} + pub fn run(cmd: &mut Command) { println!("running: {:?}", cmd); run_silent(cmd); @@ -142,7 +163,7 @@ pub fn mtime(path: &Path) -> SystemTime { .unwrap_or(UNIX_EPOCH) } -/// Returns whether `dst` is up to date given that the file or files in `src` +/// Returns `true` if `dst` is up to date given that the file or files in `src` /// are used to generate it. /// /// Uses last-modified time checks to verify this. @@ -169,12 +190,12 @@ pub struct NativeLibBoilerplate { } impl NativeLibBoilerplate { - /// On OSX we don't want to ship the exact filename that compiler-rt builds. + /// On macOS we don't want to ship the exact filename that compiler-rt builds. /// This conflicts with the system and ours is likely a wildly different /// version, so they can't be substituted. /// /// As a result, we rename it here but we need to also use - /// `install_name_tool` on OSX to rename the commands listed inside of it to + /// `install_name_tool` on macOS to rename the commands listed inside of it to /// ensure it's linked against correctly. pub fn fixup_sanitizer_lib_name(&self, sanitizer_name: &str) { if env::var("TARGET").unwrap() != "x86_64-apple-darwin" { diff --git a/src/ci/docker/README.md b/src/ci/docker/README.md index 8d4dbc399986f..34320ab4411e2 100644 --- a/src/ci/docker/README.md +++ b/src/ci/docker/README.md @@ -131,13 +131,15 @@ $category > $option = $value -- $comment For targets: `arm-unknown-linux-gnueabi` - Path and misc options > Prefix directory = /x-tools/${CT\_TARGET} +- Path and misc options > Patches origin = Bundled, then local +- Path and misc options > Local patch directory = /tmp/patches - Target options > Target Architecture = arm - Target options > Architecture level = armv6 -- (+) - Target options > Floating point = software (no FPU) -- (\*) - Operating System > Target OS = linux - Operating System > Linux kernel version = 3.2.72 -- Precise kernel -- C-library > glibc version = 2.14.1 -- C compiler > gcc version = 4.9.3 +- C-library > glibc version = 2.16.0 +- C compiler > gcc version = 5.2.0 - C compiler > C++ = ENABLE -- to cross compile LLVM ### `arm-linux-gnueabihf.config` @@ -145,6 +147,8 @@ For targets: `arm-unknown-linux-gnueabi` For targets: `arm-unknown-linux-gnueabihf` - Path and misc options > Prefix directory = /x-tools/${CT\_TARGET} +- Path and misc options > Patches origin = Bundled, then local +- Path and misc options > Local patch directory = /tmp/patches - Target options > Target Architecture = arm - Target options > Architecture level = armv6 -- (+) - Target options > Use specific FPU = vfp -- (+) @@ -152,8 +156,8 @@ For targets: `arm-unknown-linux-gnueabihf` - Target options > Default instruction set mode = arm -- (+) - Operating System > Target OS = linux - Operating System > Linux kernel version = 3.2.72 -- Precise kernel -- C-library > glibc version = 2.14.1 -- C compiler > gcc version = 4.9.3 +- C-library > glibc version = 2.16.0 +- C compiler > gcc version = 5.2.0 - C compiler > C++ = ENABLE -- to cross compile LLVM ### `armv7-linux-gnueabihf.config` @@ -161,6 +165,8 @@ For targets: `arm-unknown-linux-gnueabihf` For targets: `armv7-unknown-linux-gnueabihf` - Path and misc options > Prefix directory = /x-tools/${CT\_TARGET} +- Path and misc options > Patches origin = Bundled, then local +- Path and misc options > Local patch directory = /tmp/patches - Target options > Target Architecture = arm - Target options > Suffix to the arch-part = v7 - Target options > Architecture level = armv7-a -- (+) @@ -169,8 +175,8 @@ For targets: `armv7-unknown-linux-gnueabihf` - Target options > Default instruction set mode = thumb -- (\*) - Operating System > Target OS = linux - Operating System > Linux kernel version = 3.2.72 -- Precise kernel -- C-library > glibc version = 2.14.1 -- C compiler > gcc version = 4.9.3 +- C-library > glibc version = 2.16.0 +- C compiler > gcc version = 5.2.0 - C compiler > C++ = ENABLE -- to cross compile LLVM (\*) These options have been selected to match the configuration of the arm @@ -204,7 +210,7 @@ For targets: `powerpc-unknown-linux-gnu` - Operating System > Target OS = linux - Operating System > Linux kernel version = 2.6.32.68 -- ~RHEL6 kernel - C-library > glibc version = 2.12.2 -- ~RHEL6 glibc -- C compiler > gcc version = 4.9.3 +- C compiler > gcc version = 5.2.0 - C compiler > C++ = ENABLE -- to cross compile LLVM ### `powerpc64-linux-gnu.config` @@ -221,7 +227,7 @@ For targets: `powerpc64-unknown-linux-gnu` - Operating System > Target OS = linux - Operating System > Linux kernel version = 2.6.32.68 -- ~RHEL6 kernel - C-library > glibc version = 2.12.2 -- ~RHEL6 glibc -- C compiler > gcc version = 4.9.3 +- C compiler > gcc version = 5.2.0 - C compiler > C++ = ENABLE -- to cross compile LLVM (+) These CPU options match the configuration of the toolchains in RHEL6. @@ -232,12 +238,12 @@ For targets: `s390x-unknown-linux-gnu` - Path and misc options > Prefix directory = /x-tools/${CT\_TARGET} - Path and misc options > Patches origin = Bundled, then local -- Path and misc options > Local patch directory = /build/patches +- Path and misc options > Local patch directory = /tmp/patches - Target options > Target Architecture = s390 - Target options > Bitness = 64-bit - Operating System > Target OS = linux - Operating System > Linux kernel version = 2.6.32.68 -- ~RHEL6 kernel - C-library > glibc version = 2.12.2 -- ~RHEL6 glibc -- C compiler > gcc version = 4.9.3 +- C compiler > gcc version = 5.2.0 - C compiler > gcc extra config = --with-arch=z10 -- LLVM's minimum support - C compiler > C++ = ENABLE -- to cross compile LLVM diff --git a/src/ci/docker/dist-arm-linux/Dockerfile b/src/ci/docker/dist-arm-linux/Dockerfile index 6ddc5c1e04ae3..48851ae232c99 100644 --- a/src/ci/docker/dist-arm-linux/Dockerfile +++ b/src/ci/docker/dist-arm-linux/Dockerfile @@ -16,6 +16,7 @@ RUN sh /scripts/rustbuild-setup.sh USER rustbuild WORKDIR /tmp +COPY dist-arm-linux/patches/ /tmp/patches/ COPY dist-arm-linux/arm-linux-gnueabi.config dist-arm-linux/build-toolchains.sh /tmp/ RUN ./build-toolchains.sh diff --git a/src/ci/docker/dist-arm-linux/arm-linux-gnueabi.config b/src/ci/docker/dist-arm-linux/arm-linux-gnueabi.config index f73ad069550e1..4185112d8be90 100644 --- a/src/ci/docker/dist-arm-linux/arm-linux-gnueabi.config +++ b/src/ci/docker/dist-arm-linux/arm-linux-gnueabi.config @@ -3,6 +3,7 @@ # Crosstool-NG Configuration # CT_CONFIGURE_has_make381=y +CT_CONFIGURE_has_xz=y CT_MODULES=y # @@ -44,14 +45,16 @@ CT_CONNECT_TIMEOUT=10 # CT_FORCE_EXTRACT is not set CT_OVERIDE_CONFIG_GUESS_SUB=y # CT_ONLY_EXTRACT is not set -CT_PATCH_BUNDLED=y +# CT_PATCH_BUNDLED is not set # CT_PATCH_LOCAL is not set -# CT_PATCH_BUNDLED_LOCAL is not set +CT_PATCH_BUNDLED_LOCAL=y # CT_PATCH_LOCAL_BUNDLED is not set # CT_PATCH_BUNDLED_FALLBACK_LOCAL is not set # CT_PATCH_LOCAL_FALLBACK_BUNDLED is not set # CT_PATCH_NONE is not set -CT_PATCH_ORDER="bundled" +CT_PATCH_ORDER="bundled,local" +CT_PATCH_USE_LOCAL=y +CT_LOCAL_PATCH_DIR="/tmp/patches" # # Build behavior @@ -391,8 +394,8 @@ CT_CC_CORE_PASS_1_NEEDED=y CT_CC_CORE_PASS_2_NEEDED=y CT_CC_gcc=y # CT_CC_GCC_SHOW_LINARO is not set -# CT_CC_GCC_V_5_2_0 is not set -CT_CC_GCC_V_4_9_3=y +CT_CC_GCC_V_5_2_0=y +# CT_CC_GCC_V_4_9_3 is not set # CT_CC_GCC_V_4_8_5 is not set # CT_CC_GCC_V_4_7_4 is not set # CT_CC_GCC_V_4_6_4 is not set @@ -407,8 +410,9 @@ CT_CC_GCC_4_5_or_later=y CT_CC_GCC_4_6_or_later=y CT_CC_GCC_4_7_or_later=y CT_CC_GCC_4_8_or_later=y -CT_CC_GCC_4_9=y CT_CC_GCC_4_9_or_later=y +CT_CC_GCC_5=y +CT_CC_GCC_5_or_later=y CT_CC_GCC_HAS_GRAPHITE=y CT_CC_GCC_USE_GRAPHITE=y CT_CC_GCC_HAS_LTO=y @@ -420,7 +424,7 @@ CT_CC_GCC_USE_GMP_MPFR=y CT_CC_GCC_USE_MPC=y CT_CC_GCC_HAS_LIBQUADMATH=y CT_CC_GCC_HAS_LIBSANITIZER=y -CT_CC_GCC_VERSION="4.9.3" +CT_CC_GCC_VERSION="5.2.0" # CT_CC_LANG_FORTRAN is not set CT_CC_GCC_ENABLE_CXX_FLAGS="" CT_CC_GCC_CORE_EXTRA_CONFIG_ARRAY="" @@ -492,7 +496,6 @@ CT_GETTEXT_NEEDED=y CT_GMP_NEEDED=y CT_MPFR_NEEDED=y CT_ISL_NEEDED=y -CT_CLOOG_NEEDED=y CT_MPC_NEEDED=y CT_COMPLIBS=y CT_LIBICONV=y @@ -500,7 +503,6 @@ CT_GETTEXT=y CT_GMP=y CT_MPFR=y CT_ISL=y -CT_CLOOG=y CT_MPC=y CT_LIBICONV_V_1_14=y CT_LIBICONV_VERSION="1.14" @@ -526,15 +528,13 @@ CT_MPFR_V_3_1_3=y # CT_MPFR_V_2_4_0 is not set CT_MPFR_VERSION="3.1.3" CT_ISL_V_0_14=y +# CT_ISL_V_0_12_2 is not set CT_ISL_V_0_14_or_later=y CT_ISL_V_0_12_or_later=y CT_ISL_VERSION="0.14" -CT_CLOOG_V_0_18_4=y +# CT_CLOOG_V_0_18_4 is not set # CT_CLOOG_V_0_18_1 is not set # CT_CLOOG_V_0_18_0 is not set -CT_CLOOG_VERSION="0.18.4" -CT_CLOOG_0_18_4_or_later=y -CT_CLOOG_0_18_or_later=y CT_MPC_V_1_0_3=y # CT_MPC_V_1_0_2 is not set # CT_MPC_V_1_0_1 is not set diff --git a/src/ci/docker/dist-arm-linux/patches/glibc/ports-2.16.0/001-arm-libgcc_s_resume-used.patch b/src/ci/docker/dist-arm-linux/patches/glibc/ports-2.16.0/001-arm-libgcc_s_resume-used.patch new file mode 100644 index 0000000000000..871d5225c0f71 --- /dev/null +++ b/src/ci/docker/dist-arm-linux/patches/glibc/ports-2.16.0/001-arm-libgcc_s_resume-used.patch @@ -0,0 +1,48 @@ +commit bdb24c2851fd5f0ad9b82d7ea1db911d334b02d2 +Author: Joseph Myers +Date: Tue May 20 21:27:13 2014 +0000 + + Fix ARM build with GCC trunk. + + sysdeps/unix/sysv/linux/arm/unwind-resume.c and + sysdeps/unix/sysv/linux/arm/unwind-forcedunwind.c have static + variables that are written in C code but only read from toplevel asms. + Current GCC trunk now optimizes away such apparently write-only static + variables, so causing a build failure. This patch marks those + variables with __attribute_used__ to avoid that optimization. + + Tested that this fixes the build for ARM. + + * sysdeps/unix/sysv/linux/arm/unwind-forcedunwind.c + (libgcc_s_resume): Use __attribute_used__. + * sysdeps/unix/sysv/linux/arm/unwind-resume.c (libgcc_s_resume): + Likewise. + +diff --git a/sysdeps/unix/sysv/linux/arm/nptl/unwind-forcedunwind.c b/sysdeps/unix/sysv/linux/arm/nptl/unwind-forcedunwind.c +index 29e2c2b00b04..e848bfeffdcb 100644 +--- a/ports/sysdeps/unix/sysv/linux/arm/nptl/unwind-forcedunwind.c ++++ b/ports/sysdeps/unix/sysv/linux/arm/nptl/unwind-forcedunwind.c +@@ -22,7 +22,8 @@ + #include + + static void *libgcc_s_handle; +-static void (*libgcc_s_resume) (struct _Unwind_Exception *exc); ++static void (*libgcc_s_resume) (struct _Unwind_Exception *exc) ++ __attribute_used__; + static _Unwind_Reason_Code (*libgcc_s_personality) + (_Unwind_State, struct _Unwind_Exception *, struct _Unwind_Context *); + static _Unwind_Reason_Code (*libgcc_s_forcedunwind) +diff --git a/sysdeps/unix/sysv/linux/arm/nptl/unwind-resume.c b/sysdeps/unix/sysv/linux/arm/nptl/unwind-resume.c +index 285b99b5ed0d..48d00fc83641 100644 +--- a/ports/sysdeps/unix/sysv/linux/arm/nptl/unwind-resume.c ++++ b/ports/sysdeps/unix/sysv/linux/arm/nptl/unwind-resume.c +@@ -20,7 +20,8 @@ + #include + #include + +-static void (*libgcc_s_resume) (struct _Unwind_Exception *exc); ++static void (*libgcc_s_resume) (struct _Unwind_Exception *exc) ++ __attribute_used__; + static _Unwind_Reason_Code (*libgcc_s_personality) + (_Unwind_State, struct _Unwind_Exception *, struct _Unwind_Context *); + diff --git a/src/ci/docker/dist-armhf-linux/Dockerfile b/src/ci/docker/dist-armhf-linux/Dockerfile index e4d4b2feeec40..d1dd9faaa1035 100644 --- a/src/ci/docker/dist-armhf-linux/Dockerfile +++ b/src/ci/docker/dist-armhf-linux/Dockerfile @@ -16,6 +16,7 @@ RUN sh /scripts/rustbuild-setup.sh USER rustbuild WORKDIR /tmp +COPY dist-armhf-linux/patches/ /tmp/patches/ COPY dist-armhf-linux/arm-linux-gnueabihf.config dist-armhf-linux/build-toolchains.sh /tmp/ RUN ./build-toolchains.sh diff --git a/src/ci/docker/dist-armhf-linux/arm-linux-gnueabihf.config b/src/ci/docker/dist-armhf-linux/arm-linux-gnueabihf.config index 1feeef1555749..bebbcd1670a5e 100644 --- a/src/ci/docker/dist-armhf-linux/arm-linux-gnueabihf.config +++ b/src/ci/docker/dist-armhf-linux/arm-linux-gnueabihf.config @@ -3,6 +3,7 @@ # Crosstool-NG Configuration # CT_CONFIGURE_has_make381=y +CT_CONFIGURE_has_xz=y CT_MODULES=y # @@ -44,14 +45,16 @@ CT_CONNECT_TIMEOUT=10 # CT_FORCE_EXTRACT is not set CT_OVERIDE_CONFIG_GUESS_SUB=y # CT_ONLY_EXTRACT is not set -CT_PATCH_BUNDLED=y +# CT_PATCH_BUNDLED is not set # CT_PATCH_LOCAL is not set -# CT_PATCH_BUNDLED_LOCAL is not set +CT_PATCH_BUNDLED_LOCAL=y # CT_PATCH_LOCAL_BUNDLED is not set # CT_PATCH_BUNDLED_FALLBACK_LOCAL is not set # CT_PATCH_LOCAL_FALLBACK_BUNDLED is not set # CT_PATCH_NONE is not set -CT_PATCH_ORDER="bundled" +CT_PATCH_ORDER="bundled,local" +CT_PATCH_USE_LOCAL=y +CT_LOCAL_PATCH_DIR="/tmp/patches" # # Build behavior @@ -392,8 +395,8 @@ CT_CC_CORE_PASS_1_NEEDED=y CT_CC_CORE_PASS_2_NEEDED=y CT_CC_gcc=y # CT_CC_GCC_SHOW_LINARO is not set -# CT_CC_GCC_V_5_2_0 is not set -CT_CC_GCC_V_4_9_3=y +CT_CC_GCC_V_5_2_0=y +# CT_CC_GCC_V_4_9_3 is not set # CT_CC_GCC_V_4_8_5 is not set # CT_CC_GCC_V_4_7_4 is not set # CT_CC_GCC_V_4_6_4 is not set @@ -408,8 +411,9 @@ CT_CC_GCC_4_5_or_later=y CT_CC_GCC_4_6_or_later=y CT_CC_GCC_4_7_or_later=y CT_CC_GCC_4_8_or_later=y -CT_CC_GCC_4_9=y CT_CC_GCC_4_9_or_later=y +CT_CC_GCC_5=y +CT_CC_GCC_5_or_later=y CT_CC_GCC_HAS_GRAPHITE=y CT_CC_GCC_USE_GRAPHITE=y CT_CC_GCC_HAS_LTO=y @@ -421,7 +425,7 @@ CT_CC_GCC_USE_GMP_MPFR=y CT_CC_GCC_USE_MPC=y CT_CC_GCC_HAS_LIBQUADMATH=y CT_CC_GCC_HAS_LIBSANITIZER=y -CT_CC_GCC_VERSION="4.9.3" +CT_CC_GCC_VERSION="5.2.0" # CT_CC_LANG_FORTRAN is not set CT_CC_GCC_ENABLE_CXX_FLAGS="" CT_CC_GCC_CORE_EXTRA_CONFIG_ARRAY="" @@ -493,7 +497,6 @@ CT_GETTEXT_NEEDED=y CT_GMP_NEEDED=y CT_MPFR_NEEDED=y CT_ISL_NEEDED=y -CT_CLOOG_NEEDED=y CT_MPC_NEEDED=y CT_COMPLIBS=y CT_LIBICONV=y @@ -501,7 +504,6 @@ CT_GETTEXT=y CT_GMP=y CT_MPFR=y CT_ISL=y -CT_CLOOG=y CT_MPC=y CT_LIBICONV_V_1_14=y CT_LIBICONV_VERSION="1.14" @@ -527,15 +529,13 @@ CT_MPFR_V_3_1_3=y # CT_MPFR_V_2_4_0 is not set CT_MPFR_VERSION="3.1.3" CT_ISL_V_0_14=y +# CT_ISL_V_0_12_2 is not set CT_ISL_V_0_14_or_later=y CT_ISL_V_0_12_or_later=y CT_ISL_VERSION="0.14" -CT_CLOOG_V_0_18_4=y +# CT_CLOOG_V_0_18_4 is not set # CT_CLOOG_V_0_18_1 is not set # CT_CLOOG_V_0_18_0 is not set -CT_CLOOG_VERSION="0.18.4" -CT_CLOOG_0_18_4_or_later=y -CT_CLOOG_0_18_or_later=y CT_MPC_V_1_0_3=y # CT_MPC_V_1_0_2 is not set # CT_MPC_V_1_0_1 is not set diff --git a/src/ci/docker/dist-armhf-linux/patches/glibc/ports-2.16.0/001-arm-libgcc_s_resume-used.patch b/src/ci/docker/dist-armhf-linux/patches/glibc/ports-2.16.0/001-arm-libgcc_s_resume-used.patch new file mode 100644 index 0000000000000..871d5225c0f71 --- /dev/null +++ b/src/ci/docker/dist-armhf-linux/patches/glibc/ports-2.16.0/001-arm-libgcc_s_resume-used.patch @@ -0,0 +1,48 @@ +commit bdb24c2851fd5f0ad9b82d7ea1db911d334b02d2 +Author: Joseph Myers +Date: Tue May 20 21:27:13 2014 +0000 + + Fix ARM build with GCC trunk. + + sysdeps/unix/sysv/linux/arm/unwind-resume.c and + sysdeps/unix/sysv/linux/arm/unwind-forcedunwind.c have static + variables that are written in C code but only read from toplevel asms. + Current GCC trunk now optimizes away such apparently write-only static + variables, so causing a build failure. This patch marks those + variables with __attribute_used__ to avoid that optimization. + + Tested that this fixes the build for ARM. + + * sysdeps/unix/sysv/linux/arm/unwind-forcedunwind.c + (libgcc_s_resume): Use __attribute_used__. + * sysdeps/unix/sysv/linux/arm/unwind-resume.c (libgcc_s_resume): + Likewise. + +diff --git a/sysdeps/unix/sysv/linux/arm/nptl/unwind-forcedunwind.c b/sysdeps/unix/sysv/linux/arm/nptl/unwind-forcedunwind.c +index 29e2c2b00b04..e848bfeffdcb 100644 +--- a/ports/sysdeps/unix/sysv/linux/arm/nptl/unwind-forcedunwind.c ++++ b/ports/sysdeps/unix/sysv/linux/arm/nptl/unwind-forcedunwind.c +@@ -22,7 +22,8 @@ + #include + + static void *libgcc_s_handle; +-static void (*libgcc_s_resume) (struct _Unwind_Exception *exc); ++static void (*libgcc_s_resume) (struct _Unwind_Exception *exc) ++ __attribute_used__; + static _Unwind_Reason_Code (*libgcc_s_personality) + (_Unwind_State, struct _Unwind_Exception *, struct _Unwind_Context *); + static _Unwind_Reason_Code (*libgcc_s_forcedunwind) +diff --git a/sysdeps/unix/sysv/linux/arm/nptl/unwind-resume.c b/sysdeps/unix/sysv/linux/arm/nptl/unwind-resume.c +index 285b99b5ed0d..48d00fc83641 100644 +--- a/ports/sysdeps/unix/sysv/linux/arm/nptl/unwind-resume.c ++++ b/ports/sysdeps/unix/sysv/linux/arm/nptl/unwind-resume.c +@@ -20,7 +20,8 @@ + #include + #include + +-static void (*libgcc_s_resume) (struct _Unwind_Exception *exc); ++static void (*libgcc_s_resume) (struct _Unwind_Exception *exc) ++ __attribute_used__; + static _Unwind_Reason_Code (*libgcc_s_personality) + (_Unwind_State, struct _Unwind_Exception *, struct _Unwind_Context *); + diff --git a/src/ci/docker/dist-armv7-linux/Dockerfile b/src/ci/docker/dist-armv7-linux/Dockerfile index 99fe7bd7b8f78..170b8134d3edc 100644 --- a/src/ci/docker/dist-armv7-linux/Dockerfile +++ b/src/ci/docker/dist-armv7-linux/Dockerfile @@ -16,6 +16,7 @@ RUN sh /scripts/rustbuild-setup.sh USER rustbuild WORKDIR /tmp +COPY dist-armv7-linux/patches/ /tmp/patches/ COPY dist-armv7-linux/build-toolchains.sh dist-armv7-linux/armv7-linux-gnueabihf.config /tmp/ RUN ./build-toolchains.sh diff --git a/src/ci/docker/dist-armv7-linux/armv7-linux-gnueabihf.config b/src/ci/docker/dist-armv7-linux/armv7-linux-gnueabihf.config index 79d6c77c41152..5cccfd8444d35 100644 --- a/src/ci/docker/dist-armv7-linux/armv7-linux-gnueabihf.config +++ b/src/ci/docker/dist-armv7-linux/armv7-linux-gnueabihf.config @@ -3,6 +3,7 @@ # Crosstool-NG Configuration # CT_CONFIGURE_has_make381=y +CT_CONFIGURE_has_xz=y CT_MODULES=y # @@ -44,14 +45,16 @@ CT_CONNECT_TIMEOUT=10 # CT_FORCE_EXTRACT is not set CT_OVERIDE_CONFIG_GUESS_SUB=y # CT_ONLY_EXTRACT is not set -CT_PATCH_BUNDLED=y +# CT_PATCH_BUNDLED is not set # CT_PATCH_LOCAL is not set -# CT_PATCH_BUNDLED_LOCAL is not set +CT_PATCH_BUNDLED_LOCAL=y # CT_PATCH_LOCAL_BUNDLED is not set # CT_PATCH_BUNDLED_FALLBACK_LOCAL is not set # CT_PATCH_LOCAL_FALLBACK_BUNDLED is not set # CT_PATCH_NONE is not set -CT_PATCH_ORDER="bundled" +CT_PATCH_ORDER="bundled,local" +CT_PATCH_USE_LOCAL=y +CT_LOCAL_PATCH_DIR="/tmp/patches" # # Build behavior @@ -155,12 +158,6 @@ CT_ARCH_EXCLUSIVE_WITH_CPU=y # CT_ARCH_FLOAT_AUTO is not set # CT_ARCH_FLOAT_SOFTFP is not set CT_ARCH_FLOAT="hard" -# CT_ARCH_ALPHA_EV4 is not set -# CT_ARCH_ALPHA_EV45 is not set -# CT_ARCH_ALPHA_EV5 is not set -# CT_ARCH_ALPHA_EV56 is not set -# CT_ARCH_ALPHA_EV6 is not set -# CT_ARCH_ALPHA_EV67 is not set # # arm other options @@ -311,8 +308,6 @@ CT_LIBC="glibc" CT_LIBC_VERSION="2.16.0" CT_LIBC_glibc=y # CT_LIBC_musl is not set -# CT_LIBC_newlib is not set -# CT_LIBC_none is not set # CT_LIBC_uClibc is not set CT_LIBC_avr_libc_AVAILABLE=y CT_LIBC_glibc_AVAILABLE=y @@ -400,8 +395,8 @@ CT_CC_CORE_PASS_1_NEEDED=y CT_CC_CORE_PASS_2_NEEDED=y CT_CC_gcc=y # CT_CC_GCC_SHOW_LINARO is not set -# CT_CC_GCC_V_5_2_0 is not set -CT_CC_GCC_V_4_9_3=y +CT_CC_GCC_V_5_2_0=y +# CT_CC_GCC_V_4_9_3 is not set # CT_CC_GCC_V_4_8_5 is not set # CT_CC_GCC_V_4_7_4 is not set # CT_CC_GCC_V_4_6_4 is not set @@ -416,8 +411,9 @@ CT_CC_GCC_4_5_or_later=y CT_CC_GCC_4_6_or_later=y CT_CC_GCC_4_7_or_later=y CT_CC_GCC_4_8_or_later=y -CT_CC_GCC_4_9=y CT_CC_GCC_4_9_or_later=y +CT_CC_GCC_5=y +CT_CC_GCC_5_or_later=y CT_CC_GCC_HAS_GRAPHITE=y CT_CC_GCC_USE_GRAPHITE=y CT_CC_GCC_HAS_LTO=y @@ -429,7 +425,7 @@ CT_CC_GCC_USE_GMP_MPFR=y CT_CC_GCC_USE_MPC=y CT_CC_GCC_HAS_LIBQUADMATH=y CT_CC_GCC_HAS_LIBSANITIZER=y -CT_CC_GCC_VERSION="4.9.3" +CT_CC_GCC_VERSION="5.2.0" # CT_CC_LANG_FORTRAN is not set CT_CC_GCC_ENABLE_CXX_FLAGS="" CT_CC_GCC_CORE_EXTRA_CONFIG_ARRAY="" @@ -501,7 +497,6 @@ CT_GETTEXT_NEEDED=y CT_GMP_NEEDED=y CT_MPFR_NEEDED=y CT_ISL_NEEDED=y -CT_CLOOG_NEEDED=y CT_MPC_NEEDED=y CT_COMPLIBS=y CT_LIBICONV=y @@ -509,7 +504,6 @@ CT_GETTEXT=y CT_GMP=y CT_MPFR=y CT_ISL=y -CT_CLOOG=y CT_MPC=y CT_LIBICONV_V_1_14=y CT_LIBICONV_VERSION="1.14" @@ -535,15 +529,13 @@ CT_MPFR_V_3_1_3=y # CT_MPFR_V_2_4_0 is not set CT_MPFR_VERSION="3.1.3" CT_ISL_V_0_14=y +# CT_ISL_V_0_12_2 is not set CT_ISL_V_0_14_or_later=y CT_ISL_V_0_12_or_later=y CT_ISL_VERSION="0.14" -CT_CLOOG_V_0_18_4=y +# CT_CLOOG_V_0_18_4 is not set # CT_CLOOG_V_0_18_1 is not set # CT_CLOOG_V_0_18_0 is not set -CT_CLOOG_VERSION="0.18.4" -CT_CLOOG_0_18_4_or_later=y -CT_CLOOG_0_18_or_later=y CT_MPC_V_1_0_3=y # CT_MPC_V_1_0_2 is not set # CT_MPC_V_1_0_1 is not set diff --git a/src/ci/docker/dist-armv7-linux/patches/glibc/ports-2.16.0/001-arm-libgcc_s_resume-used.patch b/src/ci/docker/dist-armv7-linux/patches/glibc/ports-2.16.0/001-arm-libgcc_s_resume-used.patch new file mode 100644 index 0000000000000..871d5225c0f71 --- /dev/null +++ b/src/ci/docker/dist-armv7-linux/patches/glibc/ports-2.16.0/001-arm-libgcc_s_resume-used.patch @@ -0,0 +1,48 @@ +commit bdb24c2851fd5f0ad9b82d7ea1db911d334b02d2 +Author: Joseph Myers +Date: Tue May 20 21:27:13 2014 +0000 + + Fix ARM build with GCC trunk. + + sysdeps/unix/sysv/linux/arm/unwind-resume.c and + sysdeps/unix/sysv/linux/arm/unwind-forcedunwind.c have static + variables that are written in C code but only read from toplevel asms. + Current GCC trunk now optimizes away such apparently write-only static + variables, so causing a build failure. This patch marks those + variables with __attribute_used__ to avoid that optimization. + + Tested that this fixes the build for ARM. + + * sysdeps/unix/sysv/linux/arm/unwind-forcedunwind.c + (libgcc_s_resume): Use __attribute_used__. + * sysdeps/unix/sysv/linux/arm/unwind-resume.c (libgcc_s_resume): + Likewise. + +diff --git a/sysdeps/unix/sysv/linux/arm/nptl/unwind-forcedunwind.c b/sysdeps/unix/sysv/linux/arm/nptl/unwind-forcedunwind.c +index 29e2c2b00b04..e848bfeffdcb 100644 +--- a/ports/sysdeps/unix/sysv/linux/arm/nptl/unwind-forcedunwind.c ++++ b/ports/sysdeps/unix/sysv/linux/arm/nptl/unwind-forcedunwind.c +@@ -22,7 +22,8 @@ + #include + + static void *libgcc_s_handle; +-static void (*libgcc_s_resume) (struct _Unwind_Exception *exc); ++static void (*libgcc_s_resume) (struct _Unwind_Exception *exc) ++ __attribute_used__; + static _Unwind_Reason_Code (*libgcc_s_personality) + (_Unwind_State, struct _Unwind_Exception *, struct _Unwind_Context *); + static _Unwind_Reason_Code (*libgcc_s_forcedunwind) +diff --git a/sysdeps/unix/sysv/linux/arm/nptl/unwind-resume.c b/sysdeps/unix/sysv/linux/arm/nptl/unwind-resume.c +index 285b99b5ed0d..48d00fc83641 100644 +--- a/ports/sysdeps/unix/sysv/linux/arm/nptl/unwind-resume.c ++++ b/ports/sysdeps/unix/sysv/linux/arm/nptl/unwind-resume.c +@@ -20,7 +20,8 @@ + #include + #include + +-static void (*libgcc_s_resume) (struct _Unwind_Exception *exc); ++static void (*libgcc_s_resume) (struct _Unwind_Exception *exc) ++ __attribute_used__; + static _Unwind_Reason_Code (*libgcc_s_personality) + (_Unwind_State, struct _Unwind_Exception *, struct _Unwind_Context *); + diff --git a/src/ci/docker/dist-powerpc-linux/patches/glibc/2.12.2/002-newer-gcc.patch b/src/ci/docker/dist-powerpc-linux/patches/glibc/2.12.2/002-newer-gcc.patch new file mode 100644 index 0000000000000..a96b4882c2d57 --- /dev/null +++ b/src/ci/docker/dist-powerpc-linux/patches/glibc/2.12.2/002-newer-gcc.patch @@ -0,0 +1,26 @@ +diff --git a/configure b/configure +index b6752d147c6b..6089a3403410 100755 +--- a/configure ++++ b/configure +@@ -5079,7 +5079,7 @@ $as_echo_n "checking version of $CC... " >&6; } + ac_prog_version=`$CC -v 2>&1 | sed -n 's/^.*version \([egcygnustpi-]*[0-9.]*\).*$/\1/p'` + case $ac_prog_version in + '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;; +- 3.4* | 4.[0-9]* ) ++ 3.4* | [4-9].* ) + ac_prog_version="$ac_prog_version, ok"; ac_verc_fail=no;; + *) ac_prog_version="$ac_prog_version, bad"; ac_verc_fail=yes;; + +diff --git a/configure.in b/configure.in +index 56849dfc489a..09677eb3d0c1 100644 +--- a/configure.in ++++ b/configure.in +@@ -960,7 +960,7 @@ fi + # These programs are version sensitive. + AC_CHECK_TOOL_PREFIX + AC_CHECK_PROG_VER(CC, ${ac_tool_prefix}gcc ${ac_tool_prefix}cc, -v, +- [version \([egcygnustpi-]*[0-9.]*\)], [3.4* | 4.[0-9]* ], ++ [version \([egcygnustpi-]*[0-9.]*\)], [3.4* | [4-9].* ], + critic_missing="$critic_missing gcc") + AC_CHECK_PROG_VER(MAKE, gnumake gmake make, --version, + [GNU Make[^0-9]*\([0-9][0-9.]*\)], diff --git a/src/ci/docker/dist-powerpc-linux/powerpc-linux-gnu.config b/src/ci/docker/dist-powerpc-linux/powerpc-linux-gnu.config index 984a0a0304e47..7df41da2bf76e 100644 --- a/src/ci/docker/dist-powerpc-linux/powerpc-linux-gnu.config +++ b/src/ci/docker/dist-powerpc-linux/powerpc-linux-gnu.config @@ -359,8 +359,8 @@ CT_CC_CORE_PASS_1_NEEDED=y CT_CC_CORE_PASS_2_NEEDED=y CT_CC_gcc=y # CT_CC_GCC_SHOW_LINARO is not set -# CT_CC_GCC_V_5_2_0 is not set -CT_CC_GCC_V_4_9_3=y +CT_CC_GCC_V_5_2_0=y +# CT_CC_GCC_V_4_9_3 is not set # CT_CC_GCC_V_4_8_5 is not set # CT_CC_GCC_V_4_7_4 is not set # CT_CC_GCC_V_4_6_4 is not set @@ -375,8 +375,9 @@ CT_CC_GCC_4_5_or_later=y CT_CC_GCC_4_6_or_later=y CT_CC_GCC_4_7_or_later=y CT_CC_GCC_4_8_or_later=y -CT_CC_GCC_4_9=y CT_CC_GCC_4_9_or_later=y +CT_CC_GCC_5=y +CT_CC_GCC_5_or_later=y CT_CC_GCC_HAS_GRAPHITE=y CT_CC_GCC_USE_GRAPHITE=y CT_CC_GCC_HAS_LTO=y @@ -388,7 +389,7 @@ CT_CC_GCC_USE_GMP_MPFR=y CT_CC_GCC_USE_MPC=y CT_CC_GCC_HAS_LIBQUADMATH=y CT_CC_GCC_HAS_LIBSANITIZER=y -CT_CC_GCC_VERSION="4.9.3" +CT_CC_GCC_VERSION="5.2.0" # CT_CC_LANG_FORTRAN is not set CT_CC_GCC_ENABLE_CXX_FLAGS="" CT_CC_GCC_CORE_EXTRA_CONFIG_ARRAY="" @@ -460,7 +461,6 @@ CT_GETTEXT_NEEDED=y CT_GMP_NEEDED=y CT_MPFR_NEEDED=y CT_ISL_NEEDED=y -CT_CLOOG_NEEDED=y CT_MPC_NEEDED=y CT_COMPLIBS=y CT_LIBICONV=y @@ -468,7 +468,6 @@ CT_GETTEXT=y CT_GMP=y CT_MPFR=y CT_ISL=y -CT_CLOOG=y CT_MPC=y CT_LIBICONV_V_1_14=y CT_LIBICONV_VERSION="1.14" @@ -494,15 +493,13 @@ CT_MPFR_V_3_1_3=y # CT_MPFR_V_2_4_0 is not set CT_MPFR_VERSION="3.1.3" CT_ISL_V_0_14=y +# CT_ISL_V_0_12_2 is not set CT_ISL_V_0_14_or_later=y CT_ISL_V_0_12_or_later=y CT_ISL_VERSION="0.14" -CT_CLOOG_V_0_18_4=y +# CT_CLOOG_V_0_18_4 is not set # CT_CLOOG_V_0_18_1 is not set # CT_CLOOG_V_0_18_0 is not set -CT_CLOOG_VERSION="0.18.4" -CT_CLOOG_0_18_4_or_later=y -CT_CLOOG_0_18_or_later=y CT_MPC_V_1_0_3=y # CT_MPC_V_1_0_2 is not set # CT_MPC_V_1_0_1 is not set diff --git a/src/ci/docker/dist-powerpc64-linux/patches/glibc/2.12.2/003-newer-gcc.patch b/src/ci/docker/dist-powerpc64-linux/patches/glibc/2.12.2/003-newer-gcc.patch new file mode 100644 index 0000000000000..a96b4882c2d57 --- /dev/null +++ b/src/ci/docker/dist-powerpc64-linux/patches/glibc/2.12.2/003-newer-gcc.patch @@ -0,0 +1,26 @@ +diff --git a/configure b/configure +index b6752d147c6b..6089a3403410 100755 +--- a/configure ++++ b/configure +@@ -5079,7 +5079,7 @@ $as_echo_n "checking version of $CC... " >&6; } + ac_prog_version=`$CC -v 2>&1 | sed -n 's/^.*version \([egcygnustpi-]*[0-9.]*\).*$/\1/p'` + case $ac_prog_version in + '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;; +- 3.4* | 4.[0-9]* ) ++ 3.4* | [4-9].* ) + ac_prog_version="$ac_prog_version, ok"; ac_verc_fail=no;; + *) ac_prog_version="$ac_prog_version, bad"; ac_verc_fail=yes;; + +diff --git a/configure.in b/configure.in +index 56849dfc489a..09677eb3d0c1 100644 +--- a/configure.in ++++ b/configure.in +@@ -960,7 +960,7 @@ fi + # These programs are version sensitive. + AC_CHECK_TOOL_PREFIX + AC_CHECK_PROG_VER(CC, ${ac_tool_prefix}gcc ${ac_tool_prefix}cc, -v, +- [version \([egcygnustpi-]*[0-9.]*\)], [3.4* | 4.[0-9]* ], ++ [version \([egcygnustpi-]*[0-9.]*\)], [3.4* | [4-9].* ], + critic_missing="$critic_missing gcc") + AC_CHECK_PROG_VER(MAKE, gnumake gmake make, --version, + [GNU Make[^0-9]*\([0-9][0-9.]*\)], diff --git a/src/ci/docker/dist-powerpc64-linux/powerpc64-linux-gnu.config b/src/ci/docker/dist-powerpc64-linux/powerpc64-linux-gnu.config index c2d02ee85cf25..4aab4f4fd4445 100644 --- a/src/ci/docker/dist-powerpc64-linux/powerpc64-linux-gnu.config +++ b/src/ci/docker/dist-powerpc64-linux/powerpc64-linux-gnu.config @@ -359,8 +359,8 @@ CT_CC_CORE_PASS_1_NEEDED=y CT_CC_CORE_PASS_2_NEEDED=y CT_CC_gcc=y # CT_CC_GCC_SHOW_LINARO is not set -# CT_CC_GCC_V_5_2_0 is not set -CT_CC_GCC_V_4_9_3=y +CT_CC_GCC_V_5_2_0=y +# CT_CC_GCC_V_4_9_3 is not set # CT_CC_GCC_V_4_8_5 is not set # CT_CC_GCC_V_4_7_4 is not set # CT_CC_GCC_V_4_6_4 is not set @@ -375,8 +375,9 @@ CT_CC_GCC_4_5_or_later=y CT_CC_GCC_4_6_or_later=y CT_CC_GCC_4_7_or_later=y CT_CC_GCC_4_8_or_later=y -CT_CC_GCC_4_9=y CT_CC_GCC_4_9_or_later=y +CT_CC_GCC_5=y +CT_CC_GCC_5_or_later=y CT_CC_GCC_HAS_GRAPHITE=y CT_CC_GCC_USE_GRAPHITE=y CT_CC_GCC_HAS_LTO=y @@ -388,7 +389,7 @@ CT_CC_GCC_USE_GMP_MPFR=y CT_CC_GCC_USE_MPC=y CT_CC_GCC_HAS_LIBQUADMATH=y CT_CC_GCC_HAS_LIBSANITIZER=y -CT_CC_GCC_VERSION="4.9.3" +CT_CC_GCC_VERSION="5.2.0" # CT_CC_LANG_FORTRAN is not set CT_CC_GCC_ENABLE_CXX_FLAGS="" CT_CC_GCC_CORE_EXTRA_CONFIG_ARRAY="" @@ -460,7 +461,6 @@ CT_GETTEXT_NEEDED=y CT_GMP_NEEDED=y CT_MPFR_NEEDED=y CT_ISL_NEEDED=y -CT_CLOOG_NEEDED=y CT_MPC_NEEDED=y CT_COMPLIBS=y CT_LIBICONV=y @@ -468,7 +468,6 @@ CT_GETTEXT=y CT_GMP=y CT_MPFR=y CT_ISL=y -CT_CLOOG=y CT_MPC=y CT_LIBICONV_V_1_14=y CT_LIBICONV_VERSION="1.14" @@ -494,15 +493,10 @@ CT_MPFR_V_3_1_3=y # CT_MPFR_V_2_4_0 is not set CT_MPFR_VERSION="3.1.3" CT_ISL_V_0_14=y +# CT_ISL_V_0_12_2 is not set CT_ISL_V_0_14_or_later=y CT_ISL_V_0_12_or_later=y CT_ISL_VERSION="0.14" -CT_CLOOG_V_0_18_4=y -# CT_CLOOG_V_0_18_1 is not set -# CT_CLOOG_V_0_18_0 is not set -CT_CLOOG_VERSION="0.18.4" -CT_CLOOG_0_18_4_or_later=y -CT_CLOOG_0_18_or_later=y CT_MPC_V_1_0_3=y # CT_MPC_V_1_0_2 is not set # CT_MPC_V_1_0_1 is not set diff --git a/src/ci/docker/dist-s390x-linux/patches/glibc/2.12.2/002-newer-gcc.patch b/src/ci/docker/dist-s390x-linux/patches/glibc/2.12.2/002-newer-gcc.patch new file mode 100644 index 0000000000000..a96b4882c2d57 --- /dev/null +++ b/src/ci/docker/dist-s390x-linux/patches/glibc/2.12.2/002-newer-gcc.patch @@ -0,0 +1,26 @@ +diff --git a/configure b/configure +index b6752d147c6b..6089a3403410 100755 +--- a/configure ++++ b/configure +@@ -5079,7 +5079,7 @@ $as_echo_n "checking version of $CC... " >&6; } + ac_prog_version=`$CC -v 2>&1 | sed -n 's/^.*version \([egcygnustpi-]*[0-9.]*\).*$/\1/p'` + case $ac_prog_version in + '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;; +- 3.4* | 4.[0-9]* ) ++ 3.4* | [4-9].* ) + ac_prog_version="$ac_prog_version, ok"; ac_verc_fail=no;; + *) ac_prog_version="$ac_prog_version, bad"; ac_verc_fail=yes;; + +diff --git a/configure.in b/configure.in +index 56849dfc489a..09677eb3d0c1 100644 +--- a/configure.in ++++ b/configure.in +@@ -960,7 +960,7 @@ fi + # These programs are version sensitive. + AC_CHECK_TOOL_PREFIX + AC_CHECK_PROG_VER(CC, ${ac_tool_prefix}gcc ${ac_tool_prefix}cc, -v, +- [version \([egcygnustpi-]*[0-9.]*\)], [3.4* | 4.[0-9]* ], ++ [version \([egcygnustpi-]*[0-9.]*\)], [3.4* | [4-9].* ], + critic_missing="$critic_missing gcc") + AC_CHECK_PROG_VER(MAKE, gnumake gmake make, --version, + [GNU Make[^0-9]*\([0-9][0-9.]*\)], diff --git a/src/ci/docker/dist-s390x-linux/s390x-linux-gnu.config b/src/ci/docker/dist-s390x-linux/s390x-linux-gnu.config index fa5e4510987f1..cd1c41b02e312 100644 --- a/src/ci/docker/dist-s390x-linux/s390x-linux-gnu.config +++ b/src/ci/docker/dist-s390x-linux/s390x-linux-gnu.config @@ -339,8 +339,8 @@ CT_CC_CORE_PASS_1_NEEDED=y CT_CC_CORE_PASS_2_NEEDED=y CT_CC_gcc=y # CT_CC_GCC_SHOW_LINARO is not set -# CT_CC_GCC_V_5_2_0 is not set -CT_CC_GCC_V_4_9_3=y +CT_CC_GCC_V_5_2_0=y +# CT_CC_GCC_V_4_9_3 is not set # CT_CC_GCC_V_4_8_5 is not set # CT_CC_GCC_V_4_7_4 is not set # CT_CC_GCC_V_4_6_4 is not set @@ -355,8 +355,9 @@ CT_CC_GCC_4_5_or_later=y CT_CC_GCC_4_6_or_later=y CT_CC_GCC_4_7_or_later=y CT_CC_GCC_4_8_or_later=y -CT_CC_GCC_4_9=y CT_CC_GCC_4_9_or_later=y +CT_CC_GCC_5=y +CT_CC_GCC_5_or_later=y CT_CC_GCC_HAS_GRAPHITE=y CT_CC_GCC_USE_GRAPHITE=y CT_CC_GCC_HAS_LTO=y @@ -368,7 +369,7 @@ CT_CC_GCC_USE_GMP_MPFR=y CT_CC_GCC_USE_MPC=y CT_CC_GCC_HAS_LIBQUADMATH=y CT_CC_GCC_HAS_LIBSANITIZER=y -CT_CC_GCC_VERSION="4.9.3" +CT_CC_GCC_VERSION="5.2.0" # CT_CC_LANG_FORTRAN is not set CT_CC_GCC_ENABLE_CXX_FLAGS="" CT_CC_GCC_CORE_EXTRA_CONFIG_ARRAY="" @@ -440,7 +441,6 @@ CT_GETTEXT_NEEDED=y CT_GMP_NEEDED=y CT_MPFR_NEEDED=y CT_ISL_NEEDED=y -CT_CLOOG_NEEDED=y CT_MPC_NEEDED=y CT_COMPLIBS=y CT_LIBICONV=y @@ -448,7 +448,6 @@ CT_GETTEXT=y CT_GMP=y CT_MPFR=y CT_ISL=y -CT_CLOOG=y CT_MPC=y CT_LIBICONV_V_1_14=y CT_LIBICONV_VERSION="1.14" @@ -474,15 +473,13 @@ CT_MPFR_V_3_1_3=y # CT_MPFR_V_2_4_0 is not set CT_MPFR_VERSION="3.1.3" CT_ISL_V_0_14=y +# CT_ISL_V_0_12_2 is not set CT_ISL_V_0_14_or_later=y CT_ISL_V_0_12_or_later=y CT_ISL_VERSION="0.14" -CT_CLOOG_V_0_18_4=y +# CT_CLOOG_V_0_18_4 is not set # CT_CLOOG_V_0_18_1 is not set # CT_CLOOG_V_0_18_0 is not set -CT_CLOOG_VERSION="0.18.4" -CT_CLOOG_0_18_4_or_later=y -CT_CLOOG_0_18_or_later=y CT_MPC_V_1_0_3=y # CT_MPC_V_1_0_2 is not set # CT_MPC_V_1_0_1 is not set diff --git a/src/ci/docker/dist-various-1/Dockerfile b/src/ci/docker/dist-various-1/Dockerfile index 76cdd367987b2..f80293b182e97 100644 --- a/src/ci/docker/dist-various-1/Dockerfile +++ b/src/ci/docker/dist-various-1/Dockerfile @@ -112,17 +112,23 @@ ENV TARGETS=$TARGETS,thumbv7em-none-eabihf ENV TARGETS=$TARGETS,thumbv8m.main-none-eabi ENV TARGETS=$TARGETS,riscv32imc-unknown-none-elf ENV TARGETS=$TARGETS,riscv32imac-unknown-none-elf +ENV TARGETS=$TARGETS,riscv64imac-unknown-none-elf +ENV TARGETS=$TARGETS,riscv64gc-unknown-none-elf ENV TARGETS=$TARGETS,armebv7r-none-eabi ENV TARGETS=$TARGETS,armebv7r-none-eabihf ENV TARGETS=$TARGETS,armv7r-none-eabi ENV TARGETS=$TARGETS,armv7r-none-eabihf +ENV TARGETS=$TARGETS,thumbv7neon-unknown-linux-gnueabihf 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_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++ + ENV RUST_CONFIGURE_ARGS \ --musl-root-armv5te=/musl-armv5te \ --musl-root-arm=/musl-arm \ 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 29222ff60f2a0..c39be14941c90 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 @@ -6,7 +6,7 @@ set -ex apt-get update apt-get install -y --no-install-recommends software-properties-common apt-transport-https -apt-key adv --batch --yes --keyserver keyserver.ubuntu.com --recv-keys AA12E97F0881517F +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 diff --git a/src/ci/docker/dist-various-2/Dockerfile b/src/ci/docker/dist-various-2/Dockerfile index 906255533ad29..e2710a18bdae3 100644 --- a/src/ci/docker/dist-various-2/Dockerfile +++ b/src/ci/docker/dist-various-2/Dockerfile @@ -32,7 +32,7 @@ RUN /tmp/build-solaris-toolchain.sh sparcv9 sparcv9 solaris-sparc COPY dist-various-2/build-x86_64-fortanix-unknown-sgx-toolchain.sh /tmp/ # We pass the commit id of the port of LLVM's libunwind to the build script. # Any update to the commit id here, should cause the container image to be re-built from this point on. -RUN /tmp/build-x86_64-fortanix-unknown-sgx-toolchain.sh "bbe23902411be88d7388f381becefadd6e3ef819" +RUN /tmp/build-x86_64-fortanix-unknown-sgx-toolchain.sh "53b586346f2c7870e20b170decdc30729d97c42b" COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh @@ -70,6 +70,7 @@ ENV TARGETS=$TARGETS,x86_64-sun-solaris ENV TARGETS=$TARGETS,x86_64-unknown-linux-gnux32 ENV TARGETS=$TARGETS,x86_64-unknown-cloudabi ENV TARGETS=$TARGETS,x86_64-fortanix-unknown-sgx +ENV TARGETS=$TARGETS,nvptx64-nvidia-cuda ENV X86_FORTANIX_SGX_LIBS="/x86_64-fortanix-unknown-sgx/lib/" diff --git a/src/ci/docker/dist-various-2/build-cloudabi-toolchain.sh b/src/ci/docker/dist-various-2/build-cloudabi-toolchain.sh index 391f9b2fff889..3354a796c357e 100755 --- a/src/ci/docker/dist-various-2/build-cloudabi-toolchain.sh +++ b/src/ci/docker/dist-various-2/build-cloudabi-toolchain.sh @@ -32,9 +32,8 @@ ln -s ../lib/llvm-5.0/bin/lld /usr/bin/${target}-ld ln -s ../../${target} /usr/lib/llvm-5.0/${target} # Install the C++ runtime libraries from CloudABI Ports. -echo deb https://nuxi.nl/distfiles/cloudabi-ports/debian/ cloudabi cloudabi > \ - /etc/apt/sources.list.d/cloudabi.list -curl 'https://pgp.mit.edu/pks/lookup?op=get&search=0x0DA51B8531344B15' | \ - apt-key add - +apt-key adv --batch --yes --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 0DA51B8531344B15 +add-apt-repository -y 'deb https://nuxi.nl/distfiles/cloudabi-ports/debian/ cloudabi cloudabi' + apt-get update -apt-get install -y $(echo ${target} | sed -e s/_/-/g)-cxx-runtime +apt-get install -y "${target//_/-}-cxx-runtime" diff --git a/src/ci/docker/dist-various-2/build-x86_64-fortanix-unknown-sgx-toolchain.sh b/src/ci/docker/dist-various-2/build-x86_64-fortanix-unknown-sgx-toolchain.sh index 76921316df2cc..725ec341b9497 100755 --- a/src/ci/docker/dist-various-2/build-x86_64-fortanix-unknown-sgx-toolchain.sh +++ b/src/ci/docker/dist-various-2/build-x86_64-fortanix-unknown-sgx-toolchain.sh @@ -12,8 +12,7 @@ target="x86_64-fortanix-unknown-sgx" url="https://github.com/fortanix/llvm-project/archive/${1}.tar.gz" repo_name="llvm-project" -install_prereq() -{ +install_prereq() { apt-get update apt-get install -y --no-install-recommends \ build-essential \ @@ -22,36 +21,32 @@ install_prereq() git } -# Clone Fortanix's port of llvm-project to build libunwind that would link with this target. -# The below method to download a single commit from llvm-project is based on fetch_submodule -# from init_repo.sh -fetch_llvm_commit() -{ - cached="download-${repo_name}.tar.gz" - curl -f -sSL -o ${cached} ${url} - tar -xvzf ${cached} - mkdir "./${repo_name}" && tar -xf ${cached} -C ${repo_name} --strip-components 1 -} - -build_unwind() -{ +build_unwind() { + set -x dir_name="${target}_temp" - rm -rf "./${dir_name}" + rm -rf ${dir_name} mkdir -p ${dir_name} - cd ${dir_name} + pushd ${dir_name} - retry fetch_llvm_commit + # Clone Fortanix's fork of llvm-project which has a port of libunwind + fetch_github_commit_archive "$repo_name" "$url" cd "${repo_name}/libunwind" # Build libunwind mkdir -p build cd build - cmake -DCMAKE_BUILD_TYPE="RELEASE" -DRUST_SGX=1 -G "Unix Makefiles" -DLLVM_PATH=../../llvm/ ../ + cmake -DCMAKE_BUILD_TYPE="RELEASE" -DRUST_SGX=1 -G "Unix Makefiles" \ + -DLLVM_ENABLE_WARNINGS=1 -DLIBUNWIND_ENABLE_WERROR=1 -DLIBUNWIND_ENABLE_PEDANTIC=0 \ + -DLLVM_PATH=../../llvm/ ../ make unwind_static install -D "lib/libunwind.a" "/${target}/lib/libunwind.a" + + popd rm -rf ${dir_name} + + { set +x; } 2>/dev/null } set -x hide_output install_prereq -hide_output build_unwind +build_unwind diff --git a/src/ci/docker/dist-various-2/shared.sh b/src/ci/docker/dist-various-2/shared.sh index fb917b0510e40..7abace65b9c03 100644 --- a/src/ci/docker/dist-various-2/shared.sh +++ b/src/ci/docker/dist-various-2/shared.sh @@ -1,5 +1,5 @@ hide_output() { - set +x + { set +x; } 2>/dev/null on_err=" echo ERROR: An error was encountered with the build. cat /tmp/build.log @@ -14,6 +14,7 @@ exit 1 set -x } +# Copied from ../../shared.sh function retry { echo "Attempting with retry:" "$@" local n=1 @@ -31,3 +32,15 @@ function retry { } done } + +# Copied from ../../init_repo.sh +function fetch_github_commit_archive { + local module=$1 + local cached="download-${module//\//-}.tar.gz" + retry sh -c "rm -f $cached && \ + curl -f -sSL -o $cached $2" + mkdir $module + touch "$module/.git" + tar -C $module --strip-components=1 -xf $cached + rm $cached +} diff --git a/src/ci/docker/dist-x86_64-linux/build-clang.sh b/src/ci/docker/dist-x86_64-linux/build-clang.sh index ff5b50123fd37..ac681b7168622 100755 --- a/src/ci/docker/dist-x86_64-linux/build-clang.sh +++ b/src/ci/docker/dist-x86_64-linux/build-clang.sh @@ -4,26 +4,14 @@ set -ex source shared.sh -# Currently these commits are all tip-of-tree as of 2018-12-16, used to pick up -# a fix for rust-lang/rust#56849 -LLVM=032b00a5404865765cda7db3039f39d54964d8b0 -LLD=3e4aa4e8671523321af51449e0569f455ef3ad43 -CLANG=a6b9739069763243020f4ea6fe586bc135fde1f9 +LLVM=llvmorg-8.0.0-rc2 -mkdir clang -cd clang +mkdir llvm-project +cd llvm-project -curl -L https://github.com/llvm-mirror/llvm/archive/$LLVM.tar.gz | \ +curl -L https://github.com/llvm/llvm-project/archive/$LLVM.tar.gz | \ tar xzf - --strip-components=1 -mkdir -p tools/clang -curl -L https://github.com/llvm-mirror/clang/archive/$CLANG.tar.gz | \ - tar xzf - --strip-components=1 -C tools/clang - -mkdir -p tools/lld -curl -L https://github.com/llvm-mirror/lld/archive/$LLD.tar.gz | \ - tar zxf - --strip-components=1 -C tools/lld - mkdir clang-build cd clang-build @@ -39,20 +27,21 @@ cd clang-build # # [1]: https://sourceware.org/ml/crossgcc/2008-11/msg00028.html INC="/rustroot/include" -INC="$INC:/rustroot/lib/gcc/x86_64-unknown-linux-gnu/4.8.5/include-fixed" +INC="$INC:/rustroot/lib/gcc/x86_64-unknown-linux-gnu/5.5.0/include-fixed" INC="$INC:/usr/include" hide_output \ - cmake .. \ + cmake ../llvm \ -DCMAKE_C_COMPILER=/rustroot/bin/gcc \ -DCMAKE_CXX_COMPILER=/rustroot/bin/g++ \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_INSTALL_PREFIX=/rustroot \ -DLLVM_TARGETS_TO_BUILD=X86 \ + -DLLVM_ENABLE_PROJECTS="clang;lld" \ -DC_INCLUDE_DIRS="$INC" hide_output make -j10 hide_output make install cd ../.. -rm -rf clang +rm -rf llvm-project 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 9f3ae55cb3fe6..7f6e94d326ddf 100755 --- a/src/ci/docker/dist-x86_64-linux/build-gcc.sh +++ b/src/ci/docker/dist-x86_64-linux/build-gcc.sh @@ -3,9 +3,9 @@ set -ex source shared.sh -GCC=4.8.5 +GCC=5.5.0 -curl https://ftp.gnu.org/gnu/gcc/gcc-$GCC/gcc-$GCC.tar.bz2 | tar xjf - +curl https://ftp.gnu.org/gnu/gcc/gcc-$GCC/gcc-$GCC.tar.xz | xzcat | tar xf - cd gcc-$GCC # FIXME(#49246): Remove the `sed` below. diff --git a/src/ci/docker/dist-x86_64-linux/build-perl.sh b/src/ci/docker/dist-x86_64-linux/build-perl.sh index a6c3d5cb683a8..a678d353d52f5 100755 --- a/src/ci/docker/dist-x86_64-linux/build-perl.sh +++ b/src/ci/docker/dist-x86_64-linux/build-perl.sh @@ -11,7 +11,8 @@ cd perl-5.28.0 # Gotta do some hackery to tell python about our custom OpenSSL build, but other # than that fairly normal. CC=gcc \ -CFLAGS='-I /rustroot/include' LDFLAGS='-L /rustroot/lib -L /rustroot/lib64' \ +CFLAGS='-I /rustroot/include -fgnu89-inline' \ +LDFLAGS='-L /rustroot/lib -L /rustroot/lib64' \ hide_output ./configure.gnu hide_output make -j10 hide_output make install diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh index ad6188568cff2..b4426bbfb962c 100755 --- a/src/ci/docker/run.sh +++ b/src/ci/docker/run.sh @@ -20,9 +20,9 @@ travis_time_start if [ -f "$docker_dir/$image/Dockerfile" ]; then if [ "$CI" != "" ]; then hash_key=/tmp/.docker-hash-key.txt - find $docker_dir/$image $docker_dir/scripts -type f | \ - sort | \ - xargs cat >> $hash_key + rm -f "${hash_key}" + echo $image >> $hash_key + find $docker_dir -type f | sort | xargs cat >> $hash_key docker --version >> $hash_key cksum=$(sha512sum $hash_key | \ awk '{print $1}') @@ -31,7 +31,7 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then echo "Attempting to download $s3url" rm -f /tmp/rustci_docker_cache set +e - retry curl -f -L -C - -o /tmp/rustci_docker_cache "$url" + retry curl -y 30 -Y 10 --connect-timeout 30 -f -L -C - -o /tmp/rustci_docker_cache "$url" loaded_images=$(docker load -i /tmp/rustci_docker_cache | sed 's/.* sha/sha/') set -e echo "Downloaded containers:\n$loaded_images" diff --git a/src/ci/docker/scripts/android-sdk.sh b/src/ci/docker/scripts/android-sdk.sh index e06c57fbab90c..179f63fc830a6 100644 --- a/src/ci/docker/scripts/android-sdk.sh +++ b/src/ci/docker/scripts/android-sdk.sh @@ -20,7 +20,7 @@ download_sysimage() { # The output from sdkmanager is so noisy that it will occupy all of the 4 MB # log extremely quickly. Thus we must silence all output. yes | sdkmanager --licenses > /dev/null - sdkmanager platform-tools emulator \ + yes | sdkmanager platform-tools emulator \ "platforms;android-$api" \ "system-images;android-$api;default;$abi" > /dev/null } diff --git a/src/ci/docker/wasm32-unknown/Dockerfile b/src/ci/docker/test-various/Dockerfile similarity index 63% rename from src/ci/docker/wasm32-unknown/Dockerfile rename to src/ci/docker/test-various/Dockerfile index 161f0c0062fa0..6c419e13c9f05 100644 --- a/src/ci/docker/wasm32-unknown/Dockerfile +++ b/src/ci/docker/test-various/Dockerfile @@ -13,14 +13,16 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ 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 + RUN curl -sL https://nodejs.org/dist/v9.2.0/node-v9.2.0-linux-x64.tar.xz | \ - tar -xJ + tar -xJ COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh -ENV TARGETS=wasm32-unknown-unknown - ENV RUST_CONFIGURE_ARGS \ --set build.nodejs=/node-v9.2.0-linux-x64/bin/node \ --set rust.lld @@ -31,11 +33,18 @@ ENV RUST_CONFIGURE_ARGS \ # other contexts as well ENV NO_DEBUG_ASSERTIONS=1 -ENV SCRIPT python2.7 /checkout/x.py test --target $TARGETS \ +ENV WASM_TARGETS=wasm32-unknown-unknown +ENV WASM_SCRIPT python2.7 /checkout/x.py test --target $WASM_TARGETS \ src/test/run-make \ src/test/ui \ src/test/run-pass \ src/test/compile-fail \ src/test/mir-opt \ src/test/codegen-units \ - src/libcore \ + src/libcore + +ENV NVPTX_TARGETS=nvptx64-nvidia-cuda +ENV NVPTX_SCRIPT python2.7 /checkout/x.py test --target $NVPTX_TARGETS \ + src/test/run-make + +ENV SCRIPT $WASM_SCRIPT && $NVPTX_SCRIPT diff --git a/src/ci/docker/x86_64-gnu-debug/Dockerfile b/src/ci/docker/x86_64-gnu-debug/Dockerfile index bdde7ad7fe854..1c7eff68adc15 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:16.04 +FROM ubuntu:18.10 RUN apt-get update && apt-get install -y --no-install-recommends \ g++ \ @@ -7,18 +7,37 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ curl \ ca-certificates \ python2.7 \ + python2.7-dev \ + libxml2-dev \ + libncurses-dev \ + libedit-dev \ + swig \ + doxygen \ git \ cmake \ sudo \ gdb \ - xz-utils + xz-utils \ + lld \ + clang COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh +ENV RUSTBUILD_FORCE_CLANG_BASED_TESTS 1 ENV RUN_CHECK_WITH_PARALLEL_QUERIES 1 + ENV RUST_CONFIGURE_ARGS \ --build=x86_64-unknown-linux-gnu \ --enable-debug \ - --enable-optimize -ENV SCRIPT python2.7 ../x.py build + --enable-lld \ + --enable-lldb \ + --enable-optimize \ + --set llvm.use-linker=lld \ + --set target.x86_64-unknown-linux-gnu.linker=clang \ + --set target.x86_64-unknown-linux-gnu.cc=clang \ + --set target.x86_64-unknown-linux-gnu.cxx=clang++ + +ENV SCRIPT \ + python2.7 ../x.py build && \ + python2.7 ../x.py test src/test/run-make-fulldeps --test-args clang diff --git a/src/ci/docker/x86_64-gnu-tools/checktools.sh b/src/ci/docker/x86_64-gnu-tools/checktools.sh index 2e5b335950166..3343716419ff4 100755 --- a/src/ci/docker/x86_64-gnu-tools/checktools.sh +++ b/src/ci/docker/x86_64-gnu-tools/checktools.sh @@ -23,6 +23,7 @@ python2.7 "$X_PY" test --no-fail-fast \ src/doc/nomicon \ src/doc/reference \ src/doc/rust-by-example \ + src/doc/embedded-book \ src/tools/clippy \ src/tools/rls \ src/tools/rustfmt \ diff --git a/src/ci/init_repo.sh b/src/ci/init_repo.sh index be2cadbbe6cf2..3dfd338157617 100755 --- a/src/ci/init_repo.sh +++ b/src/ci/init_repo.sh @@ -34,19 +34,19 @@ if grep -q RUST_RELEASE_CHANNEL=beta src/ci/run.sh; then git fetch origin --unshallow beta master fi -function fetch_submodule { +# Duplicated in docker/dist-various-2/shared.sh +function fetch_github_commit_archive { local module=$1 local cached="download-${module//\//-}.tar.gz" retry sh -c "rm -f $cached && \ - curl -sSL -o $cached $2" + curl -f -sSL -o $cached $2" mkdir $module touch "$module/.git" tar -C $module --strip-components=1 -xf $cached rm $cached } -included="src/llvm src/llvm-emscripten src/doc/book src/doc/rust-by-example" -included="$included src/tools/lld src/tools/clang src/tools/lldb" +included="src/llvm-project src/llvm-emscripten src/doc/book src/doc/rust-by-example" modules="$(git config --file .gitmodules --get-regexp '\.path$' | cut -d' ' -f2)" modules=($modules) use_git="" @@ -59,7 +59,7 @@ for i in ${!modules[@]}; do git rm $module url=${urls[$i]} url=${url/\.git/} - fetch_submodule $module "$url/archive/$commit.tar.gz" & + fetch_github_commit_archive $module "$url/archive/$commit.tar.gz" & continue else use_git="$use_git $module" diff --git a/src/ci/run.sh b/src/ci/run.sh index b0e1b1651055f..42d0d7db5964c 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -82,7 +82,7 @@ fi SCCACHE_IDLE_TIMEOUT=10800 sccache --start-server || true if [ "$RUN_CHECK_WITH_PARALLEL_QUERIES" != "" ]; then - $SRC/configure --enable-experimental-parallel-queries + $SRC/configure --enable-parallel-compiler CARGO_INCREMENTAL=0 python2.7 ../x.py check rm -f config.toml rm -rf build diff --git a/src/ci/shared.sh b/src/ci/shared.sh index 4a49f3441a41d..3ba64ad412064 100644 --- a/src/ci/shared.sh +++ b/src/ci/shared.sh @@ -5,6 +5,7 @@ # marked as an executable file in git. # See http://unix.stackexchange.com/questions/82598 +# Duplicated in docker/dist-various-2/shared.sh function retry { echo "Attempting with retry:" "$@" local n=1 diff --git a/src/doc/embedded-book b/src/doc/embedded-book new file mode 160000 index 0000000000000..bd2778f304989 --- /dev/null +++ b/src/doc/embedded-book @@ -0,0 +1 @@ +Subproject commit bd2778f304989ee52be8201504d6ec621dd60ca9 diff --git a/src/doc/guide-error-handling.md b/src/doc/guide-error-handling.md index 54fa529f3aa8e..fd71d3e3c8e79 100644 --- a/src/doc/guide-error-handling.md +++ b/src/doc/guide-error-handling.md @@ -1,4 +1,4 @@ % Error Handling in Rust This content has moved into -[the Rust Programming Language book](book/error-handling.html). +[the Rust Programming Language book](book/ch09-00-error-handling.html). diff --git a/src/doc/guide-ownership.md b/src/doc/guide-ownership.md index 884f14726ca87..767dafc5baf92 100644 --- a/src/doc/guide-ownership.md +++ b/src/doc/guide-ownership.md @@ -1,4 +1,4 @@ % The (old) Rust Ownership Guide This content has moved into -[the Rust Programming Language book](book/ownership.html). +[the Rust Programming Language book](book/ch04-00-understanding-ownership.html). diff --git a/src/doc/guide-pointers.md b/src/doc/guide-pointers.md index dc80ec4399131..bafdb2fe0bbc3 100644 --- a/src/doc/guide-pointers.md +++ b/src/doc/guide-pointers.md @@ -2,6 +2,6 @@ This content has been removed, with no direct replacement. Rust only has two built-in pointer types now, -[references](book/references-and-borrowing.html) and [raw +[references](book/ch04-02-references-and-borrowing.html) and [raw pointers](book/raw-pointers.html). Older Rusts had many more pointer types, they’re gone now. diff --git a/src/doc/guide-testing.md b/src/doc/guide-testing.md index 67bcb0a5e546a..28d9fb48b73e7 100644 --- a/src/doc/guide-testing.md +++ b/src/doc/guide-testing.md @@ -1,4 +1,4 @@ % The (old) Rust Testing Guide This content has moved into -[the Rust Programming Language book](book/testing.html). +[the Rust Programming Language book](book/ch11-00-testing.html). diff --git a/src/doc/index.md b/src/doc/index.md index 55897e5a3e906..0a2a80e8fd6e2 100644 --- a/src/doc/index.md +++ b/src/doc/index.md @@ -52,6 +52,12 @@ If reading multiple hundreds of pages about a language isn't your style, then a lot of words, RBE shows off a bunch of code, and keeps the talking to a minimum. It also includes exercises! +## Rustlings + +[Rustlings](https://github.com/rust-lang/rustlings) guides you through downloading and setting up the Rust toolchain, +and teaches you the basics of reading and writing Rust syntax. It's an +alternative to Rust by Example that works with your own environment. + # Use Rust Once you've gotten familiar with the language, these resources can help you @@ -71,6 +77,10 @@ accomplishing various tasks. +## The Edition Guide + +[The Edition Guide](edition-guide/index.html) describes the Rust editions. + ## The Rustc Book [The Rustc Book](rustc/index.html) describes the Rust compiler, `rustc`. @@ -113,3 +123,19 @@ Rust. It's also sometimes called "the 'nomicon." [The `rustc` Guide](https://rust-lang.github.io/rustc-guide/) documents how the compiler works and how to contribute to it. This is useful if you want to build or modify the Rust compiler from source (e.g. to target something non-standard). + +# Specialize Rust + +When using Rust in specific domain areas, consider using the following resources tailored to each domain. + +## Embedded Systems + +When developing for Bare Metal or Embedded Linux systems, you may find these resources maintained by the [Embedded Working Group] useful. + +[Embedded Working Group]: https://github.com/rust-embedded + +### The Embedded Rust Book + +[The Embedded Rust Book] is targeted at developers familiar with embedded development and familiar with Rust, but have not used Rust for embedded development. + +[The Embedded Rust Book]: embedded-book/index.html diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index e4c0939fd4636..34708d1847f6b 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -13,4 +13,5 @@ - [Targets](targets/index.md) - [Built-in Targets](targets/built-in.md) - [Custom Targets](targets/custom.md) -- [Contributing to `rustc`](contributing.md) \ No newline at end of file +- [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 94f21042c8fdd..a616409d9a400 100644 --- a/src/doc/rustc/src/codegen-options/index.md +++ b/src/doc/rustc/src/codegen-options/index.md @@ -187,7 +187,7 @@ This flag lets you control debug information: This flag lets you control the optimization level. -* `0`: no optimizations +* `0`: no optimizations, also turn on `cfg(debug_assertions)`. * `1`: basic optimizations * `2`: some optimizations * `3`: all optimizations diff --git a/src/doc/rustc/src/command-line-arguments.md b/src/doc/rustc/src/command-line-arguments.md index b60c55240140e..d7e789b5a11f7 100644 --- a/src/doc/rustc/src/command-line-arguments.md +++ b/src/doc/rustc/src/command-line-arguments.md @@ -42,11 +42,11 @@ This flag prints out various information about the compiler. ## `-g`: include debug information -A synonym for `-C debug-level=2`. +A synonym for `-C debuginfo=2`, for more see [here](codegen-options/index.html#debuginfo). ## `-O`: optimize your code -A synonym for `-C opt-level=2`. +A synonym for `-C opt-level=2`, for more see [here](codegen-options/index.html#opt-level). ## `-o`: filename of the output diff --git a/src/doc/rustc/src/contributing.md b/src/doc/rustc/src/contributing.md index 3a1cafe8a6153..25a5c97b0a120 100644 --- a/src/doc/rustc/src/contributing.md +++ b/src/doc/rustc/src/contributing.md @@ -1,6 +1,12 @@ # Contributing to rustc We'd love to have your help improving `rustc`! To that end, we've written [a -whole book](https://rust-lang.github.io/rustc-guide/) on its +whole book][rustc_guide] on its internals, how it works, and how to get started working on it. To learn more, you'll want to check that out. + +If you would like to contribute to _this_ book, you can find its source in the +rustc source at [src/doc/rustc][rustc_book]. + +[rustc_guide]: https://rust-lang.github.io/rustc-guide/ +[rustc_book]: https://github.com/rust-lang/rust/tree/master/src/doc/rustc diff --git a/src/doc/rustc/src/linker-plugin-lto.md b/src/doc/rustc/src/linker-plugin-lto.md new file mode 100644 index 0000000000000..73a2efcb33a75 --- /dev/null +++ b/src/doc/rustc/src/linker-plugin-lto.md @@ -0,0 +1,108 @@ +# Linker-plugin-LTO + +The `-C linker-plugin-lto` flag allows for deferring the LTO optimization +to the actual linking step, which in turn allows for performing +interprocedural optimizations across programming language boundaries if +all the object files being linked were created by LLVM based toolchains. +The prime example here would be linking Rust code together with +Clang-compiled C/C++ code. + +## Usage + +There are two main cases how linker plugin based LTO can be used: + + - compiling a Rust `staticlib` that is used as a C ABI dependency + - compiling a Rust binary where `rustc` invokes the linker + +In both cases the Rust code has to be compiled with `-C linker-plugin-lto` and +the C/C++ code with `-flto` or `-flto=thin` so that object files are emitted +as LLVM bitcode. + +### Rust `staticlib` as dependency in C/C++ program + +In this case the Rust compiler just has to make sure that the object files in +the `staticlib` are in the right format. For linking, a linker with the +LLVM plugin must be used (e.g. LLD). + +Using `rustc` directly: + +```bash +# Compile the Rust staticlib +rustc --crate-type=staticlib -Clinker-plugin-lto -Copt-level=2 ./lib.rs +# Compile the C code with `-flto=thin` +clang -c -O2 -flto=thin -o main.o ./main.c +# Link everything, making sure that we use an appropriate linker +clang -flto=thin -fuse-ld=lld -L . -l"name-of-your-rust-lib" -o main -O2 ./cmain.o +``` + +Using `cargo`: + +```bash +# Compile the Rust staticlib +RUSTFLAGS="-Clinker-plugin-lto" cargo build --release +# Compile the C code with `-flto=thin` +clang -c -O2 -flto=thin -o main.o ./main.c +# Link everything, making sure that we use an appropriate linker +clang -flto=thin -fuse-ld=lld -L . -l"name-of-your-rust-lib" -o main -O2 ./cmain.o +``` + +### C/C++ code as a dependency in Rust + +In this case the linker will be invoked by `rustc`. We again have to make sure +that an appropriate linker is used. + +Using `rustc` directly: + +```bash +# Compile C code with `-flto` +clang ./clib.c -flto=thin -c -o ./clib.o -O2 +# Create a static library from the C code +ar crus ./libxyz.a ./clib.o + +# Invoke `rustc` with the additional arguments +rustc -Clinker-plugin-lto -L. -Copt-level=2 -Clinker=clang -Clink-arg=-fuse-ld=lld ./main.rs +``` + +Using `cargo` directly: + +```bash +# Compile C code with `-flto` +clang ./clib.c -flto=thin -c -o ./clib.o -O2 +# Create a static library from the C code +ar crus ./libxyz.a ./clib.o + +# Set the linking arguments via RUSTFLAGS +RUSTFLAGS="-Clinker-plugin-lto -Clinker=clang -Clink-arg=-fuse-ld=lld" cargo build --release +``` + +### Explicitly specifying the linker plugin to be used by `rustc` + +If one wants to use a linker other than LLD, the LLVM linker plugin has to be +specified explicitly. Otherwise the linker cannot read the object files. The +path to the plugin is passed as an argument to the `-Clinker-plugin-lto` +option: + +```bash +rustc -Clinker-plugin-lto="/path/to/LLVMgold.so" -L. -Copt-level=2 ./main.rs +``` + + +## Toolchain Compatibility + +In order for this kind of LTO to work, the LLVM linker plugin must be able to +handle the LLVM bitcode produced by both `rustc` and `clang`. + +Best results are achieved by using a `rustc` and `clang` that are based on the +exact same version of LLVM. One can use `rustc -vV` in order to view the LLVM +used by a given `rustc` version. Note that the version number given +here is only an approximation as Rust sometimes uses unstable revisions of +LLVM. However, the approximation is usually reliable. + +The following table shows known good combinations of toolchain versions. + +| | Clang 7 | Clang 8 | +|-----------|-----------|-----------| +| Rust 1.34 | ✗ | ✓ | +| Rust 1.35 | ✗ | ✓(?) | + +Note that the compatibility policy for this feature might change in the future. diff --git a/src/doc/rustc/src/lints/levels.md b/src/doc/rustc/src/lints/levels.md index 072c7585934e8..d315e0f8ca9e5 100644 --- a/src/doc/rustc/src/lints/levels.md +++ b/src/doc/rustc/src/lints/levels.md @@ -90,7 +90,9 @@ This lint level gives you that. 'forbid' is a special lint level that's stronger than 'deny'. It's the same as 'deny' in that a lint at this level will produce an error, but unlike the 'deny' level, the 'forbid' level can not be overridden to be anything lower -than an error. +than an error. However, lint levels may still be capped with `--cap-lints` +(see below) so `rustc --cap-lints warn` will make lints set to 'forbid' just +warn. ## Configuring warning levels diff --git a/src/doc/rustdoc/src/documentation-tests.md b/src/doc/rustdoc/src/documentation-tests.md index dcc13f53493f4..c9acd3c307b54 100644 --- a/src/doc/rustdoc/src/documentation-tests.md +++ b/src/doc/rustdoc/src/documentation-tests.md @@ -236,6 +236,23 @@ appears to the reader as the initial idea but works with doc tests: /// ``` ``` +As of version 1.34.0, one can also omit the `fn main()`, but you will have to +disambiguate the error type: + +```ignore +/// ``` +/// use std::io; +/// let mut input = String::new(); +/// io::stdin().read_line(&mut input)?; +/// # Ok::<(), io::Error>(()) +/// ``` +``` + +This is an unfortunate consequence of the `?` operator adding an implicit +conversion, so type inference fails because the type is not unique. Please note +that you must write the `(())` in one sequence without intermediate whitespace +so that rustdoc understands you want an implicit `Result`-returning function. + ## Documenting macros Here’s an example of documenting a macro: diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md index 905b06465340a..3463cdb126cc6 100644 --- a/src/doc/rustdoc/src/unstable-features.md +++ b/src/doc/rustdoc/src/unstable-features.md @@ -1,9 +1,8 @@ # Unstable features Rustdoc is under active development, and like the Rust compiler, some features are only available -on the nightly releases. Some of these are new and need some more testing before they're able to get -released to the world at large, and some of them are tied to features in the Rust compiler that are -themselves unstable. Several features here require a matching `#![feature(...)]` attribute to +on nightly releases. Some of these features are new and need some more testing before they're able to be +released to the world at large, and some of them are tied to features in the Rust compiler that are unstable. Several features here require a matching `#![feature(...)]` attribute to enable, and thus are more fully documented in the [Unstable Book]. Those sections will link over there as necessary. @@ -417,3 +416,15 @@ JavaScript, and font files in a single location, rather than duplicating it once (grouping of crate docs generated into the same output directory, like with `cargo doc`). Per-crate files like the search index will still load from the documentation root, but anything that gets renamed with `--resource-suffix` will load from the given path. + +### `--persist-doctests`: persist doctest executables after running + +Using this flag looks like this: + +```bash +$ rustdoc src/lib.rs --test -Z unstable-options --persist-doctests target/rustdoctest +``` + +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. diff --git a/src/doc/unstable-book/src/language-features/crate-visibility-modifier.md b/src/doc/unstable-book/src/language-features/crate-visibility-modifier.md index 11b3ee8edf0b1..b59859dd348e7 100644 --- a/src/doc/unstable-book/src/language-features/crate-visibility-modifier.md +++ b/src/doc/unstable-book/src/language-features/crate-visibility-modifier.md @@ -1,8 +1,8 @@ # `crate_visibility_modifier` -The tracking issue for this feature is: [#45388] +The tracking issue for this feature is: [#53120] -[#45388]: https://github.com/rust-lang/rust/issues/45388 +[#53120]: https://github.com/rust-lang/rust/issues/53120 ----- diff --git a/src/doc/unstable-book/src/language-features/generators.md b/src/doc/unstable-book/src/language-features/generators.md index 968534e58bd9e..426fc01a6b051 100644 --- a/src/doc/unstable-book/src/language-features/generators.md +++ b/src/doc/unstable-book/src/language-features/generators.md @@ -29,6 +29,7 @@ A syntactical example of a generator is: #![feature(generators, generator_trait)] use std::ops::{Generator, GeneratorState}; +use std::pin::Pin; fn main() { let mut generator = || { @@ -36,11 +37,11 @@ fn main() { return "foo" }; - match unsafe { generator.resume() } { + match Pin::new(&mut generator).resume() { GeneratorState::Yielded(1) => {} _ => panic!("unexpected value from resume"), } - match unsafe { generator.resume() } { + match Pin::new(&mut generator).resume() { GeneratorState::Complete("foo") => {} _ => panic!("unexpected value from resume"), } @@ -60,6 +61,7 @@ prints all numbers in order: #![feature(generators, generator_trait)] use std::ops::Generator; +use std::pin::Pin; fn main() { let mut generator = || { @@ -69,9 +71,9 @@ fn main() { }; println!("1"); - unsafe { generator.resume() }; + Pin::new(&mut generator).resume(); println!("3"); - unsafe { generator.resume() }; + Pin::new(&mut generator).resume(); println!("5"); } ``` @@ -86,13 +88,14 @@ Feedback on the design and usage is always appreciated! The `Generator` trait in `std::ops` currently looks like: ``` -# #![feature(generator_trait)] +# #![feature(arbitrary_self_types, generator_trait)] # use std::ops::GeneratorState; +# use std::pin::Pin; pub trait Generator { type Yield; type Return; - unsafe fn resume(&mut self) -> GeneratorState; + fn resume(self: Pin<&mut Self>) -> GeneratorState; } ``` @@ -167,6 +170,7 @@ Let's take a look at an example to see what's going on here: #![feature(generators, generator_trait)] use std::ops::Generator; +use std::pin::Pin; fn main() { let ret = "foo"; @@ -175,17 +179,18 @@ fn main() { return ret }; - unsafe { generator.resume() }; - unsafe { generator.resume() }; + Pin::new(&mut generator).resume(); + Pin::new(&mut generator).resume(); } ``` This generator literal will compile down to something similar to: ```rust -#![feature(generators, generator_trait)] +#![feature(arbitrary_self_types, generators, generator_trait)] use std::ops::{Generator, GeneratorState}; +use std::pin::Pin; fn main() { let ret = "foo"; @@ -200,9 +205,9 @@ fn main() { type Yield = i32; type Return = &'static str; - unsafe fn resume(&mut self) -> GeneratorState { + fn resume(mut self: Pin<&mut Self>) -> GeneratorState { use std::mem; - match mem::replace(self, __Generator::Done) { + match mem::replace(&mut *self, __Generator::Done) { __Generator::Start(s) => { *self = __Generator::Yield1(s); GeneratorState::Yielded(1) @@ -223,8 +228,8 @@ fn main() { __Generator::Start(ret) }; - unsafe { generator.resume() }; - unsafe { generator.resume() }; + Pin::new(&mut generator).resume(); + Pin::new(&mut generator).resume(); } ``` diff --git a/src/doc/unstable-book/src/language-features/plugin.md b/src/doc/unstable-book/src/language-features/plugin.md index 03ea392c86307..cab350381d2bd 100644 --- a/src/doc/unstable-book/src/language-features/plugin.md +++ b/src/doc/unstable-book/src/language-features/plugin.md @@ -52,6 +52,7 @@ that implements Roman numeral integer literals. #![feature(plugin_registrar, rustc_private)] extern crate syntax; +extern crate syntax_pos; extern crate rustc; extern crate rustc_plugin; @@ -59,7 +60,7 @@ use syntax::parse::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::ext::quote::rt::Span; +use syntax_pos::Span; use rustc_plugin::Registry; fn expand_rn(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree]) 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 new file mode 100644 index 0000000000000..415c6ebe8b4bc --- /dev/null +++ b/src/doc/unstable-book/src/language-features/repr-align-enum.md @@ -0,0 +1,42 @@ +# `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/library-features/is-sorted.md b/src/doc/unstable-book/src/library-features/is-sorted.md new file mode 100644 index 0000000000000..e3b7dc3b28eb2 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/is-sorted.md @@ -0,0 +1,11 @@ +# `is_sorted` + +The tracking issue for this feature is: [#53485] + +[#53485]: https://github.com/rust-lang/rust/issues/53485 + +------------------------ + +Add the methods `is_sorted`, `is_sorted_by` and `is_sorted_by_key` to `[T]`; +add the methods `is_sorted`, `is_sorted_by` and `is_sorted_by_key` to +`Iterator`. diff --git a/src/etc/gdb_rust_pretty_printing.py b/src/etc/gdb_rust_pretty_printing.py index 08ae289d60374..a6b09722e1c94 100755 --- a/src/etc/gdb_rust_pretty_printing.py +++ b/src/etc/gdb_rust_pretty_printing.py @@ -16,7 +16,7 @@ # This fix went in 8.1, so check for that. # See https://github.com/rust-lang/rust/issues/56730 gdb_81 = False -_match = re.match('([0-9]+)\\.([0-9]+)', gdb.VERSION) +_match = re.search('([0-9]+)\\.([0-9]+)', gdb.VERSION) if _match: if int(_match.group(1)) > 8 or (int(_match.group(1)) == 8 and int(_match.group(2)) >= 1): gdb_81 = True @@ -330,19 +330,20 @@ def children_of_node(boxed_node, height, want_values): leaf = node_ptr['data'] else: leaf = node_ptr.dereference() - keys = leaf['keys']['value']['value'] + keys = leaf['keys'] if want_values: - values = leaf['vals']['value']['value'] + values = leaf['vals'] length = int(leaf['len']) for i in xrange(0, length + 1): if height > 0: - for child in children_of_node(node_ptr['edges'][i], height - 1, want_values): + child_ptr = node_ptr['edges'][i]['value']['value'] + for child in children_of_node(child_ptr, height - 1, want_values): yield child if i < length: if want_values: - yield (keys[i], values[i]) + yield (keys[i]['value']['value'], values[i]['value']['value']) else: - yield keys[i] + yield keys[i]['value']['value'] class RustStdBTreeSetPrinter(object): def __init__(self, val): diff --git a/src/etc/generate-deriving-span-tests.py b/src/etc/generate-deriving-span-tests.py index 3d35ae07fbd68..1c525101c76f6 100755 --- a/src/etc/generate-deriving-span-tests.py +++ b/src/etc/generate-deriving-span-tests.py @@ -8,14 +8,12 @@ sample usage: src/etc/generate-deriving-span-tests.py """ -import os, datetime, stat, re +import os, stat TEST_DIR = os.path.abspath( os.path.join(os.path.dirname(__file__), '../test/ui/derives/')) -YEAR = datetime.datetime.now().year - -TEMPLATE = """ +TEMPLATE = """\ // This file was auto-generated using 'src/etc/generate-deriving-span-tests.py' {error_deriving} @@ -63,19 +61,11 @@ def create_test_case(type, trait, super_traits, error_count): errors = '\n'.join('//~%s ERROR' % ('^' * n) for n in range(error_count)) code = string.format(traits = all_traits, errors = errors) - return TEMPLATE.format(year = YEAR, error_deriving=error_deriving, code = code) + return TEMPLATE.format(error_deriving=error_deriving, code = code) def write_file(name, string): test_file = os.path.join(TEST_DIR, 'derives-span-%s.rs' % name) - with open(test_file) as f: - old_str = f.read() - old_str_ignoring_date = re.sub(r'^// Copyright \d+', - '// Copyright {year}'.format(year = YEAR), old_str) - if old_str_ignoring_date == string: - # if all we're doing is updating the copyright year, ignore it - return 0 - # set write permission if file exists, so it can be changed if os.path.exists(test_file): os.chmod(test_file, stat.S_IWUSR) @@ -86,8 +76,6 @@ def write_file(name, string): # mark file read-only os.chmod(test_file, stat.S_IRUSR|stat.S_IRGRP|stat.S_IROTH) - return 1 - ENUM = 1 STRUCT = 2 @@ -110,15 +98,11 @@ def write_file(name, string): ('Hash', [], 1)]: traits[trait] = (ALL, supers, errs) -files = 0 - for (trait, (types, super_traits, error_count)) in traits.items(): mk = lambda ty: create_test_case(ty, trait, super_traits, error_count) if types & ENUM: - files += write_file(trait + '-enum', mk(ENUM_TUPLE)) - files += write_file(trait + '-enum-struct-variant', mk(ENUM_STRUCT)) + write_file(trait + '-enum', mk(ENUM_TUPLE)) + write_file(trait + '-enum-struct-variant', mk(ENUM_STRUCT)) if types & STRUCT: - files += write_file(trait + '-struct', mk(STRUCT_FIELDS)) - files += write_file(trait + '-tuple-struct', mk(STRUCT_TUPLE)) - -print('Generated {files} deriving span test{}.'.format('s' if files != 1 else '', files = files)) + write_file(trait + '-struct', mk(STRUCT_FIELDS)) + write_file(trait + '-tuple-struct', mk(STRUCT_TUPLE)) diff --git a/src/etc/generate-keyword-tests.py b/src/etc/generate-keyword-tests.py index 9936ce71b76bc..bc046a8f42d0b 100755 --- a/src/etc/generate-keyword-tests.py +++ b/src/etc/generate-keyword-tests.py @@ -15,7 +15,7 @@ import stat -template = """ +template = """\ // This file was auto-generated using 'src/etc/generate-keyword-tests.py %s' fn main() { @@ -35,7 +35,7 @@ os.chmod(test_file, stat.S_IWUSR) with open(test_file, 'wt') as f: - f.write(template % (datetime.datetime.now().year, kw, kw, kw)) + f.write(template % (kw, kw, kw)) # mark file read-only os.chmod(test_file, stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH) diff --git a/src/liballoc/Cargo.toml b/src/liballoc/Cargo.toml index 861c7cecb8879..f6d6c1de8f511 100644 --- a/src/liballoc/Cargo.toml +++ b/src/liballoc/Cargo.toml @@ -4,6 +4,7 @@ name = "alloc" version = "0.0.0" autotests = false autobenches = false +edition = "2018" [lib] name = "alloc" diff --git a/src/liballoc/alloc.rs b/src/liballoc/alloc.rs index 096cb51e0d3ef..ec652df3b37a4 100644 --- a/src/liballoc/alloc.rs +++ b/src/liballoc/alloc.rs @@ -227,9 +227,9 @@ pub fn handle_alloc_error(layout: Layout) -> ! { #[cfg(test)] mod tests { extern crate test; - use self::test::Bencher; - use boxed::Box; - use alloc::{Global, Alloc, Layout, handle_alloc_error}; + use test::Bencher; + use crate::boxed::Box; + use crate::alloc::{Global, Alloc, Layout, handle_alloc_error}; #[test] fn allocate_zeroed() { diff --git a/src/liballoc/benches/btree/map.rs b/src/liballoc/benches/btree/map.rs index a6f584534d174..4c17bdc3e9e9d 100644 --- a/src/liballoc/benches/btree/map.rs +++ b/src/liballoc/benches/btree/map.rs @@ -1,6 +1,7 @@ use std::iter::Iterator; use std::vec::Vec; use std::collections::BTreeMap; + use rand::{Rng, seq::SliceRandom, thread_rng}; use test::{Bencher, black_box}; diff --git a/src/liballoc/benches/btree/mod.rs b/src/liballoc/benches/btree/mod.rs index 4dc2dfd9153e7..095ca5dd2e21b 100644 --- a/src/liballoc/benches/btree/mod.rs +++ b/src/liballoc/benches/btree/mod.rs @@ -1 +1,2 @@ mod map; +mod set; diff --git a/src/liballoc/benches/btree/set.rs b/src/liballoc/benches/btree/set.rs new file mode 100644 index 0000000000000..08e1db5fbb74d --- /dev/null +++ b/src/liballoc/benches/btree/set.rs @@ -0,0 +1,88 @@ +use std::collections::BTreeSet; + +use rand::{thread_rng, Rng}; +use test::{black_box, Bencher}; + +fn random(n1: u32, n2: u32) -> [BTreeSet; 2] { + 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); + } + for _ in 0..n2 { + let i = rng.gen::(); + set2.insert(i); + } + [set1, set2] +} + +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); + } + [even, odd] +} + +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); + } + [neg, pos] +} + +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); + } + [pos, neg] +} + +macro_rules! set_intersection_bench { + ($name: ident, $sets: expr) => { + #[bench] + pub fn $name(b: &mut Bencher) { + // setup + let sets = $sets; + + // measure + b.iter(|| { + let x = sets[0].intersection(&sets[1]).count(); + 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)} diff --git a/src/liballoc/benches/lib.rs b/src/liballoc/benches/lib.rs index 08c69ee6e8507..a1884b7d54852 100644 --- a/src/liballoc/benches/lib.rs +++ b/src/liballoc/benches/lib.rs @@ -1,5 +1,4 @@ #![feature(repr_simd)] -#![feature(slice_sort_by_cached_key)] #![feature(test)] extern crate rand; diff --git a/src/liballoc/benches/slice.rs b/src/liballoc/benches/slice.rs index b9ebd74f7999a..f17fb8212ce19 100644 --- a/src/liballoc/benches/slice.rs +++ b/src/liballoc/benches/slice.rs @@ -1,8 +1,6 @@ -use rand::{thread_rng}; -use std::mem; -use std::ptr; +use std::{mem, ptr}; -use rand::{Rng, SeedableRng}; +use rand::{thread_rng, Rng, SeedableRng}; use rand::distributions::{Standard, Alphanumeric}; use rand_xorshift::XorShiftRng; use test::{Bencher, black_box}; diff --git a/src/liballoc/benches/vec_deque.rs b/src/liballoc/benches/vec_deque.rs index f7aadbdbd8266..7d2d3cfa61225 100644 --- a/src/liballoc/benches/vec_deque.rs +++ b/src/liballoc/benches/vec_deque.rs @@ -45,3 +45,10 @@ fn bench_mut_iter_1000(b: &mut Bencher) { black_box(sum); }) } + +#[bench] +fn bench_try_fold(b: &mut Bencher) { + let ring: VecDeque<_> = (0..1000).collect(); + + b.iter(|| black_box(ring.iter().try_fold(0, |a, b| Some(a + b)))) +} diff --git a/src/liballoc/benches/vec_deque_append.rs b/src/liballoc/benches/vec_deque_append.rs index 2db8fbe130907..78ec91d9e3e9b 100644 --- a/src/liballoc/benches/vec_deque_append.rs +++ b/src/liballoc/benches/vec_deque_append.rs @@ -1,4 +1,3 @@ -#![cfg_attr(stage0, feature(duration_as_u128))] use std::{collections::VecDeque, time::Instant}; const VECDEQUE_LEN: i32 = 100000; diff --git a/src/liballoc/borrow.rs b/src/liballoc/borrow.rs index 603d73100a8b4..74c80a08b12ab 100644 --- a/src/liballoc/borrow.rs +++ b/src/liballoc/borrow.rs @@ -6,14 +6,14 @@ use core::cmp::Ordering; use core::hash::{Hash, Hasher}; use core::ops::{Add, AddAssign, Deref}; -use fmt; -use string::String; - -use self::Cow::*; - #[stable(feature = "rust1", since = "1.0.0")] pub use core::borrow::{Borrow, BorrowMut}; +use crate::fmt; +use crate::string::String; + +use Cow::*; + #[stable(feature = "rust1", since = "1.0.0")] impl<'a, B: ?Sized> Borrow for Cow<'a, B> where B: ToOwned, @@ -137,11 +137,11 @@ impl ToOwned for T /// ``` /// use std::borrow::{Cow, ToOwned}; /// -/// struct Items<'a, X: 'a> where [X]: ToOwned> { +/// struct Items<'a, X: 'a> where [X]: ToOwned> { /// values: Cow<'a, [X]>, /// } /// -/// impl<'a, X: Clone + 'a> Items<'a, X> where [X]: ToOwned> { +/// impl<'a, X: Clone + 'a> Items<'a, X> where [X]: ToOwned> { /// fn new(v: Cow<'a, [X]>) -> Self { /// Items { values: v } /// } @@ -182,10 +182,8 @@ pub enum Cow<'a, B: ?Sized + 'a> } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, B: ?Sized> Clone for Cow<'a, B> - where B: ToOwned -{ - fn clone(&self) -> Cow<'a, B> { +impl Clone for Cow<'_, B> { + fn clone(&self) -> Self { match *self { Borrowed(b) => Borrowed(b), Owned(ref o) => { @@ -195,7 +193,7 @@ impl<'a, B: ?Sized> Clone for Cow<'a, B> } } - fn clone_from(&mut self, source: &Cow<'a, B>) { + fn clone_from(&mut self, source: &Self) { if let Owned(ref mut dest) = *self { if let Owned(ref o) = *source { o.borrow().clone_into(dest); @@ -207,9 +205,7 @@ impl<'a, B: ?Sized> Clone for Cow<'a, B> } } -impl<'a, B: ?Sized> Cow<'a, B> - where B: ToOwned -{ +impl Cow<'_, B> { /// Acquires a mutable reference to the owned form of the data. /// /// Clones the data if it is not already owned. @@ -285,9 +281,7 @@ impl<'a, B: ?Sized> Cow<'a, B> } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, B: ?Sized> Deref for Cow<'a, B> - where B: ToOwned -{ +impl Deref for Cow<'_, B> { type Target = B; fn deref(&self) -> &B { @@ -299,14 +293,14 @@ impl<'a, B: ?Sized> Deref for Cow<'a, B> } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, B: ?Sized> Eq for Cow<'a, B> where B: Eq + ToOwned {} +impl Eq for Cow<'_, B> where B: Eq + ToOwned {} #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, B: ?Sized> Ord for Cow<'a, B> +impl Ord for Cow<'_, B> where B: Ord + ToOwned { #[inline] - fn cmp(&self, other: &Cow<'a, B>) -> Ordering { + fn cmp(&self, other: &Self) -> Ordering { Ord::cmp(&**self, &**other) } } @@ -333,11 +327,11 @@ impl<'a, B: ?Sized> PartialOrd for Cow<'a, B> } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, B: ?Sized> fmt::Debug for Cow<'a, B> +impl fmt::Debug for Cow<'_, B> where B: fmt::Debug + ToOwned, ::Owned: fmt::Debug { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { Borrowed(ref b) => fmt::Debug::fmt(b, f), Owned(ref o) => fmt::Debug::fmt(o, f), @@ -346,11 +340,11 @@ impl<'a, B: ?Sized> fmt::Debug for Cow<'a, B> } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, B: ?Sized> fmt::Display for Cow<'a, B> +impl fmt::Display for Cow<'_, B> where B: fmt::Display + ToOwned, ::Owned: fmt::Display { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { Borrowed(ref b) => fmt::Display::fmt(b, f), Owned(ref o) => fmt::Display::fmt(o, f), @@ -359,18 +353,18 @@ impl<'a, B: ?Sized> fmt::Display for Cow<'a, B> } #[stable(feature = "default", since = "1.11.0")] -impl<'a, B: ?Sized> Default for Cow<'a, B> +impl Default for Cow<'_, B> where B: ToOwned, ::Owned: Default { /// Creates an owned Cow<'a, B> with the default value for the contained owned value. - fn default() -> Cow<'a, B> { + fn default() -> Self { Owned(::Owned::default()) } } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, B: ?Sized> Hash for Cow<'a, B> +impl Hash for Cow<'_, B> where B: Hash + ToOwned { #[inline] @@ -380,8 +374,7 @@ impl<'a, B: ?Sized> Hash for Cow<'a, B> } #[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated)] -impl<'a, T: ?Sized + ToOwned> AsRef for Cow<'a, T> { +impl AsRef for Cow<'_, T> { fn as_ref(&self) -> &T { self } diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 1c459f5c4250e..0cd2373c7f021 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -71,11 +71,11 @@ use core::ops::{ CoerceUnsized, DispatchFromDyn, Deref, DerefMut, Receiver, Generator, GeneratorState }; use core::ptr::{self, NonNull, Unique}; -use core::task::{LocalWaker, Poll}; +use core::task::{Waker, Poll}; -use vec::Vec; -use raw_vec::RawVec; -use str::from_boxed_utf8_unchecked; +use crate::vec::Vec; +use crate::raw_vec::RawVec; +use crate::str::from_boxed_utf8_unchecked; /// A pointer type for heap allocation. /// @@ -202,10 +202,15 @@ impl Box { #[unstable(feature = "ptr_internals", issue = "0", reason = "use into_raw_non_null instead")] #[inline] #[doc(hidden)] - pub fn into_unique(b: Box) -> Unique { - let unique = b.0; + pub fn into_unique(mut b: Box) -> Unique { + // 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); - unique + unsafe { Unique::new_unchecked(unique) } } /// Consumes and leaks the `Box`, returning a mutable reference, @@ -603,21 +608,21 @@ impl Box { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for Box { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(&**self, f) } } #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for Box { - 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 = "rust1", since = "1.0.0")] impl fmt::Pointer for Box { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // It's not possible to extract the inner Uniq directly from the Box, // instead we cast it to a *const which aliases the Unique let ptr: *const T = &**self; @@ -737,7 +742,7 @@ impl FnBox for F #[unstable(feature = "fnbox", reason = "will be deprecated if and when `Box` becomes usable", issue = "28796")] -impl<'a, A, R> FnOnce for Box + 'a> { +impl FnOnce for Box + '_> { type Output = R; extern "rust-call" fn call_once(self, args: A) -> R { @@ -747,7 +752,7 @@ impl<'a, A, R> FnOnce for Box + 'a> { #[unstable(feature = "fnbox", reason = "will be deprecated if and when `Box` becomes usable", issue = "28796")] -impl<'a, A, R> FnOnce for Box + Send + 'a> { +impl FnOnce for Box + Send + '_> { type Output = R; extern "rust-call" fn call_once(self, args: A) -> R { @@ -873,13 +878,22 @@ impl AsMut for Box { impl Unpin for Box { } #[unstable(feature = "generator_trait", issue = "43122")] -impl Generator for Box - where T: Generator + ?Sized -{ - type Yield = T::Yield; - type Return = T::Return; - unsafe fn resume(&mut self) -> GeneratorState { - (**self).resume() +impl Generator for Box { + type Yield = G::Yield; + type Return = G::Return; + + fn resume(mut self: Pin<&mut Self>) -> GeneratorState { + G::resume(Pin::new(&mut *self)) + } +} + +#[unstable(feature = "generator_trait", issue = "43122")] +impl Generator for Pin> { + type Yield = G::Yield; + type Return = G::Return; + + fn resume(mut self: Pin<&mut Self>) -> GeneratorState { + G::resume((*self).as_mut()) } } @@ -887,7 +901,7 @@ impl Generator for Box impl Future for Box { type Output = F::Output; - fn poll(mut self: Pin<&mut Self>, lw: &LocalWaker) -> Poll { - F::poll(Pin::new(&mut *self), lw) + fn poll(mut self: Pin<&mut Self>, waker: &Waker) -> Poll { + F::poll(Pin::new(&mut *self), waker) } } diff --git a/src/liballoc/collections/binary_heap.rs b/src/liballoc/collections/binary_heap.rs index ad544e6015e4a..ccd4e9dbc0483 100644 --- a/src/liballoc/collections/binary_heap.rs +++ b/src/liballoc/collections/binary_heap.rs @@ -151,8 +151,8 @@ use core::mem::{swap, size_of, ManuallyDrop}; use core::ptr; use core::fmt; -use slice; -use vec::{self, Vec}; +use crate::slice; +use crate::vec::{self, Vec}; use super::SpecExtend; @@ -227,8 +227,8 @@ pub struct PeekMut<'a, T: 'a + Ord> { } #[stable(feature = "collection_debug", since = "1.17.0")] -impl<'a, T: Ord + fmt::Debug> fmt::Debug for PeekMut<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +impl fmt::Debug for PeekMut<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("PeekMut") .field(&self.heap.data[0]) .finish() @@ -236,7 +236,7 @@ impl<'a, T: Ord + fmt::Debug> fmt::Debug for PeekMut<'a, T> { } #[stable(feature = "binary_heap_peek_mut", since = "1.12.0")] -impl<'a, T: Ord> Drop for PeekMut<'a, T> { +impl Drop for PeekMut<'_, T> { fn drop(&mut self) { if self.sift { self.heap.sift_down(0); @@ -245,17 +245,21 @@ impl<'a, T: Ord> Drop for PeekMut<'a, T> { } #[stable(feature = "binary_heap_peek_mut", since = "1.12.0")] -impl<'a, T: Ord> Deref for PeekMut<'a, T> { +impl Deref for PeekMut<'_, T> { type Target = T; fn deref(&self) -> &T { - &self.heap.data[0] + debug_assert!(!self.heap.is_empty()); + // SAFE: PeekMut is only instantiated for non-empty heaps + unsafe { self.heap.data.get_unchecked(0) } } } #[stable(feature = "binary_heap_peek_mut", since = "1.12.0")] -impl<'a, T: Ord> DerefMut for PeekMut<'a, T> { +impl DerefMut for PeekMut<'_, T> { fn deref_mut(&mut self) -> &mut T { - &mut self.heap.data[0] + debug_assert!(!self.heap.is_empty()); + // SAFE: PeekMut is only instantiated for non-empty heaps + unsafe { self.heap.data.get_unchecked_mut(0) } } } @@ -291,7 +295,7 @@ impl Default for BinaryHeap { #[stable(feature = "binaryheap_debug", since = "1.4.0")] impl fmt::Debug for BinaryHeap { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.iter()).finish() } } @@ -349,7 +353,7 @@ impl BinaryHeap { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn iter(&self) -> Iter { + pub fn iter(&self) -> Iter<'_, T> { Iter { iter: self.data.iter() } } @@ -400,7 +404,7 @@ impl BinaryHeap { /// assert_eq!(heap.peek(), Some(&2)); /// ``` #[stable(feature = "binary_heap_peek_mut", since = "1.12.0")] - pub fn peek_mut(&mut self) -> Option> { + pub fn peek_mut(&mut self) -> Option> { if self.is_empty() { None } else { @@ -761,7 +765,7 @@ impl BinaryHeap { /// ``` #[inline] #[stable(feature = "drain", since = "1.6.0")] - pub fn drain(&mut self) -> Drain { + pub fn drain(&mut self) -> Drain<'_, T> { Drain { iter: self.data.drain(..) } } @@ -859,13 +863,14 @@ struct Hole<'a, T: 'a> { } impl<'a, T> Hole<'a, T> { - /// Create a new Hole at index `pos`. + /// Create a new `Hole` at index `pos`. /// /// Unsafe because pos must be within the data slice. #[inline] unsafe fn new(data: &'a mut [T], pos: usize) -> Self { debug_assert!(pos < data.len()); - let elt = ptr::read(&data[pos]); + // SAFE: pos should be inside the slice + let elt = ptr::read(data.get_unchecked(pos)); Hole { data, elt: ManuallyDrop::new(elt), @@ -908,7 +913,7 @@ impl<'a, T> Hole<'a, T> { } } -impl<'a, T> Drop for Hole<'a, T> { +impl Drop for Hole<'_, T> { #[inline] fn drop(&mut self) { // fill the hole again @@ -932,8 +937,8 @@ pub struct Iter<'a, T: 'a> { } #[stable(feature = "collection_debug", since = "1.17.0")] -impl<'a, T: 'a + fmt::Debug> fmt::Debug for Iter<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +impl fmt::Debug for Iter<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("Iter") .field(&self.iter.as_slice()) .finish() @@ -942,8 +947,8 @@ impl<'a, T: 'a + fmt::Debug> fmt::Debug for Iter<'a, T> { // FIXME(#26925) Remove in favor of `#[derive(Clone)]` #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> Clone for Iter<'a, T> { - fn clone(&self) -> Iter<'a, T> { +impl Clone for Iter<'_, T> { + fn clone(&self) -> Self { Iter { iter: self.iter.clone() } } } @@ -972,14 +977,14 @@ impl<'a, T> DoubleEndedIterator for Iter<'a, T> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> ExactSizeIterator for Iter<'a, T> { +impl ExactSizeIterator for Iter<'_, T> { fn is_empty(&self) -> bool { self.iter.is_empty() } } #[stable(feature = "fused", since = "1.26.0")] -impl<'a, T> FusedIterator for Iter<'a, T> {} +impl FusedIterator for Iter<'_, T> {} /// An owning iterator over the elements of a `BinaryHeap`. /// @@ -996,7 +1001,7 @@ pub struct IntoIter { #[stable(feature = "collection_debug", since = "1.17.0")] impl fmt::Debug for IntoIter { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("IntoIter") .field(&self.iter.as_slice()) .finish() @@ -1050,7 +1055,7 @@ pub struct Drain<'a, T: 'a> { } #[stable(feature = "drain", since = "1.6.0")] -impl<'a, T: 'a> Iterator for Drain<'a, T> { +impl Iterator for Drain<'_, T> { type Item = T; #[inline] @@ -1065,7 +1070,7 @@ impl<'a, T: 'a> Iterator for Drain<'a, T> { } #[stable(feature = "drain", since = "1.6.0")] -impl<'a, T: 'a> DoubleEndedIterator for Drain<'a, T> { +impl DoubleEndedIterator for Drain<'_, T> { #[inline] fn next_back(&mut self) -> Option { self.iter.next_back() @@ -1073,14 +1078,14 @@ impl<'a, T: 'a> DoubleEndedIterator for Drain<'a, T> { } #[stable(feature = "drain", since = "1.6.0")] -impl<'a, T: 'a> ExactSizeIterator for Drain<'a, T> { +impl ExactSizeIterator for Drain<'_, T> { fn is_empty(&self) -> bool { self.iter.is_empty() } } #[stable(feature = "fused", since = "1.26.0")] -impl<'a, T: 'a> FusedIterator for Drain<'a, T> {} +impl FusedIterator for Drain<'_, T> {} #[stable(feature = "binary_heap_extras_15", since = "1.5.0")] impl From> for BinaryHeap { diff --git a/src/liballoc/collections/btree/map.rs b/src/liballoc/collections/btree/map.rs index 717650aca9600..ce29978856ffd 100644 --- a/src/liballoc/collections/btree/map.rs +++ b/src/liballoc/collections/btree/map.rs @@ -1,23 +1,18 @@ +use core::borrow::Borrow; use core::cmp::Ordering; use core::fmt::Debug; use core::hash::{Hash, Hasher}; use core::iter::{FromIterator, Peekable, FusedIterator}; use core::marker::PhantomData; use core::ops::Bound::{Excluded, Included, Unbounded}; -use core::ops::Index; -use core::ops::RangeBounds; +use core::ops::{Index, RangeBounds}; use core::{fmt, intrinsics, mem, ptr}; -use borrow::Borrow; +use super::node::{self, Handle, NodeRef, marker, InsertResult::*, ForceResult::*}; +use super::search::{self, SearchResult::*}; -use super::node::{self, Handle, NodeRef, marker}; -use super::search; - -use super::node::InsertResult::*; -use super::node::ForceResult::*; -use super::search::SearchResult::*; -use self::UnderflowResult::*; -use self::Entry::*; +use UnderflowResult::*; +use Entry::*; /// A map based on a B-Tree. /// @@ -248,7 +243,7 @@ impl super::Recover for BTreeMap fn replace(&mut self, key: K) -> Option { self.ensure_root_is_owned(); - match search::search_tree::(self.root.as_mut(), &key) { + match search::search_tree::, K, (), K>(self.root.as_mut(), &key) { Found(handle) => Some(mem::replace(handle.into_kv_mut().0, key)), GoDown(handle) => { VacantEntry { @@ -278,8 +273,8 @@ pub struct Iter<'a, K: 'a, V: 'a> { } #[stable(feature = "collection_debug", since = "1.17.0")] -impl<'a, K: 'a + fmt::Debug, V: 'a + fmt::Debug> fmt::Debug for Iter<'a, K, V> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +impl fmt::Debug for Iter<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.clone()).finish() } } @@ -314,7 +309,7 @@ pub struct IntoIter { #[stable(feature = "collection_debug", since = "1.17.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 range = Range { front: self.front.reborrow(), back: self.back.reborrow(), @@ -336,8 +331,8 @@ pub struct Keys<'a, K: 'a, V: 'a> { } #[stable(feature = "collection_debug", since = "1.17.0")] -impl<'a, K: 'a + fmt::Debug, V: 'a> fmt::Debug for Keys<'a, K, V> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +impl fmt::Debug for Keys<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.clone()).finish() } } @@ -355,8 +350,8 @@ pub struct Values<'a, K: 'a, V: 'a> { } #[stable(feature = "collection_debug", since = "1.17.0")] -impl<'a, K: 'a, V: 'a + fmt::Debug> fmt::Debug for Values<'a, K, V> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +impl fmt::Debug for Values<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.clone()).finish() } } @@ -388,8 +383,8 @@ pub struct Range<'a, K: 'a, V: 'a> { } #[stable(feature = "collection_debug", since = "1.17.0")] -impl<'a, K: 'a + fmt::Debug, V: 'a + fmt::Debug> fmt::Debug for Range<'a, K, V> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +impl fmt::Debug for Range<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.clone()).finish() } } @@ -411,8 +406,8 @@ pub struct RangeMut<'a, K: 'a, V: 'a> { } #[stable(feature = "collection_debug", since = "1.17.0")] -impl<'a, K: 'a + fmt::Debug, V: 'a + fmt::Debug> fmt::Debug for RangeMut<'a, K, V> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +impl fmt::Debug for RangeMut<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let range = Range { front: self.front.reborrow(), back: self.back.reborrow(), @@ -441,8 +436,8 @@ pub enum Entry<'a, K: 'a, V: 'a> { } #[stable(feature= "debug_btree_map", since = "1.12.0")] -impl<'a, K: 'a + Debug + Ord, V: 'a + Debug> Debug for Entry<'a, K, V> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +impl Debug for Entry<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { Vacant(ref v) => f.debug_tuple("Entry") .field(v) @@ -469,8 +464,8 @@ pub struct VacantEntry<'a, K: 'a, V: 'a> { } #[stable(feature= "debug_btree_map", since = "1.12.0")] -impl<'a, K: 'a + Debug + Ord, V: 'a> Debug for VacantEntry<'a, K, V> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +impl Debug for VacantEntry<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("VacantEntry") .field(self.key()) .finish() @@ -492,8 +487,8 @@ pub struct OccupiedEntry<'a, K: 'a, V: 'a> { } #[stable(feature= "debug_btree_map", since = "1.12.0")] -impl<'a, K: 'a + Debug + Ord, V: 'a + Debug> Debug for OccupiedEntry<'a, K, V> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +impl Debug for OccupiedEntry<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("OccupiedEntry") .field("key", self.key()) .field("value", self.get()) @@ -817,7 +812,7 @@ impl BTreeMap { /// assert_eq!(Some((&5, &"b")), map.range(4..).next()); /// ``` #[stable(feature = "btree_range", since = "1.17.0")] - pub fn range(&self, range: R) -> Range + pub fn range(&self, range: R) -> Range<'_, K, V> where T: Ord, K: Borrow, R: RangeBounds { let root1 = self.root.as_ref(); @@ -858,7 +853,7 @@ impl BTreeMap { /// } /// ``` #[stable(feature = "btree_range", since = "1.17.0")] - pub fn range_mut(&mut self, range: R) -> RangeMut + pub fn range_mut(&mut self, range: R) -> RangeMut<'_, K, V> where T: Ord, K: Borrow, R: RangeBounds { let root1 = self.root.as_mut(); @@ -891,7 +886,7 @@ impl BTreeMap { /// assert_eq!(count["a"], 3); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn entry(&mut self, key: K) -> Entry { + pub fn entry(&mut self, key: K) -> Entry<'_, K, V> { // FIXME(@porglezomp) Avoid allocating if we don't insert self.ensure_root_is_owned(); match search::search_tree(self.root.as_mut(), &key) { @@ -1201,7 +1196,7 @@ impl<'a, K: 'a, V: 'a> Iterator for Iter<'a, K, V> { } #[stable(feature = "fused", since = "1.26.0")] -impl<'a, K, V> FusedIterator for Iter<'a, K, V> {} +impl FusedIterator for Iter<'_, K, V> {} #[stable(feature = "rust1", since = "1.0.0")] impl<'a, K: 'a, V: 'a> DoubleEndedIterator for Iter<'a, K, V> { @@ -1216,15 +1211,15 @@ impl<'a, K: 'a, V: 'a> DoubleEndedIterator for Iter<'a, K, V> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K: 'a, V: 'a> ExactSizeIterator for Iter<'a, K, V> { +impl ExactSizeIterator for Iter<'_, K, V> { fn len(&self) -> usize { self.length } } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K, V> Clone for Iter<'a, K, V> { - fn clone(&self) -> Iter<'a, K, V> { +impl Clone for Iter<'_, K, V> { + fn clone(&self) -> Self { Iter { range: self.range.clone(), length: self.length, @@ -1273,14 +1268,14 @@ impl<'a, K: 'a, V: 'a> DoubleEndedIterator for IterMut<'a, K, V> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K: 'a, V: 'a> ExactSizeIterator for IterMut<'a, K, V> { +impl ExactSizeIterator for IterMut<'_, K, V> { fn len(&self) -> usize { self.length } } #[stable(feature = "fused", since = "1.26.0")] -impl<'a, K, V> FusedIterator for IterMut<'a, K, V> {} +impl FusedIterator for IterMut<'_, K, V> {} #[stable(feature = "rust1", since = "1.0.0")] impl IntoIterator for BTreeMap { @@ -1436,18 +1431,18 @@ impl<'a, K, V> DoubleEndedIterator for Keys<'a, K, V> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K, V> ExactSizeIterator for Keys<'a, K, V> { +impl ExactSizeIterator for Keys<'_, K, V> { fn len(&self) -> usize { self.inner.len() } } #[stable(feature = "fused", since = "1.26.0")] -impl<'a, K, V> FusedIterator for Keys<'a, K, V> {} +impl FusedIterator for Keys<'_, K, V> {} #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K, V> Clone for Keys<'a, K, V> { - fn clone(&self) -> Keys<'a, K, V> { +impl Clone for Keys<'_, K, V> { + fn clone(&self) -> Self { Keys { inner: self.inner.clone() } } } @@ -1473,18 +1468,18 @@ impl<'a, K, V> DoubleEndedIterator for Values<'a, K, V> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K, V> ExactSizeIterator for Values<'a, K, V> { +impl ExactSizeIterator for Values<'_, K, V> { fn len(&self) -> usize { self.inner.len() } } #[stable(feature = "fused", since = "1.26.0")] -impl<'a, K, V> FusedIterator for Values<'a, K, V> {} +impl FusedIterator for Values<'_, K, V> {} #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K, V> Clone for Values<'a, K, V> { - fn clone(&self) -> Values<'a, K, V> { +impl Clone for Values<'_, K, V> { + fn clone(&self) -> Self { Values { inner: self.inner.clone() } } } @@ -1523,15 +1518,14 @@ impl<'a, K, V> DoubleEndedIterator for ValuesMut<'a, K, V> { } #[stable(feature = "map_values_mut", since = "1.10.0")] -impl<'a, K, V> ExactSizeIterator for ValuesMut<'a, K, V> { +impl ExactSizeIterator for ValuesMut<'_, K, V> { fn len(&self) -> usize { self.inner.len() } } #[stable(feature = "fused", since = "1.26.0")] -impl<'a, K, V> FusedIterator for ValuesMut<'a, K, V> {} - +impl FusedIterator for ValuesMut<'_, K, V> {} impl<'a, K, V> Range<'a, K, V> { unsafe fn next_unchecked(&mut self) -> (&'a K, &'a V) { @@ -1609,11 +1603,11 @@ impl<'a, K, V> Range<'a, K, V> { } #[stable(feature = "fused", since = "1.26.0")] -impl<'a, K, V> FusedIterator for Range<'a, K, V> {} +impl FusedIterator for Range<'_, K, V> {} #[stable(feature = "btree_range", since = "1.17.0")] -impl<'a, K, V> Clone for Range<'a, K, V> { - fn clone(&self) -> Range<'a, K, V> { +impl Clone for Range<'_, K, V> { + fn clone(&self) -> Self { Range { front: self.front, back: self.back, @@ -1640,9 +1634,11 @@ impl<'a, K, V> RangeMut<'a, K, V> { let mut cur_handle = match handle.right_kv() { Ok(kv) => { - let (k, v) = ptr::read(&kv).into_kv_mut(); - self.front = kv.right_edge(); - return (k, v); + self.front = ptr::read(&kv).right_edge(); + // Doing the descend invalidates the references returned by `into_kv_mut`, + // so we have to do this last. + let (k, v) = kv.into_kv_mut(); + return (k, v); // coerce k from `&mut K` to `&K` } Err(last_edge) => { let next_level = last_edge.into_node().ascend().ok(); @@ -1653,9 +1649,11 @@ impl<'a, K, V> RangeMut<'a, K, V> { loop { match cur_handle.right_kv() { Ok(kv) => { - let (k, v) = ptr::read(&kv).into_kv_mut(); - self.front = first_leaf_edge(kv.right_edge().descend()); - return (k, v); + self.front = first_leaf_edge(ptr::read(&kv).right_edge().descend()); + // Doing the descend invalidates the references returned by `into_kv_mut`, + // so we have to do this last. + let (k, v) = kv.into_kv_mut(); + return (k, v); // coerce k from `&mut K` to `&K` } Err(last_edge) => { let next_level = last_edge.into_node().ascend().ok(); @@ -1678,7 +1676,7 @@ impl<'a, K, V> DoubleEndedIterator for RangeMut<'a, K, V> { } #[stable(feature = "fused", since = "1.26.0")] -impl<'a, K, V> FusedIterator for RangeMut<'a, K, V> {} +impl FusedIterator for RangeMut<'_, K, V> {} impl<'a, K, V> RangeMut<'a, K, V> { unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a mut V) { @@ -1686,9 +1684,11 @@ impl<'a, K, V> RangeMut<'a, K, V> { let mut cur_handle = match handle.left_kv() { Ok(kv) => { - let (k, v) = ptr::read(&kv).into_kv_mut(); - self.back = kv.left_edge(); - return (k, v); + self.back = ptr::read(&kv).left_edge(); + // Doing the descend invalidates the references returned by `into_kv_mut`, + // so we have to do this last. + let (k, v) = kv.into_kv_mut(); + return (k, v); // coerce k from `&mut K` to `&K` } Err(last_edge) => { let next_level = last_edge.into_node().ascend().ok(); @@ -1699,9 +1699,11 @@ impl<'a, K, V> RangeMut<'a, K, V> { loop { match cur_handle.left_kv() { Ok(kv) => { - let (k, v) = ptr::read(&kv).into_kv_mut(); - self.back = last_leaf_edge(kv.left_edge().descend()); - return (k, v); + self.back = last_leaf_edge(ptr::read(&kv).left_edge().descend()); + // Doing the descend invalidates the references returned by `into_kv_mut`, + // so we have to do this last. + let (k, v) = kv.into_kv_mut(); + return (k, v); // coerce k from `&mut K` to `&K` } Err(last_edge) => { let next_level = last_edge.into_node().ascend().ok(); @@ -1783,13 +1785,13 @@ impl Ord for BTreeMap { #[stable(feature = "rust1", since = "1.0.0")] impl Debug for BTreeMap { - 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<'a, K: Ord, Q: ?Sized, V> Index<&'a Q> for BTreeMap +impl Index<&Q> for BTreeMap where K: Borrow, Q: Ord { @@ -1940,7 +1942,7 @@ impl BTreeMap { /// assert_eq!((*first_key, *first_value), (1, "a")); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn iter(&self) -> Iter { + pub fn iter(&self) -> Iter<'_, K, V> { Iter { range: Range { front: first_leaf_edge(self.root.as_ref()), @@ -1972,7 +1974,7 @@ impl BTreeMap { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn iter_mut(&mut self) -> IterMut { + pub fn iter_mut(&mut self) -> IterMut<'_, K, V> { let root1 = self.root.as_mut(); let root2 = unsafe { ptr::read(&root1) }; IterMut { @@ -2049,7 +2051,7 @@ impl BTreeMap { /// String::from("goodbye!")]); /// ``` #[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() } } @@ -2374,7 +2376,7 @@ impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> { /// Gets a mutable reference to the value in the entry. /// - /// If you need a reference to the `OccupiedEntry` which may outlive the + /// If you need a reference to the `OccupiedEntry` that may outlive the /// destruction of the `Entry` value, see [`into_mut`]. /// /// [`into_mut`]: #method.into_mut diff --git a/src/liballoc/collections/btree/node.rs b/src/liballoc/collections/btree/node.rs index f9a21aa95db71..66d619b1298b4 100644 --- a/src/liballoc/collections/btree/node.rs +++ b/src/liballoc/collections/btree/node.rs @@ -36,8 +36,8 @@ use core::mem::{self, MaybeUninit}; use core::ptr::{self, Unique, NonNull}; use core::slice; -use alloc::{Global, Alloc, Layout}; -use boxed::Box; +use crate::alloc::{Global, Alloc, Layout}; +use crate::boxed::Box; const B: usize = 6; pub const MIN_LEN: usize = B - 1; @@ -50,11 +50,11 @@ pub const CAPACITY: usize = 2 * B - 1; /// /// We have a separate type for the header and rely on it matching the prefix of `LeafNode`, in /// order to statically allocate a single dummy node to avoid allocations. This struct is -/// `repr(C)` to prevent them from being reordered. `LeafNode` does not just contain a +/// `repr(C)` to prevent them from being reordered. `LeafNode` does not just contain a /// `NodeHeader` because we do not want unnecessary padding between `len` and the keys. -/// Crucially, `NodeHeader` can be safely transmuted to different K and V. (This is exploited +/// Crucially, `NodeHeader` can be safely transmuted to different K and V. (This is exploited /// by `as_header`.) -/// See `into_key_slice` for an explanation of K2. K2 cannot be safely transmuted around +/// See `into_key_slice` for an explanation of K2. K2 cannot be safely transmuted around /// because the size of `NodeHeader` depends on its alignment! #[repr(C)] struct NodeHeader { @@ -95,8 +95,8 @@ struct LeafNode { /// The arrays storing the actual data of the node. Only the first `len` elements of each /// array are initialized and valid. - keys: MaybeUninit<[K; CAPACITY]>, - vals: MaybeUninit<[V; CAPACITY]>, + keys: [MaybeUninit; CAPACITY], + vals: [MaybeUninit; CAPACITY], } impl LeafNode { @@ -106,8 +106,8 @@ impl LeafNode { LeafNode { // As a general policy, we leave fields uninitialized if they can be, as this should // be both slightly faster and easier to track in Valgrind. - keys: MaybeUninit::uninitialized(), - vals: MaybeUninit::uninitialized(), + keys: uninitialized_array![_; CAPACITY], + vals: uninitialized_array![_; CAPACITY], parent: ptr::null(), parent_idx: MaybeUninit::uninitialized(), len: 0 @@ -145,7 +145,7 @@ struct InternalNode { /// The pointers to the children of this node. `len + 1` of these are considered /// initialized and valid. - edges: [BoxedNode; 2 * B], + edges: [MaybeUninit>; 2 * B], } impl InternalNode { @@ -159,7 +159,7 @@ impl InternalNode { unsafe fn new() -> Self { InternalNode { data: LeafNode::new(), - edges: mem::uninitialized() + edges: uninitialized_array![_; 2*B], } } } @@ -226,7 +226,7 @@ impl Root { } pub fn as_ref(&self) - -> NodeRef { + -> NodeRef, K, V, marker::LeafOrInternal> { NodeRef { height: self.height, node: self.node.as_ptr(), @@ -236,7 +236,7 @@ impl Root { } pub fn as_mut(&mut self) - -> NodeRef { + -> NodeRef, K, V, marker::LeafOrInternal> { NodeRef { height: self.height, node: self.node.as_ptr(), @@ -258,10 +258,10 @@ impl Root { /// Adds a new internal node with a single edge, pointing to the previous root, and make that /// new node the root. This increases the height by 1 and is the opposite of `pop_level`. pub fn push_level(&mut self) - -> NodeRef { + -> NodeRef, K, V, marker::Internal> { debug_assert!(!self.is_shared_root()); let mut new_node = Box::new(unsafe { InternalNode::new() }); - new_node.edges[0] = unsafe { BoxedNode::from_ptr(self.node.as_ptr()) }; + new_node.edges[0].set(unsafe { BoxedNode::from_ptr(self.node.as_ptr()) }); self.node = BoxedNode::from_internal(new_node); self.height += 1; @@ -453,7 +453,7 @@ impl NodeRef { root: self.root, _marker: PhantomData }, - idx: unsafe { usize::from(*self.as_header().parent_idx.get_ref()) }, + idx: unsafe { usize::from(*self.as_header().parent_idx.as_ptr()) }, _marker: PhantomData }) } else { @@ -531,7 +531,7 @@ impl<'a, K, V, Type> NodeRef, K, V, Type> { /// Unsafely asserts to the compiler some static information about whether this /// node is a `Leaf`. unsafe fn cast_unchecked(&mut self) - -> NodeRef { + -> NodeRef, K, V, NewType> { NodeRef { height: self.height, @@ -551,7 +551,7 @@ impl<'a, K, V, Type> NodeRef, K, V, Type> { /// of a reborrowed handle, out of bounds. // FIXME(@gereeter) consider adding yet another type parameter to `NodeRef` that restricts // the use of `ascend` and `into_root_mut` on reborrowed pointers, preventing this unsafety. - unsafe fn reborrow_mut(&mut self) -> NodeRef { + unsafe fn reborrow_mut(&mut self) -> NodeRef, K, V, Type> { NodeRef { height: self.height, node: self.node, @@ -623,7 +623,7 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { // We cannot be the root, so `as_leaf` is okay unsafe { slice::from_raw_parts( - self.as_leaf().vals.as_ptr() as *const V, + MaybeUninit::first_ptr(&self.as_leaf().vals), self.len() ) } @@ -645,12 +645,14 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { } fn into_key_slice_mut(mut self) -> &'a mut [K] { + // Same as for `into_key_slice` above, we try to avoid a run-time check + // (the alignment comparison will usually be performed at compile-time). if mem::align_of::() > mem::align_of::>() && self.is_shared_root() { &mut [] } else { unsafe { slice::from_raw_parts_mut( - (*self.as_leaf_mut()).keys.as_mut_ptr() as *mut K, + MaybeUninit::first_ptr_mut(&mut (*self.as_leaf_mut()).keys), self.len() ) } @@ -661,15 +663,32 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { debug_assert!(!self.is_shared_root()); unsafe { slice::from_raw_parts_mut( - (*self.as_leaf_mut()).vals.as_mut_ptr() as *mut V, + MaybeUninit::first_ptr_mut(&mut (*self.as_leaf_mut()).vals), self.len() ) } } - fn into_slices_mut(self) -> (&'a mut [K], &'a mut [V]) { - let k = unsafe { ptr::read(&self) }; - (k.into_key_slice_mut(), self.into_val_slice_mut()) + fn into_slices_mut(mut self) -> (&'a mut [K], &'a mut [V]) { + debug_assert!(!self.is_shared_root()); + // We cannot use the getters here, because calling the second one + // invalidates the reference returned by the first. + // More precisely, it is the call to `len` that is the culprit, + // because that creates a shared reference to the header, which *can* + // overlap with the keys (and even the values, for ZST keys). + unsafe { + let len = self.len(); + let leaf = self.as_leaf_mut(); + let keys = slice::from_raw_parts_mut( + MaybeUninit::first_ptr_mut(&mut (*leaf).keys), + len + ); + let vals = slice::from_raw_parts_mut( + MaybeUninit::first_ptr_mut(&mut (*leaf).vals), + len + ); + (keys, vals) + } } } @@ -718,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); - ptr::write(self.as_internal_mut().edges.get_unchecked_mut(idx + 1), edge.node); + self.as_internal_mut().edges.get_unchecked_mut(idx + 1).set(edge.node); (*self.as_leaf_mut()).len += 1; @@ -749,7 +768,7 @@ impl<'a, K, V> NodeRef, K, V, marker::Internal> { slice_insert(self.vals_mut(), 0, val); slice_insert( slice::from_raw_parts_mut( - self.as_internal_mut().edges.as_mut_ptr(), + MaybeUninit::first_ptr_mut(&mut self.as_internal_mut().edges), self.len()+1 ), 0, @@ -778,7 +797,9 @@ impl<'a, K, V> NodeRef, K, V, marker::LeafOrInternal> { let edge = match self.reborrow_mut().force() { ForceResult::Leaf(_) => None, ForceResult::Internal(internal) => { - let edge = ptr::read(internal.as_internal().edges.get_unchecked(idx + 1)); + let edge = ptr::read( + internal.as_internal().edges.get_unchecked(idx + 1).as_ptr() + ); let mut new_root = Root { node: edge, height: internal.height - 1 }; (*new_root.as_mut().as_leaf_mut()).parent = ptr::null(); Some(new_root) @@ -806,7 +827,7 @@ impl<'a, K, V> NodeRef, K, V, marker::LeafOrInternal> { ForceResult::Internal(mut internal) => { let edge = slice_remove( slice::from_raw_parts_mut( - internal.as_internal_mut().edges.as_mut_ptr(), + MaybeUninit::first_ptr_mut(&mut internal.as_internal_mut().edges), old_len+1 ), 0 @@ -926,7 +947,7 @@ impl /// Temporarily takes out another, immutable handle on the same location. pub fn reborrow(&self) - -> Handle, HandleType> { + -> Handle, K, V, NodeType>, HandleType> { // We can't use Handle::new_kv or Handle::new_edge because we don't know our type Handle { @@ -951,7 +972,7 @@ impl<'a, K, V, NodeType, HandleType> // FIXME(@gereeter) consider adding yet another type parameter to `NodeRef` that restricts // the use of `ascend` and `into_root_mut` on reborrowed pointers, preventing this unsafety. pub unsafe fn reborrow_mut(&mut self) - -> Handle, HandleType> { + -> Handle, K, V, NodeType>, HandleType> { // We can't use Handle::new_kv or Handle::new_edge because we don't know our type Handle { @@ -1066,7 +1087,7 @@ impl<'a, K, V> Handle, K, V, marker::Internal>, marker:: /// Unsafely asserts to the compiler some static information about whether the underlying /// node of this handle is a `Leaf`. unsafe fn cast_unchecked(&mut self) - -> Handle, marker::Edge> { + -> Handle, K, V, NewType>, marker::Edge> { Handle::new_edge(self.node.cast_unchecked(), self.idx) } @@ -1085,7 +1106,7 @@ impl<'a, K, V> Handle, K, V, marker::Internal>, marker:: slice_insert( slice::from_raw_parts_mut( - self.node.as_internal_mut().edges.as_mut_ptr(), + MaybeUninit::first_ptr_mut(&mut self.node.as_internal_mut().edges), self.node.len() ), self.idx + 1, @@ -1140,7 +1161,9 @@ impl pub fn descend(self) -> NodeRef { NodeRef { height: self.node.height - 1, - node: unsafe { self.node.as_internal().edges.get_unchecked(self.idx).as_ptr() }, + node: unsafe { + (&*self.node.as_internal().edges.get_unchecked(self.idx).as_ptr()).as_ptr() + }, root: self.node.root, _marker: PhantomData } @@ -1291,7 +1314,7 @@ impl<'a, K, V> Handle, K, V, marker::Internal>, marker:: } } - /// Returns whether it is valid to call `.merge()`, i.e., whether there is enough room in + /// Returns `true` if it is valid to call `.merge()`, i.e., whether there is enough room in /// a node to hold the combination of the nodes to the left and right of this handle along /// with the key/value pair at this handle. pub fn can_merge(&self) -> bool { @@ -1554,8 +1577,8 @@ unsafe fn move_kv( // Source and destination must have the same height. unsafe fn move_edges( - mut source: NodeRef, source_offset: usize, - mut dest: NodeRef, dest_offset: usize, + mut source: NodeRef, K, V, marker::Internal>, source_offset: usize, + mut dest: NodeRef, K, V, marker::Internal>, dest_offset: usize, count: usize) { let source_ptr = source.as_internal_mut().edges.as_mut_ptr(); @@ -1569,7 +1592,7 @@ unsafe fn move_edges( impl Handle, HandleType> { - /// Check whether the underlying node is an `Internal` node or a `Leaf` node. + /// Checks whether the underlying node is an `Internal` node or a `Leaf` node. pub fn force(self) -> ForceResult< Handle, HandleType>, Handle, HandleType> diff --git a/src/liballoc/collections/btree/search.rs b/src/liballoc/collections/btree/search.rs index 9010de7c16ac3..dfb67d2ea5756 100644 --- a/src/liballoc/collections/btree/search.rs +++ b/src/liballoc/collections/btree/search.rs @@ -1,11 +1,9 @@ +use core::borrow::Borrow; use core::cmp::Ordering; -use borrow::Borrow; +use super::node::{Handle, NodeRef, marker, ForceResult::*}; -use super::node::{Handle, NodeRef, marker}; - -use super::node::ForceResult::*; -use self::SearchResult::*; +use SearchResult::*; pub enum SearchResult { Found(Handle, marker::KV>), diff --git a/src/liballoc/collections/btree/set.rs b/src/liballoc/collections/btree/set.rs index 71fec7da9a5ed..2be6455ad5903 100644 --- a/src/liballoc/collections/btree/set.rs +++ b/src/liballoc/collections/btree/set.rs @@ -1,15 +1,14 @@ // This is pretty much entirely stolen from TreeSet, since BTreeMap has an identical interface // to TreeMap +use core::borrow::Borrow; use core::cmp::Ordering::{self, Less, Greater, Equal}; use core::cmp::{min, max}; -use core::fmt::Debug; -use core::fmt; +use core::fmt::{self, Debug}; use core::iter::{Peekable, FromIterator, FusedIterator}; use core::ops::{BitOr, BitAnd, BitXor, Sub, RangeBounds}; -use borrow::Borrow; -use collections::btree_map::{self, BTreeMap, Keys}; +use crate::collections::btree_map::{self, BTreeMap, Keys}; use super::Recover; // FIXME(conventions): implement bounded iterators @@ -76,8 +75,8 @@ pub struct Iter<'a, T: 'a> { } #[stable(feature = "collection_debug", since = "1.17.0")] -impl<'a, T: 'a + fmt::Debug> fmt::Debug for Iter<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +impl fmt::Debug for Iter<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("Iter") .field(&self.iter.clone()) .finish() @@ -124,8 +123,8 @@ pub struct Difference<'a, T: 'a> { } #[stable(feature = "collection_debug", since = "1.17.0")] -impl<'a, T: 'a + fmt::Debug> fmt::Debug for Difference<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +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) @@ -147,8 +146,8 @@ pub struct SymmetricDifference<'a, T: 'a> { } #[stable(feature = "collection_debug", since = "1.17.0")] -impl<'a, T: 'a + fmt::Debug> fmt::Debug for SymmetricDifference<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +impl fmt::Debug for SymmetricDifference<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("SymmetricDifference") .field(&self.a) .field(&self.b) @@ -170,8 +169,8 @@ pub struct Intersection<'a, T: 'a> { } #[stable(feature = "collection_debug", since = "1.17.0")] -impl<'a, T: 'a + fmt::Debug> fmt::Debug for Intersection<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +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) @@ -193,8 +192,8 @@ pub struct Union<'a, T: 'a> { } #[stable(feature = "collection_debug", since = "1.17.0")] -impl<'a, T: 'a + fmt::Debug> fmt::Debug for Union<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +impl fmt::Debug for Union<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("Union") .field(&self.a) .field(&self.b) @@ -241,7 +240,7 @@ impl BTreeSet { /// assert_eq!(Some(&5), set.range(4..).next()); /// ``` #[stable(feature = "btree_range", since = "1.17.0")] - pub fn range(&self, range: R) -> Range + pub fn range(&self, range: R) -> Range<'_, T> where K: Ord, T: Borrow, R: RangeBounds { Range { iter: self.map.range(range) } @@ -557,7 +556,7 @@ impl BTreeSet { Recover::replace(&mut self.map, value) } - /// Removes a value from the set. Returns `true` if the value was + /// Removes a value from the set. Returns whether the value was /// present in the set. /// /// The value may be any borrowed form of the set's value type, @@ -703,7 +702,7 @@ impl BTreeSet { /// assert_eq!(set_iter.next(), None); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn iter(&self) -> Iter { + pub fn iter(&self) -> Iter<'_, T> { Iter { iter: self.map.keys() } } @@ -809,7 +808,7 @@ impl Default for BTreeSet { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, 'b, T: Ord + Clone> Sub<&'b BTreeSet> for &'a BTreeSet { +impl Sub<&BTreeSet> for &BTreeSet { type Output = BTreeSet; /// Returns the difference of `self` and `rhs` as a new `BTreeSet`. @@ -832,7 +831,7 @@ impl<'a, 'b, T: Ord + Clone> Sub<&'b BTreeSet> for &'a BTreeSet { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, 'b, T: Ord + Clone> BitXor<&'b BTreeSet> for &'a BTreeSet { +impl BitXor<&BTreeSet> for &BTreeSet { type Output = BTreeSet; /// Returns the symmetric difference of `self` and `rhs` as a new `BTreeSet`. @@ -855,7 +854,7 @@ impl<'a, 'b, T: Ord + Clone> BitXor<&'b BTreeSet> for &'a BTreeSet { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, 'b, T: Ord + Clone> BitAnd<&'b BTreeSet> for &'a BTreeSet { +impl BitAnd<&BTreeSet> for &BTreeSet { type Output = BTreeSet; /// Returns the intersection of `self` and `rhs` as a new `BTreeSet`. @@ -878,7 +877,7 @@ impl<'a, 'b, T: Ord + Clone> BitAnd<&'b BTreeSet> for &'a BTreeSet { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, 'b, T: Ord + Clone> BitOr<&'b BTreeSet> for &'a BTreeSet { +impl BitOr<&BTreeSet> for &BTreeSet { type Output = BTreeSet; /// Returns the union of `self` and `rhs` as a new `BTreeSet`. @@ -902,14 +901,14 @@ impl<'a, 'b, T: Ord + Clone> BitOr<&'b BTreeSet> for &'a BTreeSet { #[stable(feature = "rust1", since = "1.0.0")] impl Debug for BTreeSet { - 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() } } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> Clone for Iter<'a, T> { - fn clone(&self) -> Iter<'a, T> { +impl Clone for Iter<'_, T> { + fn clone(&self) -> Self { Iter { iter: self.iter.clone() } } } @@ -931,12 +930,12 @@ impl<'a, T> DoubleEndedIterator for Iter<'a, T> { } } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> ExactSizeIterator for Iter<'a, T> { +impl ExactSizeIterator for Iter<'_, T> { fn len(&self) -> usize { self.iter.len() } } #[stable(feature = "fused", since = "1.26.0")] -impl<'a, T> FusedIterator for Iter<'a, T> {} +impl FusedIterator for Iter<'_, T> {} #[stable(feature = "rust1", since = "1.0.0")] impl Iterator for IntoIter { @@ -964,8 +963,8 @@ impl ExactSizeIterator for IntoIter { impl FusedIterator for IntoIter {} #[stable(feature = "btree_range", since = "1.17.0")] -impl<'a, T> Clone for Range<'a, T> { - fn clone(&self) -> Range<'a, T> { +impl Clone for Range<'_, T> { + fn clone(&self) -> Self { Range { iter: self.iter.clone() } } } @@ -987,9 +986,9 @@ impl<'a, T> DoubleEndedIterator for Range<'a, T> { } #[stable(feature = "fused", since = "1.26.0")] -impl<'a, T> FusedIterator for Range<'a, T> {} +impl FusedIterator for Range<'_, T> {} -/// Compare `x` and `y`, but return `short` if x is None and `long` if y is None +/// Compares `x` and `y`, but return `short` if x is None and `long` if y is None fn cmp_opt(x: Option<&T>, y: Option<&T>, short: Ordering, long: Ordering) -> Ordering { match (x, y) { (None, _) => short, @@ -999,8 +998,8 @@ fn cmp_opt(x: Option<&T>, y: Option<&T>, short: Ordering, long: Ordering } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> Clone for Difference<'a, T> { - fn clone(&self) -> Difference<'a, T> { +impl Clone for Difference<'_, T> { + fn clone(&self) -> Self { Difference { a: self.a.clone(), b: self.b.clone(), @@ -1034,11 +1033,11 @@ impl<'a, T: Ord> Iterator for Difference<'a, T> { } #[stable(feature = "fused", since = "1.26.0")] -impl<'a, T: Ord> FusedIterator for Difference<'a, T> {} +impl FusedIterator for Difference<'_, T> {} #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> Clone for SymmetricDifference<'a, T> { - fn clone(&self) -> SymmetricDifference<'a, T> { +impl Clone for SymmetricDifference<'_, T> { + fn clone(&self) -> Self { SymmetricDifference { a: self.a.clone(), b: self.b.clone(), @@ -1068,11 +1067,11 @@ impl<'a, T: Ord> Iterator for SymmetricDifference<'a, T> { } #[stable(feature = "fused", since = "1.26.0")] -impl<'a, T: Ord> FusedIterator for SymmetricDifference<'a, T> {} +impl FusedIterator for SymmetricDifference<'_, T> {} #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> Clone for Intersection<'a, T> { - fn clone(&self) -> Intersection<'a, T> { +impl Clone for Intersection<'_, T> { + fn clone(&self) -> Self { Intersection { a: self.a.clone(), b: self.b.clone(), @@ -1106,11 +1105,11 @@ impl<'a, T: Ord> Iterator for Intersection<'a, T> { } #[stable(feature = "fused", since = "1.26.0")] -impl<'a, T: Ord> FusedIterator for Intersection<'a, T> {} +impl FusedIterator for Intersection<'_, T> {} #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> Clone for Union<'a, T> { - fn clone(&self) -> Union<'a, T> { +impl Clone for Union<'_, T> { + fn clone(&self) -> Self { Union { a: self.a.clone(), b: self.b.clone(), @@ -1140,4 +1139,4 @@ impl<'a, T: Ord> Iterator for Union<'a, T> { } #[stable(feature = "fused", since = "1.26.0")] -impl<'a, T: Ord> FusedIterator for Union<'a, T> {} +impl FusedIterator for Union<'_, T> {} diff --git a/src/liballoc/collections/linked_list.rs b/src/liballoc/collections/linked_list.rs index 804a2e9c8873b..c2ee2e63156cf 100644 --- a/src/liballoc/collections/linked_list.rs +++ b/src/liballoc/collections/linked_list.rs @@ -20,7 +20,7 @@ use core::marker::PhantomData; use core::mem; use core::ptr::NonNull; -use boxed::Box; +use crate::boxed::Box; use super::SpecExtend; /// A doubly-linked list with owned nodes. @@ -61,8 +61,8 @@ pub struct Iter<'a, T: 'a> { } #[stable(feature = "collection_debug", since = "1.17.0")] -impl<'a, T: 'a + fmt::Debug> fmt::Debug for Iter<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +impl fmt::Debug for Iter<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("Iter") .field(&self.len) .finish() @@ -71,7 +71,7 @@ impl<'a, T: 'a + fmt::Debug> fmt::Debug for Iter<'a, T> { // FIXME(#26925) Remove in favor of `#[derive(Clone)]` #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> Clone for Iter<'a, T> { +impl Clone for Iter<'_, T> { fn clone(&self) -> Self { Iter { ..*self } } @@ -93,8 +93,8 @@ pub struct IterMut<'a, T: 'a> { } #[stable(feature = "collection_debug", since = "1.17.0")] -impl<'a, T: 'a + fmt::Debug> fmt::Debug for IterMut<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +impl fmt::Debug for IterMut<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("IterMut") .field(&self.list) .field(&self.len) @@ -117,7 +117,7 @@ pub struct IntoIter { #[stable(feature = "collection_debug", since = "1.17.0")] impl fmt::Debug for IntoIter { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("IntoIter") .field(&self.list) .finish() @@ -331,7 +331,7 @@ impl LinkedList { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn iter(&self) -> Iter { + pub fn iter(&self) -> Iter<'_, T> { Iter { head: self.head, tail: self.tail, @@ -365,7 +365,7 @@ impl LinkedList { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn iter_mut(&mut self) -> IterMut { + pub fn iter_mut(&mut self) -> IterMut<'_, T> { IterMut { head: self.head, tail: self.tail, @@ -764,7 +764,7 @@ impl LinkedList { /// assert_eq!(odds.into_iter().collect::>(), vec![1, 3, 5, 9, 11, 13, 15]); /// ``` #[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] - pub fn drain_filter(&mut self, filter: F) -> DrainFilter + pub fn drain_filter(&mut self, filter: F) -> DrainFilter<'_, T, F> where F: FnMut(&mut T) -> bool { // avoid borrow issues. @@ -832,10 +832,10 @@ impl<'a, T> DoubleEndedIterator for Iter<'a, T> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> ExactSizeIterator for Iter<'a, T> {} +impl ExactSizeIterator for Iter<'_, T> {} #[stable(feature = "fused", since = "1.26.0")] -impl<'a, T> FusedIterator for Iter<'a, T> {} +impl FusedIterator for Iter<'_, T> {} #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> Iterator for IterMut<'a, T> { @@ -881,12 +881,12 @@ impl<'a, T> DoubleEndedIterator for IterMut<'a, T> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> ExactSizeIterator for IterMut<'a, T> {} +impl ExactSizeIterator for IterMut<'_, T> {} #[stable(feature = "fused", since = "1.26.0")] -impl<'a, T> FusedIterator for IterMut<'a, T> {} +impl FusedIterator for IterMut<'_, T> {} -impl<'a, T> IterMut<'a, T> { +impl IterMut<'_, T> { /// Inserts the given element just after the element most recently returned by `.next()`. /// The inserted element does not appear in the iteration. /// @@ -982,7 +982,7 @@ pub struct DrainFilter<'a, T: 'a, F: 'a> } #[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] -impl<'a, T, F> Iterator for DrainFilter<'a, T, F> +impl Iterator for DrainFilter<'_, T, F> where F: FnMut(&mut T) -> bool, { type Item = T; @@ -1009,7 +1009,7 @@ impl<'a, T, F> Iterator for DrainFilter<'a, T, F> } #[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] -impl<'a, T, F> Drop for DrainFilter<'a, T, F> +impl Drop for DrainFilter<'_, T, F> where F: FnMut(&mut T) -> bool, { fn drop(&mut self) { @@ -1018,10 +1018,10 @@ impl<'a, T, F> Drop for DrainFilter<'a, T, F> } #[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] -impl<'a, T: 'a + fmt::Debug, F> fmt::Debug for DrainFilter<'a, T, F> +impl fmt::Debug for DrainFilter<'_, T, F> where F: FnMut(&mut T) -> bool { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("DrainFilter") .field(&self.list) .finish() @@ -1164,7 +1164,7 @@ impl Clone for LinkedList { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for LinkedList { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self).finish() } } @@ -1200,16 +1200,16 @@ unsafe impl Send for LinkedList {} unsafe impl Sync for LinkedList {} #[stable(feature = "rust1", since = "1.0.0")] -unsafe impl<'a, T: Sync> Send for Iter<'a, T> {} +unsafe impl Send for Iter<'_, T> {} #[stable(feature = "rust1", since = "1.0.0")] -unsafe impl<'a, T: Sync> Sync for Iter<'a, T> {} +unsafe impl Sync for Iter<'_, T> {} #[stable(feature = "rust1", since = "1.0.0")] -unsafe impl<'a, T: Send> Send for IterMut<'a, T> {} +unsafe impl Send for IterMut<'_, T> {} #[stable(feature = "rust1", since = "1.0.0")] -unsafe impl<'a, T: Sync> Sync for IterMut<'a, T> {} +unsafe impl Sync for IterMut<'_, T> {} #[cfg(test)] mod tests { diff --git a/src/liballoc/collections/mod.rs b/src/liballoc/collections/mod.rs index 138f5d79bb008..5a33ddc14f004 100644 --- a/src/liballoc/collections/mod.rs +++ b/src/liballoc/collections/mod.rs @@ -23,25 +23,25 @@ pub mod btree_set { #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] -pub use self::binary_heap::BinaryHeap; +pub use binary_heap::BinaryHeap; #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] -pub use self::btree_map::BTreeMap; +pub use btree_map::BTreeMap; #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] -pub use self::btree_set::BTreeSet; +pub use btree_set::BTreeSet; #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] -pub use self::linked_list::LinkedList; +pub use linked_list::LinkedList; #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] -pub use self::vec_deque::VecDeque; +pub use vec_deque::VecDeque; -use alloc::{AllocErr, LayoutErr}; +use crate::alloc::{AllocErr, LayoutErr}; /// Augments `AllocErr` with a CapacityOverflow variant. #[derive(Clone, PartialEq, Eq, Debug)] diff --git a/src/liballoc/collections/vec_deque.rs b/src/liballoc/collections/vec_deque.rs index b3f7ef5fd6ecc..4e90f783ec6a5 100644 --- a/src/liballoc/collections/vec_deque.rs +++ b/src/liballoc/collections/vec_deque.rs @@ -7,22 +7,19 @@ #![stable(feature = "rust1", since = "1.0.0")] -use core::cmp::Ordering; +use core::cmp::{self, Ordering}; use core::fmt; use core::iter::{repeat_with, FromIterator, FusedIterator}; use core::mem; use core::ops::Bound::{Excluded, Included, Unbounded}; -use core::ops::{Index, IndexMut, RangeBounds}; -use core::ptr; -use core::ptr::NonNull; +use core::ops::{Index, IndexMut, RangeBounds, Try}; +use core::ptr::{self, NonNull}; use core::slice; - use core::hash::{Hash, Hasher}; -use core::cmp; -use collections::CollectionAllocErr; -use raw_vec::RawVec; -use vec::Vec; +use crate::collections::CollectionAllocErr; +use crate::raw_vec::RawVec; +use crate::vec::Vec; const INITIAL_CAPACITY: usize = 7; // 2^3 - 1 const MINIMUM_CAPACITY: usize = 1; // 2 - 1 @@ -127,7 +124,7 @@ impl VecDeque { ptr::write(self.ptr().add(off), value); } - /// Returns `true` if and only if the buffer is at full capacity. + /// Returns `true` if the buffer is at full capacity. #[inline] fn is_full(&self) -> bool { self.cap() - self.len() == 1 @@ -563,7 +560,7 @@ impl VecDeque { /// Does nothing if the capacity is already sufficient. /// /// Note that the allocator may give the collection more space than it - /// requests. Therefore capacity can not be relied upon to be precisely + /// requests. Therefore, capacity can not be relied upon to be precisely /// minimal. Prefer `reserve` if future insertions are expected. /// /// # Errors @@ -798,7 +795,7 @@ impl VecDeque { /// assert_eq!(&c[..], b); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn iter(&self) -> Iter { + pub fn iter(&self) -> Iter<'_, T> { Iter { tail: self.tail, head: self.head, @@ -824,7 +821,7 @@ impl VecDeque { /// assert_eq!(&buf.iter_mut().collect::>()[..], b); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn iter_mut(&mut self) -> IterMut { + pub fn iter_mut(&mut self) -> IterMut<'_, T> { IterMut { tail: self.tail, head: self.head, @@ -927,7 +924,7 @@ impl VecDeque { self.tail == self.head } - /// Create a draining iterator that removes the specified range in the + /// Creates a draining iterator that removes the specified range in the /// `VecDeque` and yields the removed items. /// /// Note 1: The element range is removed even if the iterator is not @@ -935,7 +932,7 @@ impl VecDeque { /// /// Note 2: It is unspecified how many elements are removed from the deque, /// if the `Drain` value is not dropped, but the borrow it holds expires - /// (eg. due to mem::forget). + /// (e.g., due to `mem::forget`). /// /// # Panics /// @@ -958,7 +955,7 @@ impl VecDeque { /// ``` #[inline] #[stable(feature = "drain", since = "1.6.0")] - pub fn drain(&mut self, range: R) -> Drain + pub fn drain(&mut self, range: R) -> Drain<'_, T> where R: RangeBounds { // Memory safety @@ -1925,7 +1922,7 @@ impl VecDeque { /// /// # Panics /// - /// If `mid` is greater than `len()`. Note that `mid == len()` + /// If `mid` is greater than `len()`. Note that `mid == len()` /// does _not_ panic and is a no-op rotation. /// /// # Complexity @@ -1970,7 +1967,7 @@ impl VecDeque { /// /// # Panics /// - /// If `k` is greater than `len()`. Note that `k == len()` + /// If `k` is greater than `len()`. Note that `k == len()` /// does _not_ panic and is a no-op rotation. /// /// # Complexity @@ -2083,7 +2080,7 @@ trait RingSlices: Sized { } } -impl<'a, T> RingSlices for &'a [T] { +impl RingSlices for &[T] { fn slice(self, from: usize, to: usize) -> Self { &self[from..to] } @@ -2092,7 +2089,7 @@ impl<'a, T> RingSlices for &'a [T] { } } -impl<'a, T> RingSlices for &'a mut [T] { +impl RingSlices for &mut [T] { fn slice(self, from: usize, to: usize) -> Self { &mut self[from..to] } @@ -2123,8 +2120,8 @@ pub struct Iter<'a, T: 'a> { } #[stable(feature = "collection_debug", since = "1.17.0")] -impl<'a, T: 'a + fmt::Debug> fmt::Debug for Iter<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +impl fmt::Debug for Iter<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let (front, back) = RingSlices::ring_slices(self.ring, self.head, self.tail); f.debug_tuple("Iter") .field(&front) @@ -2135,8 +2132,8 @@ impl<'a, T: 'a + fmt::Debug> fmt::Debug for Iter<'a, T> { // FIXME(#26925) Remove in favor of `#[derive(Clone)]` #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> Clone for Iter<'a, T> { - fn clone(&self) -> Iter<'a, T> { +impl Clone for Iter<'_, T> { + fn clone(&self) -> Self { Iter { ring: self.ring, tail: self.tail, @@ -2172,6 +2169,31 @@ impl<'a, T> Iterator for Iter<'a, T> { accum = front.iter().fold(accum, &mut f); back.iter().fold(accum, &mut f) } + + fn try_fold(&mut self, init: B, mut f: F) -> R + where + Self: Sized, + F: FnMut(B, Self::Item) -> R, + R: Try, + { + let (mut iter, final_res); + if self.tail <= self.head { + // single slice self.ring[self.tail..self.head] + iter = self.ring[self.tail..self.head].iter(); + final_res = iter.try_fold(init, &mut f); + } else { + // two slices: self.ring[self.tail..], self.ring[..self.head] + let (front, back) = self.ring.split_at(self.tail); + let mut back_iter = back.iter(); + let res = back_iter.try_fold(init, &mut f); + let len = self.ring.len(); + self.tail = (self.ring.len() - back_iter.len()) & (len - 1); + iter = front[..self.head].iter(); + final_res = iter.try_fold(res?, &mut f); + } + self.tail = self.head - iter.len(); + final_res + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -2192,17 +2214,41 @@ impl<'a, T> DoubleEndedIterator for Iter<'a, T> { accum = back.iter().rfold(accum, &mut f); front.iter().rfold(accum, &mut f) } + + fn try_rfold(&mut self, init: B, mut f: F) -> R + where + Self: Sized, + F: FnMut(B, Self::Item) -> R, + R: Try, + { + let (mut iter, final_res); + if self.tail <= self.head { + // single slice self.ring[self.tail..self.head] + iter = self.ring[self.tail..self.head].iter(); + final_res = iter.try_rfold(init, &mut f); + } else { + // two slices: self.ring[self.tail..], self.ring[..self.head] + let (front, back) = self.ring.split_at(self.tail); + let mut front_iter = front[..self.head].iter(); + let res = front_iter.try_rfold(init, &mut f); + self.head = front_iter.len(); + iter = back.iter(); + final_res = iter.try_rfold(res?, &mut f); + } + self.head = self.tail + iter.len(); + final_res + } } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> ExactSizeIterator for Iter<'a, T> { +impl ExactSizeIterator for Iter<'_, T> { fn is_empty(&self) -> bool { self.head == self.tail } } #[stable(feature = "fused", since = "1.26.0")] -impl<'a, T> FusedIterator for Iter<'a, T> {} +impl FusedIterator for Iter<'_, T> {} /// A mutable iterator over the elements of a `VecDeque`. @@ -2220,8 +2266,8 @@ pub struct IterMut<'a, T: 'a> { } #[stable(feature = "collection_debug", since = "1.17.0")] -impl<'a, T: 'a + fmt::Debug> fmt::Debug for IterMut<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +impl fmt::Debug for IterMut<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let (front, back) = RingSlices::ring_slices(&*self.ring, self.head, self.tail); f.debug_tuple("IterMut") .field(&front) @@ -2288,14 +2334,14 @@ impl<'a, T> DoubleEndedIterator for IterMut<'a, T> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> ExactSizeIterator for IterMut<'a, T> { +impl ExactSizeIterator for IterMut<'_, T> { fn is_empty(&self) -> bool { self.head == self.tail } } #[stable(feature = "fused", since = "1.26.0")] -impl<'a, T> FusedIterator for IterMut<'a, T> {} +impl FusedIterator for IterMut<'_, T> {} /// An owning iterator over the elements of a `VecDeque`. /// @@ -2312,7 +2358,7 @@ pub struct IntoIter { #[stable(feature = "collection_debug", since = "1.17.0")] impl fmt::Debug for IntoIter { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("IntoIter") .field(&self.inner) .finish() @@ -2369,8 +2415,8 @@ pub struct Drain<'a, T: 'a> { } #[stable(feature = "collection_debug", since = "1.17.0")] -impl<'a, T: 'a + fmt::Debug> fmt::Debug for Drain<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +impl fmt::Debug for Drain<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("Drain") .field(&self.after_tail) .field(&self.after_head) @@ -2380,12 +2426,12 @@ impl<'a, T: 'a + fmt::Debug> fmt::Debug for Drain<'a, T> { } #[stable(feature = "drain", since = "1.6.0")] -unsafe impl<'a, T: Sync> Sync for Drain<'a, T> {} +unsafe impl Sync for Drain<'_, T> {} #[stable(feature = "drain", since = "1.6.0")] -unsafe impl<'a, T: Send> Send for Drain<'a, T> {} +unsafe impl Send for Drain<'_, T> {} #[stable(feature = "drain", since = "1.6.0")] -impl<'a, T: 'a> Drop for Drain<'a, T> { +impl Drop for Drain<'_, T> { fn drop(&mut self) { self.for_each(drop); @@ -2432,7 +2478,7 @@ impl<'a, T: 'a> Drop for Drain<'a, T> { } #[stable(feature = "drain", since = "1.6.0")] -impl<'a, T: 'a> Iterator for Drain<'a, T> { +impl Iterator for Drain<'_, T> { type Item = T; #[inline] @@ -2447,7 +2493,7 @@ impl<'a, T: 'a> Iterator for Drain<'a, T> { } #[stable(feature = "drain", since = "1.6.0")] -impl<'a, T: 'a> DoubleEndedIterator for Drain<'a, T> { +impl DoubleEndedIterator for Drain<'_, T> { #[inline] fn next_back(&mut self) -> Option { self.iter.next_back().map(|elt| unsafe { ptr::read(elt) }) @@ -2455,10 +2501,10 @@ impl<'a, T: 'a> DoubleEndedIterator for Drain<'a, T> { } #[stable(feature = "drain", since = "1.6.0")] -impl<'a, T: 'a> ExactSizeIterator for Drain<'a, T> {} +impl ExactSizeIterator for Drain<'_, T> {} #[stable(feature = "fused", since = "1.26.0")] -impl<'a, T: 'a> FusedIterator for Drain<'a, T> {} +impl FusedIterator for Drain<'_, T> {} #[stable(feature = "rust1", since = "1.0.0")] impl PartialEq for VecDeque { @@ -2508,7 +2554,7 @@ macro_rules! __impl_slice_eq1 { }; ($Lhs: ty, $Rhs: ty, $Bound: ident) => { #[stable(feature = "vec_deque_partial_eq_slice", since = "1.17.0")] - impl<'a, 'b, A: $Bound, B> PartialEq<$Rhs> for $Lhs where A: PartialEq { + impl PartialEq<$Rhs> for $Lhs where A: PartialEq { fn eq(&self, other: &$Rhs) -> bool { if self.len() != other.len() { return false; @@ -2522,15 +2568,15 @@ macro_rules! __impl_slice_eq1 { } __impl_slice_eq1! { VecDeque, Vec } -__impl_slice_eq1! { VecDeque, &'b [B] } -__impl_slice_eq1! { VecDeque, &'b mut [B] } +__impl_slice_eq1! { VecDeque, &[B] } +__impl_slice_eq1! { VecDeque, &mut [B] } macro_rules! array_impls { ($($N: expr)+) => { $( __impl_slice_eq1! { VecDeque, [B; $N] } - __impl_slice_eq1! { VecDeque, &'b [B; $N] } - __impl_slice_eq1! { VecDeque, &'b mut [B; $N] } + __impl_slice_eq1! { VecDeque, &[B; $N] } + __impl_slice_eq1! { VecDeque, &mut [B; $N] } )+ } } @@ -2646,7 +2692,7 @@ impl<'a, T: 'a + Copy> Extend<&'a T> for VecDeque { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for VecDeque { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self).finish() } } @@ -2750,7 +2796,7 @@ impl From> for Vec { #[cfg(test)] mod tests { - use test; + use ::test; use super::VecDeque; @@ -3028,7 +3074,7 @@ mod tests { #[test] fn test_from_vec() { - use vec::Vec; + use crate::vec::Vec; for cap in 0..35 { for len in 0..=cap { let mut vec = Vec::with_capacity(cap); @@ -3044,7 +3090,7 @@ mod tests { #[test] fn test_vec_from_vecdeque() { - use vec::Vec; + use crate::vec::Vec; fn create_vec_and_test_convert(cap: usize, offset: usize, len: usize) { let mut vd = VecDeque::with_capacity(cap); @@ -3106,7 +3152,7 @@ mod tests { #[test] fn issue_53529() { - use boxed::Box; + use crate::boxed::Box; let mut dst = VecDeque::new(); dst.push_front(Box::new(1)); diff --git a/src/liballoc/fmt.rs b/src/liballoc/fmt.rs index a1e7533449c69..d2ba9b001916c 100644 --- a/src/liballoc/fmt.rs +++ b/src/liballoc/fmt.rs @@ -27,7 +27,7 @@ //! will then parse the format string and determine if the list of arguments //! provided is suitable to pass to this format string. //! -//! To convert a single value to a string, use the [`to_string`] method. This +//! To convert a single value to a string, use the [`to_string`] method. This //! will use the [`Display`] formatting trait. //! //! ## Positional parameters @@ -102,7 +102,7 @@ //! When requesting that an argument be formatted with a particular type, you //! are actually requesting that an argument ascribes to a particular trait. //! This allows multiple actual types to be formatted via `{:x}` (like [`i8`] as -//! well as [`isize`]). The current mapping of types to traits is: +//! well as [`isize`]). The current mapping of types to traits is: //! //! * *nothing* ⇒ [`Display`] //! * `?` ⇒ [`Debug`] @@ -427,7 +427,7 @@ //! 3. An asterisk `.*`: //! //! `.*` means that this `{...}` is associated with *two* format inputs rather than one: the -//! first input holds the `usize` precision, and the second holds the value to print. Note that +//! first input holds the `usize` precision, and the second holds the value to print. Note that //! in this case, if one uses the format string `{:.*}`, then the `` part refers //! to the *value* to print, and the `precision` must come in the input preceding ``. //! @@ -527,7 +527,7 @@ pub use core::fmt::{DebugList, DebugMap, DebugSet, DebugStruct, DebugTuple}; #[stable(feature = "fmt_flags_align", since = "1.28.0")] pub use core::fmt::{Alignment}; -use string; +use crate::string; /// The `format` function takes an [`Arguments`] struct and returns the resulting /// formatted string. @@ -557,7 +557,7 @@ use string; /// [`format_args!`]: ../../std/macro.format_args.html /// [`format!`]: ../../std/macro.format.html #[stable(feature = "rust1", since = "1.0.0")] -pub fn format(args: Arguments) -> string::String { +pub fn format(args: Arguments<'_>) -> string::String { let capacity = args.estimated_capacity(); let mut output = string::String::with_capacity(capacity); output diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 3050a93ef39a0..440ce8ac5e842 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -55,18 +55,19 @@ reason = "this library is unlikely to be stabilized in its current \ form or name", issue = "27783")] -#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", - html_favicon_url = "https://doc.rust-lang.org/favicon.ico", - html_root_url = "https://doc.rust-lang.org/nightly/", +#![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(intra_doc_link_resolution_failure)] -#![deny(missing_debug_implementations)] +#![deny(rust_2018_idioms)] +#![allow(explicit_outlives_requirements)] + +#![warn(deprecated_in_future)] +#![warn(intra_doc_link_resolution_failure)] +#![warn(missing_debug_implementations)] -#![cfg_attr(not(test), feature(fn_traits))] #![cfg_attr(not(test), feature(generator_trait))] #![cfg_attr(test, feature(test))] @@ -84,6 +85,7 @@ #![feature(dropck_eyepatch)] #![feature(exact_size_is_empty)] #![feature(fmt_internals)] +#![feature(fn_traits)] #![feature(fundamental)] #![feature(futures_api)] #![feature(lang_items)] @@ -97,8 +99,8 @@ #![feature(rustc_attrs)] #![feature(receiver_trait)] #![feature(specialization)] -#![feature(split_ascii_whitespace)] #![feature(staged_api)] +#![feature(std_internals)] #![feature(str_internals)] #![feature(trusted_len)] #![feature(try_reserve)] @@ -110,8 +112,9 @@ #![feature(rustc_const_unstable)] #![feature(const_vec_new)] #![feature(slice_partition_dedup)] -#![feature(maybe_uninit)] +#![feature(maybe_uninit, maybe_uninit_slice, maybe_uninit_array)] #![feature(alloc_layout_extra)] +#![feature(try_trait)] // Allow testing this library @@ -120,8 +123,6 @@ extern crate std; #[cfg(test)] extern crate test; -#[cfg(test)] -extern crate rand; // Module with internal macros used by other modules (needs to be included before other modules). #[macro_use] @@ -131,10 +132,6 @@ mod macros; pub mod alloc; -#[unstable(feature = "futures_api", - reason = "futures in libcore are unstable", - issue = "50547")] -pub mod task; // Primitive types using the heaps above // Need to conditionally define the mod from `boxed.rs` to avoid @@ -163,5 +160,5 @@ pub mod vec; #[cfg(not(test))] mod std { - pub use core::ops; // RangeFull + pub use core::ops; // RangeFull } diff --git a/src/liballoc/macros.rs b/src/liballoc/macros.rs index db91b07fa71b4..eb3410078513d 100644 --- a/src/liballoc/macros.rs +++ b/src/liballoc/macros.rs @@ -34,7 +34,8 @@ #[cfg(not(test))] #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] -#[allow_internal_unstable] +#[cfg_attr(not(stage0), allow_internal_unstable(box_syntax))] +#[cfg_attr(stage0, allow_internal_unstable)] macro_rules! vec { ($elem:expr; $n:expr) => ( $crate::vec::from_elem($elem, $n) @@ -62,18 +63,18 @@ macro_rules! vec { /// Creates a `String` using interpolation of runtime expressions. /// -/// The first argument `format!` receives is a format string. This must be a string -/// literal. The power of the formatting string is in the `{}`s contained. +/// The first argument `format!` receives is a format string. This must be a string +/// literal. The power of the formatting string is in the `{}`s contained. /// /// Additional parameters passed to `format!` replace the `{}`s within the /// formatting string in the order given unless named or positional parameters -/// are used, see [`std::fmt`][fmt] for more information. +/// are used; see [`std::fmt`][fmt] for more information. /// /// A common use for `format!` is concatenation and interpolation of strings. /// The same convention is used with [`print!`] and [`write!`] macros, /// depending on the intended destination of the string. /// -/// To convert a single value to a string, use the [`to_string`] method. This +/// To convert a single value to a string, use the [`to_string`] method. This /// will use the [`Display`] formatting trait. /// /// [fmt]: ../std/fmt/index.html diff --git a/src/liballoc/prelude.rs b/src/liballoc/prelude.rs index 7cd22095de417..6767cf89f73ba 100644 --- a/src/liballoc/prelude.rs +++ b/src/liballoc/prelude.rs @@ -12,8 +12,8 @@ #![unstable(feature = "alloc", issue = "27783")] -#[unstable(feature = "alloc", issue = "27783")] pub use borrow::ToOwned; -#[unstable(feature = "alloc", issue = "27783")] pub use boxed::Box; -#[unstable(feature = "alloc", issue = "27783")] pub use slice::SliceConcatExt; -#[unstable(feature = "alloc", issue = "27783")] pub use string::{String, ToString}; -#[unstable(feature = "alloc", issue = "27783")] pub use vec::Vec; +#[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/raw_vec.rs b/src/liballoc/raw_vec.rs index 5e4aac9ce7871..fe28fe5095cce 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -7,10 +7,9 @@ use core::ops::Drop; use core::ptr::{self, NonNull, Unique}; use core::slice; -use alloc::{Alloc, Layout, Global, handle_alloc_error}; -use collections::CollectionAllocErr; -use collections::CollectionAllocErr::*; -use boxed::Box; +use crate::alloc::{Alloc, Layout, Global, handle_alloc_error}; +use crate::collections::CollectionAllocErr::{self, *}; +use crate::boxed::Box; /// A low-level utility for more ergonomically allocating, reallocating, and deallocating /// a buffer of memory on the heap without having to worry about all the corner cases @@ -336,7 +335,7 @@ impl RawVec { /// enough to want to do that it's easiest to just have a dedicated method. Slightly /// more efficient logic can be provided for this than the general case. /// - /// Returns true if the reallocation attempt has succeeded, or false otherwise. + /// Returns `true` if the reallocation attempt has succeeded. /// /// # Panics /// @@ -505,7 +504,7 @@ impl RawVec { /// the requested space. This is not really unsafe, but the unsafe /// code *you* write that relies on the behavior of this function may break. /// - /// Returns true if the reallocation attempt has succeeded, or false otherwise. + /// Returns `true` if the reallocation attempt has succeeded. /// /// # Panics /// @@ -621,14 +620,14 @@ enum Fallibility { Infallible, } -use self::Fallibility::*; +use Fallibility::*; enum ReserveStrategy { Exact, Amortized, } -use self::ReserveStrategy::*; +use ReserveStrategy::*; impl RawVec { fn reserve_internal( @@ -639,7 +638,7 @@ impl RawVec { strategy: ReserveStrategy, ) -> Result<(), CollectionAllocErr> { unsafe { - use alloc::AllocErr; + use crate::alloc::AllocErr; // NOTE: we don't early branch on ZSTs here because we want this // to actually catch "asking for more than usize::MAX" in that case. @@ -733,7 +732,7 @@ unsafe impl<#[may_dangle] T, A: Alloc> Drop for RawVec { #[inline] fn alloc_guard(alloc_size: usize) -> Result<(), CollectionAllocErr> { - if mem::size_of::() < 8 && alloc_size > ::core::isize::MAX as usize { + if mem::size_of::() < 8 && alloc_size > core::isize::MAX as usize { Err(CapacityOverflow) } else { Ok(()) @@ -753,7 +752,7 @@ mod tests { #[test] fn allocator_param() { - use alloc::AllocErr; + use crate::alloc::AllocErr; // Writing a test of integration between third-party // allocators and RawVec is a little tricky because the RawVec diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index d3a55c59ff69c..12f75d84211e6 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -1,5 +1,3 @@ -#![allow(deprecated)] - //! Single-threaded reference-counting pointers. 'Rc' stands for 'Reference //! Counted'. //! @@ -229,7 +227,7 @@ #![stable(feature = "rust1", since = "1.0.0")] #[cfg(not(test))] -use boxed::Box; +use crate::boxed::Box; #[cfg(test)] use std::boxed::Box; @@ -240,19 +238,18 @@ use core::cmp::Ordering; use core::fmt; use core::hash::{Hash, Hasher}; use core::intrinsics::abort; -use core::marker; -use core::marker::{Unpin, Unsize, PhantomData}; +use core::marker::{self, Unpin, Unsize, PhantomData}; use core::mem::{self, align_of_val, forget, size_of_val}; -use core::ops::{Deref, Receiver}; -use core::ops::{CoerceUnsized, DispatchFromDyn}; +use core::ops::{Deref, Receiver, CoerceUnsized, DispatchFromDyn}; use core::pin::Pin; use core::ptr::{self, NonNull}; +use core::slice::from_raw_parts_mut; use core::convert::From; use core::usize; -use alloc::{Global, Alloc, Layout, box_free, handle_alloc_error}; -use string::String; -use vec::Vec; +use crate::alloc::{Global, Alloc, Layout, box_free, handle_alloc_error}; +use crate::string::String; +use crate::vec::Vec; struct RcBox { strong: Cell, @@ -435,6 +432,27 @@ impl Rc { } } + /// Consumes the `Rc`, returning the wrapped pointer as `NonNull`. + /// + /// # Examples + /// + /// ``` + /// #![feature(rc_into_raw_non_null)] + /// + /// use std::rc::Rc; + /// + /// let x = Rc::new(10); + /// let ptr = Rc::into_raw_non_null(x); + /// let deref = unsafe { *ptr.as_ref() }; + /// assert_eq!(deref, 10); + /// ``` + #[unstable(feature = "rc_into_raw_non_null", issue = "47336")] + #[inline] + pub fn into_raw_non_null(this: Self) -> NonNull { + // safe because Rc guarantees its pointer is non-null + unsafe { NonNull::new_unchecked(Rc::into_raw(this) as *mut _) } + } + /// Creates a new [`Weak`][weak] pointer to this value. /// /// [weak]: struct.Weak.html @@ -494,7 +512,7 @@ impl Rc { this.strong() } - /// Returns true if there are no other `Rc` or [`Weak`][weak] pointers to + /// Returns `true` if there are no other `Rc` or [`Weak`][weak] pointers to /// this inner value. /// /// [weak]: struct.Weak.html @@ -543,7 +561,7 @@ impl Rc { #[inline] #[stable(feature = "ptr_eq", since = "1.17.0")] - /// Returns true if the two `Rc`s point to the same value (not + /// Returns `true` if the two `Rc`s point to the same value (not /// just values that compare as equal). /// /// # Examples @@ -747,8 +765,6 @@ impl RcFromSlice for Rc<[T]> { impl Drop for Guard { fn drop(&mut self) { - use core::slice::from_raw_parts_mut; - unsafe { let slice = from_raw_parts_mut(self.elems, self.n_elems); ptr::drop_in_place(slice); @@ -1102,21 +1118,21 @@ impl Hash for Rc { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for Rc { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(&**self, f) } } #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for Rc { - 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 = "rust1", since = "1.0.0")] impl fmt::Pointer for Rc { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Pointer::fmt(&(&**self as *const T), f) } } @@ -1286,8 +1302,40 @@ impl Weak { } } - /// Return `None` when the pointer is dangling and there is no allocated `RcBox`, - /// i.e., this `Weak` was created by `Weak::new` + /// Gets the number of strong (`Rc`) pointers pointing to this value. + /// + /// If `self` was created using [`Weak::new`], this will return 0. + /// + /// [`Weak::new`]: #method.new + #[unstable(feature = "weak_counts", issue = "57977")] + pub fn strong_count(&self) -> usize { + if let Some(inner) = self.inner() { + inner.strong() + } else { + 0 + } + } + + /// Gets the number of `Weak` pointers pointing to this value. + /// + /// If `self` was created using [`Weak::new`], this will return `None`. If + /// not, the returned value is at least 1, since `self` still points to the + /// value. + /// + /// [`Weak::new`]: #method.new + #[unstable(feature = "weak_counts", issue = "57977")] + pub fn weak_count(&self) -> Option { + self.inner().map(|inner| { + if inner.strong() > 0 { + inner.weak() - 1 // subtract the implicit weak ptr + } else { + inner.weak() + } + }) + } + + /// Returns `None` when the pointer is dangling and there is no allocated `RcBox` + /// (i.e., when this `Weak` was created by `Weak::new`). #[inline] fn inner(&self) -> Option<&RcBox> { if is_dangling(self.ptr) { @@ -1297,7 +1345,7 @@ impl Weak { } } - /// Returns true if the two `Weak`s point to the same value (not just values + /// Returns `true` if the two `Weak`s point to the same value (not just values /// that compare as equal). /// /// # Notes @@ -1408,7 +1456,7 @@ impl Clone for Weak { #[stable(feature = "rc_weak", since = "1.4.0")] impl fmt::Debug for Weak { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "(Weak)") } } @@ -1513,8 +1561,7 @@ mod tests { use super::{Rc, Weak}; use std::boxed::Box; use std::cell::RefCell; - use std::option::Option; - use std::option::Option::{None, Some}; + use std::option::Option::{self, None, Some}; use std::result::Result::{Err, Ok}; use std::mem::drop; use std::clone::Clone; @@ -1624,6 +1671,33 @@ mod tests { drop(c); } + #[test] + fn weak_counts() { + assert_eq!(Weak::weak_count(&Weak::::new()), None); + assert_eq!(Weak::strong_count(&Weak::::new()), 0); + + let a = Rc::new(0); + let w = Rc::downgrade(&a); + assert_eq!(Weak::strong_count(&w), 1); + assert_eq!(Weak::weak_count(&w), Some(1)); + let w2 = w.clone(); + assert_eq!(Weak::strong_count(&w), 1); + assert_eq!(Weak::weak_count(&w), Some(2)); + assert_eq!(Weak::strong_count(&w2), 1); + assert_eq!(Weak::weak_count(&w2), Some(2)); + drop(w); + assert_eq!(Weak::strong_count(&w2), 1); + assert_eq!(Weak::weak_count(&w2), Some(1)); + let a2 = a.clone(); + assert_eq!(Weak::strong_count(&w2), 2); + assert_eq!(Weak::weak_count(&w2), Some(1)); + drop(a2); + drop(a); + assert_eq!(Weak::strong_count(&w2), 0); + assert_eq!(Weak::weak_count(&w2), Some(1)); + drop(w2); + } + #[test] fn try_unwrap() { let x = Rc::new(3); diff --git a/src/liballoc/slice.rs b/src/liballoc/slice.rs index db19f778617f4..f4b2d463778a9 100644 --- a/src/liballoc/slice.rs +++ b/src/liballoc/slice.rs @@ -87,15 +87,15 @@ // It's cleaner to just turn off the unused_imports warning than to fix them. #![cfg_attr(test, allow(unused_imports, dead_code))] +use core::borrow::{Borrow, BorrowMut}; use core::cmp::Ordering::{self, Less}; -use core::mem::size_of; -use core::mem; +use core::mem::{self, size_of}; use core::ptr; use core::{u8, u16, u32}; -use borrow::{Borrow, BorrowMut, ToOwned}; -use boxed::Box; -use vec::Vec; +use crate::borrow::ToOwned; +use crate::boxed::Box; +use crate::vec::Vec; #[stable(feature = "rust1", since = "1.0.0")] pub use core::slice::{Chunks, Windows}; @@ -125,24 +125,24 @@ 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 #[cfg(test)] -pub use self::hack::into_vec; +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 #[cfg(test)] -pub use self::hack::to_vec; +pub use hack::to_vec; // HACK(japaric): With cfg(test) `impl [T]` is not available, these three // functions are actually methods that are in `impl [T]` but not in // `core::slice::SliceExt` - we need to supply these functions for the // `test_permutations` test mod hack { - use boxed::Box; use core::mem; + use crate::boxed::Box; + use crate::vec::Vec; #[cfg(test)] - use string::ToString; - use vec::Vec; + use crate::string::ToString; pub fn into_vec(mut b: Box<[T]>) -> Vec { unsafe { @@ -205,10 +205,10 @@ impl [T] { /// /// The comparator function must define a total ordering for the elements in the slice. If /// the ordering is not total, the order of the elements is unspecified. An order is a - /// total order if it is (for all a, b and c): + /// total order if it is (for all `a`, `b` and `c`): /// - /// * total and antisymmetric: exactly one of a < b, a == b or a > b is true; and - /// * transitive, a < b and b < c implies a < c. The same must hold for both == and >. + /// * total and antisymmetric: exactly one of `a < b`, `a == b` or `a > b` is true, and + /// * transitive, `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`. /// /// For example, while [`f64`] doesn't implement [`Ord`] because `NaN != NaN`, we can use /// `partial_cmp` as our sort function when we know the slice doesn't contain a `NaN`. @@ -257,6 +257,10 @@ impl [T] { /// This sort is stable (i.e., does not reorder equal elements) and `O(m n log(m n))` /// worst-case, where the key function is `O(m)`. /// + /// For expensive key functions (e.g. functions that are not simple property accesses or + /// basic operations), [`sort_by_cached_key`](#method.sort_by_cached_key) is likely to be + /// significantly faster, as it does not recompute element keys. + /// /// When applicable, unstable sorting is preferred because it is generally faster than stable /// sorting and it doesn't allocate auxiliary memory. /// See [`sort_unstable_by_key`](#method.sort_unstable_by_key). @@ -312,7 +316,6 @@ impl [T] { /// # Examples /// /// ``` - /// #![feature(slice_sort_by_cached_key)] /// let mut v = [-5i32, 4, 32, -3, 2]; /// /// v.sort_by_cached_key(|k| k.to_string()); @@ -320,7 +323,7 @@ impl [T] { /// ``` /// /// [pdqsort]: https://github.com/orlp/pdqsort - #[unstable(feature = "slice_sort_by_cached_key", issue = "34447")] + #[stable(feature = "slice_sort_by_cached_key", since = "1.34.0")] #[inline] pub fn sort_by_cached_key(&mut self, f: F) where F: FnMut(&T) -> K, K: Ord diff --git a/src/liballoc/str.rs b/src/liballoc/str.rs index 60d9f1626138e..a36804bddff32 100644 --- a/src/liballoc/str.rs +++ b/src/liballoc/str.rs @@ -28,20 +28,18 @@ // It's cleaner to just turn off the unused_imports warning than to fix them. #![allow(unused_imports)] -use core::fmt; -use core::str as core_str; -use core::str::pattern::Pattern; -use core::str::pattern::{Searcher, ReverseSearcher, DoubleEndedSearcher}; +use core::borrow::Borrow; +use core::str::pattern::{Pattern, Searcher, ReverseSearcher, DoubleEndedSearcher}; use core::mem; use core::ptr; use core::iter::FusedIterator; use core::unicode::conversions; -use borrow::{Borrow, ToOwned}; -use boxed::Box; -use slice::{SliceConcatExt, SliceIndex}; -use string::String; -use vec::Vec; +use crate::borrow::ToOwned; +use crate::boxed::Box; +use crate::slice::{SliceConcatExt, SliceIndex}; +use crate::string::String; +use crate::vec::Vec; #[stable(feature = "rust1", since = "1.0.0")] pub use core::str::{FromStr, Utf8Error}; @@ -68,7 +66,7 @@ pub use core::str::SplitWhitespace; pub use core::str::pattern; #[stable(feature = "encode_utf16", since = "1.8.0")] pub use core::str::EncodeUtf16; -#[unstable(feature = "split_ascii_whitespace", issue = "48656")] +#[stable(feature = "split_ascii_whitespace", since = "1.34.0")] pub use core::str::SplitAsciiWhitespace; #[unstable(feature = "slice_concat_ext", @@ -443,45 +441,6 @@ impl str { return s; } - /// Escapes each char in `s` with [`char::escape_debug`]. - /// - /// Note: only extended grapheme codepoints that begin the string will be - /// escaped. - /// - /// [`char::escape_debug`]: primitive.char.html#method.escape_debug - #[unstable(feature = "str_escape", - reason = "return type may change to be an iterator", - issue = "27791")] - pub fn escape_debug(&self) -> String { - let mut string = String::with_capacity(self.len()); - let mut chars = self.chars(); - if let Some(first) = chars.next() { - string.extend(first.escape_debug_ext(true)) - } - string.extend(chars.flat_map(|c| c.escape_debug_ext(false))); - string - } - - /// Escapes each char in `s` with [`char::escape_default`]. - /// - /// [`char::escape_default`]: primitive.char.html#method.escape_default - #[unstable(feature = "str_escape", - reason = "return type may change to be an iterator", - issue = "27791")] - pub fn escape_default(&self) -> String { - self.chars().flat_map(|c| c.escape_default()).collect() - } - - /// Escapes each char in `s` with [`char::escape_unicode`]. - /// - /// [`char::escape_unicode`]: primitive.char.html#method.escape_unicode - #[unstable(feature = "str_escape", - reason = "return type may change to be an iterator", - issue = "27791")] - pub fn escape_unicode(&self) -> String { - self.chars().flat_map(|c| c.escape_unicode()).collect() - } - /// Converts a [`Box`] into a [`String`] without copying or allocating. /// /// [`String`]: string/struct.String.html @@ -612,3 +571,4 @@ 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 fa15e9ad9018e..84c35c6f1bd2b 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -50,17 +50,16 @@ use core::char::{decode_utf16, REPLACEMENT_CHARACTER}; use core::fmt; use core::hash; use core::iter::{FromIterator, FusedIterator}; -use core::ops::Bound::{Excluded, Included, Unbounded}; use core::ops::{self, Add, AddAssign, Index, IndexMut, RangeBounds}; +use core::ops::Bound::{Excluded, Included, Unbounded}; use core::ptr; -use core::str::pattern::Pattern; -use core::str::lossy; +use core::str::{pattern::Pattern, lossy}; -use collections::CollectionAllocErr; -use borrow::{Cow, ToOwned}; -use boxed::Box; -use str::{self, from_boxed_utf8_unchecked, FromStr, Utf8Error, Chars}; -use vec::Vec; +use crate::borrow::{Cow, ToOwned}; +use crate::collections::CollectionAllocErr; +use crate::boxed::Box; +use crate::str::{self, from_boxed_utf8_unchecked, FromStr, Utf8Error, Chars}; +use crate::vec::Vec; /// A UTF-8 encoded, growable string. /// @@ -964,7 +963,7 @@ impl String { /// Does nothing if the capacity is already sufficient. /// /// Note that the allocator may give the collection more space than it - /// requests. Therefore capacity can not be relied upon to be precisely + /// requests. Therefore, capacity can not be relied upon to be precisely /// minimal. Prefer `reserve` if future insertions are expected. /// /// # Errors @@ -1378,9 +1377,7 @@ impl String { self.vec.len() } - /// Returns `true` if this `String` has a length of zero. - /// - /// Returns `false` otherwise. + /// Returns `true` if this `String` has a length of zero, and `false` otherwise. /// /// # Examples /// @@ -1485,7 +1482,7 @@ impl String { /// assert_eq!(s, ""); /// ``` #[stable(feature = "drain", since = "1.6.0")] - pub fn drain(&mut self, range: R) -> Drain + pub fn drain(&mut self, range: R) -> Drain<'_> where R: RangeBounds { // Memory safety @@ -1669,14 +1666,14 @@ impl FromUtf8Error { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for FromUtf8Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(&self.error, f) } } #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for FromUtf16Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt("invalid utf-16: lone surrogate found", f) } } @@ -1867,7 +1864,7 @@ impl Default for String { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for String { #[inline] - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(&**self, f) } } @@ -1875,7 +1872,7 @@ impl fmt::Display for String { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for String { #[inline] - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&**self, f) } } @@ -1926,7 +1923,7 @@ impl hash::Hash for String { /// let c = a.to_string() + b; /// ``` #[stable(feature = "rust1", since = "1.0.0")] -impl<'a> Add<&'a str> for String { +impl Add<&str> for String { type Output = String; #[inline] @@ -1940,7 +1937,7 @@ impl<'a> Add<&'a str> for String { /// /// This has the same behavior as the [`push_str`][String::push_str] method. #[stable(feature = "stringaddassign", since = "1.12.0")] -impl<'a> AddAssign<&'a str> for String { +impl AddAssign<&str> for String { #[inline] fn add_assign(&mut self, other: &str) { self.push_str(other); @@ -2097,14 +2094,14 @@ impl Clone for ParseError { #[stable(feature = "str_parse_error", since = "1.5.0")] impl fmt::Debug for ParseError { - fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result { match *self {} } } #[stable(feature = "str_parse_error2", since = "1.8.0")] impl fmt::Display for ParseError { - fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result { match *self {} } } @@ -2156,7 +2153,7 @@ pub trait ToString { impl ToString for T { #[inline] default fn to_string(&self) -> String { - use core::fmt::Write; + use fmt::Write; let mut buf = String::new(); buf.write_fmt(format_args!("{}", self)) .expect("a Display implementation returned an error unexpectedly"); @@ -2174,7 +2171,7 @@ impl ToString for str { } #[stable(feature = "cow_str_to_string_specialization", since = "1.17.0")] -impl<'a> ToString for Cow<'a, str> { +impl ToString for Cow<'_, str> { #[inline] fn to_string(&self) -> String { self[..].to_owned() @@ -2364,19 +2361,19 @@ pub struct Drain<'a> { } #[stable(feature = "collection_debug", since = "1.17.0")] -impl<'a> fmt::Debug for Drain<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +impl fmt::Debug for Drain<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.pad("Drain { .. }") } } #[stable(feature = "drain", since = "1.6.0")] -unsafe impl<'a> Sync for Drain<'a> {} +unsafe impl Sync for Drain<'_> {} #[stable(feature = "drain", since = "1.6.0")] -unsafe impl<'a> Send for Drain<'a> {} +unsafe impl Send for Drain<'_> {} #[stable(feature = "drain", since = "1.6.0")] -impl<'a> Drop for Drain<'a> { +impl Drop for Drain<'_> { fn drop(&mut self) { unsafe { // Use Vec::drain. "Reaffirm" the bounds checks to avoid @@ -2390,7 +2387,7 @@ impl<'a> Drop for Drain<'a> { } #[stable(feature = "drain", since = "1.6.0")] -impl<'a> Iterator for Drain<'a> { +impl Iterator for Drain<'_> { type Item = char; #[inline] @@ -2404,7 +2401,7 @@ impl<'a> Iterator for Drain<'a> { } #[stable(feature = "drain", since = "1.6.0")] -impl<'a> DoubleEndedIterator for Drain<'a> { +impl DoubleEndedIterator for Drain<'_> { #[inline] fn next_back(&mut self) -> Option { self.iter.next_back() @@ -2412,4 +2409,4 @@ impl<'a> DoubleEndedIterator for Drain<'a> { } #[stable(feature = "fused", since = "1.26.0")] -impl<'a> FusedIterator for Drain<'a> {} +impl FusedIterator for Drain<'_> {} diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs index 390a079165054..b7d7995b540ba 100644 --- a/src/liballoc/sync.rs +++ b/src/liballoc/sync.rs @@ -11,23 +11,23 @@ use core::sync::atomic; use core::sync::atomic::Ordering::{Acquire, Relaxed, Release, SeqCst}; use core::borrow; use core::fmt; -use core::cmp::Ordering; +use core::cmp::{self, Ordering}; use core::intrinsics::abort; use core::mem::{self, align_of_val, size_of_val}; -use core::ops::{Deref, Receiver}; -use core::ops::{CoerceUnsized, DispatchFromDyn}; +use core::ops::{Deref, Receiver, CoerceUnsized, DispatchFromDyn}; use core::pin::Pin; use core::ptr::{self, NonNull}; use core::marker::{Unpin, Unsize, PhantomData}; use core::hash::{Hash, Hasher}; use core::{isize, usize}; use core::convert::From; +use core::slice::from_raw_parts_mut; -use alloc::{Global, Alloc, Layout, box_free, handle_alloc_error}; -use boxed::Box; -use rc::is_dangling; -use string::String; -use vec::Vec; +use crate::alloc::{Global, Alloc, Layout, box_free, handle_alloc_error}; +use crate::boxed::Box; +use crate::rc::is_dangling; +use crate::string::String; +use crate::vec::Vec; /// A soft limit on the amount of references that may be made to an `Arc`. /// @@ -251,7 +251,7 @@ impl, U: ?Sized> DispatchFromDyn> for Weak {} #[stable(feature = "arc_weak", since = "1.4.0")] impl fmt::Debug for Weak { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "(Weak)") } } @@ -413,6 +413,27 @@ impl Arc { } } + /// Consumes the `Arc`, returning the wrapped pointer as `NonNull`. + /// + /// # Examples + /// + /// ``` + /// #![feature(rc_into_raw_non_null)] + /// + /// use std::sync::Arc; + /// + /// let x = Arc::new(10); + /// let ptr = Arc::into_raw_non_null(x); + /// let deref = unsafe { *ptr.as_ref() }; + /// assert_eq!(deref, 10); + /// ``` + #[unstable(feature = "rc_into_raw_non_null", issue = "47336")] + #[inline] + pub fn into_raw_non_null(this: Self) -> NonNull { + // safe because Arc guarantees its pointer is non-null + unsafe { NonNull::new_unchecked(Arc::into_raw(this) as *mut _) } + } + /// Creates a new [`Weak`][weak] pointer to this value. /// /// [weak]: struct.Weak.html @@ -539,7 +560,7 @@ impl Arc { #[inline] #[stable(feature = "ptr_eq", since = "1.17.0")] - /// Returns true if the two `Arc`s point to the same value (not + /// Returns `true` if the two `Arc`s point to the same value (not /// just values that compare as equal). /// /// # Examples @@ -651,8 +672,6 @@ impl ArcFromSlice for Arc<[T]> { impl Drop for Guard { fn drop(&mut self) { - use core::slice::from_raw_parts_mut; - unsafe { let slice = from_raw_parts_mut(self.elems, self.n_elems); ptr::drop_in_place(slice); @@ -1117,8 +1136,63 @@ impl Weak { } } - /// Return `None` when the pointer is dangling and there is no allocated `ArcInner`, - /// i.e., this `Weak` was created by `Weak::new` + /// Gets the number of strong (`Arc`) pointers pointing to this value. + /// + /// If `self` was created using [`Weak::new`], this will return 0. + /// + /// [`Weak::new`]: #method.new + #[unstable(feature = "weak_counts", issue = "57977")] + pub fn strong_count(&self) -> usize { + if let Some(inner) = self.inner() { + inner.strong.load(SeqCst) + } else { + 0 + } + } + + /// Gets an approximation of the number of `Weak` pointers pointing to this + /// value. + /// + /// If `self` was created using [`Weak::new`], this will return 0. If not, + /// the returned value is at least 1, since `self` still points to the + /// value. + /// + /// # Accuracy + /// + /// Due to implementation details, the returned value can be off by 1 in + /// either direction when other threads are manipulating any `Arc`s or + /// `Weak`s pointing to the same value. + /// + /// [`Weak::new`]: #method.new + #[unstable(feature = "weak_counts", issue = "57977")] + pub fn weak_count(&self) -> Option { + // Due to the implicit weak pointer added when any strong pointers are + // around, we cannot implement `weak_count` correctly since it + // necessarily requires accessing the strong count and weak count in an + // unsynchronized fashion. So this version is a bit racy. + self.inner().map(|inner| { + let strong = inner.strong.load(SeqCst); + let weak = inner.weak.load(SeqCst); + if strong == 0 { + // If the last `Arc` has *just* been dropped, it might not yet + // have removed the implicit weak count, so the value we get + // here might be 1 too high. + weak + } else { + // As long as there's still at least 1 `Arc` around, subtract + // the implicit weak pointer. + // Note that the last `Arc` might get dropped between the 2 + // loads we do above, removing the implicit weak pointer. This + // means that the value might be 1 too low here. In order to not + // return 0 here (which would happen if we're the only weak + // pointer), we guard against that specifically. + cmp::max(1, weak - 1) + } + }) + } + + /// Returns `None` when the pointer is dangling and there is no allocated `ArcInner`, + /// (i.e., when this `Weak` was created by `Weak::new`). #[inline] fn inner(&self) -> Option<&ArcInner> { if is_dangling(self.ptr) { @@ -1128,7 +1202,7 @@ impl Weak { } } - /// Returns true if the two `Weak`s point to the same value (not just values + /// Returns `true` if the two `Weak`s point to the same value (not just values /// that compare as equal). /// /// # Notes @@ -1474,21 +1548,21 @@ impl Eq for Arc {} #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for Arc { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(&**self, f) } } #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for Arc { - 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 = "rust1", since = "1.0.0")] impl fmt::Pointer for Arc { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Pointer::fmt(&(&**self as *const T), f) } } @@ -1525,7 +1599,7 @@ impl From for Arc { } #[stable(feature = "shared_from_slice", since = "1.21.0")] -impl<'a, T: Clone> From<&'a [T]> for Arc<[T]> { +impl From<&[T]> for Arc<[T]> { #[inline] fn from(v: &[T]) -> Arc<[T]> { >::from_slice(v) @@ -1533,7 +1607,7 @@ impl<'a, T: Clone> From<&'a [T]> for Arc<[T]> { } #[stable(feature = "shared_from_slice", since = "1.21.0")] -impl<'a> From<&'a str> for Arc { +impl From<&str> for Arc { #[inline] fn from(v: &str) -> Arc { let arc = Arc::<[u8]>::from(v.as_bytes()); @@ -1579,16 +1653,14 @@ mod tests { use std::sync::mpsc::channel; use std::mem::drop; use std::ops::Drop; - use std::option::Option; - use std::option::Option::{None, Some}; - use std::sync::atomic; - use std::sync::atomic::Ordering::{Acquire, SeqCst}; + use std::option::Option::{self, None, Some}; + use std::sync::atomic::{self, Ordering::{Acquire, SeqCst}}; use std::thread; use std::sync::Mutex; use std::convert::From; use super::{Arc, Weak}; - use vec::Vec; + use crate::vec::Vec; struct Canary(*mut atomic::AtomicUsize); @@ -1636,6 +1708,33 @@ mod tests { assert!(Arc::get_mut(&mut x).is_none()); } + #[test] + fn weak_counts() { + assert_eq!(Weak::weak_count(&Weak::::new()), None); + assert_eq!(Weak::strong_count(&Weak::::new()), 0); + + let a = Arc::new(0); + let w = Arc::downgrade(&a); + assert_eq!(Weak::strong_count(&w), 1); + assert_eq!(Weak::weak_count(&w), Some(1)); + let w2 = w.clone(); + assert_eq!(Weak::strong_count(&w), 1); + assert_eq!(Weak::weak_count(&w), Some(2)); + assert_eq!(Weak::strong_count(&w2), 1); + assert_eq!(Weak::weak_count(&w2), Some(2)); + drop(w); + assert_eq!(Weak::strong_count(&w2), 1); + assert_eq!(Weak::weak_count(&w2), Some(1)); + let a2 = a.clone(); + assert_eq!(Weak::strong_count(&w2), 2); + assert_eq!(Weak::weak_count(&w2), Some(1)); + drop(a2); + drop(a); + assert_eq!(Weak::strong_count(&w2), 0); + assert_eq!(Weak::weak_count(&w2), Some(1)); + drop(w2); + } + #[test] fn try_unwrap() { let x = Arc::new(3); diff --git a/src/liballoc/task.rs b/src/liballoc/task.rs deleted file mode 100644 index 604c56dd01762..0000000000000 --- a/src/liballoc/task.rs +++ /dev/null @@ -1,130 +0,0 @@ -//! Types and Traits for working with asynchronous tasks. - -pub use core::task::*; - -#[cfg(all(target_has_atomic = "ptr", target_has_atomic = "cas"))] -pub use self::if_arc::*; - -#[cfg(all(target_has_atomic = "ptr", target_has_atomic = "cas"))] -mod if_arc { - use super::*; - use core::marker::PhantomData; - use core::mem; - use core::ptr::{self, NonNull}; - use sync::Arc; - - /// A way of waking up a specific task. - /// - /// Any task executor must provide a way of signaling that a task it owns - /// is ready to be `poll`ed again. Executors do so by implementing this trait. - pub trait Wake: Send + Sync { - /// Indicates that the associated task is ready to make progress and should - /// be `poll`ed. - /// - /// Executors generally maintain a queue of "ready" tasks; `wake` should place - /// the associated task onto this queue. - fn wake(arc_self: &Arc); - - /// Indicates that the associated task is ready to make progress and should - /// be `poll`ed. This function is like `wake`, but can only be called from the - /// thread on which this `Wake` was created. - /// - /// Executors generally maintain a queue of "ready" tasks; `wake_local` should place - /// the associated task onto this queue. - #[inline] - unsafe fn wake_local(arc_self: &Arc) { - Self::wake(arc_self); - } - } - - #[cfg(all(target_has_atomic = "ptr", target_has_atomic = "cas"))] - struct ArcWrapped(PhantomData); - - unsafe impl UnsafeWake for ArcWrapped { - #[inline] - unsafe fn clone_raw(&self) -> Waker { - let me: *const ArcWrapped = self; - let arc = (*(&me as *const *const ArcWrapped as *const Arc)).clone(); - Waker::from(arc) - } - - #[inline] - unsafe fn drop_raw(&self) { - let mut me: *const ArcWrapped = self; - let me = &mut me as *mut *const ArcWrapped as *mut Arc; - ptr::drop_in_place(me); - } - - #[inline] - unsafe fn wake(&self) { - let me: *const ArcWrapped = self; - T::wake(&*(&me as *const *const ArcWrapped as *const Arc)) - } - - #[inline] - unsafe fn wake_local(&self) { - let me: *const ArcWrapped = self; - T::wake_local(&*(&me as *const *const ArcWrapped as *const Arc)) - } - } - - impl From> for Waker - where T: Wake + 'static, - { - fn from(rc: Arc) -> Self { - unsafe { - let ptr = mem::transmute::, NonNull>>(rc); - Waker::new(ptr) - } - } - } - - /// Creates a `LocalWaker` from a local `wake`. - /// - /// This function requires that `wake` is "local" (created on the current thread). - /// The resulting `LocalWaker` will call `wake.wake_local()` when awoken, and - /// will call `wake.wake()` if awoken after being converted to a `Waker`. - #[inline] - pub unsafe fn local_waker(wake: Arc) -> LocalWaker { - let ptr = mem::transmute::, NonNull>>(wake); - LocalWaker::new(ptr) - } - - struct NonLocalAsLocal(ArcWrapped); - - unsafe impl UnsafeWake for NonLocalAsLocal { - #[inline] - unsafe fn clone_raw(&self) -> Waker { - self.0.clone_raw() - } - - #[inline] - unsafe fn drop_raw(&self) { - self.0.drop_raw() - } - - #[inline] - unsafe fn wake(&self) { - self.0.wake() - } - - #[inline] - unsafe fn wake_local(&self) { - // Since we're nonlocal, we can't call wake_local - self.0.wake() - } - } - - /// Creates a `LocalWaker` from a non-local `wake`. - /// - /// This function is similar to `local_waker`, but does not require that `wake` - /// is local to the current thread. The resulting `LocalWaker` will call - /// `wake.wake()` when awoken. - #[inline] - pub fn local_waker_from_nonlocal(wake: Arc) -> LocalWaker { - unsafe { - let ptr = mem::transmute::, NonNull>>(wake); - LocalWaker::new(ptr) - } - } -} diff --git a/src/liballoc/tests/binary_heap.rs b/src/liballoc/tests/binary_heap.rs index 6af1cf4080947..1d4a3edc1ac42 100644 --- a/src/liballoc/tests/binary_heap.rs +++ b/src/liballoc/tests/binary_heap.rs @@ -2,7 +2,7 @@ use std::cmp; use std::collections::BinaryHeap; use std::collections::binary_heap::{Drain, PeekMut}; use std::panic::{self, AssertUnwindSafe}; -use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; +use std::sync::atomic::{AtomicUsize, Ordering}; use rand::{thread_rng, seq::SliceRandom}; @@ -282,8 +282,9 @@ fn assert_covariance() { // // Destructors must be called exactly once per element. #[test] +#[cfg(not(miri))] // Miri does not support panics fn panic_safe() { - static DROP_COUNTER: AtomicUsize = ATOMIC_USIZE_INIT; + static DROP_COUNTER: AtomicUsize = AtomicUsize::new(0); #[derive(Eq, PartialEq, Ord, Clone, Debug)] struct PanicOrd(T, bool); diff --git a/src/liballoc/tests/btree/map.rs b/src/liballoc/tests/btree/map.rs index 05e0bdffaa86b..f14750089c956 100644 --- a/src/liballoc/tests/btree/map.rs +++ b/src/liballoc/tests/btree/map.rs @@ -2,14 +2,17 @@ use std::collections::BTreeMap; use std::collections::btree_map::Entry::{Occupied, Vacant}; use std::ops::Bound::{self, Excluded, Included, Unbounded}; use std::rc::Rc; - use std::iter::FromIterator; + use super::DeterministicRng; #[test] fn test_basic_large() { let mut map = BTreeMap::new(); + #[cfg(not(miri))] // Miri is too slow let size = 10000; + #[cfg(miri)] + let size = 200; assert_eq!(map.len(), 0); for i in 0..size { @@ -69,7 +72,10 @@ fn test_basic_small() { #[test] fn test_iter() { + #[cfg(not(miri))] // Miri is too slow let size = 10000; + #[cfg(miri)] + let size = 200; // Forwards let mut map: BTreeMap<_, _> = (0..size).map(|i| (i, i)).collect(); @@ -91,7 +97,10 @@ fn test_iter() { #[test] fn test_iter_rev() { + #[cfg(not(miri))] // Miri is too slow let size = 10000; + #[cfg(miri)] + let size = 200; // Forwards let mut map: BTreeMap<_, _> = (0..size).map(|i| (i, i)).collect(); @@ -127,7 +136,10 @@ fn test_values_mut() { #[test] fn test_iter_mixed() { + #[cfg(not(miri))] // Miri is too slow let size = 10000; + #[cfg(miri)] + let size = 200; // Forwards let mut map: BTreeMap<_, _> = (0..size).map(|i| (i, i)).collect(); @@ -199,7 +211,7 @@ fn test_range_inclusive() { #[test] fn test_range_inclusive_max_value() { - let max = ::std::usize::MAX; + let max = std::usize::MAX; let map: BTreeMap<_, _> = vec![(max, 0)].into_iter().collect(); assert_eq!(map.range(max..=max).collect::>(), &[(&max, &0)]); @@ -214,6 +226,7 @@ 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))); @@ -221,6 +234,7 @@ 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))); @@ -228,6 +242,7 @@ 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))); @@ -235,6 +250,7 @@ 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))); @@ -242,6 +258,7 @@ 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))); @@ -249,7 +266,10 @@ fn test_range_backwards_4() { #[test] fn test_range_1000() { + #[cfg(not(miri))] // Miri is too slow let size = 1000; + #[cfg(miri)] + let size = 200; let map: BTreeMap<_, _> = (0..size).map(|i| (i, i)).collect(); fn test(map: &BTreeMap, size: u32, min: Bound<&u32>, max: Bound<&u32>) { @@ -286,7 +306,10 @@ fn test_range_borrowed_key() { #[test] fn test_range() { + #[cfg(not(miri))] // Miri is too slow let size = 200; + #[cfg(miri)] + let size = 30; let map: BTreeMap<_, _> = (0..size).map(|i| (i, i)).collect(); for i in 0..size { @@ -305,7 +328,10 @@ fn test_range() { #[test] fn test_range_mut() { + #[cfg(not(miri))] // Miri is too slow let size = 200; + #[cfg(miri)] + let size = 30; let mut map: BTreeMap<_, _> = (0..size).map(|i| (i, i)).collect(); for i in 0..size { @@ -479,7 +505,10 @@ fn test_bad_zst() { #[test] fn test_clone() { let mut map = BTreeMap::new(); + #[cfg(not(miri))] // Miri is too slow let size = 100; + #[cfg(miri)] + let size = 30; assert_eq!(map.len(), 0); for i in 0..size { @@ -631,6 +660,7 @@ create_append_test!(test_append_145, 145); create_append_test!(test_append_170, 170); create_append_test!(test_append_181, 181); create_append_test!(test_append_239, 239); +#[cfg(not(miri))] // Miri is too slow create_append_test!(test_append_1700, 1700); fn rand_data(len: usize) -> Vec<(u32, u32)> { diff --git a/src/liballoc/tests/btree/set.rs b/src/liballoc/tests/btree/set.rs index e24c04fd8acb3..4f5168f1ce572 100644 --- a/src/liballoc/tests/btree/set.rs +++ b/src/liballoc/tests/btree/set.rs @@ -1,6 +1,6 @@ use std::collections::BTreeSet; - use std::iter::FromIterator; + use super::DeterministicRng; #[test] @@ -15,6 +15,8 @@ fn test_clone_eq() { #[test] fn test_hash() { + use crate::hash; + let mut x = BTreeSet::new(); let mut y = BTreeSet::new(); @@ -26,7 +28,7 @@ fn test_hash() { y.insert(2); y.insert(1); - assert!(::hash(&x) == ::hash(&y)); + assert!(hash(&x) == hash(&y)); } fn check(a: &[i32], b: &[i32], expected: &[i32], f: F) diff --git a/src/liballoc/tests/heap.rs b/src/liballoc/tests/heap.rs index 24eea1d294965..c225ebfa96b91 100644 --- a/src/liballoc/tests/heap.rs +++ b/src/liballoc/tests/heap.rs @@ -1,6 +1,6 @@ use std::alloc::{Global, Alloc, Layout, System}; -/// https://github.com/rust-lang/rust/issues/45955 +/// Issue #45955. #[test] fn alloc_system_overaligned_request() { check_overalign_requests(System) diff --git a/src/liballoc/tests/lib.rs b/src/liballoc/tests/lib.rs index a76fd87a1a92d..2361a7db1f7a7 100644 --- a/src/liballoc/tests/lib.rs +++ b/src/liballoc/tests/lib.rs @@ -4,8 +4,6 @@ #![feature(exact_size_is_empty)] #![feature(pattern)] #![feature(repeat_generic_slice)] -#![feature(slice_sort_by_cached_key)] -#![feature(str_escape)] #![feature(try_reserve)] #![feature(unboxed_closures)] #![feature(vecdeque_rotate)] diff --git a/src/liballoc/tests/linked_list.rs b/src/liballoc/tests/linked_list.rs index 6e775f9650d12..0fbfbdccd4537 100644 --- a/src/liballoc/tests/linked_list.rs +++ b/src/liballoc/tests/linked_list.rs @@ -241,10 +241,12 @@ fn test_eq() { #[test] fn test_hash() { + use crate::hash; + let mut x = LinkedList::new(); let mut y = LinkedList::new(); - assert!(::hash(&x) == ::hash(&y)); + assert!(hash(&x) == hash(&y)); x.push_back(1); x.push_back(2); @@ -254,7 +256,7 @@ fn test_hash() { y.push_front(2); y.push_front(1); - assert!(::hash(&x) == ::hash(&y)); + assert!(hash(&x) == hash(&y)); } #[test] diff --git a/src/liballoc/tests/slice.rs b/src/liballoc/tests/slice.rs index 8ecd17236c048..feba46b0fad78 100644 --- a/src/liballoc/tests/slice.rs +++ b/src/liballoc/tests/slice.rs @@ -1,14 +1,13 @@ use std::cell::Cell; -use std::cmp::Ordering::{Equal, Greater, Less}; -use std::cmp::Ordering; +use std::cmp::Ordering::{self, Equal, Greater, Less}; use std::mem; use std::panic; use std::rc::Rc; -use std::sync::atomic::Ordering::Relaxed; -use std::sync::atomic::{ATOMIC_USIZE_INIT, AtomicUsize}; +use std::sync::atomic::{Ordering::Relaxed, AtomicUsize}; use std::thread; -use rand::{Rng, RngCore, thread_rng, seq::SliceRandom}; +use rand::{Rng, RngCore, thread_rng}; +use rand::seq::SliceRandom; use rand::distributions::Standard; fn square(n: usize) -> usize { @@ -259,6 +258,7 @@ 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,6 +390,7 @@ fn test_reverse() { } #[test] +#[cfg(not(miri))] // Miri does not support entropy fn test_sort() { let mut rng = thread_rng(); @@ -466,6 +467,7 @@ 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 { @@ -476,7 +478,7 @@ fn test_sort_stability() { // the second item represents which occurrence of that // number this element is, i.e., the second elements // will occur in sorted order. - let mut orig: Vec<_> = (0..len) + let orig: Vec<_> = (0..len) .map(|_| { let n = thread_rng().gen::() % 10; counts[n] += 1; @@ -630,6 +632,7 @@ 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); @@ -654,6 +657,7 @@ 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); @@ -935,6 +939,7 @@ 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); @@ -959,6 +964,7 @@ 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); @@ -983,6 +989,7 @@ 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); @@ -1007,6 +1014,7 @@ 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); @@ -1031,6 +1039,7 @@ 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); @@ -1083,6 +1092,7 @@ 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); @@ -1092,6 +1102,7 @@ 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); @@ -1267,6 +1278,7 @@ 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); @@ -1299,6 +1311,7 @@ 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); @@ -1331,6 +1344,7 @@ 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); @@ -1363,6 +1377,7 @@ 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); @@ -1396,6 +1411,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 fn test_box_slice_clone_panics() { use std::sync::Arc; use std::sync::atomic::{AtomicUsize, Ordering}; @@ -1460,6 +1476,7 @@ 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]; @@ -1468,6 +1485,7 @@ 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]; @@ -1500,7 +1518,7 @@ static DROP_COUNTS: [AtomicUsize; MAX_LEN] = [ AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), AtomicUsize::new(0), ]; -static VERSIONS: AtomicUsize = ATOMIC_USIZE_INIT; +static VERSIONS: AtomicUsize = AtomicUsize::new(0); #[derive(Clone, Eq)] struct DropCounter { @@ -1587,6 +1605,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 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 66a1b947a7d3a..b33a564218888 100644 --- a/src/liballoc/tests/str.rs +++ b/src/liballoc/tests/str.rs @@ -166,6 +166,7 @@ fn test_join_for_different_lengths_with_long_separator() { } #[test] +#[cfg(not(miri))] // Miri is too slow fn test_unsafe_slice() { assert_eq!("ab", unsafe {"abc".get_unchecked(0..2)}); assert_eq!("bc", unsafe {"abc".get_unchecked(1..3)}); @@ -350,6 +351,7 @@ 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"); } @@ -359,6 +361,7 @@ 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"); } @@ -406,6 +409,7 @@ 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; @@ -414,6 +418,7 @@ 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; @@ -483,6 +488,7 @@ mod slice_index { #[test] #[cfg(not(target_arch = "asmjs"))] // hits an OOM + #[cfg(not(miri))] // Miri is too slow fn simple_big() { fn a_million_letter_x() -> String { let mut i = 0; @@ -508,6 +514,7 @@ mod slice_index { #[test] #[should_panic] + #[cfg(not(miri))] // Miri does not support panics fn test_slice_fail() { &"中华Việt Nam"[0..2]; } @@ -584,7 +591,7 @@ mod slice_index { } mod boundary { - const DATA: &'static str = "abcαβγ"; + const DATA: &str = "abcαβγ"; const BAD_START: usize = 4; const GOOD_START: usize = 3; @@ -648,7 +655,7 @@ mod slice_index { } } - const LOREM_PARAGRAPH: &'static str = "\ + const LOREM_PARAGRAPH: &str = "\ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse quis lorem \ sit amet dolor ultricies condimentum. Praesent iaculis purus elit, ac malesuada \ quam malesuada in. Duis sed orci eros. Suspendisse sit amet magna mollis, mollis \ @@ -659,12 +666,14 @@ 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]; } @@ -679,6 +688,7 @@ 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]; @@ -694,6 +704,7 @@ 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; @@ -883,6 +894,7 @@ 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.) @@ -972,6 +984,7 @@ 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); @@ -979,15 +992,15 @@ fn test_split_at_boundscheck() { #[test] fn test_escape_unicode() { - assert_eq!("abc".escape_unicode(), "\\u{61}\\u{62}\\u{63}"); - assert_eq!("a c".escape_unicode(), "\\u{61}\\u{20}\\u{63}"); - assert_eq!("\r\n\t".escape_unicode(), "\\u{d}\\u{a}\\u{9}"); - assert_eq!("'\"\\".escape_unicode(), "\\u{27}\\u{22}\\u{5c}"); - assert_eq!("\x00\x01\u{fe}\u{ff}".escape_unicode(), "\\u{0}\\u{1}\\u{fe}\\u{ff}"); - assert_eq!("\u{100}\u{ffff}".escape_unicode(), "\\u{100}\\u{ffff}"); - assert_eq!("\u{10000}\u{10ffff}".escape_unicode(), "\\u{10000}\\u{10ffff}"); - assert_eq!("ab\u{fb00}".escape_unicode(), "\\u{61}\\u{62}\\u{fb00}"); - assert_eq!("\u{1d4ea}\r".escape_unicode(), "\\u{1d4ea}\\u{d}"); + assert_eq!("abc".escape_unicode().to_string(), "\\u{61}\\u{62}\\u{63}"); + assert_eq!("a c".escape_unicode().to_string(), "\\u{61}\\u{20}\\u{63}"); + assert_eq!("\r\n\t".escape_unicode().to_string(), "\\u{d}\\u{a}\\u{9}"); + assert_eq!("'\"\\".escape_unicode().to_string(), "\\u{27}\\u{22}\\u{5c}"); + assert_eq!("\x00\x01\u{fe}\u{ff}".escape_unicode().to_string(), "\\u{0}\\u{1}\\u{fe}\\u{ff}"); + assert_eq!("\u{100}\u{ffff}".escape_unicode().to_string(), "\\u{100}\\u{ffff}"); + assert_eq!("\u{10000}\u{10ffff}".escape_unicode().to_string(), "\\u{10000}\\u{10ffff}"); + assert_eq!("ab\u{fb00}".escape_unicode().to_string(), "\\u{61}\\u{62}\\u{fb00}"); + assert_eq!("\u{1d4ea}\r".escape_unicode().to_string(), "\\u{1d4ea}\\u{d}"); } #[test] @@ -998,31 +1011,32 @@ fn test_escape_debug() { // they are escaped. However, when the character is unescaped (e.g., for // printable characters), only a single backslash appears (as the character // itself appears in the debug string). - assert_eq!("abc".escape_debug(), "abc"); - assert_eq!("a c".escape_debug(), "a c"); - assert_eq!("éèê".escape_debug(), "éèê"); - assert_eq!("\r\n\t".escape_debug(), "\\r\\n\\t"); - assert_eq!("'\"\\".escape_debug(), "\\'\\\"\\\\"); - assert_eq!("\u{7f}\u{ff}".escape_debug(), "\\u{7f}\u{ff}"); - assert_eq!("\u{100}\u{ffff}".escape_debug(), "\u{100}\\u{ffff}"); - assert_eq!("\u{10000}\u{10ffff}".escape_debug(), "\u{10000}\\u{10ffff}"); - assert_eq!("ab\u{200b}".escape_debug(), "ab\\u{200b}"); - assert_eq!("\u{10d4ea}\r".escape_debug(), "\\u{10d4ea}\\r"); - assert_eq!("\u{301}a\u{301}bé\u{e000}".escape_debug(), "\\u{301}a\u{301}bé\\u{e000}"); + assert_eq!("abc".escape_debug().to_string(), "abc"); + assert_eq!("a c".escape_debug().to_string(), "a c"); + assert_eq!("éèê".escape_debug().to_string(), "éèê"); + assert_eq!("\r\n\t".escape_debug().to_string(), "\\r\\n\\t"); + assert_eq!("'\"\\".escape_debug().to_string(), "\\'\\\"\\\\"); + assert_eq!("\u{7f}\u{ff}".escape_debug().to_string(), "\\u{7f}\u{ff}"); + assert_eq!("\u{100}\u{ffff}".escape_debug().to_string(), "\u{100}\\u{ffff}"); + assert_eq!("\u{10000}\u{10ffff}".escape_debug().to_string(), "\u{10000}\\u{10ffff}"); + assert_eq!("ab\u{200b}".escape_debug().to_string(), "ab\\u{200b}"); + assert_eq!("\u{10d4ea}\r".escape_debug().to_string(), "\\u{10d4ea}\\r"); + assert_eq!("\u{301}a\u{301}bé\u{e000}".escape_debug().to_string(), + "\\u{301}a\u{301}bé\\u{e000}"); } #[test] fn test_escape_default() { - assert_eq!("abc".escape_default(), "abc"); - assert_eq!("a c".escape_default(), "a c"); - assert_eq!("éèê".escape_default(), "\\u{e9}\\u{e8}\\u{ea}"); - assert_eq!("\r\n\t".escape_default(), "\\r\\n\\t"); - assert_eq!("'\"\\".escape_default(), "\\'\\\"\\\\"); - assert_eq!("\u{7f}\u{ff}".escape_default(), "\\u{7f}\\u{ff}"); - assert_eq!("\u{100}\u{ffff}".escape_default(), "\\u{100}\\u{ffff}"); - assert_eq!("\u{10000}\u{10ffff}".escape_default(), "\\u{10000}\\u{10ffff}"); - assert_eq!("ab\u{200b}".escape_default(), "ab\\u{200b}"); - assert_eq!("\u{10d4ea}\r".escape_default(), "\\u{10d4ea}\\r"); + assert_eq!("abc".escape_default().to_string(), "abc"); + assert_eq!("a c".escape_default().to_string(), "a c"); + assert_eq!("éèê".escape_default().to_string(), "\\u{e9}\\u{e8}\\u{ea}"); + assert_eq!("\r\n\t".escape_default().to_string(), "\\r\\n\\t"); + assert_eq!("'\"\\".escape_default().to_string(), "\\'\\\"\\\\"); + assert_eq!("\u{7f}\u{ff}".escape_default().to_string(), "\\u{7f}\\u{ff}"); + assert_eq!("\u{100}\u{ffff}".escape_default().to_string(), "\\u{100}\\u{ffff}"); + assert_eq!("\u{10000}\u{10ffff}".escape_default().to_string(), "\\u{10000}\\u{10ffff}"); + assert_eq!("ab\u{200b}".escape_default().to_string(), "ab\\u{200b}"); + assert_eq!("\u{10d4ea}\r".escape_default().to_string(), "\\u{10d4ea}\\r"); } #[test] @@ -1066,9 +1080,10 @@ fn test_rev_iterator() { } #[test] +#[cfg(not(miri))] // Miri is too slow fn test_chars_decoding() { let mut bytes = [0; 4]; - for c in (0..0x110000).filter_map(::std::char::from_u32) { + for c in (0..0x110000).filter_map(std::char::from_u32) { let s = c.encode_utf8(&mut bytes); if Some(c) != s.chars().next() { panic!("character {:x}={} does not decode correctly", c as u32, c); @@ -1077,9 +1092,10 @@ fn test_chars_decoding() { } #[test] +#[cfg(not(miri))] // Miri is too slow fn test_chars_rev_decoding() { let mut bytes = [0; 4]; - for c in (0..0x110000).filter_map(::std::char::from_u32) { + for c in (0..0x110000).filter_map(std::char::from_u32) { let s = c.encode_utf8(&mut bytes); if Some(c) != s.chars().rev().next() { panic!("character {:x}={} does not decode correctly", c as u32, c); @@ -1365,6 +1381,7 @@ fn test_bool_from_str() { assert_eq!("not even a boolean".parse::().ok(), None); } +#[cfg(not(miri))] // Miri is too slow fn check_contains_all_substrings(s: &str) { assert!(s.contains("")); for i in 0..s.len() { @@ -1375,6 +1392,7 @@ fn check_contains_all_substrings(s: &str) { } #[test] +#[cfg(not(miri))] // Miri is too slow fn strslice_issue_16589() { assert!("bananas".contains("nana")); @@ -1391,6 +1409,7 @@ fn strslice_issue_16878() { #[test] +#[cfg(not(miri))] // Miri is too slow fn test_strslice_contains() { let x = "There are moments, Jeeves, when one asks oneself, 'Do trousers matter?'"; check_contains_all_substrings(x); @@ -1599,8 +1618,7 @@ fn test_repeat() { } mod pattern { - use std::str::pattern::Pattern; - use std::str::pattern::{Searcher, ReverseSearcher}; + use std::str::pattern::{Pattern, Searcher, ReverseSearcher}; use std::str::pattern::SearchStep::{self, Match, Reject, Done}; macro_rules! make_test { diff --git a/src/liballoc/tests/string.rs b/src/liballoc/tests/string.rs index 8a5bfca8b7db5..7e93d84fe3b97 100644 --- a/src/liballoc/tests/string.rs +++ b/src/liballoc/tests/string.rs @@ -21,7 +21,7 @@ impl<'a> IntoCow<'a, str> for &'a str { #[test] fn test_from_str() { - let owned: Option<::std::string::String> = "string".parse().ok(); + let owned: Option = "string".parse().ok(); assert_eq!(owned.as_ref().map(|s| &**s), Some("string")); } @@ -122,7 +122,7 @@ fn test_from_utf16() { let s_as_utf16 = s.encode_utf16().collect::>(); let u_as_string = String::from_utf16(&u).unwrap(); - assert!(::core::char::decode_utf16(u.iter().cloned()).all(|r| r.is_ok())); + assert!(core::char::decode_utf16(u.iter().cloned()).all(|r| r.is_ok())); assert_eq!(s_as_utf16, u); assert_eq!(u_as_string, s); @@ -231,6 +231,7 @@ 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); @@ -239,6 +240,7 @@ 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); @@ -287,6 +289,7 @@ 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); @@ -321,6 +324,7 @@ fn remove() { #[test] #[should_panic] +#[cfg(not(miri))] // Miri does not support panics fn remove_bad() { "ศ".to_string().remove(1); } @@ -356,11 +360,13 @@ 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'); } @@ -441,6 +447,7 @@ 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, ""); @@ -457,6 +464,7 @@ 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"); @@ -464,6 +472,7 @@ 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"); @@ -523,6 +532,7 @@ fn test_reserve_exact() { } #[test] +#[cfg(not(miri))] // Miri does not support signalling OOM fn test_try_reserve() { // These are the interesting cases: @@ -600,6 +610,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. diff --git a/src/liballoc/tests/vec.rs b/src/liballoc/tests/vec.rs index 0fdcf34c783a8..6e4ca1d90e642 100644 --- a/src/liballoc/tests/vec.rs +++ b/src/liballoc/tests/vec.rs @@ -1,3 +1,5 @@ +#![cfg(not(miri))] + use std::borrow::Cow; use std::mem::size_of; use std::{usize, isize}; @@ -8,7 +10,7 @@ struct DropCounter<'a> { count: &'a mut u32, } -impl<'a> Drop for DropCounter<'a> { +impl Drop for DropCounter<'_> { fn drop(&mut self) { *self.count += 1; } @@ -366,6 +368,7 @@ 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 { @@ -389,6 +392,7 @@ 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]; @@ -396,6 +400,7 @@ 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..]; @@ -403,6 +408,7 @@ 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]; @@ -410,6 +416,7 @@ 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]; @@ -417,6 +424,7 @@ 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]; @@ -424,6 +432,7 @@ 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]; @@ -431,6 +440,7 @@ 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); @@ -501,6 +511,7 @@ 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); @@ -574,6 +585,7 @@ 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); @@ -603,6 +615,7 @@ 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]; @@ -611,6 +624,7 @@ 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]; @@ -638,7 +652,7 @@ fn test_splice_unbounded() { fn test_splice_forget() { let mut v = vec![1, 2, 3, 4, 5]; let a = [10, 11, 12]; - ::std::mem::forget(v.splice(2..4, a.iter().cloned())); + std::mem::forget(v.splice(2..4, a.iter().cloned())); assert_eq!(v, &[1, 2]); } diff --git a/src/liballoc/tests/vec_deque.rs b/src/liballoc/tests/vec_deque.rs index 76831ba65e3b8..16ddc1444fcf9 100644 --- a/src/liballoc/tests/vec_deque.rs +++ b/src/liballoc/tests/vec_deque.rs @@ -1,12 +1,13 @@ -use std::collections::VecDeque; use std::fmt::Debug; -use std::collections::vec_deque::{Drain}; +use std::collections::{VecDeque, vec_deque::Drain}; use std::collections::CollectionAllocErr::*; use std::mem::size_of; use std::{usize, isize}; -use self::Taggy::*; -use self::Taggypar::*; +use crate::hash; + +use Taggy::*; +use Taggypar::*; #[test] fn test_simple() { @@ -107,6 +108,7 @@ 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 { @@ -583,7 +585,7 @@ fn test_hash() { y.push_back(2); y.push_back(3); - assert!(::hash(&x) == ::hash(&y)); + assert!(hash(&x) == hash(&y)); } #[test] @@ -599,7 +601,7 @@ fn test_hash_after_rotation() { *elt -= 1; } ring.push_back(len - 1); - assert_eq!(::hash(&orig), ::hash(&ring)); + assert_eq!(hash(&orig), hash(&ring)); assert_eq!(orig, ring); assert_eq!(ring, orig); } @@ -942,7 +944,10 @@ fn test_append_permutations() { out } + #[cfg(not(miri))] // Miri is too slow const MAX: usize = 5; + #[cfg(miri)] + const MAX: usize = 3; // Many different permutations of both the `VecDeque` getting appended to // and the one getting appended are generated to check `append`. @@ -998,7 +1003,7 @@ struct DropCounter<'a> { count: &'a mut u32, } -impl<'a> Drop for DropCounter<'a> { +impl Drop for DropCounter<'_> { fn drop(&mut self) { *self.count += 1; } @@ -1119,6 +1124,7 @@ fn test_reserve_exact_2() { } #[test] +#[cfg(not(miri))] // Miri does not support signalling OOM fn test_try_reserve() { // These are the interesting cases: @@ -1220,6 +1226,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. @@ -1433,3 +1440,104 @@ fn test_rotate_right_random() { } } } + +#[test] +fn test_try_fold_empty() { + assert_eq!(Some(0), VecDeque::::new().iter().try_fold(0, |_, _| None)); +} + +#[test] +fn test_try_fold_none() { + let v: VecDeque = (0..12).collect(); + assert_eq!(None, v.into_iter().try_fold(0, |a, b| + if b < 11 { Some(a + b) } else { None })); +} + +#[test] +fn test_try_fold_ok() { + let v: VecDeque = (0..12).collect(); + assert_eq!(Ok::<_, ()>(66), v.into_iter().try_fold(0, |a, b| Ok(a + b))); +} + +#[test] +fn test_try_fold_unit() { + let v: VecDeque<()> = std::iter::repeat(()).take(42).collect(); + assert_eq!(Some(()), v.into_iter().try_fold((), |(), ()| Some(()))); +} + + +#[test] +fn test_try_fold_unit_none() { + let v: std::collections::VecDeque<()> = [(); 10].iter().cloned().collect(); + let mut iter = v.into_iter(); + assert!(iter.try_fold((), |_, _| None).is_none()); + assert_eq!(iter.len(), 9); +} + +#[test] +fn test_try_fold_rotated() { + let mut v: VecDeque<_> = (0..12).collect(); + for n in 0..10 { + if n & 1 == 0 { + v.rotate_left(n); + } else { + v.rotate_right(n); + } + assert_eq!(Ok::<_, ()>(66), v.iter().try_fold(0, |a, b| Ok(a + b))); + } +} + +#[test] +fn test_try_fold_moves_iter() { + let v: VecDeque<_> = [10, 20, 30, 40, 100, 60, 70, 80, 90].iter().collect(); + let mut iter = v.into_iter(); + assert_eq!(iter.try_fold(0_i8, |acc, &x| acc.checked_add(x)), None); + assert_eq!(iter.next(), Some(&60)); +} + +#[test] +fn test_try_fold_exhaust_wrap() { + let mut v = VecDeque::with_capacity(7); + v.push_back(1); + v.push_back(1); + v.push_back(1); + v.pop_front(); + v.pop_front(); + let mut iter = v.iter(); + let _ = iter.try_fold(0, |_, _| Some(1)); + assert!(iter.is_empty()); +} + +#[test] +fn test_try_fold_wraparound() { + let mut v = VecDeque::with_capacity(8); + v.push_back(7); + v.push_back(8); + v.push_back(9); + v.push_front(2); + v.push_front(1); + let mut iter = v.iter(); + let _ = iter.find(|&&x| x == 2); + assert_eq!(Some(&7), iter.next()); +} + +#[test] +fn test_try_rfold_rotated() { + let mut v: VecDeque<_> = (0..12).collect(); + for n in 0..10 { + if n & 1 == 0 { + v.rotate_left(n); + } else { + v.rotate_right(n); + } + assert_eq!(Ok::<_, ()>(66), v.iter().try_rfold(0, |a, b| Ok(a + b))); + } +} + +#[test] +fn test_try_rfold_moves_iter() { + let v : VecDeque<_> = [10, 20, 30, 40, 100, 60, 70, 80, 90].iter().collect(); + let mut iter = v.into_iter(); + assert_eq!(iter.try_rfold(0_i8, |acc, &x| acc.checked_add(x)), None); + assert_eq!(iter.next_back(), Some(&70)); +} diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index ba3b3dfbfc2e1..dddfa3f158e71 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -63,18 +63,15 @@ use core::intrinsics::{arith_offset, assume}; use core::iter::{FromIterator, FusedIterator, TrustedLen}; use core::marker::PhantomData; use core::mem; +use core::ops::{self, Index, IndexMut, RangeBounds}; use core::ops::Bound::{Excluded, Included, Unbounded}; -use core::ops::{Index, IndexMut, RangeBounds}; -use core::ops; -use core::ptr; -use core::ptr::NonNull; -use core::slice; - -use collections::CollectionAllocErr; -use borrow::ToOwned; -use borrow::Cow; -use boxed::Box; -use raw_vec::RawVec; +use core::ptr::{self, NonNull}; +use core::slice::{self, SliceIndex}; + +use crate::borrow::{ToOwned, Cow}; +use crate::collections::CollectionAllocErr; +use crate::boxed::Box; +use crate::raw_vec::RawVec; /// A contiguous growable array type, written `Vec` but pronounced 'vector'. /// @@ -466,7 +463,7 @@ impl Vec { /// Does nothing if the capacity is already sufficient. /// /// Note that the allocator may give the collection more space than it - /// requests. Therefore capacity can not be relied upon to be precisely + /// requests. Therefore, capacity can not be relied upon to be precisely /// minimal. Prefer `reserve` if future insertions are expected. /// /// # Panics @@ -528,7 +525,7 @@ impl Vec { /// Does nothing if the capacity is already sufficient. /// /// Note that the allocator may give the collection more space than it - /// requests. Therefore capacity can not be relied upon to be precisely + /// requests. Therefore, capacity can not be relied upon to be precisely /// minimal. Prefer `reserve` if future insertions are expected. /// /// # Errors @@ -741,7 +738,7 @@ impl Vec { /// Forces the length of the vector to `new_len`. /// /// This is a low-level operation that maintains none of the normal - /// invariants of the type. Normally changing the length of a vector + /// invariants of the type. Normally changing the length of a vector /// is done using one of the safe operations instead, such as /// [`truncate`], [`resize`], [`extend`], or [`clear`]. /// @@ -1118,7 +1115,7 @@ impl Vec { /// assert_eq!(v, &[]); /// ``` #[stable(feature = "drain", since = "1.6.0")] - pub fn drain(&mut self, range: R) -> Drain + pub fn drain(&mut self, range: R) -> Drain<'_, T> where R: RangeBounds { // Memory safety @@ -1368,6 +1365,7 @@ impl Vec { /// # Examples /// /// ``` + /// # #![allow(deprecated)] /// #![feature(vec_resize_default)] /// /// let mut vec = vec![1, 2, 3]; @@ -1384,6 +1382,9 @@ impl Vec { /// [`Default`]: ../../std/default/trait.Default.html /// [`Clone`]: ../../std/clone/trait.Clone.html #[unstable(feature = "vec_resize_default", issue = "41758")] + #[rustc_deprecated(reason = "This is moving towards being removed in favor \ + of `.resize_with(Default::default)`. If you disagree, please comment \ + in the tracking issue.", since = "1.33.0")] pub fn resize_default(&mut self, new_len: usize) { let len = self.len(); @@ -1477,7 +1478,7 @@ impl<'a> SetLenOnDrop<'a> { } } -impl<'a> Drop for SetLenOnDrop<'a> { +impl Drop for SetLenOnDrop<'_> { #[inline] fn drop(&mut self) { *self.len = self.local_len; @@ -1646,7 +1647,7 @@ impl Clone for Vec { // NB see the slice::hack module in slice.rs for more information #[cfg(test)] fn clone(&self) -> Vec { - ::slice::to_vec(&**self) + crate::slice::to_vec(&**self) } fn clone_from(&mut self, other: &Vec) { @@ -1667,10 +1668,7 @@ impl Hash for Vec { message="vector indices are of type `usize` or ranges of `usize`", label="vector indices are of type `usize` or ranges of `usize`", )] -impl Index for Vec -where - I: ::core::slice::SliceIndex<[T]>, -{ +impl> Index for Vec { type Output = I::Output; #[inline] @@ -1684,10 +1682,7 @@ where message="vector indices are of type `usize` or ranges of `usize`", label="vector indices are of type `usize` or ranges of `usize`", )] -impl IndexMut for Vec -where - I: ::core::slice::SliceIndex<[T]>, -{ +impl> IndexMut for Vec { #[inline] fn index_mut(&mut self, index: I) -> &mut Self::Output { IndexMut::index_mut(&mut **self, index) @@ -1981,7 +1976,7 @@ impl Vec { /// ``` #[inline] #[stable(feature = "vec_splice", since = "1.21.0")] - pub fn splice(&mut self, range: R, replace_with: I) -> Splice + pub fn splice(&mut self, range: R, replace_with: I) -> Splice<'_, I::IntoIter> where R: RangeBounds, I: IntoIterator { Splice { @@ -2036,7 +2031,7 @@ impl Vec { /// assert_eq!(odds, vec![1, 3, 5, 9, 11, 13, 15]); /// ``` #[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] - pub fn drain_filter(&mut self, filter: F) -> DrainFilter + pub fn drain_filter(&mut self, filter: F) -> DrainFilter<'_, T, F> where F: FnMut(&mut T) -> bool, { let old_len = self.len(); @@ -2152,7 +2147,7 @@ impl Default for Vec { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for Vec { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&**self, f) } } @@ -2193,7 +2188,7 @@ impl<'a, T: Clone> From<&'a [T]> for Vec { } #[cfg(test)] fn from(s: &'a [T]) -> Vec { - ::slice::to_vec(s) + crate::slice::to_vec(s) } } @@ -2205,7 +2200,7 @@ impl<'a, T: Clone> From<&'a mut [T]> for Vec { } #[cfg(test)] fn from(s: &'a mut [T]) -> Vec { - ::slice::to_vec(s) + crate::slice::to_vec(s) } } @@ -2295,7 +2290,7 @@ pub struct IntoIter { #[stable(feature = "vec_intoiter_debug", since = "1.13.0")] impl fmt::Debug for IntoIter { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("IntoIter") .field(&self.as_slice()) .finish() @@ -2464,8 +2459,8 @@ pub struct Drain<'a, T: 'a> { } #[stable(feature = "collection_debug", since = "1.17.0")] -impl<'a, T: 'a + fmt::Debug> fmt::Debug for Drain<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +impl fmt::Debug for Drain<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("Drain") .field(&self.iter.as_slice()) .finish() @@ -2473,12 +2468,12 @@ impl<'a, T: 'a + fmt::Debug> fmt::Debug for Drain<'a, T> { } #[stable(feature = "drain", since = "1.6.0")] -unsafe impl<'a, T: Sync> Sync for Drain<'a, T> {} +unsafe impl Sync for Drain<'_, T> {} #[stable(feature = "drain", since = "1.6.0")] -unsafe impl<'a, T: Send> Send for Drain<'a, T> {} +unsafe impl Send for Drain<'_, T> {} #[stable(feature = "drain", since = "1.6.0")] -impl<'a, T> Iterator for Drain<'a, T> { +impl Iterator for Drain<'_, T> { type Item = T; #[inline] @@ -2492,7 +2487,7 @@ impl<'a, T> Iterator for Drain<'a, T> { } #[stable(feature = "drain", since = "1.6.0")] -impl<'a, T> DoubleEndedIterator for Drain<'a, T> { +impl DoubleEndedIterator for Drain<'_, T> { #[inline] fn next_back(&mut self) -> Option { self.iter.next_back().map(|elt| unsafe { ptr::read(elt as *const _) }) @@ -2500,7 +2495,7 @@ impl<'a, T> DoubleEndedIterator for Drain<'a, T> { } #[stable(feature = "drain", since = "1.6.0")] -impl<'a, T> Drop for Drain<'a, T> { +impl Drop for Drain<'_, T> { fn drop(&mut self) { // exhaust self first self.for_each(drop); @@ -2524,14 +2519,14 @@ impl<'a, T> Drop for Drain<'a, T> { #[stable(feature = "drain", since = "1.6.0")] -impl<'a, T> ExactSizeIterator for Drain<'a, T> { +impl ExactSizeIterator for Drain<'_, T> { fn is_empty(&self) -> bool { self.iter.is_empty() } } #[stable(feature = "fused", since = "1.26.0")] -impl<'a, T> FusedIterator for Drain<'a, T> {} +impl FusedIterator for Drain<'_, T> {} /// A splicing iterator for `Vec`. /// @@ -2548,7 +2543,7 @@ pub struct Splice<'a, I: Iterator + 'a> { } #[stable(feature = "vec_splice", since = "1.21.0")] -impl<'a, I: Iterator> Iterator for Splice<'a, I> { +impl Iterator for Splice<'_, I> { type Item = I::Item; fn next(&mut self) -> Option { @@ -2561,18 +2556,18 @@ impl<'a, I: Iterator> Iterator for Splice<'a, I> { } #[stable(feature = "vec_splice", since = "1.21.0")] -impl<'a, I: Iterator> DoubleEndedIterator for Splice<'a, I> { +impl DoubleEndedIterator for Splice<'_, I> { fn next_back(&mut self) -> Option { self.drain.next_back() } } #[stable(feature = "vec_splice", since = "1.21.0")] -impl<'a, I: Iterator> ExactSizeIterator for Splice<'a, I> {} +impl ExactSizeIterator for Splice<'_, I> {} #[stable(feature = "vec_splice", since = "1.21.0")] -impl<'a, I: Iterator> Drop for Splice<'a, I> { +impl Drop for Splice<'_, I> { fn drop(&mut self) { self.drain.by_ref().for_each(drop); @@ -2613,11 +2608,11 @@ impl<'a, I: Iterator> Drop for Splice<'a, I> { } /// Private helper methods for `Splice::drop` -impl<'a, T> Drain<'a, T> { +impl Drain<'_, T> { /// The range from `self.vec.len` to `self.tail_start` contains elements /// that have been moved out. /// Fill that range as much as possible with new elements from the `replace_with` iterator. - /// Return whether we filled the entire range. (`replace_with.next()` didn’t return `None`.) + /// Returns `true` if we filled the entire range. (`replace_with.next()` didn’t return `None`.) unsafe fn fill>(&mut self, replace_with: &mut I) -> bool { let vec = self.vec.as_mut(); let range_start = vec.len; @@ -2637,7 +2632,7 @@ impl<'a, T> Drain<'a, T> { true } - /// Make room for inserting more elements before the tail. + /// Makes room for inserting more elements before the tail. unsafe fn move_tail(&mut self, extra_capacity: usize) { let vec = self.vec.as_mut(); let used_capacity = self.tail_start + self.tail_len; @@ -2654,7 +2649,7 @@ impl<'a, T> Drain<'a, T> { /// An iterator produced by calling `drain_filter` on Vec. #[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] #[derive(Debug)] -pub struct DrainFilter<'a, T: 'a, F> +pub struct DrainFilter<'a, T, F> where F: FnMut(&mut T) -> bool, { vec: &'a mut Vec, @@ -2665,7 +2660,7 @@ pub struct DrainFilter<'a, T: 'a, F> } #[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] -impl<'a, T, F> Iterator for DrainFilter<'a, T, F> +impl Iterator for DrainFilter<'_, T, F> where F: FnMut(&mut T) -> bool, { type Item = T; @@ -2699,7 +2694,7 @@ impl<'a, T, F> Iterator for DrainFilter<'a, T, F> } #[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] -impl<'a, T, F> Drop for DrainFilter<'a, T, F> +impl Drop for DrainFilter<'_, T, F> where F: FnMut(&mut T) -> bool, { fn drop(&mut self) { diff --git a/src/libarena/Cargo.toml b/src/libarena/Cargo.toml index e2af67dd92861..82fc64ba64e33 100644 --- a/src/libarena/Cargo.toml +++ b/src/libarena/Cargo.toml @@ -2,6 +2,7 @@ authors = ["The Rust Project Developers"] name = "arena" version = "0.0.0" +edition = "2018" [lib] name = "arena" @@ -9,4 +10,4 @@ path = "lib.rs" crate-type = ["dylib"] [dependencies] -rustc_data_structures = { path = "../librustc_data_structures" } \ No newline at end of file +rustc_data_structures = { path = "../librustc_data_structures" } diff --git a/src/libarena/lib.rs b/src/libarena/lib.rs index 9f9ded51e37ee..8ae046c0796bc 100644 --- a/src/libarena/lib.rs +++ b/src/libarena/lib.rs @@ -8,22 +8,20 @@ //! This crate implements `TypedArena`, a simple arena that can only hold //! objects of a single type. -#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", - html_favicon_url = "https://doc.rust-lang.org/favicon.ico", - html_root_url = "https://doc.rust-lang.org/nightly/", +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/", test(no_crate_inject, attr(deny(warnings))))] +#![deny(rust_2018_idioms)] + #![feature(alloc)] #![feature(core_intrinsics)] #![feature(dropck_eyepatch)] -#![feature(nll)] #![feature(raw_vec_internals)] #![cfg_attr(test, feature(test))] #![allow(deprecated)] extern crate alloc; -extern crate rustc_data_structures; use rustc_data_structures::sync::MTLock; @@ -478,7 +476,7 @@ impl SyncDroplessArena { #[cfg(test)] mod tests { extern crate test; - use self::test::Bencher; + use test::Bencher; use super::TypedArena; use std::cell::Cell; @@ -513,15 +511,15 @@ mod tests { impl<'a> Wrap<'a> { fn alloc_inner Inner>(&self, f: F) -> &Inner { - let r: &EI = self.0.alloc(EI::I(f())); + 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())); + 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 { @@ -611,7 +609,7 @@ mod tests { count: &'a Cell, } - impl<'a> Drop for DropCounter<'a> { + impl Drop for DropCounter<'_> { fn drop(&mut self) { self.count.set(self.count.get() + 1); } @@ -621,7 +619,7 @@ mod tests { fn test_typed_arena_drop_count() { let counter = Cell::new(0); { - let arena: TypedArena = TypedArena::default(); + 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 }); @@ -633,7 +631,7 @@ mod tests { #[test] fn test_typed_arena_drop_on_clear() { let counter = Cell::new(0); - let mut arena: TypedArena = TypedArena::default(); + 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. diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index 66a3094d77d01..f49e226a5cb68 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -425,7 +425,7 @@ impl fmt::Display for CannotReallocInPlace { /// The `GlobalAlloc` trait is an `unsafe` trait for a number of reasons, and /// implementors must ensure that they adhere to these contracts: /// -/// * It's undefined behavior if global allocators unwind. This restriction may +/// * It's undefined behavior if global allocators unwind. This restriction may /// be lifted in the future, but currently a panic from any of these /// functions may lead to memory unsafety. /// diff --git a/src/libcore/any.rs b/src/libcore/any.rs index 6a863ff369a87..01ab523a4c3f6 100644 --- a/src/libcore/any.rs +++ b/src/libcore/any.rs @@ -18,7 +18,7 @@ //! //! Consider a situation where we want to log out a value passed to a function. //! We know the value we're working on implements Debug, but we don't know its -//! concrete type. We want to give special treatment to certain types: in this +//! concrete type. We want to give special treatment to certain types: in this //! case printing out the length of String values prior to their value. //! We don't know the concrete type of our value at compile time, so we need to //! use runtime reflection instead. @@ -31,8 +31,8 @@ //! fn log(value: &T) { //! let value_any = value as &dyn Any; //! -//! // try to convert our value to a String. If successful, we want to -//! // output the String's length as well as its value. If not, it's a +//! // Try to convert our value to a `String`. If successful, we want to +//! // output the String`'s length as well as its value. If not, it's a //! // different type: just print it out unadorned. //! match value_any.downcast_ref::() { //! Some(as_string) => { @@ -81,12 +81,10 @@ pub trait Any: 'static { /// # Examples /// /// ``` - /// #![feature(get_type_id)] - /// /// use std::any::{Any, TypeId}; /// /// fn is_string(s: &dyn Any) -> bool { - /// TypeId::of::() == s.get_type_id() + /// TypeId::of::() == s.type_id() /// } /// /// fn main() { @@ -94,15 +92,13 @@ pub trait Any: 'static { /// assert_eq!(is_string(&"cookie monster".to_string()), true); /// } /// ``` - #[unstable(feature = "get_type_id", - reason = "this method will likely be replaced by an associated static", - issue = "27745")] - fn get_type_id(&self) -> TypeId; + #[stable(feature = "get_type_id", since = "1.34.0")] + fn type_id(&self) -> TypeId; } #[stable(feature = "rust1", since = "1.0.0")] impl Any for T { - fn get_type_id(&self) -> TypeId { TypeId::of::() } + fn type_id(&self) -> TypeId { TypeId::of::() } } /////////////////////////////////////////////////////////////////////////////// @@ -161,10 +157,10 @@ impl dyn Any { let t = TypeId::of::(); // Get TypeId of the type in the trait object - let boxed = self.get_type_id(); + let concrete = self.type_id(); // Compare both TypeIds on equality - t == boxed + t == concrete } /// Returns some reference to the boxed value if it is of type `T`, or diff --git a/src/libcore/benches/fmt.rs b/src/libcore/benches/fmt.rs new file mode 100644 index 0000000000000..92f10c760c6d2 --- /dev/null +++ b/src/libcore/benches/fmt.rs @@ -0,0 +1,110 @@ +use std::io::{self, Write as IoWrite}; +use std::fmt::{self, Write as FmtWrite}; +use test::Bencher; + +#[bench] +fn write_vec_value(bh: &mut Bencher) { + bh.iter(|| { + let mut mem = Vec::new(); + for _ in 0..1000 { + mem.write_all("abc".as_bytes()).unwrap(); + } + }); +} + +#[bench] +fn write_vec_ref(bh: &mut Bencher) { + bh.iter(|| { + let mut mem = Vec::new(); + let wr = &mut mem as &mut dyn io::Write; + for _ in 0..1000 { + wr.write_all("abc".as_bytes()).unwrap(); + } + }); +} + +#[bench] +fn write_vec_macro1(bh: &mut Bencher) { + bh.iter(|| { + let mut mem = Vec::new(); + let wr = &mut mem as &mut dyn io::Write; + for _ in 0..1000 { + write!(wr, "abc").unwrap(); + } + }); +} + +#[bench] +fn write_vec_macro2(bh: &mut Bencher) { + bh.iter(|| { + let mut mem = Vec::new(); + let wr = &mut mem as &mut dyn io::Write; + for _ in 0..1000 { + write!(wr, "{}", "abc").unwrap(); + } + }); +} + +#[bench] +fn write_vec_macro_debug(bh: &mut Bencher) { + bh.iter(|| { + let mut mem = Vec::new(); + let wr = &mut mem as &mut dyn io::Write; + for _ in 0..1000 { + write!(wr, "{:?}", "☃").unwrap(); + } + }); +} + +#[bench] +fn write_str_value(bh: &mut Bencher) { + bh.iter(|| { + let mut mem = String::new(); + for _ in 0..1000 { + mem.write_str("abc").unwrap(); + } + }); +} + +#[bench] +fn write_str_ref(bh: &mut Bencher) { + bh.iter(|| { + let mut mem = String::new(); + let wr = &mut mem as &mut dyn fmt::Write; + for _ in 0..1000 { + wr.write_str("abc").unwrap(); + } + }); +} + +#[bench] +fn write_str_macro1(bh: &mut Bencher) { + bh.iter(|| { + let mut mem = String::new(); + for _ in 0..1000 { + write!(mem, "abc").unwrap(); + } + }); +} + +#[bench] +fn write_str_macro2(bh: &mut Bencher) { + bh.iter(|| { + let mut mem = String::new(); + let wr = &mut mem as &mut dyn fmt::Write; + for _ in 0..1000 { + write!(wr, "{}", "abc").unwrap(); + } + }); +} + +#[bench] +fn write_str_macro_debug(bh: &mut Bencher) { + bh.iter(|| { + let mut mem = String::new(); + let wr = &mut mem as &mut dyn fmt::Write; + for _ in 0..1000 { + write!(wr, "{:?}", "☃").unwrap(); + } + }); +} diff --git a/src/libcore/benches/lib.rs b/src/libcore/benches/lib.rs index 5b4971c81dd92..48572af611a5b 100644 --- a/src/libcore/benches/lib.rs +++ b/src/libcore/benches/lib.rs @@ -11,3 +11,4 @@ mod iter; mod num; mod ops; mod slice; +mod fmt; diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index d57ca13a334e8..8383d305518ab 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -130,7 +130,7 @@ //! //! This is simply a special - but common - case of the previous: hiding mutability for operations //! that appear to be immutable. The `clone` method is expected to not change the source value, and -//! is declared to take `&self`, not `&mut self`. Therefore any mutation that happens in the +//! is declared to take `&self`, not `&mut self`. Therefore, any mutation that happens in the //! `clone` method must use cell types. For example, `Rc` maintains its reference counts within a //! `Cell`. //! @@ -1133,7 +1133,7 @@ impl<'b, T: ?Sized> Ref<'b, T> { /// The `RefCell` is already immutably borrowed, so this cannot fail. /// /// This is an associated function that needs to be used as - /// `Ref::clone(...)`. A `Clone` implementation or a method would interfere + /// `Ref::clone(...)`. A `Clone` implementation or a method would interfere /// with the widespread use of `r.borrow().clone()` to clone the contents of /// a `RefCell`. #[stable(feature = "cell_extras", since = "1.15.0")] @@ -1145,7 +1145,7 @@ impl<'b, T: ?Sized> Ref<'b, T> { } } - /// Make a new `Ref` for a component of the borrowed data. + /// Makes a new `Ref` for a component of the borrowed data. /// /// The `RefCell` is already immutably borrowed, so this cannot fail. /// @@ -1174,7 +1174,7 @@ impl<'b, T: ?Sized> Ref<'b, T> { } } - /// Split a `Ref` into multiple `Ref`s for different components of the + /// Splits a `Ref` into multiple `Ref`s for different components of the /// borrowed data. /// /// The `RefCell` is already immutably borrowed, so this cannot fail. @@ -1217,13 +1217,13 @@ impl fmt::Display for Ref<'_, T> { } impl<'b, T: ?Sized> RefMut<'b, T> { - /// Make a new `RefMut` for a component of the borrowed data, e.g., an enum + /// Makes a new `RefMut` for a component of the borrowed data, e.g., an enum /// variant. /// /// The `RefCell` is already mutably borrowed, so this cannot fail. /// /// This is an associated function that needs to be used as - /// `RefMut::map(...)`. A method would interfere with methods of the same + /// `RefMut::map(...)`. A method would interfere with methods of the same /// name on the contents of a `RefCell` used through `Deref`. /// /// # Examples @@ -1253,7 +1253,7 @@ impl<'b, T: ?Sized> RefMut<'b, T> { } } - /// Split a `RefMut` into multiple `RefMut`s for different components of the + /// Splits a `RefMut` into multiple `RefMut`s for different components of the /// borrowed data. /// /// The underlying `RefCell` will remain mutably borrowed until both @@ -1416,7 +1416,7 @@ impl fmt::Display for RefMut<'_, T> { /// co-exist with it. A `&mut T` must always be unique. /// /// Note that while mutating or mutably aliasing the contents of an `&UnsafeCell` is -/// okay (provided you enforce the invariants some other way), it is still undefined behavior +/// ok (provided you enforce the invariants some other way), it is still undefined behavior /// to have multiple `&mut UnsafeCell` aliases. /// /// # Examples diff --git a/src/libcore/char/decode.rs b/src/libcore/char/decode.rs index 510c46cdca0ed..133c9169df858 100644 --- a/src/libcore/char/decode.rs +++ b/src/libcore/char/decode.rs @@ -20,7 +20,7 @@ pub struct DecodeUtf16Error { code: u16, } -/// Create an iterator over the UTF-16 encoded code points in `iter`, +/// Creates an iterator over the UTF-16 encoded code points in `iter`, /// returning unpaired surrogates as `Err`s. /// /// # Examples diff --git a/src/libcore/char/methods.rs b/src/libcore/char/methods.rs index fbc9a4a6b8efa..122e5f3affdc2 100644 --- a/src/libcore/char/methods.rs +++ b/src/libcore/char/methods.rs @@ -189,10 +189,8 @@ impl char { /// An extended version of `escape_debug` that optionally permits escaping /// Extended Grapheme codepoints. This allows us to format characters like /// nonspacing marks better when they're at the start of a string. - #[doc(hidden)] - #[unstable(feature = "str_internals", issue = "0")] #[inline] - pub fn escape_debug_ext(self, escape_grapheme_extended: bool) -> EscapeDebug { + pub(crate) fn escape_debug_ext(self, escape_grapheme_extended: bool) -> EscapeDebug { let init_state = match self { '\t' => EscapeDefaultState::Backslash('t'), '\r' => EscapeDefaultState::Backslash('r'), @@ -524,7 +522,7 @@ impl char { } } - /// Returns true if this `char` is an alphabetic code point, and false if not. + /// Returns `true` if this `char` is an alphabetic code point, and false if not. /// /// # Examples /// @@ -548,7 +546,7 @@ impl char { } } - /// Returns true if this `char` satisfies the 'XID_Start' Unicode property, and false + /// Returns `true` if this `char` satisfies the 'XID_Start' Unicode property, and false /// otherwise. /// /// 'XID_Start' is a Unicode Derived Property specified in @@ -562,7 +560,7 @@ impl char { derived_property::XID_Start(self) } - /// Returns true if this `char` satisfies the 'XID_Continue' Unicode property, and false + /// Returns `true` if this `char` satisfies the 'XID_Continue' Unicode property, and false /// otherwise. /// /// 'XID_Continue' is a Unicode Derived Property specified in @@ -576,7 +574,7 @@ impl char { derived_property::XID_Continue(self) } - /// Returns true if this `char` is lowercase, and false otherwise. + /// Returns `true` if this `char` is lowercase. /// /// 'Lowercase' is defined according to the terms of the Unicode Derived Core /// Property `Lowercase`. @@ -604,7 +602,7 @@ impl char { } } - /// Returns true if this `char` is uppercase, and false otherwise. + /// Returns `true` if this `char` is uppercase. /// /// 'Uppercase' is defined according to the terms of the Unicode Derived Core /// Property `Uppercase`. @@ -632,7 +630,7 @@ impl char { } } - /// Returns true if this `char` is whitespace, and false otherwise. + /// Returns `true` if this `char` is whitespace. /// /// 'Whitespace' is defined according to the terms of the Unicode Derived Core /// Property `White_Space`. @@ -659,7 +657,7 @@ impl char { } } - /// Returns true if this `char` is alphanumeric, and false otherwise. + /// Returns `true` if this `char` is alphanumeric. /// /// 'Alphanumeric'-ness is defined in terms of the Unicode General Categories /// 'Nd', 'Nl', 'No' and the Derived Core Property 'Alphabetic'. @@ -684,7 +682,7 @@ impl char { self.is_alphabetic() || self.is_numeric() } - /// Returns true if this `char` is a control code point, and false otherwise. + /// Returns `true` if this `char` is a control code point. /// /// 'Control code point' is defined in terms of the Unicode General /// Category `Cc`. @@ -704,7 +702,7 @@ impl char { general_category::Cc(self) } - /// Returns true if this `char` is an extended grapheme character, and false otherwise. + /// Returns `true` if this `char` is an extended grapheme character. /// /// 'Extended grapheme character' is defined in terms of the Unicode Shaping and Rendering /// Category `Grapheme_Extend`. @@ -713,7 +711,7 @@ impl char { derived_property::Grapheme_Extend(self) } - /// Returns true if this `char` is numeric, and false otherwise. + /// Returns `true` if this `char` is numeric. /// /// 'Numeric'-ness is defined in terms of the Unicode General Categories /// 'Nd', 'Nl', 'No'. diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index 86f28a957cd2c..81fcdeee12d29 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -26,7 +26,7 @@ use self::Ordering::*; /// relations](http://en.wikipedia.org/wiki/Partial_equivalence_relation). /// /// This trait allows for partial equality, for types that do not have a full -/// equivalence relation. For example, in floating point numbers `NaN != NaN`, +/// equivalence relation. For example, in floating point numbers `NaN != NaN`, /// so floating point types implement `PartialEq` but not `Eq`. /// /// Formally, the equality must be (for all `a`, `b` and `c`): @@ -91,6 +91,8 @@ use self::Ordering::*; /// For example, let's tweak our previous code a bit: /// /// ``` +/// // The derive implements == comparisons +/// #[derive(PartialEq)] /// enum BookFormat { /// Paperback, /// Hardback, @@ -102,31 +104,34 @@ use self::Ordering::*; /// format: BookFormat, /// } /// +/// // Implement == comparisons /// impl PartialEq for Book { /// fn eq(&self, other: &BookFormat) -> bool { -/// match (&self.format, other) { -/// (BookFormat::Paperback, BookFormat::Paperback) => true, -/// (BookFormat::Hardback, BookFormat::Hardback) => true, -/// (BookFormat::Ebook, BookFormat::Ebook) => true, -/// (_, _) => false, -/// } +/// self.format == *other +/// } +/// } +/// +/// // Implement == comparisons +/// impl PartialEq for BookFormat { +/// fn eq(&self, other: &Book) -> bool { +/// *self == other.format /// } /// } /// /// let b1 = Book { isbn: 3, format: BookFormat::Paperback }; /// /// assert!(b1 == BookFormat::Paperback); -/// assert!(b1 != BookFormat::Ebook); +/// assert!(BookFormat::Ebook != b1); /// ``` /// /// By changing `impl PartialEq for Book` to `impl PartialEq for Book`, -/// we've changed what type we can use on the right side of the `==` operator. -/// This lets us use it in the `assert!` statements at the bottom. +/// we allow `BookFormat`s to be compared with `Book`s. /// /// You can also combine these implementations to let the `==` operator work with /// two different types: /// /// ``` +/// #[derive(PartialEq)] /// enum BookFormat { /// Paperback, /// Hardback, @@ -140,12 +145,13 @@ use self::Ordering::*; /// /// impl PartialEq for Book { /// fn eq(&self, other: &BookFormat) -> bool { -/// match (&self.format, other) { -/// (&BookFormat::Paperback, &BookFormat::Paperback) => true, -/// (&BookFormat::Hardback, &BookFormat::Hardback) => true, -/// (&BookFormat::Ebook, &BookFormat::Ebook) => true, -/// (_, _) => false, -/// } +/// self.format == *other +/// } +/// } +/// +/// impl PartialEq for BookFormat { +/// fn eq(&self, other: &Book) -> bool { +/// *self == other.format /// } /// } /// @@ -159,7 +165,7 @@ use self::Ordering::*; /// let b2 = Book { isbn: 3, format: BookFormat::Ebook }; /// /// assert!(b1 == BookFormat::Paperback); -/// assert!(b1 != BookFormat::Ebook); +/// assert!(BookFormat::Ebook != b1); /// assert!(b1 == b2); /// ``` /// diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs index 08b5ac06f72de..b8d751cfbb6df 100644 --- a/src/libcore/convert.rs +++ b/src/libcore/convert.rs @@ -17,7 +17,10 @@ //! [`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. +//! 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. //! //! # Generic Implementations //! @@ -113,9 +116,6 @@ pub const fn identity(x: T) -> T { x } /// - 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 /// -/// See [the book][book] for a more detailed comparison. -/// -/// [book]: ../../book/first-edition/borrow-and-asref.html /// [`Borrow`]: ../../std/borrow/trait.Borrow.html /// /// **Note: this trait must not fail**. If the conversion can fail, use a @@ -217,7 +217,7 @@ pub trait AsMut { /// /// 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, +/// generic variable, then you can't implement `From` directly. For example, /// take this crate: /// /// ```compile_fail @@ -348,7 +348,7 @@ pub trait Into: Sized { /// [`String`]: ../../std/string/struct.String.html /// [`Into`]: trait.Into.html /// [`from`]: trait.From.html#tymethod.from -/// [book]: ../../book/first-edition/error-handling.html +/// [book]: ../../book/ch09-00-error-handling.html #[stable(feature = "rust1", since = "1.0.0")] pub trait From: Sized { /// Performs the conversion. @@ -463,11 +463,11 @@ impl TryInto for T where U: TryFrom // Infallible conversions are semantically equivalent to fallible conversions // with an uninhabited error type. #[unstable(feature = "try_from", issue = "33417")] -impl TryFrom for T where T: From { +impl TryFrom for T where U: Into { type Error = !; fn try_from(value: U) -> Result { - Ok(T::from(value)) + Ok(U::into(value)) } } diff --git a/src/libcore/default.rs b/src/libcore/default.rs index 0e47c2fd0b5d0..5ad05b3824764 100644 --- a/src/libcore/default.rs +++ b/src/libcore/default.rs @@ -54,7 +54,7 @@ /// /// ## How can I implement `Default`? /// -/// Provide an implementation for the `default()` method that returns the value of +/// Provides an implementation for the `default()` method that returns the value of /// your type that should be the default: /// /// ``` diff --git a/src/libcore/ffi.rs b/src/libcore/ffi.rs index 0717a88b6b8f3..d88793f2801e7 100644 --- a/src/libcore/ffi.rs +++ b/src/libcore/ffi.rs @@ -12,24 +12,27 @@ use ::fmt; /// and `*mut c_void` is equivalent to C's `void*`. That said, this is /// *not* the same as C's `void` return type, which is Rust's `()` type. /// -/// Ideally, this type would be equivalent to [`!`], but currently it may -/// be more ideal to use `c_void` for FFI purposes. +/// To model pointers to opaque types in FFI, until `extern type` is +/// stabilized, it is recommended to use a newtype wrapper around an empty +/// byte array. See the [Nomicon] for details. /// -/// [`!`]: ../../std/primitive.never.html /// [pointer]: ../../std/primitive.pointer.html +/// [Nomicon]: https://doc.rust-lang.org/nomicon/ffi.html#representing-opaque-structs // N.B., for LLVM to recognize the void pointer type and by extension // functions like malloc(), we need to have it represented as i8* in // LLVM bitcode. The enum used here ensures this and prevents misuse -// of the "raw" type by only having private variants.. We need two +// of the "raw" type by only having private variants. We need two // variants, because the compiler complains about the repr attribute -// otherwise. +// otherwise and we need at least one variant as otherwise the enum +// would be uninhabited and at least dereferencing such pointers would +// be UB. #[repr(u8)] #[stable(feature = "raw_os", since = "1.1.0")] pub enum c_void { - #[unstable(feature = "c_void_variant", reason = "should not have to exist", + #[unstable(feature = "c_void_variant", reason = "temporary implementation detail", issue = "0")] #[doc(hidden)] __variant1, - #[unstable(feature = "c_void_variant", reason = "should not have to exist", + #[unstable(feature = "c_void_variant", reason = "temporary implementation detail", issue = "0")] #[doc(hidden)] __variant2, } @@ -49,7 +52,7 @@ impl fmt::Debug for c_void { #[unstable(feature = "c_variadic", reason = "the `c_variadic` feature has not been properly tested on \ all supported platforms", - issue = "27745")] + issue = "44930")] extern { type VaListImpl; } @@ -74,7 +77,7 @@ impl fmt::Debug for VaListImpl { #[unstable(feature = "c_variadic", reason = "the `c_variadic` feature has not been properly tested on \ all supported platforms", - issue = "27745")] + issue = "44930")] struct VaListImpl { stack: *mut (), gr_top: *mut (), @@ -90,7 +93,7 @@ struct VaListImpl { #[unstable(feature = "c_variadic", reason = "the `c_variadic` feature has not been properly tested on \ all supported platforms", - issue = "27745")] + issue = "44930")] struct VaListImpl { gpr: u8, fpr: u8, @@ -106,7 +109,7 @@ struct VaListImpl { #[unstable(feature = "c_variadic", reason = "the `c_variadic` feature has not been properly tested on \ all supported platforms", - issue = "27745")] + issue = "44930")] struct VaListImpl { gp_offset: i32, fp_offset: i32, @@ -120,7 +123,7 @@ struct VaListImpl { #[unstable(feature = "c_variadic", reason = "the `c_variadic` feature has not been properly tested on \ all supported platforms", - issue = "27745")] + issue = "44930")] #[repr(transparent)] pub struct VaList<'a>(&'a mut VaListImpl); @@ -140,7 +143,7 @@ mod sealed_trait { #[unstable(feature = "c_variadic", reason = "the `c_variadic` feature has not been properly tested on \ all supported platforms", - issue = "27745")] + issue = "44930")] pub trait VaArgSafe {} } @@ -150,7 +153,7 @@ macro_rules! impl_va_arg_safe { #[unstable(feature = "c_variadic", reason = "the `c_variadic` feature has not been properly tested on \ all supported platforms", - issue = "27745")] + issue = "44930")] impl sealed_trait::VaArgSafe for $t {} )+ } @@ -163,12 +166,12 @@ impl_va_arg_safe!{f64} #[unstable(feature = "c_variadic", reason = "the `c_variadic` feature has not been properly tested on \ all supported platforms", - issue = "27745")] + issue = "44930")] impl sealed_trait::VaArgSafe for *mut T {} #[unstable(feature = "c_variadic", reason = "the `c_variadic` feature has not been properly tested on \ all supported platforms", - issue = "27745")] + issue = "44930")] impl sealed_trait::VaArgSafe for *const T {} impl<'a> VaList<'a> { @@ -176,16 +179,16 @@ impl<'a> VaList<'a> { #[unstable(feature = "c_variadic", reason = "the `c_variadic` feature has not been properly tested on \ all supported platforms", - issue = "27745")] + issue = "44930")] pub unsafe fn arg(&mut self) -> T { va_arg(self) } - /// Copy the `va_list` at the current location. + /// 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 = "27745")] + 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"), @@ -210,7 +213,7 @@ extern "rust-intrinsic" { /// `va_copy`. fn va_end(ap: &mut VaList); - /// Copy the current location of arglist `src` to the arglist `dst`. + /// 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))] diff --git a/src/libcore/fmt/builders.rs b/src/libcore/fmt/builders.rs index 2525b47f2bde5..45994c2b4f0f0 100644 --- a/src/libcore/fmt/builders.rs +++ b/src/libcore/fmt/builders.rs @@ -71,8 +71,10 @@ impl fmt::Write for PadAdapter<'_> { /// } /// } /// -/// // prints "Foo { bar: 10, baz: "Hello World" }" -/// println!("{:?}", Foo { bar: 10, baz: "Hello World".to_string() }); +/// assert_eq!( +/// format!("{:?}", Foo { bar: 10, baz: "Hello World".to_string() }), +/// "Foo { bar: 10, baz: \"Hello World\" }", +/// ); /// ``` #[must_use = "must eventually call `finish()` on Debug builders"] #[allow(missing_debug_implementations)] @@ -96,6 +98,33 @@ pub fn debug_struct_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>, impl<'a, 'b: 'a> DebugStruct<'a, 'b> { /// Adds a new field to the generated struct output. + /// + /// # Examples + /// + /// ``` + /// use std::fmt; + /// + /// struct Bar { + /// bar: i32, + /// another: String, + /// } + /// + /// impl fmt::Debug for Bar { + /// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + /// fmt.debug_struct("Bar") + /// .field("bar", &self.bar) // We add `bar` field. + /// .field("another", &self.another) // We add `another` field. + /// // We even add a field which doesn't exist (because why not?). + /// .field("not_existing_field", &1) + /// .finish() // We're good to go! + /// } + /// } + /// + /// assert_eq!( + /// format!("{:?}", Bar { bar: 10, another: "Hello World".to_string() }), + /// "Bar { bar: 10, another: \"Hello World\", not_existing_field: 1 }", + /// ); + /// ``` #[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(|_| { @@ -124,6 +153,32 @@ impl<'a, 'b: 'a> DebugStruct<'a, 'b> { } /// Finishes output and returns any error encountered. + /// + /// # Examples + /// + /// ``` + /// use std::fmt; + /// + /// struct Bar { + /// bar: i32, + /// baz: String, + /// } + /// + /// impl fmt::Debug for Bar { + /// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + /// fmt.debug_struct("Bar") + /// .field("bar", &self.bar) + /// .field("baz", &self.baz) + /// .finish() // You need to call it to "finish" the + /// // struct formatting. + /// } + /// } + /// + /// assert_eq!( + /// format!("{:?}", Bar { bar: 10, baz: "Hello World".to_string() }), + /// "Bar { bar: 10, baz: \"Hello World\" }", + /// ); + /// ``` #[stable(feature = "debug_builders", since = "1.2.0")] pub fn finish(&mut self) -> fmt::Result { if self.has_fields { @@ -168,8 +223,10 @@ impl<'a, 'b: 'a> DebugStruct<'a, 'b> { /// } /// } /// -/// // prints "Foo(10, "Hello World")" -/// println!("{:?}", Foo(10, "Hello World".to_string())); +/// assert_eq!( +/// format!("{:?}", Foo(10, "Hello World".to_string())), +/// "Foo(10, \"Hello World\")", +/// ); /// ``` #[must_use = "must eventually call `finish()` on Debug builders"] #[allow(missing_debug_implementations)] @@ -193,6 +250,28 @@ pub fn debug_tuple_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>, name: &str) -> D impl<'a, 'b: 'a> DebugTuple<'a, 'b> { /// Adds a new field to the generated tuple struct output. + /// + /// # Examples + /// + /// ``` + /// use std::fmt; + /// + /// struct Foo(i32, String); + /// + /// impl fmt::Debug for Foo { + /// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + /// fmt.debug_tuple("Foo") + /// .field(&self.0) // We add the first field. + /// .field(&self.1) // We add the second field. + /// .finish() // We're good to go! + /// } + /// } + /// + /// assert_eq!( + /// format!("{:?}", Foo(10, "Hello World".to_string())), + /// "Foo(10, \"Hello World\")", + /// ); + /// ``` #[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(|_| { @@ -220,6 +299,29 @@ impl<'a, 'b: 'a> DebugTuple<'a, 'b> { } /// Finishes output and returns any error encountered. + /// + /// # Examples + /// + /// ``` + /// use std::fmt; + /// + /// struct Foo(i32, String); + /// + /// impl fmt::Debug for Foo { + /// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + /// fmt.debug_tuple("Foo") + /// .field(&self.0) + /// .field(&self.1) + /// .finish() // You need to call it to "finish" the + /// // tuple formatting. + /// } + /// } + /// + /// assert_eq!( + /// format!("{:?}", Foo(10, "Hello World".to_string())), + /// "Foo(10, \"Hello World\")", + /// ); + /// ``` #[stable(feature = "debug_builders", since = "1.2.0")] pub fn finish(&mut self) -> fmt::Result { if self.fields > 0 { @@ -306,8 +408,10 @@ impl<'a, 'b: 'a> DebugInner<'a, 'b> { /// } /// } /// -/// // prints "{10, 11}" -/// println!("{:?}", Foo(vec![10, 11])); +/// assert_eq!( +/// format!("{:?}", Foo(vec![10, 11])), +/// "{10, 11}", +/// ); /// ``` #[must_use = "must eventually call `finish()` on Debug builders"] #[allow(missing_debug_implementations)] @@ -329,6 +433,28 @@ pub fn debug_set_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>) -> DebugSet<'a, 'b impl<'a, 'b: 'a> DebugSet<'a, 'b> { /// Adds a new entry to the set output. + /// + /// # Examples + /// + /// ``` + /// use std::fmt; + /// + /// struct Foo(Vec, Vec); + /// + /// impl fmt::Debug for Foo { + /// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + /// fmt.debug_set() + /// .entry(&self.0) // Adds the first "entry". + /// .entry(&self.1) // Adds the second "entry". + /// .finish() + /// } + /// } + /// + /// assert_eq!( + /// format!("{:?}", Foo(vec![10, 11], vec![12, 13])), + /// "{[10, 11], [12, 13]}", + /// ); + /// ``` #[stable(feature = "debug_builders", since = "1.2.0")] pub fn entry(&mut self, entry: &dyn fmt::Debug) -> &mut DebugSet<'a, 'b> { self.inner.entry(entry); @@ -336,6 +462,28 @@ impl<'a, 'b: 'a> DebugSet<'a, 'b> { } /// Adds the contents of an iterator of entries to the set output. + /// + /// # Examples + /// + /// ``` + /// use std::fmt; + /// + /// struct Foo(Vec, Vec); + /// + /// impl fmt::Debug for Foo { + /// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + /// fmt.debug_set() + /// .entries(self.0.iter()) // Adds the first "entry". + /// .entries(self.1.iter()) // Adds the second "entry". + /// .finish() + /// } + /// } + /// + /// assert_eq!( + /// format!("{:?}", Foo(vec![10, 11], vec![12, 13])), + /// "{10, 11, 12, 13}", + /// ); + /// ``` #[stable(feature = "debug_builders", since = "1.2.0")] pub fn entries(&mut self, entries: I) -> &mut DebugSet<'a, 'b> where D: fmt::Debug, @@ -348,6 +496,27 @@ impl<'a, 'b: 'a> DebugSet<'a, 'b> { } /// Finishes output and returns any error encountered. + /// + /// # Examples + /// + /// ``` + /// use std::fmt; + /// + /// struct Foo(Vec); + /// + /// impl fmt::Debug for Foo { + /// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + /// fmt.debug_set() + /// .entries(self.0.iter()) + /// .finish() // Ends the struct formatting. + /// } + /// } + /// + /// assert_eq!( + /// format!("{:?}", Foo(vec![10, 11])), + /// "{10, 11}", + /// ); + /// ``` #[stable(feature = "debug_builders", since = "1.2.0")] pub fn finish(&mut self) -> fmt::Result { self.inner.finish(); @@ -377,8 +546,10 @@ impl<'a, 'b: 'a> DebugSet<'a, 'b> { /// } /// } /// -/// // prints "[10, 11]" -/// println!("{:?}", Foo(vec![10, 11])); +/// assert_eq!( +/// format!("{:?}", Foo(vec![10, 11])), +/// "[10, 11]", +/// ); /// ``` #[must_use = "must eventually call `finish()` on Debug builders"] #[allow(missing_debug_implementations)] @@ -400,6 +571,28 @@ pub fn debug_list_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>) -> DebugList<'a, impl<'a, 'b: 'a> DebugList<'a, 'b> { /// Adds a new entry to the list output. + /// + /// # Examples + /// + /// ``` + /// use std::fmt; + /// + /// struct Foo(Vec, Vec); + /// + /// impl fmt::Debug for Foo { + /// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + /// fmt.debug_list() + /// .entry(&self.0) // We add the first "entry". + /// .entry(&self.1) // We add the second "entry". + /// .finish() + /// } + /// } + /// + /// assert_eq!( + /// format!("{:?}", Foo(vec![10, 11], vec![12, 13])), + /// "[[10, 11], [12, 13]]", + /// ); + /// ``` #[stable(feature = "debug_builders", since = "1.2.0")] pub fn entry(&mut self, entry: &dyn fmt::Debug) -> &mut DebugList<'a, 'b> { self.inner.entry(entry); @@ -407,6 +600,28 @@ impl<'a, 'b: 'a> DebugList<'a, 'b> { } /// Adds the contents of an iterator of entries to the list output. + /// + /// # Examples + /// + /// ``` + /// use std::fmt; + /// + /// struct Foo(Vec, Vec); + /// + /// impl fmt::Debug for Foo { + /// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + /// fmt.debug_list() + /// .entries(self.0.iter()) + /// .entries(self.1.iter()) + /// .finish() + /// } + /// } + /// + /// assert_eq!( + /// format!("{:?}", Foo(vec![10, 11], vec![12, 13])), + /// "[10, 11, 12, 13]", + /// ); + /// ``` #[stable(feature = "debug_builders", since = "1.2.0")] pub fn entries(&mut self, entries: I) -> &mut DebugList<'a, 'b> where D: fmt::Debug, @@ -419,6 +634,27 @@ impl<'a, 'b: 'a> DebugList<'a, 'b> { } /// Finishes output and returns any error encountered. + /// + /// # Examples + /// + /// ``` + /// use std::fmt; + /// + /// struct Foo(Vec); + /// + /// impl fmt::Debug for Foo { + /// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + /// fmt.debug_list() + /// .entries(self.0.iter()) + /// .finish() // Ends the struct formatting. + /// } + /// } + /// + /// assert_eq!( + /// format!("{:?}", Foo(vec![10, 11])), + /// "[10, 11]", + /// ); + /// ``` #[stable(feature = "debug_builders", since = "1.2.0")] pub fn finish(&mut self) -> fmt::Result { self.inner.finish(); @@ -448,8 +684,10 @@ impl<'a, 'b: 'a> DebugList<'a, 'b> { /// } /// } /// -/// // prints "{"A": 10, "B": 11}" -/// println!("{:?}", Foo(vec![("A".to_string(), 10), ("B".to_string(), 11)])); +/// assert_eq!( +/// format!("{:?}", Foo(vec![("A".to_string(), 10), ("B".to_string(), 11)])), +/// "{\"A\": 10, \"B\": 11}", +/// ); /// ``` #[must_use = "must eventually call `finish()` on Debug builders"] #[allow(missing_debug_implementations)] @@ -471,6 +709,27 @@ pub fn debug_map_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>) -> DebugMap<'a, 'b impl<'a, 'b: 'a> DebugMap<'a, 'b> { /// Adds a new entry to the map output. + /// + /// # Examples + /// + /// ``` + /// use std::fmt; + /// + /// struct Foo(Vec<(String, i32)>); + /// + /// impl fmt::Debug for Foo { + /// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + /// fmt.debug_map() + /// .entry(&"whole", &self.0) // We add the "whole" entry. + /// .finish() + /// } + /// } + /// + /// assert_eq!( + /// format!("{:?}", Foo(vec![("A".to_string(), 10), ("B".to_string(), 11)])), + /// "{\"whole\": [(\"A\", 10), (\"B\", 11)]}", + /// ); + /// ``` #[stable(feature = "debug_builders", since = "1.2.0")] pub fn entry(&mut self, key: &dyn fmt::Debug, value: &dyn fmt::Debug) -> &mut DebugMap<'a, 'b> { self.result = self.result.and_then(|_| { @@ -500,6 +759,29 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> { } /// Adds the contents of an iterator of entries to the map output. + /// + /// # Examples + /// + /// ``` + /// use std::fmt; + /// + /// struct Foo(Vec<(String, i32)>); + /// + /// impl fmt::Debug for Foo { + /// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + /// fmt.debug_map() + /// // We map our vec so each entries' first field will become + /// // the "key". + /// .entries(self.0.iter().map(|&(ref k, ref v)| (k, v))) + /// .finish() + /// } + /// } + /// + /// assert_eq!( + /// format!("{:?}", Foo(vec![("A".to_string(), 10), ("B".to_string(), 11)])), + /// "{\"A\": 10, \"B\": 11}", + /// ); + /// ``` #[stable(feature = "debug_builders", since = "1.2.0")] pub fn entries(&mut self, entries: I) -> &mut DebugMap<'a, 'b> where K: fmt::Debug, @@ -513,6 +795,27 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> { } /// Finishes output and returns any error encountered. + /// + /// # Examples + /// + /// ``` + /// use std::fmt; + /// + /// struct Foo(Vec<(String, i32)>); + /// + /// impl fmt::Debug for Foo { + /// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + /// fmt.debug_map() + /// .entries(self.0.iter().map(|&(ref k, ref v)| (k, v))) + /// .finish() // Ends the struct formatting. + /// } + /// } + /// + /// assert_eq!( + /// format!("{:?}", Foo(vec![("A".to_string(), 10), ("B".to_string(), 11)])), + /// "{\"A\": 10, \"B\": 11}", + /// ); + /// ``` #[stable(feature = "debug_builders", since = "1.2.0")] pub fn finish(&mut self) -> fmt::Result { let prefix = if self.is_pretty() && self.has_fields { diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 214b5d3a84f24..7efb7f31298bf 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -211,9 +211,18 @@ impl Write for &mut W { } } -/// A struct to represent both where to emit formatting strings to and how they -/// should be formatted. A mutable version of this is passed to all formatting -/// traits. +/// Configuration for formatting. +/// +/// A `Formatter` represents various options related to formatting. Users do not +/// construct `Formatter`s directly; a mutable reference to one is passed to +/// the `fmt` method of all formatting traits, like [`Debug`] and [`Display`]. +/// +/// To interact with a `Formatter`, you'll call various methods to change the +/// various options related to formatting. For examples, please see the +/// documentation of the methods defined on `Formatter` below. +/// +/// [`Debug`]: trait.Debug.html +/// [`Display`]: trait.Display.html #[allow(missing_debug_implementations)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Formatter<'a> { @@ -474,12 +483,12 @@ impl Display for Arguments<'_> { /// implementations, such as [`debug_struct`][debug_struct]. /// /// `Debug` implementations using either `derive` or the debug builder API -/// on [`Formatter`] support pretty printing using the alternate flag: `{:#?}`. +/// on [`Formatter`] support pretty-printing using the alternate flag: `{:#?}`. /// /// [debug_struct]: ../../std/fmt/struct.Formatter.html#method.debug_struct /// [`Formatter`]: ../../std/fmt/struct.Formatter.html /// -/// Pretty printing with `#?`: +/// Pretty-printing with `#?`: /// /// ``` /// #[derive(Debug)] @@ -997,34 +1006,57 @@ pub fn write(output: &mut dyn Write, args: Arguments) -> Result { curarg: args.args.iter(), }; - let mut pieces = args.pieces.iter(); + let mut idx = 0; match args.fmt { None => { // We can use default formatting parameters for all arguments. - for (arg, piece) in args.args.iter().zip(pieces.by_ref()) { + for (arg, piece) in args.args.iter().zip(args.pieces.iter()) { formatter.buf.write_str(*piece)?; (arg.formatter)(arg.value, &mut formatter)?; + idx += 1; } } Some(fmt) => { // Every spec has a corresponding argument that is preceded by // a string piece. - for (arg, piece) in fmt.iter().zip(pieces.by_ref()) { + for (arg, piece) in fmt.iter().zip(args.pieces.iter()) { formatter.buf.write_str(*piece)?; formatter.run(arg)?; + idx += 1; } } } // There can be only one trailing string piece left. - if let Some(piece) = pieces.next() { + if let Some(piece) = args.pieces.get(idx) { formatter.buf.write_str(*piece)?; } Ok(()) } +/// Padding after the end of something. Returned by `Formatter::padding`. +#[must_use = "don't forget to write the post padding"] +struct PostPadding { + fill: char, + padding: usize, +} + +impl PostPadding { + fn new(fill: char, padding: usize) -> PostPadding { + PostPadding { fill, padding } + } + + /// Write this post padding. + fn write(self, buf: &mut dyn Write) -> Result { + for _ in 0..self.padding { + buf.write_char(self.fill)?; + } + Ok(()) + } +} + impl<'a> Formatter<'a> { fn wrap_buf<'b, 'c, F>(&'b mut self, wrap: F) -> Formatter<'c> where 'b: 'c, F: FnOnce(&'b mut (dyn Write+'b)) -> &'c mut (dyn Write+'c) @@ -1142,47 +1174,56 @@ impl<'a> Formatter<'a> { sign = Some('+'); width += 1; } - let prefixed = self.alternate(); - if prefixed { + let prefix = if self.alternate() { width += prefix.chars().count(); - } + Some(prefix) + } else { + None + }; // Writes the sign if it exists, and then the prefix if it was requested - let write_prefix = |f: &mut Formatter| { + #[inline(never)] + fn write_prefix(f: &mut Formatter, sign: Option, prefix: Option<&str>) -> Result { if let Some(c) = sign { f.buf.write_char(c)?; } - if prefixed { f.buf.write_str(prefix) } - else { Ok(()) } - }; + if let Some(prefix) = prefix { + f.buf.write_str(prefix) + } else { + Ok(()) + } + } // The `width` field is more of a `min-width` parameter at this point. match self.width { // If there's no minimum length requirements then we can just // write the bytes. None => { - write_prefix(self)?; self.buf.write_str(buf) + write_prefix(self, sign, prefix)?; + self.buf.write_str(buf) } // Check if we're over the minimum width, if so then we can also // just write the bytes. Some(min) if width >= min => { - write_prefix(self)?; self.buf.write_str(buf) + write_prefix(self, sign, prefix)?; + self.buf.write_str(buf) } // The sign and prefix goes before the padding if the fill character // is zero Some(min) if self.sign_aware_zero_pad() => { self.fill = '0'; self.align = rt::v1::Alignment::Right; - write_prefix(self)?; - self.with_padding(min - width, rt::v1::Alignment::Right, |f| { - f.buf.write_str(buf) - }) + write_prefix(self, sign, prefix)?; + let post_padding = self.padding(min - width, rt::v1::Alignment::Right)?; + self.buf.write_str(buf)?; + post_padding.write(self.buf) } // Otherwise, the sign and prefix goes after the padding Some(min) => { - self.with_padding(min - width, rt::v1::Alignment::Right, |f| { - write_prefix(f)?; f.buf.write_str(buf) - }) + let post_padding = self.padding(min - width, rt::v1::Alignment::Right)?; + write_prefix(self, sign, prefix)?; + self.buf.write_str(buf)?; + post_padding.write(self.buf) } } } @@ -1253,19 +1294,21 @@ impl<'a> Formatter<'a> { // up the minimum width with the specified string + some alignment. Some(width) => { let align = rt::v1::Alignment::Left; - self.with_padding(width - s.chars().count(), align, |me| { - me.buf.write_str(s) - }) + let post_padding = self.padding(width - s.chars().count(), align)?; + self.buf.write_str(s)?; + post_padding.write(self.buf) } } } - /// Runs a callback, emitting the correct padding either before or - /// afterwards depending on whether right or left alignment is requested. - fn with_padding(&mut self, padding: usize, default: rt::v1::Alignment, - f: F) -> Result - where F: FnOnce(&mut Formatter) -> Result, - { + /// Write the pre-padding and return the unwritten post-padding. Callers are + /// responsible for ensuring post-padding is written after the thing that is + /// being padded. + fn padding( + &mut self, + padding: usize, + default: rt::v1::Alignment + ) -> result::Result { let align = match self.align { rt::v1::Alignment::Unknown => default, _ => self.align @@ -1278,20 +1321,11 @@ impl<'a> Formatter<'a> { rt::v1::Alignment::Center => (padding / 2, (padding + 1) / 2), }; - let mut fill = [0; 4]; - let fill = self.fill.encode_utf8(&mut fill); - for _ in 0..pre_pad { - self.buf.write_str(fill)?; - } - - f(self)?; - - for _ in 0..post_pad { - self.buf.write_str(fill)?; + self.buf.write_char(self.fill)?; } - Ok(()) + Ok(PostPadding::new(self.fill, post_pad)) } /// Takes the formatted parts and applies the padding. @@ -1323,9 +1357,9 @@ impl<'a> Formatter<'a> { let ret = if width <= len { // no padding self.write_formatted_parts(&formatted) } else { - self.with_padding(width - len, align, |f| { - f.write_formatted_parts(&formatted) - }) + let post_padding = self.padding(width - len, align)?; + self.write_formatted_parts(&formatted)?; + post_padding.write(self.buf) }; self.fill = old_fill; self.align = old_align; @@ -2037,7 +2071,7 @@ macro_rules! tuple { ( $($name:ident,)+ ) => ( #[stable(feature = "rust1", since = "1.0.0")] impl<$($name:Debug),*> Debug for ($($name,)*) where last_type!($($name,)+): ?Sized { - #[allow(non_snake_case, unused_assignments, deprecated)] + #[allow(non_snake_case, unused_assignments)] fn fmt(&self, f: &mut Formatter) -> Result { let mut builder = f.debug_tuple(""); let ($(ref $name,)*) = *self; diff --git a/src/libcore/fmt/num.rs b/src/libcore/fmt/num.rs index c7c8fc50efaae..b9fa364037108 100644 --- a/src/libcore/fmt/num.rs +++ b/src/libcore/fmt/num.rs @@ -1,14 +1,12 @@ //! Integer and floating-point number formatting -#![allow(deprecated)] - use fmt; use ops::{Div, Rem, Sub}; use str; use slice; use ptr; -use mem; +use mem::MaybeUninit; #[doc(hidden)] trait Int: PartialEq + PartialOrd + Div + Rem + @@ -53,7 +51,7 @@ trait GenericRadix { // characters for a base 2 number. let zero = T::zero(); let is_nonnegative = x >= zero; - let mut buf: [u8; 128] = unsafe { mem::uninitialized() }; + let mut buf = uninitialized_array![u8; 128]; let mut curr = buf.len(); let base = T::from_u8(Self::BASE); if is_nonnegative { @@ -62,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 = Self::digit(n.to_u8()); // Store the digit in the buffer. + byte.set(Self::digit(n.to_u8())); // Store the digit in the buffer. curr -= 1; if x == zero { // No more digits left to accumulate. @@ -74,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 = Self::digit(n.to_u8()); // Store the digit in the buffer. + byte.set(Self::digit(n.to_u8())); // Store the digit in the buffer. curr -= 1; if x == zero { // No more digits left to accumulate. @@ -82,7 +80,11 @@ trait GenericRadix { }; } } - let buf = unsafe { str::from_utf8_unchecked(&buf[curr..]) }; + let buf = &buf[curr..]; + let buf = unsafe { str::from_utf8_unchecked(slice::from_raw_parts( + MaybeUninit::first_ptr(buf), + buf.len() + )) }; f.pad_integral(is_nonnegative, Self::PREFIX, buf) } } @@ -176,7 +178,8 @@ integer! { i32, u32 } integer! { i64, u64 } integer! { i128, u128 } -const DEC_DIGITS_LUT: &'static[u8] = + +static DEC_DIGITS_LUT: &[u8; 200] = b"0001020304050607080910111213141516171819\ 2021222324252627282930313233343536373839\ 4041424344454647484950515253545556575859\ @@ -184,37 +187,27 @@ const DEC_DIGITS_LUT: &'static[u8] = 8081828384858687888990919293949596979899"; macro_rules! impl_Display { - ($($t:ident),*: $conv_fn:ident) => ($( - #[stable(feature = "rust1", since = "1.0.0")] - impl fmt::Display for $t { - #[allow(unused_comparisons)] - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let is_nonnegative = *self >= 0; - let mut n = if is_nonnegative { - self.$conv_fn() - } else { - // convert the negative num to positive by summing 1 to it's 2 complement - (!self.$conv_fn()).wrapping_add(1) - }; - let mut buf: [u8; 39] = unsafe { mem::uninitialized() }; + ($($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 { + let mut buf = uninitialized_array![u8; 39]; let mut curr = buf.len() as isize; - let buf_ptr = buf.as_mut_ptr(); + let buf_ptr = MaybeUninit::first_ptr_mut(&mut buf); let lut_ptr = DEC_DIGITS_LUT.as_ptr(); unsafe { // need at least 16 bits for the 4-characters-at-a-time to work. - if ::mem::size_of::<$t>() >= 2 { - // eagerly decode 4 characters at a time - while n >= 10000 { - let rem = (n % 10000) as isize; - n /= 10000; - - let d1 = (rem / 100) << 1; - let d2 = (rem % 100) << 1; - curr -= 4; - ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2); - ptr::copy_nonoverlapping(lut_ptr.offset(d2), buf_ptr.offset(curr + 2), 2); - } + assert!(::mem::size_of::<$u>() >= 2); + + // eagerly decode 4 characters at a time + while n >= 10000 { + let rem = (n % 10000) as isize; + n /= 10000; + + let d1 = (rem / 100) << 1; + let d2 = (rem % 100) << 1; + curr -= 4; + ptr::copy_nonoverlapping(lut_ptr.offset(d1), buf_ptr.offset(curr), 2); + ptr::copy_nonoverlapping(lut_ptr.offset(d2), buf_ptr.offset(curr + 2), 2); } // if we reach here numbers are <= 9999, so at most 4 chars long @@ -245,15 +238,41 @@ macro_rules! impl_Display { }; f.pad_integral(is_nonnegative, "", buf_slice) } - })*); + + $( + #[stable(feature = "rust1", since = "1.0.0")] + impl fmt::Display for $t { + #[allow(unused_comparisons)] + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let is_nonnegative = *self >= 0; + let n = if is_nonnegative { + self.$conv_fn() + } else { + // convert the negative num to positive by summing 1 to it's 2 complement + (!self.$conv_fn()).wrapping_add(1) + }; + $name(n, is_nonnegative, f) + } + })* + }; +} + +// Include wasm32 in here since it doesn't reflect the native pointer size, and +// often cares strongly about getting a smaller code size. +#[cfg(any(target_pointer_width = "64", target_arch = "wasm32"))] +mod imp { + use super::*; + impl_Display!( + i8, u8, i16, u16, i32, u32, i64, u64, usize, isize + as u64 via to_u64 named fmt_u64 + ); +} + +#[cfg(not(any(target_pointer_width = "64", target_arch = "wasm32")))] +mod imp { + use super::*; + impl_Display!(i8, u8, i16, u16, i32, u32, isize, usize as u32 via to_u32 named fmt_u32); + impl_Display!(i64, u64 as u64 via to_u64 named fmt_u64); } -impl_Display!(i8, u8, i16, u16, i32, u32: to_u32); -impl_Display!(i64, u64: to_u64); -impl_Display!(i128, u128: to_u128); -#[cfg(target_pointer_width = "16")] -impl_Display!(isize, usize: to_u16); -#[cfg(target_pointer_width = "32")] -impl_Display!(isize, usize: to_u32); -#[cfg(target_pointer_width = "64")] -impl_Display!(isize, usize: to_u64); +impl_Display!(i128, u128 as u128 via to_u128 named fmt_u128); diff --git a/src/libcore/future/future.rs b/src/libcore/future/future.rs index 539b07fc21eea..a143b54a61f54 100644 --- a/src/libcore/future/future.rs +++ b/src/libcore/future/future.rs @@ -5,7 +5,7 @@ use marker::Unpin; use ops; use pin::Pin; -use task::{Poll, LocalWaker}; +use task::{Poll, Waker}; /// A future represents an asynchronous computation. /// @@ -19,13 +19,15 @@ use task::{Poll, LocalWaker}; /// 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 -/// `cx.waker()`, a handle for waking up the current task. +/// the `waker` argument of the `poll()` method, 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. +#[doc(spotlight)] #[must_use = "futures do nothing unless polled"] pub trait Future { - /// The result of the `Future`. + /// The type of value produced on completion. type Output; /// Attempt to resolve the future to a final value, registering @@ -42,16 +44,16 @@ 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 [`LocalWaker`] to be woken once the future can + /// 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 - /// readable would call `.clone()` on the [`LocalWaker`] and store it. + /// readable would call `.clone()` on the [`Waker`] and store it. /// When a signal arrives elsewhere indicating that the socket is readable, - /// `[LocalWaker::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 - /// [`LocalWaker`] passed to `poll` should be scheduled to receive a + /// [`Waker`] passed to `poll` should be scheduled to receive a /// wakeup. /// /// # Runtime characteristics @@ -60,51 +62,42 @@ pub trait Future { /// progress, meaning that each time the current task is woken up, it should /// actively re-`poll` pending futures that it still has an interest in. /// - /// The `poll` function is not called repeatedly in a tight loop-- instead, + /// The `poll` function is not called repeatedly in a tight loop -- instead, /// it should only be called when the future indicates that it is ready to /// make progress (by calling `wake()`). If you're familiar with the /// `poll(2)` or `select(2)` syscalls on Unix it's worth noting that futures /// typically do *not* suffer the same problems of "all wakeups must poll /// all events"; they are more like `epoll(4)`. /// - /// An implementation of `poll` should strive to return quickly, and must - /// *never* block. Returning quickly prevents unnecessarily clogging up + /// An implementation of `poll` should strive to return quickly, and should + /// not block. Returning quickly prevents unnecessarily clogging up /// threads or event loops. If it is known ahead of time that a call to /// `poll` may end up taking awhile, the work should be offloaded to a /// thread pool (or something similar) to ensure that `poll` can return /// quickly. /// - /// # [`LocalWaker`], [`Waker`] and thread-safety - /// - /// The `poll` function takes a [`LocalWaker`], an object which knows how to - /// awaken the current task. [`LocalWaker`] is not `Send` nor `Sync`, so in - /// order to make thread-safe futures the [`LocalWaker::into_waker`] method - /// should be used to convert the [`LocalWaker`] into a thread-safe version. - /// [`LocalWaker::wake`] implementations have the ability to be more - /// efficient, however, so when thread safety is not necessary, - /// [`LocalWaker`] should be preferred. + /// 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 bad behavior. The `Future` trait itself provides no guarantees - /// about the behavior of `poll` after a future has completed. + /// 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. /// /// [`Poll::Pending`]: ../task/enum.Poll.html#variant.Pending /// [`Poll::Ready(val)`]: ../task/enum.Poll.html#variant.Ready - /// [`LocalWaker`]: ../task/struct.LocalWaker.html - /// [`LocalWaker::into_waker`]: ../task/struct.LocalWaker.html#method.into_waker - /// [`LocalWaker::wake`]: ../task/struct.LocalWaker.html#method.wake /// [`Waker`]: ../task/struct.Waker.html - fn poll(self: Pin<&mut Self>, lw: &LocalWaker) -> Poll; + /// [`Waker::wake`]: ../task/struct.Waker.html#method.wake + fn poll(self: Pin<&mut Self>, waker: &Waker) -> Poll; } -impl<'a, F: ?Sized + Future + Unpin> Future for &'a mut F { +impl Future for &mut F { type Output = F::Output; - fn poll(mut self: Pin<&mut Self>, lw: &LocalWaker) -> Poll { - F::poll(Pin::new(&mut **self), lw) + fn poll(mut self: Pin<&mut Self>, waker: &Waker) -> Poll { + F::poll(Pin::new(&mut **self), waker) } } @@ -115,7 +108,7 @@ where { type Output = <

::Target as Future>::Output; - fn poll(self: Pin<&mut Self>, lw: &LocalWaker) -> Poll { - Pin::get_mut(self).as_mut().poll(lw) + fn poll(self: Pin<&mut Self>, waker: &Waker) -> Poll { + Pin::get_mut(self).as_mut().poll(waker) } } diff --git a/src/libcore/hash/sip.rs b/src/libcore/hash/sip.rs index 3377b831a9daa..235c79307ab8d 100644 --- a/src/libcore/hash/sip.rs +++ b/src/libcore/hash/sip.rs @@ -1,6 +1,6 @@ //! An implementation of SipHash. -#![allow(deprecated)] +#![allow(deprecated)] // the types in this module are deprecated use marker::PhantomData; use ptr; @@ -10,7 +10,7 @@ use mem; /// An implementation of SipHash 1-3. /// /// This is currently the default hashing function used by standard library -/// (eg. `collections::HashMap` uses it by default). +/// (e.g., `collections::HashMap` uses it by default). /// /// See: #[unstable(feature = "hashmap_internals", issue = "0")] @@ -90,7 +90,7 @@ macro_rules! compress { }); } -/// Load an integer of the desired type from a byte stream, in LE order. Uses +/// Loads an integer of the desired type from a byte stream, in LE order. Uses /// `copy_nonoverlapping` to let the compiler generate the most efficient way /// to load it from a possibly unaligned address. /// @@ -107,7 +107,7 @@ macro_rules! load_int_le { }); } -/// Load an u64 using up to 7 bytes of a byte slice. +/// Loads an u64 using up to 7 bytes of a byte slice. /// /// Unsafe because: unchecked indexing at start..start+len #[inline] diff --git a/src/libcore/hint.rs b/src/libcore/hint.rs index 9e57a4ebc9919..89de5c1bc8af8 100644 --- a/src/libcore/hint.rs +++ b/src/libcore/hint.rs @@ -34,7 +34,7 @@ use intrinsics; /// use std::hint::unreachable_unchecked; /// /// // `b.saturating_add(1)` is always positive (not zero), -/// // hence `checked_div` will never return None. +/// // hence `checked_div` will never return `None`. /// // Therefore, the else branch is unreachable. /// a.checked_div(b.saturating_add(1)) /// .unwrap_or_else(|| unsafe { unreachable_unchecked() }) @@ -49,3 +49,26 @@ use intrinsics; pub unsafe fn unreachable_unchecked() -> ! { intrinsics::unreachable() } + +/// Save power or switch hyperthreads in 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. +/// +/// On some platforms this function may not do anything at all. +#[inline] +#[unstable(feature = "renamed_spin_loop", issue = "55002")] +pub fn spin_loop() { + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + unsafe { + asm!("pause" ::: "memory" : "volatile"); + } + + #[cfg(target_arch = "aarch64")] + unsafe { + asm!("yield" ::: "memory" : "volatile"); + } +} diff --git a/src/libcore/internal_macros.rs b/src/libcore/internal_macros.rs index d12800f712483..faca785e488c3 100644 --- a/src/libcore/internal_macros.rs +++ b/src/libcore/internal_macros.rs @@ -7,7 +7,7 @@ macro_rules! forward_ref_unop { }; (impl $imp:ident, $method:ident for $t:ty, #[$attr:meta]) => { #[$attr] - impl<'a> $imp for &'a $t { + impl $imp for &$t { type Output = <$t as $imp>::Output; #[inline] @@ -75,3 +75,47 @@ macro_rules! forward_ref_op_assign { } } } + +/// Create a zero-size type similar to a closure type, but named. +#[unstable(feature = "std_internals", issue = "0")] +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 = + |$( $arg: ident: $ArgTy: ty ),*| -> $ReturnTy: ty + $body: block; + )+) => { + $( + $( #[$attr] )* + struct $Name; + + impl $( <$( $lifetime ),+> )* Fn<($( $ArgTy, )*)> for $Name { + #[inline] + extern "rust-call" fn call(&self, ($( $arg, )*): ($( $ArgTy, )*)) -> $ReturnTy { + $body + } + } + + impl $( <$( $lifetime ),+> )* FnMut<($( $ArgTy, )*)> for $Name { + #[inline] + extern "rust-call" fn call_mut( + &mut self, + ($( $arg, )*): ($( $ArgTy, )*) + ) -> $ReturnTy { + Fn::call(&*self, ($( $arg, )*)) + } + } + + impl $( <$( $lifetime ),+> )* FnOnce<($( $ArgTy, )*)> for $Name { + type Output = $ReturnTy; + + #[inline] + extern "rust-call" fn call_once(self, ($( $arg, )*): ($( $ArgTy, )*)) -> $ReturnTy { + Fn::call(&self, ($( $arg, )*)) + } + } + )+ + } +} diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index db19baf7a2c64..e6098b1b24cc0 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1,6 +1,6 @@ -//! rustc compiler intrinsics. +//! Compiler intrinsics. //! -//! The corresponding definitions are in librustc_codegen_llvm/intrinsic.rs. +//! The corresponding definitions are in `librustc_codegen_llvm/intrinsic.rs`. //! //! # Volatiles //! @@ -315,35 +315,35 @@ extern "rust-intrinsic" { /// [`AtomicBool::swap`](../../std/sync/atomic/struct.AtomicBool.html#method.swap). pub fn atomic_xchg_relaxed(dst: *mut T, src: T) -> T; - /// Add to the current value, returning the previous value. + /// Adds to the current value, returning the previous value. /// The stabilized version of this intrinsic is available on the /// `std::sync::atomic` types via the `fetch_add` method by passing /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html) /// as the `order`. For example, /// [`AtomicIsize::fetch_add`](../../std/sync/atomic/struct.AtomicIsize.html#method.fetch_add). pub fn atomic_xadd(dst: *mut T, src: T) -> T; - /// Add to the current value, returning the previous value. + /// Adds to the current value, returning the previous value. /// The stabilized version of this intrinsic is available on the /// `std::sync::atomic` types via the `fetch_add` method by passing /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) /// as the `order`. For example, /// [`AtomicIsize::fetch_add`](../../std/sync/atomic/struct.AtomicIsize.html#method.fetch_add). pub fn atomic_xadd_acq(dst: *mut T, src: T) -> T; - /// Add to the current value, returning the previous value. + /// Adds to the current value, returning the previous value. /// The stabilized version of this intrinsic is available on the /// `std::sync::atomic` types via the `fetch_add` method by passing /// [`Ordering::Release`](../../std/sync/atomic/enum.Ordering.html) /// as the `order`. For example, /// [`AtomicIsize::fetch_add`](../../std/sync/atomic/struct.AtomicIsize.html#method.fetch_add). pub fn atomic_xadd_rel(dst: *mut T, src: T) -> T; - /// Add to the current value, returning the previous value. + /// Adds to the current value, returning the previous value. /// The stabilized version of this intrinsic is available on the /// `std::sync::atomic` types via the `fetch_add` method by passing /// [`Ordering::AcqRel`](../../std/sync/atomic/enum.Ordering.html) /// as the `order`. For example, /// [`AtomicIsize::fetch_add`](../../std/sync/atomic/struct.AtomicIsize.html#method.fetch_add). pub fn atomic_xadd_acqrel(dst: *mut T, src: T) -> T; - /// Add to the current value, returning the previous value. + /// Adds to the current value, returning the previous value. /// The stabilized version of this intrinsic is available on the /// `std::sync::atomic` types via the `fetch_add` method by passing /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) @@ -556,7 +556,7 @@ extern "rust-intrinsic" { pub fn atomic_umax_relaxed(dst: *mut T, src: T) -> T; /// The `prefetch` intrinsic is a hint to the code generator to insert a prefetch instruction - /// if supported; otherwise, it is a noop. + /// if supported; otherwise, it is a no-op. /// Prefetches have no effect on the behavior of the program but can change its performance /// characteristics. /// @@ -564,7 +564,7 @@ extern "rust-intrinsic" { /// ranging from (0) - no locality, to (3) - extremely local keep in cache pub fn prefetch_read_data(data: *const T, locality: i32); /// The `prefetch` intrinsic is a hint to the code generator to insert a prefetch instruction - /// if supported; otherwise, it is a noop. + /// if supported; otherwise, it is a no-op. /// Prefetches have no effect on the behavior of the program but can change its performance /// characteristics. /// @@ -572,7 +572,7 @@ extern "rust-intrinsic" { /// ranging from (0) - no locality, to (3) - extremely local keep in cache pub fn prefetch_write_data(data: *const T, locality: i32); /// The `prefetch` intrinsic is a hint to the code generator to insert a prefetch instruction - /// if supported; otherwise, it is a noop. + /// if supported; otherwise, it is a no-op. /// Prefetches have no effect on the behavior of the program but can change its performance /// characteristics. /// @@ -580,7 +580,7 @@ extern "rust-intrinsic" { /// ranging from (0) - no locality, to (3) - extremely local keep in cache pub fn prefetch_read_instruction(data: *const T, locality: i32); /// The `prefetch` intrinsic is a hint to the code generator to insert a prefetch instruction - /// if supported; otherwise, it is a noop. + /// if supported; otherwise, it is a no-op. /// Prefetches have no effect on the behavior of the program but can change its performance /// characteristics. /// @@ -692,13 +692,12 @@ extern "rust-intrinsic" { /// A guard for unsafe functions that cannot ever be executed if `T` is uninhabited: /// This will statically either panic, or do nothing. - #[cfg(not(stage0))] pub fn panic_if_uninhabited(); /// Creates a value initialized to zero. /// /// `init` is unsafe because it returns a zeroed-out datum, - /// which is unsafe unless T is `Copy`. Also, even if T is + /// which is unsafe unless `T` is `Copy`. Also, even if T is /// `Copy`, an all-zero value may not correspond to any legitimate /// state for the type in question. pub fn init() -> T; @@ -858,7 +857,7 @@ extern "rust-intrinsic" { /// /// // The no-copy, unsafe way, still using transmute, but not UB. /// // This is equivalent to the original, but safer, and reuses the - /// // same Vec internals. Therefore the new inner type must have the + /// // same `Vec` internals. Therefore, the new inner type must have the /// // exact same size, and the same alignment, as the old type. /// // The same caveats exist for this method as transmute, for /// // the original inner type (`&i32`) to the converted inner type @@ -876,8 +875,8 @@ extern "rust-intrinsic" { /// ``` /// use std::{slice, mem}; /// - /// // There are multiple ways to do this; and there are multiple problems - /// // with the following, transmute, way. + /// // There are multiple ways to do this, and there are multiple problems + /// // with the following (transmute) way. /// fn split_at_mut_transmute(slice: &mut [T], mid: usize) /// -> (&mut [T], &mut [T]) { /// let len = slice.len(); @@ -963,221 +962,6 @@ extern "rust-intrinsic" { /// value is not necessarily valid to be used to actually access memory. pub fn arith_offset(dst: *const T, offset: isize) -> *const T; - /// Copies `count * size_of::()` bytes from `src` to `dst`. The source - /// and destination must *not* overlap. - /// - /// For regions of memory which might overlap, use [`copy`] instead. - /// - /// `copy_nonoverlapping` is semantically equivalent to C's [`memcpy`], but - /// with the argument order swapped. - /// - /// [`copy`]: ./fn.copy.html - /// [`memcpy`]: https://en.cppreference.com/w/c/string/byte/memcpy - /// - /// # Safety - /// - /// Behavior is undefined if any of the following conditions are violated: - /// - /// * `src` must be [valid] for reads of `count * size_of::()` bytes. - /// - /// * `dst` must be [valid] for writes of `count * size_of::()` bytes. - /// - /// * Both `src` and `dst` must be properly aligned. - /// - /// * The region of memory beginning at `src` with a size of `count * - /// size_of::()` bytes must *not* overlap with the region of memory - /// beginning at `dst` with the same size. - /// - /// Like [`read`], `copy_nonoverlapping` creates a bitwise copy of `T`, regardless of - /// whether `T` is [`Copy`]. If `T` is not [`Copy`], using *both* the values - /// in the region beginning at `*src` and the region beginning at `*dst` can - /// [violate memory safety][read-ownership]. - /// - /// Note that even if the effectively copied size (`count * size_of::()`) is - /// `0`, the pointers must be non-NULL and properly aligned. - /// - /// [`Copy`]: ../marker/trait.Copy.html - /// [`read`]: ../ptr/fn.read.html - /// [read-ownership]: ../ptr/fn.read.html#ownership-of-the-returned-value - /// [valid]: ../ptr/index.html#safety - /// - /// # Examples - /// - /// Manually implement [`Vec::append`]: - /// - /// ``` - /// use std::ptr; - /// - /// /// Moves all the elements of `src` into `dst`, leaving `src` empty. - /// fn append(dst: &mut Vec, src: &mut Vec) { - /// let src_len = src.len(); - /// let dst_len = dst.len(); - /// - /// // Ensure that `dst` has enough capacity to hold all of `src`. - /// dst.reserve(src_len); - /// - /// unsafe { - /// // The call to offset is always safe because `Vec` will never - /// // allocate more than `isize::MAX` bytes. - /// let dst_ptr = dst.as_mut_ptr().offset(dst_len as isize); - /// let src_ptr = src.as_ptr(); - /// - /// // Truncate `src` without dropping its contents. We do this first, - /// // to avoid problems in case something further down panics. - /// src.set_len(0); - /// - /// // The two regions cannot overlap because mutable references do - /// // not alias, and two different vectors cannot own the same - /// // memory. - /// ptr::copy_nonoverlapping(src_ptr, dst_ptr, src_len); - /// - /// // Notify `dst` that it now holds the contents of `src`. - /// dst.set_len(dst_len + src_len); - /// } - /// } - /// - /// let mut a = vec!['r']; - /// let mut b = vec!['u', 's', 't']; - /// - /// append(&mut a, &mut b); - /// - /// assert_eq!(a, &['r', 'u', 's', 't']); - /// assert!(b.is_empty()); - /// ``` - /// - /// [`Vec::append`]: ../../std/vec/struct.Vec.html#method.append - #[stable(feature = "rust1", since = "1.0.0")] - 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. - /// - /// If the source and destination will *never* overlap, - /// [`copy_nonoverlapping`] can be used instead. - /// - /// `copy` is semantically equivalent to C's [`memmove`], but with the argument - /// order swapped. Copying takes place as if the bytes were copied from `src` - /// to a temporary array and then copied from the array to `dst`. - /// - /// [`copy_nonoverlapping`]: ./fn.copy_nonoverlapping.html - /// [`memmove`]: https://en.cppreference.com/w/c/string/byte/memmove - /// - /// # Safety - /// - /// Behavior is undefined if any of the following conditions are violated: - /// - /// * `src` must be [valid] for reads of `count * size_of::()` bytes. - /// - /// * `dst` must be [valid] for writes of `count * size_of::()` bytes. - /// - /// * Both `src` and `dst` must be properly aligned. - /// - /// Like [`read`], `copy` creates a bitwise copy of `T`, regardless of - /// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the values - /// in the region beginning at `*src` and the region beginning at `*dst` can - /// [violate memory safety][read-ownership]. - /// - /// Note that even if the effectively copied size (`count * size_of::()`) is - /// `0`, the pointers must be non-NULL and properly aligned. - /// - /// [`Copy`]: ../marker/trait.Copy.html - /// [`read`]: ../ptr/fn.read.html - /// [read-ownership]: ../ptr/fn.read.html#ownership-of-the-returned-value - /// [valid]: ../ptr/index.html#safety - /// - /// # Examples - /// - /// Efficiently create a Rust vector from an unsafe buffer: - /// - /// ``` - /// use std::ptr; - /// - /// # #[allow(dead_code)] - /// unsafe fn from_buf_raw(ptr: *const T, elts: usize) -> Vec { - /// let mut dst = Vec::with_capacity(elts); - /// dst.set_len(elts); - /// ptr::copy(ptr, dst.as_mut_ptr(), elts); - /// dst - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn copy(src: *const T, dst: *mut T, count: usize); - - /// Sets `count * size_of::()` bytes of memory starting at `dst` to - /// `val`. - /// - /// `write_bytes` is similar to C's [`memset`], but sets `count * - /// size_of::()` bytes to `val`. - /// - /// [`memset`]: https://en.cppreference.com/w/c/string/byte/memset - /// - /// # Safety - /// - /// Behavior is undefined if any of the following conditions are violated: - /// - /// * `dst` must be [valid] for writes of `count * size_of::()` bytes. - /// - /// * `dst` must be properly aligned. - /// - /// Additionally, the caller must ensure that writing `count * - /// size_of::()` bytes to the given region of memory results in a valid - /// value of `T`. Using a region of memory typed as a `T` that contains an - /// invalid value of `T` is undefined behavior. - /// - /// Note that even if the effectively copied size (`count * size_of::()`) is - /// `0`, the pointer must be non-NULL and properly aligned. - /// - /// [valid]: ../ptr/index.html#safety - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::ptr; - /// - /// let mut vec = vec![0u32; 4]; - /// unsafe { - /// let vec_ptr = vec.as_mut_ptr(); - /// ptr::write_bytes(vec_ptr, 0xfe, 2); - /// } - /// assert_eq!(vec, [0xfefefefe, 0xfefefefe, 0, 0]); - /// ``` - /// - /// Creating an invalid value: - /// - /// ``` - /// use std::ptr; - /// - /// let mut v = Box::new(0i32); - /// - /// unsafe { - /// // Leaks the previously held value by overwriting the `Box` with - /// // a null pointer. - /// ptr::write_bytes(&mut v as *mut Box, 0, 1); - /// } - /// - /// // At this point, using or dropping `v` results in undefined behavior. - /// // drop(v); // ERROR - /// - /// // Even leaking `v` "uses" it, and hence is undefined behavior. - /// // mem::forget(v); // ERROR - /// - /// // In fact, `v` is invalid according to basic type layout invariants, so *any* - /// // operation touching it is undefined behavior. - /// // let v2 = v; // ERROR - /// - /// unsafe { - /// // Let us instead put in a valid value - /// ptr::write(&mut v as *mut Box, Box::new(42i32)); - /// } - /// - /// // Now the box is fine - /// assert_eq!(*v, 42); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn write_bytes(dst: *mut T, val: u8, count: usize); - /// Equivalent to the appropriate `llvm.memcpy.p0i8.0i8.*` intrinsic, with /// a size of `count` * `size_of::()` and an alignment of /// `min_align_of::()` @@ -1201,19 +985,19 @@ extern "rust-intrinsic" { /// unless size is equal to zero. pub fn volatile_set_memory(dst: *mut T, val: u8, count: usize); - /// Perform a volatile load from the `src` pointer. + /// Performs a volatile load from the `src` pointer. /// The stabilized version of this intrinsic is /// [`std::ptr::read_volatile`](../../std/ptr/fn.read_volatile.html). pub fn volatile_load(src: *const T) -> T; - /// Perform a volatile store to the `dst` pointer. + /// Performs a volatile store to the `dst` pointer. /// The stabilized version of this intrinsic is /// [`std::ptr::write_volatile`](../../std/ptr/fn.write_volatile.html). pub fn volatile_store(dst: *mut T, val: T); - /// Perform a volatile load from the `src` pointer + /// Performs a volatile load from the `src` pointer /// The pointer is not required to be aligned. pub fn unaligned_volatile_load(src: *const T) -> T; - /// Perform a volatile store to the `dst` pointer. + /// Performs a volatile store to the `dst` pointer. /// The pointer is not required to be aligned. pub fn unaligned_volatile_store(dst: *mut T, val: T); @@ -1494,6 +1278,19 @@ extern "rust-intrinsic" { /// [`std::u32::wrapping_mul`](../../std/primitive.u32.html#method.wrapping_mul) pub fn overflowing_mul(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_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', /// cast to a `u64`; if `T` has no discriminant, returns 0. pub fn discriminant_value(v: &T) -> u64; @@ -1512,3 +1309,252 @@ extern "rust-intrinsic" { /// 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); + } +} + +/// Copies `count * size_of::()` bytes from `src` to `dst`. The source +/// and destination must *not* overlap. +/// +/// For regions of memory which might overlap, use [`copy`] instead. +/// +/// `copy_nonoverlapping` is semantically equivalent to C's [`memcpy`], but +/// with the argument order swapped. +/// +/// [`copy`]: ./fn.copy.html +/// [`memcpy`]: https://en.cppreference.com/w/c/string/byte/memcpy +/// +/// # Safety +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `src` must be [valid] for reads of `count * size_of::()` bytes. +/// +/// * `dst` must be [valid] for writes of `count * size_of::()` bytes. +/// +/// * Both `src` and `dst` must be properly aligned. +/// +/// * The region of memory beginning at `src` with a size of `count * +/// size_of::()` bytes must *not* overlap with the region of memory +/// beginning at `dst` with the same size. +/// +/// Like [`read`], `copy_nonoverlapping` creates a bitwise copy of `T`, regardless of +/// whether `T` is [`Copy`]. If `T` is not [`Copy`], using *both* the values +/// in the region beginning at `*src` and the region beginning at `*dst` can +/// [violate memory safety][read-ownership]. +/// +/// Note that even if the effectively copied size (`count * size_of::()`) is +/// `0`, the pointers must be non-NULL and properly aligned. +/// +/// [`Copy`]: ../marker/trait.Copy.html +/// [`read`]: ../ptr/fn.read.html +/// [read-ownership]: ../ptr/fn.read.html#ownership-of-the-returned-value +/// [valid]: ../ptr/index.html#safety +/// +/// # Examples +/// +/// Manually implement [`Vec::append`]: +/// +/// ``` +/// use std::ptr; +/// +/// /// Moves all the elements of `src` into `dst`, leaving `src` empty. +/// fn append(dst: &mut Vec, src: &mut Vec) { +/// let src_len = src.len(); +/// let dst_len = dst.len(); +/// +/// // Ensure that `dst` has enough capacity to hold all of `src`. +/// dst.reserve(src_len); +/// +/// unsafe { +/// // The call to offset is always safe because `Vec` will never +/// // allocate more than `isize::MAX` bytes. +/// let dst_ptr = dst.as_mut_ptr().offset(dst_len as isize); +/// let src_ptr = src.as_ptr(); +/// +/// // Truncate `src` without dropping its contents. We do this first, +/// // to avoid problems in case something further down panics. +/// src.set_len(0); +/// +/// // The two regions cannot overlap because mutable references do +/// // not alias, and two different vectors cannot own the same +/// // memory. +/// ptr::copy_nonoverlapping(src_ptr, dst_ptr, src_len); +/// +/// // Notify `dst` that it now holds the contents of `src`. +/// dst.set_len(dst_len + src_len); +/// } +/// } +/// +/// let mut a = vec!['r']; +/// let mut b = vec!['u', 's', 't']; +/// +/// append(&mut a, &mut b); +/// +/// assert_eq!(a, &['r', 'u', 's', 't']); +/// assert!(b.is_empty()); +/// ``` +/// +/// [`Vec::append`]: ../../std/vec/struct.Vec.html#method.append +#[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); +} + +/// Copies `count * size_of::()` bytes from `src` to `dst`. The source +/// and destination may overlap. +/// +/// If the source and destination will *never* overlap, +/// [`copy_nonoverlapping`] can be used instead. +/// +/// `copy` is semantically equivalent to C's [`memmove`], but with the argument +/// order swapped. Copying takes place as if the bytes were copied from `src` +/// to a temporary array and then copied from the array to `dst`. +/// +/// [`copy_nonoverlapping`]: ./fn.copy_nonoverlapping.html +/// [`memmove`]: https://en.cppreference.com/w/c/string/byte/memmove +/// +/// # Safety +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `src` must be [valid] for reads of `count * size_of::()` bytes. +/// +/// * `dst` must be [valid] for writes of `count * size_of::()` bytes. +/// +/// * Both `src` and `dst` must be properly aligned. +/// +/// Like [`read`], `copy` creates a bitwise copy of `T`, regardless of +/// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the values +/// in the region beginning at `*src` and the region beginning at `*dst` can +/// [violate memory safety][read-ownership]. +/// +/// Note that even if the effectively copied size (`count * size_of::()`) is +/// `0`, the pointers must be non-NULL and properly aligned. +/// +/// [`Copy`]: ../marker/trait.Copy.html +/// [`read`]: ../ptr/fn.read.html +/// [read-ownership]: ../ptr/fn.read.html#ownership-of-the-returned-value +/// [valid]: ../ptr/index.html#safety +/// +/// # Examples +/// +/// Efficiently create a Rust vector from an unsafe buffer: +/// +/// ``` +/// use std::ptr; +/// +/// # #[allow(dead_code)] +/// unsafe fn from_buf_raw(ptr: *const T, elts: usize) -> Vec { +/// let mut dst = Vec::with_capacity(elts); +/// dst.set_len(elts); +/// ptr::copy(ptr, dst.as_mut_ptr(), elts); +/// dst +/// } +/// ``` +#[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) +} + +/// Sets `count * size_of::()` bytes of memory starting at `dst` to +/// `val`. +/// +/// `write_bytes` is similar to C's [`memset`], but sets `count * +/// size_of::()` bytes to `val`. +/// +/// [`memset`]: https://en.cppreference.com/w/c/string/byte/memset +/// +/// # Safety +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `dst` must be [valid] for writes of `count * size_of::()` bytes. +/// +/// * `dst` must be properly aligned. +/// +/// Additionally, the caller must ensure that writing `count * +/// size_of::()` bytes to the given region of memory results in a valid +/// value of `T`. Using a region of memory typed as a `T` that contains an +/// invalid value of `T` is undefined behavior. +/// +/// Note that even if the effectively copied size (`count * size_of::()`) is +/// `0`, the pointer must be non-NULL and properly aligned. +/// +/// [valid]: ../ptr/index.html#safety +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use std::ptr; +/// +/// let mut vec = vec![0u32; 4]; +/// unsafe { +/// let vec_ptr = vec.as_mut_ptr(); +/// ptr::write_bytes(vec_ptr, 0xfe, 2); +/// } +/// assert_eq!(vec, [0xfefefefe, 0xfefefefe, 0, 0]); +/// ``` +/// +/// Creating an invalid value: +/// +/// ``` +/// use std::ptr; +/// +/// let mut v = Box::new(0i32); +/// +/// unsafe { +/// // Leaks the previously held value by overwriting the `Box` with +/// // a null pointer. +/// ptr::write_bytes(&mut v as *mut Box, 0, 1); +/// } +/// +/// // At this point, using or dropping `v` results in undefined behavior. +/// // drop(v); // ERROR +/// +/// // Even leaking `v` "uses" it, and hence is undefined behavior. +/// // mem::forget(v); // ERROR +/// +/// // In fact, `v` is invalid according to basic type layout invariants, so *any* +/// // operation touching it is undefined behavior. +/// // let v2 = v; // ERROR +/// +/// unsafe { +/// // Let us instead put in a valid value +/// ptr::write(&mut v as *mut Box, Box::new(42i32)); +/// } +/// +/// // Now the box is fine +/// assert_eq!(*v, 42); +/// ``` +#[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) +} diff --git a/src/libcore/iter/adapters/chain.rs b/src/libcore/iter/adapters/chain.rs new file mode 100644 index 0000000000000..573b096fb463e --- /dev/null +++ b/src/libcore/iter/adapters/chain.rs @@ -0,0 +1,260 @@ +use ops::Try; +use usize; +use super::super::{Iterator, DoubleEndedIterator, FusedIterator, TrustedLen}; + +/// An iterator that strings two iterators together. +/// +/// This `struct` is created by the [`chain`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`chain`]: trait.Iterator.html#method.chain +/// [`Iterator`]: trait.Iterator.html +#[derive(Clone, Debug)] +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Chain { + a: A, + b: B, + state: ChainState, +} +impl Chain { + pub(in super::super) fn new(a: A, b: B) -> Chain { + Chain { a, b, state: ChainState::Both } + } +} + +// The iterator protocol specifies that iteration ends with the return value +// `None` from `.next()` (or `.next_back()`) and it is unspecified what +// further calls return. The chain adaptor must account for this since it uses +// two subiterators. +// +// It uses three states: +// +// - Both: `a` and `b` are remaining +// - Front: `a` remaining +// - Back: `b` remaining +// +// The fourth state (neither iterator is remaining) only occurs after Chain has +// returned None once, so we don't need to store this state. +#[derive(Clone, Debug)] +enum ChainState { + // both front and back iterator are remaining + Both, + // only front is remaining + Front, + // only back is remaining + Back, +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for Chain where + A: Iterator, + B: Iterator +{ + type Item = A::Item; + + #[inline] + fn next(&mut self) -> Option { + match self.state { + ChainState::Both => match self.a.next() { + elt @ Some(..) => elt, + None => { + self.state = ChainState::Back; + self.b.next() + } + }, + ChainState::Front => self.a.next(), + ChainState::Back => self.b.next(), + } + } + + #[inline] + #[rustc_inherit_overflow_checks] + fn count(self) -> usize { + match self.state { + ChainState::Both => self.a.count() + self.b.count(), + ChainState::Front => self.a.count(), + ChainState::Back => self.b.count(), + } + } + + fn try_fold(&mut self, init: Acc, mut f: F) -> R where + Self: Sized, F: FnMut(Acc, Self::Item) -> R, R: Try + { + let mut accum = init; + match self.state { + ChainState::Both | ChainState::Front => { + accum = self.a.try_fold(accum, &mut f)?; + if let ChainState::Both = self.state { + self.state = ChainState::Back; + } + } + _ => { } + } + if let ChainState::Back = self.state { + accum = self.b.try_fold(accum, &mut f)?; + } + Try::from_ok(accum) + } + + fn fold(self, init: Acc, mut f: F) -> Acc + where F: FnMut(Acc, Self::Item) -> Acc, + { + let mut accum = init; + match self.state { + ChainState::Both | ChainState::Front => { + accum = self.a.fold(accum, &mut f); + } + _ => { } + } + match self.state { + ChainState::Both | ChainState::Back => { + accum = self.b.fold(accum, &mut f); + } + _ => { } + } + accum + } + + #[inline] + fn nth(&mut self, mut n: usize) -> Option { + match self.state { + ChainState::Both | ChainState::Front => { + for x in self.a.by_ref() { + if n == 0 { + return Some(x) + } + n -= 1; + } + if let ChainState::Both = self.state { + self.state = ChainState::Back; + } + } + ChainState::Back => {} + } + if let ChainState::Back = self.state { + self.b.nth(n) + } else { + None + } + } + + #[inline] + fn find

(&mut self, mut predicate: P) -> Option where + P: FnMut(&Self::Item) -> bool, + { + match self.state { + ChainState::Both => match self.a.find(&mut predicate) { + None => { + self.state = ChainState::Back; + self.b.find(predicate) + } + v => v + }, + ChainState::Front => self.a.find(predicate), + ChainState::Back => self.b.find(predicate), + } + } + + #[inline] + fn last(self) -> Option { + match self.state { + ChainState::Both => { + // Must exhaust a before b. + let a_last = self.a.last(); + let b_last = self.b.last(); + b_last.or(a_last) + }, + ChainState::Front => self.a.last(), + ChainState::Back => self.b.last() + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let (a_lower, a_upper) = self.a.size_hint(); + let (b_lower, b_upper) = self.b.size_hint(); + + let lower = a_lower.saturating_add(b_lower); + + let upper = match (a_upper, b_upper) { + (Some(x), Some(y)) => x.checked_add(y), + _ => None + }; + + (lower, upper) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl DoubleEndedIterator for Chain where + A: DoubleEndedIterator, + B: DoubleEndedIterator, +{ + #[inline] + fn next_back(&mut self) -> Option { + match self.state { + ChainState::Both => match self.b.next_back() { + elt @ Some(..) => elt, + None => { + self.state = ChainState::Front; + self.a.next_back() + } + }, + ChainState::Front => self.a.next_back(), + ChainState::Back => self.b.next_back(), + } + } + + fn try_rfold(&mut self, init: Acc, mut f: F) -> R where + Self: Sized, F: FnMut(Acc, Self::Item) -> R, R: Try + { + let mut accum = init; + match self.state { + ChainState::Both | ChainState::Back => { + accum = self.b.try_rfold(accum, &mut f)?; + if let ChainState::Both = self.state { + self.state = ChainState::Front; + } + } + _ => { } + } + if let ChainState::Front = self.state { + accum = self.a.try_rfold(accum, &mut f)?; + } + Try::from_ok(accum) + } + + fn rfold(self, init: Acc, mut f: F) -> Acc + where F: FnMut(Acc, Self::Item) -> Acc, + { + let mut accum = init; + match self.state { + ChainState::Both | ChainState::Back => { + accum = self.b.rfold(accum, &mut f); + } + _ => { } + } + match self.state { + ChainState::Both | ChainState::Front => { + accum = self.a.rfold(accum, &mut f); + } + _ => { } + } + accum + } + +} + +// Note: *both* must be fused to handle double-ended iterators. +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Chain + where A: FusedIterator, + B: FusedIterator, +{} + +#[unstable(feature = "trusted_len", issue = "37572")] +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 new file mode 100644 index 0000000000000..40f6865d38bcf --- /dev/null +++ b/src/libcore/iter/adapters/flatten.rs @@ -0,0 +1,330 @@ +use fmt; +use ops::Try; +use super::super::{Iterator, DoubleEndedIterator, FusedIterator}; +use super::Map; + +/// An iterator that maps each element to an iterator, and yields the elements +/// of the produced iterators. +/// +/// This `struct` is created by the [`flat_map`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`flat_map`]: trait.Iterator.html#method.flat_map +/// [`Iterator`]: trait.Iterator.html +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct FlatMap { + inner: FlattenCompat, ::IntoIter> +} +impl U> FlatMap { + pub(in super::super) fn new(iter: I, f: F) -> FlatMap { + FlatMap { inner: FlattenCompat::new(iter.map(f)) } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Clone for FlatMap + where ::IntoIter: Clone +{ + fn clone(&self) -> Self { FlatMap { inner: self.inner.clone() } } +} + +#[stable(feature = "core_impl_debug", since = "1.9.0")] +impl fmt::Debug for FlatMap + where U::IntoIter: fmt::Debug +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("FlatMap").field("inner", &self.inner).finish() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for FlatMap + where F: FnMut(I::Item) -> U, +{ + type Item = U::Item; + + #[inline] + fn next(&mut self) -> Option { self.inner.next() } + + #[inline] + fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + + #[inline] + fn try_fold(&mut self, init: Acc, fold: Fold) -> R where + Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try + { + self.inner.try_fold(init, fold) + } + + #[inline] + fn fold(self, init: Acc, fold: Fold) -> Acc + where Fold: FnMut(Acc, Self::Item) -> Acc, + { + self.inner.fold(init, fold) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl DoubleEndedIterator for FlatMap + where F: FnMut(I::Item) -> U, + U: IntoIterator, + U::IntoIter: DoubleEndedIterator +{ + #[inline] + fn next_back(&mut self) -> Option { self.inner.next_back() } + + #[inline] + fn try_rfold(&mut self, init: Acc, fold: Fold) -> R where + Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try + { + self.inner.try_rfold(init, fold) + } + + #[inline] + fn rfold(self, init: Acc, fold: Fold) -> Acc + where Fold: FnMut(Acc, Self::Item) -> Acc, + { + self.inner.rfold(init, fold) + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for FlatMap + where I: FusedIterator, U: IntoIterator, F: FnMut(I::Item) -> U {} + +/// An iterator that flattens one level of nesting in an iterator of things +/// that can be turned into iterators. +/// +/// This `struct` is created by the [`flatten`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`flatten`]: trait.Iterator.html#method.flatten +/// [`Iterator`]: trait.Iterator.html +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[stable(feature = "iterator_flatten", since = "1.29.0")] +pub struct Flatten +where I::Item: IntoIterator { + inner: FlattenCompat::IntoIter>, +} +impl Flatten +where I::Item: IntoIterator { + pub(in super::super) fn new(iter: I) -> Flatten { + Flatten { inner: FlattenCompat::new(iter) } + } +} + +#[stable(feature = "iterator_flatten", since = "1.29.0")] +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 { + f.debug_struct("Flatten").field("inner", &self.inner).finish() + } +} + +#[stable(feature = "iterator_flatten", since = "1.29.0")] +impl Clone for Flatten + where I: Iterator + Clone, U: Iterator + Clone, + I::Item: IntoIterator, +{ + fn clone(&self) -> Self { Flatten { inner: self.inner.clone() } } +} + +#[stable(feature = "iterator_flatten", since = "1.29.0")] +impl Iterator for Flatten + where I: Iterator, U: Iterator, + I::Item: IntoIterator +{ + type Item = U::Item; + + #[inline] + fn next(&mut self) -> Option { self.inner.next() } + + #[inline] + fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + + #[inline] + fn try_fold(&mut self, init: Acc, fold: Fold) -> R where + Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try + { + self.inner.try_fold(init, fold) + } + + #[inline] + fn fold(self, init: Acc, fold: Fold) -> Acc + where Fold: FnMut(Acc, Self::Item) -> Acc, + { + self.inner.fold(init, fold) + } +} + +#[stable(feature = "iterator_flatten", since = "1.29.0")] +impl DoubleEndedIterator for Flatten + where I: DoubleEndedIterator, U: DoubleEndedIterator, + I::Item: IntoIterator +{ + #[inline] + fn next_back(&mut self) -> Option { self.inner.next_back() } + + #[inline] + fn try_rfold(&mut self, init: Acc, fold: Fold) -> R where + Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try + { + self.inner.try_rfold(init, fold) + } + + #[inline] + fn rfold(self, init: Acc, fold: Fold) -> Acc + where Fold: FnMut(Acc, Self::Item) -> Acc, + { + self.inner.rfold(init, fold) + } +} + +#[stable(feature = "iterator_flatten", since = "1.29.0")] +impl FusedIterator for Flatten + where I: FusedIterator, U: Iterator, + I::Item: IntoIterator {} + +/// Real logic of both `Flatten` and `FlatMap` which simply delegate to +/// this type. +#[derive(Clone, Debug)] +struct FlattenCompat { + iter: I, + frontiter: Option, + backiter: Option, +} +impl FlattenCompat { + /// Adapts an iterator by flattening it, for use in `flatten()` and `flat_map()`. + fn new(iter: I) -> FlattenCompat { + FlattenCompat { iter, frontiter: None, backiter: None } + } +} + +impl Iterator for FlattenCompat + where I: Iterator, U: Iterator, + I::Item: IntoIterator +{ + type Item = U::Item; + + #[inline] + fn next(&mut self) -> Option { + loop { + if let Some(ref mut inner) = self.frontiter { + if let elt@Some(_) = inner.next() { return elt } + } + match self.iter.next() { + None => return self.backiter.as_mut().and_then(|it| it.next()), + Some(inner) => self.frontiter = Some(inner.into_iter()), + } + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let (flo, fhi) = self.frontiter.as_ref().map_or((0, Some(0)), |it| it.size_hint()); + let (blo, bhi) = self.backiter.as_ref().map_or((0, Some(0)), |it| it.size_hint()); + let lo = flo.saturating_add(blo); + match (self.iter.size_hint(), fhi, bhi) { + ((0, Some(0)), Some(a), Some(b)) => (lo, a.checked_add(b)), + _ => (lo, None) + } + } + + #[inline] + fn try_fold(&mut self, mut init: Acc, mut fold: Fold) -> R where + Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try + { + if let Some(ref mut front) = self.frontiter { + init = front.try_fold(init, &mut fold)?; + } + self.frontiter = None; + + { + let frontiter = &mut self.frontiter; + init = self.iter.try_fold(init, |acc, x| { + let mut mid = x.into_iter(); + let r = mid.try_fold(acc, &mut fold); + *frontiter = Some(mid); + r + })?; + } + self.frontiter = None; + + if let Some(ref mut back) = self.backiter { + init = back.try_fold(init, &mut fold)?; + } + self.backiter = None; + + Try::from_ok(init) + } + + #[inline] + fn fold(self, init: Acc, mut fold: Fold) -> Acc + where Fold: FnMut(Acc, Self::Item) -> Acc, + { + self.frontiter.into_iter() + .chain(self.iter.map(IntoIterator::into_iter)) + .chain(self.backiter) + .fold(init, |acc, iter| iter.fold(acc, &mut fold)) + } +} + +impl DoubleEndedIterator for FlattenCompat + where I: DoubleEndedIterator, U: DoubleEndedIterator, + I::Item: IntoIterator +{ + #[inline] + fn next_back(&mut self) -> Option { + loop { + if let Some(ref mut inner) = self.backiter { + if let elt@Some(_) = inner.next_back() { return elt } + } + match self.iter.next_back() { + None => return self.frontiter.as_mut().and_then(|it| it.next_back()), + next => self.backiter = next.map(IntoIterator::into_iter), + } + } + } + + #[inline] + fn try_rfold(&mut self, mut init: Acc, mut fold: Fold) -> R where + Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try + { + if let Some(ref mut back) = self.backiter { + init = back.try_rfold(init, &mut fold)?; + } + self.backiter = None; + + { + let backiter = &mut self.backiter; + init = self.iter.try_rfold(init, |acc, x| { + let mut mid = x.into_iter(); + let r = mid.try_rfold(acc, &mut fold); + *backiter = Some(mid); + r + })?; + } + self.backiter = None; + + if let Some(ref mut front) = self.frontiter { + init = front.try_rfold(init, &mut fold)?; + } + self.frontiter = None; + + Try::from_ok(init) + } + + #[inline] + fn rfold(self, init: Acc, mut fold: Fold) -> Acc + where Fold: FnMut(Acc, Self::Item) -> Acc, + { + self.frontiter.into_iter() + .chain(self.iter.map(IntoIterator::into_iter)) + .chain(self.backiter) + .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 new file mode 100644 index 0000000000000..bca1b76dbb975 --- /dev/null +++ b/src/libcore/iter/adapters/mod.rs @@ -0,0 +1,2045 @@ +use cmp; +use fmt; +use ops::Try; +use usize; +use intrinsics; +use super::{Iterator, DoubleEndedIterator, ExactSizeIterator, FusedIterator, TrustedLen}; +use super::LoopState; + +mod chain; +mod flatten; +mod zip; + +pub use self::chain::Chain; +#[stable(feature = "rust1", since = "1.0.0")] +pub use self::flatten::{FlatMap, Flatten}; +pub use self::zip::Zip; +pub(crate) use self::zip::TrustedRandomAccess; + +/// A double-ended iterator with the direction inverted. +/// +/// This `struct` is created by the [`rev`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`rev`]: trait.Iterator.html#method.rev +/// [`Iterator`]: trait.Iterator.html +#[derive(Clone, Debug)] +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Rev { + iter: T +} +impl Rev { + pub(super) fn new(iter: T) -> Rev { + Rev { iter } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for Rev where I: DoubleEndedIterator { + type Item = ::Item; + + #[inline] + fn next(&mut self) -> Option<::Item> { self.iter.next_back() } + #[inline] + fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } + + #[inline] + fn nth(&mut self, n: usize) -> Option<::Item> { self.iter.nth_back(n) } + + fn try_fold(&mut self, init: B, f: F) -> R where + Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try + { + self.iter.try_rfold(init, f) + } + + fn fold(self, init: Acc, f: F) -> Acc + where F: FnMut(Acc, Self::Item) -> Acc, + { + self.iter.rfold(init, f) + } + + #[inline] + fn find

(&mut self, predicate: P) -> Option + where P: FnMut(&Self::Item) -> bool + { + self.iter.rfind(predicate) + } + + #[inline] + fn rposition

(&mut self, predicate: P) -> Option where + P: FnMut(Self::Item) -> bool + { + self.iter.position(predicate) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl DoubleEndedIterator for Rev where I: DoubleEndedIterator { + #[inline] + fn next_back(&mut self) -> Option<::Item> { self.iter.next() } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option<::Item> { self.iter.nth(n) } + + fn try_rfold(&mut self, init: B, f: F) -> R where + Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try + { + self.iter.try_fold(init, f) + } + + fn rfold(self, init: Acc, f: F) -> Acc + where F: FnMut(Acc, Self::Item) -> Acc, + { + self.iter.fold(init, f) + } + + fn rfind

(&mut self, predicate: P) -> Option + where P: FnMut(&Self::Item) -> bool + { + self.iter.find(predicate) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for Rev + where I: ExactSizeIterator + DoubleEndedIterator +{ + fn len(&self) -> usize { + self.iter.len() + } + + fn is_empty(&self) -> bool { + self.iter.is_empty() + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Rev + where I: FusedIterator + DoubleEndedIterator {} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for Rev + where I: TrustedLen + DoubleEndedIterator {} + +/// An iterator that copies the elements of an underlying iterator. +/// +/// This `struct` is created by the [`copied`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`copied`]: trait.Iterator.html#method.copied +/// [`Iterator`]: trait.Iterator.html +#[unstable(feature = "iter_copied", issue = "57127")] +#[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")] +impl<'a, I, T: 'a> Iterator for Copied + where I: Iterator, T: Copy +{ + type Item = T; + + fn next(&mut self) -> Option { + self.it.next().copied() + } + + fn size_hint(&self) -> (usize, Option) { + self.it.size_hint() + } + + fn try_fold(&mut self, init: B, mut f: F) -> R where + Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try + { + self.it.try_fold(init, move |acc, &elt| f(acc, elt)) + } + + fn fold(self, init: Acc, mut f: F) -> Acc + where F: FnMut(Acc, Self::Item) -> Acc, + { + self.it.fold(init, move |acc, &elt| f(acc, elt)) + } +} + +#[unstable(feature = "iter_copied", issue = "57127")] +impl<'a, I, T: 'a> DoubleEndedIterator for Copied + where I: DoubleEndedIterator, T: Copy +{ + fn next_back(&mut self) -> Option { + self.it.next_back().copied() + } + + fn try_rfold(&mut self, init: B, mut f: F) -> R where + Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try + { + self.it.try_rfold(init, move |acc, &elt| f(acc, elt)) + } + + fn rfold(self, init: Acc, mut f: F) -> Acc + where F: FnMut(Acc, Self::Item) -> Acc, + { + self.it.rfold(init, move |acc, &elt| f(acc, elt)) + } +} + +#[unstable(feature = "iter_copied", issue = "57127")] +impl<'a, I, T: 'a> ExactSizeIterator for Copied + where I: ExactSizeIterator, T: Copy +{ + fn len(&self) -> usize { + self.it.len() + } + + fn is_empty(&self) -> bool { + self.it.is_empty() + } +} + +#[unstable(feature = "iter_copied", issue = "57127")] +impl<'a, I, T: 'a> FusedIterator for Copied + where I: FusedIterator, T: Copy +{} + +#[doc(hidden)] +unsafe impl<'a, I, T: 'a> TrustedRandomAccess for Copied + where I: TrustedRandomAccess, T: Copy +{ + unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item { + *self.it.get_unchecked(i) + } + + #[inline] + fn may_have_side_effect() -> bool { + I::may_have_side_effect() + } +} + +#[unstable(feature = "iter_copied", issue = "57127")] +unsafe impl<'a, I, T: 'a> TrustedLen for Copied + where I: TrustedLen, + T: Copy +{} + +/// An iterator that clones the elements of an underlying iterator. +/// +/// This `struct` is created by the [`cloned`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`cloned`]: trait.Iterator.html#method.cloned +/// [`Iterator`]: trait.Iterator.html +#[stable(feature = "iter_cloned", since = "1.1.0")] +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[derive(Clone, Debug)] +pub struct Cloned { + it: I, +} +impl Cloned { + pub(super) fn new(it: I) -> Cloned { + Cloned { it } + } +} + +#[stable(feature = "iter_cloned", since = "1.1.0")] +impl<'a, I, T: 'a> Iterator for Cloned + where I: Iterator, T: Clone +{ + type Item = T; + + fn next(&mut self) -> Option { + self.it.next().cloned() + } + + fn size_hint(&self) -> (usize, Option) { + self.it.size_hint() + } + + fn try_fold(&mut self, init: B, mut f: F) -> R where + Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try + { + self.it.try_fold(init, move |acc, elt| f(acc, elt.clone())) + } + + fn fold(self, init: Acc, mut f: F) -> Acc + where F: FnMut(Acc, Self::Item) -> Acc, + { + self.it.fold(init, move |acc, elt| f(acc, elt.clone())) + } +} + +#[stable(feature = "iter_cloned", since = "1.1.0")] +impl<'a, I, T: 'a> DoubleEndedIterator for Cloned + where I: DoubleEndedIterator, T: Clone +{ + fn next_back(&mut self) -> Option { + self.it.next_back().cloned() + } + + fn try_rfold(&mut self, init: B, mut f: F) -> R where + Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try + { + self.it.try_rfold(init, move |acc, elt| f(acc, elt.clone())) + } + + fn rfold(self, init: Acc, mut f: F) -> Acc + where F: FnMut(Acc, Self::Item) -> Acc, + { + self.it.rfold(init, move |acc, elt| f(acc, elt.clone())) + } +} + +#[stable(feature = "iter_cloned", since = "1.1.0")] +impl<'a, I, T: 'a> ExactSizeIterator for Cloned + where I: ExactSizeIterator, T: Clone +{ + fn len(&self) -> usize { + self.it.len() + } + + fn is_empty(&self) -> bool { + self.it.is_empty() + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl<'a, I, T: 'a> FusedIterator for Cloned + where I: FusedIterator, T: Clone +{} + +#[doc(hidden)] +unsafe impl<'a, I, T: 'a> TrustedRandomAccess for Cloned + where I: TrustedRandomAccess, T: Clone +{ + default unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item { + self.it.get_unchecked(i).clone() + } + + #[inline] + default fn may_have_side_effect() -> bool { true } +} + +#[doc(hidden)] +unsafe impl<'a, I, T: 'a> TrustedRandomAccess for Cloned + where I: TrustedRandomAccess, T: Copy +{ + unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item { + *self.it.get_unchecked(i) + } + + #[inline] + fn may_have_side_effect() -> bool { + I::may_have_side_effect() + } +} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl<'a, I, T: 'a> TrustedLen for Cloned + where I: TrustedLen, + T: Clone +{} + +/// An iterator that repeats endlessly. +/// +/// This `struct` is created by the [`cycle`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`cycle`]: trait.Iterator.html#method.cycle +/// [`Iterator`]: trait.Iterator.html +#[derive(Clone, Debug)] +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Cycle { + orig: I, + iter: I, +} +impl Cycle { + pub(super) fn new(iter: I) -> Cycle { + Cycle { orig: iter.clone(), iter } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for Cycle where I: Clone + Iterator { + type Item = ::Item; + + #[inline] + fn next(&mut self) -> Option<::Item> { + match self.iter.next() { + None => { self.iter = self.orig.clone(); self.iter.next() } + y => y + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + // the cycle iterator is either empty or infinite + match self.orig.size_hint() { + sz @ (0, Some(0)) => sz, + (0, _) => (0, None), + _ => (usize::MAX, None) + } + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Cycle where I: Clone + Iterator {} + +/// An iterator for stepping iterators by a custom amount. +/// +/// This `struct` is created by the [`step_by`] method on [`Iterator`]. See +/// its documentation for more. +/// +/// [`step_by`]: trait.Iterator.html#method.step_by +/// [`Iterator`]: trait.Iterator.html +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[stable(feature = "iterator_step_by", since = "1.28.0")] +#[derive(Clone, Debug)] +pub struct StepBy { + iter: I, + step: usize, + first_take: bool, +} +impl StepBy { + pub(super) fn new(iter: I, step: usize) -> StepBy { + assert!(step != 0); + StepBy { iter, step: step - 1, first_take: true } + } +} + +#[stable(feature = "iterator_step_by", since = "1.28.0")] +impl Iterator for StepBy where I: Iterator { + type Item = I::Item; + + #[inline] + fn next(&mut self) -> Option { + if self.first_take { + self.first_take = false; + self.iter.next() + } else { + self.iter.nth(self.step) + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let inner_hint = self.iter.size_hint(); + + if self.first_take { + let f = |n| if n == 0 { 0 } else { 1 + (n-1)/(self.step+1) }; + (f(inner_hint.0), inner_hint.1.map(f)) + } else { + let f = |n| n / (self.step+1); + (f(inner_hint.0), inner_hint.1.map(f)) + } + } + + #[inline] + fn nth(&mut self, mut n: usize) -> Option { + if self.first_take { + self.first_take = false; + let first = self.iter.next(); + if n == 0 { + return first; + } + n -= 1; + } + // n and self.step are indices, we need to add 1 to get the amount of elements + // When calling `.nth`, we need to subtract 1 again to convert back to an index + // step + 1 can't overflow because `.step_by` sets `self.step` to `step - 1` + let mut step = self.step + 1; + // n + 1 could overflow + // thus, if n is usize::MAX, instead of adding one, we call .nth(step) + if n == usize::MAX { + self.iter.nth(step - 1); + } else { + n += 1; + } + + // overflow handling + loop { + let mul = n.checked_mul(step); + if unsafe { intrinsics::likely(mul.is_some()) } { + return self.iter.nth(mul.unwrap() - 1); + } + let div_n = usize::MAX / n; + let div_step = usize::MAX / step; + let nth_n = div_n * n; + let nth_step = div_step * step; + let nth = if nth_n > nth_step { + step -= div_n; + nth_n + } else { + n -= div_step; + nth_step + }; + self.iter.nth(nth - 1); + } + } +} + +// StepBy can only make the iterator shorter, so the len will still fit. +#[stable(feature = "iterator_step_by", since = "1.28.0")] +impl ExactSizeIterator for StepBy where I: ExactSizeIterator {} + +/// An iterator that maps the values of `iter` with `f`. +/// +/// This `struct` is created by the [`map`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`map`]: trait.Iterator.html#method.map +/// [`Iterator`]: trait.Iterator.html +/// +/// # Notes about side effects +/// +/// The [`map`] iterator implements [`DoubleEndedIterator`], meaning that +/// you can also [`map`] backwards: +/// +/// ```rust +/// let v: Vec = vec![1, 2, 3].into_iter().map(|x| x + 1).rev().collect(); +/// +/// assert_eq!(v, [4, 3, 2]); +/// ``` +/// +/// [`DoubleEndedIterator`]: trait.DoubleEndedIterator.html +/// +/// But if your closure has state, iterating backwards may act in a way you do +/// not expect. Let's go through an example. First, in the forward direction: +/// +/// ```rust +/// let mut c = 0; +/// +/// for pair in vec!['a', 'b', 'c'].into_iter() +/// .map(|letter| { c += 1; (letter, c) }) { +/// println!("{:?}", pair); +/// } +/// ``` +/// +/// This will print "('a', 1), ('b', 2), ('c', 3)". +/// +/// Now consider this twist where we add a call to `rev`. This version will +/// print `('c', 1), ('b', 2), ('a', 3)`. Note that the letters are reversed, +/// but the values of the counter still go in order. This is because `map()` is +/// still being called lazily on each item, but we are popping items off the +/// back of the vector now, instead of shifting them from the front. +/// +/// ```rust +/// let mut c = 0; +/// +/// for pair in vec!['a', 'b', 'c'].into_iter() +/// .map(|letter| { c += 1; (letter, c) }) +/// .rev() { +/// println!("{:?}", pair); +/// } +/// ``` +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[stable(feature = "rust1", since = "1.0.0")] +#[derive(Clone)] +pub struct Map { + iter: I, + f: F, +} +impl Map { + pub(super) fn new(iter: I, f: F) -> Map { + Map { iter, f } + } +} + +#[stable(feature = "core_impl_debug", since = "1.9.0")] +impl fmt::Debug for Map { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Map") + .field("iter", &self.iter) + .finish() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for Map where F: FnMut(I::Item) -> B { + type Item = B; + + #[inline] + fn next(&mut self) -> Option { + self.iter.next().map(&mut self.f) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + + fn try_fold(&mut self, init: Acc, mut g: G) -> R where + Self: Sized, G: FnMut(Acc, Self::Item) -> R, R: Try + { + let f = &mut self.f; + self.iter.try_fold(init, move |acc, elt| g(acc, f(elt))) + } + + fn fold(self, init: Acc, mut g: G) -> Acc + where G: FnMut(Acc, Self::Item) -> Acc, + { + let mut f = self.f; + self.iter.fold(init, move |acc, elt| g(acc, f(elt))) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl DoubleEndedIterator for Map where + F: FnMut(I::Item) -> B, +{ + #[inline] + fn next_back(&mut self) -> Option { + self.iter.next_back().map(&mut self.f) + } + + fn try_rfold(&mut self, init: Acc, mut g: G) -> R where + Self: Sized, G: FnMut(Acc, Self::Item) -> R, R: Try + { + let f = &mut self.f; + self.iter.try_rfold(init, move |acc, elt| g(acc, f(elt))) + } + + fn rfold(self, init: Acc, mut g: G) -> Acc + where G: FnMut(Acc, Self::Item) -> Acc, + { + let mut f = self.f; + self.iter.rfold(init, move |acc, elt| g(acc, f(elt))) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for Map + where F: FnMut(I::Item) -> B +{ + fn len(&self) -> usize { + self.iter.len() + } + + fn is_empty(&self) -> bool { + self.iter.is_empty() + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Map + where F: FnMut(I::Item) -> B {} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for Map + where I: TrustedLen, + F: FnMut(I::Item) -> B {} + +#[doc(hidden)] +unsafe impl TrustedRandomAccess for Map + where I: TrustedRandomAccess, + F: FnMut(I::Item) -> B, +{ + unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item { + (self.f)(self.iter.get_unchecked(i)) + } + #[inline] + fn may_have_side_effect() -> bool { true } +} + +/// An iterator that filters the elements of `iter` with `predicate`. +/// +/// This `struct` is created by the [`filter`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`filter`]: trait.Iterator.html#method.filter +/// [`Iterator`]: trait.Iterator.html +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[stable(feature = "rust1", since = "1.0.0")] +#[derive(Clone)] +pub struct Filter { + iter: I, + predicate: P, +} +impl Filter { + pub(super) fn new(iter: I, predicate: P) -> Filter { + Filter { iter, predicate } + } +} + +#[stable(feature = "core_impl_debug", since = "1.9.0")] +impl fmt::Debug for Filter { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Filter") + .field("iter", &self.iter) + .finish() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for Filter where P: FnMut(&I::Item) -> bool { + type Item = I::Item; + + #[inline] + fn next(&mut self) -> Option { + for x in &mut self.iter { + if (self.predicate)(&x) { + return Some(x); + } + } + None + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let (_, upper) = self.iter.size_hint(); + (0, upper) // can't know a lower bound, due to the predicate + } + + // this special case allows the compiler to make `.filter(_).count()` + // branchless. Barring perfect branch prediction (which is unattainable in + // the general case), this will be much faster in >90% of cases (containing + // virtually all real workloads) and only a tiny bit slower in the rest. + // + // Having this specialization thus allows us to write `.filter(p).count()` + // where we would otherwise write `.map(|x| p(x) as usize).sum()`, which is + // less readable and also less backwards-compatible to Rust before 1.10. + // + // 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 + } + + #[inline] + fn try_fold(&mut self, init: Acc, mut fold: Fold) -> R where + Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try + { + let predicate = &mut self.predicate; + self.iter.try_fold(init, move |acc, item| if predicate(&item) { + fold(acc, item) + } else { + Try::from_ok(acc) + }) + } + + #[inline] + fn fold(self, init: Acc, mut fold: Fold) -> Acc + where Fold: FnMut(Acc, Self::Item) -> Acc, + { + let mut predicate = self.predicate; + self.iter.fold(init, move |acc, item| if predicate(&item) { + fold(acc, item) + } else { + acc + }) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl DoubleEndedIterator for Filter + where P: FnMut(&I::Item) -> bool, +{ + #[inline] + fn next_back(&mut self) -> Option { + for x in self.iter.by_ref().rev() { + if (self.predicate)(&x) { + return Some(x); + } + } + None + } + + #[inline] + fn try_rfold(&mut self, init: Acc, mut fold: Fold) -> R where + Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try + { + let predicate = &mut self.predicate; + self.iter.try_rfold(init, move |acc, item| if predicate(&item) { + fold(acc, item) + } else { + Try::from_ok(acc) + }) + } + + #[inline] + fn rfold(self, init: Acc, mut fold: Fold) -> Acc + where Fold: FnMut(Acc, Self::Item) -> Acc, + { + let mut predicate = self.predicate; + self.iter.rfold(init, move |acc, item| if predicate(&item) { + fold(acc, item) + } else { + acc + }) + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Filter + where P: FnMut(&I::Item) -> bool {} + +/// An iterator that uses `f` to both filter and map elements from `iter`. +/// +/// This `struct` is created by the [`filter_map`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`filter_map`]: trait.Iterator.html#method.filter_map +/// [`Iterator`]: trait.Iterator.html +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[stable(feature = "rust1", since = "1.0.0")] +#[derive(Clone)] +pub struct FilterMap { + iter: I, + f: F, +} +impl FilterMap { + pub(super) fn new(iter: I, f: F) -> FilterMap { + FilterMap { iter, f } + } +} + +#[stable(feature = "core_impl_debug", since = "1.9.0")] +impl fmt::Debug for FilterMap { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("FilterMap") + .field("iter", &self.iter) + .finish() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for FilterMap + where F: FnMut(I::Item) -> Option, +{ + type Item = B; + + #[inline] + fn next(&mut self) -> Option { + for x in self.iter.by_ref() { + if let Some(y) = (self.f)(x) { + return Some(y); + } + } + None + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let (_, upper) = self.iter.size_hint(); + (0, upper) // can't know a lower bound, due to the predicate + } + + #[inline] + fn try_fold(&mut self, init: Acc, mut fold: Fold) -> R where + Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try + { + let f = &mut self.f; + self.iter.try_fold(init, move |acc, item| match f(item) { + Some(x) => fold(acc, x), + None => Try::from_ok(acc), + }) + } + + #[inline] + fn fold(self, init: Acc, mut fold: Fold) -> Acc + where Fold: FnMut(Acc, Self::Item) -> Acc, + { + let mut f = self.f; + self.iter.fold(init, move |acc, item| match f(item) { + Some(x) => fold(acc, x), + None => acc, + }) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl DoubleEndedIterator for FilterMap + where F: FnMut(I::Item) -> Option, +{ + #[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 + } + + #[inline] + fn try_rfold(&mut self, init: Acc, mut fold: Fold) -> R where + Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try + { + let f = &mut self.f; + self.iter.try_rfold(init, move |acc, item| match f(item) { + Some(x) => fold(acc, x), + None => Try::from_ok(acc), + }) + } + + #[inline] + fn rfold(self, init: Acc, mut fold: Fold) -> Acc + where Fold: FnMut(Acc, Self::Item) -> Acc, + { + let mut f = self.f; + self.iter.rfold(init, move |acc, item| match f(item) { + Some(x) => fold(acc, x), + None => acc, + }) + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for FilterMap + where F: FnMut(I::Item) -> Option {} + +/// An iterator that yields the current count and the element during iteration. +/// +/// This `struct` is created by the [`enumerate`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`enumerate`]: trait.Iterator.html#method.enumerate +/// [`Iterator`]: trait.Iterator.html +#[derive(Clone, Debug)] +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Enumerate { + iter: I, + count: usize, +} +impl Enumerate { + pub(super) fn new(iter: I) -> Enumerate { + Enumerate { iter, count: 0 } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for Enumerate where I: Iterator { + type Item = (usize, ::Item); + + /// # Overflow Behavior + /// + /// The method does no guarding against overflows, so enumerating more than + /// `usize::MAX` elements either produces the wrong result or panics. If + /// debug assertions are enabled, a panic is guaranteed. + /// + /// # Panics + /// + /// Might panic if the index of the element overflows a `usize`. + #[inline] + #[rustc_inherit_overflow_checks] + fn next(&mut self) -> Option<(usize, ::Item)> { + self.iter.next().map(|a| { + let ret = (self.count, a); + // Possible undefined overflow. + self.count += 1; + ret + }) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + + #[inline] + #[rustc_inherit_overflow_checks] + fn nth(&mut self, n: usize) -> Option<(usize, I::Item)> { + self.iter.nth(n).map(|a| { + let i = self.count + n; + self.count = i + 1; + (i, a) + }) + } + + #[inline] + fn count(self) -> usize { + self.iter.count() + } + + #[inline] + #[rustc_inherit_overflow_checks] + fn try_fold(&mut self, init: Acc, mut fold: Fold) -> R where + Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try + { + let count = &mut self.count; + self.iter.try_fold(init, move |acc, item| { + let acc = fold(acc, (*count, item)); + *count += 1; + acc + }) + } + + #[inline] + #[rustc_inherit_overflow_checks] + fn fold(self, init: Acc, mut fold: Fold) -> Acc + where Fold: FnMut(Acc, Self::Item) -> Acc, + { + let mut count = self.count; + self.iter.fold(init, move |acc, item| { + let acc = fold(acc, (count, item)); + count += 1; + acc + }) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl DoubleEndedIterator for Enumerate where + I: ExactSizeIterator + DoubleEndedIterator +{ + #[inline] + fn next_back(&mut self) -> Option<(usize, ::Item)> { + self.iter.next_back().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 + { + // Can safely add and subtract the count, as `ExactSizeIterator` promises + // that the number of elements fits into a `usize`. + let mut count = self.count + self.iter.len(); + self.iter.try_rfold(init, move |acc, item| { + count -= 1; + fold(acc, (count, item)) + }) + } + + #[inline] + fn rfold(self, init: Acc, mut fold: Fold) -> Acc + where Fold: FnMut(Acc, Self::Item) -> Acc, + { + // Can safely add and subtract the count, as `ExactSizeIterator` promises + // that the number of elements fits into a `usize`. + let mut count = self.count + self.iter.len(); + self.iter.rfold(init, move |acc, item| { + count -= 1; + fold(acc, (count, item)) + }) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for Enumerate where I: ExactSizeIterator { + fn len(&self) -> usize { + self.iter.len() + } + + fn is_empty(&self) -> bool { + self.iter.is_empty() + } +} + +#[doc(hidden)] +unsafe impl TrustedRandomAccess for Enumerate + where I: TrustedRandomAccess +{ + unsafe fn get_unchecked(&mut self, i: usize) -> (usize, I::Item) { + (self.count + i, self.iter.get_unchecked(i)) + } + + fn may_have_side_effect() -> bool { + I::may_have_side_effect() + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Enumerate where I: FusedIterator {} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for Enumerate + where I: TrustedLen, +{} + + +/// An iterator with a `peek()` that returns an optional reference to the next +/// element. +/// +/// This `struct` is created by the [`peekable`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`peekable`]: trait.Iterator.html#method.peekable +/// [`Iterator`]: trait.Iterator.html +#[derive(Clone, Debug)] +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Peekable { + iter: I, + /// Remember a peeked value, even if it was None. + peeked: Option>, +} +impl Peekable { + pub(super) fn new(iter: I) -> Peekable { + Peekable { iter, peeked: None } + } +} + +// Peekable must remember if a None has been seen in the `.peek()` method. +// It ensures that `.peek(); .peek();` or `.peek(); .next();` only advances the +// underlying iterator at most once. This does not by itself make the iterator +// fused. +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for Peekable { + type Item = I::Item; + + #[inline] + fn next(&mut self) -> Option { + match self.peeked.take() { + Some(v) => v, + None => self.iter.next(), + } + } + + #[inline] + #[rustc_inherit_overflow_checks] + fn count(mut self) -> usize { + match self.peeked.take() { + Some(None) => 0, + Some(Some(_)) => 1 + self.iter.count(), + None => self.iter.count(), + } + } + + #[inline] + fn nth(&mut self, n: usize) -> Option { + match self.peeked.take() { + Some(None) => None, + Some(v @ Some(_)) if n == 0 => v, + Some(Some(_)) => self.iter.nth(n - 1), + None => self.iter.nth(n), + } + } + + #[inline] + fn last(mut self) -> Option { + let peek_opt = match self.peeked.take() { + Some(None) => return None, + Some(v) => v, + None => None, + }; + self.iter.last().or(peek_opt) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let peek_len = match self.peeked { + Some(None) => return (0, Some(0)), + Some(Some(_)) => 1, + None => 0, + }; + let (lo, hi) = self.iter.size_hint(); + let lo = lo.saturating_add(peek_len); + let hi = hi.and_then(|x| x.checked_add(peek_len)); + (lo, hi) + } + + #[inline] + fn try_fold(&mut self, init: B, mut f: F) -> R where + Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try + { + let acc = match self.peeked.take() { + Some(None) => return Try::from_ok(init), + Some(Some(v)) => f(init, v)?, + None => init, + }; + self.iter.try_fold(acc, f) + } + + #[inline] + fn fold(self, init: Acc, mut fold: Fold) -> Acc + where Fold: FnMut(Acc, Self::Item) -> Acc, + { + let acc = match self.peeked { + Some(None) => return init, + Some(Some(v)) => fold(init, v), + None => init, + }; + self.iter.fold(acc, fold) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for Peekable {} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Peekable {} + +impl Peekable { + /// Returns a reference to the next() value without advancing the iterator. + /// + /// Like [`next`], if there is a value, it is wrapped in a `Some(T)`. + /// But if the iteration is over, `None` is returned. + /// + /// [`next`]: trait.Iterator.html#tymethod.next + /// + /// Because `peek()` returns a reference, and many iterators iterate over + /// references, there can be a possibly confusing situation where the + /// return value is a double reference. You can see this effect in the + /// examples below. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let xs = [1, 2, 3]; + /// + /// let mut iter = xs.iter().peekable(); + /// + /// // peek() lets us see into the future + /// assert_eq!(iter.peek(), Some(&&1)); + /// assert_eq!(iter.next(), Some(&1)); + /// + /// assert_eq!(iter.next(), Some(&2)); + /// + /// // The iterator does not advance even if we `peek` multiple times + /// assert_eq!(iter.peek(), Some(&&3)); + /// assert_eq!(iter.peek(), Some(&&3)); + /// + /// assert_eq!(iter.next(), Some(&3)); + /// + /// // After the iterator is finished, so is `peek()` + /// assert_eq!(iter.peek(), None); + /// assert_eq!(iter.next(), None); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn peek(&mut self) -> Option<&I::Item> { + let iter = &mut self.iter; + self.peeked.get_or_insert_with(|| iter.next()).as_ref() + } +} + +/// An iterator that rejects elements while `predicate` is true. +/// +/// This `struct` is created by the [`skip_while`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`skip_while`]: trait.Iterator.html#method.skip_while +/// [`Iterator`]: trait.Iterator.html +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[stable(feature = "rust1", since = "1.0.0")] +#[derive(Clone)] +pub struct SkipWhile { + iter: I, + flag: bool, + predicate: P, +} +impl SkipWhile { + pub(super) fn new(iter: I, predicate: P) -> SkipWhile { + SkipWhile { iter, flag: false, predicate } + } +} + +#[stable(feature = "core_impl_debug", since = "1.9.0")] +impl fmt::Debug for SkipWhile { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("SkipWhile") + .field("iter", &self.iter) + .field("flag", &self.flag) + .finish() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for SkipWhile + where P: FnMut(&I::Item) -> bool +{ + type Item = I::Item; + + #[inline] + fn next(&mut self) -> Option { + let flag = &mut self.flag; + let pred = &mut self.predicate; + self.iter.find(move |x| { + if *flag || !pred(x) { + *flag = true; + true + } else { + false + } + }) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let (_, upper) = self.iter.size_hint(); + (0, upper) // can't know a lower bound, due to the predicate + } + + #[inline] + fn try_fold(&mut self, mut init: Acc, mut fold: Fold) -> R where + Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try + { + if !self.flag { + match self.next() { + Some(v) => init = fold(init, v)?, + None => return Try::from_ok(init), + } + } + self.iter.try_fold(init, fold) + } + + #[inline] + fn fold(mut self, mut init: Acc, mut fold: Fold) -> Acc + where Fold: FnMut(Acc, Self::Item) -> Acc, + { + if !self.flag { + match self.next() { + Some(v) => init = fold(init, v), + None => return init, + } + } + self.iter.fold(init, fold) + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for SkipWhile + where I: FusedIterator, P: FnMut(&I::Item) -> bool {} + +/// An iterator that only accepts elements while `predicate` is true. +/// +/// This `struct` is created by the [`take_while`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`take_while`]: trait.Iterator.html#method.take_while +/// [`Iterator`]: trait.Iterator.html +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[stable(feature = "rust1", since = "1.0.0")] +#[derive(Clone)] +pub struct TakeWhile { + iter: I, + flag: bool, + predicate: P, +} +impl TakeWhile { + pub(super) fn new(iter: I, predicate: P) -> TakeWhile { + TakeWhile { iter, flag: false, predicate } + } +} + +#[stable(feature = "core_impl_debug", since = "1.9.0")] +impl fmt::Debug for TakeWhile { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("TakeWhile") + .field("iter", &self.iter) + .field("flag", &self.flag) + .finish() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for TakeWhile + where P: FnMut(&I::Item) -> bool +{ + type Item = I::Item; + + #[inline] + fn next(&mut self) -> Option { + if self.flag { + None + } else { + self.iter.next().and_then(|x| { + if (self.predicate)(&x) { + Some(x) + } else { + self.flag = true; + None + } + }) + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + if self.flag { + (0, Some(0)) + } else { + let (_, upper) = self.iter.size_hint(); + (0, upper) // can't know a lower bound, due to the predicate + } + } + + #[inline] + fn try_fold(&mut self, init: Acc, mut fold: Fold) -> R where + Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try + { + if self.flag { + Try::from_ok(init) + } else { + let flag = &mut self.flag; + let p = &mut self.predicate; + self.iter.try_fold(init, move |acc, x|{ + if p(&x) { + LoopState::from_try(fold(acc, x)) + } else { + *flag = true; + LoopState::Break(Try::from_ok(acc)) + } + }).into_try() + } + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for TakeWhile + where I: FusedIterator, P: FnMut(&I::Item) -> bool {} + +/// An iterator that skips over `n` elements of `iter`. +/// +/// This `struct` is created by the [`skip`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`skip`]: trait.Iterator.html#method.skip +/// [`Iterator`]: trait.Iterator.html +#[derive(Clone, Debug)] +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Skip { + iter: I, + n: usize +} +impl Skip { + pub(super) fn new(iter: I, n: usize) -> Skip { + Skip { iter, n } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for Skip where I: Iterator { + type Item = ::Item; + + #[inline] + fn next(&mut self) -> Option { + if self.n == 0 { + self.iter.next() + } else { + let old_n = self.n; + self.n = 0; + self.iter.nth(old_n) + } + } + + #[inline] + fn nth(&mut self, n: usize) -> Option { + // Can't just add n + self.n due to overflow. + if self.n == 0 { + self.iter.nth(n) + } else { + let to_skip = self.n; + self.n = 0; + // nth(n) skips n+1 + if self.iter.nth(to_skip-1).is_none() { + return None; + } + self.iter.nth(n) + } + } + + #[inline] + fn count(self) -> usize { + self.iter.count().saturating_sub(self.n) + } + + #[inline] + fn last(mut self) -> Option { + if self.n == 0 { + self.iter.last() + } else { + let next = self.next(); + if next.is_some() { + // recurse. n should be 0. + self.last().or(next) + } else { + None + } + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let (lower, upper) = self.iter.size_hint(); + + let lower = lower.saturating_sub(self.n); + let upper = upper.map(|x| x.saturating_sub(self.n)); + + (lower, upper) + } + + #[inline] + fn try_fold(&mut self, init: Acc, fold: Fold) -> R where + Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try + { + let n = self.n; + self.n = 0; + if n > 0 { + // nth(n) skips n+1 + if self.iter.nth(n - 1).is_none() { + return Try::from_ok(init); + } + } + self.iter.try_fold(init, fold) + } + + #[inline] + fn fold(mut self, init: Acc, fold: Fold) -> Acc + where Fold: FnMut(Acc, Self::Item) -> Acc, + { + if self.n > 0 { + // nth(n) skips n+1 + if self.iter.nth(self.n - 1).is_none() { + return init; + } + } + self.iter.fold(init, fold) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for Skip where I: ExactSizeIterator {} + +#[stable(feature = "double_ended_skip_iterator", since = "1.9.0")] +impl DoubleEndedIterator for Skip where I: DoubleEndedIterator + ExactSizeIterator { + fn next_back(&mut self) -> Option { + if self.len() > 0 { + self.iter.next_back() + } else { + None + } + } + + fn try_rfold(&mut self, init: Acc, mut fold: Fold) -> R where + Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try + { + let mut n = self.len(); + if n == 0 { + Try::from_ok(init) + } else { + self.iter.try_rfold(init, move |acc, x| { + n -= 1; + let r = fold(acc, x); + if n == 0 { LoopState::Break(r) } + else { LoopState::from_try(r) } + }).into_try() + } + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Skip where I: FusedIterator {} + +/// An iterator that only iterates over the first `n` iterations of `iter`. +/// +/// This `struct` is created by the [`take`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`take`]: trait.Iterator.html#method.take +/// [`Iterator`]: trait.Iterator.html +#[derive(Clone, Debug)] +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Take { + pub(super) iter: I, + pub(super) n: usize +} +impl Take { + pub(super) fn new(iter: I, n: usize) -> Take { + Take { iter, n } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for Take where I: Iterator{ + type Item = ::Item; + + #[inline] + fn next(&mut self) -> Option<::Item> { + if self.n != 0 { + self.n -= 1; + self.iter.next() + } else { + None + } + } + + #[inline] + fn nth(&mut self, n: usize) -> Option { + if self.n > n { + self.n -= n + 1; + self.iter.nth(n) + } else { + if self.n > 0 { + self.iter.nth(self.n - 1); + self.n = 0; + } + None + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + if self.n == 0 { + return (0, Some(0)); + } + + let (lower, upper) = self.iter.size_hint(); + + let lower = cmp::min(lower, self.n); + + let upper = match upper { + Some(x) if x < self.n => Some(x), + _ => Some(self.n) + }; + + (lower, upper) + } + + #[inline] + fn try_fold(&mut self, init: Acc, mut fold: Fold) -> R where + Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try + { + if self.n == 0 { + Try::from_ok(init) + } else { + let n = &mut self.n; + self.iter.try_fold(init, move |acc, x| { + *n -= 1; + let r = fold(acc, x); + if *n == 0 { LoopState::Break(r) } + else { LoopState::from_try(r) } + }).into_try() + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for Take where I: ExactSizeIterator {} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Take where I: FusedIterator {} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for Take {} + +/// An iterator to maintain state while iterating another iterator. +/// +/// This `struct` is created by the [`scan`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`scan`]: trait.Iterator.html#method.scan +/// [`Iterator`]: trait.Iterator.html +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[stable(feature = "rust1", since = "1.0.0")] +#[derive(Clone)] +pub struct Scan { + iter: I, + f: F, + state: St, +} +impl Scan { + pub(super) fn new(iter: I, state: St, f: F) -> Scan { + Scan { iter, state, f } + } +} + +#[stable(feature = "core_impl_debug", since = "1.9.0")] +impl fmt::Debug for Scan { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Scan") + .field("iter", &self.iter) + .field("state", &self.state) + .finish() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for Scan where + I: Iterator, + F: FnMut(&mut St, I::Item) -> Option, +{ + type Item = B; + + #[inline] + fn next(&mut self) -> Option { + self.iter.next().and_then(|a| (self.f)(&mut self.state, a)) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let (_, upper) = self.iter.size_hint(); + (0, upper) // can't know a lower bound, due to the scan function + } + + #[inline] + fn try_fold(&mut self, init: Acc, mut fold: Fold) -> R where + Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try + { + let state = &mut self.state; + let f = &mut self.f; + self.iter.try_fold(init, move |acc, x| { + match f(state, x) { + None => LoopState::Break(Try::from_ok(acc)), + Some(x) => LoopState::from_try(fold(acc, x)), + } + }).into_try() + } +} + +/// An iterator that yields `None` forever after the underlying iterator +/// yields `None` once. +/// +/// This `struct` is created by the [`fuse`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`fuse`]: trait.Iterator.html#method.fuse +/// [`Iterator`]: trait.Iterator.html +#[derive(Clone, Debug)] +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Fuse { + iter: I, + done: bool +} +impl Fuse { + pub(super) fn new(iter: I) -> Fuse { + Fuse { iter, done: false } + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Fuse where I: Iterator {} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for Fuse where I: Iterator { + type Item = ::Item; + + #[inline] + default fn next(&mut self) -> Option<::Item> { + if self.done { + None + } else { + let next = self.iter.next(); + self.done = next.is_none(); + next + } + } + + #[inline] + default fn nth(&mut self, n: usize) -> Option { + if self.done { + None + } else { + let nth = self.iter.nth(n); + self.done = nth.is_none(); + nth + } + } + + #[inline] + default fn last(self) -> Option { + if self.done { + None + } else { + self.iter.last() + } + } + + #[inline] + default fn count(self) -> usize { + if self.done { + 0 + } else { + self.iter.count() + } + } + + #[inline] + default fn size_hint(&self) -> (usize, Option) { + if self.done { + (0, Some(0)) + } else { + self.iter.size_hint() + } + } + + #[inline] + default fn try_fold(&mut self, init: Acc, fold: Fold) -> R where + Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try + { + if self.done { + Try::from_ok(init) + } else { + let acc = self.iter.try_fold(init, fold)?; + self.done = true; + Try::from_ok(acc) + } + } + + #[inline] + default fn fold(self, init: Acc, fold: Fold) -> Acc + where Fold: FnMut(Acc, Self::Item) -> Acc, + { + if self.done { + init + } else { + self.iter.fold(init, fold) + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl DoubleEndedIterator for Fuse where I: DoubleEndedIterator { + #[inline] + default fn next_back(&mut self) -> Option<::Item> { + if self.done { + None + } else { + let next = self.iter.next_back(); + self.done = next.is_none(); + next + } + } + + #[inline] + default fn try_rfold(&mut self, init: Acc, fold: Fold) -> R where + Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try + { + if self.done { + Try::from_ok(init) + } else { + let acc = self.iter.try_rfold(init, fold)?; + self.done = true; + Try::from_ok(acc) + } + } + + #[inline] + default fn rfold(self, init: Acc, fold: Fold) -> Acc + where Fold: FnMut(Acc, Self::Item) -> Acc, + { + if self.done { + init + } else { + self.iter.rfold(init, fold) + } + } +} + +unsafe impl TrustedRandomAccess for Fuse + where I: TrustedRandomAccess, +{ + unsafe fn get_unchecked(&mut self, i: usize) -> I::Item { + self.iter.get_unchecked(i) + } + + fn may_have_side_effect() -> bool { + I::may_have_side_effect() + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl Iterator for Fuse where I: FusedIterator { + #[inline] + fn next(&mut self) -> Option<::Item> { + self.iter.next() + } + + #[inline] + fn nth(&mut self, n: usize) -> Option { + self.iter.nth(n) + } + + #[inline] + fn last(self) -> Option { + self.iter.last() + } + + #[inline] + fn count(self) -> usize { + self.iter.count() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + + #[inline] + fn try_fold(&mut self, init: Acc, fold: Fold) -> R where + Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try + { + self.iter.try_fold(init, fold) + } + + #[inline] + fn fold(self, init: Acc, fold: Fold) -> Acc + where Fold: FnMut(Acc, Self::Item) -> Acc, + { + self.iter.fold(init, fold) + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl DoubleEndedIterator for Fuse + where I: DoubleEndedIterator + FusedIterator +{ + #[inline] + fn next_back(&mut self) -> Option<::Item> { + self.iter.next_back() + } + + #[inline] + fn try_rfold(&mut self, init: Acc, fold: Fold) -> R where + Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try + { + self.iter.try_rfold(init, fold) + } + + #[inline] + fn rfold(self, init: Acc, fold: Fold) -> Acc + where Fold: FnMut(Acc, Self::Item) -> Acc, + { + self.iter.rfold(init, fold) + } +} + + +#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for Fuse where I: ExactSizeIterator { + fn len(&self) -> usize { + self.iter.len() + } + + fn is_empty(&self) -> bool { + self.iter.is_empty() + } +} + +/// An iterator that calls a function with a reference to each element before +/// yielding it. +/// +/// This `struct` is created by the [`inspect`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`inspect`]: trait.Iterator.html#method.inspect +/// [`Iterator`]: trait.Iterator.html +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[stable(feature = "rust1", since = "1.0.0")] +#[derive(Clone)] +pub struct Inspect { + iter: I, + f: F, +} +impl Inspect { + pub(super) fn new(iter: I, f: F) -> Inspect { + Inspect { iter, f } + } +} + +#[stable(feature = "core_impl_debug", since = "1.9.0")] +impl fmt::Debug for Inspect { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Inspect") + .field("iter", &self.iter) + .finish() + } +} + +impl Inspect where F: FnMut(&I::Item) { + #[inline] + fn do_inspect(&mut self, elt: Option) -> Option { + if let Some(ref a) = elt { + (self.f)(a); + } + + elt + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for Inspect where F: FnMut(&I::Item) { + type Item = I::Item; + + #[inline] + fn next(&mut self) -> Option { + let next = self.iter.next(); + self.do_inspect(next) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + + #[inline] + fn try_fold(&mut self, init: Acc, mut fold: Fold) -> R where + Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try + { + let f = &mut self.f; + self.iter.try_fold(init, move |acc, item| { f(&item); fold(acc, item) }) + } + + #[inline] + fn fold(self, init: Acc, mut fold: Fold) -> Acc + where Fold: FnMut(Acc, Self::Item) -> Acc, + { + let mut f = self.f; + self.iter.fold(init, move |acc, item| { f(&item); fold(acc, item) }) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl DoubleEndedIterator for Inspect + where F: FnMut(&I::Item), +{ + #[inline] + fn next_back(&mut self) -> Option { + let next = self.iter.next_back(); + self.do_inspect(next) + } + + #[inline] + fn try_rfold(&mut self, init: Acc, mut fold: Fold) -> R where + Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try + { + let f = &mut self.f; + self.iter.try_rfold(init, move |acc, item| { f(&item); fold(acc, item) }) + } + + #[inline] + fn rfold(self, init: Acc, mut fold: Fold) -> Acc + where Fold: FnMut(Acc, Self::Item) -> Acc, + { + let mut f = self.f; + self.iter.rfold(init, move |acc, item| { f(&item); fold(acc, item) }) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for Inspect + where F: FnMut(&I::Item) +{ + fn len(&self) -> usize { + self.iter.len() + } + + fn is_empty(&self) -> bool { + self.iter.is_empty() + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Inspect + where F: FnMut(&I::Item) {} diff --git a/src/libcore/iter/adapters/zip.rs b/src/libcore/iter/adapters/zip.rs new file mode 100644 index 0000000000000..3548d0e282602 --- /dev/null +++ b/src/libcore/iter/adapters/zip.rs @@ -0,0 +1,282 @@ +use cmp; +use super::super::{Iterator, DoubleEndedIterator, ExactSizeIterator, FusedIterator, TrustedLen}; + +/// An iterator that iterates two other iterators simultaneously. +/// +/// This `struct` is created by the [`zip`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`zip`]: trait.Iterator.html#method.zip +/// [`Iterator`]: trait.Iterator.html +#[derive(Clone, Debug)] +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Zip { + a: A, + b: B, + // index and len are only used by the specialized version of zip + index: usize, + len: usize, +} +impl Zip { + pub(in super::super) fn new(a: A, b: B) -> Zip { + ZipImpl::new(a, b) + } + fn super_nth(&mut self, mut n: usize) -> Option<(A::Item, B::Item)> { + while let Some(x) = Iterator::next(self) { + if n == 0 { return Some(x) } + n -= 1; + } + None + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for Zip where A: Iterator, B: Iterator +{ + type Item = (A::Item, B::Item); + + #[inline] + fn next(&mut self) -> Option { + ZipImpl::next(self) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + ZipImpl::size_hint(self) + } + + #[inline] + fn nth(&mut self, n: usize) -> Option { + ZipImpl::nth(self, n) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl DoubleEndedIterator for Zip where + A: DoubleEndedIterator + ExactSizeIterator, + B: DoubleEndedIterator + ExactSizeIterator, +{ + #[inline] + fn next_back(&mut self) -> Option<(A::Item, B::Item)> { + ZipImpl::next_back(self) + } +} + +// Zip specialization trait +#[doc(hidden)] +trait ZipImpl { + type Item; + fn new(a: A, b: B) -> Self; + fn next(&mut self) -> Option; + fn size_hint(&self) -> (usize, Option); + fn nth(&mut self, n: usize) -> Option; + fn next_back(&mut self) -> Option + where A: DoubleEndedIterator + ExactSizeIterator, + B: DoubleEndedIterator + ExactSizeIterator; +} + +// General Zip impl +#[doc(hidden)] +impl ZipImpl for Zip + where A: Iterator, B: Iterator +{ + type Item = (A::Item, B::Item); + default fn new(a: A, b: B) -> Self { + Zip { + a, + b, + index: 0, // unused + len: 0, // unused + } + } + + #[inline] + default fn next(&mut self) -> Option<(A::Item, B::Item)> { + self.a.next().and_then(|x| { + self.b.next().and_then(|y| { + Some((x, y)) + }) + }) + } + + #[inline] + default fn nth(&mut self, n: usize) -> Option { + self.super_nth(n) + } + + #[inline] + default fn next_back(&mut self) -> Option<(A::Item, B::Item)> + where A: DoubleEndedIterator + ExactSizeIterator, + B: DoubleEndedIterator + ExactSizeIterator + { + let a_sz = self.a.len(); + let b_sz = self.b.len(); + if a_sz != b_sz { + // Adjust a, b to equal length + if a_sz > b_sz { + for _ in 0..a_sz - b_sz { self.a.next_back(); } + } else { + for _ in 0..b_sz - a_sz { self.b.next_back(); } + } + } + match (self.a.next_back(), self.b.next_back()) { + (Some(x), Some(y)) => Some((x, y)), + (None, None) => None, + _ => unreachable!(), + } + } + + #[inline] + default fn size_hint(&self) -> (usize, Option) { + let (a_lower, a_upper) = self.a.size_hint(); + let (b_lower, b_upper) = self.b.size_hint(); + + let lower = cmp::min(a_lower, b_lower); + + let upper = match (a_upper, b_upper) { + (Some(x), Some(y)) => Some(cmp::min(x,y)), + (Some(x), None) => Some(x), + (None, Some(y)) => Some(y), + (None, None) => None + }; + + (lower, upper) + } +} + +#[doc(hidden)] +impl ZipImpl for Zip + where A: TrustedRandomAccess, B: TrustedRandomAccess +{ + fn new(a: A, b: B) -> Self { + let len = cmp::min(a.len(), b.len()); + Zip { + a, + b, + index: 0, + len, + } + } + + #[inline] + fn next(&mut self) -> Option<(A::Item, B::Item)> { + if self.index < self.len { + let i = self.index; + self.index += 1; + unsafe { + Some((self.a.get_unchecked(i), self.b.get_unchecked(i))) + } + } else if A::may_have_side_effect() && self.index < self.a.len() { + // match the base implementation's potential side effects + unsafe { + self.a.get_unchecked(self.index); + } + self.index += 1; + None + } else { + None + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let len = self.len - self.index; + (len, Some(len)) + } + + #[inline] + fn nth(&mut self, n: usize) -> Option { + let delta = cmp::min(n, self.len - self.index); + let end = self.index + delta; + while self.index < end { + let i = self.index; + self.index += 1; + if A::may_have_side_effect() { + unsafe { self.a.get_unchecked(i); } + } + if B::may_have_side_effect() { + unsafe { self.b.get_unchecked(i); } + } + } + + self.super_nth(n - delta) + } + + #[inline] + fn next_back(&mut self) -> Option<(A::Item, B::Item)> + where A: DoubleEndedIterator + ExactSizeIterator, + B: DoubleEndedIterator + ExactSizeIterator + { + // Adjust a, b to equal length + if A::may_have_side_effect() { + let sz = self.a.len(); + if sz > self.len { + for _ in 0..sz - cmp::max(self.len, self.index) { + self.a.next_back(); + } + } + } + if B::may_have_side_effect() { + let sz = self.b.len(); + if sz > self.len { + for _ in 0..sz - self.len { + self.b.next_back(); + } + } + } + if self.index < self.len { + self.len -= 1; + let i = self.len; + unsafe { + Some((self.a.get_unchecked(i), self.b.get_unchecked(i))) + } + } else { + None + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for Zip + where A: ExactSizeIterator, B: ExactSizeIterator {} + +#[doc(hidden)] +unsafe impl TrustedRandomAccess for Zip + where A: TrustedRandomAccess, + B: TrustedRandomAccess, +{ + unsafe fn get_unchecked(&mut self, i: usize) -> (A::Item, B::Item) { + (self.a.get_unchecked(i), self.b.get_unchecked(i)) + } + + fn may_have_side_effect() -> bool { + A::may_have_side_effect() || B::may_have_side_effect() + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Zip + where A: FusedIterator, B: FusedIterator, {} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for Zip + where A: TrustedLen, B: TrustedLen, +{} + +/// An iterator whose items are random-accessible efficiently +/// +/// # Safety +/// +/// The iterator's .len() and size_hint() must be exact. +/// `.len()` must be cheap to call. +/// +/// .get_unchecked() must return distinct mutable references for distinct +/// indices (if applicable), and must return a valid reference if index is in +/// 0..self.len(). +pub(crate) unsafe trait TrustedRandomAccess : ExactSizeIterator { + unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item; + /// Returns `true` if getting an iterator element may have + /// side effects. Remember to take inner iterators into account. + fn may_have_side_effect() -> bool; +} diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index 974906b682d21..5dcca7ee0ca01 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -306,15 +306,10 @@ #![stable(feature = "rust1", since = "1.0.0")] -use cmp; -use fmt; -use iter_private::TrustedRandomAccess; use ops::Try; -use usize; -use intrinsics; #[stable(feature = "rust1", since = "1.0.0")] -pub use self::iterator::Iterator; +pub use self::traits::Iterator; #[unstable(feature = "step_trait", reason = "likely to be replaced by finer-grained traits", @@ -331,8 +326,10 @@ pub use self::sources::{Empty, empty}; pub use self::sources::{Once, once}; #[unstable(feature = "iter_once_with", issue = "57581")] pub use self::sources::{OnceWith, once_with}; -#[unstable(feature = "iter_unfold", issue = "55977")] -pub use self::sources::{Unfold, unfold, Successors, successors}; +#[stable(feature = "iter_from_fn", since = "1.34.0")] +pub use self::sources::{FromFn, from_fn}; +#[stable(feature = "iter_successors", since = "1.34.0")] +pub use self::sources::{Successors, successors}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::traits::{FromIterator, IntoIterator, DoubleEndedIterator, Extend}; @@ -343,10 +340,27 @@ pub use self::traits::FusedIterator; #[unstable(feature = "trusted_len", issue = "37572")] pub use self::traits::TrustedLen; -mod iterator; +#[stable(feature = "rust1", since = "1.0.0")] +pub use self::adapters::{Rev, Cycle, Chain, Zip, Map, Filter, FilterMap, Enumerate}; +#[stable(feature = "rust1", since = "1.0.0")] +pub use self::adapters::{Peekable, SkipWhile, TakeWhile, Skip, Take, Scan, FlatMap}; +#[stable(feature = "rust1", since = "1.0.0")] +pub use self::adapters::{Fuse, Inspect}; +#[stable(feature = "iter_cloned", since = "1.1.0")] +pub use self::adapters::Cloned; +#[stable(feature = "iterator_step_by", since = "1.28.0")] +pub use self::adapters::StepBy; +#[stable(feature = "iterator_flatten", since = "1.29.0")] +pub use self::adapters::Flatten; +#[unstable(feature = "iter_copied", issue = "57127")] +pub use self::adapters::Copied; + +pub(crate) use self::adapters::TrustedRandomAccess; + mod range; mod sources; mod traits; +mod adapters; /// Used to make try_fold closures more like normal loops #[derive(PartialEq)] @@ -397,2767 +411,3 @@ impl LoopState { } } } - -/// A double-ended iterator with the direction inverted. -/// -/// This `struct` is created by the [`rev`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`rev`]: trait.Iterator.html#method.rev -/// [`Iterator`]: trait.Iterator.html -#[derive(Clone, Debug)] -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Rev { - iter: T -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for Rev where I: DoubleEndedIterator { - type Item = ::Item; - - #[inline] - fn next(&mut self) -> Option<::Item> { self.iter.next_back() } - #[inline] - fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } - - #[inline] - fn nth(&mut self, n: usize) -> Option<::Item> { self.iter.nth_back(n) } - - fn try_fold(&mut self, init: B, f: F) -> R where - Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try - { - self.iter.try_rfold(init, f) - } - - fn fold(self, init: Acc, f: F) -> Acc - where F: FnMut(Acc, Self::Item) -> Acc, - { - self.iter.rfold(init, f) - } - - #[inline] - fn find

(&mut self, predicate: P) -> Option - where P: FnMut(&Self::Item) -> bool - { - self.iter.rfind(predicate) - } - - #[inline] - fn rposition

(&mut self, predicate: P) -> Option where - P: FnMut(Self::Item) -> bool - { - self.iter.position(predicate) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl DoubleEndedIterator for Rev where I: DoubleEndedIterator { - #[inline] - fn next_back(&mut self) -> Option<::Item> { self.iter.next() } - - #[inline] - fn nth_back(&mut self, n: usize) -> Option<::Item> { self.iter.nth(n) } - - fn try_rfold(&mut self, init: B, f: F) -> R where - Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try - { - self.iter.try_fold(init, f) - } - - fn rfold(self, init: Acc, f: F) -> Acc - where F: FnMut(Acc, Self::Item) -> Acc, - { - self.iter.fold(init, f) - } - - fn rfind

(&mut self, predicate: P) -> Option - where P: FnMut(&Self::Item) -> bool - { - self.iter.find(predicate) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for Rev - where I: ExactSizeIterator + DoubleEndedIterator -{ - fn len(&self) -> usize { - self.iter.len() - } - - fn is_empty(&self) -> bool { - self.iter.is_empty() - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Rev - where I: FusedIterator + DoubleEndedIterator {} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for Rev - where I: TrustedLen + DoubleEndedIterator {} - -/// An iterator that copies the elements of an underlying iterator. -/// -/// This `struct` is created by the [`copied`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`copied`]: trait.Iterator.html#method.copied -/// [`Iterator`]: trait.Iterator.html -#[unstable(feature = "iter_copied", issue = "57127")] -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[derive(Clone, Debug)] -pub struct Copied { - it: I, -} - -#[unstable(feature = "iter_copied", issue = "57127")] -impl<'a, I, T: 'a> Iterator for Copied - where I: Iterator, T: Copy -{ - type Item = T; - - fn next(&mut self) -> Option { - self.it.next().copied() - } - - fn size_hint(&self) -> (usize, Option) { - self.it.size_hint() - } - - fn try_fold(&mut self, init: B, mut f: F) -> R where - Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try - { - self.it.try_fold(init, move |acc, &elt| f(acc, elt)) - } - - fn fold(self, init: Acc, mut f: F) -> Acc - where F: FnMut(Acc, Self::Item) -> Acc, - { - self.it.fold(init, move |acc, &elt| f(acc, elt)) - } -} - -#[unstable(feature = "iter_copied", issue = "57127")] -impl<'a, I, T: 'a> DoubleEndedIterator for Copied - where I: DoubleEndedIterator, T: Copy -{ - fn next_back(&mut self) -> Option { - self.it.next_back().copied() - } - - fn try_rfold(&mut self, init: B, mut f: F) -> R where - Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try - { - self.it.try_rfold(init, move |acc, &elt| f(acc, elt)) - } - - fn rfold(self, init: Acc, mut f: F) -> Acc - where F: FnMut(Acc, Self::Item) -> Acc, - { - self.it.rfold(init, move |acc, &elt| f(acc, elt)) - } -} - -#[unstable(feature = "iter_copied", issue = "57127")] -impl<'a, I, T: 'a> ExactSizeIterator for Copied - where I: ExactSizeIterator, T: Copy -{ - fn len(&self) -> usize { - self.it.len() - } - - fn is_empty(&self) -> bool { - self.it.is_empty() - } -} - -#[unstable(feature = "iter_copied", issue = "57127")] -impl<'a, I, T: 'a> FusedIterator for Copied - where I: FusedIterator, T: Copy -{} - -#[doc(hidden)] -unsafe impl<'a, I, T: 'a> TrustedRandomAccess for Copied - where I: TrustedRandomAccess, T: Copy -{ - unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item { - *self.it.get_unchecked(i) - } - - #[inline] - fn may_have_side_effect() -> bool { - I::may_have_side_effect() - } -} - -#[unstable(feature = "iter_copied", issue = "57127")] -unsafe impl<'a, I, T: 'a> TrustedLen for Copied - where I: TrustedLen, - T: Copy -{} - -/// An iterator that clones the elements of an underlying iterator. -/// -/// This `struct` is created by the [`cloned`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`cloned`]: trait.Iterator.html#method.cloned -/// [`Iterator`]: trait.Iterator.html -#[stable(feature = "iter_cloned", since = "1.1.0")] -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[derive(Clone, Debug)] -pub struct Cloned { - it: I, -} - -#[stable(feature = "iter_cloned", since = "1.1.0")] -impl<'a, I, T: 'a> Iterator for Cloned - where I: Iterator, T: Clone -{ - type Item = T; - - fn next(&mut self) -> Option { - self.it.next().cloned() - } - - fn size_hint(&self) -> (usize, Option) { - self.it.size_hint() - } - - fn try_fold(&mut self, init: B, mut f: F) -> R where - Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try - { - self.it.try_fold(init, move |acc, elt| f(acc, elt.clone())) - } - - fn fold(self, init: Acc, mut f: F) -> Acc - where F: FnMut(Acc, Self::Item) -> Acc, - { - self.it.fold(init, move |acc, elt| f(acc, elt.clone())) - } -} - -#[stable(feature = "iter_cloned", since = "1.1.0")] -impl<'a, I, T: 'a> DoubleEndedIterator for Cloned - where I: DoubleEndedIterator, T: Clone -{ - fn next_back(&mut self) -> Option { - self.it.next_back().cloned() - } - - fn try_rfold(&mut self, init: B, mut f: F) -> R where - Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try - { - self.it.try_rfold(init, move |acc, elt| f(acc, elt.clone())) - } - - fn rfold(self, init: Acc, mut f: F) -> Acc - where F: FnMut(Acc, Self::Item) -> Acc, - { - self.it.rfold(init, move |acc, elt| f(acc, elt.clone())) - } -} - -#[stable(feature = "iter_cloned", since = "1.1.0")] -impl<'a, I, T: 'a> ExactSizeIterator for Cloned - where I: ExactSizeIterator, T: Clone -{ - fn len(&self) -> usize { - self.it.len() - } - - fn is_empty(&self) -> bool { - self.it.is_empty() - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl<'a, I, T: 'a> FusedIterator for Cloned - where I: FusedIterator, T: Clone -{} - -#[doc(hidden)] -unsafe impl<'a, I, T: 'a> TrustedRandomAccess for Cloned - where I: TrustedRandomAccess, T: Clone -{ - default unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item { - self.it.get_unchecked(i).clone() - } - - #[inline] - default fn may_have_side_effect() -> bool { true } -} - -#[doc(hidden)] -unsafe impl<'a, I, T: 'a> TrustedRandomAccess for Cloned - where I: TrustedRandomAccess, T: Copy -{ - unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item { - *self.it.get_unchecked(i) - } - - #[inline] - fn may_have_side_effect() -> bool { - I::may_have_side_effect() - } -} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl<'a, I, T: 'a> TrustedLen for Cloned - where I: TrustedLen, - T: Clone -{} - -/// An iterator that repeats endlessly. -/// -/// This `struct` is created by the [`cycle`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`cycle`]: trait.Iterator.html#method.cycle -/// [`Iterator`]: trait.Iterator.html -#[derive(Clone, Debug)] -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Cycle { - orig: I, - iter: I, -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for Cycle where I: Clone + Iterator { - type Item = ::Item; - - #[inline] - fn next(&mut self) -> Option<::Item> { - match self.iter.next() { - None => { self.iter = self.orig.clone(); self.iter.next() } - y => y - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - // the cycle iterator is either empty or infinite - match self.orig.size_hint() { - sz @ (0, Some(0)) => sz, - (0, _) => (0, None), - _ => (usize::MAX, None) - } - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Cycle where I: Clone + Iterator {} - -/// An iterator for stepping iterators by a custom amount. -/// -/// This `struct` is created by the [`step_by`] method on [`Iterator`]. See -/// its documentation for more. -/// -/// [`step_by`]: trait.Iterator.html#method.step_by -/// [`Iterator`]: trait.Iterator.html -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[stable(feature = "iterator_step_by", since = "1.28.0")] -#[derive(Clone, Debug)] -pub struct StepBy { - iter: I, - step: usize, - first_take: bool, -} - -#[stable(feature = "iterator_step_by", since = "1.28.0")] -impl Iterator for StepBy where I: Iterator { - type Item = I::Item; - - #[inline] - fn next(&mut self) -> Option { - if self.first_take { - self.first_take = false; - self.iter.next() - } else { - self.iter.nth(self.step) - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let inner_hint = self.iter.size_hint(); - - if self.first_take { - let f = |n| if n == 0 { 0 } else { 1 + (n-1)/(self.step+1) }; - (f(inner_hint.0), inner_hint.1.map(f)) - } else { - let f = |n| n / (self.step+1); - (f(inner_hint.0), inner_hint.1.map(f)) - } - } - - #[inline] - fn nth(&mut self, mut n: usize) -> Option { - if self.first_take { - self.first_take = false; - let first = self.iter.next(); - if n == 0 { - return first; - } - n -= 1; - } - // n and self.step are indices, we need to add 1 to get the amount of elements - // When calling `.nth`, we need to subtract 1 again to convert back to an index - // step + 1 can't overflow because `.step_by` sets `self.step` to `step - 1` - let mut step = self.step + 1; - // n + 1 could overflow - // thus, if n is usize::MAX, instead of adding one, we call .nth(step) - if n == usize::MAX { - self.iter.nth(step - 1); - } else { - n += 1; - } - - // overflow handling - loop { - let mul = n.checked_mul(step); - if unsafe { intrinsics::likely(mul.is_some()) } { - return self.iter.nth(mul.unwrap() - 1); - } - let div_n = usize::MAX / n; - let div_step = usize::MAX / step; - let nth_n = div_n * n; - let nth_step = div_step * step; - let nth = if nth_n > nth_step { - step -= div_n; - nth_n - } else { - n -= div_step; - nth_step - }; - self.iter.nth(nth - 1); - } - } -} - -// StepBy can only make the iterator shorter, so the len will still fit. -#[stable(feature = "iterator_step_by", since = "1.28.0")] -impl ExactSizeIterator for StepBy where I: ExactSizeIterator {} - -/// An iterator that strings two iterators together. -/// -/// This `struct` is created by the [`chain`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`chain`]: trait.Iterator.html#method.chain -/// [`Iterator`]: trait.Iterator.html -#[derive(Clone, Debug)] -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Chain { - a: A, - b: B, - state: ChainState, -} - -// The iterator protocol specifies that iteration ends with the return value -// `None` from `.next()` (or `.next_back()`) and it is unspecified what -// further calls return. The chain adaptor must account for this since it uses -// two subiterators. -// -// It uses three states: -// -// - Both: `a` and `b` are remaining -// - Front: `a` remaining -// - Back: `b` remaining -// -// The fourth state (neither iterator is remaining) only occurs after Chain has -// returned None once, so we don't need to store this state. -#[derive(Clone, Debug)] -enum ChainState { - // both front and back iterator are remaining - Both, - // only front is remaining - Front, - // only back is remaining - Back, -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for Chain where - A: Iterator, - B: Iterator -{ - type Item = A::Item; - - #[inline] - fn next(&mut self) -> Option { - match self.state { - ChainState::Both => match self.a.next() { - elt @ Some(..) => elt, - None => { - self.state = ChainState::Back; - self.b.next() - } - }, - ChainState::Front => self.a.next(), - ChainState::Back => self.b.next(), - } - } - - #[inline] - #[rustc_inherit_overflow_checks] - fn count(self) -> usize { - match self.state { - ChainState::Both => self.a.count() + self.b.count(), - ChainState::Front => self.a.count(), - ChainState::Back => self.b.count(), - } - } - - fn try_fold(&mut self, init: Acc, mut f: F) -> R where - Self: Sized, F: FnMut(Acc, Self::Item) -> R, R: Try - { - let mut accum = init; - match self.state { - ChainState::Both | ChainState::Front => { - accum = self.a.try_fold(accum, &mut f)?; - if let ChainState::Both = self.state { - self.state = ChainState::Back; - } - } - _ => { } - } - if let ChainState::Back = self.state { - accum = self.b.try_fold(accum, &mut f)?; - } - Try::from_ok(accum) - } - - fn fold(self, init: Acc, mut f: F) -> Acc - where F: FnMut(Acc, Self::Item) -> Acc, - { - let mut accum = init; - match self.state { - ChainState::Both | ChainState::Front => { - accum = self.a.fold(accum, &mut f); - } - _ => { } - } - match self.state { - ChainState::Both | ChainState::Back => { - accum = self.b.fold(accum, &mut f); - } - _ => { } - } - accum - } - - #[inline] - fn nth(&mut self, mut n: usize) -> Option { - match self.state { - ChainState::Both | ChainState::Front => { - for x in self.a.by_ref() { - if n == 0 { - return Some(x) - } - n -= 1; - } - if let ChainState::Both = self.state { - self.state = ChainState::Back; - } - } - ChainState::Back => {} - } - if let ChainState::Back = self.state { - self.b.nth(n) - } else { - None - } - } - - #[inline] - fn find

(&mut self, mut predicate: P) -> Option where - P: FnMut(&Self::Item) -> bool, - { - match self.state { - ChainState::Both => match self.a.find(&mut predicate) { - None => { - self.state = ChainState::Back; - self.b.find(predicate) - } - v => v - }, - ChainState::Front => self.a.find(predicate), - ChainState::Back => self.b.find(predicate), - } - } - - #[inline] - fn last(self) -> Option { - match self.state { - ChainState::Both => { - // Must exhaust a before b. - let a_last = self.a.last(); - let b_last = self.b.last(); - b_last.or(a_last) - }, - ChainState::Front => self.a.last(), - ChainState::Back => self.b.last() - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let (a_lower, a_upper) = self.a.size_hint(); - let (b_lower, b_upper) = self.b.size_hint(); - - let lower = a_lower.saturating_add(b_lower); - - let upper = match (a_upper, b_upper) { - (Some(x), Some(y)) => x.checked_add(y), - _ => None - }; - - (lower, upper) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl DoubleEndedIterator for Chain where - A: DoubleEndedIterator, - B: DoubleEndedIterator, -{ - #[inline] - fn next_back(&mut self) -> Option { - match self.state { - ChainState::Both => match self.b.next_back() { - elt @ Some(..) => elt, - None => { - self.state = ChainState::Front; - self.a.next_back() - } - }, - ChainState::Front => self.a.next_back(), - ChainState::Back => self.b.next_back(), - } - } - - fn try_rfold(&mut self, init: Acc, mut f: F) -> R where - Self: Sized, F: FnMut(Acc, Self::Item) -> R, R: Try - { - let mut accum = init; - match self.state { - ChainState::Both | ChainState::Back => { - accum = self.b.try_rfold(accum, &mut f)?; - if let ChainState::Both = self.state { - self.state = ChainState::Front; - } - } - _ => { } - } - if let ChainState::Front = self.state { - accum = self.a.try_rfold(accum, &mut f)?; - } - Try::from_ok(accum) - } - - fn rfold(self, init: Acc, mut f: F) -> Acc - where F: FnMut(Acc, Self::Item) -> Acc, - { - let mut accum = init; - match self.state { - ChainState::Both | ChainState::Back => { - accum = self.b.rfold(accum, &mut f); - } - _ => { } - } - match self.state { - ChainState::Both | ChainState::Front => { - accum = self.a.rfold(accum, &mut f); - } - _ => { } - } - accum - } - -} - -// Note: *both* must be fused to handle double-ended iterators. -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Chain - where A: FusedIterator, - B: FusedIterator, -{} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for Chain - where A: TrustedLen, B: TrustedLen, -{} - -/// An iterator that iterates two other iterators simultaneously. -/// -/// This `struct` is created by the [`zip`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`zip`]: trait.Iterator.html#method.zip -/// [`Iterator`]: trait.Iterator.html -#[derive(Clone, Debug)] -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Zip { - a: A, - b: B, - // index and len are only used by the specialized version of zip - index: usize, - len: usize, -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for Zip where A: Iterator, B: Iterator -{ - type Item = (A::Item, B::Item); - - #[inline] - fn next(&mut self) -> Option { - ZipImpl::next(self) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - ZipImpl::size_hint(self) - } - - #[inline] - fn nth(&mut self, n: usize) -> Option { - ZipImpl::nth(self, n) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl DoubleEndedIterator for Zip where - A: DoubleEndedIterator + ExactSizeIterator, - B: DoubleEndedIterator + ExactSizeIterator, -{ - #[inline] - fn next_back(&mut self) -> Option<(A::Item, B::Item)> { - ZipImpl::next_back(self) - } -} - -// Zip specialization trait -#[doc(hidden)] -trait ZipImpl { - type Item; - fn new(a: A, b: B) -> Self; - fn next(&mut self) -> Option; - fn size_hint(&self) -> (usize, Option); - fn nth(&mut self, n: usize) -> Option; - fn super_nth(&mut self, mut n: usize) -> Option { - while let Some(x) = self.next() { - if n == 0 { return Some(x) } - n -= 1; - } - None - } - fn next_back(&mut self) -> Option - where A: DoubleEndedIterator + ExactSizeIterator, - B: DoubleEndedIterator + ExactSizeIterator; -} - -// General Zip impl -#[doc(hidden)] -impl ZipImpl for Zip - where A: Iterator, B: Iterator -{ - type Item = (A::Item, B::Item); - default fn new(a: A, b: B) -> Self { - Zip { - a, - b, - index: 0, // unused - len: 0, // unused - } - } - - #[inline] - default fn next(&mut self) -> Option<(A::Item, B::Item)> { - self.a.next().and_then(|x| { - self.b.next().and_then(|y| { - Some((x, y)) - }) - }) - } - - #[inline] - default fn nth(&mut self, n: usize) -> Option { - self.super_nth(n) - } - - #[inline] - default fn next_back(&mut self) -> Option<(A::Item, B::Item)> - where A: DoubleEndedIterator + ExactSizeIterator, - B: DoubleEndedIterator + ExactSizeIterator - { - let a_sz = self.a.len(); - let b_sz = self.b.len(); - if a_sz != b_sz { - // Adjust a, b to equal length - if a_sz > b_sz { - for _ in 0..a_sz - b_sz { self.a.next_back(); } - } else { - for _ in 0..b_sz - a_sz { self.b.next_back(); } - } - } - match (self.a.next_back(), self.b.next_back()) { - (Some(x), Some(y)) => Some((x, y)), - (None, None) => None, - _ => unreachable!(), - } - } - - #[inline] - default fn size_hint(&self) -> (usize, Option) { - let (a_lower, a_upper) = self.a.size_hint(); - let (b_lower, b_upper) = self.b.size_hint(); - - let lower = cmp::min(a_lower, b_lower); - - let upper = match (a_upper, b_upper) { - (Some(x), Some(y)) => Some(cmp::min(x,y)), - (Some(x), None) => Some(x), - (None, Some(y)) => Some(y), - (None, None) => None - }; - - (lower, upper) - } -} - -#[doc(hidden)] -impl ZipImpl for Zip - where A: TrustedRandomAccess, B: TrustedRandomAccess -{ - fn new(a: A, b: B) -> Self { - let len = cmp::min(a.len(), b.len()); - Zip { - a, - b, - index: 0, - len, - } - } - - #[inline] - fn next(&mut self) -> Option<(A::Item, B::Item)> { - if self.index < self.len { - let i = self.index; - self.index += 1; - unsafe { - Some((self.a.get_unchecked(i), self.b.get_unchecked(i))) - } - } else if A::may_have_side_effect() && self.index < self.a.len() { - // match the base implementation's potential side effects - unsafe { - self.a.get_unchecked(self.index); - } - self.index += 1; - None - } else { - None - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let len = self.len - self.index; - (len, Some(len)) - } - - #[inline] - fn nth(&mut self, n: usize) -> Option { - let delta = cmp::min(n, self.len - self.index); - let end = self.index + delta; - while self.index < end { - let i = self.index; - self.index += 1; - if A::may_have_side_effect() { - unsafe { self.a.get_unchecked(i); } - } - if B::may_have_side_effect() { - unsafe { self.b.get_unchecked(i); } - } - } - - self.super_nth(n - delta) - } - - #[inline] - fn next_back(&mut self) -> Option<(A::Item, B::Item)> - where A: DoubleEndedIterator + ExactSizeIterator, - B: DoubleEndedIterator + ExactSizeIterator - { - // Adjust a, b to equal length - if A::may_have_side_effect() { - let sz = self.a.len(); - if sz > self.len { - for _ in 0..sz - cmp::max(self.len, self.index) { - self.a.next_back(); - } - } - } - if B::may_have_side_effect() { - let sz = self.b.len(); - if sz > self.len { - for _ in 0..sz - self.len { - self.b.next_back(); - } - } - } - if self.index < self.len { - self.len -= 1; - let i = self.len; - unsafe { - Some((self.a.get_unchecked(i), self.b.get_unchecked(i))) - } - } else { - None - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for Zip - where A: ExactSizeIterator, B: ExactSizeIterator {} - -#[doc(hidden)] -unsafe impl TrustedRandomAccess for Zip - where A: TrustedRandomAccess, - B: TrustedRandomAccess, -{ - unsafe fn get_unchecked(&mut self, i: usize) -> (A::Item, B::Item) { - (self.a.get_unchecked(i), self.b.get_unchecked(i)) - } - - fn may_have_side_effect() -> bool { - A::may_have_side_effect() || B::may_have_side_effect() - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Zip - where A: FusedIterator, B: FusedIterator, {} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for Zip - where A: TrustedLen, B: TrustedLen, -{} - -/// An iterator that maps the values of `iter` with `f`. -/// -/// This `struct` is created by the [`map`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`map`]: trait.Iterator.html#method.map -/// [`Iterator`]: trait.Iterator.html -/// -/// # Notes about side effects -/// -/// The [`map`] iterator implements [`DoubleEndedIterator`], meaning that -/// you can also [`map`] backwards: -/// -/// ```rust -/// let v: Vec = vec![1, 2, 3].into_iter().map(|x| x + 1).rev().collect(); -/// -/// assert_eq!(v, [4, 3, 2]); -/// ``` -/// -/// [`DoubleEndedIterator`]: trait.DoubleEndedIterator.html -/// -/// But if your closure has state, iterating backwards may act in a way you do -/// not expect. Let's go through an example. First, in the forward direction: -/// -/// ```rust -/// let mut c = 0; -/// -/// for pair in vec!['a', 'b', 'c'].into_iter() -/// .map(|letter| { c += 1; (letter, c) }) { -/// println!("{:?}", pair); -/// } -/// ``` -/// -/// This will print "('a', 1), ('b', 2), ('c', 3)". -/// -/// Now consider this twist where we add a call to `rev`. This version will -/// print `('c', 1), ('b', 2), ('a', 3)`. Note that the letters are reversed, -/// but the values of the counter still go in order. This is because `map()` is -/// still being called lazily on each item, but we are popping items off the -/// back of the vector now, instead of shifting them from the front. -/// -/// ```rust -/// let mut c = 0; -/// -/// for pair in vec!['a', 'b', 'c'].into_iter() -/// .map(|letter| { c += 1; (letter, c) }) -/// .rev() { -/// println!("{:?}", pair); -/// } -/// ``` -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(Clone)] -pub struct Map { - iter: I, - f: F, -} - -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for Map { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("Map") - .field("iter", &self.iter) - .finish() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for Map where F: FnMut(I::Item) -> B { - type Item = B; - - #[inline] - fn next(&mut self) -> Option { - self.iter.next().map(&mut self.f) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } - - fn try_fold(&mut self, init: Acc, mut g: G) -> R where - Self: Sized, G: FnMut(Acc, Self::Item) -> R, R: Try - { - let f = &mut self.f; - self.iter.try_fold(init, move |acc, elt| g(acc, f(elt))) - } - - fn fold(self, init: Acc, mut g: G) -> Acc - where G: FnMut(Acc, Self::Item) -> Acc, - { - let mut f = self.f; - self.iter.fold(init, move |acc, elt| g(acc, f(elt))) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl DoubleEndedIterator for Map where - F: FnMut(I::Item) -> B, -{ - #[inline] - fn next_back(&mut self) -> Option { - self.iter.next_back().map(&mut self.f) - } - - fn try_rfold(&mut self, init: Acc, mut g: G) -> R where - Self: Sized, G: FnMut(Acc, Self::Item) -> R, R: Try - { - let f = &mut self.f; - self.iter.try_rfold(init, move |acc, elt| g(acc, f(elt))) - } - - fn rfold(self, init: Acc, mut g: G) -> Acc - where G: FnMut(Acc, Self::Item) -> Acc, - { - let mut f = self.f; - self.iter.rfold(init, move |acc, elt| g(acc, f(elt))) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for Map - where F: FnMut(I::Item) -> B -{ - fn len(&self) -> usize { - self.iter.len() - } - - fn is_empty(&self) -> bool { - self.iter.is_empty() - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Map - where F: FnMut(I::Item) -> B {} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for Map - where I: TrustedLen, - F: FnMut(I::Item) -> B {} - -#[doc(hidden)] -unsafe impl TrustedRandomAccess for Map - where I: TrustedRandomAccess, - F: FnMut(I::Item) -> B, -{ - unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item { - (self.f)(self.iter.get_unchecked(i)) - } - #[inline] - fn may_have_side_effect() -> bool { true } -} - -/// An iterator that filters the elements of `iter` with `predicate`. -/// -/// This `struct` is created by the [`filter`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`filter`]: trait.Iterator.html#method.filter -/// [`Iterator`]: trait.Iterator.html -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(Clone)] -pub struct Filter { - iter: I, - predicate: P, -} - -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for Filter { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("Filter") - .field("iter", &self.iter) - .finish() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for Filter where P: FnMut(&I::Item) -> bool { - type Item = I::Item; - - #[inline] - fn next(&mut self) -> Option { - for x in &mut self.iter { - if (self.predicate)(&x) { - return Some(x); - } - } - None - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let (_, upper) = self.iter.size_hint(); - (0, upper) // can't know a lower bound, due to the predicate - } - - // this special case allows the compiler to make `.filter(_).count()` - // branchless. Barring perfect branch prediction (which is unattainable in - // the general case), this will be much faster in >90% of cases (containing - // virtually all real workloads) and only a tiny bit slower in the rest. - // - // Having this specialization thus allows us to write `.filter(p).count()` - // where we would otherwise write `.map(|x| p(x) as usize).sum()`, which is - // less readable and also less backwards-compatible to Rust before 1.10. - // - // 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 - } - - #[inline] - fn try_fold(&mut self, init: Acc, mut fold: Fold) -> R where - Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try - { - let predicate = &mut self.predicate; - self.iter.try_fold(init, move |acc, item| if predicate(&item) { - fold(acc, item) - } else { - Try::from_ok(acc) - }) - } - - #[inline] - fn fold(self, init: Acc, mut fold: Fold) -> Acc - where Fold: FnMut(Acc, Self::Item) -> Acc, - { - let mut predicate = self.predicate; - self.iter.fold(init, move |acc, item| if predicate(&item) { - fold(acc, item) - } else { - acc - }) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl DoubleEndedIterator for Filter - where P: FnMut(&I::Item) -> bool, -{ - #[inline] - fn next_back(&mut self) -> Option { - for x in self.iter.by_ref().rev() { - if (self.predicate)(&x) { - return Some(x); - } - } - None - } - - #[inline] - fn try_rfold(&mut self, init: Acc, mut fold: Fold) -> R where - Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try - { - let predicate = &mut self.predicate; - self.iter.try_rfold(init, move |acc, item| if predicate(&item) { - fold(acc, item) - } else { - Try::from_ok(acc) - }) - } - - #[inline] - fn rfold(self, init: Acc, mut fold: Fold) -> Acc - where Fold: FnMut(Acc, Self::Item) -> Acc, - { - let mut predicate = self.predicate; - self.iter.rfold(init, move |acc, item| if predicate(&item) { - fold(acc, item) - } else { - acc - }) - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Filter - where P: FnMut(&I::Item) -> bool {} - -/// An iterator that uses `f` to both filter and map elements from `iter`. -/// -/// This `struct` is created by the [`filter_map`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`filter_map`]: trait.Iterator.html#method.filter_map -/// [`Iterator`]: trait.Iterator.html -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(Clone)] -pub struct FilterMap { - iter: I, - f: F, -} - -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for FilterMap { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("FilterMap") - .field("iter", &self.iter) - .finish() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for FilterMap - where F: FnMut(I::Item) -> Option, -{ - type Item = B; - - #[inline] - fn next(&mut self) -> Option { - for x in self.iter.by_ref() { - if let Some(y) = (self.f)(x) { - return Some(y); - } - } - None - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let (_, upper) = self.iter.size_hint(); - (0, upper) // can't know a lower bound, due to the predicate - } - - #[inline] - fn try_fold(&mut self, init: Acc, mut fold: Fold) -> R where - Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try - { - let f = &mut self.f; - self.iter.try_fold(init, move |acc, item| match f(item) { - Some(x) => fold(acc, x), - None => Try::from_ok(acc), - }) - } - - #[inline] - fn fold(self, init: Acc, mut fold: Fold) -> Acc - where Fold: FnMut(Acc, Self::Item) -> Acc, - { - let mut f = self.f; - self.iter.fold(init, move |acc, item| match f(item) { - Some(x) => fold(acc, x), - None => acc, - }) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl DoubleEndedIterator for FilterMap - where F: FnMut(I::Item) -> Option, -{ - #[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 - } - - #[inline] - fn try_rfold(&mut self, init: Acc, mut fold: Fold) -> R where - Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try - { - let f = &mut self.f; - self.iter.try_rfold(init, move |acc, item| match f(item) { - Some(x) => fold(acc, x), - None => Try::from_ok(acc), - }) - } - - #[inline] - fn rfold(self, init: Acc, mut fold: Fold) -> Acc - where Fold: FnMut(Acc, Self::Item) -> Acc, - { - let mut f = self.f; - self.iter.rfold(init, move |acc, item| match f(item) { - Some(x) => fold(acc, x), - None => acc, - }) - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for FilterMap - where F: FnMut(I::Item) -> Option {} - -/// An iterator that yields the current count and the element during iteration. -/// -/// This `struct` is created by the [`enumerate`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`enumerate`]: trait.Iterator.html#method.enumerate -/// [`Iterator`]: trait.Iterator.html -#[derive(Clone, Debug)] -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Enumerate { - iter: I, - count: usize, -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for Enumerate where I: Iterator { - type Item = (usize, ::Item); - - /// # Overflow Behavior - /// - /// The method does no guarding against overflows, so enumerating more than - /// `usize::MAX` elements either produces the wrong result or panics. If - /// debug assertions are enabled, a panic is guaranteed. - /// - /// # Panics - /// - /// Might panic if the index of the element overflows a `usize`. - #[inline] - #[rustc_inherit_overflow_checks] - fn next(&mut self) -> Option<(usize, ::Item)> { - self.iter.next().map(|a| { - let ret = (self.count, a); - // Possible undefined overflow. - self.count += 1; - ret - }) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } - - #[inline] - #[rustc_inherit_overflow_checks] - fn nth(&mut self, n: usize) -> Option<(usize, I::Item)> { - self.iter.nth(n).map(|a| { - let i = self.count + n; - self.count = i + 1; - (i, a) - }) - } - - #[inline] - fn count(self) -> usize { - self.iter.count() - } - - #[inline] - #[rustc_inherit_overflow_checks] - fn try_fold(&mut self, init: Acc, mut fold: Fold) -> R where - Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try - { - let count = &mut self.count; - self.iter.try_fold(init, move |acc, item| { - let acc = fold(acc, (*count, item)); - *count += 1; - acc - }) - } - - #[inline] - #[rustc_inherit_overflow_checks] - fn fold(self, init: Acc, mut fold: Fold) -> Acc - where Fold: FnMut(Acc, Self::Item) -> Acc, - { - let mut count = self.count; - self.iter.fold(init, move |acc, item| { - let acc = fold(acc, (count, item)); - count += 1; - acc - }) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl DoubleEndedIterator for Enumerate where - I: ExactSizeIterator + DoubleEndedIterator -{ - #[inline] - fn next_back(&mut self) -> Option<(usize, ::Item)> { - self.iter.next_back().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 - { - // Can safely add and subtract the count, as `ExactSizeIterator` promises - // that the number of elements fits into a `usize`. - let mut count = self.count + self.iter.len(); - self.iter.try_rfold(init, move |acc, item| { - count -= 1; - fold(acc, (count, item)) - }) - } - - #[inline] - fn rfold(self, init: Acc, mut fold: Fold) -> Acc - where Fold: FnMut(Acc, Self::Item) -> Acc, - { - // Can safely add and subtract the count, as `ExactSizeIterator` promises - // that the number of elements fits into a `usize`. - let mut count = self.count + self.iter.len(); - self.iter.rfold(init, move |acc, item| { - count -= 1; - fold(acc, (count, item)) - }) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for Enumerate where I: ExactSizeIterator { - fn len(&self) -> usize { - self.iter.len() - } - - fn is_empty(&self) -> bool { - self.iter.is_empty() - } -} - -#[doc(hidden)] -unsafe impl TrustedRandomAccess for Enumerate - where I: TrustedRandomAccess -{ - unsafe fn get_unchecked(&mut self, i: usize) -> (usize, I::Item) { - (self.count + i, self.iter.get_unchecked(i)) - } - - fn may_have_side_effect() -> bool { - I::may_have_side_effect() - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Enumerate where I: FusedIterator {} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for Enumerate - where I: TrustedLen, -{} - - -/// An iterator with a `peek()` that returns an optional reference to the next -/// element. -/// -/// This `struct` is created by the [`peekable`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`peekable`]: trait.Iterator.html#method.peekable -/// [`Iterator`]: trait.Iterator.html -#[derive(Clone, Debug)] -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Peekable { - iter: I, - /// Remember a peeked value, even if it was None. - peeked: Option>, -} - -// Peekable must remember if a None has been seen in the `.peek()` method. -// It ensures that `.peek(); .peek();` or `.peek(); .next();` only advances the -// underlying iterator at most once. This does not by itself make the iterator -// fused. -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for Peekable { - type Item = I::Item; - - #[inline] - fn next(&mut self) -> Option { - match self.peeked.take() { - Some(v) => v, - None => self.iter.next(), - } - } - - #[inline] - #[rustc_inherit_overflow_checks] - fn count(mut self) -> usize { - match self.peeked.take() { - Some(None) => 0, - Some(Some(_)) => 1 + self.iter.count(), - None => self.iter.count(), - } - } - - #[inline] - fn nth(&mut self, n: usize) -> Option { - match self.peeked.take() { - Some(None) => None, - Some(v @ Some(_)) if n == 0 => v, - Some(Some(_)) => self.iter.nth(n - 1), - None => self.iter.nth(n), - } - } - - #[inline] - fn last(mut self) -> Option { - let peek_opt = match self.peeked.take() { - Some(None) => return None, - Some(v) => v, - None => None, - }; - self.iter.last().or(peek_opt) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let peek_len = match self.peeked { - Some(None) => return (0, Some(0)), - Some(Some(_)) => 1, - None => 0, - }; - let (lo, hi) = self.iter.size_hint(); - let lo = lo.saturating_add(peek_len); - let hi = hi.and_then(|x| x.checked_add(peek_len)); - (lo, hi) - } - - #[inline] - fn try_fold(&mut self, init: B, mut f: F) -> R where - Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try - { - let acc = match self.peeked.take() { - Some(None) => return Try::from_ok(init), - Some(Some(v)) => f(init, v)?, - None => init, - }; - self.iter.try_fold(acc, f) - } - - #[inline] - fn fold(self, init: Acc, mut fold: Fold) -> Acc - where Fold: FnMut(Acc, Self::Item) -> Acc, - { - let acc = match self.peeked { - Some(None) => return init, - Some(Some(v)) => fold(init, v), - None => init, - }; - self.iter.fold(acc, fold) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for Peekable {} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Peekable {} - -impl Peekable { - /// Returns a reference to the next() value without advancing the iterator. - /// - /// Like [`next`], if there is a value, it is wrapped in a `Some(T)`. - /// But if the iteration is over, `None` is returned. - /// - /// [`next`]: trait.Iterator.html#tymethod.next - /// - /// Because `peek()` returns a reference, and many iterators iterate over - /// references, there can be a possibly confusing situation where the - /// return value is a double reference. You can see this effect in the - /// examples below. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let xs = [1, 2, 3]; - /// - /// let mut iter = xs.iter().peekable(); - /// - /// // peek() lets us see into the future - /// assert_eq!(iter.peek(), Some(&&1)); - /// assert_eq!(iter.next(), Some(&1)); - /// - /// assert_eq!(iter.next(), Some(&2)); - /// - /// // The iterator does not advance even if we `peek` multiple times - /// assert_eq!(iter.peek(), Some(&&3)); - /// assert_eq!(iter.peek(), Some(&&3)); - /// - /// assert_eq!(iter.next(), Some(&3)); - /// - /// // After the iterator is finished, so is `peek()` - /// assert_eq!(iter.peek(), None); - /// assert_eq!(iter.next(), None); - /// ``` - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn peek(&mut self) -> Option<&I::Item> { - let iter = &mut self.iter; - self.peeked.get_or_insert_with(|| iter.next()).as_ref() - } -} - -/// An iterator that rejects elements while `predicate` is true. -/// -/// This `struct` is created by the [`skip_while`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`skip_while`]: trait.Iterator.html#method.skip_while -/// [`Iterator`]: trait.Iterator.html -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(Clone)] -pub struct SkipWhile { - iter: I, - flag: bool, - predicate: P, -} - -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for SkipWhile { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("SkipWhile") - .field("iter", &self.iter) - .field("flag", &self.flag) - .finish() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for SkipWhile - where P: FnMut(&I::Item) -> bool -{ - type Item = I::Item; - - #[inline] - fn next(&mut self) -> Option { - let flag = &mut self.flag; - let pred = &mut self.predicate; - self.iter.find(move |x| { - if *flag || !pred(x) { - *flag = true; - true - } else { - false - } - }) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let (_, upper) = self.iter.size_hint(); - (0, upper) // can't know a lower bound, due to the predicate - } - - #[inline] - fn try_fold(&mut self, mut init: Acc, mut fold: Fold) -> R where - Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try - { - if !self.flag { - match self.next() { - Some(v) => init = fold(init, v)?, - None => return Try::from_ok(init), - } - } - self.iter.try_fold(init, fold) - } - - #[inline] - fn fold(mut self, mut init: Acc, mut fold: Fold) -> Acc - where Fold: FnMut(Acc, Self::Item) -> Acc, - { - if !self.flag { - match self.next() { - Some(v) => init = fold(init, v), - None => return init, - } - } - self.iter.fold(init, fold) - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for SkipWhile - where I: FusedIterator, P: FnMut(&I::Item) -> bool {} - -/// An iterator that only accepts elements while `predicate` is true. -/// -/// This `struct` is created by the [`take_while`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`take_while`]: trait.Iterator.html#method.take_while -/// [`Iterator`]: trait.Iterator.html -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(Clone)] -pub struct TakeWhile { - iter: I, - flag: bool, - predicate: P, -} - -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for TakeWhile { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("TakeWhile") - .field("iter", &self.iter) - .field("flag", &self.flag) - .finish() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for TakeWhile - where P: FnMut(&I::Item) -> bool -{ - type Item = I::Item; - - #[inline] - fn next(&mut self) -> Option { - if self.flag { - None - } else { - self.iter.next().and_then(|x| { - if (self.predicate)(&x) { - Some(x) - } else { - self.flag = true; - None - } - }) - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - if self.flag { - (0, Some(0)) - } else { - let (_, upper) = self.iter.size_hint(); - (0, upper) // can't know a lower bound, due to the predicate - } - } - - #[inline] - fn try_fold(&mut self, init: Acc, mut fold: Fold) -> R where - Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try - { - if self.flag { - Try::from_ok(init) - } else { - let flag = &mut self.flag; - let p = &mut self.predicate; - self.iter.try_fold(init, move |acc, x|{ - if p(&x) { - LoopState::from_try(fold(acc, x)) - } else { - *flag = true; - LoopState::Break(Try::from_ok(acc)) - } - }).into_try() - } - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for TakeWhile - where I: FusedIterator, P: FnMut(&I::Item) -> bool {} - -/// An iterator that skips over `n` elements of `iter`. -/// -/// This `struct` is created by the [`skip`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`skip`]: trait.Iterator.html#method.skip -/// [`Iterator`]: trait.Iterator.html -#[derive(Clone, Debug)] -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Skip { - iter: I, - n: usize -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for Skip where I: Iterator { - type Item = ::Item; - - #[inline] - fn next(&mut self) -> Option { - if self.n == 0 { - self.iter.next() - } else { - let old_n = self.n; - self.n = 0; - self.iter.nth(old_n) - } - } - - #[inline] - fn nth(&mut self, n: usize) -> Option { - // Can't just add n + self.n due to overflow. - if self.n == 0 { - self.iter.nth(n) - } else { - let to_skip = self.n; - self.n = 0; - // nth(n) skips n+1 - if self.iter.nth(to_skip-1).is_none() { - return None; - } - self.iter.nth(n) - } - } - - #[inline] - fn count(self) -> usize { - self.iter.count().saturating_sub(self.n) - } - - #[inline] - fn last(mut self) -> Option { - if self.n == 0 { - self.iter.last() - } else { - let next = self.next(); - if next.is_some() { - // recurse. n should be 0. - self.last().or(next) - } else { - None - } - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let (lower, upper) = self.iter.size_hint(); - - let lower = lower.saturating_sub(self.n); - let upper = upper.map(|x| x.saturating_sub(self.n)); - - (lower, upper) - } - - #[inline] - fn try_fold(&mut self, init: Acc, fold: Fold) -> R where - Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try - { - let n = self.n; - self.n = 0; - if n > 0 { - // nth(n) skips n+1 - if self.iter.nth(n - 1).is_none() { - return Try::from_ok(init); - } - } - self.iter.try_fold(init, fold) - } - - #[inline] - fn fold(mut self, init: Acc, fold: Fold) -> Acc - where Fold: FnMut(Acc, Self::Item) -> Acc, - { - if self.n > 0 { - // nth(n) skips n+1 - if self.iter.nth(self.n - 1).is_none() { - return init; - } - } - self.iter.fold(init, fold) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for Skip where I: ExactSizeIterator {} - -#[stable(feature = "double_ended_skip_iterator", since = "1.9.0")] -impl DoubleEndedIterator for Skip where I: DoubleEndedIterator + ExactSizeIterator { - fn next_back(&mut self) -> Option { - if self.len() > 0 { - self.iter.next_back() - } else { - None - } - } - - fn try_rfold(&mut self, init: Acc, mut fold: Fold) -> R where - Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try - { - let mut n = self.len(); - if n == 0 { - Try::from_ok(init) - } else { - self.iter.try_rfold(init, move |acc, x| { - n -= 1; - let r = fold(acc, x); - if n == 0 { LoopState::Break(r) } - else { LoopState::from_try(r) } - }).into_try() - } - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Skip where I: FusedIterator {} - -/// An iterator that only iterates over the first `n` iterations of `iter`. -/// -/// This `struct` is created by the [`take`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`take`]: trait.Iterator.html#method.take -/// [`Iterator`]: trait.Iterator.html -#[derive(Clone, Debug)] -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Take { - iter: I, - n: usize -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for Take where I: Iterator{ - type Item = ::Item; - - #[inline] - fn next(&mut self) -> Option<::Item> { - if self.n != 0 { - self.n -= 1; - self.iter.next() - } else { - None - } - } - - #[inline] - fn nth(&mut self, n: usize) -> Option { - if self.n > n { - self.n -= n + 1; - self.iter.nth(n) - } else { - if self.n > 0 { - self.iter.nth(self.n - 1); - self.n = 0; - } - None - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - if self.n == 0 { - return (0, Some(0)); - } - - let (lower, upper) = self.iter.size_hint(); - - let lower = cmp::min(lower, self.n); - - let upper = match upper { - Some(x) if x < self.n => Some(x), - _ => Some(self.n) - }; - - (lower, upper) - } - - #[inline] - fn try_fold(&mut self, init: Acc, mut fold: Fold) -> R where - Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try - { - if self.n == 0 { - Try::from_ok(init) - } else { - let n = &mut self.n; - self.iter.try_fold(init, move |acc, x| { - *n -= 1; - let r = fold(acc, x); - if *n == 0 { LoopState::Break(r) } - else { LoopState::from_try(r) } - }).into_try() - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for Take where I: ExactSizeIterator {} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Take where I: FusedIterator {} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for Take {} - -/// An iterator to maintain state while iterating another iterator. -/// -/// This `struct` is created by the [`scan`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`scan`]: trait.Iterator.html#method.scan -/// [`Iterator`]: trait.Iterator.html -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(Clone)] -pub struct Scan { - iter: I, - f: F, - state: St, -} - -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for Scan { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("Scan") - .field("iter", &self.iter) - .field("state", &self.state) - .finish() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for Scan where - I: Iterator, - F: FnMut(&mut St, I::Item) -> Option, -{ - type Item = B; - - #[inline] - fn next(&mut self) -> Option { - self.iter.next().and_then(|a| (self.f)(&mut self.state, a)) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let (_, upper) = self.iter.size_hint(); - (0, upper) // can't know a lower bound, due to the scan function - } - - #[inline] - fn try_fold(&mut self, init: Acc, mut fold: Fold) -> R where - Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try - { - let state = &mut self.state; - let f = &mut self.f; - self.iter.try_fold(init, move |acc, x| { - match f(state, x) { - None => LoopState::Break(Try::from_ok(acc)), - Some(x) => LoopState::from_try(fold(acc, x)), - } - }).into_try() - } -} - -/// An iterator that maps each element to an iterator, and yields the elements -/// of the produced iterators. -/// -/// This `struct` is created by the [`flat_map`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`flat_map`]: trait.Iterator.html#method.flat_map -/// [`Iterator`]: trait.Iterator.html -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct FlatMap { - inner: FlattenCompat, ::IntoIter> -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Clone for FlatMap - where ::IntoIter: Clone -{ - fn clone(&self) -> Self { FlatMap { inner: self.inner.clone() } } -} - -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for FlatMap - where U::IntoIter: fmt::Debug -{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("FlatMap").field("inner", &self.inner).finish() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for FlatMap - where F: FnMut(I::Item) -> U, -{ - type Item = U::Item; - - #[inline] - fn next(&mut self) -> Option { self.inner.next() } - - #[inline] - fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } - - #[inline] - fn try_fold(&mut self, init: Acc, fold: Fold) -> R where - Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try - { - self.inner.try_fold(init, fold) - } - - #[inline] - fn fold(self, init: Acc, fold: Fold) -> Acc - where Fold: FnMut(Acc, Self::Item) -> Acc, - { - self.inner.fold(init, fold) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl DoubleEndedIterator for FlatMap - where F: FnMut(I::Item) -> U, - U: IntoIterator, - U::IntoIter: DoubleEndedIterator -{ - #[inline] - fn next_back(&mut self) -> Option { self.inner.next_back() } - - #[inline] - fn try_rfold(&mut self, init: Acc, fold: Fold) -> R where - Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try - { - self.inner.try_rfold(init, fold) - } - - #[inline] - fn rfold(self, init: Acc, fold: Fold) -> Acc - where Fold: FnMut(Acc, Self::Item) -> Acc, - { - self.inner.rfold(init, fold) - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for FlatMap - where I: FusedIterator, U: IntoIterator, F: FnMut(I::Item) -> U {} - -/// An iterator that flattens one level of nesting in an iterator of things -/// that can be turned into iterators. -/// -/// This `struct` is created by the [`flatten`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`flatten`]: trait.Iterator.html#method.flatten -/// [`Iterator`]: trait.Iterator.html -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[stable(feature = "iterator_flatten", since = "1.29.0")] -pub struct Flatten -where I::Item: IntoIterator { - inner: FlattenCompat::IntoIter>, -} - -#[stable(feature = "iterator_flatten", since = "1.29.0")] -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 { - f.debug_struct("Flatten").field("inner", &self.inner).finish() - } -} - -#[stable(feature = "iterator_flatten", since = "1.29.0")] -impl Clone for Flatten - where I: Iterator + Clone, U: Iterator + Clone, - I::Item: IntoIterator, -{ - fn clone(&self) -> Self { Flatten { inner: self.inner.clone() } } -} - -#[stable(feature = "iterator_flatten", since = "1.29.0")] -impl Iterator for Flatten - where I: Iterator, U: Iterator, - I::Item: IntoIterator -{ - type Item = U::Item; - - #[inline] - fn next(&mut self) -> Option { self.inner.next() } - - #[inline] - fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } - - #[inline] - fn try_fold(&mut self, init: Acc, fold: Fold) -> R where - Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try - { - self.inner.try_fold(init, fold) - } - - #[inline] - fn fold(self, init: Acc, fold: Fold) -> Acc - where Fold: FnMut(Acc, Self::Item) -> Acc, - { - self.inner.fold(init, fold) - } -} - -#[stable(feature = "iterator_flatten", since = "1.29.0")] -impl DoubleEndedIterator for Flatten - where I: DoubleEndedIterator, U: DoubleEndedIterator, - I::Item: IntoIterator -{ - #[inline] - fn next_back(&mut self) -> Option { self.inner.next_back() } - - #[inline] - fn try_rfold(&mut self, init: Acc, fold: Fold) -> R where - Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try - { - self.inner.try_rfold(init, fold) - } - - #[inline] - fn rfold(self, init: Acc, fold: Fold) -> Acc - where Fold: FnMut(Acc, Self::Item) -> Acc, - { - self.inner.rfold(init, fold) - } -} - -#[stable(feature = "iterator_flatten", since = "1.29.0")] -impl FusedIterator for Flatten - where I: FusedIterator, U: Iterator, - I::Item: IntoIterator {} - -/// Adapts an iterator by flattening it, for use in `flatten()` and `flat_map()`. -fn flatten_compat(iter: I) -> FlattenCompat { - FlattenCompat { iter, frontiter: None, backiter: None } -} - -/// Real logic of both `Flatten` and `FlatMap` which simply delegate to -/// this type. -#[derive(Clone, Debug)] -struct FlattenCompat { - iter: I, - frontiter: Option, - backiter: Option, -} - -impl Iterator for FlattenCompat - where I: Iterator, U: Iterator, - I::Item: IntoIterator -{ - type Item = U::Item; - - #[inline] - fn next(&mut self) -> Option { - loop { - if let Some(ref mut inner) = self.frontiter { - if let elt@Some(_) = inner.next() { return elt } - } - match self.iter.next() { - None => return self.backiter.as_mut().and_then(|it| it.next()), - Some(inner) => self.frontiter = Some(inner.into_iter()), - } - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let (flo, fhi) = self.frontiter.as_ref().map_or((0, Some(0)), |it| it.size_hint()); - let (blo, bhi) = self.backiter.as_ref().map_or((0, Some(0)), |it| it.size_hint()); - let lo = flo.saturating_add(blo); - match (self.iter.size_hint(), fhi, bhi) { - ((0, Some(0)), Some(a), Some(b)) => (lo, a.checked_add(b)), - _ => (lo, None) - } - } - - #[inline] - fn try_fold(&mut self, mut init: Acc, mut fold: Fold) -> R where - Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try - { - if let Some(ref mut front) = self.frontiter { - init = front.try_fold(init, &mut fold)?; - } - self.frontiter = None; - - { - let frontiter = &mut self.frontiter; - init = self.iter.try_fold(init, |acc, x| { - let mut mid = x.into_iter(); - let r = mid.try_fold(acc, &mut fold); - *frontiter = Some(mid); - r - })?; - } - self.frontiter = None; - - if let Some(ref mut back) = self.backiter { - init = back.try_fold(init, &mut fold)?; - } - self.backiter = None; - - Try::from_ok(init) - } - - #[inline] - fn fold(self, init: Acc, mut fold: Fold) -> Acc - where Fold: FnMut(Acc, Self::Item) -> Acc, - { - self.frontiter.into_iter() - .chain(self.iter.map(IntoIterator::into_iter)) - .chain(self.backiter) - .fold(init, |acc, iter| iter.fold(acc, &mut fold)) - } -} - -impl DoubleEndedIterator for FlattenCompat - where I: DoubleEndedIterator, U: DoubleEndedIterator, - I::Item: IntoIterator -{ - #[inline] - fn next_back(&mut self) -> Option { - loop { - if let Some(ref mut inner) = self.backiter { - if let elt@Some(_) = inner.next_back() { return elt } - } - match self.iter.next_back() { - None => return self.frontiter.as_mut().and_then(|it| it.next_back()), - next => self.backiter = next.map(IntoIterator::into_iter), - } - } - } - - #[inline] - fn try_rfold(&mut self, mut init: Acc, mut fold: Fold) -> R where - Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try - { - if let Some(ref mut back) = self.backiter { - init = back.try_rfold(init, &mut fold)?; - } - self.backiter = None; - - { - let backiter = &mut self.backiter; - init = self.iter.try_rfold(init, |acc, x| { - let mut mid = x.into_iter(); - let r = mid.try_rfold(acc, &mut fold); - *backiter = Some(mid); - r - })?; - } - self.backiter = None; - - if let Some(ref mut front) = self.frontiter { - init = front.try_rfold(init, &mut fold)?; - } - self.frontiter = None; - - Try::from_ok(init) - } - - #[inline] - fn rfold(self, init: Acc, mut fold: Fold) -> Acc - where Fold: FnMut(Acc, Self::Item) -> Acc, - { - self.frontiter.into_iter() - .chain(self.iter.map(IntoIterator::into_iter)) - .chain(self.backiter) - .rfold(init, |acc, iter| iter.rfold(acc, &mut fold)) - } -} - -/// An iterator that yields `None` forever after the underlying iterator -/// yields `None` once. -/// -/// This `struct` is created by the [`fuse`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`fuse`]: trait.Iterator.html#method.fuse -/// [`Iterator`]: trait.Iterator.html -#[derive(Clone, Debug)] -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Fuse { - iter: I, - done: bool -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Fuse where I: Iterator {} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for Fuse where I: Iterator { - type Item = ::Item; - - #[inline] - default fn next(&mut self) -> Option<::Item> { - if self.done { - None - } else { - let next = self.iter.next(); - self.done = next.is_none(); - next - } - } - - #[inline] - default fn nth(&mut self, n: usize) -> Option { - if self.done { - None - } else { - let nth = self.iter.nth(n); - self.done = nth.is_none(); - nth - } - } - - #[inline] - default fn last(self) -> Option { - if self.done { - None - } else { - self.iter.last() - } - } - - #[inline] - default fn count(self) -> usize { - if self.done { - 0 - } else { - self.iter.count() - } - } - - #[inline] - default fn size_hint(&self) -> (usize, Option) { - if self.done { - (0, Some(0)) - } else { - self.iter.size_hint() - } - } - - #[inline] - default fn try_fold(&mut self, init: Acc, fold: Fold) -> R where - Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try - { - if self.done { - Try::from_ok(init) - } else { - let acc = self.iter.try_fold(init, fold)?; - self.done = true; - Try::from_ok(acc) - } - } - - #[inline] - default fn fold(self, init: Acc, fold: Fold) -> Acc - where Fold: FnMut(Acc, Self::Item) -> Acc, - { - if self.done { - init - } else { - self.iter.fold(init, fold) - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl DoubleEndedIterator for Fuse where I: DoubleEndedIterator { - #[inline] - default fn next_back(&mut self) -> Option<::Item> { - if self.done { - None - } else { - let next = self.iter.next_back(); - self.done = next.is_none(); - next - } - } - - #[inline] - default fn try_rfold(&mut self, init: Acc, fold: Fold) -> R where - Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try - { - if self.done { - Try::from_ok(init) - } else { - let acc = self.iter.try_rfold(init, fold)?; - self.done = true; - Try::from_ok(acc) - } - } - - #[inline] - default fn rfold(self, init: Acc, fold: Fold) -> Acc - where Fold: FnMut(Acc, Self::Item) -> Acc, - { - if self.done { - init - } else { - self.iter.rfold(init, fold) - } - } -} - -unsafe impl TrustedRandomAccess for Fuse - where I: TrustedRandomAccess, -{ - unsafe fn get_unchecked(&mut self, i: usize) -> I::Item { - self.iter.get_unchecked(i) - } - - fn may_have_side_effect() -> bool { - I::may_have_side_effect() - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl Iterator for Fuse where I: FusedIterator { - #[inline] - fn next(&mut self) -> Option<::Item> { - self.iter.next() - } - - #[inline] - fn nth(&mut self, n: usize) -> Option { - self.iter.nth(n) - } - - #[inline] - fn last(self) -> Option { - self.iter.last() - } - - #[inline] - fn count(self) -> usize { - self.iter.count() - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } - - #[inline] - fn try_fold(&mut self, init: Acc, fold: Fold) -> R where - Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try - { - self.iter.try_fold(init, fold) - } - - #[inline] - fn fold(self, init: Acc, fold: Fold) -> Acc - where Fold: FnMut(Acc, Self::Item) -> Acc, - { - self.iter.fold(init, fold) - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl DoubleEndedIterator for Fuse - where I: DoubleEndedIterator + FusedIterator -{ - #[inline] - fn next_back(&mut self) -> Option<::Item> { - self.iter.next_back() - } - - #[inline] - fn try_rfold(&mut self, init: Acc, fold: Fold) -> R where - Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try - { - self.iter.try_rfold(init, fold) - } - - #[inline] - fn rfold(self, init: Acc, fold: Fold) -> Acc - where Fold: FnMut(Acc, Self::Item) -> Acc, - { - self.iter.rfold(init, fold) - } -} - - -#[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for Fuse where I: ExactSizeIterator { - fn len(&self) -> usize { - self.iter.len() - } - - fn is_empty(&self) -> bool { - self.iter.is_empty() - } -} - -/// An iterator that calls a function with a reference to each element before -/// yielding it. -/// -/// This `struct` is created by the [`inspect`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`inspect`]: trait.Iterator.html#method.inspect -/// [`Iterator`]: trait.Iterator.html -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(Clone)] -pub struct Inspect { - iter: I, - f: F, -} - -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for Inspect { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("Inspect") - .field("iter", &self.iter) - .finish() - } -} - -impl Inspect where F: FnMut(&I::Item) { - #[inline] - fn do_inspect(&mut self, elt: Option) -> Option { - if let Some(ref a) = elt { - (self.f)(a); - } - - elt - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for Inspect where F: FnMut(&I::Item) { - type Item = I::Item; - - #[inline] - fn next(&mut self) -> Option { - let next = self.iter.next(); - self.do_inspect(next) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } - - #[inline] - fn try_fold(&mut self, init: Acc, mut fold: Fold) -> R where - Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try - { - let f = &mut self.f; - self.iter.try_fold(init, move |acc, item| { f(&item); fold(acc, item) }) - } - - #[inline] - fn fold(self, init: Acc, mut fold: Fold) -> Acc - where Fold: FnMut(Acc, Self::Item) -> Acc, - { - let mut f = self.f; - self.iter.fold(init, move |acc, item| { f(&item); fold(acc, item) }) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl DoubleEndedIterator for Inspect - where F: FnMut(&I::Item), -{ - #[inline] - fn next_back(&mut self) -> Option { - let next = self.iter.next_back(); - self.do_inspect(next) - } - - #[inline] - fn try_rfold(&mut self, init: Acc, mut fold: Fold) -> R where - Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try - { - let f = &mut self.f; - self.iter.try_rfold(init, move |acc, item| { f(&item); fold(acc, item) }) - } - - #[inline] - fn rfold(self, init: Acc, mut fold: Fold) -> Acc - where Fold: FnMut(Acc, Self::Item) -> Acc, - { - let mut f = self.f; - self.iter.rfold(init, move |acc, item| { f(&item); fold(acc, item) }) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for Inspect - where F: FnMut(&I::Item) -{ - fn len(&self) -> usize { - self.iter.len() - } - - fn is_empty(&self) -> bool { - self.iter.is_empty() - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Inspect - where F: FnMut(&I::Item) {} diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs index 66c09a0ddd0fb..a3e9cfa949312 100644 --- a/src/libcore/iter/range.rs +++ b/src/libcore/iter/range.rs @@ -20,19 +20,19 @@ pub trait Step: Clone + PartialOrd + Sized { /// without overflow. fn steps_between(start: &Self, end: &Self) -> Option; - /// Replaces this step with `1`, returning itself + /// Replaces this step with `1`, returning itself. fn replace_one(&mut self) -> Self; - /// Replaces this step with `0`, returning itself + /// Replaces this step with `0`, returning itself. fn replace_zero(&mut self) -> Self; - /// Adds one to this step, returning the result + /// Adds one to this step, returning the result. fn add_one(&self) -> Self; - /// Subtracts one to this step, returning the result + /// Subtracts one to this step, returning the result. fn sub_one(&self) -> Self; - /// Add an usize, returning None on overflow + /// Adds a `usize`, returning `None` on overflow. fn add_usize(&self, n: usize) -> Option; } diff --git a/src/libcore/iter/sources.rs b/src/libcore/iter/sources.rs index 2590fa6023a53..74ff7f41d76fa 100644 --- a/src/libcore/iter/sources.rs +++ b/src/libcore/iter/sources.rs @@ -491,24 +491,22 @@ pub fn once_with A>(gen: F) -> OnceWith { } /// Creates a new iterator where each iteration calls the provided closure -/// `F: FnMut(&mut St) -> Option`. +/// `F: FnMut() -> Option`. /// /// This allows creating a custom iterator with any behavior /// without using the more verbose syntax of creating a dedicated type /// and implementing the `Iterator` trait for it. /// -/// In addition to its captures and environment, -/// the closure is given a mutable reference to some state -/// that is preserved across iterations. -/// That state starts as the given `initial_state` value. -/// -/// Note that the `Unfold` iterator doesn’t make assumptions about the behavior of the closure, +/// Note that the `FromFn` iterator doesn’t make assumptions about the behavior of the closure, /// and therefore conservatively does not implement [`FusedIterator`], /// or override [`Iterator::size_hint`] from its default `(0, None)`. /// /// [`FusedIterator`]: trait.FusedIterator.html /// [`Iterator::size_hint`]: trait.Iterator.html#method.size_hint /// +/// The closure can use captures and its environment to track state across iterations. Depending on +/// how the iterator is used, this may require specifying the `move` keyword on the closure. +/// /// # Examples /// /// Let’s re-implement the counter iterator from [module-level documentation]: @@ -516,14 +514,14 @@ pub fn once_with A>(gen: F) -> OnceWith { /// [module-level documentation]: index.html /// /// ``` -/// #![feature(iter_unfold)] -/// let counter = std::iter::unfold(0, |count| { +/// let mut count = 0; +/// let counter = std::iter::from_fn(move || { /// // Increment our count. This is why we started at zero. -/// *count += 1; +/// count += 1; /// /// // Check to see if we've finished counting or not. -/// if *count < 6 { -/// Some(*count) +/// if count < 6 { +/// Some(count) /// } else { /// None /// } @@ -531,47 +529,39 @@ pub fn once_with A>(gen: F) -> OnceWith { /// assert_eq!(counter.collect::>(), &[1, 2, 3, 4, 5]); /// ``` #[inline] -#[unstable(feature = "iter_unfold", issue = "55977")] -pub fn unfold(initial_state: St, f: F) -> Unfold - where F: FnMut(&mut St) -> Option +#[stable(feature = "iter_from_fn", since = "1.34.0")] +pub fn from_fn(f: F) -> FromFn + where F: FnMut() -> Option { - Unfold { - state: initial_state, - f, - } + FromFn(f) } -/// An iterator where each iteration calls the provided closure `F: FnMut(&mut St) -> Option`. +/// An iterator where each iteration calls the provided closure `F: FnMut() -> Option`. /// -/// This `struct` is created by the [`unfold`] function. +/// This `struct` is created by the [`iter::from_fn`] function. /// See its documentation for more. /// -/// [`unfold`]: fn.unfold.html +/// [`iter::from_fn`]: fn.from_fn.html #[derive(Clone)] -#[unstable(feature = "iter_unfold", issue = "55977")] -pub struct Unfold { - state: St, - f: F, -} +#[stable(feature = "iter_from_fn", since = "1.34.0")] +pub struct FromFn(F); -#[unstable(feature = "iter_unfold", issue = "55977")] -impl Iterator for Unfold - where F: FnMut(&mut St) -> Option +#[stable(feature = "iter_from_fn", since = "1.34.0")] +impl Iterator for FromFn + where F: FnMut() -> Option { type Item = T; #[inline] fn next(&mut self) -> Option { - (self.f)(&mut self.state) + (self.0)() } } -#[unstable(feature = "iter_unfold", issue = "55977")] -impl fmt::Debug for Unfold { +#[stable(feature = "iter_from_fn", since = "1.34.0")] +impl fmt::Debug for FromFn { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("Unfold") - .field("state", &self.state) - .finish() + f.debug_struct("FromFn").finish() } } @@ -581,13 +571,12 @@ impl fmt::Debug for Unfold { /// and calls the given `FnMut(&T) -> Option` closure to compute each item’s successor. /// /// ``` -/// #![feature(iter_unfold)] /// use std::iter::successors; /// /// let powers_of_10 = successors(Some(1_u16), |n| n.checked_mul(10)); /// assert_eq!(powers_of_10.collect::>(), &[1, 10, 100, 1_000, 10_000]); /// ``` -#[unstable(feature = "iter_unfold", issue = "55977")] +#[stable(feature = "iter_successors", since = "1.34.0")] pub fn successors(first: Option, succ: F) -> Successors where F: FnMut(&T) -> Option { @@ -607,13 +596,13 @@ pub fn successors(first: Option, succ: F) -> Successors /// /// [`successors`]: fn.successors.html #[derive(Clone)] -#[unstable(feature = "iter_unfold", issue = "55977")] +#[stable(feature = "iter_successors", since = "1.34.0")] pub struct Successors { next: Option, succ: F, } -#[unstable(feature = "iter_unfold", issue = "55977")] +#[stable(feature = "iter_successors", since = "1.34.0")] impl Iterator for Successors where F: FnMut(&T) -> Option { @@ -637,12 +626,12 @@ impl Iterator for Successors } } -#[unstable(feature = "iter_unfold", issue = "55977")] +#[stable(feature = "iter_successors", since = "1.34.0")] impl FusedIterator for Successors where F: FnMut(&T) -> Option {} -#[unstable(feature = "iter_unfold", issue = "55977")] +#[stable(feature = "iter_successors", since = "1.34.0")] impl fmt::Debug for Successors { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Successors") diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs deleted file mode 100644 index e8c6cd8b79c72..0000000000000 --- a/src/libcore/iter/traits.rs +++ /dev/null @@ -1,1060 +0,0 @@ -use ops::{Mul, Add, Try}; -use num::Wrapping; - -use super::LoopState; - -/// Conversion from an `Iterator`. -/// -/// By implementing `FromIterator` for a type, you define how it will be -/// created from an iterator. This is common for types which describe a -/// collection of some kind. -/// -/// `FromIterator`'s [`from_iter`] is rarely called explicitly, and is instead -/// used through [`Iterator`]'s [`collect`] method. See [`collect`]'s -/// documentation for more examples. -/// -/// [`from_iter`]: #tymethod.from_iter -/// [`Iterator`]: trait.Iterator.html -/// [`collect`]: trait.Iterator.html#method.collect -/// -/// See also: [`IntoIterator`]. -/// -/// [`IntoIterator`]: trait.IntoIterator.html -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// use std::iter::FromIterator; -/// -/// let five_fives = std::iter::repeat(5).take(5); -/// -/// let v = Vec::from_iter(five_fives); -/// -/// assert_eq!(v, vec![5, 5, 5, 5, 5]); -/// ``` -/// -/// Using [`collect`] to implicitly use `FromIterator`: -/// -/// ``` -/// let five_fives = std::iter::repeat(5).take(5); -/// -/// let v: Vec = five_fives.collect(); -/// -/// assert_eq!(v, vec![5, 5, 5, 5, 5]); -/// ``` -/// -/// Implementing `FromIterator` for your type: -/// -/// ``` -/// use std::iter::FromIterator; -/// -/// // A sample collection, that's just a wrapper over Vec -/// #[derive(Debug)] -/// struct MyCollection(Vec); -/// -/// // Let's give it some methods so we can create one and add things -/// // to it. -/// impl MyCollection { -/// fn new() -> MyCollection { -/// MyCollection(Vec::new()) -/// } -/// -/// fn add(&mut self, elem: i32) { -/// self.0.push(elem); -/// } -/// } -/// -/// // and we'll implement FromIterator -/// impl FromIterator for MyCollection { -/// fn from_iter>(iter: I) -> Self { -/// let mut c = MyCollection::new(); -/// -/// for i in iter { -/// c.add(i); -/// } -/// -/// c -/// } -/// } -/// -/// // Now we can make a new iterator... -/// let iter = (0..5).into_iter(); -/// -/// // ... and make a MyCollection out of it -/// let c = MyCollection::from_iter(iter); -/// -/// assert_eq!(c.0, vec![0, 1, 2, 3, 4]); -/// -/// // collect works too! -/// -/// let iter = (0..5).into_iter(); -/// let c: MyCollection = iter.collect(); -/// -/// assert_eq!(c.0, vec![0, 1, 2, 3, 4]); -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -#[rustc_on_unimplemented( - message="a collection of type `{Self}` cannot be built from an iterator \ - over elements of type `{A}`", - label="a collection of type `{Self}` cannot be built from `std::iter::Iterator`", -)] -pub trait FromIterator: Sized { - /// Creates a value from an iterator. - /// - /// See the [module-level documentation] for more. - /// - /// [module-level documentation]: index.html - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::iter::FromIterator; - /// - /// let five_fives = std::iter::repeat(5).take(5); - /// - /// let v = Vec::from_iter(five_fives); - /// - /// assert_eq!(v, vec![5, 5, 5, 5, 5]); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn from_iter>(iter: T) -> Self; -} - -/// Conversion into an `Iterator`. -/// -/// By implementing `IntoIterator` for a type, you define how it will be -/// converted to an iterator. This is common for types which describe a -/// collection of some kind. -/// -/// One benefit of implementing `IntoIterator` is that your type will [work -/// with Rust's `for` loop syntax](index.html#for-loops-and-intoiterator). -/// -/// See also: [`FromIterator`]. -/// -/// [`FromIterator`]: trait.FromIterator.html -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// let v = vec![1, 2, 3]; -/// let mut iter = v.into_iter(); -/// -/// assert_eq!(Some(1), iter.next()); -/// assert_eq!(Some(2), iter.next()); -/// assert_eq!(Some(3), iter.next()); -/// assert_eq!(None, iter.next()); -/// ``` -/// Implementing `IntoIterator` for your type: -/// -/// ``` -/// // A sample collection, that's just a wrapper over Vec -/// #[derive(Debug)] -/// struct MyCollection(Vec); -/// -/// // Let's give it some methods so we can create one and add things -/// // to it. -/// impl MyCollection { -/// fn new() -> MyCollection { -/// MyCollection(Vec::new()) -/// } -/// -/// fn add(&mut self, elem: i32) { -/// self.0.push(elem); -/// } -/// } -/// -/// // and we'll implement IntoIterator -/// impl IntoIterator for MyCollection { -/// type Item = i32; -/// type IntoIter = ::std::vec::IntoIter; -/// -/// fn into_iter(self) -> Self::IntoIter { -/// self.0.into_iter() -/// } -/// } -/// -/// // Now we can make a new collection... -/// let mut c = MyCollection::new(); -/// -/// // ... add some stuff to it ... -/// c.add(0); -/// c.add(1); -/// c.add(2); -/// -/// // ... and then turn it into an Iterator: -/// for (i, n) in c.into_iter().enumerate() { -/// assert_eq!(i as i32, n); -/// } -/// ``` -/// -/// It is common to use `IntoIterator` as a trait bound. This allows -/// the input collection type to change, so long as it is still an -/// iterator. Additional bounds can be specified by restricting on -/// `Item`: -/// -/// ```rust -/// fn collect_as_strings(collection: T) -> Vec -/// where T: IntoIterator, -/// T::Item : std::fmt::Debug, -/// { -/// collection -/// .into_iter() -/// .map(|item| format!("{:?}", item)) -/// .collect() -/// } -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub trait IntoIterator { - /// The type of the elements being iterated over. - #[stable(feature = "rust1", since = "1.0.0")] - type Item; - - /// Which kind of iterator are we turning this into? - #[stable(feature = "rust1", since = "1.0.0")] - type IntoIter: Iterator; - - /// Creates an iterator from a value. - /// - /// See the [module-level documentation] for more. - /// - /// [module-level documentation]: index.html - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let v = vec![1, 2, 3]; - /// let mut iter = v.into_iter(); - /// - /// assert_eq!(Some(1), iter.next()); - /// assert_eq!(Some(2), iter.next()); - /// assert_eq!(Some(3), iter.next()); - /// assert_eq!(None, iter.next()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn into_iter(self) -> Self::IntoIter; -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl IntoIterator for I { - type Item = I::Item; - type IntoIter = I; - - fn into_iter(self) -> I { - self - } -} - -/// Extend a collection with the contents of an iterator. -/// -/// Iterators produce a series of values, and collections can also be thought -/// of as a series of values. The `Extend` trait bridges this gap, allowing you -/// to extend a collection by including the contents of that iterator. When -/// extending a collection with an already existing key, that entry is updated -/// or, in the case of collections that permit multiple entries with equal -/// keys, that entry is inserted. -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// // You can extend a String with some chars: -/// let mut message = String::from("The first three letters are: "); -/// -/// message.extend(&['a', 'b', 'c']); -/// -/// assert_eq!("abc", &message[29..32]); -/// ``` -/// -/// Implementing `Extend`: -/// -/// ``` -/// // A sample collection, that's just a wrapper over Vec -/// #[derive(Debug)] -/// struct MyCollection(Vec); -/// -/// // Let's give it some methods so we can create one and add things -/// // to it. -/// impl MyCollection { -/// fn new() -> MyCollection { -/// MyCollection(Vec::new()) -/// } -/// -/// fn add(&mut self, elem: i32) { -/// self.0.push(elem); -/// } -/// } -/// -/// // since MyCollection has a list of i32s, we implement Extend for i32 -/// impl Extend for MyCollection { -/// -/// // This is a bit simpler with the concrete type signature: we can call -/// // extend on anything which can be turned into an Iterator which gives -/// // us i32s. Because we need i32s to put into MyCollection. -/// fn extend>(&mut self, iter: T) { -/// -/// // The implementation is very straightforward: loop through the -/// // iterator, and add() each element to ourselves. -/// for elem in iter { -/// self.add(elem); -/// } -/// } -/// } -/// -/// let mut c = MyCollection::new(); -/// -/// c.add(5); -/// c.add(6); -/// c.add(7); -/// -/// // let's extend our collection with three more numbers -/// c.extend(vec![1, 2, 3]); -/// -/// // we've added these elements onto the end -/// assert_eq!("MyCollection([5, 6, 7, 1, 2, 3])", format!("{:?}", c)); -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub trait Extend { - /// Extends a collection with the contents of an iterator. - /// - /// As this is the only method for this trait, the [trait-level] docs - /// contain more details. - /// - /// [trait-level]: trait.Extend.html - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// // You can extend a String with some chars: - /// let mut message = String::from("abc"); - /// - /// message.extend(['d', 'e', 'f'].iter()); - /// - /// assert_eq!("abcdef", &message); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn extend>(&mut self, iter: T); -} - -#[stable(feature = "extend_for_unit", since = "1.28.0")] -impl Extend<()> for () { - fn extend>(&mut self, iter: T) { - iter.into_iter().for_each(drop) - } -} - -/// An iterator able to yield elements from both ends. -/// -/// Something that implements `DoubleEndedIterator` has one extra capability -/// over something that implements [`Iterator`]: the ability to also take -/// `Item`s from the back, as well as the front. -/// -/// It is important to note that both back and forth work on the same range, -/// and do not cross: iteration is over when they meet in the middle. -/// -/// In a similar fashion to the [`Iterator`] protocol, once a -/// `DoubleEndedIterator` returns `None` from a `next_back()`, calling it again -/// may or may not ever return `Some` again. `next()` and `next_back()` are -/// interchangeable for this purpose. -/// -/// [`Iterator`]: trait.Iterator.html -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// let numbers = vec![1, 2, 3, 4, 5, 6]; -/// -/// let mut iter = numbers.iter(); -/// -/// assert_eq!(Some(&1), iter.next()); -/// assert_eq!(Some(&6), iter.next_back()); -/// assert_eq!(Some(&5), iter.next_back()); -/// assert_eq!(Some(&2), iter.next()); -/// assert_eq!(Some(&3), iter.next()); -/// assert_eq!(Some(&4), iter.next()); -/// assert_eq!(None, iter.next()); -/// assert_eq!(None, iter.next_back()); -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub trait DoubleEndedIterator: Iterator { - /// Removes and returns an element from the end of the iterator. - /// - /// Returns `None` when there are no more elements. - /// - /// The [trait-level] docs contain more details. - /// - /// [trait-level]: trait.DoubleEndedIterator.html - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let numbers = vec![1, 2, 3, 4, 5, 6]; - /// - /// let mut iter = numbers.iter(); - /// - /// assert_eq!(Some(&1), iter.next()); - /// assert_eq!(Some(&6), iter.next_back()); - /// assert_eq!(Some(&5), iter.next_back()); - /// assert_eq!(Some(&2), iter.next()); - /// assert_eq!(Some(&3), iter.next()); - /// assert_eq!(Some(&4), iter.next()); - /// assert_eq!(None, iter.next()); - /// assert_eq!(None, iter.next_back()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn next_back(&mut self) -> Option; - - /// Returns the `n`th element from the end of the iterator. - /// - /// This is essentially the reversed version of [`nth`]. Although like most indexing - /// operations, the count starts from zero, so `nth_back(0)` returns the first value fro - /// the end, `nth_back(1)` the second, and so on. - /// - /// Note that all elements between the end and the returned element will be - /// consumed, including the returned element. This also means that calling - /// `nth_back(0)` multiple times on the same iterator will return different - /// elements. - /// - /// `nth_back()` will return [`None`] if `n` is greater than or equal to the length of the - /// iterator. - /// - /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// [`nth`]: ../../std/iter/trait.Iterator.html#method.nth - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// #![feature(iter_nth_back)] - /// let a = [1, 2, 3]; - /// assert_eq!(a.iter().nth_back(2), Some(&1)); - /// ``` - /// - /// Calling `nth_back()` multiple times doesn't rewind the iterator: - /// - /// ``` - /// #![feature(iter_nth_back)] - /// let a = [1, 2, 3]; - /// - /// let mut iter = a.iter(); - /// - /// assert_eq!(iter.nth_back(1), Some(&2)); - /// assert_eq!(iter.nth_back(1), None); - /// ``` - /// - /// 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")] - fn nth_back(&mut self, mut n: usize) -> Option { - for x in self.rev() { - if n == 0 { return Some(x) } - n -= 1; - } - None - } - - /// This is the reverse version of [`try_fold()`]: it takes elements - /// starting from the back of the iterator. - /// - /// [`try_fold()`]: trait.Iterator.html#method.try_fold - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let a = ["1", "2", "3"]; - /// let sum = a.iter() - /// .map(|&s| s.parse::()) - /// .try_rfold(0, |acc, x| x.and_then(|y| Ok(acc + y))); - /// assert_eq!(sum, Ok(6)); - /// ``` - /// - /// Short-circuiting: - /// - /// ``` - /// let a = ["1", "rust", "3"]; - /// let mut it = a.iter(); - /// let sum = it - /// .by_ref() - /// .map(|&s| s.parse::()) - /// .try_rfold(0, |acc, x| x.and_then(|y| Ok(acc + y))); - /// assert!(sum.is_err()); - /// - /// // Because it short-circuited, the remaining elements are still - /// // available through the iterator. - /// assert_eq!(it.next_back(), Some(&"1")); - /// ``` - #[inline] - #[stable(feature = "iterator_try_fold", since = "1.27.0")] - fn try_rfold(&mut self, init: B, mut f: F) -> R - where - Self: Sized, - F: FnMut(B, Self::Item) -> R, - R: Try - { - let mut accum = init; - while let Some(x) = self.next_back() { - accum = f(accum, x)?; - } - Try::from_ok(accum) - } - - /// An iterator method that reduces the iterator's elements to a single, - /// final value, starting from the back. - /// - /// This is the reverse version of [`fold()`]: it takes elements starting from - /// the back of the iterator. - /// - /// `rfold()` takes two arguments: an initial value, and a closure with two - /// arguments: an 'accumulator', and an element. The closure returns the value that - /// the accumulator should have for the next iteration. - /// - /// The initial value is the value the accumulator will have on the first - /// call. - /// - /// After applying this closure to every element of the iterator, `rfold()` - /// returns the accumulator. - /// - /// This operation is sometimes called 'reduce' or 'inject'. - /// - /// Folding is useful whenever you have a collection of something, and want - /// to produce a single value from it. - /// - /// [`fold()`]: trait.Iterator.html#method.fold - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let a = [1, 2, 3]; - /// - /// // the sum of all of the elements of a - /// let sum = a.iter() - /// .rfold(0, |acc, &x| acc + x); - /// - /// assert_eq!(sum, 6); - /// ``` - /// - /// This example builds a string, starting with an initial value - /// and continuing with each element from the back until the front: - /// - /// ``` - /// let numbers = [1, 2, 3, 4, 5]; - /// - /// let zero = "0".to_string(); - /// - /// let result = numbers.iter().rfold(zero, |acc, &x| { - /// format!("({} + {})", x, acc) - /// }); - /// - /// assert_eq!(result, "(1 + (2 + (3 + (4 + (5 + 0)))))"); - /// ``` - #[inline] - #[stable(feature = "iter_rfold", since = "1.27.0")] - fn rfold(mut self, accum: B, mut f: F) -> B - where - Self: Sized, - F: FnMut(B, Self::Item) -> B, - { - self.try_rfold(accum, move |acc, x| Ok::(f(acc, x))).unwrap() - } - - /// Searches for an element of an iterator from the back that satisfies a predicate. - /// - /// `rfind()` takes a closure that returns `true` or `false`. It applies - /// this closure to each element of the iterator, starting at the end, and if any - /// of them return `true`, then `rfind()` returns [`Some(element)`]. If they all return - /// `false`, it returns [`None`]. - /// - /// `rfind()` is short-circuiting; in other words, it will stop processing - /// as soon as the closure returns `true`. - /// - /// Because `rfind()` takes a reference, and many iterators iterate over - /// references, this leads to a possibly confusing situation where the - /// argument is a double reference. You can see this effect in the - /// examples below, with `&&x`. - /// - /// [`Some(element)`]: ../../std/option/enum.Option.html#variant.Some - /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let a = [1, 2, 3]; - /// - /// assert_eq!(a.iter().rfind(|&&x| x == 2), Some(&2)); - /// - /// assert_eq!(a.iter().rfind(|&&x| x == 5), None); - /// ``` - /// - /// Stopping at the first `true`: - /// - /// ``` - /// let a = [1, 2, 3]; - /// - /// let mut iter = a.iter(); - /// - /// assert_eq!(iter.rfind(|&&x| x == 2), Some(&2)); - /// - /// // we can still use `iter`, as there are more elements. - /// assert_eq!(iter.next_back(), Some(&1)); - /// ``` - #[inline] - #[stable(feature = "iter_rfind", since = "1.27.0")] - fn rfind

(&mut self, mut predicate: P) -> Option - where - Self: Sized, - P: FnMut(&Self::Item) -> bool - { - self.try_rfold((), move |(), x| { - if predicate(&x) { LoopState::Break(x) } - else { LoopState::Continue(()) } - }).break_value() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, I: DoubleEndedIterator + ?Sized> DoubleEndedIterator for &'a mut I { - fn next_back(&mut self) -> Option { - (**self).next_back() - } - fn nth_back(&mut self, n: usize) -> Option { - (**self).nth_back(n) - } -} - -/// An iterator that knows its exact length. -/// -/// Many [`Iterator`]s don't know how many times they will iterate, but some do. -/// If an iterator knows how many times it can iterate, providing access to -/// that information can be useful. For example, if you want to iterate -/// backwards, a good start is to know where the end is. -/// -/// When implementing an `ExactSizeIterator`, you must also implement -/// [`Iterator`]. When doing so, the implementation of [`size_hint`] *must* -/// return the exact size of the iterator. -/// -/// [`Iterator`]: trait.Iterator.html -/// [`size_hint`]: trait.Iterator.html#method.size_hint -/// -/// The [`len`] method has a default implementation, so you usually shouldn't -/// implement it. However, you may be able to provide a more performant -/// implementation than the default, so overriding it in this case makes sense. -/// -/// [`len`]: #method.len -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// // a finite range knows exactly how many times it will iterate -/// let five = 0..5; -/// -/// assert_eq!(5, five.len()); -/// ``` -/// -/// In the [module level docs][moddocs], we implemented an [`Iterator`], -/// `Counter`. Let's implement `ExactSizeIterator` for it as well: -/// -/// [moddocs]: index.html -/// -/// ``` -/// # struct Counter { -/// # count: usize, -/// # } -/// # impl Counter { -/// # fn new() -> Counter { -/// # Counter { count: 0 } -/// # } -/// # } -/// # impl Iterator for Counter { -/// # type Item = usize; -/// # fn next(&mut self) -> Option { -/// # self.count += 1; -/// # if self.count < 6 { -/// # Some(self.count) -/// # } else { -/// # None -/// # } -/// # } -/// # } -/// impl ExactSizeIterator for Counter { -/// // We can easily calculate the remaining number of iterations. -/// fn len(&self) -> usize { -/// 5 - self.count -/// } -/// } -/// -/// // And now we can use it! -/// -/// let counter = Counter::new(); -/// -/// assert_eq!(5, counter.len()); -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub trait ExactSizeIterator: Iterator { - /// Returns the exact number of times the iterator will iterate. - /// - /// This method has a default implementation, so you usually should not - /// implement it directly. However, if you can provide a more efficient - /// implementation, you can do so. See the [trait-level] docs for an - /// example. - /// - /// This function has the same safety guarantees as the [`size_hint`] - /// function. - /// - /// [trait-level]: trait.ExactSizeIterator.html - /// [`size_hint`]: trait.Iterator.html#method.size_hint - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// // a finite range knows exactly how many times it will iterate - /// let five = 0..5; - /// - /// assert_eq!(5, five.len()); - /// ``` - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - fn len(&self) -> usize { - let (lower, upper) = self.size_hint(); - // Note: This assertion is overly defensive, but it checks the invariant - // guaranteed by the trait. If this trait were rust-internal, - // we could use debug_assert!; assert_eq! will check all Rust user - // implementations too. - assert_eq!(upper, Some(lower)); - lower - } - - /// Returns whether the iterator is empty. - /// - /// This method has a default implementation using `self.len()`, so you - /// don't need to implement it yourself. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// #![feature(exact_size_is_empty)] - /// - /// let mut one_element = std::iter::once(0); - /// assert!(!one_element.is_empty()); - /// - /// assert_eq!(one_element.next(), Some(0)); - /// assert!(one_element.is_empty()); - /// - /// assert_eq!(one_element.next(), None); - /// ``` - #[inline] - #[unstable(feature = "exact_size_is_empty", issue = "35428")] - fn is_empty(&self) -> bool { - self.len() == 0 - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for &mut I { - fn len(&self) -> usize { - (**self).len() - } - fn is_empty(&self) -> bool { - (**self).is_empty() - } -} - -/// Trait to represent types that can be created by summing up an iterator. -/// -/// This trait is used to implement the [`sum`] method on iterators. Types which -/// implement the trait can be generated by the [`sum`] method. Like -/// [`FromIterator`] this trait should rarely be called directly and instead -/// interacted with through [`Iterator::sum`]. -/// -/// [`sum`]: ../../std/iter/trait.Sum.html#tymethod.sum -/// [`FromIterator`]: ../../std/iter/trait.FromIterator.html -/// [`Iterator::sum`]: ../../std/iter/trait.Iterator.html#method.sum -#[stable(feature = "iter_arith_traits", since = "1.12.0")] -pub trait Sum: Sized { - /// Method which takes an iterator and generates `Self` from the elements by - /// "summing up" the items. - #[stable(feature = "iter_arith_traits", since = "1.12.0")] - fn sum>(iter: I) -> Self; -} - -/// Trait to represent types that can be created by multiplying elements of an -/// iterator. -/// -/// This trait is used to implement the [`product`] method on iterators. Types -/// which implement the trait can be generated by the [`product`] method. Like -/// [`FromIterator`] this trait should rarely be called directly and instead -/// interacted with through [`Iterator::product`]. -/// -/// [`product`]: ../../std/iter/trait.Product.html#tymethod.product -/// [`FromIterator`]: ../../std/iter/trait.FromIterator.html -/// [`Iterator::product`]: ../../std/iter/trait.Iterator.html#method.product -#[stable(feature = "iter_arith_traits", since = "1.12.0")] -pub trait Product: Sized { - /// Method which takes an iterator and generates `Self` from the elements by - /// multiplying the items. - #[stable(feature = "iter_arith_traits", since = "1.12.0")] - fn product>(iter: I) -> Self; -} - -// N.B., explicitly use Add and Mul here to inherit overflow checks -macro_rules! integer_sum_product { - (@impls $zero:expr, $one:expr, #[$attr:meta], $($a:ty)*) => ($( - #[$attr] - impl Sum for $a { - fn sum>(iter: I) -> $a { - iter.fold($zero, Add::add) - } - } - - #[$attr] - impl Product for $a { - fn product>(iter: I) -> $a { - iter.fold($one, Mul::mul) - } - } - - #[$attr] - impl<'a> Sum<&'a $a> for $a { - fn sum>(iter: I) -> $a { - iter.fold($zero, Add::add) - } - } - - #[$attr] - impl<'a> Product<&'a $a> for $a { - fn product>(iter: I) -> $a { - iter.fold($one, Mul::mul) - } - } - )*); - ($($a:ty)*) => ( - integer_sum_product!(@impls 0, 1, - #[stable(feature = "iter_arith_traits", since = "1.12.0")], - $($a)+); - integer_sum_product!(@impls Wrapping(0), Wrapping(1), - #[stable(feature = "wrapping_iter_arith", since = "1.14.0")], - $(Wrapping<$a>)+); - ); -} - -macro_rules! float_sum_product { - ($($a:ident)*) => ($( - #[stable(feature = "iter_arith_traits", since = "1.12.0")] - impl Sum for $a { - fn sum>(iter: I) -> $a { - iter.fold(0.0, |a, b| a + b) - } - } - - #[stable(feature = "iter_arith_traits", since = "1.12.0")] - impl Product for $a { - fn product>(iter: I) -> $a { - iter.fold(1.0, |a, b| a * b) - } - } - - #[stable(feature = "iter_arith_traits", since = "1.12.0")] - impl<'a> Sum<&'a $a> for $a { - fn sum>(iter: I) -> $a { - iter.fold(0.0, |a, b| a + *b) - } - } - - #[stable(feature = "iter_arith_traits", since = "1.12.0")] - impl<'a> Product<&'a $a> for $a { - fn product>(iter: I) -> $a { - iter.fold(1.0, |a, b| a * *b) - } - } - )*) -} - -integer_sum_product! { i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize } -float_sum_product! { f32 f64 } - -/// An iterator adapter that produces output as long as the underlying -/// iterator produces `Result::Ok` values. -/// -/// If an error is encountered, the iterator stops and the error is -/// stored. The error may be recovered later via `reconstruct`. -struct ResultShunt { - iter: I, - error: Option, -} - -impl ResultShunt - where I: Iterator> -{ - /// Process the given iterator as if it yielded a `T` instead of a - /// `Result`. Any errors will stop the inner iterator and - /// the overall result will be an error. - pub fn process(iter: I, mut f: F) -> Result - where F: FnMut(&mut Self) -> U - { - let mut shunt = ResultShunt::new(iter); - let value = f(shunt.by_ref()); - shunt.reconstruct(value) - } - - fn new(iter: I) -> Self { - ResultShunt { - iter, - error: None, - } - } - - /// Consume the adapter and rebuild a `Result` value. This should - /// *always* be called, otherwise any potential error would be - /// lost. - fn reconstruct(self, val: U) -> Result { - match self.error { - None => Ok(val), - Some(e) => Err(e), - } - } -} - -impl Iterator for ResultShunt - where I: Iterator> -{ - type Item = T; - - fn next(&mut self) -> Option { - match self.iter.next() { - Some(Ok(v)) => Some(v), - Some(Err(e)) => { - self.error = Some(e); - None - } - None => None, - } - } - - fn size_hint(&self) -> (usize, Option) { - if self.error.is_some() { - (0, Some(0)) - } else { - let (_, upper) = self.iter.size_hint(); - (0, upper) - } - } -} - -#[stable(feature = "iter_arith_traits_result", since="1.16.0")] -impl Sum> for Result - where T: Sum, -{ - /// Takes each element in the `Iterator`: if it is an `Err`, no further - /// elements are taken, and the `Err` is returned. Should no `Err` occur, - /// the sum of all elements is returned. - /// - /// # Examples - /// - /// This sums up every integer in a vector, rejecting the sum if a negative - /// element is encountered: - /// - /// ``` - /// let v = vec![1, 2]; - /// let res: Result = v.iter().map(|&x: &i32| - /// if x < 0 { Err("Negative element found") } - /// else { Ok(x) } - /// ).sum(); - /// assert_eq!(res, Ok(3)); - /// ``` - fn sum(iter: I) -> Result - where I: Iterator>, - { - ResultShunt::process(iter, |i| i.sum()) - } -} - -#[stable(feature = "iter_arith_traits_result", since="1.16.0")] -impl Product> for Result - where T: Product, -{ - /// Takes each element in the `Iterator`: if it is an `Err`, no further - /// elements are taken, and the `Err` is returned. Should no `Err` occur, - /// the product of all elements is returned. - fn product(iter: I) -> Result - where I: Iterator>, - { - ResultShunt::process(iter, |i| i.product()) - } -} - -/// An iterator that always continues to yield `None` when exhausted. -/// -/// Calling next on a fused iterator that has returned `None` once is guaranteed -/// to return [`None`] again. This trait should be implemented by all iterators -/// that behave this way because it allows optimizing [`Iterator::fuse`]. -/// -/// Note: In general, you should not use `FusedIterator` in generic bounds if -/// you need a fused iterator. Instead, you should just call [`Iterator::fuse`] -/// on the iterator. If the iterator is already fused, the additional [`Fuse`] -/// wrapper will be a no-op with no performance penalty. -/// -/// [`None`]: ../../std/option/enum.Option.html#variant.None -/// [`Iterator::fuse`]: ../../std/iter/trait.Iterator.html#method.fuse -/// [`Fuse`]: ../../std/iter/struct.Fuse.html -#[stable(feature = "fused", since = "1.26.0")] -pub trait FusedIterator: Iterator {} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for &mut I {} - -/// An iterator that reports an accurate length using size_hint. -/// -/// The iterator reports a size hint where it is either exact -/// (lower bound is equal to upper bound), or the upper bound is [`None`]. -/// The upper bound must only be [`None`] if the actual iterator length is -/// larger than [`usize::MAX`]. In that case, the lower bound must be -/// [`usize::MAX`], resulting in a [`.size_hint`] of `(usize::MAX, None)`. -/// -/// The iterator must produce exactly the number of elements it reported -/// or diverge before reaching the end. -/// -/// # Safety -/// -/// This trait must only be implemented when the contract is upheld. -/// Consumers of this trait must inspect [`.size_hint`]’s upper bound. -/// -/// [`None`]: ../../std/option/enum.Option.html#variant.None -/// [`usize::MAX`]: ../../std/usize/constant.MAX.html -/// [`.size_hint`]: ../../std/iter/trait.Iterator.html#method.size_hint -#[unstable(feature = "trusted_len", issue = "37572")] -pub unsafe trait TrustedLen : Iterator {} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for &mut I {} diff --git a/src/libcore/iter/traits/accum.rs b/src/libcore/iter/traits/accum.rs new file mode 100644 index 0000000000000..dfe1d2a1006d7 --- /dev/null +++ b/src/libcore/iter/traits/accum.rs @@ -0,0 +1,225 @@ +use ops::{Mul, Add}; +use num::Wrapping; + +/// Trait to represent types that can be created by summing up an iterator. +/// +/// This trait is used to implement the [`sum`] method on iterators. Types which +/// implement the trait can be generated by the [`sum`] method. Like +/// [`FromIterator`] this trait should rarely be called directly and instead +/// interacted with through [`Iterator::sum`]. +/// +/// [`sum`]: ../../std/iter/trait.Sum.html#tymethod.sum +/// [`FromIterator`]: ../../std/iter/trait.FromIterator.html +/// [`Iterator::sum`]: ../../std/iter/trait.Iterator.html#method.sum +#[stable(feature = "iter_arith_traits", since = "1.12.0")] +pub trait Sum: Sized { + /// Method which takes an iterator and generates `Self` from the elements by + /// "summing up" the items. + #[stable(feature = "iter_arith_traits", since = "1.12.0")] + fn sum>(iter: I) -> Self; +} + +/// Trait to represent types that can be created by multiplying elements of an +/// iterator. +/// +/// This trait is used to implement the [`product`] method on iterators. Types +/// which implement the trait can be generated by the [`product`] method. Like +/// [`FromIterator`] this trait should rarely be called directly and instead +/// interacted with through [`Iterator::product`]. +/// +/// [`product`]: ../../std/iter/trait.Product.html#tymethod.product +/// [`FromIterator`]: ../../std/iter/trait.FromIterator.html +/// [`Iterator::product`]: ../../std/iter/trait.Iterator.html#method.product +#[stable(feature = "iter_arith_traits", since = "1.12.0")] +pub trait Product: Sized { + /// Method which takes an iterator and generates `Self` from the elements by + /// multiplying the items. + #[stable(feature = "iter_arith_traits", since = "1.12.0")] + fn product>(iter: I) -> Self; +} + +// N.B., explicitly use Add and Mul here to inherit overflow checks +macro_rules! integer_sum_product { + (@impls $zero:expr, $one:expr, #[$attr:meta], $($a:ty)*) => ($( + #[$attr] + impl Sum for $a { + fn sum>(iter: I) -> $a { + iter.fold($zero, Add::add) + } + } + + #[$attr] + impl Product for $a { + fn product>(iter: I) -> $a { + iter.fold($one, Mul::mul) + } + } + + #[$attr] + impl<'a> Sum<&'a $a> for $a { + fn sum>(iter: I) -> $a { + iter.fold($zero, Add::add) + } + } + + #[$attr] + impl<'a> Product<&'a $a> for $a { + fn product>(iter: I) -> $a { + iter.fold($one, Mul::mul) + } + } + )*); + ($($a:ty)*) => ( + integer_sum_product!(@impls 0, 1, + #[stable(feature = "iter_arith_traits", since = "1.12.0")], + $($a)+); + integer_sum_product!(@impls Wrapping(0), Wrapping(1), + #[stable(feature = "wrapping_iter_arith", since = "1.14.0")], + $(Wrapping<$a>)+); + ); +} + +macro_rules! float_sum_product { + ($($a:ident)*) => ($( + #[stable(feature = "iter_arith_traits", since = "1.12.0")] + impl Sum for $a { + fn sum>(iter: I) -> $a { + iter.fold(0.0, |a, b| a + b) + } + } + + #[stable(feature = "iter_arith_traits", since = "1.12.0")] + impl Product for $a { + fn product>(iter: I) -> $a { + iter.fold(1.0, |a, b| a * b) + } + } + + #[stable(feature = "iter_arith_traits", since = "1.12.0")] + impl<'a> Sum<&'a $a> for $a { + fn sum>(iter: I) -> $a { + iter.fold(0.0, |a, b| a + *b) + } + } + + #[stable(feature = "iter_arith_traits", since = "1.12.0")] + impl<'a> Product<&'a $a> for $a { + fn product>(iter: I) -> $a { + iter.fold(1.0, |a, b| a * *b) + } + } + )*) +} + +integer_sum_product! { i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize } +float_sum_product! { f32 f64 } + +/// An iterator adapter that produces output as long as the underlying +/// iterator produces `Result::Ok` values. +/// +/// If an error is encountered, the iterator stops and the error is +/// stored. The error may be recovered later via `reconstruct`. +struct ResultShunt { + iter: I, + error: Option, +} + +impl ResultShunt + where I: Iterator> +{ + /// Process the given iterator as if it yielded a `T` instead of a + /// `Result`. Any errors will stop the inner iterator and + /// the overall result will be an error. + pub fn process(iter: I, mut f: F) -> Result + where F: FnMut(&mut Self) -> U + { + let mut shunt = ResultShunt::new(iter); + let value = f(shunt.by_ref()); + shunt.reconstruct(value) + } + + fn new(iter: I) -> Self { + ResultShunt { + iter, + error: None, + } + } + + /// Consume the adapter and rebuild a `Result` value. This should + /// *always* be called, otherwise any potential error would be + /// lost. + fn reconstruct(self, val: U) -> Result { + match self.error { + None => Ok(val), + Some(e) => Err(e), + } + } +} + +impl Iterator for ResultShunt + where I: Iterator> +{ + type Item = T; + + fn next(&mut self) -> Option { + match self.iter.next() { + Some(Ok(v)) => Some(v), + Some(Err(e)) => { + self.error = Some(e); + None + } + None => None, + } + } + + fn size_hint(&self) -> (usize, Option) { + if self.error.is_some() { + (0, Some(0)) + } else { + let (_, upper) = self.iter.size_hint(); + (0, upper) + } + } +} + +#[stable(feature = "iter_arith_traits_result", since="1.16.0")] +impl Sum> for Result + where T: Sum, +{ + /// Takes each element in the `Iterator`: if it is an `Err`, no further + /// elements are taken, and the `Err` is returned. Should no `Err` occur, + /// the sum of all elements is returned. + /// + /// # Examples + /// + /// This sums up every integer in a vector, rejecting the sum if a negative + /// element is encountered: + /// + /// ``` + /// let v = vec![1, 2]; + /// let res: Result = v.iter().map(|&x: &i32| + /// if x < 0 { Err("Negative element found") } + /// else { Ok(x) } + /// ).sum(); + /// assert_eq!(res, Ok(3)); + /// ``` + fn sum(iter: I) -> Result + where I: Iterator>, + { + ResultShunt::process(iter, |i| i.sum()) + } +} + +#[stable(feature = "iter_arith_traits_result", since="1.16.0")] +impl Product> for Result + where T: Product, +{ + /// Takes each element in the `Iterator`: if it is an `Err`, no further + /// elements are taken, and the `Err` is returned. Should no `Err` occur, + /// the product of all elements is returned. + fn product(iter: I) -> Result + where I: Iterator>, + { + ResultShunt::process(iter, |i| i.product()) + } +} diff --git a/src/libcore/iter/traits/collect.rs b/src/libcore/iter/traits/collect.rs new file mode 100644 index 0000000000000..5204f6a642509 --- /dev/null +++ b/src/libcore/iter/traits/collect.rs @@ -0,0 +1,349 @@ +/// Conversion from an `Iterator`. +/// +/// By implementing `FromIterator` for a type, you define how it will be +/// created from an iterator. This is common for types which describe a +/// collection of some kind. +/// +/// `FromIterator`'s [`from_iter`] is rarely called explicitly, and is instead +/// used through [`Iterator`]'s [`collect`] method. See [`collect`]'s +/// documentation for more examples. +/// +/// [`from_iter`]: #tymethod.from_iter +/// [`Iterator`]: trait.Iterator.html +/// [`collect`]: trait.Iterator.html#method.collect +/// +/// See also: [`IntoIterator`]. +/// +/// [`IntoIterator`]: trait.IntoIterator.html +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use std::iter::FromIterator; +/// +/// let five_fives = std::iter::repeat(5).take(5); +/// +/// let v = Vec::from_iter(five_fives); +/// +/// assert_eq!(v, vec![5, 5, 5, 5, 5]); +/// ``` +/// +/// Using [`collect`] to implicitly use `FromIterator`: +/// +/// ``` +/// let five_fives = std::iter::repeat(5).take(5); +/// +/// let v: Vec = five_fives.collect(); +/// +/// assert_eq!(v, vec![5, 5, 5, 5, 5]); +/// ``` +/// +/// Implementing `FromIterator` for your type: +/// +/// ``` +/// use std::iter::FromIterator; +/// +/// // A sample collection, that's just a wrapper over Vec +/// #[derive(Debug)] +/// struct MyCollection(Vec); +/// +/// // Let's give it some methods so we can create one and add things +/// // to it. +/// impl MyCollection { +/// fn new() -> MyCollection { +/// MyCollection(Vec::new()) +/// } +/// +/// fn add(&mut self, elem: i32) { +/// self.0.push(elem); +/// } +/// } +/// +/// // and we'll implement FromIterator +/// impl FromIterator for MyCollection { +/// fn from_iter>(iter: I) -> Self { +/// let mut c = MyCollection::new(); +/// +/// for i in iter { +/// c.add(i); +/// } +/// +/// c +/// } +/// } +/// +/// // Now we can make a new iterator... +/// let iter = (0..5).into_iter(); +/// +/// // ... and make a MyCollection out of it +/// let c = MyCollection::from_iter(iter); +/// +/// assert_eq!(c.0, vec![0, 1, 2, 3, 4]); +/// +/// // collect works too! +/// +/// let iter = (0..5).into_iter(); +/// let c: MyCollection = iter.collect(); +/// +/// assert_eq!(c.0, vec![0, 1, 2, 3, 4]); +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_on_unimplemented( + message="a collection of type `{Self}` cannot be built from an iterator \ + over elements of type `{A}`", + label="a collection of type `{Self}` cannot be built from `std::iter::Iterator`", +)] +pub trait FromIterator: Sized { + /// Creates a value from an iterator. + /// + /// See the [module-level documentation] for more. + /// + /// [module-level documentation]: index.html + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::iter::FromIterator; + /// + /// let five_fives = std::iter::repeat(5).take(5); + /// + /// let v = Vec::from_iter(five_fives); + /// + /// assert_eq!(v, vec![5, 5, 5, 5, 5]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + fn from_iter>(iter: T) -> Self; +} + +/// Conversion into an `Iterator`. +/// +/// By implementing `IntoIterator` for a type, you define how it will be +/// converted to an iterator. This is common for types which describe a +/// collection of some kind. +/// +/// One benefit of implementing `IntoIterator` is that your type will [work +/// with Rust's `for` loop syntax](index.html#for-loops-and-intoiterator). +/// +/// See also: [`FromIterator`]. +/// +/// [`FromIterator`]: trait.FromIterator.html +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// let v = vec![1, 2, 3]; +/// let mut iter = v.into_iter(); +/// +/// assert_eq!(Some(1), iter.next()); +/// assert_eq!(Some(2), iter.next()); +/// assert_eq!(Some(3), iter.next()); +/// assert_eq!(None, iter.next()); +/// ``` +/// Implementing `IntoIterator` for your type: +/// +/// ``` +/// // A sample collection, that's just a wrapper over Vec +/// #[derive(Debug)] +/// struct MyCollection(Vec); +/// +/// // Let's give it some methods so we can create one and add things +/// // to it. +/// impl MyCollection { +/// fn new() -> MyCollection { +/// MyCollection(Vec::new()) +/// } +/// +/// fn add(&mut self, elem: i32) { +/// self.0.push(elem); +/// } +/// } +/// +/// // and we'll implement IntoIterator +/// impl IntoIterator for MyCollection { +/// type Item = i32; +/// type IntoIter = ::std::vec::IntoIter; +/// +/// fn into_iter(self) -> Self::IntoIter { +/// self.0.into_iter() +/// } +/// } +/// +/// // Now we can make a new collection... +/// let mut c = MyCollection::new(); +/// +/// // ... add some stuff to it ... +/// c.add(0); +/// c.add(1); +/// c.add(2); +/// +/// // ... and then turn it into an Iterator: +/// for (i, n) in c.into_iter().enumerate() { +/// assert_eq!(i as i32, n); +/// } +/// ``` +/// +/// It is common to use `IntoIterator` as a trait bound. This allows +/// the input collection type to change, so long as it is still an +/// iterator. Additional bounds can be specified by restricting on +/// `Item`: +/// +/// ```rust +/// fn collect_as_strings(collection: T) -> Vec +/// where T: IntoIterator, +/// T::Item : std::fmt::Debug, +/// { +/// collection +/// .into_iter() +/// .map(|item| format!("{:?}", item)) +/// .collect() +/// } +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +pub trait IntoIterator { + /// The type of the elements being iterated over. + #[stable(feature = "rust1", since = "1.0.0")] + type Item; + + /// Which kind of iterator are we turning this into? + #[stable(feature = "rust1", since = "1.0.0")] + type IntoIter: Iterator; + + /// Creates an iterator from a value. + /// + /// See the [module-level documentation] for more. + /// + /// [module-level documentation]: index.html + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let v = vec![1, 2, 3]; + /// let mut iter = v.into_iter(); + /// + /// assert_eq!(Some(1), iter.next()); + /// assert_eq!(Some(2), iter.next()); + /// assert_eq!(Some(3), iter.next()); + /// assert_eq!(None, iter.next()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + fn into_iter(self) -> Self::IntoIter; +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl IntoIterator for I { + type Item = I::Item; + type IntoIter = I; + + fn into_iter(self) -> I { + self + } +} + +/// Extend a collection with the contents of an iterator. +/// +/// Iterators produce a series of values, and collections can also be thought +/// of as a series of values. The `Extend` trait bridges this gap, allowing you +/// to extend a collection by including the contents of that iterator. When +/// extending a collection with an already existing key, that entry is updated +/// or, in the case of collections that permit multiple entries with equal +/// keys, that entry is inserted. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// // You can extend a String with some chars: +/// let mut message = String::from("The first three letters are: "); +/// +/// message.extend(&['a', 'b', 'c']); +/// +/// assert_eq!("abc", &message[29..32]); +/// ``` +/// +/// Implementing `Extend`: +/// +/// ``` +/// // A sample collection, that's just a wrapper over Vec +/// #[derive(Debug)] +/// struct MyCollection(Vec); +/// +/// // Let's give it some methods so we can create one and add things +/// // to it. +/// impl MyCollection { +/// fn new() -> MyCollection { +/// MyCollection(Vec::new()) +/// } +/// +/// fn add(&mut self, elem: i32) { +/// self.0.push(elem); +/// } +/// } +/// +/// // since MyCollection has a list of i32s, we implement Extend for i32 +/// impl Extend for MyCollection { +/// +/// // This is a bit simpler with the concrete type signature: we can call +/// // extend on anything which can be turned into an Iterator which gives +/// // us i32s. Because we need i32s to put into MyCollection. +/// fn extend>(&mut self, iter: T) { +/// +/// // The implementation is very straightforward: loop through the +/// // iterator, and add() each element to ourselves. +/// for elem in iter { +/// self.add(elem); +/// } +/// } +/// } +/// +/// let mut c = MyCollection::new(); +/// +/// c.add(5); +/// c.add(6); +/// c.add(7); +/// +/// // let's extend our collection with three more numbers +/// c.extend(vec![1, 2, 3]); +/// +/// // we've added these elements onto the end +/// assert_eq!("MyCollection([5, 6, 7, 1, 2, 3])", format!("{:?}", c)); +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +pub trait Extend { + /// Extends a collection with the contents of an iterator. + /// + /// As this is the only method for this trait, the [trait-level] docs + /// contain more details. + /// + /// [trait-level]: trait.Extend.html + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// // You can extend a String with some chars: + /// let mut message = String::from("abc"); + /// + /// message.extend(['d', 'e', 'f'].iter()); + /// + /// assert_eq!("abcdef", &message); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + fn extend>(&mut self, iter: T); +} + +#[stable(feature = "extend_for_unit", since = "1.28.0")] +impl Extend<()> for () { + fn extend>(&mut self, iter: T) { + iter.into_iter().for_each(drop) + } +} diff --git a/src/libcore/iter/traits/double_ended.rs b/src/libcore/iter/traits/double_ended.rs new file mode 100644 index 0000000000000..2976afc0b4f81 --- /dev/null +++ b/src/libcore/iter/traits/double_ended.rs @@ -0,0 +1,297 @@ +use ops::Try; +use iter::LoopState; + +/// An iterator able to yield elements from both ends. +/// +/// Something that implements `DoubleEndedIterator` has one extra capability +/// over something that implements [`Iterator`]: the ability to also take +/// `Item`s from the back, as well as the front. +/// +/// It is important to note that both back and forth work on the same range, +/// and do not cross: iteration is over when they meet in the middle. +/// +/// In a similar fashion to the [`Iterator`] protocol, once a +/// `DoubleEndedIterator` returns `None` from a `next_back()`, calling it again +/// may or may not ever return `Some` again. `next()` and `next_back()` are +/// interchangeable for this purpose. +/// +/// [`Iterator`]: trait.Iterator.html +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// let numbers = vec![1, 2, 3, 4, 5, 6]; +/// +/// let mut iter = numbers.iter(); +/// +/// assert_eq!(Some(&1), iter.next()); +/// assert_eq!(Some(&6), iter.next_back()); +/// assert_eq!(Some(&5), iter.next_back()); +/// assert_eq!(Some(&2), iter.next()); +/// assert_eq!(Some(&3), iter.next()); +/// assert_eq!(Some(&4), iter.next()); +/// assert_eq!(None, iter.next()); +/// assert_eq!(None, iter.next_back()); +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +pub trait DoubleEndedIterator: Iterator { + /// Removes and returns an element from the end of the iterator. + /// + /// Returns `None` when there are no more elements. + /// + /// The [trait-level] docs contain more details. + /// + /// [trait-level]: trait.DoubleEndedIterator.html + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let numbers = vec![1, 2, 3, 4, 5, 6]; + /// + /// let mut iter = numbers.iter(); + /// + /// assert_eq!(Some(&1), iter.next()); + /// assert_eq!(Some(&6), iter.next_back()); + /// assert_eq!(Some(&5), iter.next_back()); + /// assert_eq!(Some(&2), iter.next()); + /// assert_eq!(Some(&3), iter.next()); + /// assert_eq!(Some(&4), iter.next()); + /// assert_eq!(None, iter.next()); + /// assert_eq!(None, iter.next_back()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + fn next_back(&mut self) -> Option; + + /// Returns the `n`th element from the end of the iterator. + /// + /// This is essentially the reversed version of [`nth`]. Although like most indexing + /// operations, the count starts from zero, so `nth_back(0)` returns the first value fro + /// the end, `nth_back(1)` the second, and so on. + /// + /// Note that all elements between the end and the returned element will be + /// consumed, including the returned element. This also means that calling + /// `nth_back(0)` multiple times on the same iterator will return different + /// elements. + /// + /// `nth_back()` will return [`None`] if `n` is greater than or equal to the length of the + /// iterator. + /// + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// [`nth`]: ../../std/iter/trait.Iterator.html#method.nth + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(iter_nth_back)] + /// let a = [1, 2, 3]; + /// assert_eq!(a.iter().nth_back(2), Some(&1)); + /// ``` + /// + /// Calling `nth_back()` multiple times doesn't rewind the iterator: + /// + /// ``` + /// #![feature(iter_nth_back)] + /// let a = [1, 2, 3]; + /// + /// let mut iter = a.iter(); + /// + /// assert_eq!(iter.nth_back(1), Some(&2)); + /// assert_eq!(iter.nth_back(1), None); + /// ``` + /// + /// 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")] + fn nth_back(&mut self, mut n: usize) -> Option { + for x in self.rev() { + if n == 0 { return Some(x) } + n -= 1; + } + None + } + + /// This is the reverse version of [`try_fold()`]: it takes elements + /// starting from the back of the iterator. + /// + /// [`try_fold()`]: trait.Iterator.html#method.try_fold + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let a = ["1", "2", "3"]; + /// let sum = a.iter() + /// .map(|&s| s.parse::()) + /// .try_rfold(0, |acc, x| x.and_then(|y| Ok(acc + y))); + /// assert_eq!(sum, Ok(6)); + /// ``` + /// + /// Short-circuiting: + /// + /// ``` + /// let a = ["1", "rust", "3"]; + /// let mut it = a.iter(); + /// let sum = it + /// .by_ref() + /// .map(|&s| s.parse::()) + /// .try_rfold(0, |acc, x| x.and_then(|y| Ok(acc + y))); + /// assert!(sum.is_err()); + /// + /// // Because it short-circuited, the remaining elements are still + /// // available through the iterator. + /// assert_eq!(it.next_back(), Some(&"1")); + /// ``` + #[inline] + #[stable(feature = "iterator_try_fold", since = "1.27.0")] + fn try_rfold(&mut self, init: B, mut f: F) -> R + where + Self: Sized, + F: FnMut(B, Self::Item) -> R, + R: Try + { + let mut accum = init; + while let Some(x) = self.next_back() { + accum = f(accum, x)?; + } + Try::from_ok(accum) + } + + /// An iterator method that reduces the iterator's elements to a single, + /// final value, starting from the back. + /// + /// This is the reverse version of [`fold()`]: it takes elements starting from + /// the back of the iterator. + /// + /// `rfold()` takes two arguments: an initial value, and a closure with two + /// arguments: an 'accumulator', and an element. The closure returns the value that + /// the accumulator should have for the next iteration. + /// + /// The initial value is the value the accumulator will have on the first + /// call. + /// + /// After applying this closure to every element of the iterator, `rfold()` + /// returns the accumulator. + /// + /// This operation is sometimes called 'reduce' or 'inject'. + /// + /// Folding is useful whenever you have a collection of something, and want + /// to produce a single value from it. + /// + /// [`fold()`]: trait.Iterator.html#method.fold + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let a = [1, 2, 3]; + /// + /// // the sum of all of the elements of a + /// let sum = a.iter() + /// .rfold(0, |acc, &x| acc + x); + /// + /// assert_eq!(sum, 6); + /// ``` + /// + /// This example builds a string, starting with an initial value + /// and continuing with each element from the back until the front: + /// + /// ``` + /// let numbers = [1, 2, 3, 4, 5]; + /// + /// let zero = "0".to_string(); + /// + /// let result = numbers.iter().rfold(zero, |acc, &x| { + /// format!("({} + {})", x, acc) + /// }); + /// + /// assert_eq!(result, "(1 + (2 + (3 + (4 + (5 + 0)))))"); + /// ``` + #[inline] + #[stable(feature = "iter_rfold", since = "1.27.0")] + fn rfold(mut self, accum: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + self.try_rfold(accum, move |acc, x| Ok::(f(acc, x))).unwrap() + } + + /// Searches for an element of an iterator from the back that satisfies a predicate. + /// + /// `rfind()` takes a closure that returns `true` or `false`. It applies + /// this closure to each element of the iterator, starting at the end, and if any + /// of them return `true`, then `rfind()` returns [`Some(element)`]. If they all return + /// `false`, it returns [`None`]. + /// + /// `rfind()` is short-circuiting; in other words, it will stop processing + /// as soon as the closure returns `true`. + /// + /// Because `rfind()` takes a reference, and many iterators iterate over + /// references, this leads to a possibly confusing situation where the + /// argument is a double reference. You can see this effect in the + /// examples below, with `&&x`. + /// + /// [`Some(element)`]: ../../std/option/enum.Option.html#variant.Some + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let a = [1, 2, 3]; + /// + /// assert_eq!(a.iter().rfind(|&&x| x == 2), Some(&2)); + /// + /// assert_eq!(a.iter().rfind(|&&x| x == 5), None); + /// ``` + /// + /// Stopping at the first `true`: + /// + /// ``` + /// let a = [1, 2, 3]; + /// + /// let mut iter = a.iter(); + /// + /// assert_eq!(iter.rfind(|&&x| x == 2), Some(&2)); + /// + /// // we can still use `iter`, as there are more elements. + /// assert_eq!(iter.next_back(), Some(&1)); + /// ``` + #[inline] + #[stable(feature = "iter_rfind", since = "1.27.0")] + fn rfind

(&mut self, mut predicate: P) -> Option + where + Self: Sized, + P: FnMut(&Self::Item) -> bool + { + self.try_rfold((), move |(), x| { + if predicate(&x) { LoopState::Break(x) } + else { LoopState::Continue(()) } + }).break_value() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, I: DoubleEndedIterator + ?Sized> DoubleEndedIterator for &'a mut I { + fn next_back(&mut self) -> Option { + (**self).next_back() + } + fn nth_back(&mut self, n: usize) -> Option { + (**self).nth_back(n) + } +} diff --git a/src/libcore/iter/traits/exact_size.rs b/src/libcore/iter/traits/exact_size.rs new file mode 100644 index 0000000000000..d6eab40213edb --- /dev/null +++ b/src/libcore/iter/traits/exact_size.rs @@ -0,0 +1,143 @@ +/// An iterator that knows its exact length. +/// +/// Many [`Iterator`]s don't know how many times they will iterate, but some do. +/// If an iterator knows how many times it can iterate, providing access to +/// that information can be useful. For example, if you want to iterate +/// backwards, a good start is to know where the end is. +/// +/// When implementing an `ExactSizeIterator`, you must also implement +/// [`Iterator`]. When doing so, the implementation of [`size_hint`] *must* +/// return the exact size of the iterator. +/// +/// [`Iterator`]: trait.Iterator.html +/// [`size_hint`]: trait.Iterator.html#method.size_hint +/// +/// The [`len`] method has a default implementation, so you usually shouldn't +/// implement it. However, you may be able to provide a more performant +/// implementation than the default, so overriding it in this case makes sense. +/// +/// [`len`]: #method.len +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// // a finite range knows exactly how many times it will iterate +/// let five = 0..5; +/// +/// assert_eq!(5, five.len()); +/// ``` +/// +/// In the [module level docs][moddocs], we implemented an [`Iterator`], +/// `Counter`. Let's implement `ExactSizeIterator` for it as well: +/// +/// [moddocs]: index.html +/// +/// ``` +/// # struct Counter { +/// # count: usize, +/// # } +/// # impl Counter { +/// # fn new() -> Counter { +/// # Counter { count: 0 } +/// # } +/// # } +/// # impl Iterator for Counter { +/// # type Item = usize; +/// # fn next(&mut self) -> Option { +/// # self.count += 1; +/// # if self.count < 6 { +/// # Some(self.count) +/// # } else { +/// # None +/// # } +/// # } +/// # } +/// impl ExactSizeIterator for Counter { +/// // We can easily calculate the remaining number of iterations. +/// fn len(&self) -> usize { +/// 5 - self.count +/// } +/// } +/// +/// // And now we can use it! +/// +/// let counter = Counter::new(); +/// +/// assert_eq!(5, counter.len()); +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +pub trait ExactSizeIterator: Iterator { + /// Returns the exact number of times the iterator will iterate. + /// + /// This method has a default implementation, so you usually should not + /// implement it directly. However, if you can provide a more efficient + /// implementation, you can do so. See the [trait-level] docs for an + /// example. + /// + /// This function has the same safety guarantees as the [`size_hint`] + /// function. + /// + /// [trait-level]: trait.ExactSizeIterator.html + /// [`size_hint`]: trait.Iterator.html#method.size_hint + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// // a finite range knows exactly how many times it will iterate + /// let five = 0..5; + /// + /// assert_eq!(5, five.len()); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + fn len(&self) -> usize { + let (lower, upper) = self.size_hint(); + // Note: This assertion is overly defensive, but it checks the invariant + // guaranteed by the trait. If this trait were rust-internal, + // we could use debug_assert!; assert_eq! will check all Rust user + // implementations too. + assert_eq!(upper, Some(lower)); + lower + } + + /// Returns `true` if the iterator is empty. + /// + /// This method has a default implementation using `self.len()`, so you + /// don't need to implement it yourself. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(exact_size_is_empty)] + /// + /// let mut one_element = std::iter::once(0); + /// assert!(!one_element.is_empty()); + /// + /// assert_eq!(one_element.next(), Some(0)); + /// assert!(one_element.is_empty()); + /// + /// assert_eq!(one_element.next(), None); + /// ``` + #[inline] + #[unstable(feature = "exact_size_is_empty", issue = "35428")] + fn is_empty(&self) -> bool { + self.len() == 0 + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for &mut I { + fn len(&self) -> usize { + (**self).len() + } + fn is_empty(&self) -> bool { + (**self).is_empty() + } +} + diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/traits/iterator.rs similarity index 95% rename from src/libcore/iter/iterator.rs rename to src/libcore/iter/traits/iterator.rs index 0ad29afbadeac..861e9c3157a79 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/traits/iterator.rs @@ -1,12 +1,11 @@ use cmp::Ordering; use ops::Try; -use super::LoopState; -use super::{Chain, Cycle, Copied, Cloned, Enumerate, Filter, FilterMap, Fuse}; -use super::{Flatten, FlatMap, flatten_compat}; -use super::{Inspect, Map, Peekable, Scan, Skip, SkipWhile, StepBy, Take, TakeWhile, Rev}; -use super::{Zip, Sum, Product}; -use super::{ChainState, FromIterator, ZipImpl}; +use super::super::LoopState; +use super::super::{Chain, Cycle, Copied, Cloned, Enumerate, Filter, FilterMap, Fuse}; +use super::super::{Flatten, FlatMap}; +use super::super::{Inspect, Map, Peekable, Scan, Skip, SkipWhile, StepBy, Take, TakeWhile, Rev}; +use super::super::{Zip, Sum, Product, FromIterator}; fn _assert_is_object_safe(_: &dyn Iterator) {} @@ -121,7 +120,7 @@ pub trait Iterator { /// // ... and then None once it's over. /// assert_eq!(None, iter.next()); /// - /// // More calls may or may not return None. Here, they always will. + /// // More calls may or may not return `None`. Here, they always will. /// assert_eq!(None, iter.next()); /// assert_eq!(None, iter.next()); /// ``` @@ -367,8 +366,7 @@ pub trait Iterator { #[inline] #[stable(feature = "iterator_step_by", since = "1.28.0")] fn step_by(self, step: usize) -> StepBy where Self: Sized { - assert!(step != 0); - StepBy{iter: self, step: step - 1, first_take: true} + StepBy::new(self, step) } /// Takes two iterators and creates a new iterator over both in sequence. @@ -425,7 +423,7 @@ pub trait Iterator { fn chain(self, other: U) -> Chain where Self: Sized, U: IntoIterator, { - Chain{a: self, b: other.into_iter(), state: ChainState::Both} + Chain::new(self, other.into_iter()) } /// 'Zips up' two iterators into a single iterator of pairs. @@ -560,15 +558,15 @@ pub trait Iterator { fn map(self, f: F) -> Map where Self: Sized, F: FnMut(Self::Item) -> B, { - Map { iter: self, f } + Map::new(self, f) } /// Calls a closure on each element of an iterator. /// /// This is equivalent to using a [`for`] loop on the iterator, although - /// `break` and `continue` are not possible from a closure. It's generally + /// `break` and `continue` are not possible from a closure. It's generally /// more idiomatic to use a `for` loop, but `for_each` may be more legible - /// when processing items at the end of longer iterator chains. In some + /// when processing items at the end of longer iterator chains. In some /// cases `for_each` may also be faster than a loop, because it will use /// internal iteration on adaptors like `Chain`. /// @@ -671,7 +669,7 @@ pub trait Iterator { fn filter

(self, predicate: P) -> Filter where Self: Sized, P: FnMut(&Self::Item) -> bool, { - Filter {iter: self, predicate } + Filter::new(self, predicate) } /// Creates an iterator that both filters and maps. @@ -728,7 +726,7 @@ pub trait Iterator { fn filter_map(self, f: F) -> FilterMap where Self: Sized, F: FnMut(Self::Item) -> Option, { - FilterMap { iter: self, f } + FilterMap::new(self, f) } /// Creates an iterator which gives the current iteration count as well as @@ -772,7 +770,7 @@ pub trait Iterator { #[inline] #[stable(feature = "rust1", since = "1.0.0")] fn enumerate(self) -> Enumerate where Self: Sized { - Enumerate { iter: self, count: 0 } + Enumerate::new(self) } /// Creates an iterator which can use `peek` to look at the next element of @@ -818,7 +816,7 @@ pub trait Iterator { #[inline] #[stable(feature = "rust1", since = "1.0.0")] fn peekable(self) -> Peekable where Self: Sized { - Peekable{iter: self, peeked: None} + Peekable::new(self) } /// Creates an iterator that [`skip`]s elements based on a predicate. @@ -881,7 +879,7 @@ pub trait Iterator { fn skip_while

(self, predicate: P) -> SkipWhile where Self: Sized, P: FnMut(&Self::Item) -> bool, { - SkipWhile { iter: self, flag: false, predicate } + SkipWhile::new(self, predicate) } /// Creates an iterator that yields elements based on a predicate. @@ -954,14 +952,13 @@ pub trait Iterator { /// ``` /// /// The `3` is no longer there, because it was consumed in order to see if - /// the iteration should stop, but wasn't placed back into the iterator or - /// some similar thing. + /// the iteration should stop, but wasn't placed back into the iterator. #[inline] #[stable(feature = "rust1", since = "1.0.0")] fn take_while

(self, predicate: P) -> TakeWhile where Self: Sized, P: FnMut(&Self::Item) -> bool, { - TakeWhile { iter: self, flag: false, predicate } + TakeWhile::new(self, predicate) } /// Creates an iterator that skips the first `n` elements. @@ -983,7 +980,7 @@ pub trait Iterator { #[inline] #[stable(feature = "rust1", since = "1.0.0")] fn skip(self, n: usize) -> Skip where Self: Sized { - Skip { iter: self, n } + Skip::new(self, n) } /// Creates an iterator that yields its first `n` elements. @@ -1015,7 +1012,7 @@ pub trait Iterator { #[inline] #[stable(feature = "rust1", since = "1.0.0")] fn take(self, n: usize) -> Take where Self: Sized, { - Take { iter: self, n } + Take::new(self, n) } /// An iterator adaptor similar to [`fold`] that holds internal state and @@ -1060,7 +1057,7 @@ pub trait Iterator { fn scan(self, initial_state: St, f: F) -> Scan where Self: Sized, F: FnMut(&mut St, Self::Item) -> Option, { - Scan { iter: self, f, state: initial_state } + Scan::new(self, initial_state, f) } /// Creates an iterator that works like map, but flattens nested structure. @@ -1098,7 +1095,7 @@ pub trait Iterator { fn flat_map(self, f: F) -> FlatMap where Self: Sized, U: IntoIterator, F: FnMut(Self::Item) -> U, { - FlatMap { inner: flatten_compat(self.map(f)) } + FlatMap::new(self, f) } /// Creates an iterator that flattens nested structure. @@ -1166,7 +1163,7 @@ pub trait Iterator { #[stable(feature = "iterator_flatten", since = "1.29.0")] fn flatten(self) -> Flatten where Self: Sized, Self::Item: IntoIterator { - Flatten { inner: flatten_compat(self) } + Flatten::new(self) } /// Creates an iterator which ends after the first [`None`]. @@ -1218,7 +1215,7 @@ pub trait Iterator { /// assert_eq!(iter.next(), Some(4)); /// assert_eq!(iter.next(), None); /// - /// // it will always return None after the first time. + /// // it will always return `None` after the first time. /// assert_eq!(iter.next(), None); /// assert_eq!(iter.next(), None); /// assert_eq!(iter.next(), None); @@ -1226,7 +1223,7 @@ pub trait Iterator { #[inline] #[stable(feature = "rust1", since = "1.0.0")] fn fuse(self) -> Fuse where Self: Sized { - Fuse{iter: self, done: false} + Fuse::new(self) } /// Do something with each element of an iterator, passing the value on. @@ -1309,7 +1306,7 @@ pub trait Iterator { fn inspect(self, f: F) -> Inspect where Self: Sized, F: FnMut(&Self::Item), { - Inspect { iter: self, f } + Inspect::new(self, f) } /// Borrows an iterator, rather than consuming it. @@ -1518,7 +1515,7 @@ pub trait Iterator { /// is propagated back to the caller immediately (short-circuiting). /// /// The initial value is the value the accumulator will have on the first - /// call. If applying the closure succeeded against every element of the + /// call. If applying the closure succeeded against every element of the /// iterator, `try_fold()` returns the final accumulator as success. /// /// Folding is useful whenever you have a collection of something, and want @@ -1531,10 +1528,10 @@ pub trait Iterator { /// do something better than the default `for` loop implementation. /// /// In particular, try to have this call `try_fold()` on the internal parts - /// from which this iterator is composed. If multiple calls are needed, + /// from which this iterator is composed. If multiple calls are needed, /// the `?` operator may be convenient for chaining the accumulator value /// along, but beware any invariants that need to be upheld before those - /// early returns. This is a `&mut self` method, so iteration needs to be + /// early returns. This is a `&mut self` method, so iteration needs to be /// resumable after hitting an error here. /// /// # Examples @@ -2183,7 +2180,7 @@ pub trait Iterator { #[inline] #[stable(feature = "rust1", since = "1.0.0")] fn rev(self) -> Rev where Self: Sized + DoubleEndedIterator { - Rev{iter: self} + Rev::new(self) } /// Converts an iterator of pairs into a pair of containers. @@ -2251,7 +2248,7 @@ pub trait Iterator { fn copied<'a, T: 'a>(self) -> Copied where Self: Sized + Iterator, T: Copy { - Copied { it: self } + Copied::new(self) } /// Creates an iterator which [`clone`]s all of its elements. @@ -2280,7 +2277,7 @@ pub trait Iterator { fn cloned<'a, T: 'a>(self) -> Cloned where Self: Sized + Iterator, T: Clone { - Cloned { it: self } + Cloned::new(self) } /// Repeats an iterator endlessly. @@ -2311,7 +2308,7 @@ pub trait Iterator { #[stable(feature = "rust1", since = "1.0.0")] #[inline] fn cycle(self) -> Cycle where Self: Sized + Clone { - Cycle{orig: self.clone(), iter: self} + Cycle::new(self) } /// Sums the elements of an iterator. @@ -2605,6 +2602,95 @@ pub trait Iterator { } } } + + /// Checks if the elements of this iterator are sorted. + /// + /// That is, for each element `a` and its following element `b`, `a <= b` must hold. If the + /// iterator yields exactly zero or one element, `true` is returned. + /// + /// Note that if `Self::Item` is only `PartialOrd`, but not `Ord`, the above definition + /// implies that this function returns `false` if any two consecutive items are not + /// comparable. + /// + /// # Examples + /// + /// ``` + /// #![feature(is_sorted)] + /// + /// assert!([1, 2, 2, 9].iter().is_sorted()); + /// assert!(![1, 3, 2, 4].iter().is_sorted()); + /// assert!([0].iter().is_sorted()); + /// assert!(std::iter::empty::().is_sorted()); + /// assert!(![0.0, 1.0, std::f32::NAN].iter().is_sorted()); + /// ``` + #[inline] + #[unstable(feature = "is_sorted", reason = "new API", issue = "53485")] + fn is_sorted(self) -> bool + where + Self: Sized, + Self::Item: PartialOrd, + { + self.is_sorted_by(|a, b| a.partial_cmp(b)) + } + + /// Checks if the elements of this iterator are sorted using the given comparator function. + /// + /// Instead of using `PartialOrd::partial_cmp`, this function uses the given `compare` + /// function to determine the ordering of two elements. Apart from that, it's equivalent to + /// [`is_sorted`]; see its documentation for more information. + /// + /// [`is_sorted`]: trait.Iterator.html#method.is_sorted + #[unstable(feature = "is_sorted", reason = "new API", issue = "53485")] + fn is_sorted_by(mut self, mut compare: F) -> bool + where + Self: Sized, + F: FnMut(&Self::Item, &Self::Item) -> Option + { + let mut last = match self.next() { + Some(e) => e, + None => return true, + }; + + while let Some(curr) = self.next() { + if compare(&last, &curr) + .map(|o| o == Ordering::Greater) + .unwrap_or(true) + { + return false; + } + last = curr; + } + + true + } + + /// Checks if the elements of this iterator are sorted using the given key extraction + /// function. + /// + /// Instead of comparing the iterator's elements directly, this function compares the keys of + /// the elements, as determined by `f`. Apart from that, it's equivalent to [`is_sorted`]; see + /// its documentation for more information. + /// + /// [`is_sorted`]: trait.Iterator.html#method.is_sorted + /// + /// # Examples + /// + /// ``` + /// #![feature(is_sorted)] + /// + /// assert!(["c", "bb", "aaa"].iter().is_sorted_by_key(|s| s.len())); + /// assert!(![-2i32, -1, 0, 3].iter().is_sorted_by_key(|n| n.abs())); + /// ``` + #[inline] + #[unstable(feature = "is_sorted", reason = "new API", issue = "53485")] + fn is_sorted_by_key(self, mut f: F) -> bool + where + Self: Sized, + F: FnMut(&Self::Item) -> K, + K: PartialOrd + { + self.is_sorted_by(|a, b| f(a).partial_cmp(&f(b))) + } } /// Select an element from an iterator based on the given "projection" diff --git a/src/libcore/iter/traits/marker.rs b/src/libcore/iter/traits/marker.rs new file mode 100644 index 0000000000000..602619bce5a96 --- /dev/null +++ b/src/libcore/iter/traits/marker.rs @@ -0,0 +1,44 @@ +/// An iterator that always continues to yield `None` when exhausted. +/// +/// Calling next on a fused iterator that has returned `None` once is guaranteed +/// to return [`None`] again. This trait should be implemented by all iterators +/// that behave this way because it allows optimizing [`Iterator::fuse`]. +/// +/// Note: In general, you should not use `FusedIterator` in generic bounds if +/// you need a fused iterator. Instead, you should just call [`Iterator::fuse`] +/// on the iterator. If the iterator is already fused, the additional [`Fuse`] +/// wrapper will be a no-op with no performance penalty. +/// +/// [`None`]: ../../std/option/enum.Option.html#variant.None +/// [`Iterator::fuse`]: ../../std/iter/trait.Iterator.html#method.fuse +/// [`Fuse`]: ../../std/iter/struct.Fuse.html +#[stable(feature = "fused", since = "1.26.0")] +pub trait FusedIterator: Iterator {} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for &mut I {} + +/// An iterator that reports an accurate length using size_hint. +/// +/// The iterator reports a size hint where it is either exact +/// (lower bound is equal to upper bound), or the upper bound is [`None`]. +/// The upper bound must only be [`None`] if the actual iterator length is +/// larger than [`usize::MAX`]. In that case, the lower bound must be +/// [`usize::MAX`], resulting in a [`.size_hint`] of `(usize::MAX, None)`. +/// +/// The iterator must produce exactly the number of elements it reported +/// or diverge before reaching the end. +/// +/// # Safety +/// +/// This trait must only be implemented when the contract is upheld. +/// Consumers of this trait must inspect [`.size_hint`]’s upper bound. +/// +/// [`None`]: ../../std/option/enum.Option.html#variant.None +/// [`usize::MAX`]: ../../std/usize/constant.MAX.html +/// [`.size_hint`]: ../../std/iter/trait.Iterator.html#method.size_hint +#[unstable(feature = "trusted_len", issue = "37572")] +pub unsafe trait TrustedLen : Iterator {} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for &mut I {} diff --git a/src/libcore/iter/traits/mod.rs b/src/libcore/iter/traits/mod.rs new file mode 100644 index 0000000000000..cf3013f423c94 --- /dev/null +++ b/src/libcore/iter/traits/mod.rs @@ -0,0 +1,15 @@ +mod iterator; +mod double_ended; +mod exact_size; +mod collect; +mod accum; +mod marker; + +#[stable(feature = "rust1", since = "1.0.0")] +pub use self::iterator::Iterator; +pub use self::double_ended::DoubleEndedIterator; +pub use self::exact_size::ExactSizeIterator; +pub use self::collect::{FromIterator, IntoIterator, Extend}; +pub use self::accum::{Sum, Product}; +#[stable(feature = "rust1", since = "1.0.0")] +pub use self::marker::{FusedIterator, TrustedLen}; diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 33c0da8a54049..f2165c676fd44 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -24,7 +24,7 @@ //! often generated by LLVM. Additionally, this library can make explicit //! calls to these functions. Their signatures are the same as found in C. //! These functions are often provided by the system libc, but can also be -//! provided by the [rlibc crate](https://crates.io/crates/rlibc). +//! provided by the [compiler-builtins crate](https://crates.io/crates/compiler_builtins). //! //! * `rust_begin_panic` - This function takes four arguments, a //! `fmt::Arguments`, a `&'static str`, and two `u32`'s. These four arguments @@ -51,18 +51,17 @@ #![cfg(not(test))] #![stable(feature = "core", since = "1.6.0")] -#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", - html_favicon_url = "https://doc.rust-lang.org/favicon.ico", - html_root_url = "https://doc.rust-lang.org/nightly/", +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/", html_playground_url = "https://play.rust-lang.org/", issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/", test(no_crate_inject, attr(deny(warnings))), test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))))] - #![no_core] -#![deny(missing_docs)] -#![deny(intra_doc_link_resolution_failure)] -#![deny(missing_debug_implementations)] + +#![warn(deprecated_in_future)] +#![warn(missing_docs)] +#![warn(intra_doc_link_resolution_failure)] +#![warn(missing_debug_implementations)] #![feature(allow_internal_unstable)] #![feature(arbitrary_self_types)] @@ -71,7 +70,6 @@ #![feature(cfg_target_has_atomic)] #![feature(concat_idents)] #![feature(const_fn)] -#![cfg_attr(stage0, feature(const_int_ops))] #![feature(const_fn_union)] #![feature(custom_attribute)] #![feature(doc_cfg)] @@ -79,6 +77,7 @@ #![feature(extern_types)] #![feature(fundamental)] #![feature(intrinsics)] +#![feature(is_sorted)] #![feature(iter_once_with)] #![feature(lang_items)] #![feature(link_llvm_intrinsics)] @@ -96,6 +95,7 @@ #![feature(simd_ffi)] #![feature(specialization)] #![feature(staged_api)] +#![feature(std_internals)] #![feature(stmt_expr_attributes)] #![feature(unboxed_closures)] #![feature(unsized_locals)] @@ -111,19 +111,20 @@ #![feature(aarch64_target_feature)] #![feature(wasm_target_feature)] #![feature(avx512_target_feature)] -#![cfg_attr(not(stage0), feature(cmpxchg16b_target_feature))] +#![feature(cmpxchg16b_target_feature)] #![feature(const_slice_len)] #![feature(const_str_as_bytes)] #![feature(const_str_len)] -#![cfg_attr(stage0, feature(const_let))] -#![cfg_attr(stage0, feature(const_int_rotate))] #![feature(const_int_conversion)] #![feature(const_transmute)] #![feature(reverse_bits)] #![feature(non_exhaustive)] #![feature(structural_match)] #![feature(abi_unadjusted)] -#![cfg_attr(not(stage0), feature(adx_target_feature))] +#![feature(adx_target_feature)] +#![feature(maybe_uninit, maybe_uninit_slice, maybe_uninit_array)] +#![feature(unrestricted_attribute_tokens)] +#![feature(external_doc)] #[prelude_import] #[allow(unused)] @@ -218,33 +219,19 @@ pub mod task; pub mod alloc; // note: does not need to be public -mod iter_private; mod tuple; mod unit; -// Pull in the `coresimd` crate directly into libcore. This is where all the -// architecture-specific (and vendor-specific) intrinsics are defined. AKA -// things like SIMD and such. Note that the actual source for all this lies in a -// different repository, rust-lang-nursery/stdsimd. That's why the setup here is -// a bit wonky. -#[allow(unused_macros)] -macro_rules! test_v16 { ($item:item) => {}; } -#[allow(unused_macros)] -macro_rules! test_v32 { ($item:item) => {}; } -#[allow(unused_macros)] -macro_rules! test_v64 { ($item:item) => {}; } -#[allow(unused_macros)] -macro_rules! test_v128 { ($item:item) => {}; } -#[allow(unused_macros)] -macro_rules! test_v256 { ($item:item) => {}; } -#[allow(unused_macros)] -macro_rules! test_v512 { ($item:item) => {}; } -#[allow(unused_macros)] -macro_rules! vector_impl { ($([$f:ident, $($args:tt)*]),*) => { $($f!($($args)*);)* } } -#[path = "../stdsimd/coresimd/mod.rs"] +// Pull in the `core_arch` crate directly into libcore. The contents of +// `core_arch` are in a different repository: rust-lang-nursery/stdsimd. +// +// `core_arch` depends on libcore, but the contents of this module are +// set up in such a way that directly pulling it here works such that the +// crate uses the this crate as its libcore. +#[path = "../stdsimd/crates/core_arch/src/mod.rs"] #[allow(missing_docs, missing_debug_implementations, dead_code, unused_imports)] #[unstable(feature = "stdsimd", issue = "48556")] -mod coresimd; +mod core_arch; #[stable(feature = "simd_arch", since = "1.27.0")] -pub use coresimd::arch; +pub use core_arch::arch; diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index 2f350df2f5c18..fdbfa56000b8e 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -1,6 +1,7 @@ -/// Entry point of thread panic, for details, see std::macros +/// Entry point of thread panic. For details, see `std::macros`. #[macro_export] -#[allow_internal_unstable] +#[cfg_attr(not(stage0), allow_internal_unstable(core_panic, __rust_unstable_column))] +#[cfg_attr(stage0, allow_internal_unstable)] #[stable(feature = "core", since = "1.6.0")] macro_rules! panic { () => ( @@ -45,9 +46,12 @@ macro_rules! assert_eq { match (&$left, &$right) { (left_val, right_val) => { if !(*left_val == *right_val) { + // The reborrows below are intentional. Without them, the stack slot for the + // borrow is initialized even before the values are compared, leading to a + // noticeable slow down. panic!(r#"assertion failed: `(left == right)` left: `{:?}`, - right: `{:?}`"#, left_val, right_val) + right: `{:?}`"#, &*left_val, &*right_val) } } } @@ -59,9 +63,12 @@ macro_rules! assert_eq { match (&($left), &($right)) { (left_val, right_val) => { if !(*left_val == *right_val) { + // The reborrows below are intentional. Without them, the stack slot for the + // borrow is initialized even before the values are compared, leading to a + // noticeable slow down. panic!(r#"assertion failed: `(left == right)` left: `{:?}`, - right: `{:?}`: {}"#, left_val, right_val, + right: `{:?}`: {}"#, &*left_val, &*right_val, format_args!($($arg)+)) } } @@ -96,9 +103,12 @@ macro_rules! assert_ne { match (&$left, &$right) { (left_val, right_val) => { if *left_val == *right_val { + // The reborrows below are intentional. Without them, the stack slot for the + // borrow is initialized even before the values are compared, leading to a + // noticeable slow down. panic!(r#"assertion failed: `(left != right)` left: `{:?}`, - right: `{:?}`"#, left_val, right_val) + right: `{:?}`"#, &*left_val, &*right_val) } } } @@ -110,9 +120,12 @@ macro_rules! assert_ne { match (&($left), &($right)) { (left_val, right_val) => { if *left_val == *right_val { + // The reborrows below are intentional. Without them, the stack slot for the + // borrow is initialized even before the values are compared, leading to a + // noticeable slow down. panic!(r#"assertion failed: `(left != right)` left: `{:?}`, - right: `{:?}`: {}"#, left_val, right_val, + right: `{:?}`: {}"#, &*left_val, &*right_val, format_args!($($arg)+)) } } @@ -409,7 +422,8 @@ macro_rules! write { /// ``` #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] -#[allow_internal_unstable] +#[cfg_attr(stage0, allow_internal_unstable)] +#[cfg_attr(not(stage0), allow_internal_unstable(format_args_nl))] macro_rules! writeln { ($dst:expr) => ( write!($dst, "\n") @@ -432,7 +446,7 @@ 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`], +/// 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. /// @@ -493,7 +507,7 @@ macro_rules! unreachable { /// A standardized placeholder for marking unfinished code. /// /// This can be useful if you are prototyping and are just looking to have your -/// code typecheck, or if you're implementing a trait that requires multiple +/// code type-check, or if you're implementing a trait that requires multiple /// methods, and you're only planning on using one of them. /// /// # Panics @@ -547,6 +561,23 @@ macro_rules! unimplemented { ($($arg:tt)+) => (panic!("not yet implemented: {}", format_args!($($arg)*))); } +/// A macro to create an array of [`MaybeUninit`] +/// +/// This macro constructs an uninitialized array of the type `[MaybeUninit; N]`. +/// +/// [`MaybeUninit`]: mem/union.MaybeUninit.html +#[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 + // 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() + }); +} + /// Built-in macros to the compiler itself. /// /// These macros do not have any corresponding definition with a `macro_rules!` diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 65752ba032104..29606cb19038f 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -78,7 +78,7 @@ impl !Send for *mut T { } /// // be made into an object /// ``` /// -/// [trait object]: ../../book/first-edition/trait-objects.html +/// [trait object]: ../../book/ch17-02-trait-objects.html #[stable(feature = "rust1", since = "1.0.0")] #[lang = "sized"] #[rustc_on_unimplemented( @@ -518,7 +518,7 @@ macro_rules! impls{ /// types. We track the Rust type using a phantom type parameter on /// the struct `ExternalResource` which wraps a handle. /// -/// [FFI]: ../../book/first-edition/ffi.html +/// [FFI]: ../../book/ch19-01-unsafe-rust.html#using-extern-functions-to-call-external-code /// /// ``` /// # #![allow(dead_code)] @@ -597,36 +597,46 @@ unsafe impl Freeze for &mut T {} /// Types which can be safely moved after being pinned. /// -/// Since Rust itself has no notion of immovable types, and will consider moves to always be safe, +/// Since Rust itself has no notion of immovable types, and considers moves +/// (e.g. through assignment or [`mem::replace`]) to always be safe, /// this trait cannot prevent types from moving by itself. /// -/// Instead it can be used to prevent moves through the type system, -/// by controlling the behavior of pointers wrapped in the [`Pin`] wrapper, +/// Instead it is used to prevent moves through the type system, +/// by controlling the behavior of pointers `P` wrapped in the [`Pin

`] wrapper, /// which "pin" the type in place by not allowing it to be moved out of them. /// See the [`pin module`] documentation for more information on pinning. /// /// Implementing this trait lifts the restrictions of pinning off a type, -/// which then allows it to move out with functions such as [`replace`]. +/// which then allows it to move out with functions such as [`mem::replace`]. +/// +/// `Unpin` has no consequence at all for non-pinned data. In particular, +/// [`mem::replace`] happily moves `!Unpin` data (it works for any `&mut T`, not +/// just when `T: Unpin`). However, you cannot use +/// [`mem::replace`] on data wrapped inside a [`Pin

`] because you cannot get the +/// `&mut T` you need for that, and *that* is what makes this system work. /// /// So this, for example, can only be done on types implementing `Unpin`: /// /// ```rust -/// use std::mem::replace; +/// use std::mem; /// use std::pin::Pin; /// /// let mut string = "this".to_string(); /// let mut pinned_string = Pin::new(&mut string); /// -/// // dereferencing the pointer mutably is only possible because String implements Unpin -/// replace(&mut *pinned_string, "other".to_string()); +/// // We need a mutable reference to call `mem::replace`. +/// // We can obtain such a reference by (implicitly) invoking `Pin::deref_mut`, +/// // but that is only possible because `String` implements `Unpin`. +/// mem::replace(&mut *pinned_string, "other".to_string()); /// ``` /// /// This trait is automatically implemented for almost every type. /// -/// [`replace`]: ../../std/mem/fn.replace.html -/// [`Pin`]: ../pin/struct.Pin.html +/// [`mem::replace`]: ../../std/mem/fn.replace.html +/// [`Pin

`]: ../pin/struct.Pin.html /// [`pin module`]: ../../std/pin/index.html #[stable(feature = "pin", since = "1.33.0")] +#[cfg_attr(not(stage0), 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 index 8fcbb73d9ce46..43afc9a522a30 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -15,6 +15,7 @@ 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**. @@ -294,11 +295,11 @@ pub const fn size_of() -> usize { /// 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], +/// 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/first-edition/trait-objects.html +/// [trait object]: ../../book/ch17-02-trait-objects.html /// /// # Examples /// @@ -402,7 +403,7 @@ pub fn align_of_val(val: &T) -> usize { unsafe { intrinsics::min_align_of_val(val) } } -/// Returns whether dropping values of type `T` matters. +/// 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. @@ -489,10 +490,8 @@ pub const fn needs_drop() -> bool { /// assert_eq!(0, x); /// ``` #[inline] -#[rustc_deprecated(since = "2.0.0", reason = "use `mem::MaybeUninit::zeroed` instead")] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn zeroed() -> T { - #[cfg(not(stage0))] intrinsics::panic_if_uninhabited::(); intrinsics::init() } @@ -626,7 +625,6 @@ pub unsafe fn zeroed() -> T { #[rustc_deprecated(since = "2.0.0", reason = "use `mem::MaybeUninit::uninitialized` instead")] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn uninitialized() -> T { - #[cfg(not(stage0))] intrinsics::panic_if_uninhabited::(); intrinsics::uninit() } @@ -714,8 +712,7 @@ pub fn replace(dest: &mut T, mut src: T) -> T { /// Disposes of a value. /// -/// While this does call the argument's implementation of [`Drop`][drop], -/// it will not release any borrows, as borrows are based on lexical scope. +/// 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 @@ -742,32 +739,6 @@ pub fn replace(dest: &mut T, mut src: T) -> T { /// drop(v); // explicitly drop the vector /// ``` /// -/// Borrows are based on lexical scope, so this produces an error: -/// -/// ```compile_fail,E0502 -/// let mut v = vec![1, 2, 3]; -/// let x = &v[0]; -/// -/// drop(x); // explicitly drop the reference, but the borrow still exists -/// -/// v.push(4); // error: cannot borrow `v` as mutable because it is also -/// // borrowed as immutable -/// ``` -/// -/// An inner scope is needed to fix this: -/// -/// ``` -/// let mut v = vec![1, 2, 3]; -/// -/// { -/// let x = &v[0]; -/// -/// drop(x); // this is now redundant, as `x` is going out of scope anyway -/// } -/// -/// v.push(4); // no problems -/// ``` -/// /// Since [`RefCell`] enforces the borrow rules at runtime, `drop` can /// release a [`RefCell`] borrow: /// @@ -987,7 +958,7 @@ impl ManuallyDrop { ManuallyDrop { value } } - /// Extract the value from the `ManuallyDrop` container. + /// Extracts the value from the `ManuallyDrop` container. /// /// This allows the value to be dropped again. /// @@ -1064,7 +1035,65 @@ impl DerefMut for ManuallyDrop { } } -/// A newtype to construct uninitialized instances of `T` +/// 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}` @@ -1084,7 +1113,7 @@ impl MaybeUninit { MaybeUninit { value: ManuallyDrop::new(val) } } - /// Create a new `MaybeUninit` in an uninitialized state. + /// 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. @@ -1094,8 +1123,8 @@ impl MaybeUninit { MaybeUninit { uninit: () } } - /// Create a new `MaybeUninit` in an uninitialized state, with the memory being - /// filled with `0` bytes. It depends on `T` whether that already makes for + /// 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. @@ -1112,71 +1141,90 @@ impl MaybeUninit { u } - /// Set the value of the `MaybeUninit`. This overwrites any previous value without dropping it. + /// 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) { + pub fn set(&mut self, val: T) -> &mut T { unsafe { self.value = ManuallyDrop::new(val); + self.get_mut() } } - /// Extract the value from the `MaybeUninit` container. This is a great way + /// 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. /// /// # Unsafety /// /// It is up to the caller to guarantee that the `MaybeUninit` really is in an initialized - /// state, otherwise this will immediately cause undefined behavior. + /// 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_inner(self) -> T { - #[cfg(not(stage0))] + pub unsafe fn into_initialized(self) -> T { intrinsics::panic_if_uninhabited::(); ManuallyDrop::into_inner(self.value) } - /// Get a reference to the contained value. + /// Gets a reference to the contained value. /// /// # Unsafety /// /// It is up to the caller to guarantee that the `MaybeUninit` really is in an initialized - /// state, otherwise this will immediately cause undefined behavior. - #[unstable(feature = "maybe_uninit", issue = "53491")] + /// 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 } - /// Get a mutable reference to the contained value. + /// Gets a mutable reference to the contained value. /// /// # Unsafety /// /// It is up to the caller to guarantee that the `MaybeUninit` really is in an initialized - /// state, otherwise this will immediately cause undefined behavior. + /// 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", issue = "53491")] + #[unstable(feature = "maybe_uninit_ref", issue = "53491")] #[inline(always)] pub unsafe fn get_mut(&mut self) -> &mut T { &mut *self.value } - /// Get a pointer to the contained value. Reading from this pointer will be undefined - /// behavior unless the `MaybeUninit` is initialized. - #[unstable(feature = "maybe_uninit", issue = "53491")] + /// Gets a pointer to the first element of the array. + #[unstable(feature = "maybe_uninit_slice", issue = "53491")] #[inline(always)] - pub fn as_ptr(&self) -> *const T { - unsafe { &*self.value as *const T } + pub fn first_ptr(this: &[MaybeUninit]) -> *const T { + this as *const [MaybeUninit] as *const T } - /// Get a mutable pointer to the contained value. Reading from this pointer will be undefined - /// behavior unless the `MaybeUninit` is initialized. - #[unstable(feature = "maybe_uninit", issue = "53491")] + /// Gets a mutable pointer to the first element of the array. + #[unstable(feature = "maybe_uninit_slice", issue = "53491")] #[inline(always)] - pub fn as_mut_ptr(&mut self) -> *mut T { - unsafe { &mut *self.value as *mut T } + pub fn first_ptr_mut(this: &mut [MaybeUninit]) -> *mut T { + this as *mut [MaybeUninit] as *mut T } } diff --git a/src/libcore/num/bignum.rs b/src/libcore/num/bignum.rs index 5326ef1e7c12e..c3a42a0fc0494 100644 --- a/src/libcore/num/bignum.rs +++ b/src/libcore/num/bignum.rs @@ -46,17 +46,6 @@ macro_rules! impl_full_ops { ($($ty:ty: add($addfn:path), mul/div($bigty:ident);)*) => ( $( impl FullOps for $ty { - #[cfg(stage0)] - fn full_add(self, other: $ty, carry: bool) -> (bool, $ty) { - // This cannot overflow; the output is between `0` and `2 * 2^nbits - 1`. - // FIXME: will LLVM optimize this into ADC or similar? - let (v, carry1) = unsafe { intrinsics::add_with_overflow(self, other) }; - let (v, carry2) = unsafe { - intrinsics::add_with_overflow(v, if carry {1} else {0}) - }; - (carry1 || carry2, v) - } - #[cfg(not(stage0))] fn full_add(self, other: $ty, carry: bool) -> (bool, $ty) { // This cannot overflow; the output is between `0` and `2 * 2^nbits - 1`. // FIXME: will LLVM optimize this into ADC or similar? diff --git a/src/libcore/num/dec2flt/algorithm.rs b/src/libcore/num/dec2flt/algorithm.rs index d56fa9662a994..3b57bb7544b35 100644 --- a/src/libcore/num/dec2flt/algorithm.rs +++ b/src/libcore/num/dec2flt/algorithm.rs @@ -61,7 +61,7 @@ mod fpu_precision { unsafe { asm!("fldcw $0" :: "m" (cw) :: "volatile") } } - /// Set the precision field of the FPU to `T` and return a `FPUControlWord` + /// Sets the precision field of the FPU to `T` and returns a `FPUControlWord`. pub fn set_precision() -> FPUControlWord { let cw = 0u16; diff --git a/src/libcore/num/dec2flt/mod.rs b/src/libcore/num/dec2flt/mod.rs index 58b196a6eac3d..47ea5aa5ff000 100644 --- a/src/libcore/num/dec2flt/mod.rs +++ b/src/libcore/num/dec2flt/mod.rs @@ -37,7 +37,7 @@ //! //! In addition, there are numerous helper functions that are used in the paper but not available //! in Rust (or at least in core). Our version is additionally complicated by the need to handle -//! overflow and underflow and the desire to handle subnormal numbers. Bellerophon and +//! overflow and underflow and the desire to handle subnormal numbers. Bellerophon and //! Algorithm R have trouble with overflow, subnormals, and underflow. We conservatively switch to //! Algorithm M (with the modifications described in section 8 of the paper) well before the //! inputs get into the critical region. @@ -54,7 +54,7 @@ //! operations as well, if you want 0.5 ULP accuracy you need to do *everything* in full precision //! and round *exactly once, at the end*, by considering all truncated bits at once. //! -//! FIXME Although some code duplication is necessary, perhaps parts of the code could be shuffled +//! FIXME: Although some code duplication is necessary, perhaps parts of the code could be shuffled //! around such that less code is duplicated. Large parts of the algorithms are independent of the //! float type to output, or only needs access to a few constants, which could be passed in as //! parameters. @@ -112,11 +112,35 @@ macro_rules! from_str_float_impl { /// * '2.5E10', or equivalently, '2.5e10' /// * '2.5E-10' /// * '5.' - /// * '.5', or, equivalently, '0.5' + /// * '.5', or, equivalently, '0.5' /// * 'inf', '-inf', 'NaN' /// /// Leading and trailing whitespace represent an error. /// + /// # Grammar + /// + /// All strings that adhere to the following [EBNF] grammar + /// will result in an [`Ok`] being returned: + /// + /// ```txt + /// Float ::= Sign? ( 'inf' | 'NaN' | Number ) + /// Number ::= ( Digit+ | + /// Digit+ '.' Digit* | + /// Digit* '.' Digit+ ) Exp? + /// Exp ::= [eE] Sign? Digit+ + /// Sign ::= [+-] + /// Digit ::= [0-9] + /// ``` + /// + /// [EBNF]: https://www.w3.org/TR/REC-xml/#sec-notation + /// + /// # Known bugs + /// + /// In some situations, some strings that should create a valid float + /// instead return an error. See [issue #31407] for details. + /// + /// [issue #31407]: https://github.com/rust-lang/rust/issues/31407 + /// /// # Arguments /// /// * src - A string @@ -124,7 +148,7 @@ macro_rules! from_str_float_impl { /// # Return value /// /// `Err(ParseFloatError)` if the string did not represent a valid - /// number. Otherwise, `Ok(n)` where `n` is the floating-point + /// number. Otherwise, `Ok(n)` where `n` is the floating-point /// number represented by `src`. #[inline] fn from_str(src: &str) -> Result { @@ -185,7 +209,7 @@ fn pfe_invalid() -> ParseFloatError { ParseFloatError { kind: FloatErrorKind::Invalid } } -/// Split decimal string into sign and the rest, without inspecting or validating the rest. +/// Splits a decimal string into sign and the rest, without inspecting or validating the rest. fn extract_sign(s: &str) -> (Sign, &str) { match s.as_bytes()[0] { b'+' => (Sign::Positive, &s[1..]), @@ -195,7 +219,7 @@ fn extract_sign(s: &str) -> (Sign, &str) { } } -/// Convert a decimal string into a floating point number. +/// Converts a decimal string into a floating point number. fn dec2flt(s: &str) -> Result { if s.is_empty() { return Err(pfe_empty()) diff --git a/src/libcore/num/dec2flt/num.rs b/src/libcore/num/dec2flt/num.rs index b76c58cc66e6b..126713185711b 100644 --- a/src/libcore/num/dec2flt/num.rs +++ b/src/libcore/num/dec2flt/num.rs @@ -27,7 +27,7 @@ pub fn compare_with_half_ulp(f: &Big, ones_place: usize) -> Ordering { Equal } -/// Convert an ASCII string containing only decimal digits to a `u64`. +/// Converts an ASCII string containing only decimal digits to a `u64`. /// /// Does not perform checks for overflow or invalid characters, so if the caller is not careful, /// the result is bogus and can panic (though it won't be `unsafe`). Additionally, empty strings @@ -44,7 +44,7 @@ pub fn from_str_unchecked<'a, T>(bytes: T) -> u64 where T : IntoIterator Big { @@ -69,7 +69,7 @@ pub fn to_u64(x: &Big) -> u64 { } -/// Extract a range of bits. +/// Extracts a range of bits. /// Index 0 is the least significant bit and the range is half-open as usual. /// Panics if asked to extract more bits than fit into the return type. diff --git a/src/libcore/num/dec2flt/parse.rs b/src/libcore/num/dec2flt/parse.rs index 9e075e43303b6..933f8c1d3f781 100644 --- a/src/libcore/num/dec2flt/parse.rs +++ b/src/libcore/num/dec2flt/parse.rs @@ -42,7 +42,7 @@ pub enum ParseResult<'a> { Invalid, } -/// Check if the input string is a valid floating point number and if so, locate the integral +/// 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 { if s.is_empty() { diff --git a/src/libcore/num/dec2flt/rawfp.rs b/src/libcore/num/dec2flt/rawfp.rs index 6976bd1a0eefd..b65f539b29c97 100644 --- a/src/libcore/num/dec2flt/rawfp.rs +++ b/src/libcore/num/dec2flt/rawfp.rs @@ -59,10 +59,10 @@ pub trait RawFloat /// Type used by `to_bits` and `from_bits`. type Bits: Add + From + TryFrom; - /// Raw transmutation to integer. + /// Performs a raw transmutation to an integer. fn to_bits(self) -> Self::Bits; - /// Raw transmutation from integer. + /// Performs a raw transmutation from an integer. fn from_bits(v: Self::Bits) -> Self; /// Returns the category that this number falls into. @@ -71,14 +71,14 @@ pub trait RawFloat /// Returns the mantissa, exponent and sign as integers. fn integer_decode(self) -> (u64, i16, i8); - /// Decode the float. + /// Decodes the float. fn unpack(self) -> Unpacked; - /// Cast from a small integer that can be represented exactly. Panic if the integer can't be + /// Casts from a small integer that can be represented exactly. Panic if the integer can't be /// represented, the other code in this module makes sure to never let that happen. fn from_int(x: u64) -> Self; - /// Get the value 10e from a pre-computed table. + /// Gets the value 10e from a pre-computed table. /// Panics for `e >= CEIL_LOG5_OF_MAX_SIG`. fn short_fast_pow10(e: usize) -> Self; @@ -240,7 +240,7 @@ impl RawFloat for f64 { fn from_bits(v: Self::Bits) -> Self { Self::from_bits(v) } } -/// Convert an Fp to the closest machine float type. +/// Converts an `Fp` to the closest machine float type. /// Does not handle subnormal results. pub fn fp_to_float(x: Fp) -> T { let x = x.normalize(); @@ -319,7 +319,7 @@ pub fn big_to_fp(f: &Big) -> Fp { } } -/// Find the largest floating point number strictly smaller than the argument. +/// Finds the largest floating point number strictly smaller than the argument. /// Does not handle subnormals, zero, or exponent underflow. pub fn prev_float(x: T) -> T { match x.classify() { diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 68da79135d3a3..dc0580764acb7 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -144,7 +144,7 @@ pub mod consts { #[lang = "f32"] #[cfg(not(test))] impl f32 { - /// Returns `true` if this value is `NaN` and false otherwise. + /// Returns `true` if this value is `NaN`. /// /// ``` /// use std::f32; @@ -169,8 +169,8 @@ impl f32 { f32::from_bits(self.to_bits() & 0x7fff_ffff) } - /// Returns `true` if this value is positive infinity or negative infinity and - /// false otherwise. + /// Returns `true` if this value is positive infinity or negative infinity, and + /// `false` otherwise. /// /// ``` /// use std::f32; @@ -272,7 +272,7 @@ impl f32 { } } - /// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with + /// Returns `true` if `self` has a positive sign, including `+0.0`, `NaN`s with /// positive sign bit and positive infinity. /// /// ``` @@ -288,7 +288,7 @@ impl f32 { !self.is_sign_negative() } - /// Returns `true` if and only if `self` has a negative sign, including `-0.0`, `NaN`s with + /// Returns `true` if `self` has a negative sign, including `-0.0`, `NaN`s with /// negative sign bit and negative infinity. /// /// ``` diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index b677391548146..c3677f8c8faea 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -144,7 +144,7 @@ pub mod consts { #[lang = "f64"] #[cfg(not(test))] impl f64 { - /// Returns `true` if this value is `NaN` and false otherwise. + /// Returns `true` if this value is `NaN`. /// /// ``` /// use std::f64; @@ -169,8 +169,8 @@ impl f64 { f64::from_bits(self.to_bits() & 0x7fff_ffff_ffff_ffff) } - /// Returns `true` if this value is positive infinity or negative infinity and - /// false otherwise. + /// Returns `true` if this value is positive infinity or negative infinity, and + /// `false` otherwise. /// /// ``` /// use std::f64; @@ -272,7 +272,7 @@ impl f64 { } } - /// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with + /// Returns `true` if `self` has a positive sign, including `+0.0`, `NaN`s with /// positive sign bit and positive infinity. /// /// ``` @@ -296,7 +296,7 @@ impl f64 { self.is_sign_positive() } - /// Returns `true` if and only if `self` has a negative sign, including `-0.0`, `NaN`s with + /// Returns `true` if `self` has a negative sign, including `-0.0`, `NaN`s with /// negative sign bit and negative infinity. /// /// ``` diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 6827364c0f805..5b7d5f45d9246 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -10,9 +10,9 @@ use ops; use str::FromStr; macro_rules! impl_nonzero_fmt { - ( ( $( $Trait: ident ),+ ) for $Ty: ident ) => { + ( #[$stability: meta] ( $( $Trait: ident ),+ ) for $Ty: ident ) => { $( - #[stable(feature = "nonzero", since = "1.28.0")] + #[$stability] impl fmt::$Trait for $Ty { #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -31,7 +31,7 @@ macro_rules! doc_comment { } macro_rules! nonzero_integers { - ( $( $Ty: ident($Int: ty); )+ ) => { + ( $( #[$stability: meta] $Ty: ident($Int: ty); )+ ) => { $( doc_comment! { concat!("An integer that is known not to equal zero. @@ -41,10 +41,10 @@ For example, `Option<", stringify!($Ty), ">` is the same size as `", stringify!( ```rust use std::mem::size_of; -assert_eq!(size_of::>(), size_of::<", stringify!($Int), +assert_eq!(size_of::>(), size_of::<", stringify!($Int), ">()); ```"), - #[stable(feature = "nonzero", since = "1.28.0")] + #[$stability] #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] #[repr(transparent)] #[rustc_layout_scalar_valid_range_start(1)] @@ -52,19 +52,19 @@ assert_eq!(size_of::>(), size_of::<", st } impl $Ty { - /// Create a non-zero without checking the value. + /// Creates a non-zero without checking the value. /// /// # Safety /// /// The value must not be zero. - #[stable(feature = "nonzero", since = "1.28.0")] + #[$stability] #[inline] pub const unsafe fn new_unchecked(n: $Int) -> Self { $Ty(n) } - /// Create a non-zero if the given value is not zero. - #[stable(feature = "nonzero", since = "1.28.0")] + /// Creates a non-zero if the given value is not zero. + #[$stability] #[inline] pub fn new(n: $Int) -> Option { if n != 0 { @@ -75,7 +75,7 @@ assert_eq!(size_of::>(), size_of::<", st } /// Returns the value as a primitive type. - #[stable(feature = "nonzero", since = "1.28.0")] + #[$stability] #[inline] pub const fn get(self) -> $Int { self.0 @@ -91,19 +91,25 @@ assert_eq!(size_of::>(), size_of::<", st } impl_nonzero_fmt! { - (Debug, Display, Binary, Octal, LowerHex, UpperHex) for $Ty + #[$stability] (Debug, Display, Binary, Octal, LowerHex, UpperHex) for $Ty } )+ } } nonzero_integers! { - NonZeroU8(u8); - NonZeroU16(u16); - NonZeroU32(u32); - NonZeroU64(u64); - NonZeroU128(u128); - NonZeroUsize(usize); + #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU8(u8); + #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU16(u16); + #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU32(u32); + #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU64(u64); + #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU128(u128); + #[stable(feature = "nonzero", since = "1.28.0")] NonZeroUsize(usize); + #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI8(i8); + #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI16(i16); + #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI32(i32); + #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI64(i64); + #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI128(i128); + #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroIsize(isize); } /// Provides intentionally-wrapped arithmetic on `T`. @@ -275,7 +281,6 @@ $EndFeature, " ``` "), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(stage0, rustc_const_unstable(feature = "const_int_ops"))] #[inline] pub const fn count_ones(self) -> u32 { (self as $UnsignedT).count_ones() } } @@ -291,7 +296,6 @@ Basic usage: ", $Feature, "assert_eq!(", stringify!($SelfT), "::max_value().count_zeros(), 1);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(stage0, rustc_const_unstable(feature = "const_int_ops"))] #[inline] pub const fn count_zeros(self) -> u32 { (!self).count_ones() @@ -312,7 +316,6 @@ assert_eq!(n.leading_zeros(), 0);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(stage0, rustc_const_unstable(feature = "const_int_ops"))] #[inline] pub const fn leading_zeros(self) -> u32 { (self as $UnsignedT).leading_zeros() @@ -333,7 +336,6 @@ assert_eq!(n.trailing_zeros(), 2);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(stage0, rustc_const_unstable(feature = "const_int_ops"))] #[inline] pub const fn trailing_zeros(self) -> u32 { (self as $UnsignedT).trailing_zeros() @@ -357,7 +359,6 @@ let m = ", $rot_result, "; assert_eq!(n.rotate_left(", $rot, "), m); ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(stage0, rustc_const_unstable(feature = "const_int_rotate"))] #[inline] pub const fn rotate_left(self, n: u32) -> Self { (self as $UnsignedT).rotate_left(n) as Self @@ -382,7 +383,6 @@ let m = ", $rot_op, "; assert_eq!(n.rotate_right(", $rot, "), m); ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(stage0, rustc_const_unstable(feature = "const_int_rotate"))] #[inline] pub const fn rotate_right(self, n: u32) -> Self { (self as $UnsignedT).rotate_right(n) as Self @@ -404,7 +404,6 @@ let m = n.swap_bytes(); assert_eq!(m, ", $swapped, "); ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(stage0, rustc_const_unstable(feature = "const_int_ops"))] #[inline] pub const fn swap_bytes(self) -> Self { (self as $UnsignedT).swap_bytes() as Self @@ -454,7 +453,6 @@ if cfg!(target_endian = \"big\") { $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(stage0, rustc_const_unstable(feature = "const_int_ops"))] #[inline] pub const fn from_be(x: Self) -> Self { #[cfg(target_endian = "big")] @@ -488,7 +486,6 @@ if cfg!(target_endian = \"little\") { $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(stage0, rustc_const_unstable(feature = "const_int_ops"))] #[inline] pub const fn from_le(x: Self) -> Self { #[cfg(target_endian = "little")] @@ -522,7 +519,6 @@ if cfg!(target_endian = \"big\") { $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(stage0, rustc_const_unstable(feature = "const_int_ops"))] #[inline] pub const fn to_be(self) -> Self { // or not to be? #[cfg(target_endian = "big")] @@ -556,7 +552,6 @@ if cfg!(target_endian = \"little\") { $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(stage0, rustc_const_unstable(feature = "const_int_ops"))] #[inline] pub const fn to_le(self) -> Self { #[cfg(target_endian = "little")] @@ -841,13 +836,12 @@ overflow occurred. Basic usage: ``` -#![feature(no_panic_pow)] ", $Feature, "assert_eq!(8", stringify!($SelfT), ".checked_pow(2), Some(64)); assert_eq!(", stringify!($SelfT), "::max_value().checked_pow(2), None);", $EndFeature, " ```"), - #[unstable(feature = "no_panic_pow", issue = "48320")] + #[stable(feature = "no_panic_pow", since = "1.34.0")] #[inline] pub fn checked_pow(self, mut exp: u32) -> Option { let mut base = self; @@ -888,6 +882,7 @@ $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, @@ -895,6 +890,31 @@ $EndFeature, " None => Self::min_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!(", stringify!($SelfT), "::max_value().saturating_add(100), ", stringify!($SelfT), +"::max_value());", +$EndFeature, " +```"), + + #[stable(feature = "rust1", since = "1.0.0")] + #[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) + } } doc_comment! { @@ -913,6 +933,7 @@ $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, @@ -922,6 +943,29 @@ $EndFeature, " } } + 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(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")] + #[inline] + #[cfg(not(stage0))] + pub const fn saturating_sub(self, rhs: Self) -> Self { + intrinsics::saturating_sub(self, rhs) + } + } + doc_comment! { concat!("Saturating integer multiplication. Computes `self * rhs`, saturating at the numeric bounds instead of overflowing. @@ -960,7 +1004,6 @@ saturating at the numeric bounds instead of overflowing. Basic usage: ``` -#![feature(no_panic_pow)] ", $Feature, "use std::", stringify!($SelfT), "; assert_eq!((-4", stringify!($SelfT), ").saturating_pow(3), -64); @@ -968,7 +1011,7 @@ assert_eq!(", stringify!($SelfT), "::MIN.saturating_pow(2), ", stringify!($SelfT assert_eq!(", stringify!($SelfT), "::MIN.saturating_pow(3), ", stringify!($SelfT), "::MIN);", $EndFeature, " ```"), - #[unstable(feature = "no_panic_pow", issue = "48320")] + #[stable(feature = "no_panic_pow", since = "1.34.0")] #[inline] pub fn saturating_pow(self, exp: u32) -> Self { match self.checked_pow(exp) { @@ -994,14 +1037,8 @@ assert_eq!(", stringify!($SelfT), "::max_value().wrapping_add(2), ", stringify!( $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(stage0, rustc_const_unstable(feature = "const_int_wrapping"))] #[inline] pub const fn wrapping_add(self, rhs: Self) -> Self { - #[cfg(stage0)] - unsafe { - intrinsics::overflowing_add(self, rhs) - } - #[cfg(not(stage0))] intrinsics::overflowing_add(self, rhs) } } @@ -1021,14 +1058,8 @@ stringify!($SelfT), "::max_value());", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(stage0, rustc_const_unstable(feature = "const_int_wrapping"))] #[inline] pub const fn wrapping_sub(self, rhs: Self) -> Self { - #[cfg(stage0)] - unsafe { - intrinsics::overflowing_sub(self, rhs) - } - #[cfg(not(stage0))] intrinsics::overflowing_sub(self, rhs) } } @@ -1047,14 +1078,8 @@ assert_eq!(11i8.wrapping_mul(12), -124);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(stage0, rustc_const_unstable(feature = "const_int_wrapping"))] #[inline] pub const fn wrapping_mul(self, rhs: Self) -> Self { - #[cfg(stage0)] - unsafe { - intrinsics::overflowing_mul(self, rhs) - } - #[cfg(not(stage0))] intrinsics::overflowing_mul(self, rhs) } } @@ -1190,7 +1215,7 @@ $EndFeature, " ```"), #[stable(feature = "num_wrapping", since = "1.2.0")] #[inline] - pub fn wrapping_neg(self) -> Self { + pub const fn wrapping_neg(self) -> Self { self.overflowing_neg().0 } } @@ -1214,7 +1239,6 @@ assert_eq!((-1", stringify!($SelfT), ").wrapping_shl(128), -1);", $EndFeature, " ```"), #[stable(feature = "num_wrapping", since = "1.2.0")] - #[cfg_attr(stage0, rustc_const_unstable(feature = "const_int_wrapping"))] #[inline] pub const fn wrapping_shl(self, rhs: u32) -> Self { unsafe { @@ -1242,7 +1266,6 @@ assert_eq!((-128i16).wrapping_shr(64), -128);", $EndFeature, " ```"), #[stable(feature = "num_wrapping", since = "1.2.0")] - #[cfg_attr(stage0, rustc_const_unstable(feature = "const_int_wrapping"))] #[inline] pub const fn wrapping_shr(self, rhs: u32) -> Self { unsafe { @@ -1291,13 +1314,12 @@ wrapping around at the boundary of the type. Basic usage: ``` -#![feature(no_panic_pow)] ", $Feature, "assert_eq!(3", stringify!($SelfT), ".wrapping_pow(4), 81); assert_eq!(3i8.wrapping_pow(5), -13); assert_eq!(3i8.wrapping_pow(6), -39);", $EndFeature, " ```"), - #[unstable(feature = "no_panic_pow", issue = "48320")] + #[stable(feature = "no_panic_pow", since = "1.34.0")] #[inline] pub fn wrapping_pow(self, mut exp: u32) -> Self { let mut base = self; @@ -1340,14 +1362,8 @@ assert_eq!(", stringify!($SelfT), "::MAX.overflowing_add(1), (", stringify!($Sel "::MIN, true));", $EndFeature, " ```"), #[stable(feature = "wrapping", since = "1.7.0")] - #[cfg_attr(stage0, rustc_const_unstable(feature = "const_int_overflowing"))] #[inline] pub const fn overflowing_add(self, rhs: Self) -> (Self, bool) { - #[cfg(stage0)] - let (a, b) = unsafe { - intrinsics::add_with_overflow(self as $ActualT, rhs as $ActualT) - }; - #[cfg(not(stage0))] let (a, b) = intrinsics::add_with_overflow(self as $ActualT, rhs as $ActualT); (a as Self, b) } @@ -1371,14 +1387,8 @@ assert_eq!(", stringify!($SelfT), "::MIN.overflowing_sub(1), (", stringify!($Sel "::MAX, true));", $EndFeature, " ```"), #[stable(feature = "wrapping", since = "1.7.0")] - #[cfg_attr(stage0, rustc_const_unstable(feature = "const_int_overflowing"))] #[inline] pub const fn overflowing_sub(self, rhs: Self) -> (Self, bool) { - #[cfg(stage0)] - let (a, b) = unsafe { - intrinsics::sub_with_overflow(self as $ActualT, rhs as $ActualT) - }; - #[cfg(not(stage0))] let (a, b) = intrinsics::sub_with_overflow(self as $ActualT, rhs as $ActualT); (a as Self, b) } @@ -1400,14 +1410,8 @@ assert_eq!(1_000_000_000i32.overflowing_mul(10), (1410065408, true));", $EndFeature, " ```"), #[stable(feature = "wrapping", since = "1.7.0")] - #[cfg_attr(stage0, rustc_const_unstable(feature = "const_int_overflowing"))] #[inline] pub const fn overflowing_mul(self, rhs: Self) -> (Self, bool) { - #[cfg(stage0)] - let (a, b) = unsafe { - intrinsics::mul_with_overflow(self as $ActualT, rhs as $ActualT) - }; - #[cfg(not(stage0))] let (a, b) = intrinsics::mul_with_overflow(self as $ActualT, rhs as $ActualT); (a as Self, b) } @@ -1565,12 +1569,8 @@ assert_eq!(", stringify!($SelfT), "::MIN.overflowing_neg(), (", stringify!($Self ```"), #[inline] #[stable(feature = "wrapping", since = "1.7.0")] - pub fn overflowing_neg(self) -> (Self, bool) { - if self == Self::min_value() { - (Self::min_value(), true) - } else { - (-self, false) - } + pub const fn overflowing_neg(self) -> (Self, bool) { + ((!self).wrapping_add(1), self == Self::min_value()) } } @@ -1591,7 +1591,6 @@ assert_eq!(0x1i32.overflowing_shl(36), (0x10, true));", $EndFeature, " ```"), #[stable(feature = "wrapping", since = "1.7.0")] - #[cfg_attr(stage0, rustc_const_unstable(feature = "const_int_overflowing"))] #[inline] pub const fn overflowing_shl(self, rhs: u32) -> (Self, bool) { (self.wrapping_shl(rhs), (rhs > ($BITS - 1))) @@ -1615,7 +1614,6 @@ assert_eq!(0x10i32.overflowing_shr(36), (0x1, true));", $EndFeature, " ```"), #[stable(feature = "wrapping", since = "1.7.0")] - #[cfg_attr(stage0, rustc_const_unstable(feature = "const_int_overflowing"))] #[inline] pub const fn overflowing_shr(self, rhs: u32) -> (Self, bool) { (self.wrapping_shr(rhs), (rhs > ($BITS - 1))) @@ -1663,12 +1661,11 @@ whether an overflow happened. Basic usage: ``` -#![feature(no_panic_pow)] ", $Feature, "assert_eq!(3", stringify!($SelfT), ".overflowing_pow(4), (81, false)); assert_eq!(3i8.overflowing_pow(5), (-13, true));", $EndFeature, " ```"), - #[unstable(feature = "no_panic_pow", issue = "48320")] + #[stable(feature = "no_panic_pow", since = "1.34.0")] #[inline] pub fn overflowing_pow(self, mut exp: u32) -> (Self, bool) { let mut base = self; @@ -2240,13 +2237,9 @@ Basic usage: assert_eq!(n.count_ones(), 3);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(stage0, rustc_const_unstable(feature = "const_int_ops"))] #[inline] pub const fn count_ones(self) -> u32 { - #[cfg(stage0)] - unsafe { intrinsics::ctpop(self as $ActualT) as u32 } - #[cfg(not(stage0))] - { intrinsics::ctpop(self as $ActualT) as u32 } + intrinsics::ctpop(self as $ActualT) as u32 } } @@ -2261,7 +2254,6 @@ Basic usage: ", $Feature, "assert_eq!(", stringify!($SelfT), "::max_value().count_zeros(), 0);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(stage0, rustc_const_unstable(feature = "const_int_ops"))] #[inline] pub const fn count_zeros(self) -> u32 { (!self).count_ones() @@ -2281,13 +2273,9 @@ Basic usage: assert_eq!(n.leading_zeros(), 2);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(stage0, rustc_const_unstable(feature = "const_int_ops"))] #[inline] pub const fn leading_zeros(self) -> u32 { - #[cfg(stage0)] - unsafe { intrinsics::ctlz(self as $ActualT) as u32 } - #[cfg(not(stage0))] - { intrinsics::ctlz(self as $ActualT) as u32 } + intrinsics::ctlz(self as $ActualT) as u32 } } @@ -2305,13 +2293,9 @@ Basic usage: assert_eq!(n.trailing_zeros(), 3);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(stage0, rustc_const_unstable(feature = "const_int_ops"))] #[inline] pub const fn trailing_zeros(self) -> u32 { - #[cfg(stage0)] - unsafe { intrinsics::cttz(self) as u32 } - #[cfg(not(stage0))] - { intrinsics::cttz(self) as u32 } + intrinsics::cttz(self) as u32 } } @@ -2332,12 +2316,8 @@ let m = ", $rot_result, "; assert_eq!(n.rotate_left(", $rot, "), m); ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(stage0, rustc_const_unstable(feature = "const_int_rotate"))] #[inline] pub const fn rotate_left(self, n: u32) -> Self { - #[cfg(stage0)] - unsafe { intrinsics::rotate_left(self, n as $SelfT) } - #[cfg(not(stage0))] intrinsics::rotate_left(self, n as $SelfT) } } @@ -2360,12 +2340,8 @@ let m = ", $rot_op, "; assert_eq!(n.rotate_right(", $rot, "), m); ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(stage0, rustc_const_unstable(feature = "const_int_rotate"))] #[inline] pub const fn rotate_right(self, n: u32) -> Self { - #[cfg(stage0)] - unsafe { intrinsics::rotate_right(self, n as $SelfT) } - #[cfg(not(stage0))] intrinsics::rotate_right(self, n as $SelfT) } } @@ -2385,13 +2361,9 @@ let m = n.swap_bytes(); assert_eq!(m, ", $swapped, "); ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(stage0, rustc_const_unstable(feature = "const_int_ops"))] #[inline] pub const fn swap_bytes(self) -> Self { - #[cfg(stage0)] - unsafe { intrinsics::bswap(self as $ActualT) as Self } - #[cfg(not(stage0))] - { intrinsics::bswap(self as $ActualT) as Self } + intrinsics::bswap(self as $ActualT) as Self } } @@ -2411,13 +2383,9 @@ let m = n.reverse_bits(); assert_eq!(m, ", $reversed, "); ```"), #[unstable(feature = "reverse_bits", issue = "48763")] - #[cfg_attr(stage0, rustc_const_unstable(feature = "const_int_conversion"))] #[inline] pub const fn reverse_bits(self) -> Self { - #[cfg(stage0)] - unsafe { intrinsics::bitreverse(self as $ActualT) as Self } - #[cfg(not(stage0))] - { intrinsics::bitreverse(self as $ActualT) as Self } + intrinsics::bitreverse(self as $ActualT) as Self } } @@ -2441,7 +2409,6 @@ if cfg!(target_endian = \"big\") { }", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(stage0, rustc_const_unstable(feature = "const_int_ops"))] #[inline] pub const fn from_be(x: Self) -> Self { #[cfg(target_endian = "big")] @@ -2475,7 +2442,6 @@ if cfg!(target_endian = \"little\") { }", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(stage0, rustc_const_unstable(feature = "const_int_ops"))] #[inline] pub const fn from_le(x: Self) -> Self { #[cfg(target_endian = "little")] @@ -2509,7 +2475,6 @@ if cfg!(target_endian = \"big\") { }", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(stage0, rustc_const_unstable(feature = "const_int_ops"))] #[inline] pub const fn to_be(self) -> Self { // or not to be? #[cfg(target_endian = "big")] @@ -2543,7 +2508,6 @@ if cfg!(target_endian = \"little\") { }", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(stage0, rustc_const_unstable(feature = "const_int_ops"))] #[inline] pub const fn to_le(self) -> Self { #[cfg(target_endian = "little")] @@ -2783,11 +2747,10 @@ overflow occurred. Basic usage: ``` -#![feature(no_panic_pow)] ", $Feature, "assert_eq!(2", stringify!($SelfT), ".checked_pow(5), Some(32)); assert_eq!(", stringify!($SelfT), "::max_value().checked_pow(2), None);", $EndFeature, " ```"), - #[unstable(feature = "no_panic_pow", issue = "48320")] + #[stable(feature = "no_panic_pow", since = "1.34.0")] #[inline] pub fn checked_pow(self, mut exp: u32) -> Option { let mut base = self; @@ -2826,6 +2789,7 @@ 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, @@ -2834,6 +2798,28 @@ assert_eq!(200u8.saturating_add(127), 255);", $EndFeature, " } } + 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")] + #[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) + } + } + doc_comment! { concat!("Saturating integer subtraction. Computes `self - rhs`, saturating at the numeric bounds instead of overflowing. @@ -2848,6 +2834,7 @@ 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, @@ -2856,6 +2843,27 @@ assert_eq!(13", stringify!($SelfT), ".saturating_sub(127), 0);", $EndFeature, " } } + 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")] + #[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) + } + } + doc_comment! { concat!("Saturating integer multiplication. Computes `self * rhs`, saturating at the numeric bounds instead of overflowing. @@ -2887,14 +2895,13 @@ saturating at the numeric bounds instead of overflowing. Basic usage: ``` -#![feature(no_panic_pow)] ", $Feature, "use std::", stringify!($SelfT), "; assert_eq!(4", stringify!($SelfT), ".saturating_pow(3), 64); assert_eq!(", stringify!($SelfT), "::MAX.saturating_pow(2), ", stringify!($SelfT), "::MAX);", $EndFeature, " ```"), - #[unstable(feature = "no_panic_pow", issue = "48320")] + #[stable(feature = "no_panic_pow", since = "1.34.0")] #[inline] pub fn saturating_pow(self, exp: u32) -> Self { match self.checked_pow(exp) { @@ -2918,14 +2925,8 @@ assert_eq!(200", stringify!($SelfT), ".wrapping_add(", stringify!($SelfT), "::ma $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(stage0, rustc_const_unstable(feature = "const_int_wrapping"))] #[inline] pub const fn wrapping_add(self, rhs: Self) -> Self { - #[cfg(stage0)] - unsafe { - intrinsics::overflowing_add(self, rhs) - } - #[cfg(not(stage0))] intrinsics::overflowing_add(self, rhs) } } @@ -2944,14 +2945,8 @@ assert_eq!(100", stringify!($SelfT), ".wrapping_sub(", stringify!($SelfT), "::ma $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(stage0, rustc_const_unstable(feature = "const_int_wrapping"))] #[inline] pub const fn wrapping_sub(self, rhs: Self) -> Self { - #[cfg(stage0)] - unsafe { - intrinsics::overflowing_sub(self, rhs) - } - #[cfg(not(stage0))] intrinsics::overflowing_sub(self, rhs) } } @@ -2971,14 +2966,8 @@ $EndFeature, " /// assert_eq!(25u8.wrapping_mul(12), 44); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(stage0, rustc_const_unstable(feature = "const_int_wrapping"))] #[inline] pub const fn wrapping_mul(self, rhs: Self) -> Self { - #[cfg(stage0)] - unsafe { - intrinsics::overflowing_mul(self, rhs) - } - #[cfg(not(stage0))] intrinsics::overflowing_mul(self, rhs) } @@ -3099,7 +3088,7 @@ assert_eq!(100", stringify!($SelfT), ".wrapping_rem_euclid(10), 0); /// ``` #[stable(feature = "num_wrapping", since = "1.2.0")] #[inline] - pub fn wrapping_neg(self) -> Self { + pub const fn wrapping_neg(self) -> Self { self.overflowing_neg().0 } @@ -3124,7 +3113,6 @@ Basic usage: assert_eq!(1", stringify!($SelfT), ".wrapping_shl(128), 1);", $EndFeature, " ```"), #[stable(feature = "num_wrapping", since = "1.2.0")] - #[cfg_attr(stage0, rustc_const_unstable(feature = "const_int_wrapping"))] #[inline] pub const fn wrapping_shl(self, rhs: u32) -> Self { unsafe { @@ -3154,7 +3142,6 @@ Basic usage: assert_eq!(128", stringify!($SelfT), ".wrapping_shr(128), 128);", $EndFeature, " ```"), #[stable(feature = "num_wrapping", since = "1.2.0")] - #[cfg_attr(stage0, rustc_const_unstable(feature = "const_int_wrapping"))] #[inline] pub const fn wrapping_shr(self, rhs: u32) -> Self { unsafe { @@ -3172,11 +3159,10 @@ wrapping around at the boundary of the type. Basic usage: ``` -#![feature(no_panic_pow)] ", $Feature, "assert_eq!(3", stringify!($SelfT), ".wrapping_pow(5), 243); assert_eq!(3u8.wrapping_pow(6), 217);", $EndFeature, " ```"), - #[unstable(feature = "no_panic_pow", issue = "48320")] + #[stable(feature = "no_panic_pow", since = "1.34.0")] #[inline] pub fn wrapping_pow(self, mut exp: u32) -> Self { let mut base = self; @@ -3219,14 +3205,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")] - #[cfg_attr(stage0, rustc_const_unstable(feature = "const_int_overflowing"))] #[inline] pub const fn overflowing_add(self, rhs: Self) -> (Self, bool) { - #[cfg(stage0)] - let (a, b) = unsafe { - intrinsics::add_with_overflow(self as $ActualT, rhs as $ActualT) - }; - #[cfg(not(stage0))] let (a, b) = intrinsics::add_with_overflow(self as $ActualT, rhs as $ActualT); (a as Self, b) } @@ -3251,14 +3231,8 @@ assert_eq!(0", stringify!($SelfT), ".overflowing_sub(1), (", stringify!($SelfT), $EndFeature, " ```"), #[stable(feature = "wrapping", since = "1.7.0")] - #[cfg_attr(stage0, rustc_const_unstable(feature = "const_int_overflowing"))] #[inline] pub const fn overflowing_sub(self, rhs: Self) -> (Self, bool) { - #[cfg(stage0)] - let (a, b) = unsafe { - intrinsics::sub_with_overflow(self as $ActualT, rhs as $ActualT) - }; - #[cfg(not(stage0))] let (a, b) = intrinsics::sub_with_overflow(self as $ActualT, rhs as $ActualT); (a as Self, b) } @@ -3282,14 +3256,8 @@ $EndFeature, " /// assert_eq!(1_000_000_000u32.overflowing_mul(10), (1410065408, true)); /// ``` #[stable(feature = "wrapping", since = "1.7.0")] - #[cfg_attr(stage0, rustc_const_unstable(feature = "const_int_overflowing"))] #[inline] pub const fn overflowing_mul(self, rhs: Self) -> (Self, bool) { - #[cfg(stage0)] - let (a, b) = unsafe { - intrinsics::mul_with_overflow(self as $ActualT, rhs as $ActualT) - }; - #[cfg(not(stage0))] let (a, b) = intrinsics::mul_with_overflow(self as $ActualT, rhs as $ActualT); (a as Self, b) } @@ -3425,7 +3393,7 @@ assert_eq!(2", stringify!($SelfT), ".overflowing_neg(), (-2i32 as ", stringify!( ```"), #[inline] #[stable(feature = "wrapping", since = "1.7.0")] - pub fn overflowing_neg(self) -> (Self, bool) { + pub const fn overflowing_neg(self) -> (Self, bool) { ((!self).wrapping_add(1), self != 0) } } @@ -3448,7 +3416,6 @@ Basic usage assert_eq!(0x1", stringify!($SelfT), ".overflowing_shl(132), (0x10, true));", $EndFeature, " ```"), #[stable(feature = "wrapping", since = "1.7.0")] - #[cfg_attr(stage0, rustc_const_unstable(feature = "const_int_overflowing"))] #[inline] pub const fn overflowing_shl(self, rhs: u32) -> (Self, bool) { (self.wrapping_shl(rhs), (rhs > ($BITS - 1))) @@ -3473,7 +3440,6 @@ Basic usage assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(132), (0x1, true));", $EndFeature, " ```"), #[stable(feature = "wrapping", since = "1.7.0")] - #[cfg_attr(stage0, rustc_const_unstable(feature = "const_int_overflowing"))] #[inline] pub const fn overflowing_shr(self, rhs: u32) -> (Self, bool) { (self.wrapping_shr(rhs), (rhs > ($BITS - 1))) @@ -3491,11 +3457,10 @@ whether an overflow happened. Basic usage: ``` -#![feature(no_panic_pow)] ", $Feature, "assert_eq!(3", stringify!($SelfT), ".overflowing_pow(5), (243, false)); assert_eq!(3u8.overflowing_pow(6), (217, true));", $EndFeature, " ```"), - #[unstable(feature = "no_panic_pow", issue = "48320")] + #[stable(feature = "no_panic_pow", since = "1.34.0")] #[inline] pub fn overflowing_pow(self, mut exp: u32) -> (Self, bool) { let mut base = self; diff --git a/src/libcore/ops/arith.rs b/src/libcore/ops/arith.rs index 7d8bf18d33a01..0252edee23125 100644 --- a/src/libcore/ops/arith.rs +++ b/src/libcore/ops/arith.rs @@ -49,7 +49,7 @@ /// } /// /// // Notice that the implementation uses the associated type `Output`. -/// impl> Add for Point { +/// impl> Add for Point { /// type Output = Point; /// /// fn add(self, other: Point) -> Point { @@ -157,7 +157,7 @@ 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 { +/// impl> Sub for Point { /// type Output = Point; /// /// fn sub(self, other: Point) -> Point { @@ -518,7 +518,7 @@ pub trait Rem { macro_rules! rem_impl_integer { ($($t:ty)*) => ($( - /// This operation satisfies `n % d == n - (n / d) * d`. The + /// This operation satisfies `n % d == n - (n / d) * d`. The /// result has the same sign as the left operand. #[stable(feature = "rust1", since = "1.0.0")] impl Rem for $t { diff --git a/src/libcore/ops/deref.rs b/src/libcore/ops/deref.rs index 075c3a084f41d..eb76c2de11bec 100644 --- a/src/libcore/ops/deref.rs +++ b/src/libcore/ops/deref.rs @@ -109,7 +109,7 @@ impl Deref for &mut T { /// then: /// /// * In mutable contexts, `*x` on non-pointer types is equivalent to -/// `*Deref::deref(&x)`. +/// `*DerefMut::deref_mut(&mut x)`. /// * Values of type `&mut T` are coerced to values of type `&mut U` /// * `T` implicitly implements all the (mutable) methods of the type `U`. /// @@ -171,7 +171,7 @@ impl DerefMut for &mut T { /// Indicates that a struct can be used as a method receiver, without the /// `arbitrary_self_types` feature. This is implemented by stdlib pointer types like `Box`, /// `Rc`, `&T`, and `Pin

`. -#[cfg_attr(not(stage0), lang = "receiver")] +#[lang = "receiver"] #[unstable(feature = "receiver_trait", issue = "0")] #[doc(hidden)] pub trait Receiver { diff --git a/src/libcore/ops/function.rs b/src/libcore/ops/function.rs index 3a1d765f7b816..c69f5fd989696 100644 --- a/src/libcore/ops/function.rs +++ b/src/libcore/ops/function.rs @@ -62,7 +62,7 @@ label="expected an `Fn<{Args}>` closure, found `{Self}`", )] #[fundamental] // so that regex can rely that `&str: !FnMut` -#[must_use] +#[must_use = "closures are lazy and do nothing unless called"] pub trait Fn : FnMut { /// Performs the call operation. #[unstable(feature = "fn_traits", issue = "29625")] @@ -141,7 +141,7 @@ pub trait Fn : FnMut { label="expected an `FnMut<{Args}>` closure, found `{Self}`", )] #[fundamental] // so that regex can rely that `&str: !FnMut` -#[must_use] +#[must_use = "closures are lazy and do nothing unless called"] pub trait FnMut : FnOnce { /// Performs the call operation. #[unstable(feature = "fn_traits", issue = "29625")] @@ -220,7 +220,7 @@ pub trait FnMut : FnOnce { label="expected an `FnOnce<{Args}>` closure, found `{Self}`", )] #[fundamental] // so that regex can rely that `&str: !FnMut` -#[must_use] +#[must_use = "closures are lazy and do nothing unless called"] pub trait FnOnce { /// The returned type after the call operator is used. #[stable(feature = "fn_once_output", since = "1.12.0")] diff --git a/src/libcore/ops/generator.rs b/src/libcore/ops/generator.rs index 1542cd6397e78..5401fff860e9b 100644 --- a/src/libcore/ops/generator.rs +++ b/src/libcore/ops/generator.rs @@ -1,3 +1,6 @@ +use crate::marker::Unpin; +use crate::pin::Pin; + /// The result of a generator resumption. /// /// This enum is returned from the `Generator::resume` method and indicates the @@ -39,6 +42,7 @@ pub enum GeneratorState { /// #![feature(generators, generator_trait)] /// /// use std::ops::{Generator, GeneratorState}; +/// use std::pin::Pin; /// /// fn main() { /// let mut generator = || { @@ -46,11 +50,11 @@ pub enum GeneratorState { /// return "foo" /// }; /// -/// match unsafe { generator.resume() } { +/// match Pin::new(&mut generator).resume() { /// GeneratorState::Yielded(1) => {} /// _ => panic!("unexpected return from resume"), /// } -/// match unsafe { generator.resume() } { +/// match Pin::new(&mut generator).resume() { /// GeneratorState::Complete("foo") => {} /// _ => panic!("unexpected return from resume"), /// } @@ -88,10 +92,6 @@ pub trait Generator { /// generator will continue executing until it either yields or returns, at /// which point this function will return. /// - /// The function is unsafe because it can be used on an immovable generator. - /// After such a call, the immovable generator must not move again, but - /// this is not enforced by the compiler. - /// /// # Return value /// /// The `GeneratorState` enum returned from this function indicates what @@ -110,16 +110,25 @@ pub trait Generator { /// been returned previously. While generator literals in the language are /// guaranteed to panic on resuming after `Complete`, this is not guaranteed /// for all implementations of the `Generator` trait. - unsafe fn resume(&mut self) -> GeneratorState; + fn resume(self: Pin<&mut Self>) -> GeneratorState; +} + +#[unstable(feature = "generator_trait", issue = "43122")] +impl Generator for Pin<&mut G> { + type Yield = G::Yield; + type Return = G::Return; + + fn resume(mut self: Pin<&mut Self>) -> GeneratorState { + G::resume((*self).as_mut()) + } } #[unstable(feature = "generator_trait", issue = "43122")] -impl Generator for &mut T - where T: Generator + ?Sized -{ - type Yield = T::Yield; - type Return = T::Return; - unsafe fn resume(&mut self) -> GeneratorState { - (**self).resume() +impl Generator for &mut G { + type Yield = G::Yield; + type Return = G::Return; + + fn resume(mut self: Pin<&mut Self>) -> GeneratorState { + G::resume(Pin::new(&mut *self)) } } diff --git a/src/libcore/ops/index.rs b/src/libcore/ops/index.rs index 4f55c68ecd4ae..d4ed86142768d 100644 --- a/src/libcore/ops/index.rs +++ b/src/libcore/ops/index.rs @@ -141,6 +141,21 @@ pub trait Index { /// ``` #[lang = "index_mut"] #[rustc_on_unimplemented( + on( + _Self="&str", + note="you can use `.chars().nth()` or `.bytes().nth()` +see chapter in The Book " + ), + on( + _Self="str", + note="you can use `.chars().nth()` or `.bytes().nth()` +see chapter in The Book " + ), + on( + _Self="std::string::String", + note="you can use `.chars().nth()` or `.bytes().nth()` +see chapter in The Book " + ), message="the type `{Self}` cannot be mutably indexed by `{Idx}`", label="`{Self}` cannot be mutably indexed by `{Idx}`", )] diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index 815a4cfeed88e..b3dd5d20299c1 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -52,7 +52,7 @@ impl fmt::Debug for RangeFull { /// (`start..end`). /// /// The `Range` `start..end` contains all values with `x >= start` and -/// `x < end`. It is empty unless `start < end`. +/// `x < end`. It is empty unless `start < end`. /// /// # Examples /// @@ -297,7 +297,7 @@ impl> RangeTo { /// A range bounded inclusively below and above (`start..=end`). /// /// The `RangeInclusive` `start..=end` contains all values with `x >= start` -/// and `x <= end`. It is empty unless `start <= end`. +/// and `x <= end`. It is empty unless `start <= end`. /// /// This iterator is [fused], but the specific values of `start` and `end` after /// iteration has finished are **unspecified** other than that [`.is_empty()`] diff --git a/src/libcore/ops/try.rs b/src/libcore/ops/try.rs index 380bd12131cf6..9fa2c81954ee1 100644 --- a/src/libcore/ops/try.rs +++ b/src/libcore/ops/try.rs @@ -1,7 +1,7 @@ /// A trait for customizing the behavior of the `?` operator. /// /// A type implementing `Try` is one that has a canonical way to view it -/// in terms of a success/failure dichotomy. This trait allows both +/// in terms of a success/failure dichotomy. This trait allows both /// extracting those success or failure values from an existing instance and /// creating a new instance from a success or failure value. #[unstable(feature = "try_trait", issue = "42327")] diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 0e54397db0247..60aed7ce09d7f 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -214,7 +214,7 @@ impl Option { /// /// # Examples /// - /// Convert an `Option<`[`String`]`>` into an `Option<`[`usize`]`>`, preserving the original. + /// Converts an `Option<`[`String`]`>` into an `Option<`[`usize`]`>`, preserving the original. /// The [`map`] method takes the `self` argument by value, consuming the original, /// so this technique uses `as_ref` to first take an `Option` to a reference /// to the value inside the original. @@ -395,7 +395,7 @@ impl Option { /// /// # Examples /// - /// Convert an `Option<`[`String`]`>` into an `Option<`[`usize`]`>`, consuming the original: + /// Converts an `Option<`[`String`]`>` into an `Option<`[`usize`]`>`, consuming the original: /// /// [`String`]: ../../std/string/struct.String.html /// [`usize`]: ../../std/primitive.usize.html @@ -874,7 +874,7 @@ impl Option { } } -impl<'a, T: Copy> Option<&'a T> { +impl Option<&T> { /// Maps an `Option<&T>` to an `Option` by copying the contents of the /// option. /// @@ -895,7 +895,7 @@ impl<'a, T: Copy> Option<&'a T> { } } -impl<'a, T: Copy> Option<&'a mut T> { +impl Option<&mut T> { /// Maps an `Option<&mut T>` to an `Option` by copying the contents of the /// option. /// @@ -916,7 +916,7 @@ impl<'a, T: Copy> Option<&'a mut T> { } } -impl<'a, T: Clone> Option<&'a T> { +impl Option<&T> { /// Maps an `Option<&T>` to an `Option` by cloning the contents of the /// option. /// @@ -935,7 +935,7 @@ impl<'a, T: Clone> Option<&'a T> { } } -impl<'a, T: Clone> Option<&'a mut T> { +impl Option<&mut T> { /// Maps an `Option<&mut T>` to an `Option` by cloning the contents of the /// option. /// @@ -963,7 +963,7 @@ impl Option { /// /// # Examples /// - /// Convert a string to an integer, turning poorly-formed strings + /// Converts a string to an integer, turning poorly-formed strings /// into 0 (the default value for integers). [`parse`] converts /// a string to any other type that implements [`FromStr`], returning /// [`None`] on error. diff --git a/src/libcore/pin.rs b/src/libcore/pin.rs index 762e07549a52a..f9f20dcea9e2e 100644 --- a/src/libcore/pin.rs +++ b/src/libcore/pin.rs @@ -2,45 +2,63 @@ //! //! It is sometimes useful to have objects that are guaranteed to not 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. //! +//! 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 +//! until it gets dropped. We say that the pointee is "pinned". +//! //! By default, all types in Rust are movable. Rust allows passing all types by-value, -//! and common smart-pointer types such as `Box`, `Rc`, and `&mut` allow replacing and -//! moving the values they contain. In order to prevent objects from moving, they must -//! be pinned by wrapping a pointer to the data in the [`Pin`] type. -//! Doing this prohibits moving the value behind the pointer. -//! For example, `Pin>` functions much like a regular `Box`, -//! but doesn't allow moving `T`. The pointer value itself (the `Box`) can still be moved, -//! but the value behind it cannot. -//! -//! Since data can be moved out of `&mut` and `Box` with functions such as [`swap`], -//! changing the location of the underlying data, [`Pin`] prohibits accessing the -//! underlying pointer type (the `&mut` or `Box`) directly, and provides its own set of -//! APIs for accessing and using the value. [`Pin`] also guarantees that no other -//! functions will move the pointed-to value. This allows for the creation of -//! self-references and other special behaviors that are only possible for unmovable -//! values. +//! and common smart-pointer types such as `Box` and `&mut T` allow replacing and +//! 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 +//! 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>) { +//! // `mem::swap` needs `&mut T`, but we cannot get it. +//! // We are stuck, we cannot swap the contents of these references. +//! // We could use `Pin::get_unchecked_mut`, but that is unsafe for a reason: +//! // we are not allowed to use it for moving things out of the `Pin`. +//! } +//! ``` //! -//! However, these restrictions are usually not necessary. Many types are always freely -//! movable. These types implement the [`Unpin`] auto-trait, which nullifies the effect -//! of [`Pin`]. For `T: Unpin`, `Pin>` and `Box` function identically, as do -//! `Pin<&mut T>` and `&mut T`. +//! It is worth reiterating that [`Pin

`] does *not* change the fact that a Rust compiler +//! considers all types movable. [`mem::swap`] remains callable for any `T`. Instead, `Pin

` +//! prevents certain *values* (pointed to by pointers wrapped in `Pin

`) from being +//! moved by making it impossible to call methods that require `&mut T` on them +//! (like [`mem::swap`]). //! -//! Note that pinning and `Unpin` only affect the pointed-to type. For example, whether -//! or not `Box` is `Unpin` has no affect on the behavior of `Pin>`. Similarly, -//! `Pin>` and `Pin<&mut T>` are always `Unpin` themselves, even though the -//! `T` underneath them isn't, because the pointers in `Pin>` and `Pin<&mut _>` -//! are always freely movable, even if the data they point to isn't. +//! [`Pin

`] can be used to wrap any pointer type `P`, and as such it interacts with +//! [`Deref`] and [`DerefMut`]. A `Pin

` where `P: Deref` should be considered +//! 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. //! -//! [`Pin`]: struct.Pin.html -//! [`Unpin`]: ../../std/marker/trait.Unpin.html -//! [`swap`]: ../../std/mem/fn.swap.html -//! [`Box`]: ../../std/boxed/struct.Box.html +//! # `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`. //! -//! # Examples +//! 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 +//! `Unpin` has no effect on the behavior of `Pin>` (here, `T` is the +//! pointed-to type). +//! +//! # Example: self-referential struct //! //! ```rust //! use std::pin::Pin; @@ -94,11 +112,156 @@ //! // let new_unmoved = Unmovable::new("world".to_string()); //! // std::mem::swap(&mut *still_unmoved, &mut *new_unmoved); //! ``` +//! +//! # Example: intrusive doubly-linked list +//! +//! In an intrusive doubly-linked list, the collection does not actually allocate +//! the memory for the elements itself. Allocation is controlled by the clients, +//! and elements can live on a stack frame that lives shorter than the collection does. +//! +//! To make this work, every element has pointers to its predecessor and successor in +//! the list. Elements can only be added when they are pinned, because moving the elements +//! around would invalidate the pointers. Moreover, the `Drop` implementation of a linked +//! list element will patch the pointers of its predecessor and successor to remove itself +//! from the list. +//! +//! Crucially, we have to be able to rely on `drop` being called. If an element +//! could be deallocated or otherwise invalidated without calling `drop`, the pointers into it +//! from its neighbouring elements would become invalid, which would break the data structure. +//! +//! Therefore, pinning also comes with a `drop`-related guarantee. +//! +//! # `Drop` guarantee +//! +//! The purpose of pinning is to be able to rely on the placement of some data in memory. +//! 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 +//! 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. +//! +//! 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 +//! 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`*. +//! +//! # `Drop` implementation +//! +//! If your type uses pinning (such as the two examples above), you have to be careful +//! when implementing `Drop`. The `drop` function takes `&mut self`, but this +//! 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>`. +//! +//! In particular, 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>`? +//! +//! 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>`. +//! +//! 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: +//! +//! 1. The wrapper 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 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 +//! 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. +//! 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* +//! be `#[repr(packed)]`. +//! 3. You must make sure that you uphold the [`Drop` guarantee][drop-guarantee]: +//! once your wrapper 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 +//! `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 +//! `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. +//! +//! 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) { +//! { 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(); +//! let content = &mut *b; // And here we have `&mut T` to the same data. +//! } +//! ``` +//! This is catastrophic, it means we can first pin the content of the `RefCell` +//! (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 +//! `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. +//! +//! 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`. +//! It makes sense to do this for pointer types, because moving the `Box` +//! does not actually move the `T`: the `Box` can be freely movable (aka `Unpin`) even if the `T` +//! is not. In fact, even `Pin>` and `Pin<&mut T>` are always `Unpin` themselves, +//! for the same reason: their contents (the `T`) are pinned, but the pointers themselves +//! can be moved without moving the pinned data. For both `Box` and `Pin>`, +//! whether the content is pinned is entirely independent of whether the pointer is +//! pinned, meaning pinning is *not* structural. +//! +//! [`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 +//! [`Box`]: ../../std/boxed/struct.Box.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 +//! [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}; /// A pinned pointer. @@ -112,22 +275,69 @@ use ops::{Deref, DerefMut, Receiver, CoerceUnsized, DispatchFromDyn}; /// [`Unpin`]: ../../std/marker/trait.Unpin.html /// [`pin` module]: ../../std/pin/index.html // -// Note: the derives below are allowed because they all only use `&P`, so they -// cannot move the value behind `pointer`. +// Note: the derives below, and the explicit `PartialEq` and `PartialOrd` +// 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")] #[fundamental] #[repr(transparent)] -#[derive(Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)] +#[derive(Copy, Clone, Hash, Eq, Ord)] pub struct Pin

{ pointer: P, } +#[stable(feature = "pin_partialeq_partialord_impl_applicability", since = "1.34.0")] +impl PartialEq> for Pin

+where + P: PartialEq, +{ + fn eq(&self, other: &Pin) -> bool { + self.pointer == other.pointer + } + + fn ne(&self, other: &Pin) -> bool { + self.pointer != other.pointer + } +} + +#[stable(feature = "pin_partialeq_partialord_impl_applicability", since = "1.34.0")] +impl PartialOrd> for Pin

+where + P: PartialOrd, +{ + fn partial_cmp(&self, other: &Pin) -> Option { + self.pointer.partial_cmp(&other.pointer) + } + + fn lt(&self, other: &Pin) -> bool { + self.pointer < other.pointer + } + + fn le(&self, other: &Pin) -> bool { + self.pointer <= other.pointer + } + + fn gt(&self, other: &Pin) -> bool { + self.pointer > other.pointer + } + + fn ge(&self, other: &Pin) -> bool { + self.pointer >= other.pointer + } +} + impl Pin

where P::Target: Unpin, { - /// Construct a new `Pin` around a pointer to some data of a type that - /// implements `Unpin`. + /// Construct a new `Pin

` around a pointer to some data of a type that + /// implements [`Unpin`]. + /// + /// Unlike `Pin::new_unchecked`, this method is safe because the pointer + /// `P` dereferences to an [`Unpin`] type, which cancels the pinning guarantees. + /// + /// [`Unpin`]: ../../std/marker/trait.Unpin.html #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] pub fn new(pointer: P) -> Pin

{ @@ -138,25 +348,83 @@ where } impl Pin

{ - /// Construct a new `Pin` around a reference to some data of a type that + /// Construct a new `Pin

` around a reference to some data of a type that /// may or may not implement `Unpin`. /// + /// If `pointer` dereferences to an `Unpin` type, `Pin::new` should be used + /// instead. + /// /// # Safety /// /// This constructor is unsafe because we cannot guarantee that the data - /// pointed to by `pointer` is pinned. If the constructed `Pin

` does - /// not guarantee that the data `P` points to is pinned, constructing a - /// `Pin

` is undefined behavior. + /// pointed to by `pointer` is pinned, meaning that the data will not be moved or + /// its storage invalidated until it gets dropped. If the constructed `Pin

` does + /// not guarantee that the data `P` points to is pinned, that is a violation of + /// the API contract and may lead to undefined behavior in later (safe) operations. /// - /// If `pointer` dereferences to an `Unpin` type, `Pin::new` should be used - /// instead. + /// By using this method, you are making a promise about the `P::Deref` and + /// `P::DerefMut` implementations, if they exist. Most importantly, they + /// must not move out of their `self` arguments: `Pin::as_mut` and `Pin::as_ref` + /// will call `DerefMut::deref_mut` and `Deref::deref` *on the pinned pointer* + /// and expect these methods to uphold the pinning invariants. + /// Moreover, by calling this method you promise that the reference `P` + /// dereferences to will not be moved out of again; in particular, it + /// must not be possible to obtain a `&mut P::Target` and then + /// move out of that reference (using, for example [`mem::swap`]). + /// + /// For example, calling `Pin::new_unchecked` on an `&'a mut T` is unsafe because + /// while you are able to pin it for the given lifetime `'a`, you have no control + /// over whether it is kept pinned once `'a` ends: + /// ``` + /// use std::mem; + /// use std::pin::Pin; + /// + /// fn move_pinned_ref(mut a: T, mut b: T) { + /// unsafe { + /// let p: Pin<&mut T> = Pin::new_unchecked(&mut a); + /// // This should mean the pointee `a` can never move again. + /// } + /// mem::swap(&mut a, &mut b); + /// // The address of `a` changed to `b`'s stack slot, so `a` got moved even + /// // though we have previously pinned it! We have violated the pinning API contract. + /// } + /// ``` + /// A value, once pinned, must remain pinned forever (unless its type implements `Unpin`). + /// + /// Similarily, calling `Pin::new_unchecked` on an `Rc` is unsafe because there could be + /// aliases to the same data that are not subject to the pinning restrictions: + /// ``` + /// use std::rc::Rc; + /// use std::pin::Pin; + /// + /// fn move_pinned_rc(mut x: Rc) { + /// let pinned = unsafe { Pin::new_unchecked(x.clone()) }; + /// { + /// let p: Pin<&T> = pinned.as_ref(); + /// // This should mean the pointee can never move again. + /// } + /// drop(pinned); + /// let content = Rc::get_mut(&mut x).unwrap(); + /// // Now, if `x` was the only reference, we have a mutable reference to + /// // data that we pinned above, which we could use to move it as we have + /// // seen in the previous example. We have violated the pinning API contract. + /// } + /// ``` + /// + /// [`mem::swap`]: ../../std/mem/fn.swap.html #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] pub unsafe fn new_unchecked(pointer: P) -> Pin

{ Pin { pointer } } - /// Get a pinned shared reference from this pinned pointer. + /// Gets a pinned shared reference from this pinned pointer. + /// + /// This is a generic method to go from `&Pin>` to `Pin<&T>`. + /// It is safe because, as part of the contract of `Pin::new_unchecked`, + /// the pointee cannot move after `Pin>` got created. + /// "Malicious" implementations of `Pointer::Deref` are likewise + /// ruled out by the contract of `Pin::new_unchecked`. #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] pub fn as_ref(self: &Pin

) -> Pin<&P::Target> { @@ -165,14 +433,23 @@ impl Pin

{ } impl Pin

{ - /// Get a pinned mutable reference from this pinned pointer. + /// Gets a pinned mutable reference from this pinned pointer. + /// + /// This is a generic method to go from `&mut Pin>` to `Pin<&mut T>`. + /// It is safe because, as part of the contract of `Pin::new_unchecked`, + /// the pointee cannot move after `Pin>` got created. + /// "Malicious" implementations of `Pointer::DerefMut` are likewise + /// ruled out by the contract of `Pin::new_unchecked`. #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] pub fn as_mut(self: &mut Pin

) -> Pin<&mut P::Target> { unsafe { Pin::new_unchecked(&mut *self.pointer) } } - /// Assign a new value to the memory behind the pinned reference. + /// Assigns a new value to the memory behind the pinned reference. + /// + /// This overwrites pinned data, but that is okay: its destructor gets + /// run before being overwritten, so no pinning guarantee is violated. #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] pub fn set(self: &mut Pin

, value: P::Target) @@ -184,10 +461,12 @@ impl Pin

{ } impl<'a, T: ?Sized> Pin<&'a T> { - /// Construct a new pin by mapping the interior value. + /// Constructs a new pin by mapping the interior value. /// /// For example, if you wanted to get a `Pin` of a field of something, /// you could use this to get access to that field in one line of code. + /// However, there are several gotchas with these "pinning projections"; + /// see the [`pin` module] documentation for further details on that topic. /// /// # Safety /// @@ -195,6 +474,8 @@ impl<'a, T: ?Sized> Pin<&'a T> { /// will not move so long as the argument value does not move (for example, /// because it is one of the fields of that value), and also that you do /// not move out of the argument you receive to the interior function. + /// + /// [`pin` module]: ../../std/pin/index.html#projections-and-structural-pinning #[stable(feature = "pin", since = "1.33.0")] pub unsafe fn map_unchecked(self: Pin<&'a T>, func: F) -> Pin<&'a U> where F: FnOnce(&T) -> &U, @@ -204,13 +485,23 @@ impl<'a, T: ?Sized> Pin<&'a T> { Pin::new_unchecked(new_pointer) } - /// Get a shared reference out of a pin. + /// Gets a shared reference out of a pin. + /// + /// This is safe because it is not possible to move out of a shared reference. + /// It may seem like there is an issue here with interior mutability: in fact, + /// it *is* possible to move a `T` out of a `&RefCell`. However, this is + /// not a problem as long as there does not also exist a `Pin<&T>` pointing + /// to the same data, and `RefCell` does not let you create a pinned reference + /// to its contents. See the discussion on ["pinning projections"] for further + /// details. /// /// Note: `Pin` also implements `Deref` to the target, which can be used /// to access the inner value. However, `Deref` only provides a reference /// that lives for as long as the borrow of the `Pin`, not the lifetime of /// the `Pin` itself. This method allows turning the `Pin` into a reference /// with the same lifetime as the original `Pin`. + /// + /// ["pinning projections"]: ../../std/pin/index.html#projections-and-structural-pinning #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] pub fn get_ref(self: Pin<&'a T>) -> &'a T { @@ -219,14 +510,14 @@ impl<'a, T: ?Sized> Pin<&'a T> { } impl<'a, T: ?Sized> Pin<&'a mut T> { - /// Convert this `Pin<&mut T>` into a `Pin<&T>` with the same lifetime. + /// Converts this `Pin<&mut T>` into a `Pin<&T>` with the same lifetime. #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] pub fn into_ref(self: Pin<&'a mut T>) -> Pin<&'a T> { Pin { pointer: self.pointer } } - /// Get a mutable reference to the data inside of this `Pin`. + /// Gets a mutable reference to the data inside of this `Pin`. /// /// This requires that the data inside this `Pin` is `Unpin`. /// @@ -243,7 +534,7 @@ impl<'a, T: ?Sized> Pin<&'a mut T> { self.pointer } - /// Get a mutable reference to the data inside of this `Pin`. + /// Gets a mutable reference to the data inside of this `Pin`. /// /// # Safety /// @@ -263,6 +554,8 @@ impl<'a, T: ?Sized> Pin<&'a mut T> { /// /// For example, if you wanted to get a `Pin` of a field of something, /// you could use this to get access to that field in one line of code. + /// However, there are several gotchas with these "pinning projections"; + /// see the [`pin` module] documentation for further details on that topic. /// /// # Safety /// @@ -270,6 +563,8 @@ impl<'a, T: ?Sized> Pin<&'a mut T> { /// will not move so long as the argument value does not move (for example, /// because it is one of the fields of that value), and also that you do /// not move out of the argument you receive to the interior function. + /// + /// [`pin` module]: ../../std/pin/index.html#projections-and-structural-pinning #[stable(feature = "pin", since = "1.33.0")] pub unsafe fn map_unchecked_mut(self: Pin<&'a mut T>, func: F) -> Pin<&'a mut U> where F: FnOnce(&mut T) -> &mut U, diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 02eef07afd7ab..866c8d0896b3c 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -12,7 +12,7 @@ //! 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 +//! 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]. @@ -104,7 +104,7 @@ pub use intrinsics::write_bytes; /// /// * `to_drop` must be [valid] for reads. /// -/// * `to_drop` must be properly aligned. See the example below for how to drop +/// * `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 @@ -135,7 +135,7 @@ pub use intrinsics::write_bytes; /// 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, +/// // 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, @@ -531,7 +531,7 @@ pub unsafe fn replace(dst: *mut T, mut src: T) -> T { /// /// `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 +/// `*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. @@ -573,7 +573,7 @@ pub unsafe fn replace(dst: *mut T, mut src: T) -> T { pub unsafe fn read(src: *const T) -> T { let mut tmp = MaybeUninit::::uninitialized(); copy_nonoverlapping(src, tmp.as_mut_ptr(), 1); - tmp.into_inner() + tmp.into_initialized() } /// Reads the value from `src` without moving it. This leaves the @@ -588,7 +588,7 @@ pub unsafe fn read(src: *const T) -> T { /// * `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 +/// 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. @@ -642,7 +642,7 @@ pub unsafe fn read_unaligned(src: *const T) -> T { copy_nonoverlapping(src as *const u8, tmp.as_mut_ptr() as *mut u8, mem::size_of::()); - tmp.into_inner() + tmp.into_initialized() } /// Overwrites a memory location with the given value without reading or @@ -825,7 +825,7 @@ pub unsafe fn write_unaligned(dst: *mut T, src: T) { /// /// 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 no-ops +/// (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 @@ -839,7 +839,7 @@ pub unsafe fn write_unaligned(dst: *mut T, src: T) { /// * `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 +/// 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. @@ -903,7 +903,7 @@ pub unsafe fn read_volatile(src: *const T) -> T { /// /// 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 no-ops +/// (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 @@ -1093,7 +1093,7 @@ impl *const T { /// 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 + /// 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 @@ -1712,7 +1712,7 @@ impl *mut T { /// 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 + /// 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 @@ -2473,7 +2473,7 @@ impl PartialEq for *mut T { #[stable(feature = "rust1", since = "1.0.0")] impl Eq for *mut T {} -/// Compare raw pointers for equality. +/// 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, diff --git a/src/libcore/result.rs b/src/libcore/result.rs index 1ebf0714e23e4..92d29f6ee8a30 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -896,7 +896,7 @@ impl Result { /// /// # Examples /// - /// Convert a string to an integer, turning poorly-formed strings + /// Converts a string to an integer, turning poorly-formed strings /// into 0 (the default value for integers). [`parse`] converts /// a string to any other type that implements [`FromStr`], returning an /// [`Err`] on error. diff --git a/src/libcore/slice/memchr.rs b/src/libcore/slice/memchr.rs index 312838a170c6b..cbba546b8daba 100644 --- a/src/libcore/slice/memchr.rs +++ b/src/libcore/slice/memchr.rs @@ -11,7 +11,7 @@ const HI_U64: u64 = 0x8080808080808080; const LO_USIZE: usize = LO_U64 as usize; const HI_USIZE: usize = HI_U64 as usize; -/// Returns whether `x` contains any zero byte. +/// Returns `true` if `x` contains any zero byte. /// /// From *Matters Computational*, J. Arndt: /// diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 7fdc2acb8cc92..d89443662df87 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -34,7 +34,6 @@ use result::Result::{Ok, Err}; use ptr; use mem; use marker::{Copy, Send, Sync, Sized, self}; -use iter_private::TrustedRandomAccess; #[unstable(feature = "slice_internals", issue = "0", reason = "exposed from core to be reused in std; use the memchr crate")] @@ -1198,7 +1197,7 @@ impl [T] { /// Returns an iterator over subslices separated by elements that match /// `pred` limited to returning at most `n` items. This starts at the end of - /// the slice and works backwards. The matched element is not contained in + /// the slice and works backwards. The matched element is not contained in /// the subslices. /// /// The last element returned, if any, will contain the remainder of the @@ -1564,6 +1563,10 @@ impl [T] { /// randomization to avoid degenerate cases, but with a fixed seed to always provide /// deterministic behavior. /// + /// Due to its key calling strategy, [`sort_unstable_by_key`](#method.sort_unstable_by_key) + /// is likely to be slower than [`sort_by_cached_key`](#method.sort_by_cached_key) in + /// cases where the key function is expensive. + /// /// # Examples /// /// ``` @@ -1783,7 +1786,7 @@ impl [T] { /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f']; /// a[1..5].rotate_left(1); /// assert_eq!(a, ['a', 'c', 'd', 'e', 'b', 'f']); - /// ``` + /// ``` #[stable(feature = "slice_rotate", since = "1.26.0")] pub fn rotate_left(&mut self, mid: usize) { assert!(mid <= self.len()); @@ -2250,6 +2253,77 @@ impl [T] { from_raw_parts_mut(mut_ptr.add(rest.len() - ts_len), ts_len)) } } + + /// Checks if the elements of this slice are sorted. + /// + /// That is, for each element `a` and its following element `b`, `a <= b` must hold. If the + /// slice yields exactly zero or one element, `true` is returned. + /// + /// Note that if `Self::Item` is only `PartialOrd`, but not `Ord`, the above definition + /// implies that this function returns `false` if any two consecutive items are not + /// comparable. + /// + /// # Examples + /// + /// ``` + /// #![feature(is_sorted)] + /// let empty: [i32; 0] = []; + /// + /// assert!([1, 2, 2, 9].is_sorted()); + /// assert!(![1, 3, 2, 4].is_sorted()); + /// assert!([0].is_sorted()); + /// assert!(empty.is_sorted()); + /// assert!(![0.0, 1.0, std::f32::NAN].is_sorted()); + /// ``` + #[inline] + #[unstable(feature = "is_sorted", reason = "new API", issue = "53485")] + pub fn is_sorted(&self) -> bool + where + T: PartialOrd, + { + self.is_sorted_by(|a, b| a.partial_cmp(b)) + } + + /// Checks if the elements of this slice are sorted using the given comparator function. + /// + /// Instead of using `PartialOrd::partial_cmp`, this function uses the given `compare` + /// function to determine the ordering of two elements. Apart from that, it's equivalent to + /// [`is_sorted`]; see its documentation for more information. + /// + /// [`is_sorted`]: #method.is_sorted + #[unstable(feature = "is_sorted", reason = "new API", issue = "53485")] + pub fn is_sorted_by(&self, mut compare: F) -> bool + where + F: FnMut(&T, &T) -> Option + { + self.iter().is_sorted_by(|a, b| compare(*a, *b)) + } + + /// Checks if the elements of this slice are sorted using the given key extraction function. + /// + /// Instead of comparing the slice's elements directly, this function compares the keys of the + /// elements, as determined by `f`. Apart from that, it's equivalent to [`is_sorted`]; see its + /// documentation for more information. + /// + /// [`is_sorted`]: #method.is_sorted + /// + /// # Examples + /// + /// ``` + /// #![feature(is_sorted)] + /// + /// assert!(["c", "bb", "aaa"].is_sorted_by_key(|s| s.len())); + /// assert!(![-2i32, -1, 0, 3].is_sorted_by_key(|n| n.abs())); + /// ``` + #[inline] + #[unstable(feature = "is_sorted", reason = "new API", issue = "53485")] + pub fn is_sorted_by_key(&self, mut f: F) -> bool + where + F: FnMut(&T) -> K, + K: PartialOrd + { + self.is_sorted_by(|a, b| f(a).partial_cmp(&f(b))) + } } #[lang = "slice_u8"] @@ -2312,7 +2386,6 @@ impl [u8] { } #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_on_unimplemented = "slice indices are of type `usize` or ranges of `usize`"] impl ops::Index for [T] where I: SliceIndex<[T]> { @@ -2325,7 +2398,6 @@ impl ops::Index for [T] } #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_on_unimplemented = "slice indices are of type `usize` or ranges of `usize`"] impl ops::IndexMut for [T] where I: SliceIndex<[T]> { @@ -2376,7 +2448,19 @@ mod private_slice_index { /// A helper trait used for indexing operations. #[stable(feature = "slice_get_slice", since = "1.28.0")] -#[rustc_on_unimplemented = "slice indices are of type `usize` or ranges of `usize`"] +#[rustc_on_unimplemented( + on( + T = "str", + label = "string indices are ranges of `usize`", + ), + on( + all(any(T = "str", T = "&str", T = "std::string::String"), _Self="{integer}"), + note="you can use `.chars().nth()` or `.bytes().nth()` +see chapter in The Book " + ), + message = "the type `{T}` cannot be indexed by `{Self}`", + label = "slice indices are of type `usize` or ranges of `usize`", +)] pub trait SliceIndex: private_slice_index::Sealed { /// The output type returned by methods. #[stable(feature = "slice_get_slice", since = "1.28.0")] @@ -2773,7 +2857,13 @@ macro_rules! len { // The shared definition of the `Iter` and `IterMut` iterators macro_rules! iterator { - (struct $name:ident -> $ptr:ty, $elem:ty, $raw_mut:tt, $( $mut_:tt )*) => { + ( + struct $name:ident -> $ptr:ty, + $elem:ty, + $raw_mut:tt, + {$( $mut_:tt )*}, + {$($extra:tt)*} + ) => { impl<'a, T> $name<'a, T> { // Helper function for creating a slice from the iterator. #[inline(always)] @@ -2813,7 +2903,7 @@ macro_rules! iterator { } #[stable(feature = "rust1", since = "1.0.0")] - impl<'a, T> ExactSizeIterator for $name<'a, T> { + impl ExactSizeIterator for $name<'_, T> { #[inline(always)] fn len(&self) -> usize { len!(self) @@ -2950,6 +3040,8 @@ macro_rules! iterator { i }) } + + $($extra)* } #[stable(feature = "rust1", since = "1.0.0")] @@ -3006,10 +3098,10 @@ macro_rules! iterator { } #[stable(feature = "fused", since = "1.26.0")] - impl<'a, T> FusedIterator for $name<'a, T> {} + impl FusedIterator for $name<'_, T> {} #[unstable(feature = "trusted_len", issue = "37572")] - unsafe impl<'a, T> TrustedLen for $name<'a, T> {} + unsafe impl TrustedLen for $name<'_, T> {} } } @@ -3057,7 +3149,7 @@ unsafe impl Sync for Iter<'_, T> {} unsafe impl Send for Iter<'_, T> {} impl<'a, T> Iter<'a, T> { - /// View the underlying data as a subslice of the original data. + /// Views the underlying data as a subslice of the original data. /// /// This has the same lifetime as the original slice, and so the /// iterator can continue to be used while this exists. @@ -3087,7 +3179,17 @@ impl<'a, T> Iter<'a, T> { } } -iterator!{struct Iter -> *const T, &'a T, const, /* no mut */} +iterator!{struct Iter -> *const T, &'a T, const, {/* no mut */}, { + fn is_sorted_by(self, mut compare: F) -> bool + where + Self: Sized, + F: FnMut(&Self::Item, &Self::Item) -> Option, + { + self.as_slice().windows(2).all(|w| { + compare(&&w[0], &&w[1]).map(|o| o != Ordering::Greater).unwrap_or(false) + }) + } +}} #[stable(feature = "rust1", since = "1.0.0")] impl Clone for Iter<'_, T> { @@ -3149,7 +3251,7 @@ unsafe impl Sync for IterMut<'_, T> {} unsafe impl Send for IterMut<'_, T> {} impl<'a, T> IterMut<'a, T> { - /// View the underlying data as a subslice of the original data. + /// Views the underlying data as a subslice of the original data. /// /// To avoid creating `&mut` references that alias, this is forced /// to consume the iterator. @@ -3188,7 +3290,7 @@ impl<'a, T> IterMut<'a, T> { } } -iterator!{struct IterMut -> *mut T, &'a mut T, mut, mut} +iterator!{struct IterMut -> *mut T, &'a mut T, mut, {mut}, {}} /// An internal abstraction over the splitting iterators, so that /// splitn, splitn_mut etc can be implemented once. @@ -4025,7 +4127,7 @@ pub struct ChunksExact<'a, T:'a> { } impl<'a, T> ChunksExact<'a, T> { - /// Return the remainder of the original slice that is not going to be + /// Returns the remainder of the original slice that is not going to be /// returned by the iterator. The returned slice has at most `chunk_size-1` /// elements. #[stable(feature = "chunks_exact", since = "1.31.0")] @@ -4149,7 +4251,7 @@ pub struct ChunksExactMut<'a, T:'a> { } impl<'a, T> ChunksExactMut<'a, T> { - /// Return the remainder of the original slice that is not going to be + /// Returns the remainder of the original slice that is not going to be /// returned by the iterator. The returned slice has at most `chunk_size-1` /// elements. #[stable(feature = "chunks_exact", since = "1.31.0")] @@ -4263,8 +4365,8 @@ pub struct RChunks<'a, T:'a> { // FIXME(#26925) Remove in favor of `#[derive(Clone)]` #[stable(feature = "rchunks", since = "1.31.0")] -impl<'a, T> Clone for RChunks<'a, T> { - fn clone(&self) -> RChunks<'a, T> { +impl Clone for RChunks<'_, T> { + fn clone(&self) -> Self { RChunks { v: self.v, chunk_size: self.chunk_size, @@ -4353,13 +4455,13 @@ impl<'a, T> DoubleEndedIterator for RChunks<'a, T> { } #[stable(feature = "rchunks", since = "1.31.0")] -impl<'a, T> ExactSizeIterator for RChunks<'a, T> {} +impl ExactSizeIterator for RChunks<'_, T> {} #[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl<'a, T> TrustedLen for RChunks<'a, T> {} +unsafe impl TrustedLen for RChunks<'_, T> {} #[stable(feature = "rchunks", since = "1.31.0")] -impl<'a, T> FusedIterator for RChunks<'a, T> {} +impl FusedIterator for RChunks<'_, T> {} #[doc(hidden)] #[stable(feature = "rchunks", since = "1.31.0")] @@ -4478,13 +4580,13 @@ impl<'a, T> DoubleEndedIterator for RChunksMut<'a, T> { } #[stable(feature = "rchunks", since = "1.31.0")] -impl<'a, T> ExactSizeIterator for RChunksMut<'a, T> {} +impl ExactSizeIterator for RChunksMut<'_, T> {} #[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl<'a, T> TrustedLen for RChunksMut<'a, T> {} +unsafe impl TrustedLen for RChunksMut<'_, T> {} #[stable(feature = "rchunks", since = "1.31.0")] -impl<'a, T> FusedIterator for RChunksMut<'a, T> {} +impl FusedIterator for RChunksMut<'_, T> {} #[doc(hidden)] #[stable(feature = "rchunks", since = "1.31.0")] @@ -4521,7 +4623,7 @@ pub struct RChunksExact<'a, T:'a> { } impl<'a, T> RChunksExact<'a, T> { - /// Return the remainder of the original slice that is not going to be + /// Returns the remainder of the original slice that is not going to be /// returned by the iterator. The returned slice has at most `chunk_size-1` /// elements. #[stable(feature = "rchunks", since = "1.31.0")] @@ -4609,10 +4711,10 @@ impl<'a, T> ExactSizeIterator for RChunksExact<'a, T> { } #[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl<'a, T> TrustedLen for RChunksExact<'a, T> {} +unsafe impl TrustedLen for RChunksExact<'_, T> {} #[stable(feature = "rchunks", since = "1.31.0")] -impl<'a, T> FusedIterator for RChunksExact<'a, T> {} +impl FusedIterator for RChunksExact<'_, T> {} #[doc(hidden)] #[stable(feature = "rchunks", since = "1.31.0")] @@ -4646,7 +4748,7 @@ pub struct RChunksExactMut<'a, T:'a> { } impl<'a, T> RChunksExactMut<'a, T> { - /// Return the remainder of the original slice that is not going to be + /// Returns the remainder of the original slice that is not going to be /// returned by the iterator. The returned slice has at most `chunk_size-1` /// elements. #[stable(feature = "rchunks", since = "1.31.0")] @@ -4720,17 +4822,17 @@ impl<'a, T> DoubleEndedIterator for RChunksExactMut<'a, T> { } #[stable(feature = "rchunks", since = "1.31.0")] -impl<'a, T> ExactSizeIterator for RChunksExactMut<'a, T> { +impl ExactSizeIterator for RChunksExactMut<'_, T> { fn is_empty(&self) -> bool { self.v.is_empty() } } #[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl<'a, T> TrustedLen for RChunksExactMut<'a, T> {} +unsafe impl TrustedLen for RChunksExactMut<'_, T> {} #[stable(feature = "rchunks", since = "1.31.0")] -impl<'a, T> FusedIterator for RChunksExactMut<'a, T> {} +impl FusedIterator for RChunksExactMut<'_, T> {} #[doc(hidden)] #[stable(feature = "rchunks", since = "1.31.0")] diff --git a/src/libcore/slice/rotate.rs b/src/libcore/slice/rotate.rs index 52677713f5ac4..9b35b51349a02 100644 --- a/src/libcore/slice/rotate.rs +++ b/src/libcore/slice/rotate.rs @@ -26,7 +26,7 @@ impl RawArray { } /// Rotates the range `[mid-left, mid+right)` such that the element at `mid` -/// becomes the first element. Equivalently, rotates the range `left` +/// becomes the first element. Equivalently, rotates the range `left` /// elements to the left or `right` elements to the right. /// /// # Safety @@ -36,10 +36,10 @@ impl RawArray { /// # Algorithm /// /// For longer rotations, swap the left-most `delta = min(left, right)` -/// elements with the right-most `delta` elements. LLVM vectorizes this, +/// elements with the right-most `delta` elements. LLVM vectorizes this, /// which is profitable as we only reach this step for a "large enough" -/// rotation. Doing this puts `delta` elements on the larger side into the -/// correct position, leaving a smaller rotate problem. Demonstration: +/// rotation. Doing this puts `delta` elements on the larger side into the +/// correct position, leaving a smaller rotate problem. Demonstration: /// /// ```text /// [ 6 7 8 9 10 11 12 13 . 1 2 3 4 5 ] diff --git a/src/libcore/slice/sort.rs b/src/libcore/slice/sort.rs index dd9b49fb7a002..3f84faa049939 100644 --- a/src/libcore/slice/sort.rs +++ b/src/libcore/slice/sort.rs @@ -216,14 +216,14 @@ fn partition_in_blocks(v: &mut [T], pivot: &T, is_less: &mut F) -> usize let mut block_l = BLOCK; let mut start_l = ptr::null_mut(); let mut end_l = ptr::null_mut(); - let mut offsets_l = MaybeUninit::<[u8; BLOCK]>::uninitialized(); + let mut offsets_l: [MaybeUninit; BLOCK] = uninitialized_array![u8; BLOCK]; // The current block on the right side (from `r.sub(block_r)` to `r`). let mut r = unsafe { l.add(v.len()) }; let mut block_r = BLOCK; let mut start_r = ptr::null_mut(); let mut end_r = ptr::null_mut(); - let mut offsets_r = MaybeUninit::<[u8; BLOCK]>::uninitialized(); + let mut offsets_r: [MaybeUninit; BLOCK] = uninitialized_array![u8; BLOCK]; // FIXME: When we get VLAs, try creating one array of length `min(v.len(), 2 * BLOCK)` rather // than two fixed-size arrays of length `BLOCK`. VLAs might be more cache-efficient. @@ -262,8 +262,8 @@ fn partition_in_blocks(v: &mut [T], pivot: &T, is_less: &mut F) -> usize if start_l == end_l { // Trace `block_l` elements from the left side. - start_l = offsets_l.as_mut_ptr() as *mut u8; - end_l = offsets_l.as_mut_ptr() as *mut u8; + start_l = MaybeUninit::first_ptr_mut(&mut offsets_l); + end_l = MaybeUninit::first_ptr_mut(&mut offsets_l); let mut elem = l; for i in 0..block_l { @@ -278,8 +278,8 @@ fn partition_in_blocks(v: &mut [T], pivot: &T, is_less: &mut F) -> usize if start_r == end_r { // Trace `block_r` elements from the right side. - start_r = offsets_r.as_mut_ptr() as *mut u8; - end_r = offsets_r.as_mut_ptr() as *mut u8; + start_r = MaybeUninit::first_ptr_mut(&mut offsets_r); + end_r = MaybeUninit::first_ptr_mut(&mut offsets_r); let mut elem = r; for i in 0..block_r { diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index bdde187d931cc..8b51d8465141a 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -1,6 +1,6 @@ -//! String manipulation +//! String manipulation. //! -//! For more details, see std::str +//! For more details, see the `std::str` module. #![stable(feature = "rust1", since = "1.0.0")] @@ -8,11 +8,13 @@ use self::pattern::Pattern; use self::pattern::{Searcher, ReverseSearcher, DoubleEndedSearcher}; use char; -use fmt; -use iter::{Map, Cloned, FusedIterator, TrustedLen, Filter}; -use iter_private::TrustedRandomAccess; +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; pub mod pattern; @@ -227,7 +229,7 @@ impl Utf8Error { #[stable(feature = "utf8_error", since = "1.5.0")] pub fn valid_up_to(&self) -> usize { self.valid_up_to } - /// Provide more information about the failure: + /// Provides more information about the failure: /// /// * `None`: the end of the input was reached unexpectedly. /// `self.valid_up_to()` is 1 to 3 bytes from the end of the input. @@ -613,7 +615,7 @@ impl<'a> DoubleEndedIterator for Chars<'a> { impl FusedIterator for Chars<'_> {} impl<'a> Chars<'a> { - /// View the underlying data as a subslice of the original data. + /// Views the underlying data as a subslice of the original data. /// /// This has the same lifetime as the original slice, and so the /// iterator can continue to be used while this exists. @@ -703,7 +705,7 @@ impl<'a> DoubleEndedIterator for CharIndices<'a> { impl FusedIterator for CharIndices<'_> {} impl<'a> CharIndices<'a> { - /// View the underlying data as a subslice of the original data. + /// Views the underlying data as a subslice of the original data. /// /// This has the same lifetime as the original slice, and so the /// iterator can continue to be used while this exists. @@ -821,7 +823,7 @@ impl FusedIterator for Bytes<'_> {} unsafe impl TrustedLen for Bytes<'_> {} #[doc(hidden)] -unsafe impl<'a> TrustedRandomAccess for Bytes<'a> { +unsafe impl TrustedRandomAccess for Bytes<'_> { unsafe fn get_unchecked(&mut self, i: usize) -> u8 { self.0.get_unchecked(i) } @@ -1346,33 +1348,14 @@ impl FusedIterator for Lines<'_> {} #[allow(deprecated)] pub struct LinesAny<'a>(Lines<'a>); -/// A nameable, cloneable fn type -#[derive(Clone)] -struct LinesAnyMap; - -impl<'a> Fn<(&'a str,)> for LinesAnyMap { - #[inline] - extern "rust-call" fn call(&self, (line,): (&'a str,)) -> &'a str { +impl_fn_for_zst! { + /// A nameable, cloneable fn type + #[derive(Clone)] + struct LinesAnyMap impl<'a> Fn = |line: &'a str| -> &'a str { let l = line.len(); if l > 0 && line.as_bytes()[l - 1] == b'\r' { &line[0 .. l - 1] } else { line } - } -} - -impl<'a> FnMut<(&'a str,)> for LinesAnyMap { - #[inline] - extern "rust-call" fn call_mut(&mut self, (line,): (&'a str,)) -> &'a str { - Fn::call(&*self, (line,)) - } -} - -impl<'a> FnOnce<(&'a str,)> for LinesAnyMap { - type Output = &'a str; - - #[inline] - extern "rust-call" fn call_once(self, (line,): (&'a str,)) -> &'a str { - Fn::call(&self, (line,)) - } + }; } #[stable(feature = "rust1", since = "1.0.0")] @@ -1580,9 +1563,9 @@ mod traits { /// Implements ordering of strings. /// - /// Strings are ordered lexicographically by their byte values. This orders Unicode code - /// points based on their positions in the code charts. This is not necessarily the same as - /// "alphabetical" order, which varies by language and locale. Sorting strings according to + /// Strings are ordered lexicographically by their byte values. This orders Unicode code + /// points based on their positions in the code charts. This is not necessarily the same as + /// "alphabetical" order, which varies by language and locale. Sorting strings according to /// culturally-accepted standards requires locale-specific data that is outside the scope of /// the `str` type. #[stable(feature = "rust1", since = "1.0.0")] @@ -1608,9 +1591,9 @@ mod traits { /// Implements comparison operations on strings. /// - /// Strings are compared lexicographically by their byte values. This compares Unicode code - /// points based on their positions in the code charts. This is not necessarily the same as - /// "alphabetical" order, which varies by language and locale. Comparing strings according to + /// Strings are compared lexicographically by their byte values. This compares Unicode code + /// points based on their positions in the code charts. This is not necessarily the same as + /// "alphabetical" order, which varies by language and locale. Comparing strings according to /// culturally-accepted standards requires locale-specific data that is outside the scope of /// the `str` type. #[stable(feature = "rust1", since = "1.0.0")] @@ -1621,190 +1604,26 @@ mod traits { } } - /// Implements substring slicing with syntax `&self[begin .. end]`. - /// - /// Returns a slice of the given string from the byte range - /// [`begin`..`end`). - /// - /// This operation is `O(1)`. - /// - /// # Panics - /// - /// Panics if `begin` or `end` does not point to the starting - /// byte offset of a character (as defined by `is_char_boundary`). - /// Requires that `begin <= end` and `end <= len` where `len` is the - /// length of the string. - /// - /// # Examples - /// - /// ``` - /// let s = "Löwe 老虎 Léopard"; - /// assert_eq!(&s[0 .. 1], "L"); - /// - /// assert_eq!(&s[1 .. 9], "öwe 老"); - /// - /// // these will panic: - /// // byte 2 lies within `ö`: - /// // &s[2 ..3]; - /// - /// // byte 8 lies within `老` - /// // &s[1 .. 8]; - /// - /// // byte 100 is outside the string - /// // &s[3 .. 100]; - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - impl ops::Index> for str { - type Output = str; - #[inline] - fn index(&self, index: ops::Range) -> &str { - index.index(self) - } - } - - /// Implements mutable substring slicing with syntax - /// `&mut self[begin .. end]`. - /// - /// Returns a mutable slice of the given string from the byte range - /// [`begin`..`end`). - /// - /// This operation is `O(1)`. - /// - /// # Panics - /// - /// Panics if `begin` or `end` does not point to the starting - /// byte offset of a character (as defined by `is_char_boundary`). - /// Requires that `begin <= end` and `end <= len` where `len` is the - /// length of the string. - #[stable(feature = "derefmut_for_string", since = "1.3.0")] - impl ops::IndexMut> for str { - #[inline] - fn index_mut(&mut self, index: ops::Range) -> &mut str { - index.index_mut(self) - } - } - - /// Implements substring slicing with syntax `&self[.. end]`. - /// - /// Returns a slice of the string from the beginning to byte offset - /// `end`. - /// - /// Equivalent to `&self[0 .. end]`. #[stable(feature = "rust1", since = "1.0.0")] - impl ops::Index> for str { - type Output = str; - - #[inline] - fn index(&self, index: ops::RangeTo) -> &str { - index.index(self) - } - } - - /// Implements mutable substring slicing with syntax `&mut self[.. end]`. - /// - /// Returns a mutable slice of the string from the beginning to byte offset - /// `end`. - /// - /// Equivalent to `&mut self[0 .. end]`. - #[stable(feature = "derefmut_for_string", since = "1.3.0")] - impl ops::IndexMut> for str { - #[inline] - fn index_mut(&mut self, index: ops::RangeTo) -> &mut str { - index.index_mut(self) - } - } - - /// Implements substring slicing with syntax `&self[begin ..]`. - /// - /// Returns a slice of the string from byte offset `begin` - /// to the end of the string. - /// - /// Equivalent to `&self[begin .. len]`. - #[stable(feature = "rust1", since = "1.0.0")] - impl ops::Index> for str { - type Output = str; + impl ops::Index for str + where + I: SliceIndex, + { + type Output = I::Output; #[inline] - fn index(&self, index: ops::RangeFrom) -> &str { + fn index(&self, index: I) -> &I::Output { index.index(self) } } - /// Implements mutable substring slicing with syntax `&mut self[begin ..]`. - /// - /// Returns a mutable slice of the string from byte offset `begin` - /// to the end of the string. - /// - /// Equivalent to `&mut self[begin .. len]`. - #[stable(feature = "derefmut_for_string", since = "1.3.0")] - impl ops::IndexMut> for str { - #[inline] - fn index_mut(&mut self, index: ops::RangeFrom) -> &mut str { - index.index_mut(self) - } - } - - /// Implements substring slicing with syntax `&self[..]`. - /// - /// Returns a slice of the whole string. This operation can - /// never panic. - /// - /// Equivalent to `&self[0 .. len]`. #[stable(feature = "rust1", since = "1.0.0")] - impl ops::Index for str { - type Output = str; - - #[inline] - fn index(&self, _index: ops::RangeFull) -> &str { - self - } - } - - /// Implements mutable substring slicing with syntax `&mut self[..]`. - /// - /// Returns a mutable slice of the whole string. This operation can - /// never panic. - /// - /// Equivalent to `&mut self[0 .. len]`. - #[stable(feature = "derefmut_for_string", since = "1.3.0")] - impl ops::IndexMut for str { - #[inline] - fn index_mut(&mut self, _index: ops::RangeFull) -> &mut str { - self - } - } - - #[stable(feature = "inclusive_range", since = "1.26.0")] - impl ops::Index> for str { - type Output = str; - - #[inline] - fn index(&self, index: ops::RangeInclusive) -> &str { - index.index(self) - } - } - - #[stable(feature = "inclusive_range", since = "1.26.0")] - impl ops::Index> for str { - type Output = str; - - #[inline] - fn index(&self, index: ops::RangeToInclusive) -> &str { - index.index(self) - } - } - - #[stable(feature = "inclusive_range", since = "1.26.0")] - impl ops::IndexMut> for str { - #[inline] - fn index_mut(&mut self, index: ops::RangeInclusive) -> &mut str { - index.index_mut(self) - } - } - #[stable(feature = "inclusive_range", since = "1.26.0")] - impl ops::IndexMut> for str { + impl ops::IndexMut for str + where + I: SliceIndex, + { #[inline] - fn index_mut(&mut self, index: ops::RangeToInclusive) -> &mut str { + fn index_mut(&mut self, index: I) -> &mut I::Output { index.index_mut(self) } } @@ -1815,6 +1634,18 @@ mod traits { panic!("attempted to index str up to maximum usize"); } + /// Implements substring slicing with syntax `&self[..]` or `&mut self[..]`. + /// + /// Returns a slice of the whole string, i.e., returns `&self` or `&mut + /// self`. Equivalent to `&self[0 .. len]` or `&mut self[0 .. len]`. Unlike + /// other indexing operations, this can never panic. + /// + /// This operation is `O(1)`. + /// + /// Prior to 1.20.0, these indexing operations were still supported by + /// direct implementation of `Index` and `IndexMut`. + /// + /// Equivalent to `&self[0 .. len]` or `&mut self[0 .. len]`. #[stable(feature = "str_checked_slicing", since = "1.20.0")] impl SliceIndex for ops::RangeFull { type Output = str; @@ -1844,6 +1675,41 @@ mod traits { } } + /// Implements substring slicing with syntax `&self[begin .. end]` or `&mut + /// self[begin .. end]`. + /// + /// Returns a slice of the given string from the byte range + /// [`begin`, `end`). + /// + /// This operation is `O(1)`. + /// + /// Prior to 1.20.0, these indexing operations were still supported by + /// direct implementation of `Index` and `IndexMut`. + /// + /// # Panics + /// + /// Panics if `begin` or `end` does not point to the starting byte offset of + /// a character (as defined by `is_char_boundary`), if `begin > end`, or if + /// `end > len`. + /// + /// # Examples + /// + /// ``` + /// let s = "Löwe 老虎 Léopard"; + /// assert_eq!(&s[0 .. 1], "L"); + /// + /// assert_eq!(&s[1 .. 9], "öwe 老"); + /// + /// // these will panic: + /// // byte 2 lies within `ö`: + /// // &s[2 ..3]; + /// + /// // byte 8 lies within `老` + /// // &s[1 .. 8]; + /// + /// // byte 100 is outside the string + /// // &s[3 .. 100]; + /// ``` #[stable(feature = "str_checked_slicing", since = "1.20.0")] impl SliceIndex for ops::Range { type Output = str; @@ -1875,9 +1741,9 @@ mod traits { } #[inline] unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output { - let ptr = slice.as_ptr().add(self.start); + let ptr = slice.as_mut_ptr().add(self.start); let len = self.end - self.start; - super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr as *mut u8, len)) + super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr, len)) } #[inline] fn index(self, slice: &str) -> &Self::Output { @@ -1898,6 +1764,21 @@ mod traits { } } + /// Implements substring slicing with syntax `&self[.. end]` or `&mut + /// self[.. end]`. + /// + /// Returns a slice of the given string from the byte range [`0`, `end`). + /// Equivalent to `&self[0 .. end]` or `&mut self[0 .. end]`. + /// + /// This operation is `O(1)`. + /// + /// Prior to 1.20.0, these indexing operations were still supported by + /// direct implementation of `Index` and `IndexMut`. + /// + /// # Panics + /// + /// Panics if `end` does not point to the starting byte offset of a + /// character (as defined by `is_char_boundary`), or if `end > len`. #[stable(feature = "str_checked_slicing", since = "1.20.0")] impl SliceIndex for ops::RangeTo { type Output = str; @@ -1924,8 +1805,8 @@ mod traits { } #[inline] unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output { - let ptr = slice.as_ptr(); - super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr as *mut u8, self.end)) + let ptr = slice.as_mut_ptr(); + super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr, self.end)) } #[inline] fn index(self, slice: &str) -> &Self::Output { @@ -1943,6 +1824,22 @@ mod traits { } } + /// Implements substring slicing with syntax `&self[begin ..]` or `&mut + /// self[begin ..]`. + /// + /// Returns a slice of the given string from the byte range [`begin`, + /// `len`). Equivalent to `&self[begin .. len]` or `&mut self[begin .. + /// len]`. + /// + /// This operation is `O(1)`. + /// + /// Prior to 1.20.0, these indexing operations were still supported by + /// direct implementation of `Index` and `IndexMut`. + /// + /// # Panics + /// + /// Panics if `begin` does not point to the starting byte offset of + /// a character (as defined by `is_char_boundary`), or if `begin >= len`. #[stable(feature = "str_checked_slicing", since = "1.20.0")] impl SliceIndex for ops::RangeFrom { type Output = str; @@ -1970,9 +1867,9 @@ mod traits { } #[inline] unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output { - let ptr = slice.as_ptr().add(self.start); + let ptr = slice.as_mut_ptr().add(self.start); let len = slice.len() - self.start; - super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr as *mut u8, len)) + super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr, len)) } #[inline] fn index(self, slice: &str) -> &Self::Output { @@ -1990,6 +1887,22 @@ mod traits { } } + /// Implements substring slicing with syntax `&self[begin ..= end]` or `&mut + /// self[begin ..= end]`. + /// + /// Returns a slice of the given string from the byte range + /// [`begin`, `end`]. Equivalent to `&self [begin .. end + 1]` or `&mut + /// self[begin .. end + 1]`, except if `end` has the maximum value for + /// `usize`. + /// + /// This operation is `O(1)`. + /// + /// # Panics + /// + /// Panics if `begin` does not point to the starting byte offset of + /// a character (as defined by `is_char_boundary`), if `end` does not point + /// to the ending byte offset of a character (`end + 1` is either a starting + /// byte offset or equal to `len`), if `begin > end`, or if `end >= len`. #[stable(feature = "inclusive_range", since = "1.26.0")] impl SliceIndex for ops::RangeInclusive { type Output = str; @@ -2023,8 +1936,20 @@ mod traits { } } - - + /// Implements substring slicing with syntax `&self[..= end]` or `&mut + /// self[..= end]`. + /// + /// Returns a slice of the given string from the byte range [0, `end`]. + /// Equivalent to `&self [0 .. end + 1]`, except if `end` has the maximum + /// value for `usize`. + /// + /// This operation is `O(1)`. + /// + /// # Panics + /// + /// Panics if `end` does not point to the ending byte offset of a character + /// (`end + 1` is either a starting byte offset as defined by + /// `is_char_boundary`, or equal to `len`), or if `end >= len`. #[stable(feature = "inclusive_range", since = "1.26.0")] impl SliceIndex for ops::RangeToInclusive { type Output = str; @@ -2272,6 +2197,22 @@ impl str { self as *const str as *const u8 } + /// Converts a mutable string slice to a raw pointer. + /// + /// As string slices are a slice of bytes, the raw pointer points to a + /// [`u8`]. This pointer will be pointing to the first byte of the string + /// slice. + /// + /// It is your responsibility to make sure that the string slice only gets + /// modified in a way that it remains valid UTF-8. + /// + /// [`u8`]: primitive.u8.html + #[unstable(feature = "str_as_mut_ptr", issue = "58215")] + #[inline] + pub fn as_mut_ptr(&mut self) -> *mut u8 { + self as *mut str as *mut u8 + } + /// Returns a subslice of `str`. /// /// This is the non-panicking alternative to indexing the `str`. Returns @@ -2559,7 +2500,7 @@ impl str { // is_char_boundary checks that the index is in [0, .len()] if self.is_char_boundary(mid) { let len = self.len(); - let ptr = self.as_ptr() as *mut u8; + let ptr = self.as_mut_ptr(); unsafe { (from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr, mid)), from_utf8_unchecked_mut(slice::from_raw_parts_mut( @@ -2702,7 +2643,7 @@ impl str { Bytes(self.as_bytes().iter().cloned()) } - /// Split a string slice by whitespace. + /// Splits a string slice by whitespace. /// /// The iterator returned will return string slices that are sub-slices of /// the original string slice, separated by any amount of whitespace. @@ -2745,7 +2686,7 @@ impl str { SplitWhitespace { inner: self.split(IsWhitespace).filter(IsNotEmpty) } } - /// Split a string slice by ASCII whitespace. + /// Splits a string slice by ASCII whitespace. /// /// The iterator returned will return string slices that are sub-slices of /// the original string slice, separated by any amount of ASCII whitespace. @@ -2759,7 +2700,6 @@ impl str { /// Basic usage: /// /// ``` - /// #![feature(split_ascii_whitespace)] /// let mut iter = "A few words".split_ascii_whitespace(); /// /// assert_eq!(Some("A"), iter.next()); @@ -2781,13 +2721,13 @@ impl str { /// /// assert_eq!(None, iter.next()); /// ``` - #[unstable(feature = "split_ascii_whitespace", issue = "48656")] + #[stable(feature = "split_ascii_whitespace", since = "1.34.0")] #[inline] pub fn split_ascii_whitespace(&self) -> SplitAsciiWhitespace { let inner = self .as_bytes() .split(IsAsciiWhitespace) - .filter(IsNotEmpty) + .filter(BytesIsNotEmpty) .map(UnsafeBytesToStr); SplitAsciiWhitespace { inner } } @@ -3021,8 +2961,8 @@ impl str { /// An iterator over substrings of this string slice, separated by /// characters matched by a pattern. /// - /// The pattern can be a `&str`, [`char`], or a closure that determines the - /// split. + /// The pattern can be any type that implements the Pattern trait. Notable + /// examples are `&str`, [`char`], and closures that determines the split. /// /// # Iterator behavior /// @@ -3138,8 +3078,8 @@ impl str { /// An iterator over substrings of the given string slice, separated by /// characters matched by a pattern and yielded in reverse order. /// - /// The pattern can be a `&str`, [`char`], or a closure that determines the - /// split. + /// The pattern can be any type that implements the Pattern trait. Notable + /// examples are `&str`, [`char`], and closures that determines the split. /// /// # Iterator behavior /// @@ -3188,8 +3128,8 @@ impl str { /// An iterator over substrings of the given string slice, separated by /// characters matched by a pattern. /// - /// The pattern can be a `&str`, [`char`], or a closure that determines the - /// split. + /// The pattern can be any type that implements the Pattern trait. Notable + /// examples are `&str`, [`char`], and closures that determines the split. /// /// Equivalent to [`split`], except that the trailing substring /// is skipped if empty. @@ -3235,8 +3175,8 @@ impl str { /// An iterator over substrings of `self`, separated by characters /// matched by a pattern and yielded in reverse order. /// - /// The pattern can be a simple `&str`, [`char`], or a closure that - /// determines the split. + /// The pattern can be any type that implements the Pattern trait. Notable + /// examples are `&str`, [`char`], and closures that determines the split. /// Additional libraries might provide more complex patterns like /// regular expressions. /// @@ -3282,8 +3222,8 @@ impl str { /// If `n` substrings are returned, the last substring (the `n`th substring) /// will contain the remainder of the string. /// - /// The pattern can be a `&str`, [`char`], or a closure that determines the - /// split. + /// The pattern can be any type that implements the Pattern trait. Notable + /// examples are `&str`, [`char`], and closures that determines the split. /// /// # Iterator behavior /// @@ -3335,8 +3275,8 @@ impl str { /// If `n` substrings are returned, the last substring (the `n`th substring) /// will contain the remainder of the string. /// - /// The pattern can be a `&str`, [`char`], or a closure that - /// determines the split. + /// The pattern can be any type that implements the Pattern trait. Notable + /// examples are `&str`, [`char`], and closures that determines the split. /// /// # Iterator behavior /// @@ -3379,8 +3319,8 @@ impl str { /// An iterator over the disjoint matches of a pattern within the given string /// slice. /// - /// The pattern can be a `&str`, [`char`], or a closure that - /// determines if a character matches. + /// The pattern can be any type that implements the Pattern trait. Notable + /// examples are `&str`, [`char`], and closures that determines the split. /// /// # Iterator behavior /// @@ -3548,6 +3488,8 @@ impl str { /// /// assert_eq!("Hello\tworld", s.trim()); /// ``` + #[must_use = "this returns the trimmed string as a slice, \ + without modifying the original"] #[stable(feature = "rust1", since = "1.0.0")] pub fn trim(&self) -> &str { self.trim_matches(|c: char| c.is_whitespace()) @@ -3562,7 +3504,7 @@ impl str { /// /// A string is a sequence of bytes. `start` in this context means the first /// position of that byte string; for a left-to-right language like English or - /// Russian, this will be left side; and for right-to-left languages like + /// Russian, this will be left side, and for right-to-left languages like /// like Arabic or Hebrew, this will be the right side. /// /// # Examples @@ -3583,6 +3525,8 @@ impl str { /// let s = " עברית "; /// assert!(Some('ע') == s.trim_start().chars().next()); /// ``` + #[must_use = "this returns the trimmed string as a new slice, \ + without modifying the original"] #[stable(feature = "trim_direction", since = "1.30.0")] pub fn trim_start(&self) -> &str { self.trim_start_matches(|c: char| c.is_whitespace()) @@ -3597,7 +3541,7 @@ impl str { /// /// A string is a sequence of bytes. `end` in this context means the last /// position of that byte string; for a left-to-right language like English or - /// Russian, this will be right side; and for right-to-left languages like + /// Russian, this will be right side, and for right-to-left languages like /// like Arabic or Hebrew, this will be the left side. /// /// # Examples @@ -3618,6 +3562,8 @@ impl str { /// let s = " עברית "; /// assert!(Some('ת') == s.trim_end().chars().rev().next()); /// ``` + #[must_use = "this returns the trimmed string as a new slice, \ + without modifying the original"] #[stable(feature = "trim_direction", since = "1.30.0")] pub fn trim_end(&self) -> &str { self.trim_end_matches(|c: char| c.is_whitespace()) @@ -3720,6 +3666,8 @@ impl str { /// ``` /// assert_eq!("1foo1barXX".trim_matches(|c| c == '1' || c == 'X'), "foo1bar"); /// ``` + #[must_use = "this returns the trimmed string as a new slice, \ + without modifying the original"] #[stable(feature = "rust1", since = "1.0.0")] pub fn trim_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str where P::Searcher: DoubleEndedSearcher<'a> @@ -3765,6 +3713,8 @@ impl str { /// let x: &[_] = &['1', '2']; /// assert_eq!("12foo1bar12".trim_start_matches(x), "foo1bar12"); /// ``` + #[must_use = "this returns the trimmed string as a new slice, \ + without modifying the original"] #[stable(feature = "trim_direction", since = "1.30.0")] pub fn trim_start_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str { let mut i = self.len(); @@ -3808,6 +3758,8 @@ impl str { /// ``` /// assert_eq!("1fooX".trim_end_matches(|c| c == '1' || c == 'X'), "1foo"); /// ``` + #[must_use = "this returns the trimmed string as a new slice, \ + without modifying the original"] #[stable(feature = "trim_direction", since = "1.30.0")] pub fn trim_end_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str where P::Searcher: ReverseSearcher<'a> @@ -3833,10 +3785,10 @@ impl str { /// /// # Text directionality /// - /// A string is a sequence of bytes. 'Left' in this context means the first - /// position of that byte string; for a language like Arabic or Hebrew - /// which are 'right to left' rather than 'left to right', this will be - /// the _right_ side, not the left. + /// A string is a sequence of bytes. `start` in this context means the first + /// position of that byte string; for a left-to-right language like English or + /// Russian, this will be left side, and for right-to-left languages like + /// like Arabic or Hebrew, this will be the right side. /// /// # Examples /// @@ -3865,10 +3817,10 @@ impl str { /// /// # Text directionality /// - /// A string is a sequence of bytes. 'Right' in this context means the last - /// position of that byte string; for a language like Arabic or Hebrew - /// which are 'right to left' rather than 'left to right', this will be - /// the _left_ side, not the right. + /// A string is a sequence of bytes. `end` in this context means the last + /// position of that byte string; for a left-to-right language like English or + /// Russian, this will be right side, and for right-to-left languages like + /// like Arabic or Hebrew, this will be the left side. /// /// # Examples /// @@ -4012,6 +3964,146 @@ impl str { let me = unsafe { self.as_bytes_mut() }; me.make_ascii_lowercase() } + + /// Return an iterator that escapes each char in `s` with [`char::escape_debug`]. + /// + /// Note: only extended grapheme codepoints that begin the string will be + /// escaped. + /// + /// [`char::escape_debug`]: ../std/primitive.char.html#method.escape_debug + /// + /// # Examples + /// + /// As an iterator: + /// + /// ``` + /// for c in "❤\n!".escape_debug() { + /// print!("{}", c); + /// } + /// println!(); + /// ``` + /// + /// Using `println!` directly: + /// + /// ``` + /// println!("{}", "❤\n!".escape_debug()); + /// ``` + /// + /// + /// Both are equivalent to: + /// + /// ``` + /// println!("❤\\n!"); + /// ``` + /// + /// Using `to_string`: + /// + /// ``` + /// assert_eq!("❤\n!".escape_debug().to_string(), "❤\\n!"); + /// ``` + #[stable(feature = "str_escape", since = "1.34.0")] + pub fn escape_debug(&self) -> EscapeDebug { + let mut chars = self.chars(); + EscapeDebug { + inner: chars.next() + .map(|first| first.escape_debug_ext(true)) + .into_iter() + .flatten() + .chain(chars.flat_map(CharEscapeDebugContinue)) + } + } + + /// Return an iterator that escapes each char in `s` with [`char::escape_default`]. + /// + /// [`char::escape_default`]: ../std/primitive.char.html#method.escape_default + /// + /// # Examples + /// + /// As an iterator: + /// + /// ``` + /// for c in "❤\n!".escape_default() { + /// print!("{}", c); + /// } + /// println!(); + /// ``` + /// + /// Using `println!` directly: + /// + /// ``` + /// println!("{}", "❤\n!".escape_default()); + /// ``` + /// + /// + /// Both are equivalent to: + /// + /// ``` + /// println!("\\u{{2764}}\n!"); + /// ``` + /// + /// Using `to_string`: + /// + /// ``` + /// assert_eq!("❤\n!".escape_default().to_string(), "\\u{2764}\\n!"); + /// ``` + #[stable(feature = "str_escape", since = "1.34.0")] + 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`]. + /// + /// [`char::escape_unicode`]: ../std/primitive.char.html#method.escape_unicode + /// + /// # Examples + /// + /// As an iterator: + /// + /// ``` + /// for c in "❤\n!".escape_unicode() { + /// print!("{}", c); + /// } + /// println!(); + /// ``` + /// + /// Using `println!` directly: + /// + /// ``` + /// println!("{}", "❤\n!".escape_unicode()); + /// ``` + /// + /// + /// Both are equivalent to: + /// + /// ``` + /// println!("\\u{{2764}}\\u{{a}}\\u{{21}}"); + /// ``` + /// + /// Using `to_string`: + /// + /// ``` + /// 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 { + EscapeUnicode { inner: self.chars().flat_map(CharEscapeUnicode) } + } +} + +impl_fn_for_zst! { + #[derive(Clone)] + struct CharEscapeDebugContinue impl Fn = |c: char| -> char::EscapeDebug { + c.escape_debug_ext(false) + }; + + #[derive(Clone)] + struct CharEscapeUnicode impl Fn = |c: char| -> char::EscapeUnicode { + c.escape_unicode() + }; + #[derive(Clone)] + struct CharEscapeDefault impl Fn = |c: char| -> char::EscapeDefault { + c.escape_default() + }; } #[stable(feature = "rust1", since = "1.0.0")] @@ -4056,105 +4148,39 @@ pub struct SplitWhitespace<'a> { /// /// [`split_ascii_whitespace`]: ../../std/primitive.str.html#method.split_ascii_whitespace /// [`str`]: ../../std/primitive.str.html -#[unstable(feature = "split_ascii_whitespace", issue = "48656")] +#[stable(feature = "split_ascii_whitespace", since = "1.34.0")] #[derive(Clone, Debug)] pub struct SplitAsciiWhitespace<'a> { - inner: Map, IsNotEmpty>, UnsafeBytesToStr>, -} - -#[derive(Clone)] -struct IsWhitespace; - -impl FnOnce<(char, )> for IsWhitespace { - type Output = bool; - - #[inline] - extern "rust-call" fn call_once(mut self, arg: (char, )) -> bool { - self.call_mut(arg) - } -} - -impl FnMut<(char, )> for IsWhitespace { - #[inline] - extern "rust-call" fn call_mut(&mut self, arg: (char, )) -> bool { - arg.0.is_whitespace() - } -} - -#[derive(Clone)] -struct IsAsciiWhitespace; - -impl<'a> FnOnce<(&'a u8, )> for IsAsciiWhitespace { - type Output = bool; - - #[inline] - extern "rust-call" fn call_once(mut self, arg: (&u8, )) -> bool { - self.call_mut(arg) - } -} - -impl<'a> FnMut<(&'a u8, )> for IsAsciiWhitespace { - #[inline] - extern "rust-call" fn call_mut(&mut self, arg: (&u8, )) -> bool { - arg.0.is_ascii_whitespace() - } -} - -#[derive(Clone)] -struct IsNotEmpty; - -impl<'a, 'b> FnOnce<(&'a &'b str, )> for IsNotEmpty { - type Output = bool; - - #[inline] - extern "rust-call" fn call_once(mut self, arg: (&'a &'b str, )) -> bool { - self.call_mut(arg) - } -} - -impl<'a, 'b> FnMut<(&'a &'b str, )> for IsNotEmpty { - #[inline] - extern "rust-call" fn call_mut(&mut self, arg: (&'a &'b str, )) -> bool { - !arg.0.is_empty() - } -} - -impl<'a, 'b> FnOnce<(&'a &'b [u8], )> for IsNotEmpty { - type Output = bool; - - #[inline] - extern "rust-call" fn call_once(mut self, arg: (&'a &'b [u8], )) -> bool { - self.call_mut(arg) - } + inner: Map, BytesIsNotEmpty>, UnsafeBytesToStr>, } -impl<'a, 'b> FnMut<(&'a &'b [u8], )> for IsNotEmpty { - #[inline] - extern "rust-call" fn call_mut(&mut self, arg: (&'a &'b [u8], )) -> bool { - !arg.0.is_empty() - } -} +impl_fn_for_zst! { + #[derive(Clone)] + struct IsWhitespace impl Fn = |c: char| -> bool { + c.is_whitespace() + }; -#[derive(Clone)] -struct UnsafeBytesToStr; + #[derive(Clone)] + struct IsAsciiWhitespace impl Fn = |byte: &u8| -> bool { + byte.is_ascii_whitespace() + }; -impl<'a> FnOnce<(&'a [u8], )> for UnsafeBytesToStr { - type Output = &'a str; + #[derive(Clone)] + struct IsNotEmpty impl<'a, 'b> Fn = |s: &'a &'b str| -> bool { + !s.is_empty() + }; - #[inline] - extern "rust-call" fn call_once(mut self, arg: (&'a [u8], )) -> &'a str { - self.call_mut(arg) - } -} + #[derive(Clone)] + struct BytesIsNotEmpty impl<'a, 'b> Fn = |s: &'a &'b [u8]| -> bool { + !s.is_empty() + }; -impl<'a> FnMut<(&'a [u8], )> for UnsafeBytesToStr { - #[inline] - extern "rust-call" fn call_mut(&mut self, arg: (&'a [u8], )) -> &'a str { - unsafe { from_utf8_unchecked(arg.0) } - } + #[derive(Clone)] + struct UnsafeBytesToStr impl<'a> Fn = |bytes: &'a [u8]| -> &'a str { + unsafe { from_utf8_unchecked(bytes) } + }; } - #[stable(feature = "split_whitespace", since = "1.1.0")] impl<'a> Iterator for SplitWhitespace<'a> { type Item = &'a str; @@ -4181,7 +4207,7 @@ impl<'a> DoubleEndedIterator for SplitWhitespace<'a> { #[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for SplitWhitespace<'_> {} -#[unstable(feature = "split_ascii_whitespace", issue = "48656")] +#[stable(feature = "split_ascii_whitespace", since = "1.34.0")] impl<'a> Iterator for SplitAsciiWhitespace<'a> { type Item = &'a str; @@ -4196,7 +4222,7 @@ impl<'a> Iterator for SplitAsciiWhitespace<'a> { } } -#[unstable(feature = "split_ascii_whitespace", issue = "48656")] +#[stable(feature = "split_ascii_whitespace", since = "1.34.0")] impl<'a> DoubleEndedIterator for SplitAsciiWhitespace<'a> { #[inline] fn next_back(&mut self) -> Option<&'a str> { @@ -4204,7 +4230,7 @@ impl<'a> DoubleEndedIterator for SplitAsciiWhitespace<'a> { } } -#[unstable(feature = "split_ascii_whitespace", issue = "48656")] +#[stable(feature = "split_ascii_whitespace", since = "1.34.0")] impl FusedIterator for SplitAsciiWhitespace<'_> {} /// An iterator of [`u16`] over the string encoded as UTF-16. @@ -4264,3 +4290,74 @@ impl<'a> Iterator for EncodeUtf16<'a> { #[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for EncodeUtf16<'_> {} + +/// The return type of [`str::escape_debug`]. +/// +/// [`str::escape_debug`]: ../../std/primitive.str.html#method.escape_debug +#[stable(feature = "str_escape", since = "1.34.0")] +#[derive(Clone, Debug)] +pub struct EscapeDebug<'a> { + inner: Chain< + Flatten>, + FlatMap, char::EscapeDebug, CharEscapeDebugContinue> + >, +} + +/// The return type of [`str::escape_default`]. +/// +/// [`str::escape_default`]: ../../std/primitive.str.html#method.escape_default +#[stable(feature = "str_escape", since = "1.34.0")] +#[derive(Clone, Debug)] +pub struct EscapeDefault<'a> { + inner: FlatMap, char::EscapeDefault, CharEscapeDefault>, +} + +/// The return type of [`str::escape_unicode`]. +/// +/// [`str::escape_unicode`]: ../../std/primitive.str.html#method.escape_unicode +#[stable(feature = "str_escape", since = "1.34.0")] +#[derive(Clone, Debug)] +pub struct EscapeUnicode<'a> { + inner: FlatMap, char::EscapeUnicode, CharEscapeUnicode>, +} + +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 { + self.clone().try_for_each(|c| f.write_char(c)) + } + } + + #[stable(feature = "str_escape", since = "1.34.0")] + impl<'a> Iterator for $Name<'a> { + type Item = char; + + #[inline] + fn next(&mut self) -> Option { self.inner.next() } + + #[inline] + fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + + #[inline] + fn try_fold(&mut self, init: Acc, fold: Fold) -> R where + Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try + { + self.inner.try_fold(init, fold) + } + + #[inline] + fn fold(self, init: Acc, fold: Fold) -> Acc + where Fold: FnMut(Acc, Self::Item) -> Acc, + { + self.inner.fold(init, fold) + } + } + + #[stable(feature = "str_escape", since = "1.34.0")] + impl<'a> FusedIterator for $Name<'a> {} + )+} +} + +escape_types_impls!(EscapeDebug, EscapeDefault, EscapeUnicode); diff --git a/src/libcore/str/pattern.rs b/src/libcore/str/pattern.rs index 55a7ba181e527..2571780ad0bab 100644 --- a/src/libcore/str/pattern.rs +++ b/src/libcore/str/pattern.rs @@ -1,7 +1,7 @@ //! The string Pattern API. //! -//! For more details, see the traits `Pattern`, `Searcher`, -//! `ReverseSearcher` and `DoubleEndedSearcher`. +//! For more details, see the traits [`Pattern`], [`Searcher`], +//! [`ReverseSearcher`], and [`DoubleEndedSearcher`]. #![unstable(feature = "pattern", reason = "API not fully fleshed out and ready to be stabilized", @@ -117,7 +117,7 @@ pub unsafe trait Searcher<'a> { /// `[Reject(0, 1), Reject(1, 2), Match(2, 5), Reject(5, 8)]` fn next(&mut self) -> SearchStep; - /// Find the next `Match` result. See `next()` + /// Finds the next `Match` result. See `next()` /// /// Unlike next(), there is no guarantee that the returned ranges /// of this and next_reject will overlap. This will return (start_match, end_match), @@ -134,7 +134,7 @@ pub unsafe trait Searcher<'a> { } } - /// Find the next `Reject` result. See `next()` and `next_match()` + /// Finds the next `Reject` result. See `next()` and `next_match()` /// /// Unlike next(), there is no guarantee that the returned ranges /// of this and next_match will overlap. @@ -185,7 +185,7 @@ pub unsafe trait ReverseSearcher<'a>: Searcher<'a> { /// `[Reject(7, 8), Match(4, 7), Reject(1, 4), Reject(0, 1)]` fn next_back(&mut self) -> SearchStep; - /// Find the next `Match` result. See `next_back()` + /// Finds the next `Match` result. See `next_back()` #[inline] fn next_match_back(&mut self) -> Option<(usize, usize)>{ loop { @@ -197,7 +197,7 @@ pub unsafe trait ReverseSearcher<'a>: Searcher<'a> { } } - /// Find the next `Reject` result. See `next_back()` + /// Finds the next `Reject` result. See `next_back()` #[inline] fn next_reject_back(&mut self) -> Option<(usize, usize)>{ loop { diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index 99e6365d15ec0..d0ee5fa9e6b31 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -5,13 +5,16 @@ //! types. //! //! This module defines atomic versions of a select number of primitive -//! types, including [`AtomicBool`], [`AtomicIsize`], and [`AtomicUsize`]. +//! types, including [`AtomicBool`], [`AtomicIsize`], [`AtomicUsize`], +//! [`AtomicI8`], [`AtomicU16`], etc. //! Atomic types present operations that, when used correctly, synchronize //! updates between threads. //! //! [`AtomicBool`]: struct.AtomicBool.html //! [`AtomicIsize`]: struct.AtomicIsize.html //! [`AtomicUsize`]: struct.AtomicUsize.html +//! [`AtomicI8`]: struct.AtomicI8.html +//! [`AtomicU16`]: struct.AtomicU16.html //! //! Each method takes an [`Ordering`] which represents the strength of //! the memory barrier for that operation. These orderings are the @@ -31,11 +34,46 @@ //! [`Sync`]: ../../marker/trait.Sync.html //! [arc]: ../../../std/sync/struct.Arc.html //! -//! Most atomic types may be stored in static variables, initialized using -//! the provided static initializers like [`ATOMIC_BOOL_INIT`]. Atomic statics +//! Atomic types may be stored in static variables, initialized using +//! the constant initializers like [`AtomicBool::new`]. Atomic statics //! are often used for lazy global initialization. //! -//! [`ATOMIC_BOOL_INIT`]: constant.ATOMIC_BOOL_INIT.html +//! [`AtomicBool::new`]: struct.AtomicBool.html#method.new +//! +//! # Portability +//! +//! All atomic types in this module are guaranteed to be [lock-free] if they're +//! available. This means they don't internally acquire a global mutex. Atomic +//! types and operations are not guaranteed to be wait-free. This means that +//! operations like `fetch_or` may be implemented with a compare-and-swap loop. +//! +//! Atomic operations may be implemented at the instruction layer with +//! larger-size atomics. For example some platforms use 4-byte atomic +//! instructions to implement `AtomicI8`. Note that this emulation should not +//! have an impact on correctness of code, it's just something to be aware of. +//! +//! The atomic types in this module may not be available on all platforms. The +//! atomic types here are all widely available, however, and can generally be +//! relied upon existing. Some notable exceptions are: +//! +//! * PowerPC and MIPS platforms with 32-bit pointers do not have `AtomicU64` or +//! `AtomicI64` types. +//! * ARM platforms like `armv5te` that aren't for Linux do not have any atomics +//! at all. +//! * ARM targets with `thumbv6m` do not have atomic operations at all. +//! +//! Note that future platforms may be added that also do not have support for +//! some atomic operations. Maximally portable code will want to be careful +//! about which atomic types are used. `AtomicUsize` and `AtomicIsize` are +//! generally the most portable, but even then they're not available everywhere. +//! For reference, the `std` library requires pointer-sized atomics, although +//! `core` does not. +//! +//! Currently you'll need to use `#[cfg(target_arch)]` primarily to +//! conditionally compile in code with atomics. There is an unstable +//! `#[cfg(target_has_atomic)]` as well which may be stabilized in the future. +//! +//! [lock-free]: https://en.wikipedia.org/wiki/Non-blocking_algorithm //! //! # Examples //! @@ -66,9 +104,9 @@ //! Keep a global count of live threads: //! //! ``` -//! use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT}; +//! use std::sync::atomic::{AtomicUsize, Ordering}; //! -//! static GLOBAL_THREAD_COUNT: AtomicUsize = ATOMIC_USIZE_INIT; +//! static GLOBAL_THREAD_COUNT: AtomicUsize = AtomicUsize::new(0); //! //! let old_thread_count = GLOBAL_THREAD_COUNT.fetch_add(1, Ordering::SeqCst); //! println!("live threads: {}", old_thread_count + 1); @@ -84,6 +122,8 @@ use intrinsics; use cell::UnsafeCell; use fmt; +use hint::spin_loop; + /// Save power or switch hyperthreads in a busy-wait spin-loop. /// /// This function is deliberately more primitive than @@ -96,15 +136,7 @@ use fmt; #[inline] #[stable(feature = "spin_loop_hint", since = "1.24.0")] pub fn spin_loop_hint() { - #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - unsafe { - asm!("pause" ::: "memory" : "volatile"); - } - - #[cfg(target_arch = "aarch64")] - unsafe { - asm!("yield" ::: "memory" : "volatile"); - } + spin_loop() } /// A boolean type which can be safely shared between threads. @@ -258,6 +290,15 @@ 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( + 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")] @@ -1090,10 +1131,12 @@ macro_rules! atomic_int { $stable_access:meta, $stable_from:meta, $stable_nand:meta, + $stable_init_const:meta, $s_int_type:expr, $int_ref:expr, $extra_feature:expr, $min_fn:ident, $max_fn:ident, $align:expr, + $atomic_new:expr, $int_type:ident $atomic_type:ident $atomic_init:ident) => { /// An integer type which can be safely shared between threads. /// @@ -1103,7 +1146,8 @@ macro_rules! atomic_int { /// `]( #[doc = $int_ref] /// ). For more about the differences between atomic types and - /// non-atomic types, please see the [module-level documentation]. + /// non-atomic types as well as information about the portability of + /// this type, please see the [module-level documentation]. /// /// [module-level documentation]: index.html #[$stable] @@ -1113,7 +1157,16 @@ macro_rules! atomic_int { } /// An atomic integer initialized to `0`. - #[$stable] + #[$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( + 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] @@ -1833,114 +1886,130 @@ assert_eq!(min_foo, 12); #[cfg(target_has_atomic = "8")] atomic_int! { - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + 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)", i8 AtomicI8 ATOMIC_I8_INIT } #[cfg(target_has_atomic = "8")] atomic_int! { - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + 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)", u8 AtomicU8 ATOMIC_U8_INIT } #[cfg(target_has_atomic = "16")] atomic_int! { - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + 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)", i16 AtomicI16 ATOMIC_I16_INIT } #[cfg(target_has_atomic = "16")] atomic_int! { - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + 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)", u16 AtomicU16 ATOMIC_U16_INIT } #[cfg(target_has_atomic = "32")] atomic_int! { - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + 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)", i32 AtomicI32 ATOMIC_I32_INIT } #[cfg(target_has_atomic = "32")] atomic_int! { - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + 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)", u32 AtomicU32 ATOMIC_U32_INIT } #[cfg(target_has_atomic = "64")] atomic_int! { - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + 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)", i64 AtomicI64 ATOMIC_I64_INIT } #[cfg(target_has_atomic = "64")] atomic_int! { - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), - unstable(feature = "integer_atomics", issue = "32976"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + stable(feature = "integer_atomics_stable", since = "1.34.0"), + 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)", u64 AtomicU64 ATOMIC_U64_INIT } #[cfg(target_has_atomic = "128")] @@ -1951,10 +2020,12 @@ atomic_int! { unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), + unstable(feature = "integer_atomics", issue = "32976"), "i128", "../../../std/primitive.i128.html", "#![feature(integer_atomics)]\n\n", atomic_min, atomic_max, 16, + "AtomicI128::new(0)", i128 AtomicI128 ATOMIC_I128_INIT } #[cfg(target_has_atomic = "128")] @@ -1965,10 +2036,12 @@ atomic_int! { unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), + unstable(feature = "integer_atomics", issue = "32976"), "u128", "../../../std/primitive.u128.html", "#![feature(integer_atomics)]\n\n", atomic_umin, atomic_umax, 16, + "AtomicU128::new(0)", u128 AtomicU128 ATOMIC_U128_INIT } #[cfg(target_pointer_width = "16")] @@ -1991,10 +2064,12 @@ atomic_int!{ stable(feature = "atomic_access", since = "1.15.0"), stable(feature = "atomic_from", since = "1.23.0"), stable(feature = "atomic_nand", since = "1.27.0"), + stable(feature = "rust1", since = "1.0.0"), "isize", "../../../std/primitive.isize.html", "", atomic_min, atomic_max, ptr_width!(), + "AtomicIsize::new(0)", isize AtomicIsize ATOMIC_ISIZE_INIT } #[cfg(target_has_atomic = "ptr")] @@ -2005,10 +2080,12 @@ atomic_int!{ stable(feature = "atomic_access", since = "1.15.0"), stable(feature = "atomic_from", since = "1.23.0"), stable(feature = "atomic_nand", since = "1.27.0"), + stable(feature = "rust1", since = "1.0.0"), "usize", "../../../std/primitive.usize.html", "", atomic_umin, atomic_umax, ptr_width!(), + "AtomicUsize::new(0)", usize AtomicUsize ATOMIC_USIZE_INIT } @@ -2378,12 +2455,11 @@ pub fn fence(order: Ordering) { /// /// ``` /// use std::sync::atomic::{AtomicBool, AtomicUsize}; -/// use std::sync::atomic::{ATOMIC_BOOL_INIT, ATOMIC_USIZE_INIT}; /// use std::sync::atomic::Ordering; /// use std::sync::atomic::compiler_fence; /// -/// static IMPORTANT_VARIABLE: AtomicUsize = ATOMIC_USIZE_INIT; -/// static IS_READY: AtomicBool = ATOMIC_BOOL_INIT; +/// static IMPORTANT_VARIABLE: AtomicUsize = AtomicUsize::new(0); +/// static IS_READY: AtomicBool = AtomicBool::new(false); /// /// fn main() { /// IMPORTANT_VARIABLE.store(42, Ordering::Relaxed); diff --git a/src/libcore/task/mod.rs b/src/libcore/task/mod.rs index 9552e53ebf849..9b8f598116200 100644 --- a/src/libcore/task/mod.rs +++ b/src/libcore/task/mod.rs @@ -8,4 +8,4 @@ mod poll; pub use self::poll::Poll; mod wake; -pub use self::wake::{Waker, LocalWaker, UnsafeWake}; +pub use self::wake::{Waker, RawWaker, RawWakerVTable}; diff --git a/src/libcore/task/poll.rs b/src/libcore/task/poll.rs index 27b1139e15c79..c811f96ace3ba 100644 --- a/src/libcore/task/poll.rs +++ b/src/libcore/task/poll.rs @@ -7,6 +7,7 @@ use 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)] pub enum Poll { /// Represents that a value is immediately ready. @@ -21,7 +22,7 @@ pub enum Poll { } impl Poll { - /// Change the ready value of this `Poll` with the closure provided + /// Changes the ready value of this `Poll` with the closure provided. pub fn map(self, f: F) -> Poll where F: FnOnce(T) -> U { @@ -31,7 +32,7 @@ impl Poll { } } - /// Returns whether this is `Poll::Ready` + /// Returns `true` if this is `Poll::Ready` #[inline] pub fn is_ready(&self) -> bool { match *self { @@ -40,7 +41,7 @@ impl Poll { } } - /// Returns whether this is `Poll::Pending` + /// Returns `true` if this is `Poll::Pending` #[inline] pub fn is_pending(&self) -> bool { !self.is_ready() @@ -48,7 +49,7 @@ impl Poll { } impl Poll> { - /// Change the success value of this `Poll` with the closure provided + /// Changes the success value of this `Poll` with the closure provided. pub fn map_ok(self, f: F) -> Poll> where F: FnOnce(T) -> U { @@ -59,7 +60,7 @@ impl Poll> { } } - /// Change the error value of this `Poll` with the closure provided + /// Changes the error value of this `Poll` with the closure provided. pub fn map_err(self, f: F) -> Poll> where F: FnOnce(E) -> U { diff --git a/src/libcore/task/wake.rs b/src/libcore/task/wake.rs index 3f7098f1ef934..21f0a8cea4168 100644 --- a/src/libcore/task/wake.rs +++ b/src/libcore/task/wake.rs @@ -4,16 +4,92 @@ use fmt; use marker::Unpin; -use ptr::NonNull; + +/// A `RawWaker` allows the implementor of a task executor to create a [`Waker`] +/// which provides customized wakeup behavior. +/// +/// [vtable]: https://en.wikipedia.org/wiki/Virtual_method_table +/// +/// It consists of a data pointer and a [virtual function pointer table (vtable)][vtable] that +/// customizes the behavior of the `RawWaker`. +#[derive(PartialEq, Debug)] +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` + /// that is associated with the task. + /// The value of this field gets passed to all functions that are part of + /// the vtable as the first parameter. + data: *const (), + /// Virtual function pointer table that customizes the behavior of this waker. + vtable: &'static RawWakerVTable, +} + +impl RawWaker { + /// Creates a new `RawWaker` from the provided `data` pointer and `vtable`. + /// + /// The `data` pointer can be used to store arbitrary data as required + /// by the executor. This could be e.g. a type-erased pointer to an `Arc` + /// that is associated with the task. + /// The value of this poiner will get passed to all functions that are part + /// of the `vtable` as the first parameter. + /// + /// 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. + pub const fn new(data: *const (), vtable: &'static RawWakerVTable) -> RawWaker { + RawWaker { + data, + vtable, + } + } +} + +/// A virtual function pointer table (vtable) that specifies the behavior +/// of a [`RawWaker`]. +/// +/// The pointer passed to all functions inside the vtable is the `data` pointer +/// from the enclosing [`RawWaker`] object. +/// +/// The functions inside this struct are only intended be called on the `data` +/// 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. +#[derive(PartialEq, Copy, Clone, Debug)] +pub struct RawWakerVTable { + /// 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`]. + pub 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 + /// pointer. + pub wake: 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 ()), +} /// A `Waker` is a handle for waking up a task by notifying its executor that it /// is ready to be run. /// -/// This handle contains a trait object pointing to an instance of the `UnsafeWake` -/// trait, allowing notifications to get routed through it. +/// This handle encapsulates a [`RawWaker`] instance, which defines the +/// executor-specific wakeup behavior. +/// +/// Implements [`Clone`], [`Send`], and [`Sync`]. #[repr(transparent)] pub struct Waker { - inner: NonNull, + waker: RawWaker, } impl Unpin for Waker {} @@ -21,264 +97,66 @@ unsafe impl Send for Waker {} unsafe impl Sync for Waker {} impl Waker { - /// Constructs a new `Waker` directly. - /// - /// Note that most code will not need to call this. Implementers of the - /// `UnsafeWake` trait will typically provide a wrapper that calls this - /// but you otherwise shouldn't call it directly. - /// - /// If you're working with the standard library then it's recommended to - /// use the `Waker::from` function instead which works with the safe - /// `Arc` type and the safe `Wake` trait. - #[inline] - pub unsafe fn new(inner: NonNull) -> Self { - Waker { inner } - } - /// Wake up the task associated with this `Waker`. - #[inline] pub fn wake(&self) { - unsafe { self.inner.as_ref().wake() } + // The actual wakeup call is delegated through a virtual function call + // to the implementation which is defined by the executor. + + // SAFETY: This is safe because `Waker::new_unchecked` 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) } } - /// Returns whether or not this `Waker` and `other` awaken the same task. + /// Returns whether or not this `Waker` and other `Waker` have awaken 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. + /// returns `true`, it is guaranteed that the `Waker`s will awaken the same task. /// /// This function is primarily used for optimization purposes. - #[inline] pub fn will_wake(&self, other: &Waker) -> bool { - self.inner == other.inner + self.waker == other.waker } - /// Returns whether or not this `Waker` and `other` `LocalWaker` awaken - /// the same task. + /// Creates a new `Waker` from [`RawWaker`]. /// - /// 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] - pub fn will_wake_local(&self, other: &LocalWaker) -> bool { - self.will_wake(&other.0) + /// 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 { + Waker { + waker, + } } } impl Clone for Waker { - #[inline] fn clone(&self) -> Self { - unsafe { - self.inner.as_ref().clone_raw() + Waker { + // SAFETY: This is safe because `Waker::new_unchecked` 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) }, } } } -impl fmt::Debug for Waker { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("Waker") - .finish() - } -} - impl Drop for Waker { - #[inline] fn drop(&mut self) { - unsafe { - self.inner.as_ref().drop_raw() - } - } -} - -/// A `LocalWaker` is a handle for waking up a task by notifying its executor that it -/// is ready to be run. -/// -/// This is similar to the `Waker` type, but cannot be sent across threads. -/// Task executors can use this type to implement more optimized single-threaded wakeup -/// behavior. -#[repr(transparent)] -#[derive(Clone)] -pub struct LocalWaker(Waker); - -impl Unpin for LocalWaker {} -impl !Send for LocalWaker {} -impl !Sync for LocalWaker {} - -impl LocalWaker { - /// Constructs a new `LocalWaker` directly. - /// - /// Note that most code will not need to call this. Implementers of the - /// `UnsafeWake` trait will typically provide a wrapper that calls this - /// but you otherwise shouldn't call it directly. - /// - /// If you're working with the standard library then it's recommended to - /// use the `local_waker_from_nonlocal` or `local_waker` to convert a `Waker` - /// into a `LocalWaker`. - /// - /// For this function to be used safely, it must be sound to call `inner.wake_local()` - /// on the current thread. - #[inline] - pub unsafe fn new(inner: NonNull) -> Self { - LocalWaker(Waker::new(inner)) - } - - /// Borrows this `LocalWaker` as a `Waker`. - /// - /// `Waker` is nearly identical to `LocalWaker`, but is threadsafe - /// (implements `Send` and `Sync`). - #[inline] - pub fn as_waker(&self) -> &Waker { - &self.0 - } - - /// Converts this `LocalWaker` into a `Waker`. - /// - /// `Waker` is nearly identical to `LocalWaker`, but is threadsafe - /// (implements `Send` and `Sync`). - #[inline] - pub fn into_waker(self) -> Waker { - self.0 - } - - /// Wake up the task associated with this `LocalWaker`. - #[inline] - pub fn wake(&self) { - unsafe { self.0.inner.as_ref().wake_local() } - } - - /// Returns whether or not this `LocalWaker` and `other` `LocalWaker` awaken the same task. - /// - /// This function works on a best-effort basis, and may return false even - /// when the `LocalWaker`s would awaken the same task. However, if this function - /// returns true, it is guaranteed that the `LocalWaker`s will awaken the same - /// task. - /// - /// This function is primarily used for optimization purposes. - #[inline] - pub fn will_wake(&self, other: &LocalWaker) -> bool { - self.0.will_wake(&other.0) - } - - /// Returns whether or not this `LocalWaker` and `other` `Waker` awaken 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 `LocalWaker`s will awaken the same - /// task. - /// - /// This function is primarily used for optimization purposes. - #[inline] - pub fn will_wake_nonlocal(&self, other: &Waker) -> bool { - self.0.will_wake(other) - } -} - -impl From for Waker { - /// Converts a `LocalWaker` into a `Waker`. - /// - /// This conversion turns a `!Sync` `LocalWaker` into a `Sync` `Waker`, allowing a wakeup - /// object to be sent to another thread, but giving up its ability to do specialized - /// thread-local wakeup behavior. - #[inline] - fn from(local_waker: LocalWaker) -> Self { - local_waker.0 + // SAFETY: This is safe because `Waker::new_unchecked` 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) } } } -impl fmt::Debug for LocalWaker { +impl fmt::Debug for Waker { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("LocalWaker") + let vtable_ptr = self.waker.vtable as *const RawWakerVTable; + f.debug_struct("Waker") + .field("data", &self.waker.data) + .field("vtable", &vtable_ptr) .finish() } } - -/// An unsafe trait for implementing custom memory management for a `Waker` or `LocalWaker`. -/// -/// A `Waker` conceptually is a cloneable trait object for `Wake`, and is -/// most often essentially just `Arc`. However, in some contexts -/// (particularly `no_std`), it's desirable to avoid `Arc` in favor of some -/// custom memory management strategy. This trait is designed to allow for such -/// customization. -/// -/// When using `std`, a default implementation of the `UnsafeWake` trait is provided for -/// `Arc` where `T: Wake`. -pub unsafe trait UnsafeWake: Send + Sync { - /// Creates a clone of this `UnsafeWake` and stores it behind a `Waker`. - /// - /// This function will create a new uniquely owned handle that under the - /// hood references the same notification instance. In other words calls - /// to `wake` on the returned handle should be equivalent to calls to - /// `wake` on this handle. - /// - /// # Unsafety - /// - /// This function is unsafe to call because it's asserting the `UnsafeWake` - /// value is in a consistent state, i.e., hasn't been dropped. - unsafe fn clone_raw(&self) -> Waker; - - /// Drops this instance of `UnsafeWake`, deallocating resources - /// associated with it. - /// - /// FIXME(cramertj) - /// This method is intended to have a signature such as: - /// - /// ```ignore (not-a-doctest) - /// fn drop_raw(self: *mut Self); - /// ``` - /// - /// Unfortunately in Rust today that signature is not object safe. - /// Nevertheless it's recommended to implement this function *as if* that - /// were its signature. As such it is not safe to call on an invalid - /// pointer, nor is the validity of the pointer guaranteed after this - /// function returns. - /// - /// # Unsafety - /// - /// This function is unsafe to call because it's asserting the `UnsafeWake` - /// value is in a consistent state, i.e., hasn't been dropped. - unsafe fn drop_raw(&self); - - /// Indicates that the associated task is ready to make progress and should - /// be `poll`ed. - /// - /// Executors generally maintain a queue of "ready" tasks; `wake` should place - /// the associated task onto this queue. - /// - /// # Panics - /// - /// Implementations should avoid panicking, but clients should also be prepared - /// for panics. - /// - /// # Unsafety - /// - /// This function is unsafe to call because it's asserting the `UnsafeWake` - /// value is in a consistent state, i.e., hasn't been dropped. - unsafe fn wake(&self); - - /// Indicates that the associated task is ready to make progress and should - /// be `poll`ed. This function is the same as `wake`, but can only be called - /// from the thread that this `UnsafeWake` is "local" to. This allows for - /// implementors to provide specialized wakeup behavior specific to the current - /// thread. This function is called by `LocalWaker::wake`. - /// - /// Executors generally maintain a queue of "ready" tasks; `wake_local` should place - /// the associated task onto this queue. - /// - /// # Panics - /// - /// Implementations should avoid panicking, but clients should also be prepared - /// for panics. - /// - /// # Unsafety - /// - /// This function is unsafe to call because it's asserting the `UnsafeWake` - /// value is in a consistent state, i.e., hasn't been dropped, and that the - /// `UnsafeWake` hasn't moved from the thread on which it was created. - unsafe fn wake_local(&self) { - self.wake() - } -} diff --git a/src/libcore/tests/cell.rs b/src/libcore/tests/cell.rs index 56f295dff8e43..b16416022c04e 100644 --- a/src/libcore/tests/cell.rs +++ b/src/libcore/tests/cell.rs @@ -109,6 +109,7 @@ 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(); @@ -349,6 +350,7 @@ fn refcell_ref_coercion() { #[test] #[should_panic] +#[cfg(not(miri))] // Miri does not support panics fn refcell_swap_borrows() { let x = RefCell::new(0); let _b = x.borrow(); @@ -358,6 +360,7 @@ 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/fmt/mod.rs b/src/libcore/tests/fmt/mod.rs index d86e21cf40b6e..df1deeaeb97b7 100644 --- a/src/libcore/tests/fmt/mod.rs +++ b/src/libcore/tests/fmt/mod.rs @@ -3,6 +3,7 @@ mod float; mod num; #[test] +#[cfg(not(miri))] // Miri cannot print pointers fn test_format_flags() { // No residual flags left by pointer formatting let p = "".as_ptr(); @@ -12,6 +13,7 @@ fn test_format_flags() { } #[test] +#[cfg(not(miri))] // Miri cannot print pointers fn test_pointer_formats_data_pointer() { let b: &[u8] = b""; let s: &str = ""; diff --git a/src/libcore/tests/hash/mod.rs b/src/libcore/tests/hash/mod.rs index 135f4dfcac7d5..1000088e6b063 100644 --- a/src/libcore/tests/hash/mod.rs +++ b/src/libcore/tests/hash/mod.rs @@ -73,9 +73,11 @@ fn test_writer_hasher() { let cs: &mut [u8] = &mut [1, 2, 3]; let ptr = cs.as_ptr(); let slice_ptr = cs as *const [u8]; + #[cfg(not(miri))] // Miri cannot hash pointers assert_eq!(hash(&slice_ptr), hash(&ptr) + cs.len() as u64); let slice_ptr = cs as *mut [u8]; + #[cfg(not(miri))] // Miri cannot hash pointers assert_eq!(hash(&slice_ptr), hash(&ptr) + cs.len() as u64); } diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index 3944bc749d029..9b76a4af98824 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -253,6 +253,7 @@ 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(); @@ -877,7 +878,7 @@ fn test_iterator_flat_map() { assert_eq!(i, ys.len()); } -/// Test `FlatMap::fold` with items already picked off the front and back, +/// Tests `FlatMap::fold` with items already picked off the front and back, /// to make sure all parts of the `FlatMap` are folded correctly. #[test] fn test_iterator_flat_map_fold() { @@ -915,7 +916,7 @@ fn test_iterator_flatten() { assert_eq!(i, ys.len()); } -/// Test `Flatten::fold` with items already picked off the front and back, +/// Tests `Flatten::fold` with items already picked off the front and back, /// to make sure all parts of the `Flatten` are folded correctly. #[test] fn test_iterator_flatten_fold() { @@ -1413,6 +1414,7 @@ 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), @@ -2235,3 +2237,16 @@ fn test_monad_laws_associativity() { assert_eq!((0..10).flat_map(f).flat_map(g).sum::(), (0..10).flat_map(|x| f(x).flat_map(g)).sum::()); } + +#[test] +fn test_is_sorted() { + assert!([1, 2, 2, 9].iter().is_sorted()); + assert!(![1, 3, 2].iter().is_sorted()); + assert!([0].iter().is_sorted()); + assert!(std::iter::empty::().is_sorted()); + assert!(![0.0, 1.0, std::f32::NAN].iter().is_sorted()); + assert!([-2, -1, 0, 3].iter().is_sorted()); + assert!(![-2i32, -1, 0, 3].iter().is_sorted_by_key(|n| n.abs())); + assert!(!["c", "bb", "aaa"].iter().is_sorted()); + assert!(["c", "bb", "aaa"].iter().is_sorted_by_key(|s| s.len())); +} diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index a9b8decfd0262..4cd734bad90a4 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -10,10 +10,10 @@ #![feature(flt2dec)] #![feature(fmt_internals)] #![feature(hashmap_internals)] +#![feature(is_sorted)] #![feature(iter_copied)] #![feature(iter_nth_back)] #![feature(iter_once_with)] -#![feature(iter_unfold)] #![feature(pattern)] #![feature(range_is_empty)] #![feature(raw)] diff --git a/src/libcore/tests/nonzero.rs b/src/libcore/tests/nonzero.rs index c813bf20cb61a..4532568ee0c16 100644 --- a/src/libcore/tests/nonzero.rs +++ b/src/libcore/tests/nonzero.rs @@ -1,4 +1,4 @@ -use core::num::NonZeroU32; +use core::num::{NonZeroU32, NonZeroI32}; use core::option::Option; use core::option::Option::{Some, None}; use std::mem::size_of; @@ -13,6 +13,7 @@ fn test_create_nonzero_instance() { #[test] fn test_size_nonzero_in_option() { assert_eq!(size_of::(), size_of::>()); + assert_eq!(size_of::(), size_of::>()); } #[test] @@ -118,3 +119,10 @@ fn test_from_nonzero() { let num: u32 = nz.into(); assert_eq!(num, 1u32); } + +#[test] +fn test_from_signed_nonzero() { + let nz = NonZeroI32::new(1).unwrap(); + let num: i32 = nz.into(); + assert_eq!(num, 1i32); +} diff --git a/src/libcore/tests/num/bignum.rs b/src/libcore/tests/num/bignum.rs index b873f1dd0652f..956c22c998219 100644 --- a/src/libcore/tests/num/bignum.rs +++ b/src/libcore/tests/num/bignum.rs @@ -3,6 +3,7 @@ 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); } @@ -19,12 +20,14 @@ 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)); } @@ -42,6 +45,7 @@ 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); } @@ -57,12 +61,14 @@ 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)); } @@ -76,6 +82,7 @@ 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); } @@ -94,12 +101,14 @@ 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); } @@ -118,12 +127,14 @@ 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); } @@ -141,12 +152,14 @@ 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]); } @@ -206,6 +219,7 @@ 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); } diff --git a/src/libcore/tests/num/dec2flt/mod.rs b/src/libcore/tests/num/dec2flt/mod.rs index 8f1cd32c3563c..faeaabbf95ada 100644 --- a/src/libcore/tests/num/dec2flt/mod.rs +++ b/src/libcore/tests/num/dec2flt/mod.rs @@ -52,6 +52,7 @@ fn large() { } #[test] +#[cfg(not(miri))] // Miri is too slow fn subnormals() { test_literal!(5e-324); test_literal!(91e-324); @@ -63,6 +64,7 @@ fn subnormals() { } #[test] +#[cfg(not(miri))] // Miri is too slow fn infinity() { test_literal!(1e400); test_literal!(1e309); diff --git a/src/libcore/tests/num/flt2dec/mod.rs b/src/libcore/tests/num/flt2dec/mod.rs index fed9ce73b2a8e..d362c7994d806 100644 --- a/src/libcore/tests/num/flt2dec/mod.rs +++ b/src/libcore/tests/num/flt2dec/mod.rs @@ -1,3 +1,5 @@ +#![cfg(not(miri))] // Miri does not implement ldexp, which most tests here need + use std::prelude::v1::*; use std::{str, i16, f32, f64, fmt}; diff --git a/src/libcore/tests/option.rs b/src/libcore/tests/option.rs index b059b134868d9..87ce2720c5918 100644 --- a/src/libcore/tests/option.rs +++ b/src/libcore/tests/option.rs @@ -69,6 +69,7 @@ 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); @@ -129,6 +130,7 @@ fn test_unwrap() { #[test] #[should_panic] +#[cfg(not(miri))] // Miri does not support panics fn test_unwrap_panic1() { let x: Option = None; x.unwrap(); @@ -136,6 +138,7 @@ 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/ptr.rs b/src/libcore/tests/ptr.rs index 65c1a3e0254d2..03fe1fe5a7cf8 100644 --- a/src/libcore/tests/ptr.rs +++ b/src/libcore/tests/ptr.rs @@ -44,13 +44,13 @@ fn test_is_null() { let p: *const isize = null(); assert!(p.is_null()); - let q = unsafe { p.offset(1) }; + let q = p.wrapping_offset(1); assert!(!q.is_null()); let mp: *mut isize = null_mut(); assert!(mp.is_null()); - let mq = unsafe { mp.offset(1) }; + let mq = mp.wrapping_offset(1); assert!(!mq.is_null()); // Pointers to unsized types -- slices @@ -145,6 +145,7 @@ fn test_as_ref() { } #[test] +#[cfg(not(miri))] // This test is UB according to Stacked Borrows fn test_as_mut() { unsafe { let p: *mut isize = null_mut(); @@ -221,8 +222,11 @@ fn test_ptr_subtraction() { let m_start = xs_mut.as_mut_ptr(); let mut m_ptr = m_start.offset(9); - while m_ptr >= m_start { + loop { *m_ptr += *m_ptr; + if m_ptr == m_start { + break; + } m_ptr = m_ptr.offset(-1); } @@ -249,6 +253,7 @@ fn test_unsized_nonnull() { #[test] #[allow(warnings)] +#[cfg(not(miri))] // Miri cannot hash pointers // Have a symbol for the test below. It doesn’t need to be an actual variadic function, match the // ABI, or even point to an actual executable code, because the function itself is never invoked. #[no_mangle] @@ -288,6 +293,7 @@ fn write_unaligned_drop() { } #[test] +#[cfg(not(miri))] // Miri cannot compute actual alignment of an allocation fn align_offset_zst() { // For pointers of stride = 0, the pointer is already aligned or it cannot be aligned at // all, because no amount of elements will align the pointer. @@ -302,6 +308,7 @@ fn align_offset_zst() { } #[test] +#[cfg(not(miri))] // Miri cannot compute actual alignment of an allocation fn align_offset_stride1() { // For pointers of stride = 1, the pointer can always be aligned. The offset is equal to // number of bytes. @@ -318,6 +325,7 @@ fn align_offset_stride1() { } #[test] +#[cfg(not(miri))] // Miri is too slow fn align_offset_weird_strides() { #[repr(packed)] struct A3(u16, u8); diff --git a/src/libcore/tests/result.rs b/src/libcore/tests/result.rs index 1fab07526a07f..bbc8568517667 100644 --- a/src/libcore/tests/result.rs +++ b/src/libcore/tests/result.rs @@ -117,6 +117,7 @@ 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." { @@ -138,6 +139,7 @@ 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"); @@ -151,6 +153,7 @@ 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 2c96efbda7673..31d16e0e32057 100644 --- a/src/libcore/tests/slice.rs +++ b/src/libcore/tests/slice.rs @@ -782,6 +782,7 @@ 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]); } @@ -791,6 +792,7 @@ 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]); } @@ -840,6 +842,7 @@ 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; @@ -848,6 +851,7 @@ 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; @@ -1011,6 +1015,7 @@ 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; @@ -1166,6 +1171,7 @@ pub mod memchr { } #[test] +#[cfg(not(miri))] // Miri cannot compute actual alignment of an allocation fn test_align_to_simple() { let bytes = [1u8, 2, 3, 4, 5, 6, 7]; let (prefix, aligned, suffix) = unsafe { bytes.align_to::() }; @@ -1189,6 +1195,7 @@ fn test_align_to_zst() { } #[test] +#[cfg(not(miri))] // Miri cannot compute actual alignment of an allocation fn test_align_to_non_trivial() { #[repr(align(8))] struct U64(u64, u64); #[repr(align(8))] struct U64U64U32(u64, u64, u32); @@ -1297,6 +1304,7 @@ fn test_copy_within() { #[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. @@ -1305,6 +1313,7 @@ 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. @@ -1312,8 +1321,24 @@ 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] +fn test_is_sorted() { + let empty: [i32; 0] = []; + + assert!([1, 2, 2, 9].is_sorted()); + assert!(![1, 3, 2].is_sorted()); + assert!([0].is_sorted()); + assert!(empty.is_sorted()); + assert!(![0.0, 1.0, std::f32::NAN].is_sorted()); + assert!([-2, -1, 0, 3].is_sorted()); + assert!(![-2i32, -1, 0, 3].is_sorted_by_key(|n| n.abs())); + assert!(!["c", "bb", "aaa"].is_sorted()); + assert!(["c", "bb", "aaa"].is_sorted_by_key(|s| s.len())); +} diff --git a/src/libcore/tests/time.rs b/src/libcore/tests/time.rs index 6efd22572dc18..09aae4583482f 100644 --- a/src/libcore/tests/time.rs +++ b/src/libcore/tests/time.rs @@ -107,12 +107,14 @@ 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/time.rs b/src/libcore/time.rs index a751965dffab3..ac7e11754aa3a 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -43,7 +43,7 @@ pub const NANOSECOND: Duration = Duration::from_nanos(1); /// timeouts. /// /// Each `Duration` is composed of a whole number of seconds and a fractional part -/// represented in nanoseconds. If the underlying system does not support +/// represented in nanoseconds. If the underlying system does not support /// nanosecond-level precision, APIs binding a system timeout will typically round up /// the number of nanoseconds. /// @@ -515,7 +515,7 @@ impl Duration { } } - /// Multiply `Duration` by `f64`. + /// Multiplies `Duration` by `f64`. /// /// # Panics /// This method will panic if result is not finite, negative or overflows `Duration`. diff --git a/src/libfmt_macros/Cargo.toml b/src/libfmt_macros/Cargo.toml index b3f4d2deae2fc..50779a2d9ad08 100644 --- a/src/libfmt_macros/Cargo.toml +++ b/src/libfmt_macros/Cargo.toml @@ -2,6 +2,7 @@ authors = ["The Rust Project Developers"] name = "fmt_macros" version = "0.0.0" +edition = "2018" [lib] name = "fmt_macros" diff --git a/src/libfmt_macros/lib.rs b/src/libfmt_macros/lib.rs index 32ae878909f30..aacd6cec565a5 100644 --- a/src/libfmt_macros/lib.rs +++ b/src/libfmt_macros/lib.rs @@ -4,19 +4,20 @@ //! Parsing does not happen at runtime: structures of `std::fmt::rt` are //! generated instead. -#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", - html_favicon_url = "https://doc.rust-lang.org/favicon.ico", - html_root_url = "https://doc.rust-lang.org/nightly/", +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/", html_playground_url = "https://play.rust-lang.org/", test(attr(deny(warnings))))] +#![deny(rust_2018_idioms)] + #![feature(nll)] +#![feature(rustc_private)] -pub use self::Piece::*; -pub use self::Position::*; -pub use self::Alignment::*; -pub use self::Flag::*; -pub use self::Count::*; +pub use Piece::*; +pub use Position::*; +pub use Alignment::*; +pub use Flag::*; +pub use Count::*; use std::str; use std::string; @@ -72,6 +73,15 @@ pub enum Position<'a> { ArgumentNamed(&'a str), } +impl Position<'_> { + pub fn index(&self) -> Option { + match self { + ArgumentIs(i) | ArgumentImplicitlyIs(i) => Some(*i), + _ => None, + } + } +} + /// Enum of alignments which are supported. #[derive(Copy, Clone, PartialEq)] pub enum Alignment { diff --git a/src/libgraphviz/Cargo.toml b/src/libgraphviz/Cargo.toml index 76ef3a1d188ce..a6a3c1a249d64 100644 --- a/src/libgraphviz/Cargo.toml +++ b/src/libgraphviz/Cargo.toml @@ -2,6 +2,7 @@ authors = ["The Rust Project Developers"] name = "graphviz" version = "0.0.0" +edition = "2018" [lib] name = "graphviz" diff --git a/src/libgraphviz/lib.rs b/src/libgraphviz/lib.rs index 164dec97b8fdb..489020d4ee778 100644 --- a/src/libgraphviz/lib.rs +++ b/src/libgraphviz/lib.rs @@ -271,15 +271,14 @@ //! //! * [DOT language](http://www.graphviz.org/doc/info/lang.html) -#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", - html_favicon_url = "https://doc.rust-lang.org/favicon.ico", - html_root_url = "https://doc.rust-lang.org/nightly/", +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/", test(attr(allow(unused_variables), deny(warnings))))] +#![deny(rust_2018_idioms)] + #![feature(nll)] -#![feature(str_escape)] -use self::LabelText::*; +use LabelText::*; use std::borrow::Cow; use std::io::prelude::*; @@ -393,7 +392,7 @@ impl<'a> Id<'a> { /// digit (i.e., the regular expression `[a-zA-Z_][a-zA-Z_0-9]*`). /// /// (Note: this format is a strict subset of the `ID` format - /// defined by the DOT language. This function may change in the + /// defined by the DOT language. This function may change in the /// future to accept a broader subset, or the entirety, of DOT's /// `ID` format.) /// @@ -530,7 +529,7 @@ impl<'a> LabelText<'a> { } /// Decomposes content into string suitable for making EscStr that - /// yields same content as self. The result obeys the law + /// yields same content as self. The result obeys the law /// render(`lt`) == render(`EscStr(lt.pre_escaped_content())`) for /// all `lt: LabelText`. fn pre_escaped_content(self) -> Cow<'a, str> { @@ -538,7 +537,7 @@ impl<'a> LabelText<'a> { EscStr(s) => s, LabelStr(s) => { if s.contains('\\') { - (&*s).escape_default().into() + (&*s).escape_default().to_string().into() } else { s } @@ -548,12 +547,12 @@ impl<'a> LabelText<'a> { } /// Puts `prefix` on a line above this label, with a blank line separator. - pub fn prefix_line(self, prefix: LabelText) -> LabelText<'static> { + pub fn prefix_line(self, prefix: LabelText<'_>) -> LabelText<'static> { prefix.suffix_line(self) } /// Puts `suffix` on a line below this label, with a blank line separator. - pub fn suffix_line(self, suffix: LabelText) -> LabelText<'static> { + pub fn suffix_line(self, suffix: LabelText<'_>) -> LabelText<'static> { let mut prefix = self.pre_escaped_content().into_owned(); let suffix = suffix.pre_escaped_content(); prefix.push_str(r"\n\n"); @@ -686,7 +685,7 @@ pub fn render_opts<'a, N, E, G, W>(g: &'a G, #[cfg(test)] mod tests { - use self::NodeLabels::*; + use NodeLabels::*; use super::{Id, Labeller, Nodes, Edges, GraphWalk, render, Style}; use super::LabelText::{self, LabelStr, EscStr, HtmlStr}; use std::io; diff --git a/src/libpanic_abort/Cargo.toml b/src/libpanic_abort/Cargo.toml index e304e61c32936..2bee0b716c750 100644 --- a/src/libpanic_abort/Cargo.toml +++ b/src/libpanic_abort/Cargo.toml @@ -2,6 +2,7 @@ authors = ["The Rust Project Developers"] name = "panic_abort" version = "0.0.0" +edition = "2018" [lib] path = "lib.rs" diff --git a/src/libpanic_abort/lib.rs b/src/libpanic_abort/lib.rs index 8832a16d4ca4e..edc97cd28a52a 100644 --- a/src/libpanic_abort/lib.rs +++ b/src/libpanic_abort/lib.rs @@ -5,14 +5,13 @@ #![no_std] #![unstable(feature = "panic_abort", issue = "32837")] -#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", - html_favicon_url = "https://doc.rust-lang.org/favicon.ico", - html_root_url = "https://doc.rust-lang.org/nightly/", +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/", issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/")] #![panic_runtime] + #![allow(unused_features)] +#![deny(rust_2018_idioms)] -#![cfg_attr(stage0, feature(cfg_target_vendor))] #![feature(core_intrinsics)] #![feature(libc)] #![feature(nll)] @@ -47,7 +46,6 @@ pub unsafe extern fn __rust_start_panic(_payload: usize) -> u32 { #[cfg(any(unix, target_os = "cloudabi"))] unsafe fn abort() -> ! { - extern crate libc; libc::abort(); } diff --git a/src/libpanic_unwind/Cargo.toml b/src/libpanic_unwind/Cargo.toml index c9fce621608a2..1b3901ac11a96 100644 --- a/src/libpanic_unwind/Cargo.toml +++ b/src/libpanic_unwind/Cargo.toml @@ -2,6 +2,7 @@ authors = ["The Rust Project Developers"] name = "panic_unwind" version = "0.0.0" +edition = "2018" [lib] path = "lib.rs" diff --git a/src/libpanic_unwind/dummy.rs b/src/libpanic_unwind/dummy.rs index b052f76e2a3a8..3a00d6376658c 100644 --- a/src/libpanic_unwind/dummy.rs +++ b/src/libpanic_unwind/dummy.rs @@ -1,6 +1,6 @@ -//! Unwinding for wasm32 +//! Unwinding for *wasm32* target. //! -//! Right now we don't support this, so this is just stubs +//! Right now we don't support this, so this is just stubs. use alloc::boxed::Box; use core::any::Any; diff --git a/src/libpanic_unwind/dwarf/eh.rs b/src/libpanic_unwind/dwarf/eh.rs index ce7fab8584a28..07fa2971847f6 100644 --- a/src/libpanic_unwind/dwarf/eh.rs +++ b/src/libpanic_unwind/dwarf/eh.rs @@ -6,12 +6,12 @@ //! http://www.airs.com/blog/archives/464 //! //! A reference implementation may be found in the GCC source tree -//! (/libgcc/unwind-c.c as of this writing) +//! (`/libgcc/unwind-c.c` as of this writing). #![allow(non_upper_case_globals)] #![allow(unused)] -use dwarf::DwarfReader; +use crate::dwarf::DwarfReader; use core::mem; pub const DW_EH_PE_omit: u8 = 0xFF; @@ -51,7 +51,7 @@ pub enum EHAction { pub const USING_SJLJ_EXCEPTIONS: bool = cfg!(all(target_os = "ios", target_arch = "arm")); -pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext) +pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext<'_>) -> Result { if lsda.is_null() { @@ -145,7 +145,7 @@ fn round_up(unrounded: usize, align: usize) -> Result { } unsafe fn read_encoded_pointer(reader: &mut DwarfReader, - context: &EHContext, + context: &EHContext<'_>, encoding: u8) -> Result { if encoding == DW_EH_PE_omit { diff --git a/src/libpanic_unwind/dwarf/mod.rs b/src/libpanic_unwind/dwarf/mod.rs index eb5fb81f61b83..0360696426dc9 100644 --- a/src/libpanic_unwind/dwarf/mod.rs +++ b/src/libpanic_unwind/dwarf/mod.rs @@ -1,5 +1,5 @@ //! Utilities for parsing DWARF-encoded data streams. -//! See http://www.dwarfstd.org, +//! See , //! DWARF-4 standard, Section 7 - "Data Representation" // This module is used only by x86_64-pc-windows-gnu for now, but we diff --git a/src/libpanic_unwind/emcc.rs b/src/libpanic_unwind/emcc.rs index 45c9244a46fcd..18e9006468ef3 100644 --- a/src/libpanic_unwind/emcc.rs +++ b/src/libpanic_unwind/emcc.rs @@ -1,19 +1,19 @@ -//! Unwinding for emscripten +//! Unwinding for *emscripten* target. //! //! Whereas Rust's usual unwinding implementation for Unix platforms -//! calls into the libunwind APIs directly, on emscripten we instead +//! calls into the libunwind APIs directly, on Emscripten we instead //! call into the C++ unwinding APIs. This is just an expedience since -//! emscripten's runtime always implements those APIs and does not +//! Emscripten's runtime always implements those APIs and does not //! implement libunwind. #![allow(private_no_mangle_fns)] use core::any::Any; use core::ptr; +use core::mem; use alloc::boxed::Box; use libc::{self, c_int}; use unwind as uw; -use core::mem; pub fn payload() -> *mut u8 { ptr::null_mut() diff --git a/src/libpanic_unwind/gcc.rs b/src/libpanic_unwind/gcc.rs index 065403aba1b98..e2b743b379704 100644 --- a/src/libpanic_unwind/gcc.rs +++ b/src/libpanic_unwind/gcc.rs @@ -1,4 +1,4 @@ -//! Implementation of panics backed by libgcc/libunwind (in some form) +//! Implementation of panics backed by libgcc/libunwind (in some form). //! //! For background on exception handling and stack unwinding please see //! "Exception Handling in LLVM" (llvm.org/docs/ExceptionHandling.html) and @@ -23,14 +23,14 @@ //! //! In the search phase, the job of a personality routine is to examine //! exception object being thrown, and to decide whether it should be caught at -//! that stack frame. Once the handler frame has been identified, cleanup phase +//! that stack frame. Once the handler frame has been identified, cleanup phase //! begins. //! //! In the cleanup phase, the unwinder invokes each personality routine again. //! This time it decides which (if any) cleanup code needs to be run for -//! the current stack frame. If so, the control is transferred to a special +//! the current stack frame. If so, the control is transferred to a special //! branch in the function body, the "landing pad", which invokes destructors, -//! frees memory, etc. At the end of the landing pad, control is transferred +//! frees memory, etc. At the end of the landing pad, control is transferred //! back to the unwinder and unwinding resumes. //! //! Once stack has been unwound down to the handler frame level, unwinding stops @@ -39,7 +39,7 @@ //! ## `eh_personality` and `eh_unwind_resume` //! //! These language items are used by the compiler when generating unwind info. -//! The first one is the personality routine described above. The second one +//! The first one is the personality routine described above. The second one //! allows compilation target to customize the process of resuming unwind at the //! end of the landing pads. `eh_unwind_resume` is used only if //! `custom_unwind_resume` flag in the target options is set. @@ -52,7 +52,7 @@ use alloc::boxed::Box; use unwind as uw; use libc::{c_int, uintptr_t}; -use dwarf::eh::{self, EHContext, EHAction}; +use crate::dwarf::eh::{self, EHContext, EHAction}; #[repr(C)] struct Exception { diff --git a/src/libpanic_unwind/lib.rs b/src/libpanic_unwind/lib.rs index 98f174710d243..9d3d8f6185bb3 100644 --- a/src/libpanic_unwind/lib.rs +++ b/src/libpanic_unwind/lib.rs @@ -14,11 +14,11 @@ #![no_std] #![unstable(feature = "panic_unwind", issue = "32837")] -#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", - html_favicon_url = "https://doc.rust-lang.org/favicon.ico", - html_root_url = "https://doc.rust-lang.org/nightly/", +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/", issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/")] +#![deny(rust_2018_idioms)] + #![feature(allocator_api)] #![feature(alloc)] #![feature(core_intrinsics)] @@ -34,11 +34,6 @@ #![panic_runtime] #![feature(panic_runtime)] -extern crate alloc; -extern crate libc; -#[cfg(not(any(target_env = "msvc", all(windows, target_arch = "x86_64", target_env = "gnu"))))] -extern crate unwind; - use alloc::boxed::Box; use core::intrinsics; use core::mem; @@ -89,7 +84,7 @@ pub unsafe extern "C" fn __rust_maybe_catch_panic(f: fn(*mut u8), vtable_ptr: *mut usize) -> u32 { let mut payload = imp::payload(); - if intrinsics::try(f, data, &mut payload as *mut _ as *mut _) == 0 { + if intrinsics::r#try(f, data, &mut payload as *mut _ as *mut _) == 0 { 0 } else { let obj = mem::transmute::<_, raw::TraitObject>(imp::cleanup(payload)); diff --git a/src/libpanic_unwind/seh.rs b/src/libpanic_unwind/seh.rs index f52d010815c5d..996fdb931eff2 100644 --- a/src/libpanic_unwind/seh.rs +++ b/src/libpanic_unwind/seh.rs @@ -52,7 +52,7 @@ use core::any::Any; use core::mem; use core::raw; -use windows as c; +use crate::windows as c; use libc::{c_int, c_uint}; // First up, a whole bunch of type definitions. There's a few platform-specific @@ -301,5 +301,5 @@ pub unsafe fn cleanup(payload: [u64; 2]) -> Box { #[lang = "eh_personality"] #[cfg(not(test))] fn rust_eh_personality() { - unsafe { ::core::intrinsics::abort() } + unsafe { core::intrinsics::abort() } } diff --git a/src/libpanic_unwind/seh64_gnu.rs b/src/libpanic_unwind/seh64_gnu.rs index 56ff6082190bc..457ffcd34f9c7 100644 --- a/src/libpanic_unwind/seh64_gnu.rs +++ b/src/libpanic_unwind/seh64_gnu.rs @@ -9,8 +9,8 @@ use alloc::boxed::Box; use core::any::Any; use core::intrinsics; use core::ptr; -use dwarf::eh::{EHContext, EHAction, find_eh_action}; -use windows as c; +use crate::dwarf::eh::{EHContext, EHAction, find_eh_action}; +use crate::windows as c; // Define our exception codes: // according to http://msdn.microsoft.com/en-us/library/het71c37(v=VS.80).aspx, diff --git a/src/libproc_macro/Cargo.toml b/src/libproc_macro/Cargo.toml index f903f79f9afc0..b3d0ee94f0e12 100644 --- a/src/libproc_macro/Cargo.toml +++ b/src/libproc_macro/Cargo.toml @@ -2,6 +2,7 @@ authors = ["The Rust Project Developers"] name = "proc_macro" version = "0.0.0" +edition = "2018" [lib] path = "lib.rs" diff --git a/src/libproc_macro/bridge/buffer.rs b/src/libproc_macro/bridge/buffer.rs index 8bc4f0fec85a8..0d8cc552d61ab 100644 --- a/src/libproc_macro/bridge/buffer.rs +++ b/src/libproc_macro/bridge/buffer.rs @@ -6,7 +6,7 @@ use std::ops::{Deref, DerefMut}; use std::slice; #[repr(C)] -struct Slice<'a, T: 'a> { +struct Slice<'a, T> { data: &'a [T; 0], len: usize, } @@ -42,7 +42,7 @@ pub struct Buffer { data: *mut T, len: usize, capacity: usize, - extend_from_slice: extern "C" fn(Buffer, Slice) -> Buffer, + extend_from_slice: extern "C" fn(Buffer, Slice<'_, T>) -> Buffer, drop: extern "C" fn(Buffer), } @@ -139,7 +139,7 @@ impl From> for Buffer { } } - extern "C" fn extend_from_slice(b: Buffer, xs: Slice) -> Buffer { + extern "C" fn extend_from_slice(b: Buffer, xs: Slice<'_, T>) -> Buffer { let mut v = to_vec(b); v.extend_from_slice(&xs); Buffer::from(v) diff --git a/src/libproc_macro/bridge/client.rs b/src/libproc_macro/bridge/client.rs index 3095c8041f2c1..b198bdb144699 100644 --- a/src/libproc_macro/bridge/client.rs +++ b/src/libproc_macro/bridge/client.rs @@ -66,7 +66,7 @@ macro_rules! define_handles { impl DecodeMut<'_, '_, HandleStore>> for Marked { - fn decode(r: &mut Reader, s: &mut HandleStore>) -> Self { + fn decode(r: &mut Reader<'_>, s: &mut HandleStore>) -> Self { s.$oty.take(handle::Handle::decode(r, &mut ())) } } @@ -80,7 +80,7 @@ macro_rules! define_handles { impl Decode<'_, 's, HandleStore>> for &'s Marked { - fn decode(r: &mut Reader, s: &'s HandleStore>) -> Self { + fn decode(r: &mut Reader<'_>, s: &'s HandleStore>) -> Self { &s.$oty[handle::Handle::decode(r, &mut ())] } } @@ -94,7 +94,10 @@ macro_rules! define_handles { impl DecodeMut<'_, 's, HandleStore>> for &'s mut Marked { - fn decode(r: &mut Reader, s: &'s mut HandleStore>) -> Self { + fn decode( + r: &mut Reader<'_>, + s: &'s mut HandleStore> + ) -> Self { &mut s.$oty[handle::Handle::decode(r, &mut ())] } } @@ -108,7 +111,7 @@ macro_rules! define_handles { } impl DecodeMut<'_, '_, S> for $oty { - fn decode(r: &mut Reader, s: &mut S) -> Self { + fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { $oty(handle::Handle::decode(r, s)) } } @@ -130,7 +133,7 @@ macro_rules! define_handles { impl DecodeMut<'_, '_, HandleStore>> for Marked { - fn decode(r: &mut Reader, s: &mut HandleStore>) -> Self { + fn decode(r: &mut Reader<'_>, s: &mut HandleStore>) -> Self { s.$ity.copy(handle::Handle::decode(r, &mut ())) } } @@ -144,7 +147,7 @@ macro_rules! define_handles { } impl DecodeMut<'_, '_, S> for $ity { - fn decode(r: &mut Reader, s: &mut S) -> Self { + fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { $ity(handle::Handle::decode(r, s)) } } @@ -200,7 +203,7 @@ impl Clone for Literal { // FIXME(eddyb) `Literal` should not expose internal `Debug` impls. impl fmt::Debug for Literal { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(&self.debug()) } } @@ -212,7 +215,7 @@ impl Clone for SourceFile { } impl fmt::Debug for Span { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(&self.debug()) } } @@ -275,7 +278,7 @@ impl BridgeState<'_> { /// /// N.B., while `f` is running, the thread-local state /// is `BridgeState::InUse`. - fn with(f: impl FnOnce(&mut BridgeState) -> R) -> R { + fn with(f: impl FnOnce(&mut BridgeState<'_>) -> R) -> R { BRIDGE_STATE.with(|state| { state.replace(BridgeState::InUse, |mut state| { // FIXME(#52812) pass `f` directly to `replace` when `RefMutL` is gone @@ -306,7 +309,7 @@ impl Bridge<'_> { BRIDGE_STATE.with(|state| state.set(BridgeState::Connected(self), f)) } - fn with(f: impl FnOnce(&mut Bridge) -> R) -> R { + fn with(f: impl FnOnce(&mut Bridge<'_>) -> R) -> R { BridgeState::with(|state| match state { BridgeState::NotConnected => { panic!("procedural macro API is used outside of a procedural macro"); @@ -331,15 +334,15 @@ impl Bridge<'_> { #[derive(Copy, Clone)] pub struct Client { pub(super) get_handle_counters: extern "C" fn() -> &'static HandleCounters, - pub(super) run: extern "C" fn(Bridge, F) -> Buffer, + pub(super) run: extern "C" fn(Bridge<'_>, F) -> Buffer, pub(super) f: F, } // FIXME(#53451) public to work around `Cannot create local mono-item` ICE, // affecting not only the function itself, but also the `BridgeState` `thread_local!`. pub extern "C" fn __run_expand1( - mut bridge: Bridge, - f: fn(::TokenStream) -> ::TokenStream, + mut bridge: Bridge<'_>, + f: fn(crate::TokenStream) -> crate::TokenStream, ) -> Buffer { // The initial `cached_buffer` contains the input. let mut b = bridge.cached_buffer.take(); @@ -352,7 +355,7 @@ pub extern "C" fn __run_expand1( // Put the `cached_buffer` back in the `Bridge`, for requests. Bridge::with(|bridge| bridge.cached_buffer = b.take()); - let output = f(::TokenStream(input)).0; + let output = f(crate::TokenStream(input)).0; // Take the `cached_buffer` back out, for the output value. b = Bridge::with(|bridge| bridge.cached_buffer.take()); @@ -378,8 +381,8 @@ pub extern "C" fn __run_expand1( b } -impl Client ::TokenStream> { - pub const fn expand1(f: fn(::TokenStream) -> ::TokenStream) -> Self { +impl Client crate::TokenStream> { + pub const fn expand1(f: fn(crate::TokenStream) -> crate::TokenStream) -> Self { Client { get_handle_counters: HandleCounters::get, run: __run_expand1, @@ -391,8 +394,8 @@ impl Client ::TokenStream> { // FIXME(#53451) public to work around `Cannot create local mono-item` ICE, // affecting not only the function itself, but also the `BridgeState` `thread_local!`. pub extern "C" fn __run_expand2( - mut bridge: Bridge, - f: fn(::TokenStream, ::TokenStream) -> ::TokenStream, + mut bridge: Bridge<'_>, + f: fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream, ) -> Buffer { // The initial `cached_buffer` contains the input. let mut b = bridge.cached_buffer.take(); @@ -406,7 +409,7 @@ pub extern "C" fn __run_expand2( // Put the `cached_buffer` back in the `Bridge`, for requests. Bridge::with(|bridge| bridge.cached_buffer = b.take()); - let output = f(::TokenStream(input), ::TokenStream(input2)).0; + let output = f(crate::TokenStream(input), crate::TokenStream(input2)).0; // Take the `cached_buffer` back out, for the output value. b = Bridge::with(|bridge| bridge.cached_buffer.take()); @@ -432,8 +435,10 @@ pub extern "C" fn __run_expand2( b } -impl Client ::TokenStream> { - pub const fn expand2(f: fn(::TokenStream, ::TokenStream) -> ::TokenStream) -> Self { +impl Client crate::TokenStream> { + pub const fn expand2( + f: fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream + ) -> Self { Client { get_handle_counters: HandleCounters::get, run: __run_expand2, @@ -448,17 +453,17 @@ pub enum ProcMacro { CustomDerive { trait_name: &'static str, attributes: &'static [&'static str], - client: Client ::TokenStream>, + client: Client crate::TokenStream>, }, Attr { name: &'static str, - client: Client ::TokenStream>, + client: Client crate::TokenStream>, }, Bang { name: &'static str, - client: Client ::TokenStream>, + client: Client crate::TokenStream>, }, } @@ -466,7 +471,7 @@ impl ProcMacro { pub const fn custom_derive( trait_name: &'static str, attributes: &'static [&'static str], - expand: fn(::TokenStream) -> ::TokenStream, + expand: fn(crate::TokenStream) -> crate::TokenStream, ) -> Self { ProcMacro::CustomDerive { trait_name, @@ -477,7 +482,7 @@ impl ProcMacro { pub const fn attr( name: &'static str, - expand: fn(::TokenStream, ::TokenStream) -> ::TokenStream, + expand: fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream, ) -> Self { ProcMacro::Attr { name, @@ -485,7 +490,10 @@ impl ProcMacro { } } - pub const fn bang(name: &'static str, expand: fn(::TokenStream) -> ::TokenStream) -> Self { + pub const fn bang( + name: &'static str, + expand: fn(crate::TokenStream) -> crate::TokenStream + ) -> Self { ProcMacro::Bang { name, client: Client::expand1(expand), diff --git a/src/libproc_macro/bridge/mod.rs b/src/libproc_macro/bridge/mod.rs index 6c3e534bf9197..3173651b03951 100644 --- a/src/libproc_macro/bridge/mod.rs +++ b/src/libproc_macro/bridge/mod.rs @@ -17,7 +17,7 @@ use std::panic; use std::sync::atomic::AtomicUsize; use std::sync::Once; use std::thread; -use {Delimiter, Level, LineColumn, Spacing}; +use crate::{Delimiter, Level, LineColumn, Spacing}; /// Higher-order macro describing the server RPC API, allowing automatic /// generation of type-safe Rust APIs, both client-side and server-side. @@ -196,9 +196,9 @@ mod scoped_cell; #[forbid(unsafe_code)] pub mod server; -use self::buffer::Buffer; -pub use self::rpc::PanicMessage; -use self::rpc::{Decode, DecodeMut, Encode, Reader, Writer}; +use buffer::Buffer; +pub use rpc::PanicMessage; +use rpc::{Decode, DecodeMut, Encode, Reader, Writer}; /// An active connection between a server and a client. /// The server creates the bridge (`Bridge::run_server` in `server.rs`), diff --git a/src/libproc_macro/bridge/rpc.rs b/src/libproc_macro/bridge/rpc.rs index 74ae711a47372..a3bc0d2290846 100644 --- a/src/libproc_macro/bridge/rpc.rs +++ b/src/libproc_macro/bridge/rpc.rs @@ -40,7 +40,7 @@ macro_rules! rpc_encode_decode { } impl DecodeMut<'_, '_, S> for $ty { - fn decode(r: &mut Reader, s: &mut S) -> Self { + fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { let mut byte = 0x80; let mut v = 0; let mut shift = 0; @@ -61,7 +61,7 @@ macro_rules! rpc_encode_decode { } impl DecodeMut<'_, '_, S> for $name { - fn decode(r: &mut Reader, s: &mut S) -> Self { + fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { $name { $($field: DecodeMut::decode(r, s)),* } @@ -119,7 +119,7 @@ impl Encode for () { } impl DecodeMut<'_, '_, S> for () { - fn decode(_: &mut Reader, _: &mut S) -> Self {} + fn decode(_: &mut Reader<'_>, _: &mut S) -> Self {} } impl Encode for u8 { @@ -129,7 +129,7 @@ impl Encode for u8 { } impl DecodeMut<'_, '_, S> for u8 { - fn decode(r: &mut Reader, _: &mut S) -> Self { + fn decode(r: &mut Reader<'_>, _: &mut S) -> Self { let x = r[0]; *r = &r[1..]; x @@ -146,7 +146,7 @@ impl Encode for bool { } impl DecodeMut<'_, '_, S> for bool { - fn decode(r: &mut Reader, s: &mut S) -> Self { + fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { match u8::decode(r, s) { 0 => false, 1 => true, @@ -162,7 +162,7 @@ impl Encode for char { } impl DecodeMut<'_, '_, S> for char { - fn decode(r: &mut Reader, s: &mut S) -> Self { + fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { char::from_u32(u32::decode(r, s)).unwrap() } } @@ -174,7 +174,7 @@ impl Encode for NonZeroU32 { } impl DecodeMut<'_, '_, S> for NonZeroU32 { - fn decode(r: &mut Reader, s: &mut S) -> Self { + fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { Self::new(u32::decode(r, s)).unwrap() } } @@ -251,7 +251,7 @@ impl Encode for String { } impl DecodeMut<'_, '_, S> for String { - fn decode(r: &mut Reader, s: &mut S) -> Self { + fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { <&str>::decode(r, s).to_string() } } @@ -306,7 +306,7 @@ impl Encode for PanicMessage { } impl DecodeMut<'_, '_, S> for PanicMessage { - fn decode(r: &mut Reader, s: &mut S) -> Self { + fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { match Option::::decode(r, s) { Some(s) => PanicMessage::String(s), None => PanicMessage::Unknown, diff --git a/src/libproc_macro/bridge/scoped_cell.rs b/src/libproc_macro/bridge/scoped_cell.rs index b1ab27c153e06..6f7965095b638 100644 --- a/src/libproc_macro/bridge/scoped_cell.rs +++ b/src/libproc_macro/bridge/scoped_cell.rs @@ -38,7 +38,7 @@ impl ScopedCell { ScopedCell(Cell::new(value)) } - /// Set the value in `self` to `replacement` while + /// Sets the value in `self` to `replacement` while /// running `f`, which gets the old value, mutably. /// The old value will be restored after `f` exits, even /// by panic, including modifications made to it by `f`. @@ -73,7 +73,7 @@ impl ScopedCell { f(RefMutL(put_back_on_drop.value.as_mut().unwrap())) } - /// Set the value in `self` to `value` while running `f`. + /// Sets the value in `self` to `value` while running `f`. pub fn set<'a, R>(&self, value: >::Out, f: impl FnOnce() -> R) -> R { self.replace(value, |_| f()) } diff --git a/src/libproc_macro/bridge/server.rs b/src/libproc_macro/bridge/server.rs index 9a7cb1318dbe4..75806eb9d1760 100644 --- a/src/libproc_macro/bridge/server.rs +++ b/src/libproc_macro/bridge/server.rs @@ -131,7 +131,7 @@ pub trait ExecutionStrategy { &self, dispatcher: &mut impl DispatcherTrait, input: Buffer, - run_client: extern "C" fn(Bridge, D) -> Buffer, + run_client: extern "C" fn(Bridge<'_>, D) -> Buffer, client_data: D, ) -> Buffer; } @@ -143,7 +143,7 @@ impl ExecutionStrategy for SameThread { &self, dispatcher: &mut impl DispatcherTrait, input: Buffer, - run_client: extern "C" fn(Bridge, D) -> Buffer, + run_client: extern "C" fn(Bridge<'_>, D) -> Buffer, client_data: D, ) -> Buffer { let mut dispatch = |b| dispatcher.dispatch(b); @@ -168,7 +168,7 @@ impl ExecutionStrategy for CrossThread1 { &self, dispatcher: &mut impl DispatcherTrait, input: Buffer, - run_client: extern "C" fn(Bridge, D) -> Buffer, + run_client: extern "C" fn(Bridge<'_>, D) -> Buffer, client_data: D, ) -> Buffer { use std::sync::mpsc::channel; @@ -206,7 +206,7 @@ impl ExecutionStrategy for CrossThread2 { &self, dispatcher: &mut impl DispatcherTrait, input: Buffer, - run_client: extern "C" fn(Bridge, D) -> Buffer, + run_client: extern "C" fn(Bridge<'_>, D) -> Buffer, client_data: D, ) -> Buffer { use std::sync::{Arc, Mutex}; @@ -273,7 +273,7 @@ fn run_server< handle_counters: &'static client::HandleCounters, server: S, input: I, - run_client: extern "C" fn(Bridge, D) -> Buffer, + run_client: extern "C" fn(Bridge<'_>, D) -> Buffer, client_data: D, ) -> Result { let mut dispatcher = Dispatcher { @@ -289,7 +289,7 @@ fn run_server< Result::decode(&mut &b[..], &mut dispatcher.handle_store) } -impl client::Client ::TokenStream> { +impl client::Client crate::TokenStream> { pub fn run( &self, strategy: &impl ExecutionStrategy, @@ -313,7 +313,7 @@ impl client::Client ::TokenStream> { } } -impl client::Client ::TokenStream> { +impl client::Client crate::TokenStream> { pub fn run( &self, strategy: &impl ExecutionStrategy, diff --git a/src/libproc_macro/diagnostic.rs b/src/libproc_macro/diagnostic.rs index 64d0c3893c730..65eebb5ec3737 100644 --- a/src/libproc_macro/diagnostic.rs +++ b/src/libproc_macro/diagnostic.rs @@ -1,4 +1,4 @@ -use Span; +use crate::Span; /// An enum representing a diagnostic level. #[unstable(feature = "proc_macro_diagnostic", issue = "54140")] @@ -56,7 +56,7 @@ pub struct Diagnostic { macro_rules! diagnostic_child_methods { ($spanned:ident, $regular:ident, $level:expr) => ( - /// Add a new child diagnostic message to `self` with the level + /// Adds a new child diagnostic message to `self` with the level /// identified by this method's name with the given `spans` and /// `message`. #[unstable(feature = "proc_macro_diagnostic", issue = "54140")] @@ -67,7 +67,7 @@ macro_rules! diagnostic_child_methods { self } - /// Add a new child diagnostic message to `self` with the level + /// Adds a new child diagnostic message to `self` with the level /// identified by this method's name with the given `message`. #[unstable(feature = "proc_macro_diagnostic", issue = "54140")] pub fn $regular>(mut self, message: T) -> Diagnostic { @@ -80,7 +80,7 @@ macro_rules! diagnostic_child_methods { /// Iterator over the children diagnostics of a `Diagnostic`. #[derive(Debug, Clone)] #[unstable(feature = "proc_macro_diagnostic", issue = "54140")] -pub struct Children<'a>(::std::slice::Iter<'a, Diagnostic>); +pub struct Children<'a>(std::slice::Iter<'a, Diagnostic>); #[unstable(feature = "proc_macro_diagnostic", issue = "54140")] impl<'a> Iterator for Children<'a> { @@ -93,7 +93,7 @@ impl<'a> Iterator for Children<'a> { #[unstable(feature = "proc_macro_diagnostic", issue = "54140")] impl Diagnostic { - /// Create a new diagnostic with the given `level` and `message`. + /// Creates a new diagnostic with the given `level` and `message`. #[unstable(feature = "proc_macro_diagnostic", issue = "54140")] pub fn new>(level: Level, message: T) -> Diagnostic { Diagnostic { @@ -104,7 +104,7 @@ impl Diagnostic { } } - /// Create a new diagnostic with the given `level` and `message` pointing to + /// Creates a new diagnostic with the given `level` and `message` pointing to /// the given set of `spans`. #[unstable(feature = "proc_macro_diagnostic", issue = "54140")] pub fn spanned(spans: S, level: Level, message: T) -> Diagnostic @@ -161,22 +161,22 @@ impl Diagnostic { /// Returns an iterator over the children diagnostics of `self`. #[unstable(feature = "proc_macro_diagnostic", issue = "54140")] - pub fn children(&self) -> Children { + pub fn children(&self) -> Children<'_> { Children(self.children.iter()) } /// Emit the diagnostic. #[unstable(feature = "proc_macro_diagnostic", issue = "54140")] pub fn emit(self) { - fn to_internal(spans: Vec) -> ::bridge::client::MultiSpan { - let mut multi_span = ::bridge::client::MultiSpan::new(); + fn to_internal(spans: Vec) -> crate::bridge::client::MultiSpan { + let mut multi_span = crate::bridge::client::MultiSpan::new(); for span in spans { multi_span.push(span.0); } multi_span } - let mut diag = ::bridge::client::Diagnostic::new( + let mut diag = crate::bridge::client::Diagnostic::new( self.level, &self.message[..], to_internal(self.spans), diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs index 868190d01057d..6c061189d00d7 100644 --- a/src/libproc_macro/lib.rs +++ b/src/libproc_macro/lib.rs @@ -5,18 +5,20 @@ //! function-like macros `#[proc_macro]`, macro attributes `#[proc_macro_attribute]` and //! custom derive attributes`#[proc_macro_derive]`. //! -//! See [the book](../book/first-edition/procedural-macros.html) for more. +//! See [the book] for more. +//! +//! [the book]: ../book/ch19-06-macros.html#procedural-macros-for-generating-code-from-attributes #![stable(feature = "proc_macro_lib", since = "1.15.0")] #![deny(missing_docs)] -#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", - html_favicon_url = "https://doc.rust-lang.org/favicon.ico", - html_root_url = "https://doc.rust-lang.org/nightly/", +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/", html_playground_url = "https://play.rust-lang.org/", issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/", test(no_crate_inject, attr(deny(warnings))), test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))))] +#![deny(rust_2018_idioms)] + #![feature(nll)] #![feature(staged_api)] #![feature(const_fn)] @@ -89,7 +91,7 @@ impl TokenStream { /// or characters not existing in the language. /// All tokens in the parsed stream get `Span::call_site()` spans. /// -/// NOTE: Some errors may cause panics instead of returning `LexError`. We reserve the right to +/// NOTE: some errors may cause panics instead of returning `LexError`. We reserve the right to /// change these errors into `LexError`s later. #[stable(feature = "proc_macro_lib", since = "1.15.0")] impl FromStr for TokenStream { @@ -114,7 +116,7 @@ impl ToString for TokenStream { /// with `Delimiter::None` delimiters and negative numeric literals. #[stable(feature = "proc_macro_lib", since = "1.15.0")] impl fmt::Display for TokenStream { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(&self.to_string()) } } @@ -122,7 +124,7 @@ impl fmt::Display for TokenStream { /// Prints token in a form convenient for debugging. #[stable(feature = "proc_macro_lib", since = "1.15.0")] impl fmt::Debug for TokenStream { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("TokenStream ")?; f.debug_list().entries(self.clone()).finish() } @@ -183,7 +185,7 @@ impl Extend for TokenStream { /// Public implementation details for the `TokenStream` type, such as iterators. #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub mod token_stream { - use {bridge, Group, Ident, Literal, Punct, TokenTree, TokenStream}; + use crate::{bridge, Group, Ident, Literal, Punct, TokenTree, TokenStream}; /// An iterator over `TokenStream`'s `TokenTree`s. /// The iteration is "shallow", e.g., the iterator doesn't recurse into delimited groups, @@ -245,7 +247,7 @@ impl !Sync for Span {} macro_rules! diagnostic_method { ($name:ident, $level:expr) => ( - /// Create a new `Diagnostic` with the given `message` at the span + /// Creates a new `Diagnostic` with the given `message` at the span /// `self`. #[unstable(feature = "proc_macro_diagnostic", issue = "54140")] pub fn $name>(self, message: T) -> Diagnostic { @@ -291,19 +293,19 @@ impl Span { Span(self.0.source()) } - /// Get the starting line/column in the source file for this span. + /// Gets the starting line/column in the source file for this span. #[unstable(feature = "proc_macro_span", issue = "54725")] pub fn start(&self) -> LineColumn { self.0.start() } - /// Get the ending line/column in the source file for this span. + /// Gets the ending line/column in the source file for this span. #[unstable(feature = "proc_macro_span", issue = "54725")] pub fn end(&self) -> LineColumn { self.0.end() } - /// Create a new span encompassing `self` and `other`. + /// Creates a new span encompassing `self` and `other`. /// /// Returns `None` if `self` and `other` are from different files. #[unstable(feature = "proc_macro_span", issue = "54725")] @@ -340,7 +342,7 @@ impl Span { /// Prints a span in a form convenient for debugging. #[stable(feature = "proc_macro_lib2", since = "1.29.0")] impl fmt::Debug for Span { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) } } @@ -369,7 +371,7 @@ impl !Sync for LineColumn {} pub struct SourceFile(bridge::client::SourceFile); impl SourceFile { - /// Get the path to this source file. + /// Gets the path to this source file. /// /// ### Note /// If the code span associated with this `SourceFile` was generated by an external macro, this @@ -398,7 +400,7 @@ impl SourceFile { #[unstable(feature = "proc_macro_span", issue = "54725")] impl fmt::Debug for SourceFile { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("SourceFile") .field("path", &self.path()) .field("is_real", &self.is_real()) @@ -483,7 +485,7 @@ impl TokenTree { /// Prints token tree in a form convenient for debugging. #[stable(feature = "proc_macro_lib2", since = "1.29.0")] impl fmt::Debug for TokenTree { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // Each of these has the name in the struct type in the derived debug, // so don't bother with an extra layer of indirection match *self { @@ -542,7 +544,7 @@ impl ToString for TokenTree { /// with `Delimiter::None` delimiters and negative numeric literals. #[stable(feature = "proc_macro_lib2", since = "1.29.0")] impl fmt::Display for TokenTree { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(&self.to_string()) } } @@ -667,14 +669,14 @@ impl ToString for Group { /// with `Delimiter::None` delimiters. #[stable(feature = "proc_macro_lib2", since = "1.29.0")] impl fmt::Display for Group { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(&self.to_string()) } } #[stable(feature = "proc_macro_lib2", since = "1.29.0")] impl fmt::Debug for Group { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Group") .field("delimiter", &self.delimiter()) .field("stream", &self.stream()) @@ -763,14 +765,14 @@ impl ToString for Punct { /// back into the same character. #[stable(feature = "proc_macro_lib2", since = "1.29.0")] impl fmt::Display for Punct { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(&self.to_string()) } } #[stable(feature = "proc_macro_lib2", since = "1.29.0")] impl fmt::Debug for Punct { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Punct") .field("ch", &self.as_char()) .field("spacing", &self.spacing()) @@ -842,14 +844,14 @@ impl ToString for Ident { /// back into the same identifier. #[stable(feature = "proc_macro_lib2", since = "1.29.0")] impl fmt::Display for Ident { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(&self.to_string()) } } #[stable(feature = "proc_macro_lib2", since = "1.29.0")] impl fmt::Debug for Ident { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Ident") .field("ident", &self.to_string()) .field("span", &self.span()) @@ -1092,14 +1094,14 @@ impl ToString for Literal { /// back into the same literal (except for possible rounding for floating point literals). #[stable(feature = "proc_macro_lib2", since = "1.29.0")] impl fmt::Display for Literal { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(&self.to_string()) } } #[stable(feature = "proc_macro_lib2", since = "1.29.0")] impl fmt::Debug for Literal { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // FIXME(eddyb) `Literal` should not expose internal `Debug` impls. self.0.fmt(f) } diff --git a/src/libproc_macro/quote.rs b/src/libproc_macro/quote.rs index bd7e96210a950..e3d31b78f4a09 100644 --- a/src/libproc_macro/quote.rs +++ b/src/libproc_macro/quote.rs @@ -4,7 +4,7 @@ //! This quasiquoter uses macros 2.0 hygiene to reliably access //! items from `proc_macro`, to build a `proc_macro::TokenStream`. -use {Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree}; +use crate::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree}; macro_rules! quote_tt { (($($t:tt)*)) => { Group::new(Delimiter::Parenthesis, quote!($($t)*)) }; @@ -63,7 +63,7 @@ macro_rules! quote { #[unstable(feature = "proc_macro_quote", issue = "54722")] pub fn quote(stream: TokenStream) -> TokenStream { if stream.is_empty() { - return quote!(::TokenStream::new()); + return quote!(crate::TokenStream::new()); } let mut after_dollar = false; let tokens = stream @@ -73,7 +73,7 @@ pub fn quote(stream: TokenStream) -> TokenStream { after_dollar = false; match tree { TokenTree::Ident(_) => { - return Some(quote!(Into::<::TokenStream>::into( + return Some(quote!(Into::::into( Clone::clone(&(@ tree))),)); } TokenTree::Punct(ref tt) if tt.as_char() == '$' => {} @@ -86,33 +86,33 @@ pub fn quote(stream: TokenStream) -> TokenStream { } } - Some(quote!(::TokenStream::from((@ match tree { - TokenTree::Punct(tt) => quote!(::TokenTree::Punct(::Punct::new( + Some(quote!(crate::TokenStream::from((@ match tree { + TokenTree::Punct(tt) => quote!(crate::TokenTree::Punct(crate::Punct::new( (@ TokenTree::from(Literal::character(tt.as_char()))), (@ match tt.spacing() { - Spacing::Alone => quote!(::Spacing::Alone), - Spacing::Joint => quote!(::Spacing::Joint), + Spacing::Alone => quote!(crate::Spacing::Alone), + Spacing::Joint => quote!(crate::Spacing::Joint), }), ))), - TokenTree::Group(tt) => quote!(::TokenTree::Group(::Group::new( + TokenTree::Group(tt) => quote!(crate::TokenTree::Group(crate::Group::new( (@ match tt.delimiter() { - Delimiter::Parenthesis => quote!(::Delimiter::Parenthesis), - Delimiter::Brace => quote!(::Delimiter::Brace), - Delimiter::Bracket => quote!(::Delimiter::Bracket), - Delimiter::None => quote!(::Delimiter::None), + Delimiter::Parenthesis => quote!(crate::Delimiter::Parenthesis), + Delimiter::Brace => quote!(crate::Delimiter::Brace), + Delimiter::Bracket => quote!(crate::Delimiter::Bracket), + Delimiter::None => quote!(crate::Delimiter::None), }), (@ quote(tt.stream())), ))), - TokenTree::Ident(tt) => quote!(::TokenTree::Ident(::Ident::new( + TokenTree::Ident(tt) => quote!(crate::TokenTree::Ident(crate::Ident::new( (@ TokenTree::from(Literal::string(&tt.to_string()))), (@ quote_span(tt.span())), ))), - TokenTree::Literal(tt) => quote!(::TokenTree::Literal({ + TokenTree::Literal(tt) => quote!(crate::TokenTree::Literal({ let mut iter = (@ TokenTree::from(Literal::string(&tt.to_string()))) - .parse::<::TokenStream>() + .parse::() .unwrap() .into_iter(); - if let (Some(::TokenTree::Literal(mut lit)), None) = + if let (Some(crate::TokenTree::Literal(mut lit)), None) = (iter.next(), iter.next()) { lit.set_span((@ quote_span(tt.span()))); @@ -129,12 +129,12 @@ pub fn quote(stream: TokenStream) -> TokenStream { panic!("unexpected trailing `$` in `quote!`"); } - quote!([(@ tokens)].iter().cloned().collect::<::TokenStream>()) + quote!([(@ tokens)].iter().cloned().collect::()) } /// Quote a `Span` into a `TokenStream`. /// This is needed to implement a custom quoter. #[unstable(feature = "proc_macro_quote", issue = "54722")] pub fn quote_span(_: Span) -> TokenStream { - quote!(::Span::def_site()) + quote!(crate::Span::def_site()) } diff --git a/src/libprofiler_builtins/Cargo.toml b/src/libprofiler_builtins/Cargo.toml index 7c95cf0a0542a..0d36bd0b39d76 100644 --- a/src/libprofiler_builtins/Cargo.toml +++ b/src/libprofiler_builtins/Cargo.toml @@ -3,6 +3,7 @@ authors = ["The Rust Project Developers"] build = "build.rs" name = "profiler_builtins" version = "0.0.0" +edition = "2018" [lib] name = "profiler_builtins" diff --git a/src/libprofiler_builtins/build.rs b/src/libprofiler_builtins/build.rs index b66cd66448748..ff52a03d9dd97 100644 --- a/src/libprofiler_builtins/build.rs +++ b/src/libprofiler_builtins/build.rs @@ -2,8 +2,6 @@ //! //! See the build.rs for libcompiler_builtins crate for details. -extern crate cc; - use std::env; use std::path::Path; diff --git a/src/libprofiler_builtins/lib.rs b/src/libprofiler_builtins/lib.rs index 0d12ba01c87a2..2ce1a110b44c0 100644 --- a/src/libprofiler_builtins/lib.rs +++ b/src/libprofiler_builtins/lib.rs @@ -7,3 +7,4 @@ #![allow(unused_features)] #![feature(nll)] #![feature(staged_api)] +#![deny(rust_2018_idioms)] diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml index 504e016e5b803..cb9eb32f8d21f 100644 --- a/src/librustc/Cargo.toml +++ b/src/librustc/Cargo.toml @@ -2,6 +2,7 @@ authors = ["The Rust Project Developers"] name = "rustc" version = "0.0.0" +edition = "2018" [lib] name = "rustc" @@ -15,6 +16,7 @@ fmt_macros = { path = "../libfmt_macros" } graphviz = { path = "../libgraphviz" } jobserver = "0.1" lazy_static = "1.0.0" +num_cpus = "1.0" scoped-tls = { version = "0.1.1", features = ["nightly"] } log = { version = "0.4", features = ["release_max_level_info", "std"] } polonius-engine = "0.6.2" @@ -23,7 +25,7 @@ rustc-rayon-core = "0.1.1" rustc_apfloat = { path = "../librustc_apfloat" } rustc_target = { path = "../librustc_target" } rustc_data_structures = { path = "../librustc_data_structures" } -rustc_errors = { path = "../librustc_errors" } +errors = { path = "../librustc_errors", package = "rustc_errors" } serialize = { path = "../libserialize" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs index 978d20ea94789..9eeae6eeb5f34 100644 --- a/src/librustc/cfg/construct.rs +++ b/src/librustc/cfg/construct.rs @@ -1,11 +1,11 @@ -use cfg::*; -use middle::region; +use crate::cfg::*; +use crate::middle::region; use rustc_data_structures::graph::implementation as graph; use syntax::ptr::P; -use ty::{self, TyCtxt}; +use crate::ty::{self, TyCtxt}; -use hir::{self, PatKind}; -use hir::def_id::DefId; +use crate::hir::{self, PatKind}; +use crate::hir::def_id::DefId; struct CFGBuilder<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -99,30 +99,20 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { } fn stmt(&mut self, stmt: &hir::Stmt, pred: CFGIndex) -> CFGIndex { - let hir_id = self.tcx.hir().node_to_hir_id(stmt.node.id()); - match stmt.node { - hir::StmtKind::Decl(ref decl, _) => { - let exit = self.decl(&decl, pred); - self.add_ast_node(hir_id.local_id, &[exit]) - } - - hir::StmtKind::Expr(ref expr, _) | - hir::StmtKind::Semi(ref expr, _) => { - let exit = self.expr(&expr, pred); - self.add_ast_node(hir_id.local_id, &[exit]) - } - } - } - - fn decl(&mut self, decl: &hir::Decl, pred: CFGIndex) -> CFGIndex { - match decl.node { - hir::DeclKind::Local(ref local) => { + let exit = match stmt.node { + hir::StmtKind::Local(ref local) => { let init_exit = self.opt_expr(&local.init, pred); self.pat(&local.pat, init_exit) } - - hir::DeclKind::Item(_) => pred, - } + hir::StmtKind::Item(_) => { + pred + } + hir::StmtKind::Expr(ref expr) | + hir::StmtKind::Semi(ref expr) => { + self.expr(&expr, pred) + } + }; + self.add_ast_node(stmt.hir_id.local_id, &[exit]) } fn pat(&mut self, pat: &hir::Pat, pred: CFGIndex) -> CFGIndex { @@ -160,9 +150,11 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { } } - fn pats_all<'b, I: Iterator>>(&mut self, - pats: I, - pred: CFGIndex) -> CFGIndex { + fn pats_all<'b, I: Iterator>>( + &mut self, + pats: I, + pred: CFGIndex + ) -> CFGIndex { //! Handles case where all of the patterns must match. pats.fold(pred, |pred, pat| self.pat(&pat, pred)) } diff --git a/src/librustc/cfg/graphviz.rs b/src/librustc/cfg/graphviz.rs index 6dec421760899..969c38bd66329 100644 --- a/src/librustc/cfg/graphviz.rs +++ b/src/librustc/cfg/graphviz.rs @@ -4,9 +4,9 @@ // For clarity, rename the graphviz crate locally to dot. use graphviz as dot; -use cfg; -use hir; -use ty::TyCtxt; +use crate::cfg; +use crate::hir; +use crate::ty::TyCtxt; pub type Node<'a> = (cfg::CFGIndex, &'a cfg::CFGNode); pub type Edge<'a> = &'a cfg::CFGEdge; diff --git a/src/librustc/cfg/mod.rs b/src/librustc/cfg/mod.rs index e58557839f9b9..345dff88b5f0b 100644 --- a/src/librustc/cfg/mod.rs +++ b/src/librustc/cfg/mod.rs @@ -2,9 +2,9 @@ //! Uses `Graph` as the underlying representation. use rustc_data_structures::graph::implementation as graph; -use ty::TyCtxt; -use hir; -use hir::def_id::DefId; +use crate::ty::TyCtxt; +use crate::hir; +use crate::hir::def_id::DefId; mod construct; pub mod graphviz; diff --git a/src/librustc/dep_graph/cgu_reuse_tracker.rs b/src/librustc/dep_graph/cgu_reuse_tracker.rs index e8d1b71048705..13f6f95332973 100644 --- a/src/librustc/dep_graph/cgu_reuse_tracker.rs +++ b/src/librustc/dep_graph/cgu_reuse_tracker.rs @@ -2,7 +2,7 @@ //! compilation. This is used for incremental compilation tests and debug //! output. -use session::Session; +use crate::session::Session; use rustc_data_structures::fx::FxHashMap; use std::sync::{Arc, Mutex}; use syntax_pos::Span; diff --git a/src/librustc/dep_graph/debug.rs b/src/librustc/dep_graph/debug.rs index a9ad22c5e913e..f18ee3dced72d 100644 --- a/src/librustc/dep_graph/debug.rs +++ b/src/librustc/dep_graph/debug.rs @@ -22,7 +22,7 @@ impl DepNodeFilter { } } - /// True if all nodes always pass the filter. + /// Returns `true` if all nodes always pass the filter. pub fn accepts_all(&self) -> bool { self.text.is_empty() } diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 427fe51e6ff9c..796739c872174 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -49,25 +49,25 @@ //! user of the `DepNode` API of having to know how to compute the expected //! fingerprint for a given set of node parameters. -use mir::interpret::GlobalId; -use hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX}; -use hir::map::DefPathHash; -use hir::HirId; +use crate::mir::interpret::GlobalId; +use crate::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX}; +use crate::hir::map::DefPathHash; +use crate::hir::HirId; -use ich::{Fingerprint, StableHashingContext}; +use crate::ich::{Fingerprint, StableHashingContext}; use rustc_data_structures::stable_hasher::{StableHasher, HashStable}; use std::fmt; use std::hash::Hash; use syntax_pos::symbol::InternedString; -use traits; -use traits::query::{ +use crate::traits; +use crate::traits::query::{ CanonicalProjectionGoal, CanonicalTyGoal, CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpSubtypeGoal, CanonicalPredicateGoal, CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpNormalizeGoal, }; -use ty::{TyCtxt, FnSig, Instance, InstanceDef, +use crate::ty::{TyCtxt, FnSig, Instance, InstanceDef, ParamEnv, ParamEnvAnd, Predicate, PolyFnSig, PolyTraitRef, Ty}; -use ty::subst::Substs; +use crate::ty::subst::Substs; // erase!() just makes tokens go away. It's used to specify which macro argument // is repeated (i.e., which sub-expression of the macro we are in) but don't need @@ -302,7 +302,7 @@ macro_rules! define_dep_nodes { } } - /// Create a new, parameterless DepNode. This method will assert + /// Creates a new, parameterless DepNode. This method will assert /// that the DepNode corresponding to the given DepKind actually /// does not require any parameters. #[inline(always)] @@ -314,7 +314,7 @@ macro_rules! define_dep_nodes { } } - /// Extract the DefId corresponding to this DepNode. This will work + /// Extracts the DefId corresponding to this DepNode. This will work /// if two conditions are met: /// /// 1. The Fingerprint of the DepNode actually is a DefPathHash, and @@ -389,7 +389,7 @@ impl fmt::Debug for DepNode { write!(f, "(")?; - ::ty::tls::with_opt(|opt_tcx| { + crate::ty::tls::with_opt(|opt_tcx| { if let Some(tcx) = opt_tcx { if let Some(def_id) = self.extract_def_id(tcx) { write!(f, "{}", tcx.def_path_debug_str(def_id))?; @@ -476,6 +476,10 @@ define_dep_nodes!( <'tcx> [] CheckModLoops(DefId), [] CheckModUnstableApiUsage(DefId), [] CheckModItemTypes(DefId), + [] CheckModPrivacy(DefId), + [] CheckModIntrinsics(DefId), + [] CheckModLiveness(DefId), + [] CheckModImplWf(DefId), [] CollectModItemTypes(DefId), [] Reachability, @@ -583,6 +587,7 @@ define_dep_nodes!( <'tcx> [] CheckImplItemWellFormed(DefId), [] ReachableNonGenerics(CrateNum), [] NativeLibraries(CrateNum), + [] EntryFn(CrateNum), [] PluginRegistrarFn(CrateNum), [] ProcMacroDeclsStatic(CrateNum), [input] CrateDisambiguator(CrateNum), @@ -630,6 +635,7 @@ define_dep_nodes!( <'tcx> [input] Freevars(DefId), [input] MaybeUnusedTraitImport(DefId), [input] MaybeUnusedExternCrates, + [input] NamesImportedByGlobUse(DefId), [eval_always] StabilityIndex, [eval_always] AllTraits, [input] AllCrateNums, @@ -637,6 +643,7 @@ define_dep_nodes!( <'tcx> [eval_always] CollectAndPartitionMonoItems, [] IsCodegenedItem(DefId), [] CodegenUnit(InternedString), + [] BackendOptimizationLevel(CrateNum), [] CompileCodegenUnit(InternedString), [input] OutputFilenames, [] NormalizeProjectionTy(CanonicalProjectionGoal<'tcx>), @@ -791,7 +798,7 @@ impl<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> DepNodeParams<'a, 'gcx, 'tcx> for HirId { } /// A "work product" corresponds to a `.o` (or other) file that we -/// save in between runs. These ids do not have a DefId but rather +/// save in between runs. These IDs do not have a `DefId` but rather /// some independent path or string that persists between runs without /// the need to be mapped or unmapped. (This ensures we can serialize /// them even in the absence of a tcx.) @@ -818,6 +825,6 @@ impl WorkProductId { } } -impl_stable_hash_for!(struct ::dep_graph::WorkProductId { +impl_stable_hash_for!(struct crate::dep_graph::WorkProductId { hash }); diff --git a/src/librustc/dep_graph/dep_tracking_map.rs b/src/librustc/dep_graph/dep_tracking_map.rs index 331a9c6109c4c..94b832bea628e 100644 --- a/src/librustc/dep_graph/dep_tracking_map.rs +++ b/src/librustc/dep_graph/dep_tracking_map.rs @@ -2,7 +2,7 @@ use rustc_data_structures::fx::FxHashMap; use std::cell::RefCell; use std::hash::Hash; use std::marker::PhantomData; -use util::common::MemoizationMap; +use crate::util::common::MemoizationMap; use super::{DepKind, DepNodeIndex, DepGraph}; @@ -43,7 +43,7 @@ impl MemoizationMap for RefCell> { /// /// Here, `[op]` represents whatever nodes `op` reads in the /// course of execution; `Map(key)` represents the node for this - /// map; and `CurrentTask` represents the current task when + /// map, and `CurrentTask` represents the current task when /// `memoize` is invoked. /// /// **Important:** when `op` is invoked, the current task will be diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs index 501ef01d74c6e..8a2f79e6793c0 100644 --- a/src/librustc/dep_graph/graph.rs +++ b/src/librustc/dep_graph/graph.rs @@ -1,16 +1,17 @@ -use errors::DiagnosticBuilder; +use errors::{Diagnostic, DiagnosticBuilder}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use smallvec::SmallVec; -use rustc_data_structures::sync::{Lrc, Lock}; +use rustc_data_structures::sync::{Lrc, Lock, AtomicU32, Ordering}; use std::env; use std::hash::Hash; use std::collections::hash_map::Entry; -use ty::{self, TyCtxt}; -use util::common::{ProfileQueriesMsg, profq_msg}; +use crate::ty::{self, TyCtxt}; +use crate::util::common::{ProfileQueriesMsg, profq_msg}; +use parking_lot::{Mutex, Condvar}; -use ich::{StableHashingContext, StableHashingContextProvider, Fingerprint}; +use crate::ich::{StableHashingContext, StableHashingContextProvider, Fingerprint}; use super::debug::EdgeFilter; use super::dep_node::{DepNode, DepKind, WorkProductId}; @@ -58,9 +59,15 @@ struct DepGraphData { /// nodes and edges as well as all fingerprints of nodes that have them. previous: PreviousDepGraph, - colors: Lock, + colors: DepNodeColorMap, - /// When we load, there may be `.o` files, cached mir, or other such + /// A set of loaded diagnostics that have been emitted. + emitted_diagnostics: Mutex>, + + /// Used to wait for diagnostics to be emitted. + emitted_diagnostics_cond_var: Condvar, + + /// When we load, there may be `.o` files, cached MIR, or other such /// things available to us. If we find that they are not dirty, we /// load the path to the file storing those work-products here into /// this map. We can later look for and extract that data. @@ -72,6 +79,16 @@ struct DepGraphData { loaded_from_cache: Lock>, } +pub fn hash_result(hcx: &mut StableHashingContext<'_>, result: &R) -> Option +where + R: for<'a> HashStable>, +{ + let mut stable_hasher = StableHasher::new(); + result.hash_stable(hcx, &mut stable_hasher); + + Some(stable_hasher.finish()) +} + impl DepGraph { pub fn new(prev_graph: PreviousDepGraph, @@ -83,8 +100,10 @@ impl DepGraph { previous_work_products: prev_work_products, dep_node_debug: Default::default(), current: Lock::new(CurrentDepGraph::new(prev_graph_node_count)), + emitted_diagnostics: Default::default(), + emitted_diagnostics_cond_var: Condvar::new(), previous: prev_graph, - colors: Lock::new(DepNodeColorMap::new(prev_graph_node_count)), + colors: DepNodeColorMap::new(prev_graph_node_count), loaded_from_cache: Default::default(), })), } @@ -96,7 +115,7 @@ impl DepGraph { } } - /// True if we are actually building the full dep-graph. + /// Returns `true` if we are actually building the full dep-graph, and `false` otherwise. #[inline] pub fn is_fully_enabled(&self) -> bool { self.data.is_some() @@ -169,14 +188,16 @@ impl DepGraph { /// `arg` parameter. /// /// [rustc guide]: https://rust-lang.github.io/rustc-guide/incremental-compilation.html - pub fn with_task<'gcx, C, A, R>(&self, - key: DepNode, - cx: C, - arg: A, - task: fn(C, A) -> R) - -> (R, DepNodeIndex) - where C: DepGraphSafe + StableHashingContextProvider<'gcx>, - R: HashStable>, + pub fn with_task<'a, C, A, R>( + &self, + key: DepNode, + cx: C, + arg: A, + task: fn(C, A) -> R, + hash_result: impl FnOnce(&mut StableHashingContext<'_>, &R) -> Option, + ) -> (R, DepNodeIndex) + where + C: DepGraphSafe + StableHashingContextProvider<'a>, { self.with_task_impl(key, cx, arg, false, task, |_key| Some(TaskDeps { @@ -187,17 +208,18 @@ impl DepGraph { }), |data, key, fingerprint, task| { data.borrow_mut().complete_task(key, task.unwrap(), fingerprint) - }) + }, + hash_result) } /// Creates a new dep-graph input with value `input` - pub fn input_task<'gcx, C, R>(&self, + pub fn input_task<'a, C, R>(&self, key: DepNode, cx: C, input: R) -> (R, DepNodeIndex) - where C: DepGraphSafe + StableHashingContextProvider<'gcx>, - R: HashStable>, + where C: DepGraphSafe + StableHashingContextProvider<'a>, + R: for<'b> HashStable>, { fn identity_fn(_: C, arg: A) -> A { arg @@ -207,10 +229,11 @@ impl DepGraph { |_| None, |data, key, fingerprint, _| { data.borrow_mut().alloc_node(key, SmallVec::new(), fingerprint) - }) + }, + hash_result::) } - fn with_task_impl<'gcx, C, A, R>( + fn with_task_impl<'a, C, A, R>( &self, key: DepNode, cx: C, @@ -221,11 +244,11 @@ impl DepGraph { finish_task_and_alloc_depnode: fn(&Lock, DepNode, Fingerprint, - Option) -> DepNodeIndex + Option) -> DepNodeIndex, + hash_result: impl FnOnce(&mut StableHashingContext<'_>, &R) -> Option, ) -> (R, DepNodeIndex) where - C: DepGraphSafe + StableHashingContextProvider<'gcx>, - R: HashStable>, + C: DepGraphSafe + StableHashingContextProvider<'a>, { if let Some(ref data) = self.data { let task_deps = create_task(key).map(|deps| Lock::new(deps)); @@ -260,34 +283,50 @@ impl DepGraph { profq_msg(hcx.sess(), ProfileQueriesMsg::TaskEnd) }; - let mut stable_hasher = StableHasher::new(); - result.hash_stable(&mut hcx, &mut stable_hasher); - - let current_fingerprint = stable_hasher.finish(); + let current_fingerprint = hash_result(&mut hcx, &result); let dep_node_index = finish_task_and_alloc_depnode( &data.current, key, - current_fingerprint, + current_fingerprint.unwrap_or(Fingerprint::ZERO), task_deps.map(|lock| lock.into_inner()), ); + let print_status = cfg!(debug_assertions) && hcx.sess().opts.debugging_opts.dep_tasks; + // Determine the color of the new DepNode. if let Some(prev_index) = data.previous.node_to_index_opt(&key) { let prev_fingerprint = data.previous.fingerprint_by_index(prev_index); - let color = if current_fingerprint == prev_fingerprint { - DepNodeColor::Green(dep_node_index) + let color = if let Some(current_fingerprint) = current_fingerprint { + if current_fingerprint == prev_fingerprint { + if print_status { + eprintln!("[task::green] {:?}", key); + } + DepNodeColor::Green(dep_node_index) + } else { + if print_status { + eprintln!("[task::red] {:?}", key); + } + DepNodeColor::Red + } } else { + if print_status { + eprintln!("[task::unknown] {:?}", key); + } + // Mark the node as Red if we can't hash the result DepNodeColor::Red }; - let mut colors = data.colors.borrow_mut(); - debug_assert!(colors.get(prev_index).is_none(), - "DepGraph::with_task() - Duplicate DepNodeColor \ - insertion for {:?}", key); + debug_assert!(data.colors.get(prev_index).is_none(), + "DepGraph::with_task() - Duplicate DepNodeColor \ + insertion for {:?}", key); - colors.insert(prev_index, color); + data.colors.insert(prev_index, color); + } else { + if print_status { + eprintln!("[task::new] {:?}", key); + } } (result, dep_node_index) @@ -296,8 +335,8 @@ impl DepGraph { } } - /// Execute something within an "anonymous" task, that is, a task the - /// DepNode of which is determined by the list of inputs it read from. + /// Executes something within an "anonymous" task, that is, a task the + /// `DepNode` of which is determined by the list of inputs it read from. pub fn with_anon_task(&self, dep_kind: DepKind, op: OP) -> (R, DepNodeIndex) where OP: FnOnce() -> R { @@ -332,16 +371,18 @@ impl DepGraph { } } - /// Execute something within an "eval-always" task which is a task - // that runs whenever anything changes. - pub fn with_eval_always_task<'gcx, C, A, R>(&self, - key: DepNode, - cx: C, - arg: A, - task: fn(C, A) -> R) - -> (R, DepNodeIndex) - where C: DepGraphSafe + StableHashingContextProvider<'gcx>, - R: HashStable>, + /// Executes something within an "eval-always" task which is a task + /// that runs whenever anything changes. + pub fn with_eval_always_task<'a, C, A, R>( + &self, + key: DepNode, + cx: C, + arg: A, + task: fn(C, A) -> R, + hash_result: impl FnOnce(&mut StableHashingContext<'_>, &R) -> Option, + ) -> (R, DepNodeIndex) + where + C: DepGraphSafe + StableHashingContextProvider<'a>, { self.with_task_impl(key, cx, arg, false, task, |_| None, @@ -351,7 +392,8 @@ impl DepGraph { &DepNode::new_no_params(DepKind::Krate) ]; current.alloc_node(key, smallvec![krate_idx], fingerprint) - }) + }, + hash_result) } #[inline] @@ -411,7 +453,7 @@ impl DepGraph { self.data.as_ref().unwrap().previous.node_to_index(dep_node) } - /// Check whether a previous work product exists for `v` and, if + /// Checks whether a previous work product exists for `v` and, if /// so, return the path that leads to it. Used to skip doing work. pub fn previous_work_product(&self, v: &WorkProductId) -> Option { self.data @@ -502,7 +544,7 @@ impl DepGraph { pub fn node_color(&self, dep_node: &DepNode) -> Option { if let Some(ref data) = self.data { if let Some(prev_index) = data.previous.node_to_index_opt(dep_node) { - return data.colors.borrow().get(prev_index) + return data.colors.get(prev_index) } else { // This is a node that did not exist in the previous compilation // session, so we consider it to be red. @@ -513,56 +555,89 @@ impl DepGraph { None } - pub fn try_mark_green<'tcx>(&self, - tcx: TyCtxt<'_, 'tcx, 'tcx>, - dep_node: &DepNode) - -> Option { - debug!("try_mark_green({:?}) - BEGIN", dep_node); - let data = self.data.as_ref().unwrap(); + /// Try to read a node index for the node dep_node. + /// A node will have an index, when it's already been marked green, or when we can mark it + /// green. This function will mark the current task as a reader of the specified node, when + /// a node index can be found for that node. + pub fn try_mark_green_and_read( + &self, + tcx: TyCtxt<'_, '_, '_>, + dep_node: &DepNode + ) -> Option<(SerializedDepNodeIndex, DepNodeIndex)> { + self.try_mark_green(tcx, dep_node).map(|(prev_index, dep_node_index)| { + debug_assert!(self.is_green(&dep_node)); + self.read_index(dep_node_index); + (prev_index, dep_node_index) + }) + } - #[cfg(not(parallel_queries))] - debug_assert!(!data.current.borrow().node_to_node_index.contains_key(dep_node)); - - if dep_node.kind.is_input() { - // We should only hit try_mark_green() for inputs that do not exist - // anymore in the current compilation session. Existing inputs are - // eagerly marked as either red/green before any queries are - // executed. - debug_assert!(dep_node.extract_def_id(tcx).is_none()); - debug!("try_mark_green({:?}) - END - DepNode is deleted input", dep_node); - return None; - } + pub fn try_mark_green( + &self, + tcx: TyCtxt<'_, '_, '_>, + dep_node: &DepNode + ) -> Option<(SerializedDepNodeIndex, DepNodeIndex)> { + debug_assert!(!dep_node.kind.is_input()); + + // Return None if the dep graph is disabled + let data = self.data.as_ref()?; + + // Return None if the dep node didn't exist in the previous session + let prev_index = data.previous.node_to_index_opt(dep_node)?; - let (prev_deps, prev_dep_node_index) = match data.previous.edges_from(dep_node) { - Some(prev) => { + match data.colors.get(prev_index) { + Some(DepNodeColor::Green(dep_node_index)) => Some((prev_index, dep_node_index)), + Some(DepNodeColor::Red) => None, + None => { // This DepNode and the corresponding query invocation existed // in the previous compilation session too, so we can try to // mark it as green by recursively marking all of its // dependencies green. - prev - } - None => { - // This DepNode did not exist in the previous compilation session, - // so we cannot mark it as green. - debug!("try_mark_green({:?}) - END - DepNode does not exist in \ - current compilation session anymore", dep_node); - return None + self.try_mark_previous_green( + tcx.global_tcx(), + data, + prev_index, + &dep_node + ).map(|dep_node_index| { + (prev_index, dep_node_index) + }) } - }; + } + } + + /// Try to mark a dep-node which existed in the previous compilation session as green. + fn try_mark_previous_green<'tcx>( + &self, + tcx: TyCtxt<'_, 'tcx, 'tcx>, + data: &DepGraphData, + prev_dep_node_index: SerializedDepNodeIndex, + dep_node: &DepNode + ) -> Option { + debug!("try_mark_previous_green({:?}) - BEGIN", dep_node); + + #[cfg(not(parallel_compiler))] + { + debug_assert!(!data.current.borrow().node_to_node_index.contains_key(dep_node)); + debug_assert!(data.colors.get(prev_dep_node_index).is_none()); + } - debug_assert!(data.colors.borrow().get(prev_dep_node_index).is_none()); + // We never try to mark inputs as green + debug_assert!(!dep_node.kind.is_input()); + + debug_assert_eq!(data.previous.index_to_node(prev_dep_node_index), *dep_node); + + let prev_deps = data.previous.edge_targets_from(prev_dep_node_index); let mut current_deps = SmallVec::new(); for &dep_dep_node_index in prev_deps { - let dep_dep_node_color = data.colors.borrow().get(dep_dep_node_index); + let dep_dep_node_color = data.colors.get(dep_dep_node_index); match dep_dep_node_color { Some(DepNodeColor::Green(node_index)) => { // This dependency has been marked as green before, we are // still fine and can continue with checking the other // dependencies. - debug!("try_mark_green({:?}) --- found dependency {:?} to \ + debug!("try_mark_previous_green({:?}) --- found dependency {:?} to \ be immediately green", dep_node, data.previous.index_to_node(dep_dep_node_index)); @@ -573,7 +648,7 @@ impl DepGraph { // compared to the previous compilation session. We cannot // mark the DepNode as green and also don't need to bother // with checking any of the other dependencies. - debug!("try_mark_green({:?}) - END - dependency {:?} was \ + debug!("try_mark_previous_green({:?}) - END - dependency {:?} was \ immediately red", dep_node, data.previous.index_to_node(dep_dep_node_index)); @@ -585,12 +660,18 @@ impl DepGraph { // We don't know the state of this dependency. If it isn't // an input node, let's try to mark it green recursively. if !dep_dep_node.kind.is_input() { - debug!("try_mark_green({:?}) --- state of dependency {:?} \ + debug!("try_mark_previous_green({:?}) --- state of dependency {:?} \ is unknown, trying to mark it green", dep_node, dep_dep_node); - if let Some(node_index) = self.try_mark_green(tcx, dep_dep_node) { - debug!("try_mark_green({:?}) --- managed to MARK \ + let node_index = self.try_mark_previous_green( + tcx, + data, + dep_dep_node_index, + dep_dep_node + ); + if let Some(node_index) = node_index { + debug!("try_mark_previous_green({:?}) --- managed to MARK \ dependency {:?} as green", dep_node, dep_dep_node); current_deps.push(node_index); continue; @@ -600,7 +681,7 @@ impl DepGraph { DepKind::Hir | DepKind::HirBody | DepKind::CrateMetadata => { - if dep_node.extract_def_id(tcx).is_none() { + if dep_dep_node.extract_def_id(tcx).is_none() { // If the node does not exist anymore, we // just fail to mark green. return None @@ -620,20 +701,20 @@ impl DepGraph { } // We failed to mark it green, so we try to force the query. - debug!("try_mark_green({:?}) --- trying to force \ + debug!("try_mark_previous_green({:?}) --- trying to force \ dependency {:?}", dep_node, dep_dep_node); - if ::ty::query::force_from_dep_node(tcx, dep_dep_node) { - let dep_dep_node_color = data.colors.borrow().get(dep_dep_node_index); + if crate::ty::query::force_from_dep_node(tcx, dep_dep_node) { + let dep_dep_node_color = data.colors.get(dep_dep_node_index); match dep_dep_node_color { Some(DepNodeColor::Green(node_index)) => { - debug!("try_mark_green({:?}) --- managed to \ + debug!("try_mark_previous_green({:?}) --- managed to \ FORCE dependency {:?} to green", dep_node, dep_dep_node); current_deps.push(node_index); } Some(DepNodeColor::Red) => { - debug!("try_mark_green({:?}) - END - \ + debug!("try_mark_previous_green({:?}) - END - \ dependency {:?} was red after forcing", dep_node, dep_dep_node); @@ -641,7 +722,7 @@ impl DepGraph { } None => { if !tcx.sess.has_errors() { - bug!("try_mark_green() - Forcing the DepNode \ + bug!("try_mark_previous_green() - Forcing the DepNode \ should have set its color") } else { // If the query we just forced has resulted @@ -653,7 +734,7 @@ impl DepGraph { } } else { // The DepNode could not be forced. - debug!("try_mark_green({:?}) - END - dependency {:?} \ + debug!("try_mark_previous_green({:?}) - END - dependency {:?} \ could not be forced", dep_node, dep_dep_node); return None } @@ -680,44 +761,76 @@ impl DepGraph { }; // ... emitting any stored diagnostic ... - if did_allocation { - // Only the thread which did the allocation emits the error messages - - // FIXME: Ensure that these are printed before returning for all threads. - // Currently threads where did_allocation = false can continue on - // and emit other diagnostics before these diagnostics are emitted. - // Such diagnostics should be emitted after these. - // See https://github.com/rust-lang/rust/issues/48685 - let diagnostics = tcx.queries.on_disk_cache - .load_diagnostics(tcx, prev_dep_node_index); - - if diagnostics.len() > 0 { - let handle = tcx.sess.diagnostic(); - // Promote the previous diagnostics to the current session. - tcx.queries.on_disk_cache - .store_diagnostics(dep_node_index, diagnostics.clone().into()); + let diagnostics = tcx.queries.on_disk_cache + .load_diagnostics(tcx, prev_dep_node_index); - for diagnostic in diagnostics { - DiagnosticBuilder::new_diagnostic(handle, diagnostic).emit(); - } - } + if unlikely!(diagnostics.len() > 0) { + self.emit_diagnostics( + tcx, + data, + dep_node_index, + did_allocation, + diagnostics + ); } // ... and finally storing a "Green" entry in the color map. - let mut colors = data.colors.borrow_mut(); // Multiple threads can all write the same color here - #[cfg(not(parallel_queries))] - debug_assert!(colors.get(prev_dep_node_index).is_none(), - "DepGraph::try_mark_green() - Duplicate DepNodeColor \ + #[cfg(not(parallel_compiler))] + debug_assert!(data.colors.get(prev_dep_node_index).is_none(), + "DepGraph::try_mark_previous_green() - Duplicate DepNodeColor \ insertion for {:?}", dep_node); - colors.insert(prev_dep_node_index, DepNodeColor::Green(dep_node_index)); + data.colors.insert(prev_dep_node_index, DepNodeColor::Green(dep_node_index)); - debug!("try_mark_green({:?}) - END - successfully marked as green", dep_node); + debug!("try_mark_previous_green({:?}) - END - successfully marked as green", dep_node); Some(dep_node_index) } + /// Atomically emits some loaded diagnotics, assuming that this only gets called with + /// `did_allocation` set to `true` on a single thread. + #[cold] + #[inline(never)] + fn emit_diagnostics<'tcx>( + &self, + tcx: TyCtxt<'_, 'tcx, 'tcx>, + data: &DepGraphData, + dep_node_index: DepNodeIndex, + did_allocation: bool, + diagnostics: Vec, + ) { + if did_allocation || !cfg!(parallel_compiler) { + // Only the thread which did the allocation emits the error messages + let handle = tcx.sess.diagnostic(); + + // Promote the previous diagnostics to the current session. + tcx.queries.on_disk_cache + .store_diagnostics(dep_node_index, diagnostics.clone().into()); + + for diagnostic in diagnostics { + DiagnosticBuilder::new_diagnostic(handle, diagnostic).emit(); + } + + #[cfg(parallel_compiler)] + { + // Mark the diagnostics and emitted and wake up waiters + data.emitted_diagnostics.lock().insert(dep_node_index); + data.emitted_diagnostics_cond_var.notify_all(); + } + } else { + // The other threads will wait for the diagnostics to be emitted + + let mut emitted_diagnostics = data.emitted_diagnostics.lock(); + loop { + if emitted_diagnostics.contains(&dep_node_index) { + break; + } + data.emitted_diagnostics_cond_var.wait(&mut emitted_diagnostics); + } + } + } + // Returns true if the given node has been marked as green during the // current compilation session. Used in various assertions pub fn is_green(&self, dep_node: &DepNode) -> bool { @@ -735,9 +848,8 @@ impl DepGraph { pub fn exec_cache_promotions<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) { let green_nodes: Vec = { let data = self.data.as_ref().unwrap(); - let colors = data.colors.borrow(); - colors.values.indices().filter_map(|prev_index| { - match colors.get(prev_index) { + data.colors.values.indices().filter_map(|prev_index| { + match data.colors.get(prev_index) { Some(DepNodeColor::Green(_)) => { let dep_node = data.previous.index_to_node(prev_index); if dep_node.cache_on_disk(tcx) { @@ -816,7 +928,7 @@ impl DepGraph { #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] pub struct WorkProduct { pub cgu_name: String, - /// Saved files associated with this CGU + /// Saved files associated with this CGU. pub saved_files: Vec<(WorkProductFileKind, String)>, } @@ -840,17 +952,17 @@ pub(super) struct CurrentDepGraph { #[allow(dead_code)] forbidden_edge: Option, - // Anonymous DepNodes are nodes the ID of which we compute from the list of - // their edges. This has the beneficial side-effect that multiple anonymous - // nodes can be coalesced into one without changing the semantics of the - // dependency graph. However, the merging of nodes can lead to a subtle - // problem during red-green marking: The color of an anonymous node from - // the current session might "shadow" the color of the node with the same - // ID from the previous session. In order to side-step this problem, we make - // sure that anon-node IDs allocated in different sessions don't overlap. - // This is implemented by mixing a session-key into the ID fingerprint of - // each anon node. The session-key is just a random number generated when - // the DepGraph is created. + /// Anonymous `DepNode`s are nodes whose IDs we compute from the list of + /// their edges. This has the beneficial side-effect that multiple anonymous + /// nodes can be coalesced into one without changing the semantics of the + /// dependency graph. However, the merging of nodes can lead to a subtle + /// problem during red-green marking: The color of an anonymous node from + /// the current session might "shadow" the color of the node with the same + /// ID from the previous session. In order to side-step this problem, we make + /// sure that anonymous `NodeId`s allocated in different sessions don't overlap. + /// This is implemented by mixing a session-key into the ID fingerprint of + /// each anon node. The session-key is just a random number generated when + /// the `DepGraph` is created. anon_id_seed: Fingerprint, total_read_count: u64, @@ -1035,7 +1147,7 @@ pub struct TaskDeps { // A data structure that stores Option values as a contiguous // array, using one u32 per entry. struct DepNodeColorMap { - values: IndexVec, + values: IndexVec, } const COMPRESSED_NONE: u32 = 0; @@ -1045,12 +1157,12 @@ const COMPRESSED_FIRST_GREEN: u32 = 2; impl DepNodeColorMap { fn new(size: usize) -> DepNodeColorMap { DepNodeColorMap { - values: IndexVec::from_elem_n(COMPRESSED_NONE, size) + values: (0..size).map(|_| AtomicU32::new(COMPRESSED_NONE)).collect(), } } fn get(&self, index: SerializedDepNodeIndex) -> Option { - match self.values[index] { + match self.values[index].load(Ordering::Acquire) { COMPRESSED_NONE => None, COMPRESSED_RED => Some(DepNodeColor::Red), value => Some(DepNodeColor::Green(DepNodeIndex::from_u32( @@ -1059,10 +1171,10 @@ impl DepNodeColorMap { } } - fn insert(&mut self, index: SerializedDepNodeIndex, color: DepNodeColor) { - self.values[index] = match color { + fn insert(&self, index: SerializedDepNodeIndex, color: DepNodeColor) { + self.values[index].store(match color { DepNodeColor::Red => COMPRESSED_RED, DepNodeColor::Green(index) => index.as_u32() + COMPRESSED_FIRST_GREEN, - } + }, Ordering::Release) } } diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs index 022caabcbf3a1..b84d2ad145889 100644 --- a/src/librustc/dep_graph/mod.rs +++ b/src/librustc/dep_graph/mod.rs @@ -10,7 +10,7 @@ pub mod cgu_reuse_tracker; pub use self::dep_tracking_map::{DepTrackingMap, DepTrackingMapConfig}; pub use self::dep_node::{DepNode, DepKind, DepConstructor, WorkProductId, label_strs}; -pub use self::graph::{DepGraph, WorkProduct, DepNodeIndex, DepNodeColor, TaskDeps}; +pub use self::graph::{DepGraph, WorkProduct, DepNodeIndex, DepNodeColor, TaskDeps, hash_result}; pub use self::graph::WorkProductFileKind; pub use self::prev::PreviousDepGraph; pub use self::query::DepGraphQuery; diff --git a/src/librustc/dep_graph/prev.rs b/src/librustc/dep_graph/prev.rs index 76d2954b4e35c..d971690bbe317 100644 --- a/src/librustc/dep_graph/prev.rs +++ b/src/librustc/dep_graph/prev.rs @@ -1,4 +1,4 @@ -use ich::Fingerprint; +use crate::ich::Fingerprint; use rustc_data_structures::fx::FxHashMap; use super::dep_node::DepNode; use super::serialized::{SerializedDepGraph, SerializedDepNodeIndex}; @@ -19,14 +19,11 @@ impl PreviousDepGraph { } #[inline] - pub fn edges_from(&self, - dep_node: &DepNode) - -> Option<(&[SerializedDepNodeIndex], SerializedDepNodeIndex)> { - self.index - .get(dep_node) - .map(|&node_index| { - (self.data.edge_targets_from(node_index), node_index) - }) + pub fn edge_targets_from( + &self, + dep_node_index: SerializedDepNodeIndex + ) -> &[SerializedDepNodeIndex] { + self.data.edge_targets_from(dep_node_index) } #[inline] diff --git a/src/librustc/dep_graph/safe.rs b/src/librustc/dep_graph/safe.rs index f1e8224a70d14..fc767defe9c71 100644 --- a/src/librustc/dep_graph/safe.rs +++ b/src/librustc/dep_graph/safe.rs @@ -1,9 +1,9 @@ //! The `DepGraphSafe` trait -use hir::BodyId; -use hir::def_id::DefId; +use crate::hir::BodyId; +use crate::hir::def_id::DefId; use syntax::ast::NodeId; -use ty::TyCtxt; +use crate::ty::TyCtxt; /// The `DepGraphSafe` trait is used to specify what kinds of values /// are safe to "leak" into a task. The idea is that this should be diff --git a/src/librustc/dep_graph/serialized.rs b/src/librustc/dep_graph/serialized.rs index 3c04f01a5e1eb..b64f71ed908d8 100644 --- a/src/librustc/dep_graph/serialized.rs +++ b/src/librustc/dep_graph/serialized.rs @@ -1,7 +1,7 @@ //! The data that we will serialize and deserialize. -use dep_graph::DepNode; -use ich::Fingerprint; +use crate::dep_graph::DepNode; +use crate::ich::Fingerprint; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; newtype_index! { diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 287a45a21eadf..00f9fa3a938d6 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -1,3 +1,4 @@ +// ignore-tidy-linelength #![allow(non_snake_case)] // Error messages for EXXXX errors. @@ -362,6 +363,10 @@ struct Foo1 { x: &bool } // ^ expected lifetime parameter struct Foo2<'a> { x: &'a bool } // correct +impl Foo2 {} + // ^^^^ expected lifetime parameter +impl<'a> Foo2<'a> {} // correct + struct Bar1 { x: Foo2 } // ^^^^ expected lifetime parameter struct Bar2<'a> { x: Foo2<'a> } // correct @@ -403,11 +408,7 @@ fn bar(x: &str, y: &str) -> &str { } fn baz<'a>(x: &'a str, y: &str) -> &str { } ``` -Lifetime elision in implementation headers was part of the lifetime elision -RFC. It is, however, [currently unimplemented][iss15872]. - -[book-le]: https://doc.rust-lang.org/nightly/book/first-edition/lifetimes.html#lifetime-elision -[iss15872]: https://github.com/rust-lang/rust/issues/15872 +[book-le]: https://doc.rust-lang.org/book/ch10-03-lifetime-syntax.html#lifetime-elision "##, E0119: r##" @@ -642,7 +643,9 @@ attributes: #![no_std] ``` -See also https://doc.rust-lang.org/book/first-edition/no-stdlib.html +See also the [unstable book][1]. + +[1]: https://doc.rust-lang.org/unstable-book/language-features/lang-items.html#writing-an-executable-without-stdlib "##, E0214: r##" @@ -766,11 +769,40 @@ struct Foo { These can be fixed by declaring lifetime parameters: ``` +struct Foo<'a> { + x: &'a str, +} + fn foo<'a>(x: &'a str) {} +``` + +Impl blocks declare lifetime parameters separately. You need to add lifetime +parameters to an impl block if you're implementing a type that has a lifetime +parameter of its own. +For example: +```compile_fail,E0261 struct Foo<'a> { x: &'a str, } + +// error, use of undeclared lifetime name `'a` +impl Foo<'a> { + fn foo<'a>(x: &'a str) {} +} +``` + +This is fixed by declaring the impl block like this: + +``` +struct Foo<'a> { + x: &'a str, +} + +// correct +impl<'a> Foo<'a> { + fn foo(x: &'a str) {} +} ``` "##, @@ -1154,7 +1186,7 @@ impl Generator for AnotherImpl { fn main() { let cont: u32 = Generator::create(); // error, impossible to choose one of Generator trait implementation - // Impl or AnotherImpl? Maybe anything else? + // Should it be Impl or AnotherImpl, maybe something else? } ``` @@ -1680,7 +1712,7 @@ fn main() { ``` To understand better how closures work in Rust, read: -https://doc.rust-lang.org/book/first-edition/closures.html +https://doc.rust-lang.org/book/ch13-01-closures.html "##, E0580: r##" diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs index b4a00715c0f22..ddc1eebe645ae 100644 --- a/src/librustc/hir/check_attr.rs +++ b/src/librustc/hir/check_attr.rs @@ -5,13 +5,12 @@ //! item. -use ty::TyCtxt; -use ty::query::Providers; -use ty::query::queries; +use crate::ty::TyCtxt; +use crate::ty::query::Providers; -use hir; -use hir::def_id::DefId; -use hir::intravisit::{self, Visitor, NestedVisitorMap}; +use crate::hir; +use crate::hir::def_id::DefId; +use crate::hir::intravisit::{self, Visitor, NestedVisitorMap}; use std::fmt::{self, Display}; use syntax_pos::Span; @@ -92,7 +91,7 @@ struct CheckAttrVisitor<'a, 'tcx: 'a> { } impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> { - /// Check any attribute. + /// Checks any attribute. fn check_attributes(&self, item: &hir::Item, target: Target) { if target == Target::Fn || target == Target::Const { self.tcx.codegen_fn_attrs(self.tcx.hir().local_def_id(item.id)); @@ -116,7 +115,7 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> { self.check_used(item, target); } - /// Check if an `#[inline]` is applied to a function or a closure. + /// Checks if an `#[inline]` is applied to a function or a closure. fn check_inline(&self, attr: &hir::Attribute, span: &Span, target: Target) { if target != Target::Fn && target != Target::Closure { struct_span_err!(self.tcx.sess, @@ -128,7 +127,7 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> { } } - /// Check if the `#[non_exhaustive]` attribute on an `item` is valid. + /// Checks if the `#[non_exhaustive]` attribute on an `item` is valid. fn check_non_exhaustive(&self, attr: &hir::Attribute, item: &hir::Item, target: Target) { match target { Target::Struct | Target::Enum => { /* Valid */ }, @@ -144,7 +143,7 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> { } } - /// Check if the `#[marker]` attribute on an `item` is valid. + /// Checks if the `#[marker]` attribute on an `item` is valid. fn check_marker(&self, attr: &hir::Attribute, item: &hir::Item, target: Target) { match target { Target::Trait => { /* Valid */ }, @@ -158,7 +157,7 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> { } } - /// Check if the `#[repr]` attributes on `item` are valid. + /// Checks if the `#[repr]` attributes on `item` are valid. fn check_repr(&self, item: &hir::Item, target: Target) { // Extract the names of all repr hints, e.g., [foo, bar, align] for: // ``` @@ -187,8 +186,8 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> { }; let (article, allowed_targets) = match &*name.as_str() { - "C" => { - is_c = true; + "C" | "align" => { + is_c |= name == "C"; if target != Target::Struct && target != Target::Union && target != Target::Enum { @@ -213,14 +212,6 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> { continue } } - "align" => { - if target != Target::Struct && - target != Target::Union { - ("a", "struct or union") - } else { - continue - } - } "transparent" => { is_transparent = true; if target != Target::Struct { @@ -283,8 +274,8 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> { fn check_stmt_attributes(&self, stmt: &hir::Stmt) { // When checking statements ignore expressions, they will be checked later - if let hir::StmtKind::Decl(_, _) = stmt.node { - for attr in stmt.node.attrs() { + if let hir::StmtKind::Local(ref l) = stmt.node { + for attr in l.attrs.iter() { if attr.check_name("inline") { self.check_inline(attr, &stmt.span, Target::Statement); } @@ -355,7 +346,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckAttrVisitor<'a, 'tcx> { pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { for &module in tcx.hir().krate().modules.keys() { - queries::check_mod_attrs::ensure(tcx, tcx.hir().local_def_id(module)); + tcx.ensure().check_mod_attrs(tcx.hir().local_def_id(module)); } } @@ -363,7 +354,7 @@ fn is_c_like_enum(item: &hir::Item) -> bool { if let hir::ItemKind::Enum(ref def, _) = item.node { for variant in &def.variants { match variant.node.data { - hir::VariantData::Unit(_) => { /* continue */ } + hir::VariantData::Unit(..) => { /* continue */ } _ => { return false; } } } diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs index 8a74c51d3f723..f6d864f5b404d 100644 --- a/src/librustc/hir/def.rs +++ b/src/librustc/hir/def.rs @@ -1,10 +1,10 @@ -use hir::def_id::DefId; -use util::nodemap::{NodeMap, DefIdMap}; +use crate::hir::def_id::DefId; +use crate::util::nodemap::{NodeMap, DefIdMap}; use syntax::ast; use syntax::ext::base::MacroKind; use syntax_pos::Span; -use hir; -use ty; +use crate::hir; +use crate::ty; use self::Namespace::*; @@ -58,6 +58,7 @@ pub enum Def { // Value namespace Fn(DefId), Const(DefId), + ConstParam(DefId), Static(DefId, bool /* is_mutbl */), StructCtor(DefId, CtorKind), // `DefId` refers to `NodeId` of the struct's constructor VariantCtor(DefId, CtorKind), // `DefId` refers to the enum variant @@ -181,7 +182,7 @@ impl ::std::ops::IndexMut for PerNS { } impl PerNS> { - /// Returns whether all the items in this collection are `None`. + /// Returns `true` if all the items in this collection are `None`. pub fn is_empty(&self) -> bool { self.type_ns.is_none() && self.value_ns.is_none() && self.macro_ns.is_none() } @@ -252,18 +253,21 @@ impl NonMacroAttrKind { } impl Def { + /// Return the `DefId` of this `Def` if it has an id, else panic. pub fn def_id(&self) -> DefId { self.opt_def_id().unwrap_or_else(|| { bug!("attempted .def_id() on invalid def: {:?}", self) }) } + /// Return `Some(..)` with the `DefId` of this `Def` if it has a id, else `None`. pub fn opt_def_id(&self) -> Option { match *self { Def::Fn(id) | Def::Mod(id) | Def::Static(id, _) | Def::Variant(id) | Def::VariantCtor(id, ..) | Def::Enum(id) | Def::TyAlias(id) | Def::TraitAlias(id) | - Def::AssociatedTy(id) | Def::TyParam(id) | Def::Struct(id) | Def::StructCtor(id, ..) | + Def::AssociatedTy(id) | Def::TyParam(id) | Def::ConstParam(id) | Def::Struct(id) | + Def::StructCtor(id, ..) | Def::Union(id) | Def::Trait(id) | Def::Method(id) | Def::Const(id) | Def::AssociatedConst(id) | Def::Macro(id, ..) | Def::Existential(id) | Def::AssociatedExistential(id) | Def::ForeignTy(id) => { @@ -284,6 +288,14 @@ impl Def { } } + /// Return the `DefId` of this `Def` if it represents a module. + pub fn mod_def_id(&self) -> Option { + match *self { + Def::Mod(id) => Some(id), + _ => None, + } + } + /// A human readable name for the def kind ("function", "module", etc.). pub fn kind_name(&self) -> &'static str { match *self { @@ -312,6 +324,7 @@ impl Def { Def::Const(..) => "constant", Def::AssociatedConst(..) => "associated constant", Def::TyParam(..) => "type parameter", + Def::ConstParam(..) => "const parameter", Def::PrimTy(..) => "builtin type", Def::Local(..) => "local variable", Def::Upvar(..) => "closure capture", diff --git a/src/librustc/hir/def_id.rs b/src/librustc/hir/def_id.rs index 9181076740ba0..ed1c15a73c260 100644 --- a/src/librustc/hir/def_id.rs +++ b/src/librustc/hir/def_id.rs @@ -1,6 +1,6 @@ -use ty; -use ty::TyCtxt; -use hir::map::definitions::FIRST_FREE_HIGH_DEF_INDEX; +use crate::ty; +use crate::ty::TyCtxt; +use crate::hir::map::definitions::FIRST_FREE_HIGH_DEF_INDEX; use rustc_data_structures::indexed_vec::Idx; use serialize; use std::fmt; @@ -229,7 +229,7 @@ impl fmt::Debug for DefId { } impl DefId { - /// Make a local `DefId` with the given index. + /// Makes a local `DefId` from the given `DefIndex`. #[inline] pub fn local(index: DefIndex) -> DefId { DefId { krate: LOCAL_CRATE, index: index } diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index f633703be56d4..4a2bc213fea80 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -4,7 +4,7 @@ //! `super::itemlikevisit::ItemLikeVisitor` trait.** //! //! If you have decided to use this visitor, here are some general -//! notes on how to do it: +//! notes on how to do so: //! //! Each overridden visit method has full control over what //! happens with its node, it can do its own traversal of the node's children, @@ -33,13 +33,11 @@ use syntax::ast::{NodeId, CRATE_NODE_ID, Ident, Name, Attribute}; use syntax_pos::Span; -use hir::*; -use hir::def::Def; -use hir::map::{self, Map}; +use crate::hir::*; +use crate::hir::def::Def; +use crate::hir::map::Map; use super::itemlikevisit::DeepVisitor; -use std::cmp; - #[derive(Copy, Clone)] pub enum FnKind<'a> { /// `#[xxx] pub async/const/extern "Abi" fn foo()` @@ -88,7 +86,7 @@ pub enum NestedVisitorMap<'this, 'tcx: 'this> { /// using this setting. OnlyBodies(&'this Map<'tcx>), - /// Visit all nested things, including item-likes. + /// Visits all nested things, including item-likes. /// /// **This is an unusual choice.** It is used when you want to /// process everything within their lexical context. Typically you @@ -98,7 +96,7 @@ pub enum NestedVisitorMap<'this, 'tcx: 'this> { impl<'this, 'tcx> NestedVisitorMap<'this, 'tcx> { /// Returns the map to use for an "intra item-like" thing (if any). - /// e.g., function body. + /// E.g., function body. pub fn intra(self) -> Option<&'this Map<'tcx>> { match self { NestedVisitorMap::None => None, @@ -108,7 +106,7 @@ impl<'this, 'tcx> NestedVisitorMap<'this, 'tcx> { } /// Returns the map to use for an "item-like" thing (if any). - /// e.g., item, impl-item. + /// E.g., item, impl-item. pub fn inter(self) -> Option<&'this Map<'tcx>> { match self { NestedVisitorMap::None => None, @@ -119,7 +117,7 @@ impl<'this, 'tcx> NestedVisitorMap<'this, 'tcx> { } /// Each method of the Visitor trait is a hook to be potentially -/// overridden. Each method's default implementation recursively visits +/// overridden. Each method's default implementation recursively visits /// the substructure of the input via the corresponding `walk` method; /// e.g., the `visit_mod` method by default calls `intravisit::walk_mod`. /// @@ -131,7 +129,7 @@ impl<'this, 'tcx> NestedVisitorMap<'this, 'tcx> { /// on `visit_nested_item` for details on how to visit nested items. /// /// If you want to ensure that your code handles every variant -/// explicitly, you need to override each method. (And you also need +/// explicitly, you need to override each method. (And you also need /// to monitor future changes to `Visitor` in case a new method with a /// new default implementation gets introduced.) pub trait Visitor<'v> : Sized { @@ -205,7 +203,7 @@ pub trait Visitor<'v> : Sized { } } - /// Visit the top-level item and (optionally) nested items / impl items. See + /// Visits the top-level item and (optionally) nested items / impl items. See /// `visit_nested_item` for details. fn visit_item(&mut self, i: &'v Item) { walk_item(self, i) @@ -216,7 +214,7 @@ pub trait Visitor<'v> : Sized { } /// When invoking `visit_all_item_likes()`, you need to supply an - /// item-like visitor. This method converts a "intra-visit" + /// item-like visitor. This method converts a "intra-visit" /// visitor into an item-like visitor that walks the entire tree. /// If you use this, you probably don't want to process the /// contents of nested item-like things, since the outer loop will @@ -260,9 +258,6 @@ pub trait Visitor<'v> : Sized { fn visit_pat(&mut self, p: &'v Pat) { walk_pat(self, p) } - fn visit_decl(&mut self, d: &'v Decl) { - walk_decl(self, d) - } fn visit_anon_const(&mut self, c: &'v AnonConst) { walk_anon_const(self, c) } @@ -339,6 +334,7 @@ pub trait Visitor<'v> : Sized { match generic_arg { GenericArg::Lifetime(lt) => self.visit_lifetime(lt), GenericArg::Type(ty) => self.visit_ty(ty), + GenericArg::Const(ct) => self.visit_anon_const(&ct.value), } } fn visit_lifetime(&mut self, lifetime: &'v Lifetime) { @@ -699,7 +695,7 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) { PatKind::Ref(ref subpattern, _) => { visitor.visit_pat(subpattern) } - PatKind::Binding(_, canonical_id, ident, ref optional_subpattern) => { + PatKind::Binding(_, canonical_id, _hir_id, ident, ref optional_subpattern) => { visitor.visit_def_mention(Def::Local(canonical_id)); visitor.visit_ident(ident); walk_list!(visitor, visit_pat, optional_subpattern); @@ -757,6 +753,7 @@ pub fn walk_generic_param<'v, V: Visitor<'v>>(visitor: &mut V, param: &'v Generi match param.kind { GenericParamKind::Lifetime { .. } => {} GenericParamKind::Type { ref default, .. } => walk_list!(visitor, visit_ty, default), + GenericParamKind::Const { ref ty } => visitor.visit_ty(ty), } walk_list!(visitor, visit_param_bound, ¶m.bounds); } @@ -953,26 +950,17 @@ pub fn walk_block<'v, V: Visitor<'v>>(visitor: &mut V, block: &'v Block) { } pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt) { + visitor.visit_id(statement.id); match statement.node { - StmtKind::Decl(ref declaration, id) => { - visitor.visit_id(id); - visitor.visit_decl(declaration) - } - StmtKind::Expr(ref expression, id) | - StmtKind::Semi(ref expression, id) => { - visitor.visit_id(id); + StmtKind::Local(ref local) => visitor.visit_local(local), + StmtKind::Item(item) => visitor.visit_nested_item(item), + StmtKind::Expr(ref expression) | + StmtKind::Semi(ref expression) => { visitor.visit_expr(expression) } } } -pub fn walk_decl<'v, V: Visitor<'v>>(visitor: &mut V, declaration: &'v Decl) { - match declaration.node { - DeclKind::Local(ref local) => visitor.visit_local(local), - DeclKind::Item(item) => visitor.visit_nested_item(item), - } -} - pub fn walk_anon_const<'v, V: Visitor<'v>>(visitor: &mut V, constant: &'v AnonConst) { visitor.visit_id(constant.id); visitor.visit_nested_body(constant.body); @@ -1133,57 +1121,3 @@ pub fn walk_defaultness<'v, V: Visitor<'v>>(_: &mut V, _: &'v Defaultness) { // the right thing to do, should content be added in the future, // would be to walk it. } - -#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug)] -pub struct IdRange { - pub min: NodeId, - pub max: NodeId, -} - -impl IdRange { - pub fn max() -> IdRange { - IdRange { - min: NodeId::MAX, - max: NodeId::from_u32(0), - } - } - - pub fn empty(&self) -> bool { - self.min >= self.max - } - - pub fn contains(&self, id: NodeId) -> bool { - id >= self.min && id < self.max - } - - pub fn add(&mut self, id: NodeId) { - self.min = cmp::min(self.min, id); - self.max = cmp::max(self.max, NodeId::from_u32(id.as_u32() + 1)); - } -} - - -pub struct IdRangeComputingVisitor<'a, 'hir: 'a> { - result: IdRange, - map: &'a map::Map<'hir>, -} - -impl<'a, 'hir> IdRangeComputingVisitor<'a, 'hir> { - pub fn new(map: &'a map::Map<'hir>) -> IdRangeComputingVisitor<'a, 'hir> { - IdRangeComputingVisitor { result: IdRange::max(), map: map } - } - - pub fn result(&self) -> IdRange { - self.result - } -} - -impl<'a, 'hir> Visitor<'hir> for IdRangeComputingVisitor<'a, 'hir> { - fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'hir> { - NestedVisitorMap::OnlyBodies(&self.map) - } - - fn visit_id(&mut self, id: NodeId) { - self.result.add(id); - } -} diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 8badcbfc1b301..9f48a628274db 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -3,24 +3,24 @@ //! Since the AST and HIR are fairly similar, this is mostly a simple procedure, //! much like a fold. Where lowering involves a bit more work things get more //! interesting and there are some invariants you should know about. These mostly -//! concern spans and ids. +//! concern spans and IDs. //! //! Spans are assigned to AST nodes during parsing and then are modified during //! expansion to indicate the origin of a node and the process it went through -//! being expanded. Ids are assigned to AST nodes just before lowering. +//! being expanded. IDs are assigned to AST nodes just before lowering. //! -//! For the simpler lowering steps, ids and spans should be preserved. Unlike +//! For the simpler lowering steps, IDs and spans should be preserved. Unlike //! expansion we do not preserve the process of lowering in the spans, so spans //! should not be modified here. When creating a new node (as opposed to -//! 'folding' an existing one), then you create a new id using `next_id()`. +//! 'folding' an existing one), then you create a new ID using `next_id()`. //! -//! You must ensure that ids are unique. That means that you should only use the -//! id from an AST node in a single HIR node (you can assume that AST node ids -//! are unique). Every new node must have a unique id. Avoid cloning HIR nodes. -//! If you do, you must then set the new node's id to a fresh one. +//! You must ensure that IDs are unique. That means that you should only use the +//! ID from an AST node in a single HIR node (you can assume that AST node IDs +//! are unique). Every new node must have a unique ID. Avoid cloning HIR nodes. +//! If you do, you must then set the new node's ID to a fresh one. //! //! Spans are used for error messages and for tools to map semantics back to -//! source code. It is therefore not as important with spans as ids to be strict +//! source code. It is therefore not as important with spans as IDs to be strict //! about use (you can't break the compiler by screwing up a span). Obviously, a //! HIR node can only have a single span. But multiple nodes can have the same //! span and spans don't need to be kept in order, etc. Where code is preserved @@ -30,23 +30,25 @@ //! get confused if the spans from leaf AST nodes occur in multiple places //! in the HIR, especially for multiple identifiers. -use dep_graph::DepGraph; -use hir::{self, ParamName}; -use hir::HirVec; -use hir::map::{DefKey, DefPathData, Definitions}; -use hir::def_id::{DefId, DefIndex, DefIndexAddressSpace, CRATE_DEF_INDEX}; -use hir::def::{Def, PathResolution, PerNS}; -use hir::GenericArg; -use lint::builtin::{self, PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES, +use crate::dep_graph::DepGraph; +use crate::hir::{self, ParamName}; +use crate::hir::HirVec; +use crate::hir::map::{DefKey, DefPathData, Definitions}; +use crate::hir::def_id::{DefId, DefIndex, DefIndexAddressSpace, CRATE_DEF_INDEX}; +use crate::hir::def::{Def, PathResolution, PerNS}; +use crate::hir::{GenericArg, ConstArg}; +use crate::lint::builtin::{self, PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES, ELIDED_LIFETIMES_IN_PATHS}; -use middle::cstore::CrateStore; +use crate::middle::cstore::CrateStore; +use crate::session::Session; +use crate::session::config::nightly_options; +use crate::util::common::FN_OUTPUT_NAME; +use crate::util::nodemap::{DefIdMap, NodeMap}; +use errors::Applicability; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::indexed_vec::IndexVec; use rustc_data_structures::thin_vec::ThinVec; -use session::Session; -use session::config::nightly_options; -use util::common::FN_OUTPUT_NAME; -use util::nodemap::{DefIdMap, NodeMap}; +use rustc_data_structures::sync::Lrc; use std::collections::{BTreeSet, BTreeMap}; use std::fmt::Debug; @@ -143,7 +145,7 @@ pub trait Resolver { is_value: bool, ) -> hir::Path; - /// Obtain the resolution for a node-id. + /// Obtain the resolution for a `NodeId`. fn get_resolution(&mut self, id: NodeId) -> Option; /// Obtain the possible resolutions for the given `use` statement. @@ -272,10 +274,10 @@ enum ParenthesizedGenericArgs { } /// What to do when we encounter an **anonymous** lifetime -/// reference. Anonymous lifetime references come in two flavors. You +/// reference. Anonymous lifetime references come in two flavors. You /// have implicit, or fully elided, references to lifetimes, like the /// one in `&T` or `Ref`, and you have `'_` lifetimes, like `&'_ T` -/// or `Ref<'_, T>`. These often behave the same, but not always: +/// or `Ref<'_, T>`. These often behave the same, but not always: /// /// - certain usages of implicit references are deprecated, like /// `Ref`, and we sometimes just give hard errors in those cases @@ -680,13 +682,20 @@ impl<'a> LoweringContext<'a> { Ident::with_empty_ctxt(Symbol::gensym(s)) } - fn allow_internal_unstable(&self, reason: CompilerDesugaringKind, span: Span) -> Span { + /// Reuses the span but adds information like the kind of the desugaring and features that are + /// allowed inside this span. + fn mark_span_with_reason( + &self, + reason: CompilerDesugaringKind, + span: Span, + allow_internal_unstable: Option>, + ) -> Span { let mark = Mark::fresh(Mark::root()); mark.set_expn_info(source_map::ExpnInfo { call_site: span, def_site: Some(span), format: source_map::CompilerDesugaring(reason), - allow_internal_unstable: true, + allow_internal_unstable, allow_internal_unsafe: false, local_inner_macros: false, edition: source_map::hygiene::default_edition(), @@ -740,7 +749,7 @@ impl<'a> LoweringContext<'a> { let params = lifetimes_to_define .into_iter() .map(|(span, hir_name)| { - let def_node_id = self.next_id().node_id; + let LoweredNodeId { node_id, hir_id } = self.next_id(); // Get the name we'll use to make the def-path. Note // that collisions are ok here and this shouldn't @@ -763,7 +772,7 @@ impl<'a> LoweringContext<'a> { // Add a definition for the in-band lifetime def. self.resolver.definitions().create_def_with_parent( parent_id.index, - def_node_id, + node_id, DefPathData::LifetimeParam(str_name), DefIndexAddressSpace::High, Mark::root(), @@ -771,7 +780,8 @@ impl<'a> LoweringContext<'a> { ); hir::GenericParam { - id: def_node_id, + id: node_id, + hir_id, name: hir_name, attrs: hir_vec![], bounds: hir_vec![], @@ -962,7 +972,13 @@ impl<'a> LoweringContext<'a> { attrs: ThinVec::new(), }; - let unstable_span = self.allow_internal_unstable(CompilerDesugaringKind::Async, span); + let unstable_span = self.mark_span_with_reason( + CompilerDesugaringKind::Async, + span, + Some(vec![ + Symbol::intern("gen_future"), + ].into()), + ); let gen_future = self.expr_std_path( unstable_span, &["future", "from_generator"], None, ThinVec::new()); hir::ExprKind::Call(P(gen_future), hir_vec![generator]) @@ -1137,8 +1153,11 @@ impl<'a> LoweringContext<'a> { fn lower_ty_binding(&mut self, b: &TypeBinding, itctx: ImplTraitContext<'_>) -> hir::TypeBinding { + let LoweredNodeId { node_id, hir_id } = self.lower_node_id(b.id); + hir::TypeBinding { - id: self.lower_node_id(b.id).node_id, + id: node_id, + hir_id, ident: b.ident, ty: self.lower_ty(&b.ty, itctx), span: b.span, @@ -1152,6 +1171,12 @@ impl<'a> LoweringContext<'a> { match arg { ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime(<)), ast::GenericArg::Type(ty) => GenericArg::Type(self.lower_ty_direct(&ty, itctx)), + ast::GenericArg::Const(ct) => { + GenericArg::Const(ConstArg { + value: self.lower_anon_const(&ct), + span: ct.value.span, + }) + } } } @@ -1260,7 +1285,7 @@ impl<'a> LoweringContext<'a> { ) } ImplTraitContext::Universal(in_band_ty_params) => { - self.lower_node_id(def_node_id); + let LoweredNodeId { node_id: _, hir_id } = self.lower_node_id(def_node_id); // Add a definition for the in-band `Param`. let def_index = self .resolver @@ -1276,6 +1301,7 @@ impl<'a> LoweringContext<'a> { let ident = Ident::from_str(&pprust::ty_to_string(t)).with_span_pos(span); in_band_ty_params.push(hir::GenericParam { id: def_node_id, + hir_id, name: ParamName::Plain(ident), pure_wrt_drop: false, attrs: hir_vec![], @@ -1345,9 +1371,10 @@ impl<'a> LoweringContext<'a> { // desugaring that explicitly states that we don't want to track that. // Not tracking it makes lints in rustc and clippy very fragile as // frequently opened issues show. - let exist_ty_span = self.allow_internal_unstable( + let exist_ty_span = self.mark_span_with_reason( CompilerDesugaringKind::ExistentialReturnType, span, + None, ); let exist_ty_def_index = self @@ -1367,11 +1394,13 @@ impl<'a> LoweringContext<'a> { ); self.with_hir_id_owner(exist_ty_node_id, |lctx| { + let LoweredNodeId { node_id, hir_id } = lctx.next_id(); let exist_ty_item_kind = hir::ItemKind::Existential(hir::ExistTy { generics: hir::Generics { params: lifetime_defs, where_clause: hir::WhereClause { - id: lctx.next_id().node_id, + id: node_id, + hir_id, predicates: Vec::new().into(), }, span, @@ -1504,8 +1533,10 @@ impl<'a> LoweringContext<'a> { && !self.already_defined_lifetimes.contains(&name) { self.already_defined_lifetimes.insert(name); + let LoweredNodeId { node_id, hir_id } = self.context.next_id(); self.output_lifetimes.push(hir::GenericArg::Lifetime(hir::Lifetime { - id: self.context.next_id().node_id, + id: node_id, + hir_id, span: lifetime.span, name, })); @@ -1514,7 +1545,8 @@ impl<'a> LoweringContext<'a> { // definitions will go into the explicit `existential type` // declaration and thus need to have their owner set to that item let def_node_id = self.context.sess.next_node_id(); - let _ = self.context.lower_node_id_with_owner(def_node_id, self.exist_ty_id); + let LoweredNodeId { node_id: _, hir_id } = + self.context.lower_node_id_with_owner(def_node_id, self.exist_ty_id); self.context.resolver.definitions().create_def_with_parent( self.parent, def_node_id, @@ -1538,6 +1570,7 @@ impl<'a> LoweringContext<'a> { self.output_lifetime_params.push(hir::GenericParam { id: def_node_id, + hir_id, name, span: lifetime.span, pure_wrt_drop: false, @@ -1806,7 +1839,7 @@ impl<'a> LoweringContext<'a> { explicit_owner: Option, ) -> hir::PathSegment { let (mut generic_args, infer_types) = if let Some(ref generic_args) = segment.args { - let msg = "parenthesized parameters may only be used with a trait"; + let msg = "parenthesized type parameters may only be used with a `Fn` trait"; match **generic_args { GenericArgs::AngleBracketed(ref data) => { self.lower_angle_bracketed_parameter_data(data, param_mode, itctx) @@ -1823,10 +1856,25 @@ impl<'a> LoweringContext<'a> { (hir::GenericArgs::none(), true) } ParenthesizedGenericArgs::Err => { - struct_span_err!(self.sess, data.span, E0214, "{}", msg) - .span_label(data.span, "only traits may use parentheses") - .emit(); - (hir::GenericArgs::none(), true) + let mut err = struct_span_err!(self.sess, data.span, E0214, "{}", msg); + err.span_label(data.span, "only `Fn` traits may use parentheses"); + if let Ok(snippet) = self.sess.source_map().span_to_snippet(data.span) { + // Do not suggest going from `Trait()` to `Trait<>` + if data.inputs.len() > 0 { + err.span_suggestion( + data.span, + "use angle brackets instead", + format!("<{}>", &snippet[1..snippet.len() - 1]), + Applicability::MaybeIncorrect, + ); + } + }; + err.emit(); + (self.lower_angle_bracketed_parameter_data( + &data.as_angle_bracketed_args(), + param_mode, + itctx).0, + false) } }, } @@ -1888,6 +1936,7 @@ impl<'a> LoweringContext<'a> { hir::PathSegment::new( segment.ident, Some(id.node_id), + Some(id.hir_id), Some(def), generic_args, infer_types, @@ -1915,7 +1964,7 @@ impl<'a> LoweringContext<'a> { fn lower_parenthesized_parameter_data( &mut self, - data: &ParenthesisedArgs, + data: &ParenthesizedArgs, ) -> (hir::GenericArgs, bool) { // Switch to `PassThrough` mode for anonymous lifetimes: this // means that we permit things like `&Ref`, where `Ref` has @@ -1925,7 +1974,7 @@ impl<'a> LoweringContext<'a> { self.with_anonymous_lifetime_mode( AnonymousLifetimeMode::PassThrough, |this| { - let &ParenthesisedArgs { ref inputs, ref output, span } = data; + let &ParenthesizedArgs { ref inputs, ref output, span } = data; let inputs = inputs .iter() .map(|ty| this.lower_ty_direct(ty, ImplTraitContext::disallowed())) @@ -1934,13 +1983,15 @@ impl<'a> LoweringContext<'a> { let LoweredNodeId { node_id, hir_id } = this.next_id(); hir::Ty { node: hir::TyKind::Tup(tys), id: node_id, hir_id, span } }; + let LoweredNodeId { node_id, hir_id } = this.next_id(); ( hir::GenericArgs { args: hir_vec![GenericArg::Type(mk_tup(this, inputs, span))], bindings: hir_vec![ hir::TypeBinding { - id: this.next_id().node_id, + id: node_id, + hir_id, ident: Ident::from_str(FN_OUTPUT_NAME), ty: output .as_ref() @@ -1957,7 +2008,7 @@ impl<'a> LoweringContext<'a> { ) } - fn lower_local(&mut self, l: &Local) -> (P, SmallVec<[hir::ItemId; 1]>) { + fn lower_local(&mut self, l: &Local) -> (hir::Local, SmallVec<[hir::ItemId; 1]>) { let LoweredNodeId { node_id, hir_id } = self.lower_node_id(l.id); let mut ids = SmallVec::<[hir::ItemId; 1]>::new(); if self.sess.features_untracked().impl_trait_in_bindings { @@ -1967,7 +2018,7 @@ impl<'a> LoweringContext<'a> { } } let parent_def_id = DefId::local(self.current_hir_id_owner.last().unwrap().0); - (P(hir::Local { + (hir::Local { id: node_id, hir_id, ty: l.ty @@ -1984,7 +2035,7 @@ impl<'a> LoweringContext<'a> { span: l.span, attrs: l.attrs.clone(), source: hir::LocalSource::Normal, - }), ids) + }, ids) } fn lower_mutability(&mut self, m: Mutability) -> hir::Mutability { @@ -2270,7 +2321,7 @@ impl<'a> LoweringContext<'a> { let LoweredNodeId { node_id, hir_id } = this.next_id(); P(hir::Ty { id: node_id, - hir_id: hir_id, + hir_id, node: hir::TyKind::Tup(hir_vec![]), span: *span, }) @@ -2278,12 +2329,14 @@ impl<'a> LoweringContext<'a> { }; // "" + let LoweredNodeId { node_id, hir_id } = this.next_id(); let future_params = P(hir::GenericArgs { args: hir_vec![], bindings: hir_vec![hir::TypeBinding { ident: Ident::from_str(FN_OUTPUT_NAME), ty: output_ty, - id: this.next_id().node_id, + id: node_id, + hir_id, span, }], parenthesized: false, @@ -2309,8 +2362,9 @@ impl<'a> LoweringContext<'a> { ]; if let Some((name, span)) = bound_lifetime { + let LoweredNodeId { node_id, hir_id } = this.next_id(); bounds.push(hir::GenericBound::Outlives( - hir::Lifetime { id: this.next_id().node_id, name, span })); + hir::Lifetime { id: node_id, hir_id, name, span })); } hir::HirVec::from(bounds) @@ -2377,8 +2431,11 @@ impl<'a> LoweringContext<'a> { span: Span, name: hir::LifetimeName, ) -> hir::Lifetime { + let LoweredNodeId { node_id, hir_id } = self.lower_node_id(id); + hir::Lifetime { - id: self.lower_node_id(id).node_id, + id: node_id, + hir_id, span, name: name, } @@ -2405,7 +2462,7 @@ impl<'a> LoweringContext<'a> { |this| this.lower_param_bounds(¶m.bounds, itctx.reborrow()), ); - match param.kind { + let (name, kind) = match param.kind { GenericParamKind::Lifetime => { let was_collecting_in_band = self.is_collecting_in_band_lifetimes; self.is_collecting_in_band_lifetimes = false; @@ -2421,21 +2478,14 @@ impl<'a> LoweringContext<'a> { | hir::LifetimeName::Static => hir::ParamName::Plain(lt.name.ident()), hir::LifetimeName::Error => ParamName::Error, }; - let param = hir::GenericParam { - id: lt.id, - name: param_name, - span: lt.span, - pure_wrt_drop: attr::contains_name(¶m.attrs, "may_dangle"), - attrs: self.lower_attrs(¶m.attrs), - bounds, - kind: hir::GenericParamKind::Lifetime { - kind: hir::LifetimeParamKind::Explicit, - } + + let kind = hir::GenericParamKind::Lifetime { + kind: hir::LifetimeParamKind::Explicit }; self.is_collecting_in_band_lifetimes = was_collecting_in_band; - param + (param_name, kind) } GenericParamKind::Type { ref default, .. } => { // Don't expose `Self` (recovered "keyword used as ident" parse error). @@ -2455,24 +2505,36 @@ impl<'a> LoweringContext<'a> { .collect(); } - hir::GenericParam { - id: self.lower_node_id(param.id).node_id, - name: hir::ParamName::Plain(ident), - pure_wrt_drop: attr::contains_name(¶m.attrs, "may_dangle"), - attrs: self.lower_attrs(¶m.attrs), - bounds, - span: ident.span, - kind: hir::GenericParamKind::Type { - default: default.as_ref().map(|x| { - self.lower_ty(x, ImplTraitContext::disallowed()) - }), - synthetic: param.attrs.iter() - .filter(|attr| attr.check_name("rustc_synthetic")) - .map(|_| hir::SyntheticTyParamKind::ImplTrait) - .next(), - } - } + let kind = hir::GenericParamKind::Type { + default: default.as_ref().map(|x| { + self.lower_ty(x, ImplTraitContext::disallowed()) + }), + synthetic: param.attrs.iter() + .filter(|attr| attr.check_name("rustc_synthetic")) + .map(|_| hir::SyntheticTyParamKind::ImplTrait) + .next(), + }; + + (hir::ParamName::Plain(ident), kind) + } + GenericParamKind::Const { ref ty } => { + (hir::ParamName::Plain(param.ident), hir::GenericParamKind::Const { + ty: self.lower_ty(&ty, ImplTraitContext::disallowed()), + }) } + }; + + let LoweredNodeId { node_id, hir_id } = self.lower_node_id(param.id); + + hir::GenericParam { + id: node_id, + hir_id, + name, + span: param.ident.span, + pure_wrt_drop: attr::contains_name(¶m.attrs, "may_dangle"), + attrs: self.lower_attrs(¶m.attrs), + bounds, + kind, } } @@ -2546,8 +2608,11 @@ impl<'a> LoweringContext<'a> { self.with_anonymous_lifetime_mode( AnonymousLifetimeMode::ReportError, |this| { + let LoweredNodeId { node_id, hir_id } = this.lower_node_id(wc.id); + hir::WhereClause { - id: this.lower_node_id(wc.id).node_id, + id: node_id, + hir_id, predicates: wc.predicates .iter() .map(|predicate| this.lower_where_predicate(predicate)) @@ -2606,34 +2671,53 @@ impl<'a> LoweringContext<'a> { ref lhs_ty, ref rhs_ty, span, - }) => hir::WherePredicate::EqPredicate(hir::WhereEqPredicate { - id: self.lower_node_id(id).node_id, - lhs_ty: self.lower_ty(lhs_ty, ImplTraitContext::disallowed()), - rhs_ty: self.lower_ty(rhs_ty, ImplTraitContext::disallowed()), - span, - }), + }) => { + let LoweredNodeId { node_id, hir_id } = self.lower_node_id(id); + + hir::WherePredicate::EqPredicate(hir::WhereEqPredicate { + id: node_id, + hir_id, + lhs_ty: self.lower_ty(lhs_ty, ImplTraitContext::disallowed()), + rhs_ty: self.lower_ty(rhs_ty, ImplTraitContext::disallowed()), + span, + }) + }, } } fn lower_variant_data(&mut self, vdata: &VariantData) -> hir::VariantData { match *vdata { - VariantData::Struct(ref fields, id) => hir::VariantData::Struct( - fields - .iter() - .enumerate() - .map(|f| self.lower_struct_field(f)) - .collect(), - self.lower_node_id(id).node_id, - ), - VariantData::Tuple(ref fields, id) => hir::VariantData::Tuple( - fields - .iter() - .enumerate() - .map(|f| self.lower_struct_field(f)) - .collect(), - self.lower_node_id(id).node_id, - ), - VariantData::Unit(id) => hir::VariantData::Unit(self.lower_node_id(id).node_id), + VariantData::Struct(ref fields, id) => { + let LoweredNodeId { node_id, hir_id } = self.lower_node_id(id); + + hir::VariantData::Struct( + fields + .iter() + .enumerate() + .map(|f| self.lower_struct_field(f)) + .collect(), + node_id, + hir_id, + ) + }, + VariantData::Tuple(ref fields, id) => { + let LoweredNodeId { node_id, hir_id } = self.lower_node_id(id); + + hir::VariantData::Tuple( + fields + .iter() + .enumerate() + .map(|f| self.lower_struct_field(f)) + .collect(), + node_id, + hir_id, + ) + }, + VariantData::Unit(id) => { + let LoweredNodeId { node_id, hir_id } = self.lower_node_id(id); + + hir::VariantData::Unit(node_id, hir_id) + }, } } @@ -2673,9 +2757,12 @@ impl<'a> LoweringContext<'a> { } fn lower_struct_field(&mut self, (index, f): (usize, &StructField)) -> hir::StructField { + let LoweredNodeId { node_id, hir_id } = self.lower_node_id(f.id); + hir::StructField { span: f.span, - id: self.lower_node_id(f.id).node_id, + id: node_id, + hir_id, ident: match f.ident { Some(ident) => ident, // FIXME(jseyfried): positional field hygiene @@ -2688,8 +2775,11 @@ impl<'a> LoweringContext<'a> { } fn lower_field(&mut self, f: &Field) -> hir::Field { + let LoweredNodeId { node_id, hir_id } = self.next_id(); + hir::Field { - id: self.next_id().node_id, + id: node_id, + hir_id, ident: f.ident, expr: P(self.lower_expr(&f.expr)), span: f.span, @@ -3205,7 +3295,7 @@ impl<'a> LoweringContext<'a> { /// Paths like the visibility path in `pub(super) use foo::{bar, baz}` are repeated /// many times in the HIR tree; for each occurrence, we need to assign distinct - /// node-ids. (See e.g., #56128.) + /// `NodeId`s. (See, e.g., #56128.) fn renumber_segment_ids(&mut self, path: &P) -> P { debug!("renumber_segment_ids(path = {:?})", path); let mut path = path.clone(); @@ -3447,11 +3537,13 @@ impl<'a> LoweringContext<'a> { if !def.legacy || attr::contains_name(&i.attrs, "macro_export") || attr::contains_name(&i.attrs, "rustc_doc_only_macro") { let body = self.lower_token_stream(def.stream()); + let hir_id = self.lower_node_id(i.id).hir_id; self.exported_macros.push(hir::MacroDef { name: ident.name, vis, attrs, id: i.id, + hir_id, span: i.span, body, legacy: def.legacy, @@ -3476,10 +3568,11 @@ impl<'a> LoweringContext<'a> { } fn lower_foreign_item(&mut self, i: &ForeignItem) -> hir::ForeignItem { - let node_id = self.lower_node_id(i.id).node_id; + let LoweredNodeId { node_id, hir_id } = self.lower_node_id(i.id); let def_id = self.resolver.definitions().local_def_id(node_id); hir::ForeignItem { id: node_id, + hir_id, ident: i.ident, attrs: self.lower_attrs(&i.attrs), node: match i.node { @@ -3616,9 +3709,11 @@ impl<'a> LoweringContext<'a> { Some(Def::Local(id)) => id, _ => p.id, }; + let hir_id = self.lower_node_id(canonical_id).hir_id; hir::PatKind::Binding( self.lower_binding_mode(binding_mode), canonical_id, + hir_id, ident, sub.as_ref().map(|x| self.lower_pat(x)), ) @@ -3669,14 +3764,19 @@ impl<'a> LoweringContext<'a> { let fs = fields .iter() - .map(|f| Spanned { - span: f.span, - node: hir::FieldPat { - id: self.next_id().node_id, - ident: f.node.ident, - pat: self.lower_pat(&f.node.pat), - is_shorthand: f.node.is_shorthand, - }, + .map(|f| { + let LoweredNodeId { node_id, hir_id } = self.next_id(); + + Spanned { + span: f.span, + node: hir::FieldPat { + id: node_id, + hir_id, + ident: f.node.ident, + pat: self.lower_pat(&f.node.pat), + is_shorthand: f.node.is_shorthand, + }, + } }) .collect(); hir::PatKind::Struct(qpath, fs, etc) @@ -3752,7 +3852,7 @@ impl<'a> LoweringContext<'a> { hir::ExprKind::Call(f, args.iter().map(|x| self.lower_expr(x)).collect()) } ExprKind::MethodCall(ref seg, ref args) => { - let hir_seg = self.lower_path_segment( + let hir_seg = P(self.lower_path_segment( e.span, seg, ParamMode::Optional, @@ -3760,7 +3860,7 @@ impl<'a> LoweringContext<'a> { ParenthesizedGenericArgs::Err, ImplTraitContext::disallowed(), None, - ); + )); let args = args.iter().map(|x| self.lower_expr(x)).collect(); hir::ExprKind::MethodCall(hir_seg, seg.ident.span, args) } @@ -3775,7 +3875,7 @@ impl<'a> LoweringContext<'a> { let ohs = P(self.lower_expr(ohs)); hir::ExprKind::Unary(op, ohs) } - ExprKind::Lit(ref l) => hir::ExprKind::Lit(P((*l).clone())), + ExprKind::Lit(ref l) => hir::ExprKind::Lit((*l).clone()), ExprKind::Cast(ref expr, ref ty) => { let expr = P(self.lower_expr(expr)); hir::ExprKind::Cast(expr, self.lower_ty(ty, ImplTraitContext::disallowed())) @@ -3835,8 +3935,13 @@ impl<'a> LoweringContext<'a> { }), ExprKind::TryBlock(ref body) => { self.with_catch_scope(body.id, |this| { - let unstable_span = - this.allow_internal_unstable(CompilerDesugaringKind::TryBlock, body.span); + let unstable_span = this.mark_span_with_reason( + CompilerDesugaringKind::TryBlock, + body.span, + Some(vec![ + Symbol::intern("try_trait"), + ].into()), + ); let mut block = this.lower_block(body, true).into_inner(); let tail = block.expr.take().map_or_else( || { @@ -4036,7 +4141,7 @@ impl<'a> LoweringContext<'a> { node: if is_unit { hir::ExprKind::Path(struct_path) } else { - hir::ExprKind::Struct(struct_path, fields, None) + hir::ExprKind::Struct(P(struct_path), fields, None) }, span: e.span, attrs: e.attrs.clone(), @@ -4108,13 +4213,13 @@ impl<'a> LoweringContext<'a> { hir::ExprKind::InlineAsm(P(hir_asm), outputs, inputs) } ExprKind::Struct(ref path, ref fields, ref maybe_expr) => hir::ExprKind::Struct( - self.lower_qpath( + P(self.lower_qpath( e.id, &None, path, ParamMode::Optional, ImplTraitContext::disallowed(), - ), + )), fields.iter().map(|x| self.lower_field(x)).collect(), maybe_expr.as_ref().map(|x| P(self.lower_expr(x))), ), @@ -4268,9 +4373,10 @@ impl<'a> LoweringContext<'a> { // expand let head = self.lower_expr(head); let head_sp = head.span; - let desugared_span = self.allow_internal_unstable( + let desugared_span = self.mark_span_with_reason( CompilerDesugaringKind::ForLoop, head_sp, + None, ); let iter = self.str_to_ident("iter"); @@ -4331,10 +4437,13 @@ impl<'a> LoweringContext<'a> { ThinVec::new(), )) }; - let match_stmt = respan( - head_sp, - hir::StmtKind::Expr(match_expr, self.next_id().node_id) - ); + let LoweredNodeId { node_id, hir_id } = self.next_id(); + let match_stmt = hir::Stmt { + id: node_id, + hir_id, + node: hir::StmtKind::Expr(match_expr), + span: head_sp, + }; let next_expr = P(self.expr_ident(head_sp, next_ident, next_pat.id)); @@ -4357,10 +4466,13 @@ impl<'a> LoweringContext<'a> { let body_block = self.with_loop_scope(e.id, |this| this.lower_block(body, false)); let body_expr = P(self.expr_block(body_block, ThinVec::new())); - let body_stmt = respan( - body.span, - hir::StmtKind::Expr(body_expr, self.next_id().node_id) - ); + let LoweredNodeId { node_id, hir_id } = self.next_id(); + let body_stmt = hir::Stmt { + id: node_id, + hir_id, + node: hir::StmtKind::Expr(body_expr), + span: body.span, + }; let loop_block = P(self.block_all( e.span, @@ -4427,8 +4539,13 @@ impl<'a> LoweringContext<'a> { // return Try::from_error(From::from(err)), // } - let unstable_span = - self.allow_internal_unstable(CompilerDesugaringKind::QuestionMark, e.span); + let unstable_span = self.mark_span_with_reason( + CompilerDesugaringKind::QuestionMark, + e.span, + Some(vec![ + Symbol::intern("try_trait") + ].into()), + ); // `Try::into_result()` let discr = { @@ -4533,26 +4650,26 @@ impl<'a> LoweringContext<'a> { let (l, item_ids) = self.lower_local(l); let mut ids: SmallVec<[hir::Stmt; 1]> = item_ids .into_iter() - .map(|item_id| Spanned { - node: hir::StmtKind::Decl( - P(Spanned { - node: hir::DeclKind::Item(item_id), - span: s.span, - }), - self.next_id().node_id, - ), - span: s.span, + .map(|item_id| { + let LoweredNodeId { node_id, hir_id } = self.next_id(); + + hir::Stmt { + id: node_id, + hir_id, + node: hir::StmtKind::Item(item_id), + span: s.span, + } }) .collect(); - ids.push(Spanned { - node: hir::StmtKind::Decl( - P(Spanned { - node: hir::DeclKind::Local(l), - span: s.span, - }), - self.lower_node_id(s.id).node_id, - ), - span: s.span, + ids.push({ + let LoweredNodeId { node_id, hir_id } = self.lower_node_id(s.id); + + hir::Stmt { + id: node_id, + hir_id, + node: hir::StmtKind::Local(P(l)), + span: s.span, + } }); return ids; }, @@ -4561,27 +4678,39 @@ impl<'a> LoweringContext<'a> { let mut id = Some(s.id); return self.lower_item_id(it) .into_iter() - .map(|item_id| Spanned { - node: hir::StmtKind::Decl( - P(Spanned { - node: hir::DeclKind::Item(item_id), - span: s.span, - }), - id.take() - .map(|id| self.lower_node_id(id).node_id) - .unwrap_or_else(|| self.next_id().node_id), - ), - span: s.span, + .map(|item_id| { + let LoweredNodeId { node_id, hir_id } = id.take() + .map(|id| self.lower_node_id(id)) + .unwrap_or_else(|| self.next_id()); + + hir::Stmt { + id: node_id, + hir_id, + node: hir::StmtKind::Item(item_id), + span: s.span, + } }) .collect(); } - StmtKind::Expr(ref e) => Spanned { - node: hir::StmtKind::Expr(P(self.lower_expr(e)), self.lower_node_id(s.id).node_id), - span: s.span, + StmtKind::Expr(ref e) => { + let LoweredNodeId { node_id, hir_id } = self.lower_node_id(s.id); + + hir::Stmt { + id: node_id, + hir_id, + node: hir::StmtKind::Expr(P(self.lower_expr(e))), + span: s.span, + } }, - StmtKind::Semi(ref e) => Spanned { - node: hir::StmtKind::Semi(P(self.lower_expr(e)), self.lower_node_id(s.id).node_id), - span: s.span, + StmtKind::Semi(ref e) => { + let LoweredNodeId { node_id, hir_id } = self.lower_node_id(s.id); + + hir::Stmt { + id: node_id, + hir_id, + node: hir::StmtKind::Semi(P(self.lower_expr(e))), + span: s.span, + } }, StmtKind::Mac(..) => panic!("Shouldn't exist here"), }] @@ -4692,8 +4821,11 @@ impl<'a> LoweringContext<'a> { } fn field(&mut self, ident: Ident, expr: P, span: Span) -> hir::Field { + let LoweredNodeId { node_id, hir_id } = self.next_id(); + hir::Field { - id: self.next_id().node_id, + id: node_id, + hir_id, ident, span, expr, @@ -4795,7 +4927,7 @@ impl<'a> LoweringContext<'a> { ) -> hir::Stmt { let LoweredNodeId { node_id, hir_id } = self.next_id(); - let local = P(hir::Local { + let local = hir::Local { pat, ty: None, init: ex, @@ -4804,9 +4936,15 @@ impl<'a> LoweringContext<'a> { span: sp, attrs: ThinVec::new(), source, - }); - let decl = respan(sp, hir::DeclKind::Local(local)); - respan(sp, hir::StmtKind::Decl(P(decl), self.next_id().node_id)) + }; + + let LoweredNodeId { node_id, hir_id } = self.next_id(); + hir::Stmt { + id: node_id, + hir_id, + node: hir::StmtKind::Local(P(local)), + span: sp + } } fn stmt_let( @@ -4898,7 +5036,7 @@ impl<'a> LoweringContext<'a> { P(hir::Pat { id: node_id, hir_id, - node: hir::PatKind::Binding(bm, node_id, ident.with_span_pos(span), None), + node: hir::PatKind::Binding(bm, node_id, hir_id, ident.with_span_pos(span), None), span, }) } @@ -4984,8 +5122,10 @@ impl<'a> LoweringContext<'a> { // `'f`. AnonymousLifetimeMode::CreateParameter => { let fresh_name = self.collect_fresh_in_band_lifetime(span); + let LoweredNodeId { node_id, hir_id } = self.next_id(); hir::Lifetime { - id: self.next_id().node_id, + id: node_id, + hir_id, span, name: hir::LifetimeName::Param(fresh_name), } @@ -5085,8 +5225,11 @@ impl<'a> LoweringContext<'a> { } fn new_implicit_lifetime(&mut self, span: Span) -> hir::Lifetime { + let LoweredNodeId { node_id, hir_id } = self.next_id(); + hir::Lifetime { - id: self.next_id().node_id, + id: node_id, + hir_id, span, name: hir::LifetimeName::Implicit, } diff --git a/src/librustc/hir/map/blocks.rs b/src/librustc/hir/map/blocks.rs index f61b8551927bb..6919628c76755 100644 --- a/src/librustc/hir/map/blocks.rs +++ b/src/librustc/hir/map/blocks.rs @@ -1,9 +1,9 @@ //! This module provides a simplified abstraction for working with -//! code blocks identified by their integer node-id. In particular, +//! code blocks identified by their integer `NodeId`. In particular, //! it captures a common set of attributes that all "function-like -//! things" (represented by `FnLike` instances) share. For example, +//! things" (represented by `FnLike` instances) share. For example, //! all `FnLike` instances have a type signature (be it explicit or -//! inferred). And all `FnLike` instances have a body, i.e., the code +//! inferred). And all `FnLike` instances have a body, i.e., the code //! that is run when the function-like thing it represents is invoked. //! //! With the above abstraction in place, one can treat the program @@ -11,10 +11,10 @@ //! nested within a uniquely determined `FnLike`), and users can ask //! for the `Code` associated with a particular NodeId. -use hir as ast; -use hir::map; -use hir::{Expr, FnDecl, Node}; -use hir::intravisit::FnKind; +use crate::hir as ast; +use crate::hir::map; +use crate::hir::{Expr, FnDecl, Node}; +use crate::hir::intravisit::FnKind; use syntax::ast::{Attribute, Ident, NodeId}; use syntax_pos::Span; diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs index ae9bb37842990..37552f18f4a08 100644 --- a/src/librustc/hir/map/collector.rs +++ b/src/librustc/hir/map/collector.rs @@ -1,18 +1,19 @@ use super::*; -use dep_graph::{DepGraph, DepKind, DepNodeIndex}; -use hir::def_id::{LOCAL_CRATE, CrateNum}; -use hir::intravisit::{Visitor, NestedVisitorMap}; +use crate::dep_graph::{DepGraph, DepKind, DepNodeIndex}; +use crate::hir; +use crate::hir::def_id::{LOCAL_CRATE, CrateNum}; +use crate::hir::intravisit::{Visitor, NestedVisitorMap}; use rustc_data_structures::svh::Svh; -use ich::Fingerprint; -use middle::cstore::CrateStore; -use session::CrateDisambiguator; -use session::Session; +use crate::ich::Fingerprint; +use crate::middle::cstore::CrateStore; +use crate::session::CrateDisambiguator; +use crate::session::Session; use std::iter::repeat; use syntax::ast::{NodeId, CRATE_NODE_ID}; use syntax::source_map::SourceMap; use syntax_pos::Span; -use ich::StableHashingContext; +use crate::ich::StableHashingContext; use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult}; /// A Visitor that walks over the HIR and collects Nodes into a HIR map @@ -28,6 +29,8 @@ pub(super) struct NodeCollector<'a, 'hir> { /// The parent of this node parent_node: NodeId, + parent_hir: hir::HirId, + // These fields keep track of the currently relevant DepNodes during // the visitor's traversal. current_dep_node_owner: DefIndex, @@ -45,14 +48,14 @@ pub(super) struct NodeCollector<'a, 'hir> { hir_body_nodes: Vec<(DefPathHash, Fingerprint)>, } -fn input_dep_node_and_hash<'a, I>( +fn input_dep_node_and_hash( dep_graph: &DepGraph, - hcx: &mut StableHashingContext<'a>, + hcx: &mut StableHashingContext<'_>, dep_node: DepNode, input: I, ) -> (DepNodeIndex, Fingerprint) where - I: HashStable>, + I: for<'a> HashStable>, { let dep_node_index = dep_graph.input_task(dep_node, &mut *hcx, &input).1; @@ -67,15 +70,15 @@ where (dep_node_index, hash) } -fn alloc_hir_dep_nodes<'a, I>( +fn alloc_hir_dep_nodes( dep_graph: &DepGraph, - hcx: &mut StableHashingContext<'a>, + hcx: &mut StableHashingContext<'_>, def_path_hash: DefPathHash, item_like: I, hir_body_nodes: &mut Vec<(DefPathHash, Fingerprint)>, ) -> (DepNodeIndex, DepNodeIndex) where - I: HashStable>, + I: for<'a> HashStable>, { let sig = dep_graph.input_task( def_path_hash.to_dep_node(DepKind::Hir), @@ -145,6 +148,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { source_map: sess.source_map(), map: repeat(None).take(sess.current_node_id_count()).collect(), parent_node: CRATE_NODE_ID, + parent_hir: hir::CRATE_HIR_ID, current_signature_dep_index: root_mod_sig_dep_index, current_full_dep_index: root_mod_full_dep_index, current_dep_node_owner: CRATE_DEF_INDEX, @@ -156,6 +160,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { }; collector.insert_entry(CRATE_NODE_ID, Entry { parent: CRATE_NODE_ID, + parent_hir: hir::CRATE_HIR_ID, dep_node: root_mod_sig_dep_index, node: Node::Crate, }); @@ -226,6 +231,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { fn insert(&mut self, span: Span, id: NodeId, node: Node<'hir>) { let entry = Entry { parent: self.parent_node, + parent_hir: self.parent_hir, dep_node: if self.currently_in_body { self.current_full_dep_index } else { @@ -247,7 +253,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { None => format!("{:?}", node) }; - let forgot_str = if hir_id == ::hir::DUMMY_HIR_ID { + let forgot_str = if hir_id == crate::hir::DUMMY_HIR_ID { format!("\nMaybe you forgot to lower the node id {:?}?", id) } else { String::new() @@ -280,7 +286,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { self.parent_node = parent_node; } - fn with_dep_node_owner>, + fn with_dep_node_owner HashStable>, F: FnOnce(&mut Self)>(&mut self, dep_node_owner: DefIndex, item_like: &T, @@ -426,7 +432,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { } fn visit_stmt(&mut self, stmt: &'hir Stmt) { - let id = stmt.node.id(); + let id = stmt.id; self.insert(stmt.span, id, Node::Stmt(stmt)); self.with_parent(id, |this| { diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index bc0a64ae7c5d8..8fe10a85ef380 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -1,6 +1,6 @@ -use hir::map::definitions::*; -use hir::def_id::{CRATE_DEF_INDEX, DefIndex, DefIndexAddressSpace}; -use session::CrateDisambiguator; +use crate::hir::map::definitions::*; +use crate::hir::def_id::{CRATE_DEF_INDEX, DefIndex, DefIndexAddressSpace}; +use crate::session::CrateDisambiguator; use syntax::ast::*; use syntax::ext::hygiene::Mark; @@ -10,9 +10,9 @@ use syntax::symbol::Symbol; use syntax::parse::token::{self, Token}; use syntax_pos::Span; -use hir::map::{ITEM_LIKE_SPACE, REGULAR_SPACE}; +use crate::hir::map::{ITEM_LIKE_SPACE, REGULAR_SPACE}; -/// Creates def ids for nodes in the AST. +/// Creates `DefId`s for nodes in the AST. pub struct DefCollector<'a> { definitions: &'a mut Definitions, parent_def: Option, @@ -120,10 +120,10 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { let def_data = match i.node { ItemKind::Impl(..) => DefPathData::Impl, ItemKind::Trait(..) => DefPathData::Trait(i.ident.as_interned_str()), + ItemKind::TraitAlias(..) => DefPathData::TraitAlias(i.ident.as_interned_str()), ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) | - ItemKind::TraitAlias(..) | ItemKind::Existential(..) | - ItemKind::ExternCrate(..) | ItemKind::ForeignMod(..) | ItemKind::Ty(..) => - DefPathData::TypeNs(i.ident.as_interned_str()), + ItemKind::Existential(..) | ItemKind::ExternCrate(..) | ItemKind::ForeignMod(..) | + ItemKind::Ty(..) => DefPathData::TypeNs(i.ident.as_interned_str()), ItemKind::Mod(..) if i.ident == keywords::Invalid.ident() => { return visit::walk_item(self, i); } @@ -218,6 +218,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { let def_path_data = match param.kind { GenericParamKind::Lifetime { .. } => DefPathData::LifetimeParam(name), GenericParamKind::Type { .. } => DefPathData::TypeParam(name), + GenericParamKind::Const { .. } => DefPathData::ConstParam(name), }; self.create_def(param.id, def_path_data, REGULAR_SPACE, param.ident.span); diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs index 6b707dd2dcc80..f454d691d4188 100644 --- a/src/librustc/hir/map/definitions.rs +++ b/src/librustc/hir/map/definitions.rs @@ -1,18 +1,18 @@ -//! For each definition, we track the following data. A definition -//! here is defined somewhat circularly as "something with a def-id", +//! For each definition, we track the following data. A definition +//! here is defined somewhat circularly as "something with a `DefId`", //! but it generally corresponds to things like structs, enums, etc. //! There are also some rather random cases (like const initializer //! expressions) that are mostly just leftovers. -use hir; -use hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE, DefIndexAddressSpace, +use crate::hir; +use crate::hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE, DefIndexAddressSpace, CRATE_DEF_INDEX}; -use ich::Fingerprint; +use crate::ich::Fingerprint; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::indexed_vec::{IndexVec}; use rustc_data_structures::stable_hasher::StableHasher; use serialize::{Encodable, Decodable, Encoder, Decoder}; -use session::CrateDisambiguator; +use crate::session::CrateDisambiguator; use std::borrow::Borrow; use std::fmt::Write; use std::hash::Hash; @@ -20,7 +20,7 @@ use syntax::ast; use syntax::ext::hygiene::Mark; use syntax::symbol::{Symbol, InternedString}; use syntax_pos::{Span, DUMMY_SP}; -use util::nodemap::NodeMap; +use crate::util::nodemap::NodeMap; /// The DefPathTable maps DefIndexes to DefKeys and vice versa. /// Internally the DefPathTable holds a tree of DefKeys, where each DefKey @@ -163,10 +163,10 @@ pub struct Definitions { /// any) with a `DisambiguatedDefPathData`. #[derive(Clone, PartialEq, Debug, Hash, RustcEncodable, RustcDecodable)] pub struct DefKey { - /// Parent path. + /// The parent path. pub parent: Option, - /// Identifier of this node. + /// The identifier of this node. pub disambiguated_data: DisambiguatedDefPathData, } @@ -207,12 +207,12 @@ impl DefKey { } } -/// Pair of `DefPathData` and an integer disambiguator. The integer is +/// A pair of `DefPathData` and an integer disambiguator. The integer is /// normally 0, but in the event that there are multiple defs with the /// same `parent` and `data`, we use this field to disambiguate /// between them. This introduces some artificial ordering dependency /// but means that if you have (e.g.) two impls for the same type in -/// the same module, they do get distinct def-ids. +/// the same module, they do get distinct `DefId`s. #[derive(Clone, PartialEq, Debug, Hash, RustcEncodable, RustcDecodable)] pub struct DisambiguatedDefPathData { pub data: DefPathData, @@ -221,10 +221,10 @@ pub struct DisambiguatedDefPathData { #[derive(Clone, Debug, Hash, RustcEncodable, RustcDecodable)] pub struct DefPath { - /// the path leading from the crate root to the item + /// The path leading from the crate root to the item. pub data: Vec, - /// what krate root is this path relative to? + /// The crate root this path is relative to. pub krate: CrateNum, } @@ -260,9 +260,9 @@ impl DefPath { DefPath { data: data, krate: krate } } - /// Returns a string representation of the DefPath without + /// Returns a string representation of the `DefPath` without /// the crate-prefix. This method is useful if you don't have - /// a TyCtxt available. + /// a `TyCtxt` available. pub fn to_string_no_crate(&self) -> String { let mut s = String::with_capacity(self.data.len() * 16); @@ -277,7 +277,7 @@ impl DefPath { s } - /// Return filename friendly string of the DefPah with the + /// Returns a filename-friendly string for the `DefPath`, with the /// crate-prefix. pub fn to_string_friendly(&self, crate_imported_name: F) -> String where F: FnOnce(CrateNum) -> Symbol @@ -302,9 +302,9 @@ impl DefPath { s } - /// Return filename friendly string of the DefPah without + /// Returns a filename-friendly string of the `DefPath`, without /// the crate-prefix. This method is useful if you don't have - /// a TyCtxt available. + /// a `TyCtxt` available. pub fn to_filename_friendly_no_crate(&self) -> String { let mut s = String::with_capacity(self.data.len() * 16); @@ -356,10 +356,12 @@ pub enum DefPathData { /// A closure expression ClosureExpr, // Subportions of items - /// A type parameter (generic parameter) + /// A type (generic) parameter TypeParam(InternedString), - /// A lifetime definition + /// A lifetime (generic) parameter LifetimeParam(InternedString), + /// A const (generic) parameter + ConstParam(InternedString), /// A variant of a enum EnumVariant(InternedString), /// A struct field @@ -373,7 +375,9 @@ pub enum DefPathData { /// GlobalMetaData identifies a piece of crate metadata that is global to /// a whole crate (as opposed to just one item). GlobalMetaData components /// are only supposed to show up right below the crate root. - GlobalMetaData(InternedString) + GlobalMetaData(InternedString), + /// A trait alias. + TraitAlias(InternedString), } #[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug, @@ -390,18 +394,18 @@ impl Borrow for DefPathHash { } impl Definitions { - /// Create new empty definition map. + /// Creates new empty definition map. /// - /// The DefIndex returned from a new Definitions are as follows: - /// 1. At DefIndexAddressSpace::Low, + /// The `DefIndex` returned from a new `Definitions` are as follows: + /// 1. At `DefIndexAddressSpace::Low`, /// CRATE_ROOT has index 0:0, and then new indexes are allocated in /// ascending order. - /// 2. At DefIndexAddressSpace::High, - /// the first FIRST_FREE_HIGH_DEF_INDEX indexes are reserved for - /// internal use, then 1:FIRST_FREE_HIGH_DEF_INDEX are allocated in + /// 2. At `DefIndexAddressSpace::High`, + /// the first `FIRST_FREE_HIGH_DEF_INDEX` indexes are reserved for + /// internal use, then `1:FIRST_FREE_HIGH_DEF_INDEX` are allocated in /// ascending order. - /// - /// FIXME: there is probably a better place to put this comment. + // + // FIXME: there is probably a better place to put this comment. pub fn new() -> Self { Self::default() } @@ -410,7 +414,7 @@ impl Definitions { &self.table } - /// Get the number of definitions. + /// Gets the number of definitions. pub fn def_index_counts_lo_hi(&self) -> (usize, usize) { (self.table.index_to_key[DefIndexAddressSpace::Low.index()].len(), self.table.index_to_key[DefIndexAddressSpace::High.index()].len()) @@ -465,6 +469,21 @@ impl Definitions { } } + // FIXME(@ljedrz): replace the NodeId variant + #[inline] + pub fn as_local_hir_id(&self, def_id: DefId) -> Option { + if def_id.krate == LOCAL_CRATE { + let hir_id = self.def_index_to_hir_id(def_id.index); + if hir_id != hir::DUMMY_HIR_ID { + Some(hir_id) + } else { + None + } + } else { + None + } + } + #[inline] pub fn node_to_hir_id(&self, node_id: ast::NodeId) -> hir::HirId { self.node_to_hir_id[node_id] @@ -478,8 +497,8 @@ impl Definitions { self.node_to_hir_id[node_id] } - /// Retrieve the span of the given `DefId` if `DefId` is in the local crate, the span exists and - /// it's not DUMMY_SP + /// Retrieves the span of the given `DefId` if `DefId` is in the local crate, the span exists + /// and it's not `DUMMY_SP`. #[inline] pub fn opt_span(&self, def_id: DefId) -> Option { if def_id.krate == LOCAL_CRATE { @@ -489,7 +508,7 @@ impl Definitions { } } - /// Add a definition with a parent definition. + /// Adds a root definition (no parent). pub fn create_root_def(&mut self, crate_name: &str, crate_disambiguator: CrateDisambiguator) @@ -587,7 +606,7 @@ impl Definitions { index } - /// Initialize the ast::NodeId to HirId mapping once it has been generated during + /// Initialize the `ast::NodeId` to `HirId` mapping once it has been generated during /// AST to HIR lowering. pub fn init_node_id_to_hir_id_mapping(&mut self, mapping: IndexVec) { @@ -615,6 +634,7 @@ impl DefPathData { match *self { TypeNs(name) | Trait(name) | + TraitAlias(name) | AssocTypeInTrait(name) | AssocTypeInImpl(name) | AssocExistentialInImpl(name) | @@ -623,6 +643,7 @@ impl DefPathData { MacroDef(name) | TypeParam(name) | LifetimeParam(name) | + ConstParam(name) | EnumVariant(name) | Field(name) | GlobalMetaData(name) => Some(name), @@ -642,6 +663,7 @@ impl DefPathData { let s = match *self { TypeNs(name) | Trait(name) | + TraitAlias(name) | AssocTypeInTrait(name) | AssocTypeInImpl(name) | AssocExistentialInImpl(name) | @@ -650,6 +672,7 @@ impl DefPathData { MacroDef(name) | TypeParam(name) | LifetimeParam(name) | + ConstParam(name) | EnumVariant(name) | Field(name) | GlobalMetaData(name) => { diff --git a/src/librustc/hir/map/hir_id_validator.rs b/src/librustc/hir/map/hir_id_validator.rs index 91c8c29144406..2c3ff4c9b5c05 100644 --- a/src/librustc/hir/map/hir_id_validator.rs +++ b/src/librustc/hir/map/hir_id_validator.rs @@ -1,7 +1,7 @@ -use hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX}; -use hir::{self, intravisit, HirId, ItemLocalId}; +use crate::hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX}; +use crate::hir::{self, intravisit, HirId, ItemLocalId}; use syntax::ast::NodeId; -use hir::itemlikevisit::ItemLikeVisitor; +use crate::hir::itemlikevisit::ItemLikeVisitor; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::{Lock, ParallelIterator, par_iter}; diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 869baef1f5afc..e933e4b7180c4 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -3,11 +3,11 @@ pub use self::def_collector::{DefCollector, MacroInvocationData}; pub use self::definitions::{Definitions, DefKey, DefPath, DefPathData, DisambiguatedDefPathData, DefPathHash}; -use dep_graph::{DepGraph, DepNode, DepKind, DepNodeIndex}; +use crate::dep_graph::{DepGraph, DepNode, DepKind, DepNodeIndex}; -use hir::def_id::{CRATE_DEF_INDEX, DefId, LocalDefId, DefIndexAddressSpace}; +use crate::hir::def_id::{CRATE_DEF_INDEX, DefId, LocalDefId, DefIndexAddressSpace}; -use middle::cstore::CrateStoreDyn; +use crate::middle::cstore::CrateStoreDyn; use rustc_target::spec::abi::Abi; use rustc_data_structures::svh::Svh; @@ -17,15 +17,15 @@ use syntax::source_map::Spanned; use syntax::ext::base::MacroKind; use syntax_pos::{Span, DUMMY_SP}; -use hir::*; -use hir::itemlikevisit::ItemLikeVisitor; -use hir::print::Nested; -use util::nodemap::FxHashMap; -use util::common::time; +use crate::hir::*; +use crate::hir::itemlikevisit::ItemLikeVisitor; +use crate::hir::print::Nested; +use crate::util::nodemap::FxHashMap; +use crate::util::common::time; use std::io; use std::result::Result::Err; -use ty::TyCtxt; +use crate::ty::TyCtxt; pub mod blocks; mod collector; @@ -36,10 +36,11 @@ mod hir_id_validator; pub const ITEM_LIKE_SPACE: DefIndexAddressSpace = DefIndexAddressSpace::Low; pub const REGULAR_SPACE: DefIndexAddressSpace = DefIndexAddressSpace::High; -/// Represents an entry and its parent NodeId. +/// Represents an entry and its parent `NodeId`. #[derive(Copy, Clone, Debug)] pub struct Entry<'hir> { parent: NodeId, + parent_hir: HirId, dep_node: DepNodeIndex, node: Node<'hir>, } @@ -126,9 +127,9 @@ impl<'hir> Entry<'hir> { } } - fn is_body_owner(self, node_id: NodeId) -> bool { + fn is_body_owner(self, hir_id: HirId) -> bool { match self.associated_body() { - Some(b) => b.node_id == node_id, + Some(b) => b.hir_id == hir_id, None => false, } } @@ -161,8 +162,7 @@ impl Forest { } } -/// Represents a mapping from Node IDs to AST elements and their parent -/// Node IDs +/// Represents a mapping from `NodeId`s to AST elements and their parent `NodeId`s. #[derive(Clone)] pub struct Map<'hir> { /// The backing storage for all the AST nodes. @@ -208,6 +208,12 @@ impl<'hir> Map<'hir> { } } + // FIXME(@ljedrz): replace the NodeId variant + pub fn read_by_hir_id(&self, hir_id: HirId) { + let node_id = self.hir_to_node_id(hir_id); + self.read(node_id); + } + #[inline] pub fn definitions(&self) -> &'hir Definitions { self.definitions @@ -224,6 +230,11 @@ impl<'hir> Map<'hir> { }) } + // FIXME(@ljedrz): replace the NodeId variant + pub fn def_path_from_hir_id(&self, id: HirId) -> DefPath { + self.def_path(self.local_def_id_from_hir_id(id)) + } + pub fn def_path(&self, def_id: DefId) -> DefPath { assert!(def_id.is_local()); self.definitions.def_path(def_id.index) @@ -237,6 +248,23 @@ impl<'hir> Map<'hir> { }) } + // FIXME(@ljedrz): replace the NodeId variant + #[inline] + pub fn local_def_id_from_hir_id(&self, hir_id: HirId) -> DefId { + let node_id = self.hir_to_node_id(hir_id); + self.opt_local_def_id(node_id).unwrap_or_else(|| { + bug!("local_def_id_from_hir_id: no entry for `{:?}`, which has a map of `{:?}`", + hir_id, self.find_entry(node_id)) + }) + } + + // FIXME(@ljedrz): replace the NodeId variant + #[inline] + pub fn opt_local_def_id_from_hir_id(&self, hir_id: HirId) -> Option { + let node_id = self.hir_to_node_id(hir_id); + self.definitions.opt_local_def_id(node_id) + } + #[inline] pub fn opt_local_def_id(&self, node: NodeId) -> Option { self.definitions.opt_local_def_id(node) @@ -247,6 +275,12 @@ impl<'hir> Map<'hir> { self.definitions.as_local_node_id(def_id) } + // FIXME(@ljedrz): replace the NodeId variant + #[inline] + pub fn as_local_hir_id(&self, def_id: DefId) -> Option { + self.definitions.as_local_hir_id(def_id) + } + #[inline] pub fn hir_to_node_id(&self, hir_id: HirId) -> NodeId { self.hir_to_node_id[&hir_id] @@ -336,8 +370,12 @@ impl<'hir> Map<'hir> { let def_id = self.local_def_id(variant.node.data.id()); Some(Def::Variant(def_id)) } - Node::Field(_) | + Node::StructCtor(variant) => { + let def_id = self.local_def_id(variant.id()); + Some(Def::StructCtor(def_id, def::CtorKind::from_hir(variant))) + } Node::AnonConst(_) | + Node::Field(_) | Node::Expr(_) | Node::Stmt(_) | Node::PathSegment(_) | @@ -345,7 +383,6 @@ impl<'hir> Map<'hir> { Node::TraitRef(_) | Node::Pat(_) | Node::Binding(_) | - Node::StructCtor(_) | Node::Lifetime(_) | Node::Visibility(_) | Node::Block(_) | @@ -361,11 +398,18 @@ impl<'hir> Map<'hir> { Some(match param.kind { GenericParamKind::Lifetime { .. } => Def::Local(param.id), GenericParamKind::Type { .. } => Def::TyParam(self.local_def_id(param.id)), + GenericParamKind::Const { .. } => Def::ConstParam(self.local_def_id(param.id)), }) } } } + // FIXME(@ljedrz): replace the NodeId variant + pub fn describe_def_by_hir_id(&self, hir_id: HirId) -> Option { + let node_id = self.hir_to_node_id(hir_id); + self.describe_def(node_id) + } + fn entry_count(&self) -> usize { self.map.len() } @@ -395,7 +439,7 @@ impl<'hir> Map<'hir> { } pub fn body(&self, id: BodyId) -> &'hir Body { - self.read(id.node_id); + self.read_by_hir_id(id.hir_id); // N.B., intentionally bypass `self.forest.krate()` so that we // do not trigger a read of the whole krate here @@ -410,12 +454,19 @@ impl<'hir> Map<'hir> { } } + // FIXME(@ljedrz): replace the NodeId variant + pub fn fn_decl_by_hir_id(&self, hir_id: HirId) -> Option { + let node_id = self.hir_to_node_id(hir_id); + self.fn_decl(node_id) + } + /// Returns the `NodeId` that corresponds to the definition of /// which this is the body of, i.e., a `fn`, `const` or `static` /// item (possibly associated), a closure, or a `hir::AnonConst`. - pub fn body_owner(&self, BodyId { node_id }: BodyId) -> NodeId { + pub fn body_owner(&self, BodyId { hir_id }: BodyId) -> NodeId { + let node_id = self.hir_to_node_id(hir_id); let parent = self.get_parent_node(node_id); - assert!(self.map[parent.as_usize()].map_or(false, |e| e.is_body_owner(node_id))); + assert!(self.map[parent.as_usize()].map_or(false, |e| e.is_body_owner(hir_id))); parent } @@ -423,7 +474,7 @@ impl<'hir> Map<'hir> { self.local_def_id(self.body_owner(id)) } - /// Given a node id, returns the `BodyId` associated with it, + /// Given a `NodeId`, returns the `BodyId` associated with it, /// if the node is a body owner, otherwise returns `None`. pub fn maybe_body_owned_by(&self, id: NodeId) -> Option { if let Some(entry) = self.find_entry(id) { @@ -439,6 +490,12 @@ impl<'hir> Map<'hir> { } } + // FIXME(@ljedrz): replace the NodeId variant + pub fn maybe_body_owned_by_by_hir_id(&self, id: HirId) -> Option { + let node_id = self.hir_to_node_id(id); + self.maybe_body_owned_by(node_id) + } + /// Given a body owner's id, returns the `BodyId` associated with it. pub fn body_owned_by(&self, id: NodeId) -> BodyId { self.maybe_body_owned_by(id).unwrap_or_else(|| { @@ -455,14 +512,29 @@ impl<'hir> Map<'hir> { Node::AnonConst(_) => { BodyOwnerKind::Const } + Node::Variant(&Spanned { node: VariantKind { data: VariantData::Tuple(..), .. }, .. }) | + Node::StructCtor(..) | + Node::Item(&Item { node: ItemKind::Fn(..), .. }) | + Node::TraitItem(&TraitItem { node: TraitItemKind::Method(..), .. }) | + Node::ImplItem(&ImplItem { node: ImplItemKind::Method(..), .. }) => { + BodyOwnerKind::Fn + } Node::Item(&Item { node: ItemKind::Static(_, m, _), .. }) => { BodyOwnerKind::Static(m) } - // Default to function if it's not a constant or static. - _ => BodyOwnerKind::Fn + Node::Expr(&Expr { node: ExprKind::Closure(..), .. }) => { + BodyOwnerKind::Closure + } + node => bug!("{:#?} is not a body node", node), } } + // FIXME(@ljedrz): replace the NodeId variant + pub fn body_owner_kind_by_hir_id(&self, id: HirId) -> BodyOwnerKind { + let node_id = self.hir_to_node_id(id); + self.body_owner_kind(node_id) + } + pub fn ty_param_owner(&self, id: NodeId) -> NodeId { match self.get(id) { Node::Item(&Item { node: ItemKind::Trait(..), .. }) => id, @@ -499,7 +571,7 @@ impl<'hir> Map<'hir> { self.trait_auto_impl(trait_did).is_some() } - /// Get the attributes on the krate. This is preferable to + /// Gets the attributes on the crate. This is preferable to /// invoking `krate.attrs` because it registers a tighter /// dep-graph access. pub fn krate_attrs(&self) -> &'hir [ast::Attribute] { @@ -509,6 +581,21 @@ impl<'hir> Map<'hir> { &self.forest.krate.attrs } + pub fn get_module(&self, module: DefId) -> (&'hir Mod, Span, NodeId) + { + let node_id = self.as_local_node_id(module).unwrap(); + self.read(node_id); + match self.find_entry(node_id).unwrap().node { + Node::Item(&Item { + span, + node: ItemKind::Mod(ref m), + .. + }) => (m, span, node_id), + Node::Crate => (&self.forest.krate.module, self.forest.krate.span, node_id), + _ => panic!("not a module") + } + } + pub fn visit_item_likes_in_module(&self, module: DefId, visitor: &mut V) where V: ItemLikeVisitor<'hir> { @@ -542,6 +629,12 @@ impl<'hir> Map<'hir> { self.find(id).unwrap_or_else(|| bug!("couldn't find node id {} in the AST map", id)) } + // FIXME(@ljedrz): replace the NodeId variant + pub fn get_by_hir_id(&self, id: HirId) -> Node<'hir> { + let node_id = self.hir_to_node_id(id); + self.get(node_id) + } + pub fn get_if_local(&self, id: DefId) -> Option> { self.as_local_node_id(id).map(|id| self.get(id)) // read recorded by `get` } @@ -573,8 +666,7 @@ impl<'hir> Map<'hir> { self.get_generics(id).map(|generics| generics.span).filter(|sp| *sp != DUMMY_SP) } - /// Retrieve the Node corresponding to `id`, returning None if - /// cannot be found. + /// Retrieves the `Node` corresponding to `id`, returning `None` if cannot be found. pub fn find(&self, id: NodeId) -> Option> { let result = self.find_entry(id).and_then(|entry| { if let Node::Crate = entry.node { @@ -589,6 +681,12 @@ impl<'hir> Map<'hir> { result } + // FIXME(@ljedrz): replace the NodeId variant + pub fn find_by_hir_id(&self, hir_id: HirId) -> Option> { + let node_id = self.hir_to_node_id(hir_id); + self.find(node_id) + } + /// Similar to `get_parent`; returns the parent node-id, or own `id` if there is /// no parent. Note that the parent may be `CRATE_NODE_ID`, which is not itself /// present in the map -- so passing the return value of get_parent_node to @@ -597,8 +695,8 @@ impl<'hir> Map<'hir> { /// returns the enclosing item. Note that this might not be the actual parent /// node in the AST - some kinds of nodes are not in the map and these will /// never appear as the parent_node. So you can always walk the `parent_nodes` - /// from a node to the root of the ast (unless you get the same id back here - /// that can happen if the id is not in the map itself or is just weird). + /// from a node to the root of the ast (unless you get the same ID back here + /// that can happen if the ID is not in the map itself or is just weird). pub fn get_parent_node(&self, id: NodeId) -> NodeId { if self.dep_graph.is_fully_enabled() { let hir_id_owner = self.node_to_hir_id(id).owner; @@ -609,6 +707,13 @@ impl<'hir> Map<'hir> { self.find_entry(id).and_then(|x| x.parent_node()).unwrap_or(id) } + // FIXME(@ljedrz): replace the NodeId variant + pub fn get_parent_node_by_hir_id(&self, id: HirId) -> HirId { + let node_id = self.hir_to_node_id(id); + let parent_node_id = self.get_parent_node(node_id); + self.node_to_hir_id(parent_node_id) + } + /// Check if the node is an argument. An argument is a local variable whose /// immediate parent is an item or a closure. pub fn is_argument(&self, id: NodeId) -> bool { @@ -632,7 +737,7 @@ impl<'hir> Map<'hir> { /// If there is some error when walking the parents (e.g., a node does not /// have a parent in the map or a node can't be found), then we return the - /// last good node id we found. Note that reaching the crate root (`id == 0`), + /// last good `NodeId` we found. Note that reaching the crate root (`id == 0`), /// is not an error, since items in the crate module have the crate root as /// parent. fn walk_parent_nodes(&self, @@ -668,7 +773,7 @@ impl<'hir> Map<'hir> { } } - /// Retrieve the `NodeId` for `id`'s enclosing method, unless there's a + /// Retrieves the `NodeId` for `id`'s enclosing method, unless there's a /// `while` or `loop` before reaching it, as block tail returns are not /// available in them. /// @@ -716,7 +821,7 @@ impl<'hir> Map<'hir> { self.walk_parent_nodes(id, match_fn, match_non_returning_block).ok() } - /// Retrieve the `NodeId` for `id`'s parent item, or `id` itself if no + /// Retrieves the `NodeId` for `id`'s parent item, or `id` itself if no /// parent item is in this map. The "parent item" is the closest parent node /// in the HIR which is recorded by the map and is an item, either an item /// in a module, trait, or impl. @@ -733,12 +838,25 @@ impl<'hir> Map<'hir> { } } + // FIXME(@ljedrz): replace the NodeId variant + pub fn get_parent_item(&self, id: HirId) -> HirId { + let node_id = self.hir_to_node_id(id); + let parent_node_id = self.get_parent(node_id); + self.node_to_hir_id(parent_node_id) + } + /// Returns the `DefId` of `id`'s nearest module parent, or `id` itself if no /// module parent is in this map. pub fn get_module_parent(&self, id: NodeId) -> DefId { self.local_def_id(self.get_module_parent_node(id)) } + // FIXME(@ljedrz): replace the NodeId variant + pub fn get_module_parent_by_hir_id(&self, id: HirId) -> DefId { + let node_id = self.hir_to_node_id(id); + self.get_module_parent(node_id) + } + /// Returns the `NodeId` of `id`'s nearest module parent, or `id` itself if no /// module parent is in this map. pub fn get_module_parent_node(&self, id: NodeId) -> NodeId { @@ -770,6 +888,12 @@ impl<'hir> Map<'hir> { self.local_def_id(self.get_parent(id)) } + // FIXME(@ljedrz): replace the NodeId variant + pub fn get_parent_did_by_hir_id(&self, id: HirId) -> DefId { + let node_id = self.hir_to_node_id(id); + self.get_parent_did(node_id) + } + pub fn get_foreign_abi(&self, id: NodeId) -> Abi { let parent = self.get_parent(id); if let Some(entry) = self.find_entry(parent) { @@ -783,6 +907,12 @@ impl<'hir> Map<'hir> { bug!("expected foreign mod or inlined parent, found {}", self.node_to_string(parent)) } + // FIXME(@ljedrz): replace the NodeId variant + pub fn get_foreign_abi_by_hir_id(&self, id: HirId) -> Abi { + let node_id = self.hir_to_node_id(id); + self.get_foreign_abi(node_id) + } + pub fn expect_item(&self, id: NodeId) -> &'hir Item { match self.find(id) { // read recorded by `find` Some(Node::Item(item)) => item, @@ -790,6 +920,12 @@ impl<'hir> Map<'hir> { } } + // FIXME(@ljedrz): replace the NodeId variant + pub fn expect_item_by_hir_id(&self, id: HirId) -> &'hir Item { + let node_id = self.hir_to_node_id(id); + self.expect_item(node_id) + } + pub fn expect_impl_item(&self, id: NodeId) -> &'hir ImplItem { match self.find(id) { Some(Node::ImplItem(item)) => item, @@ -797,6 +933,18 @@ impl<'hir> Map<'hir> { } } + // FIXME(@ljedrz): replace the NodeId variant + pub fn expect_impl_item_by_hir_id(&self, id: HirId) -> &'hir ImplItem { + let node_id = self.hir_to_node_id(id); + self.expect_impl_item(node_id) + } + + // FIXME(@ljedrz): replace the NodeId variant + pub fn expect_trait_item_by_hir_id(&self, id: HirId) -> &'hir TraitItem { + let node_id = self.hir_to_node_id(id); + self.expect_trait_item(node_id) + } + pub fn expect_trait_item(&self, id: NodeId) -> &'hir TraitItem { match self.find(id) { Some(Node::TraitItem(item)) => item, @@ -804,7 +952,9 @@ impl<'hir> Map<'hir> { } } - pub fn expect_variant_data(&self, id: NodeId) -> &'hir VariantData { + pub fn expect_variant_data(&self, id: HirId) -> &'hir VariantData { + let id = self.hir_to_node_id(id); // FIXME(@ljedrz): remove when possible + match self.find(id) { Some(Node::Item(i)) => { match i.node { @@ -819,7 +969,9 @@ impl<'hir> Map<'hir> { } } - pub fn expect_variant(&self, id: NodeId) -> &'hir Variant { + pub fn expect_variant(&self, id: HirId) -> &'hir Variant { + let id = self.hir_to_node_id(id); // FIXME(@ljedrz): remove when possible + match self.find(id) { Some(Node::Variant(variant)) => variant, _ => bug!("expected variant, found {}", self.node_to_string(id)), @@ -840,6 +992,12 @@ impl<'hir> Map<'hir> { } } + // FIXME(@ljedrz): replace the NodeId variant + pub fn expect_expr_by_hir_id(&self, id: HirId) -> &'hir Expr { + let node_id = self.hir_to_node_id(id); + self.expect_expr(node_id) + } + /// Returns the name associated with the given NodeId's AST. pub fn name(&self, id: NodeId) -> Name { match self.get(id) { @@ -851,12 +1009,18 @@ impl<'hir> Map<'hir> { Node::Field(f) => f.ident.name, Node::Lifetime(lt) => lt.name.ident().name, Node::GenericParam(param) => param.name.ident().name, - Node::Binding(&Pat { node: PatKind::Binding(_,_,l,_), .. }) => l.name, + Node::Binding(&Pat { node: PatKind::Binding(_, _, _, l, _), .. }) => l.name, Node::StructCtor(_) => self.name(self.get_parent(id)), _ => bug!("no name for {}", self.node_to_string(id)) } } + // FIXME(@ljedrz): replace the NodeId variant + pub fn name_by_hir_id(&self, id: HirId) -> Name { + let node_id = self.hir_to_node_id(id); + self.name(node_id) + } + /// Given a node ID, get a list of attributes associated with the AST /// corresponding to the Node ID pub fn attrs(&self, id: NodeId) -> &'hir [ast::Attribute] { @@ -879,6 +1043,12 @@ impl<'hir> Map<'hir> { attrs.unwrap_or(&[]) } + // FIXME(@ljedrz): replace the NodeId variant + pub fn attrs_by_hir_id(&self, id: HirId) -> &'hir [ast::Attribute] { + let node_id = self.hir_to_node_id(id); + self.attrs(node_id) + } + /// Returns an iterator that yields the node id's with paths that /// match `parts`. (Requires `parts` is non-empty.) /// @@ -928,6 +1098,12 @@ impl<'hir> Map<'hir> { } } + // FIXME(@ljedrz): replace the NodeId variant + pub fn span_by_hir_id(&self, id: HirId) -> Span { + let node_id = self.hir_to_node_id(id); + self.span(node_id) + } + pub fn span_if_local(&self, id: DefId) -> Option { self.as_local_node_id(id).map(|id| self.span(id)) } @@ -936,13 +1112,28 @@ impl<'hir> Map<'hir> { node_id_to_string(self, id, true) } + // FIXME(@ljedrz): replace the NodeId variant + pub fn hir_to_string(&self, id: HirId) -> String { + hir_id_to_string(self, id, true) + } + pub fn node_to_user_string(&self, id: NodeId) -> String { node_id_to_string(self, id, false) } + // FIXME(@ljedrz): replace the NodeId variant + pub fn hir_to_user_string(&self, id: HirId) -> String { + hir_id_to_string(self, id, false) + } + pub fn node_to_pretty_string(&self, id: NodeId) -> String { print::to_string(self, |s| s.print_node(self.get(id))) } + + // FIXME(@ljedrz): replace the NodeId variant + pub fn hir_to_pretty_string(&self, id: HirId) -> String { + print::to_string(self, |s| s.print_node(self.get_by_hir_id(id))) + } } pub struct NodesMatchingSuffix<'a, 'hir:'a> { @@ -953,7 +1144,7 @@ pub struct NodesMatchingSuffix<'a, 'hir:'a> { } impl<'a, 'hir> NodesMatchingSuffix<'a, 'hir> { - /// Returns true only if some suffix of the module path for parent + /// Returns `true` only if some suffix of the module path for parent /// matches `self.in_which`. /// /// In other words: let `[x_0,x_1,...,x_k]` be `self.in_which`; @@ -1046,13 +1237,13 @@ impl Named for StructField { fn name(&self) -> Name { self.ident.name } } impl Named for TraitItem { fn name(&self) -> Name { self.ident.name } } impl Named for ImplItem { fn name(&self) -> Name { self.ident.name } } -pub fn map_crate<'hir>(sess: &::session::Session, +pub fn map_crate<'hir>(sess: &crate::session::Session, cstore: &CrateStoreDyn, forest: &'hir Forest, definitions: &'hir Definitions) -> Map<'hir> { let ((map, crate_hash), hir_to_node_id) = join(|| { - let hcx = ::ich::StableHashingContext::new(sess, &forest.krate, definitions, cstore); + let hcx = crate::ich::StableHashingContext::new(sess, &forest.krate, definitions, cstore); let mut collector = NodeCollector::root(sess, &forest.krate, @@ -1163,7 +1354,7 @@ fn node_id_to_string(map: &Map<'_>, id: NodeId, include_id: bool) -> String { let path_str = || { // This functionality is used for debugging, try to use TyCtxt to get // the user-friendly path, otherwise fall back to stringifying DefPath. - ::ty::tls::with_opt(|tcx| { + crate::ty::tls::with_opt(|tcx| { if let Some(tcx) = tcx { tcx.node_path_str(id) } else if let Some(path) = map.def_path_from_id(id) { @@ -1286,6 +1477,12 @@ fn node_id_to_string(map: &Map<'_>, id: NodeId, include_id: bool) -> String { } } +// FIXME(@ljedrz): replace the NodeId variant +fn hir_id_to_string(map: &Map<'_>, id: HirId, include_id: bool) -> String { + let node_id = map.hir_to_node_id(id); + node_id_to_string(map, node_id, include_id) +} + pub fn describe_def(tcx: TyCtxt<'_, '_, '_>, def_id: DefId) -> Option { if let Some(node_id) = tcx.hir().as_local_node_id(def_id) { tcx.hir().describe_def(node_id) diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index fc4bd05476f6c..d0b92587b59f0 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -10,26 +10,27 @@ pub use self::PrimTy::*; pub use self::UnOp::*; pub use self::UnsafeSource::*; -use hir::def::Def; -use hir::def_id::{DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX}; -use util::nodemap::{NodeMap, FxHashSet}; -use mir::mono::Linkage; +use crate::hir::def::Def; +use crate::hir::def_id::{DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX}; +use crate::util::nodemap::{NodeMap, FxHashSet}; +use crate::mir::mono::Linkage; +use errors::FatalError; use syntax_pos::{Span, DUMMY_SP, symbol::InternedString}; -use syntax::source_map::{self, Spanned}; +use syntax::source_map::Spanned; use rustc_target::spec::abi::Abi; use syntax::ast::{self, CrateSugar, Ident, Name, NodeId, DUMMY_NODE_ID, AsmDialect}; -use syntax::ast::{Attribute, Lit, StrStyle, FloatTy, IntTy, UintTy}; -use syntax::attr::InlineAttr; +use syntax::ast::{Attribute, Label, Lit, StrStyle, FloatTy, IntTy, UintTy}; +use syntax::attr::{InlineAttr, OptimizeAttr}; use syntax::ext::hygiene::SyntaxContext; use syntax::ptr::P; use syntax::symbol::{Symbol, keywords}; use syntax::tokenstream::TokenStream; use syntax::util::parser::ExprPrecedence; -use ty::AdtKind; -use ty::query::Providers; +use crate::ty::AdtKind; +use crate::ty::query::Providers; -use rustc_data_structures::sync::{ParallelIterator, par_iter, Send, Sync, scope}; +use rustc_data_structures::sync::{ParallelIterator, par_iter, Send, Sync}; use rustc_data_structures::thin_vec::ThinVec; use serialize::{self, Encoder, Encodable, Decoder, Decodable}; @@ -61,17 +62,17 @@ pub mod map; pub mod pat_util; pub mod print; -/// A HirId uniquely identifies a node in the HIR of the current crate. It is -/// composed of the `owner`, which is the DefIndex of the directly enclosing -/// hir::Item, hir::TraitItem, or hir::ImplItem (i.e., the closest "item-like"), +/// Uniquely identifies a node in the HIR of the current crate. It is +/// composed of the `owner`, which is the `DefIndex` of the directly enclosing +/// `hir::Item`, `hir::TraitItem`, or `hir::ImplItem` (i.e., the closest "item-like"), /// and the `local_id` which is unique within the given owner. /// /// This two-level structure makes for more stable values: One can move an item /// around within the source code, or add or remove stuff before it, without -/// the local_id part of the HirId changing, which is a very useful property in +/// the `local_id` part of the `HirId` changing, which is a very useful property in /// incremental compilation where we have to persist things through changes to /// the code base. -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)] pub struct HirId { pub owner: DefIndex, pub local_id: ItemLocalId, @@ -129,7 +130,7 @@ mod item_local_id_inner { pub use self::item_local_id_inner::ItemLocalId; -/// The `HirId` corresponding to CRATE_NODE_ID and CRATE_DEF_INDEX +/// The `HirId` corresponding to `CRATE_NODE_ID` and `CRATE_DEF_INDEX`. pub const CRATE_HIR_ID: HirId = HirId { owner: CRATE_DEF_INDEX, local_id: ItemLocalId::from_u32_const(0) @@ -142,24 +143,14 @@ pub const DUMMY_HIR_ID: HirId = HirId { pub const DUMMY_ITEM_LOCAL_ID: ItemLocalId = ItemLocalId::MAX; -#[derive(Clone, RustcEncodable, RustcDecodable, Copy)] -pub struct Label { - pub ident: Ident, -} - -impl fmt::Debug for Label { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "label({:?})", self.ident) - } -} - #[derive(Clone, RustcEncodable, RustcDecodable, Copy)] pub struct Lifetime { pub id: NodeId, + pub hir_id: HirId, pub span: Span, - /// Either "'a", referring to a named lifetime definition, - /// or "" (aka keywords::Invalid), for elision placeholders. + /// Either "`'a`", referring to a named lifetime definition, + /// or "``" (i.e., `keywords::Invalid`), for elision placeholders. /// /// HIR lowering inserts these placeholders in type paths that /// refer to type definitions needing lifetime parameters, @@ -172,8 +163,9 @@ pub enum ParamName { /// Some user-given name like `T` or `'x`. Plain(Ident), - /// Synthetic name generated when user elided a lifetime in an impl header, - /// e.g., the lifetimes in cases like these: + /// Synthetic name generated when user elided a lifetime in an impl header. + /// + /// E.g., the lifetimes in cases like these: /// /// impl Foo for &u32 /// impl Foo<'_> for u32 @@ -189,7 +181,7 @@ pub enum ParamName { /// Indicates an illegal name was given and an error has been /// repored (so we should squelch other derived errors). Occurs - /// when e.g., `'_` is used in the wrong place. + /// when, e.g., `'_` is used in the wrong place. Error, } @@ -214,17 +206,17 @@ pub enum LifetimeName { /// User-given names or fresh (synthetic) names. Param(ParamName), - /// User typed nothing. e.g., the lifetime in `&u32`. + /// User wrote nothing (e.g., the lifetime in `&u32`). Implicit, /// Indicates an error during lowering (usually `'_` in wrong place) /// that was already reported. Error, - /// User typed `'_`. + /// User wrote specifies `'_`. Underscore, - /// User wrote `'static` + /// User wrote `'static`. Static, } @@ -289,7 +281,7 @@ impl Lifetime { } } -/// A "Path" is essentially Rust's notion of a name; for instance: +/// A `Path` is essentially Rust's notion of a name; for instance, /// `std::cmp::PartialEq`. It's represented as a sequence of identifiers, /// along with a bunch of supporting information. #[derive(Clone, RustcEncodable, RustcDecodable)] @@ -331,6 +323,7 @@ pub struct PathSegment { // affected. (In general, we don't bother to get the defs for synthesized // segments, only for segments which have come from the AST). pub id: Option, + pub hir_id: Option, pub def: Option, /// Type/lifetime parameters attached to this path. They come in @@ -348,11 +341,12 @@ pub struct PathSegment { } impl PathSegment { - /// Convert an identifier to the corresponding segment. + /// Converts an identifier to the corresponding segment. pub fn from_ident(ident: Ident) -> PathSegment { PathSegment { ident, id: None, + hir_id: None, def: None, infer_types: true, args: None, @@ -362,6 +356,7 @@ impl PathSegment { pub fn new( ident: Ident, id: Option, + hir_id: Option, def: Option, args: GenericArgs, infer_types: bool, @@ -369,6 +364,7 @@ impl PathSegment { PathSegment { ident, id, + hir_id, def, infer_types, args: if args.is_empty() { @@ -393,10 +389,17 @@ impl PathSegment { } } +#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +pub struct ConstArg { + pub value: AnonConst, + pub span: Span, +} + #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub enum GenericArg { Lifetime(Lifetime), Type(Ty), + Const(ConstArg), } impl GenericArg { @@ -404,6 +407,7 @@ impl GenericArg { match self { GenericArg::Lifetime(l) => l.span, GenericArg::Type(t) => t.span, + GenericArg::Const(c) => c.span, } } @@ -411,6 +415,7 @@ impl GenericArg { match self { GenericArg::Lifetime(l) => l.id, GenericArg::Type(t) => t.id, + GenericArg::Const(c) => c.value.id, } } } @@ -452,6 +457,7 @@ impl GenericArgs { } break; } + GenericArg::Const(_) => {} } } } @@ -468,6 +474,7 @@ impl GenericArgs { match arg { GenericArg::Lifetime(_) => own_counts.lifetimes += 1, GenericArg::Type(_) => own_counts.types += 1, + GenericArg::Const(_) => own_counts.consts += 1, }; } @@ -532,12 +539,16 @@ pub enum GenericParamKind { Type { default: Option>, synthetic: Option, + }, + Const { + ty: P, } } #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct GenericParam { pub id: NodeId, + pub hir_id: HirId, pub name: ParamName, pub attrs: HirVec, pub bounds: GenericBounds, @@ -551,6 +562,7 @@ pub struct GenericParam { pub struct GenericParamCount { pub lifetimes: usize, pub types: usize, + pub consts: usize, } /// Represents lifetimes and type parameters attached to a declaration @@ -568,6 +580,7 @@ impl Generics { params: HirVec::new(), where_clause: WhereClause { id: DUMMY_NODE_ID, + hir_id: DUMMY_HIR_ID, predicates: HirVec::new(), }, span: DUMMY_SP, @@ -584,6 +597,7 @@ impl Generics { match param.kind { GenericParamKind::Lifetime { .. } => own_counts.lifetimes += 1, GenericParamKind::Type { .. } => own_counts.types += 1, + GenericParamKind::Const { .. } => own_counts.consts += 1, }; } @@ -600,17 +614,18 @@ impl Generics { } } -/// Synthetic Type Parameters are converted to an other form during lowering, this allows -/// to track the original form they had. Useful for error messages. +/// Synthetic type parameters are converted to another form during lowering; this allows +/// us to track the original form they had, and is useful for error messages. #[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum SyntheticTyParamKind { ImplTrait } -/// A `where` clause in a definition +/// A where-clause in a definition. #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct WhereClause { pub id: NodeId, + pub hir_id: HirId, pub predicates: HirVec, } @@ -626,7 +641,7 @@ impl WhereClause { } } -/// A single predicate in a `where` clause +/// A single predicate in a where-clause. #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub enum WherePredicate { /// A type binding (e.g., `for<'c> Foo: Send + Clone + 'c`). @@ -647,19 +662,19 @@ impl WherePredicate { } } -/// A type bound, eg `for<'c> Foo: Send+Clone+'c` +/// A type bound (e.g., `for<'c> Foo: Send + Clone + 'c`). #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct WhereBoundPredicate { pub span: Span, - /// Any generics from a `for` binding + /// Any generics from a `for` binding. pub bound_generic_params: HirVec, - /// The type being bounded + /// The type being bounded. pub bounded_ty: P, - /// Trait and lifetime bounds (`Clone+Send+'static`) + /// Trait and lifetime bounds (e.g., `Clone + Send + 'static`). pub bounds: GenericBounds, } -/// A lifetime predicate, e.g., `'a: 'b+'c` +/// A lifetime predicate (e.g., `'a: 'b + 'c`). #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct WhereRegionPredicate { pub span: Span, @@ -667,10 +682,11 @@ pub struct WhereRegionPredicate { pub bounds: GenericBounds, } -/// An equality predicate (unsupported), e.g., `T=int` +/// An equality predicate (e.g., `T = int`); currently unsupported. #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct WhereEqPredicate { pub id: NodeId, + pub hir_id: HirId, pub span: Span, pub lhs_ty: P, pub rhs_ty: P, @@ -760,27 +776,21 @@ impl Crate { } } - /// A parallel version of visit_all_item_likes + /// A parallel version of `visit_all_item_likes`. pub fn par_visit_all_item_likes<'hir, V>(&'hir self, visitor: &V) where V: itemlikevisit::ParItemLikeVisitor<'hir> + Sync + Send { - scope(|s| { - s.spawn(|_| { - par_iter(&self.items).for_each(|(_, item)| { - visitor.visit_item(item); - }); + parallel!({ + par_iter(&self.items).for_each(|(_, item)| { + visitor.visit_item(item); }); - - s.spawn(|_| { - par_iter(&self.trait_items).for_each(|(_, trait_item)| { - visitor.visit_trait_item(trait_item); - }); + }, { + par_iter(&self.trait_items).for_each(|(_, trait_item)| { + visitor.visit_trait_item(trait_item); }); - - s.spawn(|_| { - par_iter(&self.impl_items).for_each(|(_, impl_item)| { - visitor.visit_impl_item(impl_item); - }); + }, { + par_iter(&self.impl_items).for_each(|(_, impl_item)| { + visitor.visit_impl_item(impl_item); }); }); } @@ -799,6 +809,7 @@ pub struct MacroDef { pub vis: Visibility, pub attrs: HirVec, pub id: NodeId, + pub hir_id: HirId, pub span: Span, pub body: TokenStream, pub legacy: bool, @@ -806,14 +817,14 @@ pub struct MacroDef { #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct Block { - /// Statements in a block + /// Statements in a block. pub stmts: HirVec, /// An expression at the end of the block - /// without a semicolon, if any + /// without a semicolon, if any. pub expr: Option>, pub id: NodeId, pub hir_id: HirId, - /// Distinguishes between `unsafe { ... }` and `{ ... }` + /// Distinguishes between `unsafe { ... }` and `{ ... }`. pub rules: BlockCheckMode, pub span: Span, /// If true, then there may exist `break 'a` values that aim to @@ -880,17 +891,18 @@ impl Pat { } } -/// A single field in a struct pattern +/// A single field in a struct pattern. /// /// Patterns like the fields of Foo `{ x, ref y, ref mut z }` /// are treated the same as` x: x, y: ref y, z: ref mut z`, -/// except is_shorthand is true +/// except `is_shorthand` is true. #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct FieldPat { pub id: NodeId, - /// The identifier for the field + pub hir_id: HirId, + /// The identifier for the field. pub ident: Ident, - /// The pattern the field is destructured to + /// The pattern the field is destructured to. pub pat: P, pub is_shorthand: bool, } @@ -927,41 +939,46 @@ pub enum RangeEnd { #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub enum PatKind { - /// Represents a wildcard pattern (`_`) + /// Represents a wildcard pattern (i.e., `_`). Wild, /// A fresh binding `ref mut binding @ OPT_SUBPATTERN`. /// The `NodeId` is the canonical ID for the variable being bound, - /// e.g., in `Ok(x) | Err(x)`, both `x` use the same canonical ID, + /// (e.g., in `Ok(x) | Err(x)`, both `x` use the same canonical ID), /// which is the pattern ID of the first `x`. - Binding(BindingAnnotation, NodeId, Ident, Option>), + Binding(BindingAnnotation, NodeId, HirId, Ident, Option>), - /// A struct or struct variant pattern, e.g., `Variant {x, y, ..}`. + /// A struct or struct variant pattern (e.g., `Variant {x, y, ..}`). /// The `bool` is `true` in the presence of a `..`. Struct(QPath, HirVec>, bool), /// A tuple struct/variant pattern `Variant(x, y, .., z)`. /// If the `..` pattern fragment is present, then `Option` denotes its position. - /// 0 <= position <= subpats.len() + /// `0 <= position <= subpats.len()` TupleStruct(QPath, HirVec>, Option), /// A path pattern for an unit struct/variant or a (maybe-associated) constant. Path(QPath), - /// A tuple pattern `(a, b)`. + /// A tuple pattern (e.g., `(a, b)`). /// If the `..` pattern fragment is present, then `Option` denotes its position. - /// 0 <= position <= subpats.len() + /// `0 <= position <= subpats.len()` Tuple(HirVec>, Option), - /// A `box` pattern + + /// A `box` pattern. Box(P), - /// A reference pattern, e.g., `&mut (a, b)` + + /// A reference pattern (e.g., `&mut (a, b)`). Ref(P, Mutability), - /// A literal + + /// A literal. Lit(P), - /// A range pattern, e.g., `1...2` or `1..2` + + /// A range pattern (e.g., `1...2` or `1..2`). Range(P, P, RangeEnd), + /// `[a, b, ..i, y, z]` is represented as: - /// `PatKind::Slice(box [a, b], Some(i), box [y, z])` + /// `PatKind::Slice(box [a, b], Some(i), box [y, z])`. Slice(HirVec>, Option>, HirVec>), } @@ -972,7 +989,7 @@ pub enum Mutability { } impl Mutability { - /// Return MutMutable only if both arguments are mutable. + /// Returns `MutMutable` only if both arguments are mutable. pub fn and(self, other: Self) -> Self { match self { MutMutable => other, @@ -983,41 +1000,41 @@ impl Mutability { #[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, Copy, Hash)] pub enum BinOpKind { - /// The `+` operator (addition) + /// The `+` operator (addition). Add, - /// The `-` operator (subtraction) + /// The `-` operator (subtraction). Sub, - /// The `*` operator (multiplication) + /// The `*` operator (multiplication). Mul, - /// The `/` operator (division) + /// The `/` operator (division). Div, - /// The `%` operator (modulus) + /// The `%` operator (modulus). Rem, - /// The `&&` operator (logical and) + /// The `&&` operator (logical and). And, - /// The `||` operator (logical or) + /// The `||` operator (logical or). Or, - /// The `^` operator (bitwise xor) + /// The `^` operator (bitwise xor). BitXor, - /// The `&` operator (bitwise and) + /// The `&` operator (bitwise and). BitAnd, - /// The `|` operator (bitwise or) + /// The `|` operator (bitwise or). BitOr, - /// The `<<` operator (shift left) + /// The `<<` operator (shift left). Shl, - /// The `>>` operator (shift right) + /// The `>>` operator (shift right). Shr, - /// The `==` operator (equality) + /// The `==` operator (equality). Eq, - /// The `<` operator (less than) + /// The `<` operator (less than). Lt, - /// The `<=` operator (less than or equal to) + /// The `<=` operator (less than or equal to). Le, - /// The `!=` operator (not equal to) + /// The `!=` operator (not equal to). Ne, - /// The `>=` operator (greater than or equal to) + /// The `>=` operator (greater than or equal to). Ge, - /// The `>` operator (greater than) + /// The `>` operator (greater than). Gt, } @@ -1082,7 +1099,7 @@ impl BinOpKind { } } - /// Returns `true` if the binary operator takes its arguments by value + /// Returns `true` if the binary operator takes its arguments by value. pub fn is_by_value(self) -> bool { !self.is_comparison() } @@ -1117,11 +1134,11 @@ pub type BinOp = Spanned; #[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, Copy, Hash)] pub enum UnOp { - /// The `*` operator for dereferencing + /// The `*` operator (deferencing). UnDeref, - /// The `!` operator for logical inversion + /// The `!` operator (logical negation). UnNot, - /// The `-` operator for negation + /// The `-` operator (negation). UnNeg, } @@ -1134,7 +1151,7 @@ impl UnOp { } } - /// Returns `true` if the unary operator takes its argument by value + /// Returns `true` if the unary operator takes its argument by value. pub fn is_by_value(self) -> bool { match self { UnNeg | UnNot => true, @@ -1143,56 +1160,54 @@ impl UnOp { } } -/// A statement -pub type Stmt = Spanned; +/// A statement. +#[derive(Clone, RustcEncodable, RustcDecodable)] +pub struct Stmt { + pub id: NodeId, + pub hir_id: HirId, + pub node: StmtKind, + pub span: Span, +} -impl fmt::Debug for StmtKind { +impl fmt::Debug for Stmt { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // Sadness. - let spanned = source_map::dummy_spanned(self.clone()); - write!(f, - "stmt({}: {})", - spanned.node.id(), - print::to_string(print::NO_ANN, |s| s.print_stmt(&spanned))) + write!(f, "stmt({}: {})", self.id, + print::to_string(print::NO_ANN, |s| s.print_stmt(self))) } } #[derive(Clone, RustcEncodable, RustcDecodable)] pub enum StmtKind { - /// Could be an item or a local (let) binding: - Decl(P, NodeId), + /// A local (`let`) binding. + Local(P), + + /// An item binding. + Item(ItemId), - /// Expr without trailing semi-colon (must have unit type): - Expr(P, NodeId), + /// An expression without a trailing semi-colon (must have unit type). + Expr(P), - /// Expr with trailing semi-colon (may have any type): - Semi(P, NodeId), + /// An expression with a trailing semi-colon (may have any type). + Semi(P), } impl StmtKind { pub fn attrs(&self) -> &[Attribute] { match *self { - StmtKind::Decl(ref d, _) => d.node.attrs(), - StmtKind::Expr(ref e, _) | - StmtKind::Semi(ref e, _) => &e.attrs, - } - } - - pub fn id(&self) -> NodeId { - match *self { - StmtKind::Decl(_, id) | - StmtKind::Expr(_, id) | - StmtKind::Semi(_, id) => id, + StmtKind::Local(ref l) => &l.attrs, + StmtKind::Item(_) => &[], + StmtKind::Expr(ref e) | + StmtKind::Semi(ref e) => &e.attrs, } } } -/// Local represents a `let` statement, e.g., `let : = ;` +/// Represents a `let` statement (i.e., `let : = ;`). #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct Local { pub pat: P, pub ty: Option>, - /// Initializer expression to set the value, if any + /// Initializer expression to set the value, if any. pub init: Option>, pub id: NodeId, pub hir_id: HirId, @@ -1201,33 +1216,7 @@ pub struct Local { pub source: LocalSource, } -pub type Decl = Spanned; - -#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] -pub enum DeclKind { - /// A local (let) binding: - Local(P), - /// An item binding: - Item(ItemId), -} - -impl DeclKind { - pub fn attrs(&self) -> &[Attribute] { - match *self { - DeclKind::Local(ref l) => &l.attrs, - DeclKind::Item(_) => &[] - } - } - - pub fn is_local(&self) -> bool { - match *self { - DeclKind::Local(_) => true, - _ => false, - } - } -} - -/// represents one arm of a 'match' +/// Represents a single arm of a `match` expression. #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct Arm { pub attrs: HirVec, @@ -1244,6 +1233,7 @@ pub enum Guard { #[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct Field { pub id: NodeId, + pub hir_id: HirId, pub ident: Ident, pub expr: P, pub span: Span, @@ -1266,7 +1256,7 @@ pub enum UnsafeSource { #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct BodyId { - pub node_id: NodeId, + pub hir_id: HirId, } /// The body of a function, closure, or constant value. In the case of @@ -1300,7 +1290,7 @@ pub struct Body { impl Body { pub fn id(&self) -> BodyId { BodyId { - node_id: self.value.id + hir_id: self.value.hir_id, } } } @@ -1310,6 +1300,9 @@ pub enum BodyOwnerKind { /// Functions and methods. Fn, + /// Closures + Closure, + /// Constants and associated constants. Const, @@ -1317,12 +1310,21 @@ pub enum BodyOwnerKind { Static(Mutability), } +impl BodyOwnerKind { + pub fn is_fn_or_closure(self) -> bool { + match self { + BodyOwnerKind::Fn | BodyOwnerKind::Closure => true, + BodyOwnerKind::Const | BodyOwnerKind::Static(_) => false, + } + } +} + /// A constant (expression) that's not an item or associated item, /// but needs its own `DefId` for type-checking, const-eval, etc. /// These are usually found nested inside types (e.g., array lengths) /// or expressions (e.g., repeat counts), and also used to define /// explicit discriminant values for enum variants. -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Debug)] pub struct AnonConst { pub id: NodeId, pub hir_id: HirId, @@ -1339,6 +1341,10 @@ pub struct Expr { pub hir_id: HirId, } +// `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::() == 72); + impl Expr { pub fn precedence(&self) -> ExprPrecedence { match self.node { @@ -1440,16 +1446,16 @@ impl fmt::Debug for Expr { pub enum ExprKind { /// A `box x` expression. Box(P), - /// An array (`[a, b, c, d]`) + /// An array (e.g., `[a, b, c, d]`). Array(HirVec), - /// A function call + /// A function call. /// /// The first field resolves to the function itself (usually an `ExprKind::Path`), /// and the second field is the list of arguments. /// This also represents calling the constructor of /// tuple-like ADTs such as tuple structs and enum variants. Call(P, HirVec), - /// A method call (`x.foo::<'static, Bar, Baz>(a, b, c, d)`) + /// A method call (e.g., `x.foo::<'static, Bar, Baz>(a, b, c, d)`). /// /// The `PathSegment`/`Span` represent the method name and its generic arguments /// (within the angle brackets). @@ -1458,64 +1464,65 @@ pub enum ExprKind { /// and the remaining elements are the rest of the arguments. /// Thus, `x.foo::(a, b, c, d)` is represented as /// `ExprKind::MethodCall(PathSegment { foo, [Bar, Baz] }, [x, a, b, c, d])`. - MethodCall(PathSegment, Span, HirVec), - /// A tuple (`(a, b, c ,d)`) + MethodCall(P, Span, HirVec), + /// A tuple (e.g., `(a, b, c ,d)`). Tup(HirVec), - /// A binary operation (For example: `a + b`, `a * b`) + /// A binary operation (e.g., `a + b`, `a * b`). Binary(BinOp, P, P), - /// A unary operation (For example: `!x`, `*x`) + /// A unary operation (e.g., `!x`, `*x`). Unary(UnOp, P), - /// A literal (For example: `1`, `"foo"`) - Lit(P), - /// A cast (`foo as f64`) + /// A literal (e.g., `1`, `"foo"`). + Lit(Lit), + /// A cast (e.g., `foo as f64`). Cast(P, P), + /// A type reference (e.g., `Foo`). Type(P, P), - /// An `if` block, with an optional else block + /// An `if` block, with an optional else block. /// - /// `if expr { expr } else { expr }` + /// I.e., `if { } else { }`. If(P, P, Option>), /// A while loop, with an optional label /// - /// `'label: while expr { block }` + /// I.e., `'label: while expr { }`. While(P, P, Option::new` and /// so forth. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] -pub enum UserTypeAnnotation<'tcx> { +pub enum UserType<'tcx> { Ty(Ty<'tcx>), /// The canonical type is the result of `type_of(def_id)` with the @@ -862,17 +893,17 @@ pub enum UserTypeAnnotation<'tcx> { } EnumTypeFoldableImpl! { - impl<'tcx> TypeFoldable<'tcx> for UserTypeAnnotation<'tcx> { - (UserTypeAnnotation::Ty)(ty), - (UserTypeAnnotation::TypeOf)(def, substs), + impl<'tcx> TypeFoldable<'tcx> for UserType<'tcx> { + (UserType::Ty)(ty), + (UserType::TypeOf)(def, substs), } } EnumLiftImpl! { - impl<'a, 'tcx> Lift<'tcx> for UserTypeAnnotation<'a> { - type Lifted = UserTypeAnnotation<'tcx>; - (UserTypeAnnotation::Ty)(ty), - (UserTypeAnnotation::TypeOf)(def, substs), + impl<'a, 'tcx> Lift<'tcx> for UserType<'a> { + type Lifted = UserType<'tcx>; + (UserType::Ty)(ty), + (UserType::TypeOf)(def, substs), } } @@ -983,6 +1014,9 @@ pub struct GlobalCtxt<'tcx> { maybe_unused_trait_imports: FxHashSet, maybe_unused_extern_crates: Vec<(DefId, Span)>, + /// A map of glob use to a set of names it actually imports. Currently only + /// used in save-analysis. + glob_map: FxHashMap>, /// Extern prelude entries. The value is `true` if the entry was introduced /// via `extern crate` item and not `--extern` option or compiler built-in. pub extern_prelude: FxHashMap, @@ -1027,7 +1061,7 @@ pub struct GlobalCtxt<'tcx> { } impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { - /// Get the global TyCtxt. + /// Gets the global `TyCtxt`. #[inline] pub fn global_tcx(self) -> TyCtxt<'gcx, 'gcx, 'gcx> { TyCtxt { @@ -1072,10 +1106,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.global_arenas.adt_def.alloc(def) } - pub fn intern_const_alloc( - self, - alloc: Allocation, - ) -> &'gcx Allocation { + pub fn intern_const_alloc(self, alloc: Allocation) -> &'gcx Allocation { self.allocation_interner.borrow_mut().intern(alloc, |alloc| { self.global_arenas.const_allocs.alloc(alloc) }) @@ -1095,10 +1126,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { }) } - pub fn intern_lazy_const(self, c: ty::LazyConst<'tcx>) -> &'tcx ty::LazyConst<'tcx> { - self.global_interners.arena.alloc(c) - } - pub fn intern_layout(self, layout: LayoutDetails) -> &'gcx LayoutDetails { self.layout_interner.borrow_mut().intern(layout, |layout| { self.global_arenas.layout.alloc(layout) @@ -1134,12 +1161,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { value.lift_to_tcx(self.global_tcx()) } - /// Returns true if self is the same as self.global_tcx(). + /// Returns `true` if self is the same as self.global_tcx(). fn is_global(self) -> bool { ptr::eq(self.interners, &self.global_interners) } - /// Create a type context and call the closure with a `TyCtxt` reference + /// Creates a type context and call the closure with a `TyCtxt` reference /// to the context. The closure enforces that the type context and any interned /// value (types, substs, etc.) can only be used while `ty::tls` has a valid /// reference to the context, to allow formatting values that need it. @@ -1232,6 +1259,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { .into_iter() .map(|(id, sp)| (hir.local_def_id(id), sp)) .collect(), + glob_map: resolutions.glob_map.into_iter().map(|(id, names)| { + (hir.local_def_id(id), names) + }).collect(), extern_prelude: resolutions.extern_prelude, hir_map: hir, def_path_hash_to_def_id, @@ -1331,7 +1361,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } - /// Convert a `DefId` into its fully expanded `DefPath` (every + /// Converts a `DefId` into its fully expanded `DefPath` (every /// `DefId` is really just an interned def-path). /// /// Note that if `id` is not local to this crate, the result will @@ -1408,7 +1438,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.dep_graph.with_task(dep_node, self, crate_hash, - |_, x| x // No transformation needed + |_, x| x, // No transformation needed + dep_graph::hash_result, ); } } @@ -1648,6 +1679,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } false } + + /// Determine whether identifiers in the assembly have strict naming rules. + /// Currently, only NVPTX* targets need it. + pub fn has_strict_asm_symbol_naming(&self) -> bool { + self.gcx.sess.target.target.arch.contains("nvptx") + } } impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { @@ -1740,7 +1777,7 @@ macro_rules! nop_list_lift { impl<'a, 'tcx> Lift<'tcx> for &'a List<$ty> { type Lifted = &'tcx List<$lifted>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { - if self.is_empty() { + if self.is_empty() { return Some(List::empty()); } if tcx.interners.arena.in_arena(*self as *const _) { @@ -1789,18 +1826,18 @@ pub mod tls { use std::marker::PhantomData; use std::ptr; use syntax_pos; - use ty::query; + use crate::ty::query; use errors::{Diagnostic, TRACK_DIAGNOSTICS}; use rustc_data_structures::OnDrop; use rustc_data_structures::sync::{self, Lrc, Lock}; use rustc_data_structures::thin_vec::ThinVec; - use dep_graph::TaskDeps; + use crate::dep_graph::TaskDeps; - #[cfg(not(parallel_queries))] + #[cfg(not(parallel_compiler))] use std::cell::Cell; - #[cfg(parallel_queries)] - use rayon_core; + #[cfg(parallel_compiler)] + use rustc_rayon_core as rayon_core; /// This is the implicit state of rustc. It contains the current /// TyCtxt and query. It is updated when creating a local interner or @@ -1832,7 +1869,7 @@ pub mod tls { /// Sets Rayon's thread local variable which is preserved for Rayon jobs /// to `value` during the call to `f`. It is restored to its previous value after. /// This is used to set the pointer to the new ImplicitCtxt. - #[cfg(parallel_queries)] + #[cfg(parallel_compiler)] #[inline] fn set_tlv R, R>(value: usize, f: F) -> R { rayon_core::tlv::with(value, f) @@ -1840,20 +1877,20 @@ pub mod tls { /// Gets Rayon's thread local variable which is preserved for Rayon jobs. /// This is used to get the pointer to the current ImplicitCtxt. - #[cfg(parallel_queries)] + #[cfg(parallel_compiler)] #[inline] fn get_tlv() -> usize { rayon_core::tlv::get() } /// A thread local variable which stores a pointer to the current ImplicitCtxt - #[cfg(not(parallel_queries))] + #[cfg(not(parallel_compiler))] thread_local!(static TLV: Cell = Cell::new(0)); /// Sets TLV to `value` during the call to `f`. /// It is restored to its previous value after. /// This is used to set the pointer to the new ImplicitCtxt. - #[cfg(not(parallel_queries))] + #[cfg(not(parallel_compiler))] #[inline] fn set_tlv R, R>(value: usize, f: F) -> R { let old = get_tlv(); @@ -1863,7 +1900,7 @@ pub mod tls { } /// This is used to get the pointer to the current ImplicitCtxt. - #[cfg(not(parallel_queries))] + #[cfg(not(parallel_compiler))] fn get_tlv() -> usize { TLV.with(|tlv| tlv.get()) } @@ -2081,8 +2118,8 @@ macro_rules! sty_debug_print { // variable names. #[allow(non_snake_case)] mod inner { - use ty::{self, TyCtxt}; - use ty::context::Interned; + use crate::ty::{self, TyCtxt}; + use crate::ty::context::Interned; #[derive(Copy, Clone)] struct DebugStat { @@ -2238,6 +2275,12 @@ impl<'tcx: 'lcx, 'lcx> Borrow> for Interned<'tcx, GoalKind<'tcx>> } } +impl<'tcx: 'lcx, 'lcx> Borrow> for Interned<'tcx, LazyConst<'tcx>> { + fn borrow<'a>(&'a self) -> &'a LazyConst<'lcx> { + &self.0 + } +} + impl<'tcx: 'lcx, 'lcx> Borrow<[ExistentialPredicate<'lcx>]> for Interned<'tcx, List>> { fn borrow<'a>(&'a self) -> &'a [ExistentialPredicate<'lcx>] { @@ -2344,7 +2387,8 @@ pub fn keep_local<'tcx, T: ty::TypeFoldable<'tcx>>(x: &T) -> bool { direct_interners!('tcx, region: mk_region(|r: &RegionKind| r.keep_in_local_tcx()) -> RegionKind, - goal: mk_goal(|c: &GoalKind<'_>| keep_local(c)) -> GoalKind<'tcx> + goal: mk_goal(|c: &GoalKind<'_>| keep_local(c)) -> GoalKind<'tcx>, + lazy_const: mk_lazy_const(|c: &LazyConst<'_>| keep_local(&c)) -> LazyConst<'tcx> ); macro_rules! slice_interners { @@ -2529,7 +2573,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { #[inline] pub fn mk_array(self, ty: Ty<'tcx>, n: u64) -> Ty<'tcx> { - self.mk_ty(Array(ty, self.intern_lazy_const( + self.mk_ty(Array(ty, self.mk_lazy_const( ty::LazyConst::Evaluated(ty::Const::from_usize(self.global_tcx(), n)) ))) } @@ -2972,6 +3016,10 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) { assert_eq!(cnum, LOCAL_CRATE); Lrc::new(tcx.maybe_unused_extern_crates.clone()) }; + providers.names_imported_by_glob_use = |tcx, id| { + assert_eq!(id.krate, LOCAL_CRATE); + Lrc::new(tcx.glob_map.get(&id).cloned().unwrap_or_default()) + }; providers.stability_index = |tcx, cnum| { assert_eq!(cnum, LOCAL_CRATE); diff --git a/src/librustc/ty/erase_regions.rs b/src/librustc/ty/erase_regions.rs index bbf71c62ca69d..0431afcc76c9e 100644 --- a/src/librustc/ty/erase_regions.rs +++ b/src/librustc/ty/erase_regions.rs @@ -1,5 +1,5 @@ -use ty::{self, Ty, TyCtxt}; -use ty::fold::{TypeFolder, TypeFoldable}; +use crate::ty::{self, Ty, TyCtxt, TypeFlags}; +use crate::ty::fold::{TypeFolder, TypeFoldable}; pub(super) fn provide(providers: &mut ty::query::Providers<'_>) { *providers = ty::query::Providers { @@ -21,6 +21,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn erase_regions(self, value: &T) -> T where T : TypeFoldable<'tcx> { + // If there's nothing to erase avoid performing the query at all + if !value.has_type_flags(TypeFlags::HAS_RE_LATE_BOUND | TypeFlags::HAS_FREE_REGIONS) { + return value.clone(); + } + let value1 = value.fold_with(&mut RegionEraserVisitor { tcx: self }); debug!("erase_regions({:?}) = {:?}", value, value1); value1 diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index 834b541d4c01b..f58e5e4fb69f6 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -1,5 +1,5 @@ -use hir::def_id::DefId; -use ty::{self, Region, Ty, TyCtxt}; +use crate::hir::def_id::DefId; +use crate::ty::{self, BoundRegion, Region, Ty, TyCtxt}; use std::borrow::Cow; use std::fmt; use rustc_target::spec::abi; @@ -7,7 +7,7 @@ use syntax::ast; use errors::{Applicability, DiagnosticBuilder}; use syntax_pos::Span; -use hir; +use crate::hir; #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct ExpectedFound { @@ -27,6 +27,8 @@ pub enum TypeError<'tcx> { ArgCount, RegionsDoesNotOutlive(Region<'tcx>, Region<'tcx>), + RegionsInsufficientlyPolymorphic(BoundRegion, Region<'tcx>), + RegionsOverlyPolymorphic(BoundRegion, Region<'tcx>), RegionsPlaceholderMismatch, Sorts(ExpectedFound>), @@ -101,6 +103,18 @@ impl<'tcx> fmt::Display for TypeError<'tcx> { RegionsDoesNotOutlive(..) => { write!(f, "lifetime mismatch") } + RegionsInsufficientlyPolymorphic(br, _) => { + write!(f, + "expected bound lifetime parameter{}{}, found concrete lifetime", + if br.is_named() { " " } else { "" }, + br) + } + RegionsOverlyPolymorphic(br, _) => { + write!(f, + "expected concrete lifetime, found bound lifetime parameter{}{}", + if br.is_named() { " " } else { "" }, + br) + } RegionsPlaceholderMismatch => { write!(f, "one type is more general than the other") } @@ -237,7 +251,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { { if let Ok(snippet) = self.sess.source_map().span_to_snippet(sp) { if snippet.chars().all(|c| c.is_digit(10) || c == '-' || c == '_') { - db.span_suggestion_with_applicability( + db.span_suggestion( sp, "use a float literal", format!("{}.0", snippet), diff --git a/src/librustc/ty/fast_reject.rs b/src/librustc/ty/fast_reject.rs index 2b41fc4fe341f..59ab4561f2c87 100644 --- a/src/librustc/ty/fast_reject.rs +++ b/src/librustc/ty/fast_reject.rs @@ -1,12 +1,12 @@ -use hir::def_id::DefId; -use ich::StableHashingContext; +use crate::hir::def_id::DefId; +use crate::ich::StableHashingContext; use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult, HashStable}; use std::fmt::Debug; use std::hash::Hash; use std::mem; use syntax::ast; -use ty::{self, Ty, TyCtxt}; +use crate::ty::{self, Ty, TyCtxt}; use self::SimplifiedTypeGen::*; diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index 4fa13a01d5a92..25ec3e49cdf67 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -1,5 +1,5 @@ -use ty::subst::Substs; -use ty::{self, Ty, TypeFlags, TypeFoldable}; +use crate::ty::subst::Substs; +use crate::ty::{self, Ty, TypeFlags, TypeFoldable}; #[derive(Debug)] pub struct FlagComputation { diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index 28b6f010ce09c..aa4d1e5ea90cb 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -4,7 +4,7 @@ //! instance of a "folder" (a type which implements `TypeFolder`). Then //! the setup is intended to be: //! -//! T.fold_with(F) --calls--> F.fold_T(T) --calls--> T.super_fold_with(F) +//! T.fold_with(F) --calls--> F.fold_T(T) --calls--> T.super_fold_with(F) //! //! This way, when you define a new folder F, you can override //! `fold_T()` to customize the behavior, and invoke `T.super_fold_with()` @@ -25,16 +25,18 @@ //! proper thing. //! //! A `TypeFoldable` T can also be visited by a `TypeVisitor` V using similar setup: -//! T.visit_with(V) --calls--> V.visit_T(T) --calls--> T.super_visit_with(V). -//! These methods return true to indicate that the visitor has found what it is looking for -//! and does not need to visit anything else. +//! +//! T.visit_with(V) --calls--> V.visit_T(T) --calls--> T.super_visit_with(V). +//! +//! These methods return true to indicate that the visitor has found what it is +//! looking for, and does not need to visit anything else. -use hir::def_id::DefId; -use ty::{self, Binder, Ty, TyCtxt, TypeFlags}; +use crate::hir::def_id::DefId; +use crate::ty::{self, Binder, Ty, TyCtxt, TypeFlags}; use std::collections::BTreeMap; use std::fmt; -use util::nodemap::FxHashSet; +use crate::util::nodemap::FxHashSet; /// The TypeFoldable trait is implemented for every type that can be folded. /// Basically, every type that has a corresponding method in TypeFolder. @@ -52,7 +54,7 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { self.super_visit_with(visitor) } - /// True if `self` has any late-bound regions that are either + /// Returns `true` if `self` has any late-bound regions that are either /// bound by `binder` or bound by some binder outside of `binder`. /// If `binder` is `ty::INNERMOST`, this indicates whether /// there are any late-bound regions that appear free. @@ -60,7 +62,7 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { self.visit_with(&mut HasEscapingVarsVisitor { outer_index: binder }) } - /// True if this `self` has any regions that escape `binder` (and + /// Returns `true` if this `self` has any regions that escape `binder` (and /// hence are not bound by it). fn has_vars_bound_above(&self, binder: ty::DebruijnIndex) -> bool { self.has_vars_bound_at_or_above(binder.shifted_in(1)) @@ -141,7 +143,7 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { } } -/// The TypeFolder trait defines the actual *folding*. There is a +/// The `TypeFolder` trait defines the actual *folding*. There is a /// method defined for every foldable type. Each of these has a /// default implementation that does an "identity" fold. Within each /// identity fold, it should invoke `foo.fold_with(self)` to fold each @@ -262,7 +264,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { }); } - /// True if `callback` returns true for every region appearing free in `value`. + /// Returns `true` if `callback` returns true for every region appearing free in `value`. pub fn all_free_regions_meet( self, value: &impl TypeFoldable<'tcx>, @@ -271,7 +273,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { !self.any_free_region_meets(value, |r| !callback(r)) } - /// True if `callback` returns true for some region appearing free in `value`. + /// Returns `true` if `callback` returns true for some region appearing free in `value`. pub fn any_free_region_meets( self, value: &impl TypeFoldable<'tcx>, @@ -292,8 +294,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// ^ ^ ^ ^ /// | | | | here, would be shifted in 1 /// | | | here, would be shifted in 2 - /// | | here, would be INNERMOST shifted in by 1 - /// | here, initially, binder would be INNERMOST + /// | | here, would be `INNERMOST` shifted in by 1 + /// | here, initially, binder would be `INNERMOST` /// ``` /// /// You see that, initially, *any* bound value is free, @@ -496,12 +498,12 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for BoundVarReplacer<'a, 'gcx, 'tcx> } impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { - /// Replace all regions bound by the given `Binder` with the + /// Replaces all regions bound by the given `Binder` with the /// results returned by the closure; the closure is expected to /// return a free region (relative to this binder), and hence the /// binder is removed in the return type. The closure is invoked /// once for each unique `BoundRegion`; multiple references to the - /// same `BoundRegion` will reuse the previous result. A map is + /// same `BoundRegion` will reuse the previous result. A map is /// returned at the end with each bound region and the free region /// that replaced it. /// @@ -520,7 +522,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.replace_escaping_bound_vars(value.skip_binder(), fld_r, fld_t) } - /// Replace all escaping bound vars. The `fld_r` closure replaces escaping + /// Replaces all escaping bound vars. The `fld_r` closure replaces escaping /// bound regions while the `fld_t` closure replaces escaping bound types. pub fn replace_escaping_bound_vars( self, @@ -554,7 +556,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } - /// Replace all types or regions bound by the given `Binder`. The `fld_r` + /// Replaces all types or regions bound by the given `Binder`. The `fld_r` /// closure replaces bound regions while the `fld_t` closure replaces bound /// types. pub fn replace_bound_vars( @@ -570,7 +572,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.replace_escaping_bound_vars(value.skip_binder(), fld_r, fld_t) } - /// Replace any late-bound regions bound in `value` with + /// Replaces any late-bound regions bound in `value` with /// free variants attached to `all_outlive_scope`. pub fn liberate_late_bound_regions( &self, @@ -586,31 +588,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { }).0 } - /// Flattens multiple binding levels into one. So `for<'a> for<'b> Foo` - /// becomes `for<'a,'b> Foo`. - pub fn flatten_late_bound_regions(self, bound2_value: &Binder>) - -> Binder - where T: TypeFoldable<'tcx> - { - let bound0_value = bound2_value.skip_binder().skip_binder(); - let value = self.fold_regions(bound0_value, &mut false, |region, current_depth| { - match *region { - ty::ReLateBound(debruijn, br) => { - // We assume no regions bound *outside* of the - // binders in `bound2_value` (nmatsakis added in - // the course of this PR; seems like a reasonable - // sanity check though). - assert!(debruijn == current_depth); - self.mk_region(ty::ReLateBound(current_depth, br)) - } - _ => { - region - } - } - }); - Binder::bind(value) - } - /// Returns a set of all late-bound regions that are constrained /// by `value`, meaning that if we instantiate those LBR with /// variables and equate `value` with something else, those @@ -640,7 +617,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { collector.regions } - /// Replace any late-bound regions bound in `value` with `'erased`. Useful in codegen but also + /// Replaces any late-bound regions bound in `value` with `'erased`. Useful in codegen but also /// method lookup and a few other places where precise region relationships are not required. pub fn erase_late_bound_regions(self, value: &Binder) -> T where T : TypeFoldable<'tcx> @@ -648,13 +625,13 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.replace_late_bound_regions(value, |_| self.types.re_erased).0 } - /// Rewrite any late-bound regions so that they are anonymous. Region numbers are + /// Rewrite any late-bound regions so that they are anonymous. Region numbers are /// assigned starting at 1 and increasing monotonically in the order traversed /// by the fold operation. /// /// The chief purpose of this function is to canonicalize regions so that two /// `FnSig`s or `TraitRef`s which are equivalent up to region naming will become - /// structurally identical. For example, `for<'a, 'b> fn(&'a isize, &'b isize)` and + /// structurally identical. For example, `for<'a, 'b> fn(&'a isize, &'b isize)` and /// `for<'a, 'b> fn(&'b isize, &'a isize)` will become identical after anonymization. pub fn anonymize_late_bound_regions(self, sig: &Binder) -> Binder where T : TypeFoldable<'tcx>, @@ -818,7 +795,7 @@ pub fn shift_out_vars<'a, 'gcx, 'tcx, T>( /// scope to which it is attached, etc. An escaping var represents /// a bound var for which this processing has not yet been done. struct HasEscapingVarsVisitor { - /// Anything bound by `outer_index` or "above" is escaping + /// Anything bound by `outer_index` or "above" is escaping. outer_index: ty::DebruijnIndex, } @@ -881,10 +858,10 @@ struct LateBoundRegionsCollector { current_index: ty::DebruijnIndex, regions: FxHashSet, - /// If true, we only want regions that are known to be + /// `true` if we only want regions that are known to be /// "constrained" when you equate this type with another type. In /// particular, if you have e.g., `&'a u32` and `&'b u32`, equating - /// them constraints `'a == 'b`. But if you have `<&'a u32 as + /// them constraints `'a == 'b`. But if you have `<&'a u32 as /// Trait>::Foo` and `<&'b u32 as Trait>::Foo`, normalizing those /// types may mean that `'a` and `'b` don't appear in the results, /// so they are not considered *constrained*. diff --git a/src/librustc/ty/inhabitedness/def_id_forest.rs b/src/librustc/ty/inhabitedness/def_id_forest.rs index 41fd88607e893..3b393c3ca15bb 100644 --- a/src/librustc/ty/inhabitedness/def_id_forest.rs +++ b/src/librustc/ty/inhabitedness/def_id_forest.rs @@ -1,8 +1,8 @@ use std::mem; use smallvec::SmallVec; use syntax::ast::CRATE_NODE_ID; -use ty::context::TyCtxt; -use ty::{DefId, DefIdTree}; +use crate::ty::context::TyCtxt; +use crate::ty::{DefId, DefIdTree}; /// Represents a forest of DefIds closed under the ancestor relation. That is, /// if a DefId representing a module is contained in the forest then all @@ -22,14 +22,14 @@ pub struct DefIdForest { } impl<'a, 'gcx, 'tcx> DefIdForest { - /// Create an empty forest. + /// Creates an empty forest. pub fn empty() -> DefIdForest { DefIdForest { root_ids: SmallVec::new(), } } - /// Create a forest consisting of a single tree representing the entire + /// Creates a forest consisting of a single tree representing the entire /// crate. #[inline] pub fn full(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> DefIdForest { @@ -37,7 +37,7 @@ impl<'a, 'gcx, 'tcx> DefIdForest { DefIdForest::from_id(crate_id) } - /// Create a forest containing a DefId and all its descendants. + /// Creates a forest containing a DefId and all its descendants. pub fn from_id(id: DefId) -> DefIdForest { let mut root_ids = SmallVec::new(); root_ids.push(id); @@ -46,12 +46,12 @@ impl<'a, 'gcx, 'tcx> DefIdForest { } } - /// Test whether the forest is empty. + /// Tests whether the forest is empty. pub fn is_empty(&self) -> bool { self.root_ids.is_empty() } - /// Test whether the forest contains a given DefId. + /// Tests whether the forest contains a given DefId. pub fn contains(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, id: DefId) -> bool diff --git a/src/librustc/ty/inhabitedness/mod.rs b/src/librustc/ty/inhabitedness/mod.rs index 6dfc9681cfd86..601ffe70eec18 100644 --- a/src/librustc/ty/inhabitedness/mod.rs +++ b/src/librustc/ty/inhabitedness/mod.rs @@ -1,8 +1,8 @@ -use ty::context::TyCtxt; -use ty::{AdtDef, VariantDef, FieldDef, Ty, TyS}; -use ty::{self, DefId, Substs}; -use ty::{AdtKind, Visibility}; -use ty::TyKind::*; +use crate::ty::context::TyCtxt; +use crate::ty::{AdtDef, VariantDef, FieldDef, Ty, TyS}; +use crate::ty::{self, DefId, Substs}; +use crate::ty::{AdtKind, Visibility}; +use crate::ty::TyKind::*; pub use self::def_id_forest::DefIdForest; diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index 78b6ffaa54e17..5fc22e3c02b60 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -1,9 +1,9 @@ -use hir::Unsafety; -use hir::def_id::DefId; -use ty::{self, Ty, PolyFnSig, TypeFoldable, Substs, TyCtxt}; -use traits; +use crate::hir::Unsafety; +use crate::hir::def_id::DefId; +use crate::ty::{self, Ty, PolyFnSig, TypeFoldable, Substs, TyCtxt}; +use crate::traits; use rustc_target::spec::abi::Abi; -use util::ppaux; +use crate::util::ppaux; use std::fmt; use std::iter; @@ -22,17 +22,17 @@ pub enum InstanceDef<'tcx> { /// `::method` where `method` receives unsizeable `self: Self`. VtableShim(DefId), - /// \::call_* - /// def-id is FnTrait::call_* + /// `::call_*` + /// `DefId` is `FnTrait::call_*` FnPtrShim(DefId, Ty<'tcx>), - /// ::fn + /// `::fn` Virtual(DefId, usize), - /// <[mut closure] as FnOnce>::call_once + /// `<[mut closure] as FnOnce>::call_once` ClosureOnceShim { call_once: DefId }, - /// drop_in_place::; None for empty drop glue. + /// `drop_in_place::; None` for empty drop glue. DropGlue(DefId, Option>), ///`::clone` shim. @@ -76,6 +76,11 @@ impl<'a, 'tcx> Instance<'tcx> { let env_region = ty::ReLateBound(ty::INNERMOST, ty::BrEnv); let env_ty = tcx.mk_mut_ref(tcx.mk_region(env_region), ty); + let pin_did = tcx.lang_items().pin_type().unwrap(); + let pin_adt_ref = tcx.adt_def(pin_did); + let pin_substs = tcx.intern_substs(&[env_ty.into()]); + let env_ty = tcx.mk_adt(pin_adt_ref, pin_substs); + sig.map_bound(|sig| { let state_did = tcx.lang_items().gen_state().unwrap(); let state_adt_ref = tcx.adt_def(state_did); @@ -136,7 +141,7 @@ impl<'tcx> InstanceDef<'tcx> { &self, tcx: TyCtxt<'a, 'tcx, 'tcx> ) -> bool { - use hir::map::DefPathData; + use crate::hir::map::DefPathData; let def_id = match *self { ty::InstanceDef::Item(def_id) => def_id, ty::InstanceDef::DropGlue(_, Some(_)) => return false, @@ -215,7 +220,7 @@ impl<'a, 'b, 'tcx> Instance<'tcx> { self.def.def_id() } - /// Resolve a (def_id, substs) pair to an (optional) instance -- most commonly, + /// Resolves a `(def_id, substs)` pair to an (optional) instance -- most commonly, /// this is used to find the precise code that will run for a trait method invocation, /// if known. /// diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs index 417e14054d24f..26e2705a7a034 100644 --- a/src/librustc/ty/item_path.rs +++ b/src/librustc/ty/item_path.rs @@ -1,7 +1,7 @@ -use hir::map::DefPathData; -use hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; -use ty::{self, DefIdTree, Ty, TyCtxt}; -use middle::cstore::{ExternCrate, ExternCrateSource}; +use crate::hir::map::DefPathData; +use crate::hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; +use crate::ty::{self, DefIdTree, Ty, TyCtxt}; +use crate::middle::cstore::{ExternCrate, ExternCrateSource}; use syntax::ast; use syntax::symbol::{keywords, LocalInternedString, Symbol}; @@ -42,7 +42,7 @@ pub fn with_forced_impl_filename_line R, R>(f: F) -> R { }) } -/// Add the `crate::` prefix to paths where appropriate. +/// Adds the `crate::` prefix to paths where appropriate. pub fn with_crate_prefix R, R>(f: F) -> R { SHOULD_PREFIX_WITH_CRATE.with(|flag| { let old = flag.get(); @@ -54,7 +54,7 @@ pub fn with_crate_prefix R, R>(f: F) -> R { } impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { - /// Returns a string identifying this def-id. This string is + /// Returns a string identifying this `DefId`. This string is /// suitable for user output. It is relative to the current crate /// root, unless with_forced_absolute_paths was used. pub fn item_path_str(self, def_id: DefId) -> String { @@ -210,12 +210,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { let visible_parent = visible_parent_map.get(&cur_def).cloned(); let actual_parent = self.parent(cur_def); - debug!( - "try_push_visible_item_path: visible_parent={:?} actual_parent={:?}", - visible_parent, actual_parent, - ); let data = cur_def_key.disambiguated_data.data; + debug!( + "try_push_visible_item_path: data={:?} visible_parent={:?} actual_parent={:?}", + data, visible_parent, actual_parent, + ); let symbol = match data { // In order to output a path that could actually be imported (valid and visible), // we need to handle re-exports correctly. @@ -248,16 +248,16 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // the children of the visible parent (as was done when computing // `visible_parent_map`), looking for the specific child we currently have and then // have access to the re-exported name. - DefPathData::Module(module_name) if visible_parent != actual_parent => { - let mut name: Option = None; - if let Some(visible_parent) = visible_parent { - for child in self.item_children(visible_parent).iter() { - if child.def.def_id() == cur_def { - name = Some(child.ident); - } - } - } - name.map(|n| n.as_str()).unwrap_or(module_name.as_str()) + DefPathData::Module(actual_name) | + DefPathData::TypeNs(actual_name) if visible_parent != actual_parent => { + visible_parent + .and_then(|parent| { + self.item_children(parent) + .iter() + .find(|child| child.def.def_id() == cur_def) + .map(|child| child.ident.as_str()) + }) + .unwrap_or_else(|| actual_name.as_str()) }, _ => { data.get_opt_name().map(|n| n.as_str()).unwrap_or_else(|| { @@ -311,6 +311,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { data @ DefPathData::Misc | data @ DefPathData::TypeNs(..) | data @ DefPathData::Trait(..) | + data @ DefPathData::TraitAlias(..) | data @ DefPathData::AssocTypeInTrait(..) | data @ DefPathData::AssocTypeInImpl(..) | data @ DefPathData::AssocExistentialInImpl(..) | @@ -318,6 +319,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { data @ DefPathData::Module(..) | data @ DefPathData::TypeParam(..) | data @ DefPathData::LifetimeParam(..) | + data @ DefPathData::ConstParam(..) | data @ DefPathData::EnumVariant(..) | data @ DefPathData::Field(..) | data @ DefPathData::AnonConst | @@ -454,13 +456,13 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // only occur very early in the compiler pipeline. let parent_def_id = self.parent_def_id(impl_def_id).unwrap(); self.push_item_path(buffer, parent_def_id, pushed_prelude_crate); - let node_id = self.hir().as_local_node_id(impl_def_id).unwrap(); - let item = self.hir().expect_item(node_id); + let hir_id = self.hir().as_local_hir_id(impl_def_id).unwrap(); + let item = self.hir().expect_item_by_hir_id(hir_id); let span_str = self.sess.source_map().span_to_string(item.span); buffer.push(&format!("", span_str)); } - /// Returns the def-id of `def_id`'s parent in the def tree. If + /// Returns the `DefId` of `def_id`'s parent in the def tree. If /// this returns `None`, then `def_id` represents a crate root or /// inlined root. pub fn parent_def_id(self, def_id: DefId) -> Option { @@ -470,9 +472,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } /// As a heuristic, when we see an impl, if we see that the -/// 'self-type' is a type defined in the same module as the impl, +/// 'self type' is a type defined in the same module as the impl, /// we can omit including the path to the impl itself. This -/// function tries to find a "characteristic def-id" for a +/// function tries to find a "characteristic `DefId`" for a /// type. It's just a heuristic so it makes some questionable /// decisions and we may want to adjust it later. pub fn characteristic_def_id_of_type(ty: Ty<'_>) -> Option { @@ -527,7 +529,7 @@ pub trait ItemPathBuffer { #[derive(Debug)] pub enum RootMode { - /// Try to make a path relative to the local crate. In + /// Try to make a path relative to the local crate. In /// particular, local paths have no prefix, and if the path comes /// from an extern crate, start with the path to the `extern /// crate` declaration. diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 1162bff852cbb..6c507c0015d7b 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -1,5 +1,5 @@ -use session::{self, DataTypeKind}; -use ty::{self, Ty, TyCtxt, TypeFoldable, ReprOptions}; +use crate::session::{self, DataTypeKind}; +use crate::ty::{self, Ty, TyCtxt, TypeFoldable, ReprOptions}; use syntax::ast::{self, Ident, IntTy, UintTy}; use syntax::attr; @@ -12,7 +12,7 @@ use std::iter; use std::mem; use std::ops::Bound; -use ich::StableHashingContext; +use crate::ich::StableHashingContext; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult}; @@ -46,7 +46,7 @@ impl IntegerExt for Integer { } } - /// Get the Integer type from an attr::IntType. + /// Gets the Integer type from an attr::IntType. fn from_attr(cx: &C, ity: attr::IntType) -> Integer { let dl = cx.data_layout(); @@ -62,7 +62,7 @@ impl IntegerExt for Integer { } } - /// Find the appropriate Integer type and signedness for the given + /// Finds the appropriate Integer type and signedness for the given /// signed discriminant range and #[repr] attribute. /// N.B.: u128 values above i128::MAX will be treated as signed, but /// that shouldn't affect anything, other than maybe debuginfo. @@ -1686,7 +1686,7 @@ impl<'a, 'tcx, C> TyLayoutMethods<'tcx, C> for Ty<'tcx> tcx.types.re_static, tcx.mk_array(tcx.types.usize, 3), ) - /* FIXME use actual fn pointers + /* FIXME: use actual fn pointers Warning: naively computing the number of entries in the vtable by counting the methods on the trait + methods on all parent traits does not work, because some methods can @@ -1872,7 +1872,7 @@ impl<'a> HashStable> for Variants { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - use ty::layout::Variants::*; + use crate::ty::layout::Variants::*; mem::discriminant(self).hash_stable(hcx, hasher); match *self { @@ -1908,7 +1908,7 @@ impl<'a> HashStable> for FieldPlacement { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - use ty::layout::FieldPlacement::*; + use crate::ty::layout::FieldPlacement::*; mem::discriminant(self).hash_stable(hcx, hasher); match *self { @@ -1941,7 +1941,7 @@ impl<'a> HashStable> for Abi { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - use ty::layout::Abi::*; + use crate::ty::layout::Abi::*; mem::discriminant(self).hash_stable(hcx, hasher); match *self { @@ -1975,7 +1975,7 @@ impl<'a> HashStable> for Scalar { } } -impl_stable_hash_for!(struct ::ty::layout::LayoutDetails { +impl_stable_hash_for!(struct crate::ty::layout::LayoutDetails { variants, fields, abi, @@ -1983,7 +1983,7 @@ impl_stable_hash_for!(struct ::ty::layout::LayoutDetails { align }); -impl_stable_hash_for!(enum ::ty::layout::Integer { +impl_stable_hash_for!(enum crate::ty::layout::Integer { I8, I16, I32, @@ -1991,13 +1991,13 @@ impl_stable_hash_for!(enum ::ty::layout::Integer { I128 }); -impl_stable_hash_for!(enum ::ty::layout::Primitive { +impl_stable_hash_for!(enum crate::ty::layout::Primitive { Int(integer, signed), Float(fty), Pointer }); -impl_stable_hash_for!(struct ::ty::layout::AbiAndPrefAlign { +impl_stable_hash_for!(struct crate::ty::layout::AbiAndPrefAlign { abi, pref }); @@ -2023,7 +2023,7 @@ impl<'a, 'gcx> HashStable> for LayoutError<'gcx> fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - use ty::layout::LayoutError::*; + use crate::ty::layout::LayoutError::*; mem::discriminant(self).hash_stable(hcx, hasher); match *self { diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 26b4735d926a5..02e4fb12af5c9 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -4,31 +4,31 @@ pub use self::BorrowKind::*; pub use self::IntVarValue::*; pub use self::fold::TypeFoldable; -use hir::{map as hir_map, FreevarMap, TraitMap}; -use hir::Node; -use hir::def::{Def, CtorKind, ExportMap}; -use hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE}; -use hir::map::DefPathData; +use crate::hir::{map as hir_map, FreevarMap, GlobMap, TraitMap}; +use crate::hir::Node; +use crate::hir::def::{Def, CtorKind, ExportMap}; +use crate::hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE}; +use crate::hir::map::DefPathData; use rustc_data_structures::svh::Svh; -use ich::Fingerprint; -use ich::StableHashingContext; -use infer::canonical::Canonical; -use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem}; -use middle::resolve_lifetime::ObjectLifetimeDefault; -use mir::Mir; -use mir::interpret::{GlobalId, ErrorHandled}; -use mir::GeneratorLayout; -use session::CrateDisambiguator; -use traits::{self, Reveal}; -use ty; -use ty::layout::VariantIdx; -use ty::subst::{Subst, Substs}; -use ty::util::{IntTypeExt, Discr}; -use ty::walk::TypeWalker; -use util::captures::Captures; -use util::nodemap::{NodeSet, DefIdMap, FxHashMap}; +use crate::ich::Fingerprint; +use crate::ich::StableHashingContext; +use crate::infer::canonical::Canonical; +use crate::middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem}; +use crate::middle::resolve_lifetime::ObjectLifetimeDefault; +use crate::mir::Mir; +use crate::mir::interpret::{GlobalId, ErrorHandled}; +use crate::mir::GeneratorLayout; +use crate::session::CrateDisambiguator; +use crate::traits::{self, Reveal}; +use crate::ty; +use crate::ty::layout::VariantIdx; +use crate::ty::subst::{Subst, Substs}; +use crate::ty::util::{IntTypeExt, Discr}; +use crate::ty::walk::TypeWalker; +use crate::util::captures::Captures; +use crate::util::nodemap::{NodeSet, DefIdMap, FxHashMap}; use arena::SyncDroplessArena; -use session::DataTypeKind; +use crate::session::DataTypeKind; use serialize::{self, Encodable, Encoder}; use std::cell::RefCell; @@ -39,18 +39,18 @@ use std::ops::Deref; use rustc_data_structures::sync::{self, Lrc, ParallelIterator, par_iter}; use std::slice; use std::{mem, ptr}; -use syntax::ast::{self, DUMMY_NODE_ID, Name, Ident, NodeId}; +use syntax::ast::{self, Name, Ident, NodeId}; use syntax::attr; use syntax::ext::hygiene::Mark; use syntax::symbol::{keywords, Symbol, LocalInternedString, InternedString}; -use syntax_pos::{DUMMY_SP, Span}; +use syntax_pos::Span; use smallvec; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult, HashStable}; -use hir; +use crate::hir; pub use self::sty::{Binder, BoundTy, BoundTyKind, BoundVar, DebruijnIndex, INNERMOST}; pub use self::sty::{FnSig, GenSig, CanonicalPolyFnSig, PolyFnSig, PolyGenSig}; @@ -73,8 +73,8 @@ pub use self::binding::BindingMode::*; pub use self::context::{TyCtxt, FreeRegionInfo, GlobalArenas, AllArenas, tls, keep_local}; pub use self::context::{Lift, TypeckTables, CtxtInterners}; pub use self::context::{ - UserTypeAnnotationIndex, UserTypeAnnotation, CanonicalUserTypeAnnotation, - CanonicalUserTypeAnnotations, + UserTypeAnnotationIndex, UserType, CanonicalUserType, + CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, ResolvedOpaqueTy, }; pub use self::instance::{Instance, InstanceDef}; @@ -115,16 +115,6 @@ mod sty; // Data types -/// The complete set of all analyses described in this module. This is -/// produced by the driver and fed to codegen and later passes. -/// -/// N.B., these contents are being migrated into queries using the -/// *on-demand* infrastructure. -#[derive(Clone)] -pub struct CrateAnalysis { - pub glob_map: hir::GlobMap, -} - #[derive(Clone)] pub struct Resolutions { pub freevars: FreevarMap, @@ -132,6 +122,7 @@ pub struct Resolutions { pub maybe_unused_trait_imports: NodeSet, pub maybe_unused_extern_crates: Vec<(NodeId, Span)>, pub export_map: ExportMap, + pub glob_map: GlobMap, /// Extern prelude entries. The value is `true` if the entry was introduced /// via `extern crate` item and not `--extern` option or compiler built-in. pub extern_prelude: FxHashMap, @@ -144,8 +135,8 @@ pub enum AssociatedItemContainer { } impl AssociatedItemContainer { - /// Asserts that this is the def-id of an associated item declared - /// in a trait, and returns the trait def-id. + /// Asserts that this is the `DefId` of an associated item declared + /// in a trait, and returns the trait `DefId`. pub fn assert_trait(&self) -> DefId { match *self { TraitContainer(id) => id, @@ -163,7 +154,7 @@ impl AssociatedItemContainer { /// The "header" of an impl is everything outside the body: a Self type, a trait /// ref (in the case of a trait impl), and a set of predicates (from the -/// bounds/where clauses). +/// bounds / where-clauses). #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub struct ImplHeader<'tcx> { pub impl_def_id: DefId, @@ -337,7 +328,7 @@ pub enum Variance { /// item. pub struct CrateVariancesMap { /// For each item with generics, maps to a vector of the variance - /// of its generics. If an item has no generics, it will have no + /// of its generics. If an item has no generics, it will have no /// entry. pub variances: FxHashMap>>, @@ -347,7 +338,7 @@ pub struct CrateVariancesMap { impl Variance { /// `a.xform(b)` combines the variance of a context with the - /// variance of a type with the following meaning. If we are in a + /// variance of a type with the following meaning. If we are in a /// context with variance `a`, and we encounter a type argument in /// a position with variance `b`, then `a.xform(b)` is the new /// variance with which the argument appears. @@ -371,10 +362,10 @@ impl Variance { /// The ambient variance is covariant. A `fn` type is /// contravariant with respect to its parameters, so the variance /// within which both pointer types appear is - /// `Covariant.xform(Contravariant)`, or `Contravariant`. `*const + /// `Covariant.xform(Contravariant)`, or `Contravariant`. `*const /// T` is covariant with respect to `T`, so the variance within /// which the first `Vec` appears is - /// `Contravariant.xform(Covariant)` or `Contravariant`. The same + /// `Contravariant.xform(Covariant)` or `Contravariant`. The same /// is true for its `i32` argument. In the `*mut T` case, the /// variance of `Vec` is `Contravariant.xform(Invariant)`, /// and hence the outermost type is `Invariant` with respect to @@ -498,12 +489,12 @@ pub struct TyS<'tcx> { /// So, for a type without any late-bound things, like `u32`, this /// will be *innermost*, because that is the innermost binder that /// captures nothing. But for a type `&'D u32`, where `'D` is a - /// late-bound region with debruijn index `D`, this would be `D + 1` + /// late-bound region with De Bruijn index `D`, this would be `D + 1` /// -- the binder itself does not capture `D`, but `D` is captured /// by an inner binder. /// /// We call this concept an "exclusive" binder `D` because all - /// debruijn indices within the type are contained within `0..D` + /// De Bruijn indices within the type are contained within `0..D` /// (exclusive). outer_exclusive_binder: ty::DebruijnIndex, } @@ -729,9 +720,9 @@ pub struct UpvarPath { pub hir_id: hir::HirId, } -/// Upvars do not get their own node-id. Instead, we use the pair of -/// the original var id (that is, the root variable that is referenced -/// by the upvar) and the id of the closure expression. +/// Upvars do not get their own `NodeId`. Instead, we use the pair of +/// the original var ID (that is, the root variable that is referenced +/// by the upvar) and the ID of the closure expression. #[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub struct UpvarId { pub var_path: UpvarPath, @@ -743,7 +734,7 @@ pub enum BorrowKind { /// Data must be immutable and is aliasable. ImmBorrow, - /// Data must be immutable but not aliasable. This kind of borrow + /// Data must be immutable but not aliasable. This kind of borrow /// cannot currently be expressed by the user and is used only in /// implicit closure bindings. It is needed when the closure /// is borrowing or mutating a mutable referent, e.g.: @@ -1105,7 +1096,7 @@ impl<'a, 'gcx, 'tcx> Predicate<'tcx> { /// Performs a substitution suitable for going from a /// poly-trait-ref to supertraits that must hold if that /// poly-trait-ref holds. This is slightly different from a normal - /// substitution in terms of what happens with bound regions. See + /// substitution in terms of what happens with bound regions. See /// lengthy comment below for details. pub fn subst_supertrait(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, trait_ref: &ty::PolyTraitRef<'tcx>) @@ -1244,7 +1235,7 @@ pub type PolySubtypePredicate<'tcx> = ty::Binder>; /// This kind of predicate has no *direct* correspondent in the /// syntax, but it roughly corresponds to the syntactic forms: /// -/// 1. `T: TraitRef<..., Item=Type>` +/// 1. `T: TraitRef<..., Item = Type>` /// 2. `>::Item == Type` (NYI) /// /// In particular, form #1 is "desugared" to the combination of a @@ -1465,8 +1456,8 @@ impl<'tcx> Predicate<'tcx> { } /// Represents the bounds declared on a particular set of type -/// parameters. Should eventually be generalized into a flag list of -/// where clauses. You can obtain a `InstantiatedPredicates` list from a +/// parameters. Should eventually be generalized into a flag list of +/// where-clauses. You can obtain a `InstantiatedPredicates` list from a /// `GenericPredicates` by using the `instantiate` method. Note that this method /// reflects an important semantic invariant of `InstantiatedPredicates`: while /// the `GenericPredicates` are expressed in terms of the bound type @@ -1480,7 +1471,7 @@ impl<'tcx> Predicate<'tcx> { /// struct Foo> { ... } /// /// Here, the `GenericPredicates` for `Foo` would contain a list of bounds like -/// `[[], [U:Bar]]`. Now if there were some particular reference +/// `[[], [U:Bar]]`. Now if there were some particular reference /// like `Foo`, then the `InstantiatedPredicates` would be `[[], /// [usize:Bar]]`. #[derive(Clone)] @@ -1546,7 +1537,7 @@ impl UniverseIndex { /// Returns the "next" universe index in order -- this new index /// is considered to extend all previous universes. This - /// corresponds to entering a `forall` quantifier. So, for + /// corresponds to entering a `forall` quantifier. So, for /// example, suppose we have this type in universe `U`: /// /// ``` @@ -1628,7 +1619,7 @@ pub struct ParamEnv<'tcx> { impl<'tcx> ParamEnv<'tcx> { /// Construct a trait environment suitable for contexts where - /// there are no where clauses in scope. Hidden types (like `impl + /// there are no where-clauses in scope. Hidden types (like `impl /// Trait`) are left hidden, so this is suitable for ordinary /// type-checking. #[inline] @@ -1636,12 +1627,12 @@ impl<'tcx> ParamEnv<'tcx> { Self::new(List::empty(), Reveal::UserFacing, None) } - /// Construct a trait environment with no where clauses in scope + /// Construct a trait environment with no where-clauses in scope /// where the values of all `impl Trait` and other hidden types /// are revealed. This is suitable for monomorphized, post-typeck /// environments like codegen or doing optimizations. /// - /// N.B. If you want to have predicates in scope, use `ParamEnv::new`, + /// N.B., if you want to have predicates in scope, use `ParamEnv::new`, /// or invoke `param_env.with_reveal_all()`. #[inline] pub fn reveal_all() -> Self { @@ -1660,7 +1651,7 @@ impl<'tcx> ParamEnv<'tcx> { /// Returns a new parameter environment with the same clauses, but /// which "reveals" the true results of projections in all cases - /// (even for associated types that are specializable). This is + /// (even for associated types that are specializable). This is /// the desired behavior during codegen and certain other special /// contexts; normally though we want to use `Reveal::UserFacing`, /// which is the default. @@ -1745,7 +1736,7 @@ impl<'a, 'gcx, T> HashStable> for ParamEnvAnd<'gcx, T> #[derive(Copy, Clone, Debug)] pub struct Destructor { - /// The def-id of the destructor method + /// The `DefId` of the destructor method pub did: DefId, } @@ -1790,20 +1781,21 @@ pub struct VariantDef { } impl<'a, 'gcx, 'tcx> VariantDef { - /// Create a new `VariantDef`. + /// Creates a new `VariantDef`. /// - /// - `did` is the DefId used for the variant - for tuple-structs, it is the constructor DefId, - /// and for everything else, it is the variant DefId. + /// - `did` is the `DefId` used for the variant. + /// This is the constructor `DefId` for tuple stucts, and the variant `DefId` for everything + /// else. /// - `attribute_def_id` is the DefId that has the variant's attributes. - /// this is the struct DefId for structs, and the variant DefId for variants. + /// This is the struct `DefId` for structs, and the variant `DefId` for variants. /// - /// Note that we *could* use the constructor DefId, because the constructor attributes + /// Note that we *could* use the constructor `DefId`, because the constructor attributes /// redirect to the base attributes, but compiling a small crate requires - /// loading the AdtDefs for all the structs in the universe (e.g., coherence for any + /// loading the `AdtDef`s for all the structs in the universe (e.g., coherence for any /// built-in trait), and we do not want to load attributes twice. /// /// If someone speeds up attribute loading to not be a performance concern, they can - /// remove this hack and use the constructor DefId everywhere. + /// remove this hack and use the constructor `DefId` everywhere. pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>, did: DefId, ident: Ident, @@ -2058,13 +2050,13 @@ impl ReprOptions { } /// Returns `true` if this `#[repr()]` should inhibit struct field reordering - /// optimizations, such as with repr(C), repr(packed(1)), or repr(). + /// optimizations, such as with `repr(C)`, `repr(packed(1))`, or `repr()`. pub fn inhibit_struct_field_reordering_opt(&self) -> bool { self.flags.intersects(ReprFlags::IS_UNOPTIMISABLE) || self.pack == 1 || self.int.is_some() } - /// Returns true if this `#[repr()]` should inhibit union abi optimisations + /// Returns `true` if this `#[repr()]` should inhibit union ABI optimisations. pub fn inhibit_union_abi_opt(&self) -> bool { self.c() } @@ -2179,14 +2171,14 @@ impl<'a, 'gcx, 'tcx> AdtDef { self.flags.contains(AdtFlags::HAS_CTOR) } - /// Returns whether this type is `#[fundamental]` for the purposes + /// Returns `true` if this type is `#[fundamental]` for the purposes /// of coherence checking. #[inline] pub fn is_fundamental(&self) -> bool { self.flags.contains(AdtFlags::IS_FUNDAMENTAL) } - /// Returns `true` if this is PhantomData. + /// Returns `true` if this is `PhantomData`. #[inline] pub fn is_phantom_data(&self) -> bool { self.flags.contains(AdtFlags::IS_PHANTOM_DATA) @@ -2208,7 +2200,7 @@ impl<'a, 'gcx, 'tcx> AdtDef { self.flags.contains(AdtFlags::IS_BOX) } - /// Returns whether this type has a destructor. + /// Returns `true` if this type has a destructor. pub fn has_dtor(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> bool { self.destructor(tcx).is_some() } @@ -2286,7 +2278,7 @@ impl<'a, 'gcx, 'tcx> AdtDef { }) } else { info!("invalid enum discriminant: {:#?}", val); - ::mir::interpret::struct_error( + crate::mir::interpret::struct_error( tcx.at(tcx.def_span(expr_did)), "constant evaluation of enum discriminant resulted in non-integer", ).emit(); @@ -2329,7 +2321,7 @@ impl<'a, 'gcx, 'tcx> AdtDef { }) } - /// Compute the discriminant value used by a specific variant. + /// Computes the discriminant value used by a specific variant. /// Unlike `discriminants`, this is (amortized) constant-time, /// only doing at most one query for evaluating an explicit /// discriminant (the last one before the requested variant), @@ -2345,9 +2337,9 @@ impl<'a, 'gcx, 'tcx> AdtDef { explicit_value.checked_add(tcx, offset as u128).0 } - /// Yields a DefId for the discriminant and an offset to add to it + /// Yields a `DefId` for the discriminant and an offset to add to it /// Alternatively, if there is no explicit discriminant, returns the - /// inferred discriminant directly + /// inferred discriminant directly. pub fn discriminant_def_for_variant( &self, variant_index: VariantIdx, @@ -2377,30 +2369,17 @@ impl<'a, 'gcx, 'tcx> AdtDef { } /// Returns a list of types such that `Self: Sized` if and only - /// if that type is Sized, or `TyErr` if this type is recursive. + /// if that type is `Sized`, or `TyErr` if this type is recursive. /// - /// Oddly enough, checking that the sized-constraint is Sized is + /// Oddly enough, checking that the sized-constraint is `Sized` is /// actually more expressive than checking all members: - /// the Sized trait is inductive, so an associated type that references - /// Self would prevent its containing ADT from being Sized. + /// the `Sized` trait is inductive, so an associated type that references + /// `Self` would prevent its containing ADT from being `Sized`. /// /// Due to normalization being eager, this applies even if - /// the associated type is behind a pointer, e.g., issue #31299. + /// the associated type is behind a pointer (e.g., issue #31299). pub fn sized_constraint(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> &'tcx [Ty<'tcx>] { - match tcx.try_adt_sized_constraint(DUMMY_SP, self.did) { - Ok(tys) => tys, - Err(mut bug) => { - debug!("adt_sized_constraint: {:?} is recursive", self); - // This should be reported as an error by `check_representable`. - // - // Consider the type as Sized in the meanwhile to avoid - // further errors. Delay our `bug` diagnostic here to get - // emitted later as well in case we accidentally otherwise don't - // emit an error. - bug.delay_as_bug(); - tcx.intern_type_list(&[tcx.types.err]) - } - } + tcx.adt_sized_constraint(self.did).0 } fn sized_constraint_for_ty(&self, @@ -2489,7 +2468,7 @@ impl<'a, 'gcx, 'tcx> FieldDef { } } -/// Represents the various closure traits in the Rust language. This +/// Represents the various closure traits in the language. This /// will determine the type of the environment (`self`, in the /// desugaring) argument that the closure expects. /// @@ -2561,7 +2540,7 @@ impl<'tcx> TyS<'tcx> { TypeWalker::new(self) } - /// Iterator that walks the immediate children of `self`. Hence + /// Iterator that walks the immediate children of `self`. Hence /// `Foo, u32>` yields the sequence `[Bar, u32]` /// (but not `i32`, like `walk`). pub fn walk_shallow(&'tcx self) -> smallvec::IntoIter> { @@ -2569,7 +2548,7 @@ impl<'tcx> TyS<'tcx> { } /// Walks `ty` and any types appearing within `ty`, invoking the - /// callback `f` on each type. If the callback returns false, then the + /// callback `f` on each type. If the callback returns `false`, then the /// children of the current type are ignored. /// /// Note: prefer `ty.walk()` where possible. @@ -2679,7 +2658,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.typeck_tables_of(self.hir().body_owner_def_id(body)) } - /// Returns an iterator of the def-ids for all body-owners in this + /// Returns an iterator of the `DefId`s for all body-owners in this /// crate. If you would prefer to iterate over the bodies /// themselves, you can do `self.hir().krate().body_ids.iter()`. pub fn body_owners( @@ -2803,7 +2782,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn find_field_index(self, ident: Ident, variant: &VariantDef) -> Option { variant.fields.iter().position(|field| { - self.adjust_ident(ident, variant.did, DUMMY_NODE_ID).0 == field.ident.modern() + self.adjust_ident(ident, variant.did, hir::DUMMY_HIR_ID).0 == field.ident.modern() }) } @@ -2926,7 +2905,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } - /// Return the possibly-auto-generated MIR of a (DefId, Subst) pair. + /// Returns the possibly-auto-generated MIR of a `(DefId, Subst)` pair. pub fn instance_mir(self, instance: ty::InstanceDef<'gcx>) -> &'gcx Mir<'gcx> { @@ -2946,26 +2925,16 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } - /// Given the DefId of an item, returns its MIR, borrowed immutably. - /// Returns None if there is no MIR for the DefId - pub fn maybe_optimized_mir(self, did: DefId) -> Option<&'gcx Mir<'gcx>> { - if self.is_mir_available(did) { - Some(self.optimized_mir(did)) - } else { - None - } - } - - /// Get the attributes of a definition. + /// Gets the attributes of a definition. pub fn get_attrs(self, did: DefId) -> Attributes<'gcx> { - if let Some(id) = self.hir().as_local_node_id(did) { - Attributes::Borrowed(self.hir().attrs(id)) + if let Some(id) = self.hir().as_local_hir_id(did) { + Attributes::Borrowed(self.hir().attrs_by_hir_id(id)) } else { Attributes::Owned(self.item_attrs(did)) } } - /// Determine whether an item is annotated with an attribute. + /// Determines whether an item is annotated with an attribute. pub fn has_attr(self, did: DefId, attr: &str) -> bool { attr::contains_name(&self.get_attrs(did), attr) } @@ -2979,14 +2948,14 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.optimized_mir(def_id).generator_layout.as_ref().unwrap() } - /// Given the def-id of an impl, return the def_id of the trait it implements. - /// If it implements no trait, return `None`. + /// Given the `DefId` of an impl, returns the `DefId` of the trait it implements. + /// If it implements no trait, returns `None`. pub fn trait_id_of_impl(self, def_id: DefId) -> Option { self.impl_trait_ref(def_id).map(|tr| tr.def_id) } - /// If the given defid describes a method belonging to an impl, return the - /// def-id of the impl that the method belongs to. Otherwise, return `None`. + /// If the given defid describes a method belonging to an impl, returns the + /// `DefId` of the impl that the method belongs to; otherwise, returns `None`. pub fn impl_of_method(self, def_id: DefId) -> Option { let item = if def_id.krate != LOCAL_CRATE { if let Some(Def::Method(_)) = self.describe_def(def_id) { @@ -3010,21 +2979,21 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// with the name of the crate containing the impl. pub fn span_of_impl(self, impl_did: DefId) -> Result { if impl_did.is_local() { - let node_id = self.hir().as_local_node_id(impl_did).unwrap(); - Ok(self.hir().span(node_id)) + let hir_id = self.hir().as_local_hir_id(impl_did).unwrap(); + Ok(self.hir().span_by_hir_id(hir_id)) } else { Err(self.crate_name(impl_did.krate)) } } - // Hygienically compare a use-site name (`use_name`) for a field or an associated item with its - // supposed definition name (`def_name`). The method also needs `DefId` of the supposed - // definition's parent/scope to perform comparison. + /// Hygienically compares a use-site name (`use_name`) for a field or an associated item with + /// its supposed definition name (`def_name`). The method also needs `DefId` of the supposed + /// definition's parent/scope to perform comparison. pub fn hygienic_eq(self, use_name: Ident, def_name: Ident, def_parent_def_id: DefId) -> bool { - self.adjust_ident(use_name, def_parent_def_id, DUMMY_NODE_ID).0 == def_name.modern() + self.adjust_ident(use_name, def_parent_def_id, hir::DUMMY_HIR_ID).0 == def_name.modern() } - pub fn adjust_ident(self, mut ident: Ident, scope: DefId, block: NodeId) -> (Ident, DefId) { + pub fn adjust_ident(self, mut ident: Ident, scope: DefId, block: hir::HirId) -> (Ident, DefId) { ident = ident.modern(); let target_expansion = match scope.krate { LOCAL_CRATE => self.hir().definitions().expansion_that_defined(scope.index), @@ -3033,8 +3002,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { let scope = match ident.span.adjust(target_expansion) { Some(actual_expansion) => self.hir().definitions().parent_module_of_macro_def(actual_expansion), - None if block == DUMMY_NODE_ID => DefId::local(CRATE_DEF_INDEX), // Dummy DefId - None => self.hir().get_module_parent(block), + None if block == hir::DUMMY_HIR_ID => DefId::local(CRATE_DEF_INDEX), // Dummy DefId + None => self.hir().get_module_parent_by_hir_id(block), }; (ident, scope) } @@ -3101,7 +3070,10 @@ fn associated_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Asso parent_item.node) } -/// Calculates the Sized-constraint. +#[derive(Clone)] +pub struct AdtSizedConstraint<'tcx>(pub &'tcx [Ty<'tcx>]); + +/// Calculates the `Sized` constraint. /// /// In fact, there are only a few options for the types in the constraint: /// - an obviously-unsized type @@ -3112,7 +3084,7 @@ fn associated_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Asso /// check should catch this case. fn adt_sized_constraint<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) - -> &'tcx [Ty<'tcx>] { + -> AdtSizedConstraint<'tcx> { let def = tcx.adt_def(def_id); let result = tcx.mk_type_list(def.variants.iter().flat_map(|v| { @@ -3123,14 +3095,14 @@ fn adt_sized_constraint<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, debug!("adt_sized_constraint: {:?} => {:?}", def, result); - result + AdtSizedConstraint(result) } fn associated_item_def_ids<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Lrc> { - let id = tcx.hir().as_local_node_id(def_id).unwrap(); - let item = tcx.hir().expect_item(id); + let id = tcx.hir().as_local_hir_id(def_id).unwrap(); + let item = tcx.hir().expect_item_by_hir_id(id); let vec: Vec<_> = match item.node { hir::ItemKind::Trait(.., ref trait_item_refs) => { trait_item_refs.iter() @@ -3154,9 +3126,9 @@ fn def_span<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Span { tcx.hir().span_if_local(def_id).unwrap() } -/// If the given def ID describes an item belonging to a trait, -/// return the ID of the trait that the trait item belongs to. -/// Otherwise, return `None`. +/// If the given `DefId` describes an item belonging to a trait, +/// returns the `DefId` of the trait that the trait item belongs to; +/// otherwise, returns `None`. fn trait_of_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Option { tcx.opt_associated_item(def_id) .and_then(|associated_item| { @@ -3179,18 +3151,6 @@ pub fn is_impl_trait_defn(tcx: TyCtxt<'_, '_, '_>, def_id: DefId) -> Option, def_id: DefId) -> bool { - if let Some(node_id) = tcx.hir().as_local_node_id(def_id) { - if let Node::Item(item) = tcx.hir().get(node_id) { - if let hir::ItemKind::TraitAlias(..) = item.node { - return true; - } - } - } - false -} - /// See `ParamEnv` struct definition for details. fn param_env<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) @@ -3223,8 +3183,8 @@ fn param_env<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if tcx.sess.opts.debugging_opts.chalk { Some(def_id) } else { None } ); - let body_id = tcx.hir().as_local_node_id(def_id).map_or(DUMMY_NODE_ID, |id| { - tcx.hir().maybe_body_owned_by(id).map_or(id, |body| body.node_id) + let body_id = tcx.hir().as_local_hir_id(def_id).map_or(hir::DUMMY_HIR_ID, |id| { + tcx.hir().maybe_body_owned_by_by_hir_id(id).map_or(id, |body| body.hir_id) }); let cause = traits::ObligationCause::misc(tcx.def_span(def_id), body_id); traits::normalize_param_env_or_error(tcx, def_id, unnormalized_env, cause) @@ -3263,10 +3223,9 @@ fn instance_def_size_estimate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } -/// If `def_id` is an issue 33140 hack impl, return its self type. Otherwise -/// return None. +/// If `def_id` is an issue 33140 hack impl, returns its self type; otherwise, returns `None`. /// -/// See ImplOverlapKind::Issue33140 for more details. +/// See [`ImplOverlapKind::Issue33140`] for more details. fn issue33140_self_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Option> diff --git a/src/librustc/ty/outlives.rs b/src/librustc/ty/outlives.rs index ca2d5cd718c64..5b21ed5abd77b 100644 --- a/src/librustc/ty/outlives.rs +++ b/src/librustc/ty/outlives.rs @@ -3,7 +3,7 @@ // RFC for reference. use smallvec::SmallVec; -use ty::{self, Ty, TyCtxt, TypeFoldable}; +use crate::ty::{self, Ty, TyCtxt, TypeFoldable}; #[derive(Debug)] pub enum Component<'tcx> { diff --git a/src/librustc/ty/query/README.md b/src/librustc/ty/query/README.md index 0fcaef5de54c2..4b5e08cecd99c 100644 --- a/src/librustc/ty/query/README.md +++ b/src/librustc/ty/query/README.md @@ -1,302 +1,3 @@ -# The Rust Compiler Query System - -The Compiler Query System is the key to our new demand-driven -organization. The idea is pretty simple. You have various queries -that compute things about the input -- for example, there is a query -called `type_of(def_id)` that, given the def-id of some item, will -compute the type of that item and return it to you. - -Query execution is **memoized** -- so the first time you invoke a -query, it will go do the computation, but the next time, the result is -returned from a hashtable. Moreover, query execution fits nicely into -**incremental computation**; the idea is roughly that, when you do a -query, the result **may** be returned to you by loading stored data -from disk (but that's a separate topic we won't discuss further here). - -The overall vision is that, eventually, the entire compiler -control-flow will be query driven. There will effectively be one -top-level query ("compile") that will run compilation on a crate; this -will in turn demand information about that crate, starting from the -*end*. For example: - -- This "compile" query might demand to get a list of codegen-units - (i.e., modules that need to be compiled by LLVM). -- But computing the list of codegen-units would invoke some subquery - that returns the list of all modules defined in the Rust source. -- That query in turn would invoke something asking for the HIR. -- This keeps going further and further back until we wind up doing the - actual parsing. - -However, that vision is not fully realized. Still, big chunks of the -compiler (for example, generating MIR) work exactly like this. - -### Invoking queries - -To invoke a query is simple. The tcx ("type context") offers a method -for each defined query. So, for example, to invoke the `type_of` -query, you would just do this: - -```rust -let ty = tcx.type_of(some_def_id); -``` - -### Cycles between queries - -Currently, cycles during query execution should always result in a -compilation error. Typically, they arise because of illegal programs -that contain cyclic references they shouldn't (though sometimes they -arise because of compiler bugs, in which case we need to factor our -queries in a more fine-grained fashion to avoid them). - -However, it is nonetheless often useful to *recover* from a cycle -(after reporting an error, say) and try to soldier on, so as to give a -better user experience. In order to recover from a cycle, you don't -get to use the nice method-call-style syntax. Instead, you invoke -using the `try_get` method, which looks roughly like this: - -```rust -use ty::query::queries; -... -match queries::type_of::try_get(tcx, DUMMY_SP, self.did) { - Ok(result) => { - // no cycle occurred! You can use `result` - } - Err(err) => { - // A cycle occurred! The error value `err` is a `DiagnosticBuilder`, - // meaning essentially an "in-progress", not-yet-reported error message. - // See below for more details on what to do here. - } -} -``` - -So, if you get back an `Err` from `try_get`, then a cycle *did* occur. This means that -you must ensure that a compiler error message is reported. You can do that in two ways: - -The simplest is to invoke `err.emit()`. This will emit the cycle error to the user. - -However, often cycles happen because of an illegal program, and you -know at that point that an error either already has been reported or -will be reported due to this cycle by some other bit of code. In that -case, you can invoke `err.cancel()` to not emit any error. It is -traditional to then invoke: - -``` -tcx.sess.delay_span_bug(some_span, "some message") -``` - -`delay_span_bug()` is a helper that says: we expect a compilation -error to have happened or to happen in the future; so, if compilation -ultimately succeeds, make an ICE with the message `"some -message"`. This is basically just a precaution in case you are wrong. - -### How the compiler executes a query - -So you may be wondering what happens when you invoke a query -method. The answer is that, for each query, the compiler maintains a -cache -- if your query has already been executed, then, the answer is -simple: we clone the return value out of the cache and return it -(therefore, you should try to ensure that the return types of queries -are cheaply cloneable; insert a `Rc` if necessary). - -#### Providers - -If, however, the query is *not* in the cache, then the compiler will -try to find a suitable **provider**. A provider is a function that has -been defined and linked into the compiler somewhere that contains the -code to compute the result of the query. - -**Providers are defined per-crate.** The compiler maintains, -internally, a table of providers for every crate, at least -conceptually. Right now, there are really two sets: the providers for -queries about the **local crate** (that is, the one being compiled) -and providers for queries about **external crates** (that is, -dependencies of the local crate). Note that what determines the crate -that a query is targeting is not the *kind* of query, but the *key*. -For example, when you invoke `tcx.type_of(def_id)`, that could be a -local query or an external query, depending on what crate the `def_id` -is referring to (see the `self::keys::Key` trait for more information -on how that works). - -Providers always have the same signature: - -```rust -fn provider<'cx, 'tcx>(tcx: TyCtxt<'cx, 'tcx, 'tcx>, - key: QUERY_KEY) - -> QUERY_RESULT -{ - ... -} -``` - -Providers take two arguments: the `tcx` and the query key. Note also -that they take the *global* tcx (i.e., they use the `'tcx` lifetime -twice), rather than taking a tcx with some active inference context. -They return the result of the query. - -#### How providers are setup - -When the tcx is created, it is given the providers by its creator using -the `Providers` struct. This struct is generate by the macros here, but it -is basically a big list of function pointers: - -```rust -struct Providers { - type_of: for<'cx, 'tcx> fn(TyCtxt<'cx, 'tcx, 'tcx>, DefId) -> Ty<'tcx>, - ... -} -``` - -At present, we have one copy of the struct for local crates, and one -for external crates, though the plan is that we may eventually have -one per crate. - -These `Provider` structs are ultimately created and populated by -`librustc_driver`, but it does this by distributing the work -throughout the other `rustc_*` crates. This is done by invoking -various `provide` functions. These functions tend to look something -like this: - -```rust -pub fn provide(providers: &mut Providers) { - *providers = Providers { - type_of, - ..*providers - }; -} -``` - -That is, they take an `&mut Providers` and mutate it in place. Usually -we use the formulation above just because it looks nice, but you could -as well do `providers.type_of = type_of`, which would be equivalent. -(Here, `type_of` would be a top-level function, defined as we saw -before.) So, if we want to add a provider for some other query, -let's call it `fubar`, into the crate above, we might modify the `provide()` -function like so: - -```rust -pub fn provide(providers: &mut Providers) { - *providers = Providers { - type_of, - fubar, - ..*providers - }; -} - -fn fubar<'cx, 'tcx>(tcx: TyCtxt<'cx, 'tcx>, key: DefId) -> Fubar<'tcx> { .. } -``` - -NB. Most of the `rustc_*` crates only provide **local -providers**. Almost all **extern providers** wind up going through the -`rustc_metadata` crate, which loads the information from the crate -metadata. But in some cases there are crates that provide queries for -*both* local and external crates, in which case they define both a -`provide` and a `provide_extern` function that `rustc_driver` can -invoke. - -### Adding a new kind of query - -So suppose you want to add a new kind of query, how do you do so? -Well, defining a query takes place in two steps: - -1. first, you have to specify the query name and arguments; and then, -2. you have to supply query providers where needed. - -To specify the query name and arguments, you simply add an entry -to the big macro invocation in `mod.rs`. This will probably have changed -by the time you read this README, but at present it looks something -like: - -``` -define_queries! { <'tcx> - /// Records the type of every item. - [] fn type_of: TypeOfItem(DefId) -> Ty<'tcx>, - - ... -} -``` - -Each line of the macro defines one query. The name is broken up like this: - -``` -[] fn type_of: TypeOfItem(DefId) -> Ty<'tcx>, -^^ ^^^^^^^ ^^^^^^^^^^ ^^^^^ ^^^^^^^^ -| | | | | -| | | | result type of query -| | | query key type -| | dep-node constructor -| name of query -query flags -``` - -Let's go over them one by one: - -- **Query flags:** these are largely unused right now, but the intention - is that we'll be able to customize various aspects of how the query is - processed. -- **Name of query:** the name of the query method - (`tcx.type_of(..)`). Also used as the name of a struct - (`ty::query::queries::type_of`) that will be generated to represent - this query. -- **Dep-node constructor:** indicates the constructor function that - connects this query to incremental compilation. Typically, this is a - `DepNode` variant, which can be added by modifying the - `define_dep_nodes!` macro invocation in - `librustc/dep_graph/dep_node.rs`. - - However, sometimes we use a custom function, in which case the - name will be in snake case and the function will be defined at the - bottom of the file. This is typically used when the query key is - not a def-id, or just not the type that the dep-node expects. -- **Query key type:** the type of the argument to this query. - This type must implement the `ty::query::keys::Key` trait, which - defines (for example) how to map it to a crate, and so forth. -- **Result type of query:** the type produced by this query. This type - should (a) not use `RefCell` or other interior mutability and (b) be - cheaply cloneable. Interning or using `Rc` or `Arc` is recommended for - non-trivial data types. - - The one exception to those rules is the `ty::steal::Steal` type, - which is used to cheaply modify MIR in place. See the definition - of `Steal` for more details. New uses of `Steal` should **not** be - added without alerting `@rust-lang/compiler`. - -So, to add a query: - -- Add an entry to `define_queries!` using the format above. -- Possibly add a corresponding entry to the dep-node macro. -- Link the provider by modifying the appropriate `provide` method; - or add a new one if needed and ensure that `rustc_driver` is invoking it. - -#### Query structs and descriptions - -For each kind, the `define_queries` macro will generate a "query struct" -named after the query. This struct is a kind of a place-holder -describing the query. Each such struct implements the -`self::config::QueryConfig` trait, which has associated types for the -key/value of that particular query. Basically the code generated looks something -like this: - -```rust -// Dummy struct representing a particular kind of query: -pub struct type_of<'tcx> { phantom: PhantomData<&'tcx ()> } - -impl<'tcx> QueryConfig for type_of<'tcx> { - type Key = DefId; - type Value = Ty<'tcx>; -} -``` - -There is an additional trait that you may wish to implement called -`self::config::QueryDescription`. This trait is used during cycle -errors to give a "human readable" name for the query, so that we can -summarize what was happening when the cycle occurred. Implementing -this trait is optional if the query key is `DefId`, but if you *don't* -implement it, you get a pretty generic error ("processing `foo`..."). -You can put new impls into the `config` module. They look something like this: - -```rust -impl<'tcx> QueryDescription for queries::type_of<'tcx> { - fn describe(tcx: TyCtxt<'_, '_, '_>, key: DefId) -> String { - format!("computing the type of `{}`", tcx.item_path_str(key)) - } -} -``` +For more information about how the query system works, see the [rustc guide]. +[rustc guide]: https://rust-lang.github.io/rustc-guide/query.html diff --git a/src/librustc/ty/query/config.rs b/src/librustc/ty/query/config.rs index ca5d1f6bd3203..1870812893c14 100644 --- a/src/librustc/ty/query/config.rs +++ b/src/librustc/ty/query/config.rs @@ -1,27 +1,28 @@ -use dep_graph::SerializedDepNodeIndex; -use dep_graph::DepNode; -use hir::def_id::{CrateNum, DefId, DefIndex}; -use mir::interpret::GlobalId; -use traits; -use traits::query::{ +use crate::dep_graph::SerializedDepNodeIndex; +use crate::dep_graph::DepNode; +use crate::hir::def_id::{CrateNum, DefId, DefIndex}; +use crate::mir::interpret::GlobalId; +use crate::traits; +use crate::traits::query::{ CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal, CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal, CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal, }; -use ty::{self, ParamEnvAnd, Ty, TyCtxt}; -use ty::subst::Substs; -use ty::query::queries; -use ty::query::Query; -use ty::query::QueryCache; -use util::profiling::ProfileCategory; +use crate::ty::{self, ParamEnvAnd, Ty, TyCtxt}; +use crate::ty::subst::Substs; +use crate::ty::query::queries; +use crate::ty::query::Query; +use crate::ty::query::QueryCache; +use crate::ty::query::plumbing::CycleError; +use crate::util::profiling::ProfileCategory; use std::borrow::Cow; use std::hash::Hash; use std::fmt::Debug; use syntax_pos::symbol::InternedString; use rustc_data_structures::sync::Lock; -use rustc_data_structures::stable_hasher::HashStable; -use ich::StableHashingContext; +use rustc_data_structures::fingerprint::Fingerprint; +use crate::ich::StableHashingContext; // Query configuration and description traits. @@ -30,7 +31,7 @@ pub trait QueryConfig<'tcx> { const CATEGORY: ProfileCategory; type Key: Eq + Hash + Clone + Debug; - type Value: Clone + for<'a> HashStable>; + type Value: Clone; } pub(super) trait QueryAccessors<'tcx>: QueryConfig<'tcx> { @@ -44,14 +45,19 @@ pub(super) trait QueryAccessors<'tcx>: QueryConfig<'tcx> { // Don't use this method to compute query results, instead use the methods on TyCtxt fn compute(tcx: TyCtxt<'_, 'tcx, '_>, key: Self::Key) -> Self::Value; - fn handle_cycle_error(tcx: TyCtxt<'_, 'tcx, '_>) -> Self::Value; + fn hash_result( + hcx: &mut StableHashingContext<'_>, + result: &Self::Value + ) -> Option; + + fn handle_cycle_error(tcx: TyCtxt<'_, 'tcx, '_>, error: CycleError<'tcx>) -> Self::Value; } pub(super) trait QueryDescription<'tcx>: QueryAccessors<'tcx> { fn describe(tcx: TyCtxt<'_, '_, '_>, key: Self::Key) -> Cow<'static, str>; #[inline] - fn cache_on_disk(_: Self::Key) -> bool { + fn cache_on_disk(_: TyCtxt<'_, 'tcx, 'tcx>, _: Self::Key) -> bool { false } @@ -109,6 +115,42 @@ impl<'tcx> QueryDescription<'tcx> for queries::check_mod_item_types<'tcx> { } } +impl<'tcx> QueryDescription<'tcx> for queries::check_mod_privacy<'tcx> { + fn describe( + tcx: TyCtxt<'_, '_, '_>, + key: DefId, + ) -> Cow<'static, str> { + format!("checking privacy in {}", key.describe_as_module(tcx)).into() + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::check_mod_intrinsics<'tcx> { + fn describe( + tcx: TyCtxt<'_, '_, '_>, + key: DefId, + ) -> Cow<'static, str> { + format!("checking intrinsics in {}", key.describe_as_module(tcx)).into() + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::check_mod_liveness<'tcx> { + fn describe( + tcx: TyCtxt<'_, '_, '_>, + key: DefId, + ) -> Cow<'static, str> { + format!("checking liveness of variables in {}", key.describe_as_module(tcx)).into() + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::check_mod_impl_wf<'tcx> { + fn describe( + tcx: TyCtxt<'_, '_, '_>, + key: DefId, + ) -> Cow<'static, str> { + format!("checking that impls are well-formed in {}", key.describe_as_module(tcx)).into() + } +} + impl<'tcx> QueryDescription<'tcx> for queries::collect_mod_item_types<'tcx> { fn describe( tcx: TyCtxt<'_, '_, '_>, @@ -351,7 +393,7 @@ impl<'tcx> QueryDescription<'tcx> for queries::const_eval<'tcx> { } #[inline] - fn cache_on_disk(_key: Self::Key) -> bool { + fn cache_on_disk(_: TyCtxt<'_, 'tcx, 'tcx>, _key: Self::Key) -> bool { true } @@ -371,7 +413,7 @@ impl<'tcx> QueryDescription<'tcx> for queries::const_eval_raw<'tcx> { } #[inline] - fn cache_on_disk(_key: Self::Key) -> bool { + fn cache_on_disk(_: TyCtxt<'_, 'tcx, 'tcx>, _key: Self::Key) -> bool { true } @@ -395,7 +437,7 @@ impl<'tcx> QueryDescription<'tcx> for queries::symbol_name<'tcx> { } #[inline] - fn cache_on_disk(_: Self::Key) -> bool { + fn cache_on_disk(_: TyCtxt<'_, 'tcx, 'tcx>, _: Self::Key) -> bool { true } @@ -469,7 +511,7 @@ impl<'tcx> QueryDescription<'tcx> for queries::const_is_rvalue_promotable_to_sta } #[inline] - fn cache_on_disk(_: Self::Key) -> bool { + fn cache_on_disk(_: TyCtxt<'_, 'tcx, 'tcx>, _: Self::Key) -> bool { true } @@ -503,7 +545,7 @@ impl<'tcx> QueryDescription<'tcx> for queries::codegen_fulfill_obligation<'tcx> } #[inline] - fn cache_on_disk(_: Self::Key) -> bool { + fn cache_on_disk(_: TyCtxt<'_, 'tcx, 'tcx>, _: Self::Key) -> bool { true } @@ -629,6 +671,12 @@ impl<'tcx> QueryDescription<'tcx> for queries::foreign_modules<'tcx> { } } +impl<'tcx> QueryDescription<'tcx> for queries::entry_fn<'tcx> { + fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> { + "looking up the entry function of a crate".into() + } +} + impl<'tcx> QueryDescription<'tcx> for queries::plugin_registrar_fn<'tcx> { fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> { "looking up the plugin registrar for a crate".into() @@ -835,7 +883,7 @@ impl<'tcx> QueryDescription<'tcx> for queries::features_query<'tcx> { impl<'tcx> QueryDescription<'tcx> for queries::typeck_tables_of<'tcx> { #[inline] - fn cache_on_disk(def_id: Self::Key) -> bool { + fn cache_on_disk(_: TyCtxt<'_, 'tcx, 'tcx>, def_id: Self::Key) -> bool { def_id.is_local() } @@ -852,14 +900,14 @@ impl<'tcx> QueryDescription<'tcx> for queries::typeck_tables_of<'tcx> { impl<'tcx> QueryDescription<'tcx> for queries::optimized_mir<'tcx> { #[inline] - fn cache_on_disk(def_id: Self::Key) -> bool { + fn cache_on_disk(_: TyCtxt<'_, 'tcx, 'tcx>, def_id: Self::Key) -> bool { def_id.is_local() } fn try_load_from_disk<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: SerializedDepNodeIndex) -> Option { - let mir: Option<::mir::Mir<'tcx>> = tcx.queries.on_disk_cache + let mir: Option> = tcx.queries.on_disk_cache .try_load_query_result(tcx, id); mir.map(|x| tcx.alloc_mir(x)) } @@ -891,7 +939,7 @@ impl<'tcx> QueryDescription<'tcx> for queries::instance_def_size_estimate<'tcx> impl<'tcx> QueryDescription<'tcx> for queries::generics_of<'tcx> { #[inline] - fn cache_on_disk(def_id: Self::Key) -> bool { + fn cache_on_disk(_: TyCtxt<'_, 'tcx, 'tcx>, def_id: Self::Key) -> bool { def_id.is_local() } @@ -934,11 +982,17 @@ impl<'tcx> QueryDescription<'tcx> for queries::dllimport_foreign_items<'tcx> { } } +impl<'tcx> QueryDescription<'tcx> for queries::backend_optimization_level<'tcx> { + fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> { + "optimization level used by backend".into() + } +} + macro_rules! impl_disk_cacheable_query( - ($query_name:ident, |$key:tt| $cond:expr) => { + ($query_name:ident, |$tcx:tt, $key:tt| $cond:expr) => { impl<'tcx> QueryDescription<'tcx> for queries::$query_name<'tcx> { #[inline] - fn cache_on_disk($key: Self::Key) -> bool { + fn cache_on_disk($tcx: TyCtxt<'_, 'tcx, 'tcx>, $key: Self::Key) -> bool { $cond } @@ -952,14 +1006,17 @@ macro_rules! impl_disk_cacheable_query( } ); -impl_disk_cacheable_query!(unsafety_check_result, |def_id| def_id.is_local()); -impl_disk_cacheable_query!(borrowck, |def_id| def_id.is_local()); -impl_disk_cacheable_query!(mir_borrowck, |def_id| def_id.is_local()); -impl_disk_cacheable_query!(mir_const_qualif, |def_id| def_id.is_local()); -impl_disk_cacheable_query!(check_match, |def_id| def_id.is_local()); -impl_disk_cacheable_query!(def_symbol_name, |_| true); -impl_disk_cacheable_query!(type_of, |def_id| def_id.is_local()); -impl_disk_cacheable_query!(predicates_of, |def_id| def_id.is_local()); -impl_disk_cacheable_query!(used_trait_imports, |def_id| def_id.is_local()); -impl_disk_cacheable_query!(codegen_fn_attrs, |_| true); -impl_disk_cacheable_query!(specialization_graph_of, |_| true); +impl_disk_cacheable_query!(mir_borrowck, |tcx, def_id| { + def_id.is_local() && tcx.is_closure(def_id) +}); + +impl_disk_cacheable_query!(unsafety_check_result, |_, def_id| def_id.is_local()); +impl_disk_cacheable_query!(borrowck, |_, def_id| def_id.is_local()); +impl_disk_cacheable_query!(mir_const_qualif, |_, def_id| def_id.is_local()); +impl_disk_cacheable_query!(check_match, |_, def_id| def_id.is_local()); +impl_disk_cacheable_query!(def_symbol_name, |_, _| true); +impl_disk_cacheable_query!(type_of, |_, def_id| def_id.is_local()); +impl_disk_cacheable_query!(predicates_of, |_, def_id| def_id.is_local()); +impl_disk_cacheable_query!(used_trait_imports, |_, def_id| def_id.is_local()); +impl_disk_cacheable_query!(codegen_fn_attrs, |_, _| true); +impl_disk_cacheable_query!(specialization_graph_of, |_, _| true); diff --git a/src/librustc/ty/query/job.rs b/src/librustc/ty/query/job.rs index d794429a8a706..22211468412c1 100644 --- a/src/librustc/ty/query/job.rs +++ b/src/librustc/ty/query/job.rs @@ -1,25 +1,27 @@ #![allow(warnings)] use std::mem; +use std::process; +use std::{fmt, ptr}; + use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sync::{Lock, LockGuard, Lrc, Weak}; use rustc_data_structures::OnDrop; use syntax_pos::Span; -use ty::tls; -use ty::query::Query; -use ty::query::plumbing::CycleError; -#[cfg(not(parallel_queries))] -use ty::query::{ + +use crate::ty::tls; +use crate::ty::query::Query; +use crate::ty::query::plumbing::CycleError; +#[cfg(not(parallel_compiler))] +use crate::ty::query::{ plumbing::TryGetJob, config::QueryDescription, }; -use ty::context::TyCtxt; -use std::process; -use std::{fmt, ptr}; +use crate::ty::context::TyCtxt; -#[cfg(parallel_queries)] +#[cfg(parallel_compiler)] use { - rayon_core, + rustc_rayon_core as rayon_core, parking_lot::{Mutex, Condvar}, std::sync::atomic::Ordering, std::thread, @@ -29,71 +31,54 @@ use { rustc_data_structures::stable_hasher::{StableHasherResult, StableHasher, HashStable}, }; -/// Indicates the state of a query for a given key in a query map +/// Indicates the state of a query for a given key in a query map. pub(super) enum QueryResult<'tcx> { - /// An already executing query. The query job can be used to await for its completion + /// An already executing query. The query job can be used to await for its completion. Started(Lrc>), - /// The query panicked. Queries trying to wait on this will raise a fatal error / silently panic + /// The query panicked. Queries trying to wait on this will raise a fatal error or + /// silently panic. Poisoned, } -/// A span and a query key +/// Represents a span and a query key. #[derive(Clone, Debug)] pub struct QueryInfo<'tcx> { - /// The span for a reason this query was required + /// The span corresponding to the reason for which this query was required. pub span: Span, pub query: Query<'tcx>, } -/// A object representing an active query job. +/// Representss an object representing an active query job. pub struct QueryJob<'tcx> { pub info: QueryInfo<'tcx>, /// The parent query job which created this job and is implicitly waiting on it. pub parent: Option>>, - /// The latch which is used to wait on this job - #[cfg(parallel_queries)] + /// The latch that is used to wait on this job. + #[cfg(parallel_compiler)] latch: QueryLatch<'tcx>, } impl<'tcx> QueryJob<'tcx> { - /// Creates a new query job + /// Creates a new query job. pub fn new(info: QueryInfo<'tcx>, parent: Option>>) -> Self { QueryJob { info, parent, - #[cfg(parallel_queries)] + #[cfg(parallel_compiler)] latch: QueryLatch::new(), } } /// Awaits for the query job to complete. - /// - /// For single threaded rustc there's no concurrent jobs running, so if we are waiting for any - /// query that means that there is a query cycle, thus this always running a cycle error. - #[cfg(not(parallel_queries))] - #[inline(never)] - #[cold] - pub(super) fn cycle_error<'lcx, 'a, D: QueryDescription<'tcx>>( - &self, - tcx: TyCtxt<'_, 'tcx, 'lcx>, - span: Span, - ) -> TryGetJob<'a, 'tcx, D> { - TryGetJob::JobCompleted(Err(Box::new(self.find_cycle_in_stack(tcx, span)))) - } - - /// Awaits for the query job to complete. - /// - /// For single threaded rustc there's no concurrent jobs running, so if we are waiting for any - /// query that means that there is a query cycle, thus this always running a cycle error. - #[cfg(parallel_queries)] - pub(super) fn await<'lcx>( + #[cfg(parallel_compiler)] + pub(super) fn r#await<'lcx>( &self, tcx: TyCtxt<'_, 'tcx, 'lcx>, span: Span, - ) -> Result<(), Box>> { + ) -> Result<(), CycleError<'tcx>> { tls::with_related_context(tcx, move |icx| { let mut waiter = Lrc::new(QueryWaiter { query: icx.query.clone(), @@ -101,20 +86,20 @@ impl<'tcx> QueryJob<'tcx> { cycle: Lock::new(None), condvar: Condvar::new(), }); - self.latch.await(&waiter); + self.latch.r#await(&waiter); // FIXME: Get rid of this lock. We have ownership of the QueryWaiter // although another thread may still have a Lrc reference so we cannot // use Lrc::get_mut let mut cycle = waiter.cycle.lock(); match cycle.take() { None => Ok(()), - Some(cycle) => Err(Box::new(cycle)) + Some(cycle) => Err(cycle) } }) } - #[cfg(not(parallel_queries))] - fn find_cycle_in_stack<'lcx>( + #[cfg(not(parallel_compiler))] + pub(super) fn find_cycle_in_stack<'lcx>( &self, tcx: TyCtxt<'_, 'tcx, 'lcx>, span: Span, @@ -152,7 +137,7 @@ impl<'tcx> QueryJob<'tcx> { /// This does nothing for single threaded rustc, /// as there are no concurrent jobs which could be waiting on us pub fn signal_complete(&self) { - #[cfg(parallel_queries)] + #[cfg(parallel_compiler)] self.latch.set(); } @@ -161,7 +146,7 @@ impl<'tcx> QueryJob<'tcx> { } } -#[cfg(parallel_queries)] +#[cfg(parallel_compiler)] struct QueryWaiter<'tcx> { query: Option>>, condvar: Condvar, @@ -169,7 +154,7 @@ struct QueryWaiter<'tcx> { cycle: Lock>>, } -#[cfg(parallel_queries)] +#[cfg(parallel_compiler)] impl<'tcx> QueryWaiter<'tcx> { fn notify(&self, registry: &rayon_core::Registry) { rayon_core::mark_unblocked(registry); @@ -177,18 +162,18 @@ impl<'tcx> QueryWaiter<'tcx> { } } -#[cfg(parallel_queries)] +#[cfg(parallel_compiler)] struct QueryLatchInfo<'tcx> { complete: bool, waiters: Vec>>, } -#[cfg(parallel_queries)] +#[cfg(parallel_compiler)] struct QueryLatch<'tcx> { info: Mutex>, } -#[cfg(parallel_queries)] +#[cfg(parallel_compiler)] impl<'tcx> QueryLatch<'tcx> { fn new() -> Self { QueryLatch { @@ -200,7 +185,7 @@ impl<'tcx> QueryLatch<'tcx> { } /// Awaits the caller on this latch by blocking the current thread. - fn await(&self, waiter: &Lrc>) { + fn r#await(&self, waiter: &Lrc>) { let mut info = self.info.lock(); if !info.complete { // We push the waiter on to the `waiters` list. It can be accessed inside @@ -228,7 +213,7 @@ impl<'tcx> QueryLatch<'tcx> { } } - /// Remove a single waiter from the list of waiters. + /// Removes a single waiter from the list of waiters. /// This is used to break query cycles. fn extract_waiter( &self, @@ -242,7 +227,7 @@ impl<'tcx> QueryLatch<'tcx> { } /// A resumable waiter of a query. The usize is the index into waiters in the query's latch -#[cfg(parallel_queries)] +#[cfg(parallel_compiler)] type Waiter<'tcx> = (Lrc>, usize); /// Visits all the non-resumable and resumable waiters of a query. @@ -254,7 +239,7 @@ type Waiter<'tcx> = (Lrc>, usize); /// For visits of resumable waiters it returns Some(Some(Waiter)) which has the /// required information to resume the waiter. /// If all `visit` calls returns None, this function also returns None. -#[cfg(parallel_queries)] +#[cfg(parallel_compiler)] fn visit_waiters<'tcx, F>(query: Lrc>, mut visit: F) -> Option>> where F: FnMut(Span, Lrc>) -> Option>> @@ -282,7 +267,7 @@ where /// `span` is the reason for the `query` to execute. This is initially DUMMY_SP. /// If a cycle is detected, this initial value is replaced with the span causing /// the cycle. -#[cfg(parallel_queries)] +#[cfg(parallel_compiler)] fn cycle_check<'tcx>(query: Lrc>, span: Span, stack: &mut Vec<(Span, Lrc>)>, @@ -321,7 +306,7 @@ fn cycle_check<'tcx>(query: Lrc>, /// Finds out if there's a path to the compiler root (aka. code which isn't in a query) /// from `query` without going through any of the queries in `visited`. /// This is achieved with a depth first search. -#[cfg(parallel_queries)] +#[cfg(parallel_compiler)] fn connected_to_root<'tcx>( query: Lrc>, visited: &mut FxHashSet<*const QueryJob<'tcx>> @@ -346,7 +331,7 @@ fn connected_to_root<'tcx>( } // Deterministically pick an query from a list -#[cfg(parallel_queries)] +#[cfg(parallel_compiler)] fn pick_query<'a, 'tcx, T, F: Fn(&T) -> (Span, Lrc>)>( tcx: TyCtxt<'_, 'tcx, '_>, queries: &'a [T], @@ -372,7 +357,7 @@ fn pick_query<'a, 'tcx, T, F: Fn(&T) -> (Span, Lrc>)>( /// the function return true. /// If a cycle was not found, the starting query is removed from `jobs` and /// the function returns false. -#[cfg(parallel_queries)] +#[cfg(parallel_compiler)] fn remove_cycle<'tcx>( jobs: &mut Vec>>, wakelist: &mut Vec>>, @@ -475,7 +460,7 @@ fn remove_cycle<'tcx>( /// Creates a new thread and forwards information in thread locals to it. /// The new thread runs the deadlock handler. /// Must only be called when a deadlock is about to happen. -#[cfg(parallel_queries)] +#[cfg(parallel_compiler)] pub unsafe fn handle_deadlock() { use syntax; use syntax_pos; @@ -514,7 +499,7 @@ pub unsafe fn handle_deadlock() { /// uses a query latch and then resuming that waiter. /// There may be multiple cycles involved in a deadlock, so this searches /// all active queries for cycles before finally resuming all the waiters at once. -#[cfg(parallel_queries)] +#[cfg(parallel_compiler)] fn deadlock(tcx: TyCtxt<'_, '_, '_>, registry: &rayon_core::Registry) { let on_panic = OnDrop(|| { eprintln!("deadlock handler panicked, aborting process"); diff --git a/src/librustc/ty/query/keys.rs b/src/librustc/ty/query/keys.rs index af6f5a00dee5c..f5eb7374cc19b 100644 --- a/src/librustc/ty/query/keys.rs +++ b/src/librustc/ty/query/keys.rs @@ -1,12 +1,12 @@ //! Defines the set of legal keys that can be used in queries. -use infer::canonical::Canonical; -use hir::def_id::{CrateNum, DefId, LOCAL_CRATE, DefIndex}; -use traits; -use ty::{self, Ty, TyCtxt}; -use ty::subst::Substs; -use ty::fast_reject::SimplifiedType; -use mir; +use crate::infer::canonical::Canonical; +use crate::hir::def_id::{CrateNum, DefId, LOCAL_CRATE, DefIndex}; +use crate::traits; +use crate::ty::{self, Ty, TyCtxt}; +use crate::ty::subst::Substs; +use crate::ty::fast_reject::SimplifiedType; +use crate::mir; use std::fmt::Debug; use std::hash::Hash; diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs index 39d76ceed9507..740875109d029 100644 --- a/src/librustc/ty/query/mod.rs +++ b/src/librustc/ty/query/mod.rs @@ -1,54 +1,55 @@ -use dep_graph::{DepConstructor, DepNode}; -use errors::DiagnosticBuilder; -use hir::def_id::{CrateNum, DefId, DefIndex}; -use hir::def::{Def, Export}; -use hir::{self, TraitCandidate, ItemLocalId, CodegenFnAttrs}; -use rustc_data_structures::svh::Svh; -use infer::canonical::{self, Canonical}; -use lint; -use middle::borrowck::BorrowCheckResult; -use middle::cstore::{ExternCrate, LinkagePreference, NativeLibrary, ForeignModule}; -use middle::cstore::{NativeLibraryKind, DepKind, CrateSource}; -use middle::privacy::AccessLevels; -use middle::reachable::ReachableSet; -use middle::region; -use middle::resolve_lifetime::{ResolveLifetimes, Region, ObjectLifetimeDefault}; -use middle::stability::{self, DeprecationEntry}; -use middle::lib_features::LibFeatures; -use middle::lang_items::{LanguageItems, LangItem}; -use middle::exported_symbols::{SymbolExportLevel, ExportedSymbol}; -use mir::interpret::{ConstEvalRawResult, ConstEvalResult}; -use mir::mono::CodegenUnit; -use mir; -use mir::interpret::GlobalId; -use session::{CompileResult, CrateDisambiguator}; -use session::config::OutputFilenames; -use traits::{self, Vtable}; -use traits::query::{ +use crate::dep_graph::{self, DepConstructor, DepNode}; +use crate::hir::def_id::{CrateNum, DefId, DefIndex}; +use crate::hir::def::{Def, Export}; +use crate::hir::{self, TraitCandidate, ItemLocalId, CodegenFnAttrs}; +use crate::infer::canonical::{self, Canonical}; +use crate::lint; +use crate::middle::borrowck::BorrowCheckResult; +use crate::middle::cstore::{ExternCrate, LinkagePreference, NativeLibrary, ForeignModule}; +use crate::middle::cstore::{NativeLibraryKind, DepKind, CrateSource}; +use crate::middle::privacy::AccessLevels; +use crate::middle::reachable::ReachableSet; +use crate::middle::region; +use crate::middle::resolve_lifetime::{ResolveLifetimes, Region, ObjectLifetimeDefault}; +use crate::middle::stability::{self, DeprecationEntry}; +use crate::middle::lib_features::LibFeatures; +use crate::middle::lang_items::{LanguageItems, LangItem}; +use crate::middle::exported_symbols::{SymbolExportLevel, ExportedSymbol}; +use crate::mir::interpret::{ConstEvalRawResult, ConstEvalResult}; +use crate::mir::mono::CodegenUnit; +use crate::mir; +use crate::mir::interpret::GlobalId; +use crate::session::{CompileResult, CrateDisambiguator}; +use crate::session::config::{EntryFnType, OutputFilenames, OptLevel}; +use crate::traits::{self, Vtable}; +use crate::traits::query::{ CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal, CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpSubtypeGoal, CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpNormalizeGoal, NoSolution, }; -use traits::query::method_autoderef::MethodAutoderefStepsResult; -use traits::query::dropck_outlives::{DtorckConstraint, DropckOutlivesResult}; -use traits::query::normalize::NormalizationResult; -use traits::query::outlives_bounds::OutlivesBound; -use traits::specialization_graph; -use traits::Clauses; -use ty::{self, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt}; -use ty::steal::Steal; -use ty::subst::Substs; -use util::nodemap::{DefIdSet, DefIdMap, ItemLocalSet}; -use util::common::{ErrorReported}; -use util::profiling::ProfileCategory::*; -use session::Session; +use crate::traits::query::method_autoderef::MethodAutoderefStepsResult; +use crate::traits::query::dropck_outlives::{DtorckConstraint, DropckOutlivesResult}; +use crate::traits::query::normalize::NormalizationResult; +use crate::traits::query::outlives_bounds::OutlivesBound; +use crate::traits::specialization_graph; +use crate::traits::Clauses; +use crate::ty::{self, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt, AdtSizedConstraint}; +use crate::ty::steal::Steal; +use crate::ty::subst::Substs; +use crate::ty::util::NeedsDrop; +use crate::util::nodemap::{DefIdSet, DefIdMap, ItemLocalSet}; +use crate::util::common::{ErrorReported}; +use crate::util::profiling::ProfileCategory::*; +use crate::session::Session; +use rustc_data_structures::svh::Svh; use rustc_data_structures::bit_set::BitSet; use rustc_data_structures::indexed_vec::IndexVec; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stable_hasher::StableVec; use rustc_data_structures::sync::Lrc; +use rustc_data_structures::fingerprint::Fingerprint; use rustc_target::spec::PanicStrategy; use std::borrow::Cow; @@ -69,7 +70,7 @@ pub use self::plumbing::{force_from_dep_node, CycleError}; mod job; pub use self::job::{QueryJob, QueryInfo}; -#[cfg(parallel_queries)] +#[cfg(parallel_compiler)] pub use self::job::handle_deadlock; mod keys; @@ -101,12 +102,12 @@ define_queries! { <'tcx> /// Records the type of every item. [] fn type_of: TypeOfItem(DefId) -> Ty<'tcx>, - /// Maps from the def-id of an item (trait/struct/enum/fn) to its + /// Maps from the `DefId` of an item (trait/struct/enum/fn) to its /// associated generics. [] fn generics_of: GenericsOfItem(DefId) -> &'tcx ty::Generics, - /// Maps from the def-id of an item (trait/struct/enum/fn) to the - /// predicates (where clauses) that must be proven true in order + /// Maps from the `DefId` of an item (trait/struct/enum/fn) to the + /// predicates (where-clauses) that must be proven true in order /// to reference it. This is almost always the "predicates query" /// that you want. /// @@ -122,8 +123,8 @@ define_queries! { <'tcx> /// user.) [] fn predicates_of: PredicatesOfItem(DefId) -> Lrc>, - /// Maps from the def-id of an item (trait/struct/enum/fn) to the - /// predicates (where clauses) directly defined on it. This is + /// Maps from the `DefId` of an item (trait/struct/enum/fn) to the + /// predicates (where-clauses) directly defined on it. This is /// equal to the `explicit_predicates_of` predicates plus the /// `inferred_outlives_of` predicates. [] fn predicates_defined_on: PredicatesDefinedOnItem(DefId) @@ -137,7 +138,7 @@ define_queries! { <'tcx> /// Foo<'a, T> { x: &'a T }`, this would return `T: 'a`). [] fn inferred_outlives_of: InferredOutlivesOf(DefId) -> Lrc>>, - /// Maps from the def-id of a trait to the list of + /// Maps from the `DefId` of a trait to the list of /// super-predicates. This is a subset of the full list of /// predicates. We store these in a separate map because we must /// evaluate them even during type conversion, often before the @@ -153,7 +154,16 @@ define_queries! { <'tcx> [] fn trait_def: TraitDefOfItem(DefId) -> &'tcx ty::TraitDef, [] fn adt_def: AdtDefOfItem(DefId) -> &'tcx ty::AdtDef, [] fn adt_destructor: AdtDestructor(DefId) -> Option, - [] fn adt_sized_constraint: SizedConstraint(DefId) -> &'tcx [Ty<'tcx>], + + // The cycle error here should be reported as an error by `check_representable`. + // We consider the type as Sized in the meanwhile to avoid + // further errors (done in impl Value for AdtSizedConstraint). + // Use `cycle_delay_bug` to delay the cycle error here to be emitted later + // in case we accidentally otherwise don't emit an error. + [cycle_delay_bug] fn adt_sized_constraint: SizedConstraint( + DefId + ) -> AdtSizedConstraint<'tcx>, + [] fn adt_dtorck_constraint: DtorckConstraint( DefId ) -> Result, NoSolution>, @@ -215,7 +225,7 @@ define_queries! { <'tcx> }, Codegen { - /// Set of all the def-ids in this crate that have MIR associated with + /// Set of all the `DefId`s in this crate that have MIR associated with /// them. This includes all the body owners, but also things like struct /// constructors. [] fn mir_keys: mir_keys(CrateNum) -> Lrc, @@ -225,17 +235,17 @@ define_queries! { <'tcx> /// the value isn't known except to the pass itself. [] fn mir_const_qualif: MirConstQualif(DefId) -> (u8, Lrc>), - /// Fetch the MIR for a given def-id right after it's built - this includes + /// Fetch the MIR for a given `DefId` right after it's built - this includes /// unreachable code. [] fn mir_built: MirBuilt(DefId) -> &'tcx Steal>, - /// Fetch the MIR for a given def-id up till the point where it is + /// Fetch the MIR for a given `DefId` up till the point where it is /// ready for const evaluation. /// /// See the README for the `mir` module for details. - [] fn mir_const: MirConst(DefId) -> &'tcx Steal>, + [no_hash] fn mir_const: MirConst(DefId) -> &'tcx Steal>, - [] fn mir_validated: MirValidated(DefId) -> &'tcx Steal>, + [no_hash] fn mir_validated: MirValidated(DefId) -> &'tcx Steal>, /// MIR after our optimization passes have run. This is MIR that is ready /// for codegen. This is also the only query that can fetch non-local MIR, at present. @@ -243,7 +253,7 @@ define_queries! { <'tcx> }, TypeChecking { - /// The result of unsafety-checking this def-id. + /// The result of unsafety-checking this `DefId`. [] fn unsafety_check_result: UnsafetyCheckResult(DefId) -> mir::UnsafetyCheckResult, /// HACK: when evaluated, this reports a "unsafe derive on repr(packed)" error @@ -264,6 +274,14 @@ define_queries! { <'tcx> [] fn check_mod_item_types: CheckModItemTypes(DefId) -> (), + [] fn check_mod_privacy: CheckModPrivacy(DefId) -> (), + + [] fn check_mod_intrinsics: CheckModIntrinsics(DefId) -> (), + + [] fn check_mod_liveness: CheckModLiveness(DefId) -> (), + + [] fn check_mod_impl_wf: CheckModImplWf(DefId) -> (), + [] fn collect_mod_item_types: CollectModItemTypes(DefId) -> (), /// Caches CoerceUnsized kinds for impls on custom types. @@ -298,13 +316,13 @@ define_queries! { <'tcx> TypeChecking { /// Gets a complete map from all types to their inherent impls. /// Not meant to be used directly outside of coherence. - /// (Defined only for LOCAL_CRATE) + /// (Defined only for `LOCAL_CRATE`.) [] fn crate_inherent_impls: crate_inherent_impls_dep_node(CrateNum) -> Lrc, - /// Checks all types in the krate for overlap in their inherent impls. Reports errors. + /// Checks all types in the crate for overlap in their inherent impls. Reports errors. /// Not meant to be used directly outside of coherence. - /// (Defined only for LOCAL_CRATE) + /// (Defined only for `LOCAL_CRATE`.) [] fn crate_inherent_impls_overlap_check: inherent_impls_overlap_check_dep_node(CrateNum) -> (), }, @@ -312,9 +330,9 @@ define_queries! { <'tcx> Other { /// Evaluate a constant without running sanity checks /// - /// DO NOT USE THIS outside const eval. Const eval uses this to break query cycles during - /// validation. Please add a comment to every use site explaining why using `const_eval` - /// isn't sufficient + /// **Do not use this** outside const eval. Const eval uses this to break query cycles + /// during validation. Please add a comment to every use site explaining why using + /// `const_eval` isn't sufficient [] fn const_eval_raw: const_eval_raw_dep_node(ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) -> ConstEvalRawResult<'tcx>, @@ -335,7 +353,7 @@ define_queries! { <'tcx> Other { [] fn reachable_set: reachability_dep_node(CrateNum) -> ReachableSet, - /// Per-body `region::ScopeTree`. The `DefId` should be the owner-def-id for the body; + /// Per-body `region::ScopeTree`. The `DefId` should be the owner `DefId` for the body; /// in the case of closures, this will be redirected to the enclosing function. [] fn region_scope_tree: RegionScopeTree(DefId) -> Lrc, @@ -389,7 +407,7 @@ define_queries! { <'tcx> -> Lrc, [] fn is_object_safe: ObjectSafety(DefId) -> bool, - /// Get the ParameterEnvironment for a given item; this environment + /// Gets the ParameterEnvironment for a given item; this environment /// will be in "user-facing" mode, meaning that it is suitabe for /// type-checking etc, and it does not normalize specializable /// associated types. This is almost always what you want, @@ -402,7 +420,16 @@ define_queries! { <'tcx> [] fn is_copy_raw: is_copy_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool, [] fn is_sized_raw: is_sized_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool, [] fn is_freeze_raw: is_freeze_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool, - [] fn needs_drop_raw: needs_drop_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool, + + // The cycle error here should be reported as an error by `check_representable`. + // We consider the type as not needing drop in the meanwhile to avoid + // further errors (done in impl Value for NeedsDrop). + // Use `cycle_delay_bug` to delay the cycle error here to be emitted later + // in case we accidentally otherwise don't emit an error. + [cycle_delay_bug] fn needs_drop_raw: needs_drop_dep_node( + ty::ParamEnvAnd<'tcx, Ty<'tcx>> + ) -> NeedsDrop, + [] fn layout_raw: layout_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> Result<&'tcx ty::layout::LayoutDetails, ty::layout::LayoutError<'tcx>>, @@ -476,6 +503,9 @@ define_queries! { <'tcx> [] fn foreign_modules: ForeignModules(CrateNum) -> Lrc>, + /// Identifies the entry-point (e.g., the `main` function) for a given + /// crate, returning `None` if there is no entry point (such as for library crates). + [] fn entry_fn: EntryFn(CrateNum) -> Option<(DefId, EntryFnType)>, [] fn plugin_registrar_fn: PluginRegistrarFn(CrateNum) -> Option, [] fn proc_macro_decls_static: ProcMacroDeclsStatic(CrateNum) -> Option, [] fn crate_disambiguator: CrateDisambiguator(CrateNum) -> CrateDisambiguator, @@ -541,6 +571,8 @@ define_queries! { <'tcx> [] fn maybe_unused_trait_import: MaybeUnusedTraitImport(DefId) -> bool, [] fn maybe_unused_extern_crates: maybe_unused_extern_crates_node(CrateNum) -> Lrc>, + [] fn names_imported_by_glob_use: NamesImportedByGlobUse(DefId) + -> Lrc>, [] fn stability_index: stability_index_node(CrateNum) -> Lrc>, [] fn all_crate_nums: all_crate_nums_node(CrateNum) -> Lrc>, @@ -562,6 +594,7 @@ define_queries! { <'tcx> -> (Arc, Arc>>>), [] fn is_codegened_item: IsCodegenedItem(DefId) -> bool, [] fn codegen_unit: CodegenUnit(InternedString) -> Arc>, + [] fn backend_optimization_level: BackendOptimizationLevel(CrateNum) -> OptLevel, }, Other { @@ -716,32 +749,6 @@ define_queries! { <'tcx> }, } -// `try_get_query` can't be public because it uses the private query -// implementation traits, so we provide access to it selectively. -impl<'a, 'tcx, 'lcx> TyCtxt<'a, 'tcx, 'lcx> { - pub fn try_adt_sized_constraint( - self, - span: Span, - key: DefId, - ) -> Result<&'tcx [Ty<'tcx>], Box>> { - self.try_get_query::>(span, key) - } - pub fn try_needs_drop_raw( - self, - span: Span, - key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, - ) -> Result>> { - self.try_get_query::>(span, key) - } - pub fn try_optimized_mir( - self, - span: Span, - key: DefId, - ) -> Result<&'tcx mir::Mir<'tcx>, Box>> { - self.try_get_query::>(span, key) - } -} - ////////////////////////////////////////////////////////////////////// // These functions are little shims used to find the dep-node for a // given query when there is not a *direct* mapping: diff --git a/src/librustc/ty/query/on_disk_cache.rs b/src/librustc/ty/query/on_disk_cache.rs index a674e942b3893..c16f861dedb50 100644 --- a/src/librustc/ty/query/on_disk_cache.rs +++ b/src/librustc/ty/query/on_disk_cache.rs @@ -1,28 +1,29 @@ -use dep_graph::{DepNodeIndex, SerializedDepNodeIndex}; +use crate::dep_graph::{DepNodeIndex, SerializedDepNodeIndex}; +use crate::hir; +use crate::hir::def_id::{CrateNum, DefIndex, DefId, LocalDefId, LOCAL_CRATE}; +use crate::hir::map::definitions::DefPathHash; +use crate::ich::{CachingSourceMapView, Fingerprint}; +use crate::mir::{self, interpret}; +use crate::mir::interpret::{AllocDecodingSession, AllocDecodingState}; +use crate::rustc_serialize::{Decodable, Decoder, Encodable, Encoder, opaque, + SpecializedDecoder, SpecializedEncoder, + UseSpecializedDecodable, UseSpecializedEncodable}; +use crate::session::{CrateDisambiguator, Session}; +use crate::ty; +use crate::ty::codec::{self as ty_codec, TyDecoder, TyEncoder}; +use crate::ty::context::TyCtxt; +use crate::util::common::time; + use errors::Diagnostic; -use hir; -use hir::def_id::{CrateNum, DefIndex, DefId, LocalDefId, LOCAL_CRATE}; -use hir::map::definitions::DefPathHash; -use ich::{CachingSourceMapView, Fingerprint}; -use mir::{self, interpret}; -use mir::interpret::{AllocDecodingSession, AllocDecodingState}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::thin_vec::ThinVec; use rustc_data_structures::sync::{Lrc, Lock, HashMapExt, Once}; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; -use rustc_serialize::{Decodable, Decoder, Encodable, Encoder, opaque, - SpecializedDecoder, SpecializedEncoder, - UseSpecializedDecodable, UseSpecializedEncodable}; -use session::{CrateDisambiguator, Session}; use std::mem; use syntax::ast::NodeId; use syntax::source_map::{SourceMap, StableSourceFileId}; use syntax_pos::{BytePos, Span, DUMMY_SP, SourceFile}; use syntax_pos::hygiene::{Mark, SyntaxContext, ExpnInfo}; -use ty; -use ty::codec::{self as ty_codec, TyDecoder, TyEncoder}; -use ty::context::TyCtxt; -use util::common::time; const TAG_FILE_FOOTER: u128 = 0xC0FFEE_C0FFEE_C0FFEE_C0FFEE_C0FFEE; @@ -103,7 +104,7 @@ impl AbsoluteBytePos { } impl<'sess> OnDiskCache<'sess> { - /// Create a new OnDiskCache instance from the serialized data in `data`. + /// Creates a new OnDiskCache instance from the serialized data in `data`. pub fn new(sess: &'sess Session, data: Vec, start_pos: usize) -> OnDiskCache<'sess> { debug_assert!(sess.opts.incremental.is_some()); @@ -202,7 +203,7 @@ impl<'sess> OnDiskCache<'sess> { let mut query_result_index = EncodedQueryResultIndex::new(); time(tcx.sess, "encode query results", || { - use ty::query::queries::*; + use crate::ty::query::queries::*; let enc = &mut encoder; let qri = &mut query_result_index; @@ -225,12 +226,12 @@ impl<'sess> OnDiskCache<'sess> { encode_query_results::, _>(tcx, enc, qri)?; // const eval is special, it only encodes successfully evaluated constants - use ty::query::QueryAccessors; + use crate::ty::query::QueryAccessors; let cache = const_eval::query_cache(tcx).borrow(); assert!(cache.active.is_empty()); for (key, entry) in cache.results.iter() { - use ty::query::config::QueryDescription; - if const_eval::cache_on_disk(key.clone()) { + use crate::ty::query::config::QueryDescription; + if const_eval::cache_on_disk(tcx, key.clone()) { if let Ok(ref value) = entry.value { let dep_node = SerializedDepNodeIndex::new(entry.index.index()); @@ -325,7 +326,7 @@ impl<'sess> OnDiskCache<'sess> { }) } - /// Load a diagnostic emitted during the previous compilation session. + /// Loads a diagnostic emitted during the previous compilation session. pub fn load_diagnostics<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, dep_node_index: SerializedDepNodeIndex) @@ -339,7 +340,7 @@ impl<'sess> OnDiskCache<'sess> { diagnostics.unwrap_or_default() } - /// Store a diagnostic emitted during the current compilation session. + /// Stores a diagnostic emitted during the current compilation session. /// Anything stored like this will be available via `load_diagnostics` in /// the next compilation session. #[inline(never)] @@ -353,7 +354,7 @@ impl<'sess> OnDiskCache<'sess> { } /// Returns the cached query result if there is something in the cache for - /// the given SerializedDepNodeIndex. Otherwise returns None. + /// the given `SerializedDepNodeIndex`; otherwise returns `None`. pub fn try_load_query_result<'tcx, T>(&self, tcx: TyCtxt<'_, 'tcx, 'tcx>, dep_node_index: SerializedDepNodeIndex) @@ -366,7 +367,7 @@ impl<'sess> OnDiskCache<'sess> { "query result") } - /// Store a diagnostic emitted during computation of an anonymous query. + /// Stores a diagnostic emitted during computation of an anonymous query. /// Since many anonymous queries can share the same `DepNode`, we aggregate /// them -- as opposed to regular queries where we assume that there is a /// 1:1 relationship between query-key and `DepNode`. @@ -777,7 +778,7 @@ impl<'enc, 'a, 'tcx, E> CacheEncoder<'enc, 'a, 'tcx, E> value: &V) -> Result<(), E::Error> { - use ty::codec::TyEncoder; + use crate::ty::codec::TyEncoder; let start_pos = self.position(); tag.encode(self)?; @@ -1086,7 +1087,7 @@ fn encode_query_results<'enc, 'a, 'tcx, Q, E>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let map = Q::query_cache(tcx).borrow(); assert!(map.active.is_empty()); for (key, entry) in map.results.iter() { - if Q::cache_on_disk(key.clone()) { + if Q::cache_on_disk(tcx, key.clone()) { let dep_node = SerializedDepNodeIndex::new(entry.index.index()); // Record position of the cache entry diff --git a/src/librustc/ty/query/plumbing.rs b/src/librustc/ty/query/plumbing.rs index 562cd75a75ff4..37cb6753ed5b2 100644 --- a/src/librustc/ty/query/plumbing.rs +++ b/src/librustc/ty/query/plumbing.rs @@ -1,24 +1,26 @@ -//! The implementation of the query system itself. Defines the macros -//! that generate the actual methods on tcx which find and execute the -//! provider, manage the caches, and so forth. +//! The implementation of the query system itself. This defines the macros that +//! generate the actual methods on tcx which find and execute the provider, +//! manage the caches, and so forth. + +use crate::dep_graph::{DepNodeIndex, DepNode, DepKind, SerializedDepNodeIndex}; +use crate::ty::tls; +use crate::ty::{TyCtxt}; +use crate::ty::query::Query; +use crate::ty::query::config::{QueryConfig, QueryDescription}; +use crate::ty::query::job::{QueryJob, QueryResult, QueryInfo}; +use crate::ty::item_path; + +use crate::util::common::{profq_msg, ProfileQueriesMsg, QueryMsg}; -use dep_graph::{DepNodeIndex, DepNode, DepKind, DepNodeColor}; use errors::DiagnosticBuilder; use errors::Level; use errors::Diagnostic; use errors::FatalError; -use ty::tls; -use ty::{TyCtxt}; -use ty::query::Query; -use ty::query::config::{QueryConfig, QueryDescription}; -use ty::query::job::{QueryJob, QueryResult, QueryInfo}; -use ty::item_path; - -use util::common::{profq_msg, ProfileQueriesMsg, QueryMsg}; - use rustc_data_structures::fx::{FxHashMap}; use rustc_data_structures::sync::{Lrc, Lock}; use rustc_data_structures::thin_vec::ThinVec; +#[cfg(not(parallel_compiler))] +use rustc_data_structures::cold_path; use std::mem; use std::ptr; use std::collections::hash_map::Entry; @@ -113,8 +115,8 @@ impl<'a, 'tcx, Q: QueryDescription<'tcx>> JobOwner<'a, 'tcx, Q> { let mut lock = cache.borrow_mut(); if let Some(value) = lock.results.get(key) { profq_msg!(tcx, ProfileQueriesMsg::CacheHit); - tcx.sess.profiler(|p| p.record_query_hit(Q::CATEGORY)); - let result = Ok((value.value.clone(), value.index)); + tcx.sess.profiler(|p| p.record_query_hit(Q::NAME, Q::CATEGORY)); + let result = (value.value.clone(), value.index); #[cfg(debug_assertions)] { lock.cache_hits += 1; @@ -124,7 +126,15 @@ impl<'a, 'tcx, Q: QueryDescription<'tcx>> JobOwner<'a, 'tcx, Q> { let job = match lock.active.entry((*key).clone()) { Entry::Occupied(entry) => { match *entry.get() { - QueryResult::Started(ref job) => job.clone(), + QueryResult::Started(ref job) => { + //For parallel queries, we'll block and wait until the query running + //in another thread has completed. Record how long we wait in the + //self-profiler + #[cfg(parallel_compiler)] + tcx.sess.profiler(|p| p.query_blocked_start(Q::NAME, Q::CATEGORY)); + + job.clone() + }, QueryResult::Poisoned => FatalError.raise(), } } @@ -152,16 +162,21 @@ impl<'a, 'tcx, Q: QueryDescription<'tcx>> JobOwner<'a, 'tcx, Q> { mem::drop(lock); // If we are single-threaded we know that we have cycle error, - // so we just turn the errror - #[cfg(not(parallel_queries))] - return job.cycle_error(tcx, span); + // so we just return the error + #[cfg(not(parallel_compiler))] + return TryGetJob::Cycle(cold_path(|| { + Q::handle_cycle_error(tcx, job.find_cycle_in_stack(tcx, span)) + })); // With parallel queries we might just have to wait on some other // thread - #[cfg(parallel_queries)] + #[cfg(parallel_compiler)] { - if let Err(cycle) = job.await(tcx, span) { - return TryGetJob::JobCompleted(Err(cycle)); + let result = job.r#await(tcx, span); + tcx.sess.profiler(|p| p.query_blocked_end(Q::NAME, Q::CATEGORY)); + + if let Err(cycle) = result { + return TryGetJob::Cycle(Q::handle_cycle_error(tcx, cycle)); } } } @@ -188,40 +203,6 @@ impl<'a, 'tcx, Q: QueryDescription<'tcx>> JobOwner<'a, 'tcx, Q> { job.signal_complete(); } - - /// Executes a job by changing the ImplicitCtxt to point to the - /// new query job while it executes. It returns the diagnostics - /// captured during execution and the actual result. - #[inline(always)] - pub(super) fn start<'lcx, F, R>( - &self, - tcx: TyCtxt<'_, 'tcx, 'lcx>, - diagnostics: Option<&Lock>>, - compute: F) - -> R - where - F: for<'b> FnOnce(TyCtxt<'b, 'tcx, 'lcx>) -> R - { - // The TyCtxt stored in TLS has the same global interner lifetime - // as `tcx`, so we use `with_related_context` to relate the 'gcx lifetimes - // when accessing the ImplicitCtxt - tls::with_related_context(tcx, move |current_icx| { - // Update the ImplicitCtxt to point to our new query job - let new_icx = tls::ImplicitCtxt { - tcx: tcx.global_tcx(), - query: Some(self.job.clone()), - diagnostics, - layout_depth: current_icx.layout_depth, - task_deps: current_icx.task_deps, - }; - - // Use the ImplicitCtxt while we execute the query - tls::enter_context(&new_icx, |_| { - compute(tcx) - }) - }) - } - } #[inline(always)] @@ -261,16 +242,52 @@ pub(super) enum TryGetJob<'a, 'tcx: 'a, D: QueryDescription<'tcx> + 'a> { /// The query was already completed. /// Returns the result of the query and its dep node index /// if it succeeded or a cycle error if it failed - JobCompleted(Result<(D::Value, DepNodeIndex), Box>>), + JobCompleted((D::Value, DepNodeIndex)), + + /// Trying to execute the query resulted in a cycle. + Cycle(D::Value), } impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { + /// Executes a job by changing the ImplicitCtxt to point to the + /// new query job while it executes. It returns the diagnostics + /// captured during execution and the actual result. + #[inline(always)] + pub(super) fn start_query( + self, + job: Lrc>, + diagnostics: Option<&Lock>>, + compute: F) + -> R + where + F: for<'b, 'lcx> FnOnce(TyCtxt<'b, 'gcx, 'lcx>) -> R + { + // The TyCtxt stored in TLS has the same global interner lifetime + // as `self`, so we use `with_related_context` to relate the 'gcx lifetimes + // when accessing the ImplicitCtxt + tls::with_related_context(self, move |current_icx| { + // Update the ImplicitCtxt to point to our new query job + let new_icx = tls::ImplicitCtxt { + tcx: self.global_tcx(), + query: Some(job), + diagnostics, + layout_depth: current_icx.layout_depth, + task_deps: current_icx.task_deps, + }; + + // Use the ImplicitCtxt while we execute the query + tls::enter_context(&new_icx, |_| { + compute(self.global_tcx()) + }) + }) + } + #[inline(never)] #[cold] pub(super) fn report_cycle( self, - box CycleError { usage, cycle: stack }: Box> - ) -> Box> + CycleError { usage, cycle: stack }: CycleError<'gcx> + ) -> DiagnosticBuilder<'a> { assert!(!stack.is_empty()); @@ -304,7 +321,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { &format!("cycle used when {}", query.describe(self))); } - return Box::new(err) + err }) } @@ -335,48 +352,13 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { eprintln!("end of query stack"); } - /// Try to read a node index for the node dep_node. - /// A node will have an index, when it's already been marked green, or when we can mark it - /// green. This function will mark the current task as a reader of the specified node, when - /// a node index can be found for that node. - pub(super) fn try_mark_green_and_read(self, dep_node: &DepNode) -> Option { - match self.dep_graph.node_color(dep_node) { - Some(DepNodeColor::Green(dep_node_index)) => { - self.dep_graph.read_index(dep_node_index); - Some(dep_node_index) - } - Some(DepNodeColor::Red) => { - None - } - None => { - // try_mark_green (called below) will panic when full incremental - // compilation is disabled. If that's the case, we can't try to mark nodes - // as green anyway, so we can safely return None here. - if !self.dep_graph.is_fully_enabled() { - return None; - } - match self.dep_graph.try_mark_green(self.global_tcx(), &dep_node) { - Some(dep_node_index) => { - debug_assert!(self.dep_graph.is_green(&dep_node)); - self.dep_graph.read_index(dep_node_index); - Some(dep_node_index) - } - None => { - None - } - } - } - } - } - #[inline(never)] - fn try_get_with>( + pub(super) fn get_query>( self, span: Span, key: Q::Key) - -> Result>> - { - debug!("ty::queries::{}::try_get_with(key={:?}, span={:?})", + -> Q::Value { + debug!("ty::query::get_query<{}>(key={:?}, span={:?})", Q::NAME, key, span); @@ -390,36 +372,35 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { let job = match JobOwner::try_get(self, span, &key) { TryGetJob::NotYetStarted(job) => job, - TryGetJob::JobCompleted(result) => { - return result.map(|(v, index)| { - self.dep_graph.read_index(index); - v - }) + TryGetJob::Cycle(result) => return result, + TryGetJob::JobCompleted((v, index)) => { + self.dep_graph.read_index(index); + return v } }; // Fast path for when incr. comp. is off. `to_dep_node` is // expensive for some DepKinds. if !self.dep_graph.is_fully_enabled() { - let null_dep_node = DepNode::new_no_params(::dep_graph::DepKind::Null); - return Ok(self.force_query_with_job::(key, job, null_dep_node).0); + let null_dep_node = DepNode::new_no_params(crate::dep_graph::DepKind::Null); + return self.force_query_with_job::(key, job, null_dep_node).0; } let dep_node = Q::to_dep_node(self, &key); if dep_node.kind.is_anon() { profq_msg!(self, ProfileQueriesMsg::ProviderBegin); - self.sess.profiler(|p| p.start_activity(Q::CATEGORY)); + self.sess.profiler(|p| p.start_query(Q::NAME, Q::CATEGORY)); let ((result, dep_node_index), diagnostics) = with_diagnostics(|diagnostics| { - job.start(self, diagnostics, |tcx| { + self.start_query(job.job.clone(), diagnostics, |tcx| { tcx.dep_graph.with_anon_task(dep_node.kind, || { Q::compute(tcx.global_tcx(), key) }) }) }); - self.sess.profiler(|p| p.end_activity(Q::CATEGORY)); + self.sess.profiler(|p| p.end_query(Q::NAME, Q::CATEGORY)); profq_msg!(self, ProfileQueriesMsg::ProviderEnd); self.dep_graph.read_index(dep_node_index); @@ -431,29 +412,39 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { job.complete(&result, dep_node_index); - return Ok(result); + return result; } if !dep_node.kind.is_input() { - if let Some(dep_node_index) = self.try_mark_green_and_read(&dep_node) { - return Ok(self.load_from_disk_and_cache_in_memory::( - key, - job, - dep_node_index, - &dep_node - )) + // The diagnostics for this query will be + // promoted to the current session during + // try_mark_green(), so we can ignore them here. + let loaded = self.start_query(job.job.clone(), None, |tcx| { + let marked = tcx.dep_graph.try_mark_green_and_read(tcx, &dep_node); + marked.map(|(prev_dep_node_index, dep_node_index)| { + (tcx.load_from_disk_and_cache_in_memory::( + key.clone(), + prev_dep_node_index, + dep_node_index, + &dep_node + ), dep_node_index) + }) + }); + if let Some((result, dep_node_index)) = loaded { + job.complete(&result, dep_node_index); + return result; } } let (result, dep_node_index) = self.force_query_with_job::(key, job, dep_node); self.dep_graph.read_index(dep_node_index); - Ok(result) + result } fn load_from_disk_and_cache_in_memory>( self, key: Q::Key, - job: JobOwner<'a, 'gcx, Q>, + prev_dep_node_index: SerializedDepNodeIndex, dep_node_index: DepNodeIndex, dep_node: &DepNode ) -> Q::Value @@ -464,12 +455,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { debug_assert!(self.dep_graph.is_green(dep_node)); // First we try to load the result from the on-disk cache - let result = if Q::cache_on_disk(key.clone()) && + let result = if Q::cache_on_disk(self.global_tcx(), key.clone()) && self.sess.opts.debugging_opts.incremental_queries { - let prev_dep_node_index = - self.dep_graph.prev_dep_node_index_of(dep_node); - let result = Q::try_load_from_disk(self.global_tcx(), - prev_dep_node_index); + self.sess.profiler(|p| p.incremental_load_result_start(Q::NAME)); + let result = Q::try_load_from_disk(self.global_tcx(), prev_dep_node_index); + self.sess.profiler(|p| p.incremental_load_result_end(Q::NAME)); // We always expect to find a cached result for things that // can be forced from DepNode. @@ -485,27 +475,22 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { let result = if let Some(result) = result { profq_msg!(self, ProfileQueriesMsg::CacheHit); - self.sess.profiler(|p| p.record_query_hit(Q::CATEGORY)); + self.sess.profiler(|p| p.record_query_hit(Q::NAME, Q::CATEGORY)); result } else { // We could not load a result from the on-disk cache, so // recompute. - self.sess.profiler(|p| p.start_activity(Q::CATEGORY)); + self.sess.profiler(|p| p.start_query(Q::NAME, Q::CATEGORY)); - // The diagnostics for this query have already been - // promoted to the current session during - // try_mark_green(), so we can ignore them here. - let result = job.start(self, None, |tcx| { - // The dep-graph for this computation is already in - // place - tcx.dep_graph.with_ignore(|| { - Q::compute(tcx, key) - }) + // The dep-graph for this computation is already in + // place + let result = self.dep_graph.with_ignore(|| { + Q::compute(self, key) }); - self.sess.profiler(|p| p.end_activity(Q::CATEGORY)); + self.sess.profiler(|p| p.end_query(Q::NAME, Q::CATEGORY)); result }; @@ -519,8 +504,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.dep_graph.mark_loaded_from_cache(dep_node_index, true); } - job.complete(&result, dep_node_index); - result } @@ -532,8 +515,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { dep_node: &DepNode, dep_node_index: DepNodeIndex, ) { - use rustc_data_structures::stable_hasher::{StableHasher, HashStable}; - use ich::Fingerprint; + use crate::ich::Fingerprint; assert!(Some(self.dep_graph.fingerprint_of(dep_node_index)) == self.dep_graph.prev_fingerprint_of(dep_node), @@ -542,11 +524,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { debug!("BEGIN verify_ich({:?})", dep_node); let mut hcx = self.create_stable_hashing_context(); - let mut hasher = StableHasher::new(); - - result.hash_stable(&mut hcx, &mut hasher); - let new_hash: Fingerprint = hasher.finish(); + let new_hash = Q::hash_result(&mut hcx, result).unwrap_or(Fingerprint::ZERO); debug!("END verify_ich({:?})", dep_node); let old_hash = self.dep_graph.fingerprint_of(dep_node_index); @@ -574,32 +553,34 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { key, dep_node); profq_msg!(self, ProfileQueriesMsg::ProviderBegin); - self.sess.profiler(|p| p.start_activity(Q::CATEGORY)); + self.sess.profiler(|p| p.start_query(Q::NAME, Q::CATEGORY)); let ((result, dep_node_index), diagnostics) = with_diagnostics(|diagnostics| { - job.start(self, diagnostics, |tcx| { + self.start_query(job.job.clone(), diagnostics, |tcx| { if dep_node.kind.is_eval_always() { tcx.dep_graph.with_eval_always_task(dep_node, tcx, key, - Q::compute) + Q::compute, + Q::hash_result) } else { tcx.dep_graph.with_task(dep_node, tcx, key, - Q::compute) + Q::compute, + Q::hash_result) } }) }); - self.sess.profiler(|p| p.end_activity(Q::CATEGORY)); + self.sess.profiler(|p| p.end_query(Q::NAME, Q::CATEGORY)); profq_msg!(self, ProfileQueriesMsg::ProviderEnd); if unlikely!(self.sess.opts.debugging_opts.query_dep_graph) { self.dep_graph.mark_loaded_from_cache(dep_node_index, false); } - if dep_node.kind != ::dep_graph::DepKind::Null { + if dep_node.kind != crate::dep_graph::DepKind::Null { if unlikely!(!diagnostics.is_empty()) { self.queries.on_disk_cache .store_diagnostics(dep_node_index, diagnostics); @@ -624,7 +605,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // Ensuring an "input" or anonymous query makes no sense assert!(!dep_node.kind.is_anon()); assert!(!dep_node.kind.is_input()); - if self.try_mark_green_and_read(&dep_node).is_none() { + if self.dep_graph.try_mark_green_and_read(self, &dep_node).is_none() { // A None return from `try_mark_green_and_read` means that this is either // a new dep node or that the dep node has already been marked red. // Either way, we can't call `dep_graph.read()` as we don't have the @@ -635,7 +616,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { let _ = self.get_query::(DUMMY_SP, key); } else { profq_msg!(self, ProfileQueriesMsg::CacheHit); - self.sess.profiler(|p| p.record_query_hit(Q::CATEGORY)); + self.sess.profiler(|p| p.record_query_hit(Q::NAME, Q::CATEGORY)); } } @@ -655,63 +636,46 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // Ensure that only one of them runs the query let job = match JobOwner::try_get(self, span, &key) { TryGetJob::NotYetStarted(job) => job, - TryGetJob::JobCompleted(result) => { - if let Err(e) = result { - self.report_cycle(e).emit(); - } + TryGetJob::Cycle(_) | + TryGetJob::JobCompleted(_) => { return } }; self.force_query_with_job::(key, job, dep_node); } - - pub(super) fn try_get_query>( - self, - span: Span, - key: Q::Key, - ) -> Result>> { - match self.try_get_with::(span, key) { - Ok(e) => Ok(e), - Err(e) => Err(self.report_cycle(e)), - } - } - - // FIXME: Try uninlining this - #[inline(always)] - pub(super) fn get_query>( - self, - span: Span, - key: Q::Key, - ) -> Q::Value { - self.try_get_with::(span, key).unwrap_or_else(|e| { - self.emit_error::(e) - }) - } - - #[inline(never)] - #[cold] - fn emit_error>( - self, - e: Box>, - ) -> Q::Value { - self.report_cycle(e).emit(); - Q::handle_cycle_error(self) - } } macro_rules! handle_cycle_error { - ([][$this: expr]) => {{ - Value::from_cycle_error($this.global_tcx()) + ([][$tcx: expr, $error:expr]) => {{ + $tcx.report_cycle($error).emit(); + Value::from_cycle_error($tcx.global_tcx()) + }}; + ([fatal_cycle$(, $modifiers:ident)*][$tcx:expr, $error:expr]) => {{ + $tcx.report_cycle($error).emit(); + $tcx.sess.abort_if_errors(); + unreachable!() }}; - ([fatal_cycle$(, $modifiers:ident)*][$this:expr]) => {{ - $this.sess.abort_if_errors(); - unreachable!(); + ([cycle_delay_bug$(, $modifiers:ident)*][$tcx:expr, $error:expr]) => {{ + $tcx.report_cycle($error).delay_as_bug(); + Value::from_cycle_error($tcx.global_tcx()) }}; ([$other:ident$(, $modifiers:ident)*][$($args:tt)*]) => { handle_cycle_error!([$($modifiers),*][$($args)*]) }; } +macro_rules! hash_result { + ([][$hcx:expr, $result:expr]) => {{ + dep_graph::hash_result($hcx, &$result) + }}; + ([no_hash$(, $modifiers:ident)*][$hcx:expr, $result:expr]) => {{ + None + }}; + ([$other:ident$(, $modifiers:ident)*][$($args:tt)*]) => { + hash_result!([$($modifiers),*][$($args)*]) + }; +} + macro_rules! define_queries { (<$tcx:tt> $($category:tt { $($(#[$attr:meta])* [$($modifiers:tt)*] fn $name:ident: $node:ident($K:ty) -> $V:ty,)* @@ -728,16 +692,16 @@ macro_rules! define_queries_inner { [$($modifiers:tt)*] fn $name:ident: $node:ident($K:ty) -> $V:ty,)*) => { use std::mem; - #[cfg(parallel_queries)] + #[cfg(parallel_compiler)] use ty::query::job::QueryResult; use rustc_data_structures::sync::Lock; - use { + use crate::{ rustc_data_structures::stable_hasher::HashStable, rustc_data_structures::stable_hasher::StableHasherResult, rustc_data_structures::stable_hasher::StableHasher, ich::StableHashingContext }; - use util::profiling::ProfileCategory; + use crate::util::profiling::ProfileCategory; define_queries_struct! { tcx: $tcx, @@ -762,6 +726,7 @@ macro_rules! define_queries_inner { sess.profiler(|p| { $( p.record_computed_queries( + as QueryConfig<'_>>::NAME, as QueryConfig<'_>>::CATEGORY, self.$name.lock().results.len() ); @@ -769,7 +734,7 @@ macro_rules! define_queries_inner { }); } - #[cfg(parallel_queries)] + #[cfg(parallel_compiler)] pub fn collect_active_jobs(&self) -> Vec>> { let mut jobs = Vec::new(); @@ -980,7 +945,7 @@ macro_rules! define_queries_inner { #[allow(unused)] #[inline(always)] fn to_dep_node(tcx: TyCtxt<'_, $tcx, '_>, key: &Self::Key) -> DepNode { - use dep_graph::DepConstructor::*; + use crate::dep_graph::DepConstructor::*; DepNode::new(tcx, $node(*key)) } @@ -999,24 +964,34 @@ macro_rules! define_queries_inner { }) } - fn handle_cycle_error(tcx: TyCtxt<'_, 'tcx, '_>) -> Self::Value { - handle_cycle_error!([$($modifiers)*][tcx]) + fn hash_result( + _hcx: &mut StableHashingContext<'_>, + _result: &Self::Value + ) -> Option { + hash_result!([$($modifiers)*][_hcx, _result]) } - } - impl<'a, $tcx, 'lcx> queries::$name<$tcx> { - /// Ensure that either this query has all green inputs or been executed. - /// Executing query::ensure(D) is considered a read of the dep-node D. - /// - /// This function is particularly useful when executing passes for their - /// side-effects -- e.g., in order to report errors for erroneous programs. - /// - /// Note: The optimization is only available during incr. comp. - pub fn ensure(tcx: TyCtxt<'a, $tcx, 'lcx>, key: $K) -> () { - tcx.ensure_query::>(key); + fn handle_cycle_error( + tcx: TyCtxt<'_, 'tcx, '_>, + error: CycleError<'tcx> + ) -> Self::Value { + handle_cycle_error!([$($modifiers)*][tcx, error]) } })* + #[derive(Copy, Clone)] + pub struct TyCtxtEnsure<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { + pub tcx: TyCtxt<'a, 'gcx, 'tcx>, + } + + impl<'a, $tcx, 'lcx> TyCtxtEnsure<'a, $tcx, 'lcx> { + $($(#[$attr])* + #[inline(always)] + pub fn $name(self, key: $K) { + self.tcx.ensure_query::>(key) + })* + } + #[derive(Copy, Clone)] pub struct TyCtxtAt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { pub tcx: TyCtxt<'a, 'gcx, 'tcx>, @@ -1032,7 +1007,16 @@ macro_rules! define_queries_inner { } impl<'a, $tcx, 'lcx> TyCtxt<'a, $tcx, 'lcx> { - /// Return a transparent wrapper for `TyCtxt` which uses + /// Returns a transparent wrapper for `TyCtxt`, which ensures queries + /// are executed instead of just returing their results. + #[inline(always)] + pub fn ensure(self) -> TyCtxtEnsure<'a, $tcx, 'lcx> { + TyCtxtEnsure { + tcx: self, + } + } + + /// Returns a transparent wrapper for `TyCtxt` which uses /// `span` as the location of queries performed through it. #[inline(always)] pub fn at(self, span: Span) -> TyCtxtAt<'a, $tcx, 'lcx> { @@ -1073,7 +1057,7 @@ macro_rules! define_queries_struct { (tcx: $tcx:tt, input: ($(([$($modifiers:tt)*] [$($attr:tt)*] [$name:ident]))*)) => { pub struct Queries<$tcx> { - /// This provides access to the incr. comp. on-disk cache for query results. + /// This provides access to the incrimental comilation on-disk cache for query results. /// Do not access this directly. It is only meant to be used by /// `DepGraph::try_mark_green()` and the query infrastructure. pub(crate) on_disk_cache: OnDiskCache<'tcx>, @@ -1129,29 +1113,29 @@ macro_rules! define_provider_struct { /// /// Now, if force_from_dep_node() would always fail, it would be pretty useless. /// Fortunately, we can use some contextual information that will allow us to -/// reconstruct query-keys for certain kinds of DepNodes. In particular, we -/// enforce by construction that the GUID/fingerprint of certain DepNodes is a -/// valid DefPathHash. Since we also always build a huge table that maps every -/// DefPathHash in the current codebase to the corresponding DefId, we have +/// reconstruct query-keys for certain kinds of `DepNode`s. In particular, we +/// enforce by construction that the GUID/fingerprint of certain `DepNode`s is a +/// valid `DefPathHash`. Since we also always build a huge table that maps every +/// `DefPathHash` in the current codebase to the corresponding `DefId`, we have /// everything we need to re-run the query. /// /// Take the `mir_validated` query as an example. Like many other queries, it -/// just has a single parameter: the DefId of the item it will compute the -/// validated MIR for. Now, when we call `force_from_dep_node()` on a dep-node -/// with kind `MirValidated`, we know that the GUID/fingerprint of the dep-node -/// is actually a DefPathHash, and can therefore just look up the corresponding -/// DefId in `tcx.def_path_hash_to_def_id`. +/// just has a single parameter: the `DefId` of the item it will compute the +/// validated MIR for. Now, when we call `force_from_dep_node()` on a `DepNode` +/// with kind `MirValidated`, we know that the GUID/fingerprint of the `DepNode` +/// is actually a `DefPathHash`, and can therefore just look up the corresponding +/// `DefId` in `tcx.def_path_hash_to_def_id`. /// /// When you implement a new query, it will likely have a corresponding new -/// DepKind, and you'll have to support it here in `force_from_dep_node()`. As -/// a rule of thumb, if your query takes a DefId or DefIndex as sole parameter, +/// `DepKind`, and you'll have to support it here in `force_from_dep_node()`. As +/// a rule of thumb, if your query takes a `DefId` or `DefIndex` as sole parameter, /// then `force_from_dep_node()` should not fail for it. Otherwise, you can just /// add it to the "We don't have enough information to reconstruct..." group in /// the match below. pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, dep_node: &DepNode) -> bool { - use hir::def_id::LOCAL_CRATE; + use crate::hir::def_id::LOCAL_CRATE; // We must avoid ever having to call force_from_dep_node() for a // DepNode::CodegenUnit: @@ -1191,7 +1175,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, macro_rules! force { ($query:ident, $key:expr) => { { - tcx.force_query::<::ty::query::queries::$query<'_>>($key, DUMMY_SP, *dep_node); + tcx.force_query::>($key, DUMMY_SP, *dep_node); } } }; @@ -1281,6 +1265,10 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, DepKind::CheckModLoops => { force!(check_mod_loops, def_id!()); } DepKind::CheckModUnstableApiUsage => { force!(check_mod_unstable_api_usage, def_id!()); } DepKind::CheckModItemTypes => { force!(check_mod_item_types, def_id!()); } + DepKind::CheckModPrivacy => { force!(check_mod_privacy, def_id!()); } + DepKind::CheckModIntrinsics => { force!(check_mod_intrinsics, def_id!()); } + DepKind::CheckModLiveness => { force!(check_mod_liveness, def_id!()); } + DepKind::CheckModImplWf => { force!(check_mod_impl_wf, def_id!()); } DepKind::CollectModItemTypes => { force!(collect_mod_item_types, def_id!()); } DepKind::Reachability => { force!(reachable_set, LOCAL_CRATE); } DepKind::MirKeys => { force!(mir_keys, LOCAL_CRATE); } @@ -1362,6 +1350,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, DepKind::CheckImplItemWellFormed => { force!(check_impl_item_well_formed, def_id!()); } DepKind::ReachableNonGenerics => { force!(reachable_non_generics, krate!()); } DepKind::NativeLibraries => { force!(native_libraries, krate!()); } + DepKind::EntryFn => { force!(entry_fn, krate!()); } DepKind::PluginRegistrarFn => { force!(plugin_registrar_fn, krate!()); } DepKind::ProcMacroDeclsStatic => { force!(proc_macro_decls_static, krate!()); } DepKind::CrateDisambiguator => { force!(crate_disambiguator, krate!()); } @@ -1413,6 +1402,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, DepKind::MaybeUnusedTraitImport => { force!(maybe_unused_trait_import, def_id!()); } + DepKind::NamesImportedByGlobUse => { force!(names_imported_by_glob_use, def_id!()); } DepKind::MaybeUnusedExternCrates => { force!(maybe_unused_extern_crates, LOCAL_CRATE); } DepKind::StabilityIndex => { force!(stability_index, LOCAL_CRATE); } DepKind::AllTraits => { force!(all_traits, LOCAL_CRATE); } @@ -1438,6 +1428,9 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, DepKind::UpstreamMonomorphizationsFor => { force!(upstream_monomorphizations_for, def_id!()); } + DepKind::BackendOptimizationLevel => { + force!(backend_optimization_level, krate!()); + } } true @@ -1452,13 +1445,13 @@ macro_rules! impl_load_from_cache { // Check whether the query invocation corresponding to the given // DepNode is eligible for on-disk-caching. pub fn cache_on_disk(&self, tcx: TyCtxt<'_, '_, '_>) -> bool { - use ty::query::queries; - use ty::query::QueryDescription; + use crate::ty::query::queries; + use crate::ty::query::QueryDescription; match self.kind { $(DepKind::$dep_kind => { let def_id = self.extract_def_id(tcx).unwrap(); - queries::$query_name::cache_on_disk(def_id) + queries::$query_name::cache_on_disk(tcx.global_tcx(), def_id) })* _ => false } diff --git a/src/librustc/ty/query/values.rs b/src/librustc/ty/query/values.rs index 3f84f1bc78972..a4b8d365a12ef 100644 --- a/src/librustc/ty/query/values.rs +++ b/src/librustc/ty/query/values.rs @@ -1,4 +1,5 @@ -use ty::{self, Ty, TyCtxt}; +use crate::ty::{self, Ty, TyCtxt, AdtSizedConstraint}; +use crate::ty::util::NeedsDrop; use syntax::symbol::Symbol; @@ -31,3 +32,14 @@ impl<'tcx> Value<'tcx> for ty::SymbolName { } } +impl<'tcx> Value<'tcx> for NeedsDrop { + fn from_cycle_error(_: TyCtxt<'_, 'tcx, 'tcx>) -> Self { + NeedsDrop(false) + } +} + +impl<'tcx> Value<'tcx> for AdtSizedConstraint<'tcx> { + fn from_cycle_error(tcx: TyCtxt<'_, 'tcx, 'tcx>) -> Self { + AdtSizedConstraint(tcx.intern_type_list(&[tcx.types.err])) + } +} diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index a16d6fea74c0b..db248072d9b50 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -4,18 +4,18 @@ //! types or regions but can be other things. Examples of type relations are //! subtyping, type equality, etc. -use hir::def_id::DefId; -use ty::subst::{Kind, UnpackedKind, Substs}; -use ty::{self, Ty, TyCtxt, TypeFoldable}; -use ty::error::{ExpectedFound, TypeError}; -use mir::interpret::GlobalId; -use util::common::ErrorReported; +use crate::hir::def_id::DefId; +use crate::ty::subst::{Kind, UnpackedKind, Substs}; +use crate::ty::{self, Ty, TyCtxt, TypeFoldable}; +use crate::ty::error::{ExpectedFound, TypeError}; +use crate::mir::interpret::GlobalId; +use crate::util::common::ErrorReported; use syntax_pos::DUMMY_SP; use std::rc::Rc; use std::iter; use rustc_target::spec::abi; -use hir as ast; -use traits; +use crate::hir as ast; +use crate::traits; pub type RelateResult<'tcx, T> = Result>; @@ -30,7 +30,7 @@ pub trait TypeRelation<'a, 'gcx: 'a+'tcx, 'tcx: 'a> : Sized { /// Returns a static string we can use for printouts. fn tag(&self) -> &'static str; - /// Returns true if the value `a` is the "expected" type in the + /// Returns `true` if the value `a` is the "expected" type in the /// relation. Just affects error messages. fn a_is_expected(&self) -> bool; @@ -588,7 +588,7 @@ impl<'tcx> Relate<'tcx> for &'tcx ty::List> { let tcx = relation.tcx(); let v = a.iter().zip(b.iter()).map(|(ep_a, ep_b)| { - use ty::ExistentialPredicate::*; + use crate::ty::ExistentialPredicate::*; match (*ep_a, *ep_b) { (Trait(ref a), Trait(ref b)) => Ok(Trait(relation.relate(a, b)?)), (Projection(ref a), Projection(ref b)) => Ok(Projection(relation.relate(a, b)?)), @@ -746,7 +746,7 @@ impl<'tcx> Relate<'tcx> for traits::WhereClause<'tcx> { ) -> RelateResult<'tcx, traits::WhereClause<'tcx>> where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'tcx, 'tcx: 'a { - use traits::WhereClause::*; + use crate::traits::WhereClause::*; match (a, b) { (Implemented(a_pred), Implemented(b_pred)) => { Ok(Implemented(relation.relate(a_pred, b_pred)?)) @@ -783,7 +783,7 @@ impl<'tcx> Relate<'tcx> for traits::WellFormed<'tcx> { ) -> RelateResult<'tcx, traits::WellFormed<'tcx>> where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'tcx, 'tcx: 'a { - use traits::WellFormed::*; + use crate::traits::WellFormed::*; match (a, b) { (Trait(a_pred), Trait(b_pred)) => Ok(Trait(relation.relate(a_pred, b_pred)?)), (Ty(a_ty), Ty(b_ty)) => Ok(Ty(relation.relate(a_ty, b_ty)?)), @@ -800,7 +800,7 @@ impl<'tcx> Relate<'tcx> for traits::FromEnv<'tcx> { ) -> RelateResult<'tcx, traits::FromEnv<'tcx>> where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'tcx, 'tcx: 'a { - use traits::FromEnv::*; + use crate::traits::FromEnv::*; match (a, b) { (Trait(a_pred), Trait(b_pred)) => Ok(Trait(relation.relate(a_pred, b_pred)?)), (Ty(a_ty), Ty(b_ty)) => Ok(Ty(relation.relate(a_ty, b_ty)?)), @@ -817,7 +817,7 @@ impl<'tcx> Relate<'tcx> for traits::DomainGoal<'tcx> { ) -> RelateResult<'tcx, traits::DomainGoal<'tcx>> where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'tcx, 'tcx: 'a { - use traits::DomainGoal::*; + use crate::traits::DomainGoal::*; match (a, b) { (Holds(a_wc), Holds(b_wc)) => Ok(Holds(relation.relate(a_wc, b_wc)?)), (WellFormed(a_wf), WellFormed(b_wf)) => Ok(WellFormed(relation.relate(a_wf, b_wf)?)), @@ -840,7 +840,7 @@ impl<'tcx> Relate<'tcx> for traits::Goal<'tcx> { ) -> RelateResult<'tcx, traits::Goal<'tcx>> where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'tcx, 'tcx: 'a { - use traits::GoalKind::*; + use crate::traits::GoalKind::*; match (a, b) { (Implies(a_clauses, a_goal), Implies(b_clauses, b_goal)) => { let clauses = relation.relate(a_clauses, b_clauses)?; @@ -904,7 +904,7 @@ impl<'tcx> Relate<'tcx> for traits::Clause<'tcx> { ) -> RelateResult<'tcx, traits::Clause<'tcx>> where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'tcx, 'tcx: 'a { - use traits::Clause::*; + use crate::traits::Clause::*; match (a, b) { (Implies(a_clause), Implies(b_clause)) => { let clause = relation.relate(a_clause, b_clause)?; diff --git a/src/librustc/ty/steal.rs b/src/librustc/ty/steal.rs index 336a4c3bf2279..a8f9301ba51c9 100644 --- a/src/librustc/ty/steal.rs +++ b/src/librustc/ty/steal.rs @@ -12,14 +12,14 @@ use rustc_data_structures::sync::{RwLock, ReadGuard, MappedReadGuard}; /// Steal>` (to be very specific). Now we can read from this /// as much as we want (using `borrow()`), but you can also /// `steal()`. Once you steal, any further attempt to read will panic. -/// Therefore we know that -- assuming no ICE -- nobody is observing +/// Therefore, we know that -- assuming no ICE -- nobody is observing /// the fact that the MIR was updated. /// /// Obviously, whenever you have a query that yields a `Steal` value, /// you must treat it with caution, and make sure that you know that /// -- once the value is stolen -- it will never be read from again. -/// -/// FIXME(#41710) -- what is the best way to model linear queries? +// +// FIXME(#41710): what is the best way to model linear queries? pub struct Steal { value: RwLock> } diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 258470bf6f860..f9173836cc627 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -3,13 +3,13 @@ //! hand, though we've recently added some macros (e.g., //! `BraceStructLiftImpl!`) to help with the tedium. -use mir::ProjectionKind; -use mir::interpret::ConstValue; -use ty::{self, Lift, Ty, TyCtxt}; -use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; +use crate::mir::ProjectionKind; +use crate::mir::interpret::ConstValue; +use crate::ty::{self, Lift, Ty, TyCtxt}; +use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; use smallvec::SmallVec; -use mir::interpret; +use crate::mir::interpret; use std::rc::Rc; @@ -23,35 +23,35 @@ CloneTypeFoldableAndLiftImpls! { (), bool, usize, - ::ty::layout::VariantIdx, + crate::ty::layout::VariantIdx, u64, String, - ::middle::region::Scope, + crate::middle::region::Scope, ::syntax::ast::FloatTy, ::syntax::ast::NodeId, ::syntax_pos::symbol::Symbol, - ::hir::def::Def, - ::hir::def_id::DefId, - ::hir::InlineAsm, - ::hir::MatchSource, - ::hir::Mutability, - ::hir::Unsafety, + crate::hir::def::Def, + crate::hir::def_id::DefId, + crate::hir::InlineAsm, + crate::hir::MatchSource, + crate::hir::Mutability, + crate::hir::Unsafety, ::rustc_target::spec::abi::Abi, - ::mir::Local, - ::mir::Promoted, - ::traits::Reveal, - ::ty::adjustment::AutoBorrowMutability, - ::ty::AdtKind, + crate::mir::Local, + crate::mir::Promoted, + crate::traits::Reveal, + crate::ty::adjustment::AutoBorrowMutability, + crate::ty::AdtKind, // Including `BoundRegion` is a *bit* dubious, but direct // references to bound region appear in `ty::Error`, and aren't // really meant to be folded. In general, we can only fold a fully // general `Region`. - ::ty::BoundRegion, - ::ty::ClosureKind, - ::ty::IntVarValue, - ::ty::ParamTy, - ::ty::UniverseIndex, - ::ty::Variance, + crate::ty::BoundRegion, + crate::ty::ClosureKind, + crate::ty::IntVarValue, + crate::ty::ParamTy, + crate::ty::UniverseIndex, + crate::ty::Variance, ::syntax_pos::Span, } @@ -421,7 +421,7 @@ impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for ty::error::ExpectedFound { impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> { type Lifted = ty::error::TypeError<'tcx>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { - use ty::error::TypeError::*; + use crate::ty::error::TypeError::*; Some(match *self { Mismatch => Mismatch, @@ -434,6 +434,12 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> { RegionsDoesNotOutlive(a, b) => { return tcx.lift(&(a, b)).map(|(a, b)| RegionsDoesNotOutlive(a, b)) } + RegionsInsufficientlyPolymorphic(a, b) => { + return tcx.lift(&b).map(|b| RegionsInsufficientlyPolymorphic(a, b)) + } + RegionsOverlyPolymorphic(a, b) => { + return tcx.lift(&b).map(|b| RegionsOverlyPolymorphic(a, b)) + } RegionsPlaceholderMismatch => RegionsPlaceholderMismatch, IntMismatch(x) => IntMismatch(x), FloatMismatch(x) => FloatMismatch(x), @@ -498,7 +504,7 @@ impl<'a, 'tcx> Lift<'tcx> for ConstValue<'a> { fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { match *self { ConstValue::Scalar(x) => Some(ConstValue::Scalar(x)), - ConstValue::ScalarPair(x, y) => Some(ConstValue::ScalarPair(x, y)), + ConstValue::Slice(x, y) => Some(ConstValue::Slice(x, y)), ConstValue::ByRef(x, alloc, z) => Some(ConstValue::ByRef( x, alloc.lift_to_tcx(tcx)?, z, )), @@ -651,7 +657,7 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List> { impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - use ty::InstanceDef::*; + use crate::ty::InstanceDef::*; Self { substs: self.substs.fold_with(folder), def: match self.def { @@ -682,7 +688,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> { } fn super_visit_with>(&self, visitor: &mut V) -> bool { - use ty::InstanceDef::*; + use crate::ty::InstanceDef::*; self.substs.visit_with(visitor) || match self.def { Item(did) | VtableShim(did) | Intrinsic(did) | Virtual(did, _) => { @@ -1021,6 +1027,8 @@ EnumTypeFoldableImpl! { (ty::error::TypeError::FixedArraySize)(x), (ty::error::TypeError::ArgCount), (ty::error::TypeError::RegionsDoesNotOutlive)(a, b), + (ty::error::TypeError::RegionsInsufficientlyPolymorphic)(a, b), + (ty::error::TypeError::RegionsOverlyPolymorphic)(a, b), (ty::error::TypeError::RegionsPlaceholderMismatch), (ty::error::TypeError::IntMismatch)(x), (ty::error::TypeError::FloatMismatch)(x), @@ -1042,7 +1050,7 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::LazyConst<'tcx> { ty::LazyConst::Unevaluated(*def_id, substs.fold_with(folder)) } }; - folder.tcx().intern_lazy_const(new) + folder.tcx().mk_lazy_const(new) } fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index b98369b62ea37..350bc45026322 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -1,17 +1,17 @@ //! This module contains `TyKind` and its major components. -use hir; -use hir::def_id::DefId; -use infer::canonical::Canonical; -use mir::interpret::ConstValue; -use middle::region; +use crate::hir; +use crate::hir::def_id::DefId; +use crate::infer::canonical::Canonical; +use crate::mir::interpret::ConstValue; +use crate::middle::region; use polonius_engine::Atom; use rustc_data_structures::indexed_vec::Idx; -use ty::subst::{Substs, Subst, Kind, UnpackedKind}; -use ty::{self, AdtDef, TypeFlags, Ty, TyCtxt, TypeFoldable}; -use ty::{List, TyS, ParamEnvAnd, ParamEnv}; -use util::captures::Captures; -use mir::interpret::{Scalar, Pointer}; +use crate::ty::subst::{Substs, Subst, Kind, UnpackedKind}; +use crate::ty::{self, AdtDef, TypeFlags, Ty, TyCtxt, TypeFoldable}; +use crate::ty::{List, TyS, ParamEnvAnd, ParamEnv}; +use crate::util::captures::Captures; +use crate::mir::interpret::{Scalar, Pointer}; use smallvec::SmallVec; use std::iter; @@ -47,7 +47,7 @@ pub enum BoundRegion { /// Named region parameters for functions (a in &'a T) /// - /// The def-id is needed to distinguish free regions in + /// The `DefId` is needed to distinguish free regions in /// the event of shadowing. BrNamed(DefId, InternedString), @@ -87,7 +87,7 @@ pub enum TyKind<'tcx> { Bool, /// The primitive character type; holds a Unicode scalar value - /// (a non-surrogate code point). Written as `char`. + /// (a non-surrogate code point). Written as `char`. Char, /// A primitive signed integer type. For example, `i32`. @@ -107,6 +107,7 @@ pub enum TyKind<'tcx> { /// definition and not a concrete use of it. Adt(&'tcx AdtDef, &'tcx Substs<'tcx>), + /// An unsized FFI type that is opaque to Rust. Written as `extern type T`. Foreign(DefId), /// The pointee of a string slice. Written as `str`. @@ -115,7 +116,7 @@ pub enum TyKind<'tcx> { /// An array with the given length. Written as `[T; n]`. Array(Ty<'tcx>, &'tcx ty::LazyConst<'tcx>), - /// The pointee of an array slice. Written as `[T]`. + /// The pointee of an array slice. Written as `[T]`. Slice(Ty<'tcx>), /// A raw pointer. Written as `*mut T` or `*const T` @@ -137,7 +138,7 @@ pub enum TyKind<'tcx> { /// ``` FnDef(DefId, &'tcx Substs<'tcx>), - /// A pointer to a function. Written as `fn() -> i32`. + /// A pointer to a function. Written as `fn() -> i32`. /// /// For example the type of `bar` here: /// @@ -165,10 +166,10 @@ pub enum TyKind<'tcx> { /// The never type `!` Never, - /// A tuple type. For example, `(i32, bool)`. + /// A tuple type. For example, `(i32, bool)`. Tuple(&'tcx List>), - /// The projection of an associated type. For example, + /// The projection of an associated type. For example, /// `>::N`. Projection(ProjectionTy<'tcx>), @@ -277,7 +278,7 @@ static_assert!(MEM_SIZE_OF_TY_KIND: ::std::mem::size_of::>() == 24); /// /// All right, you say, but why include the type parameters from the /// original function then? The answer is that codegen may need them -/// when monomorphizing, and they may not appear in the upvars. A +/// when monomorphizing, and they may not appear in the upvars. A /// closure could capture no variables but still make use of some /// in-scope type parameter with a bound (e.g., if our example above /// had an extra `U: Default`, and the closure called `U::default()`). @@ -294,9 +295,9 @@ static_assert!(MEM_SIZE_OF_TY_KIND: ::std::mem::size_of::>() == 24); /// ## Generators /// /// Perhaps surprisingly, `ClosureSubsts` are also used for -/// generators. In that case, what is written above is only half-true +/// generators. In that case, what is written above is only half-true /// -- the set of type parameters is similar, but the role of CK and -/// CS are different. CK represents the "yield type" and CS +/// CS are different. CK represents the "yield type" and CS /// represents the "return type" of the generator. /// /// It'd be nice to split this struct into ClosureSubsts and @@ -441,17 +442,17 @@ impl<'tcx> GeneratorSubsts<'tcx> { self.split(def_id, tcx).return_ty } - /// Return the "generator signature", which consists of its yield + /// Returns the "generator signature", which consists of its yield /// and return types. /// - /// NB. Some bits of the code prefers to see this wrapped in a + /// N.B., some bits of the code prefers to see this wrapped in a /// binder, but it never contains bound regions. Probably this /// function should be removed. pub fn poly_sig(self, def_id: DefId, tcx: TyCtxt<'_, '_, '_>) -> PolyGenSig<'tcx> { ty::Binder::dummy(self.sig(def_id, tcx)) } - /// Return the "generator signature", which consists of its yield + /// Returns the "generator signature", which consists of its yield /// and return types. pub fn sig(self, def_id: DefId, tcx: TyCtxt<'_, '_, '_>) -> GenSig<'tcx> { ty::GenSig { @@ -519,11 +520,11 @@ impl<'tcx> UpvarSubsts<'tcx> { #[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash, RustcEncodable, RustcDecodable)] pub enum ExistentialPredicate<'tcx> { - /// e.g., Iterator + /// E.g., `Iterator`. Trait(ExistentialTraitRef<'tcx>), - /// e.g., Iterator::Item = T + /// E.g., `Iterator::Item = T`. Projection(ExistentialProjection<'tcx>), - /// e.g., Send + /// E.g., `Send`. AutoTrait(DefId), } @@ -550,7 +551,7 @@ impl<'a, 'gcx, 'tcx> ExistentialPredicate<'tcx> { impl<'a, 'gcx, 'tcx> Binder> { pub fn with_self_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, self_ty: Ty<'tcx>) -> ty::Predicate<'tcx> { - use ty::ToPredicate; + use crate::ty::ToPredicate; match *self.skip_binder() { ExistentialPredicate::Trait(tr) => Binder(tr).with_self_ty(tcx, self_ty).to_predicate(), ExistentialPredicate::Projection(p) => @@ -654,12 +655,12 @@ impl<'tcx> Binder<&'tcx List>> { } /// A complete reference to a trait. These take numerous guises in syntax, -/// but perhaps the most recognizable form is in a where clause: +/// but perhaps the most recognizable form is in a where-clause: /// /// T: Foo /// -/// This would be represented by a trait-reference where the def-id is the -/// def-id for the trait `Foo` and the substs define `T` as parameter 0, +/// This would be represented by a trait-reference where the `DefId` is the +/// `DefId` for the trait `Foo` and the substs define `T` as parameter 0, /// and `U` as parameter 1. /// /// Trait references also appear in object types like `Foo`, but in @@ -765,9 +766,9 @@ impl<'a, 'gcx, 'tcx> ExistentialTraitRef<'tcx> { } } - /// Object types don't have a self-type specified. Therefore, when + /// Object types don't have a self type specified. Therefore, when /// we convert the principal trait-ref into a normal trait-ref, - /// you must give *some* self-type. A common choice is `mk_err()` + /// you must give *some* self type. A common choice is `mk_err()` /// or some placeholder type. pub fn with_self_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, self_ty: Ty<'tcx>) -> ty::TraitRef<'tcx> { @@ -788,9 +789,9 @@ impl<'tcx> PolyExistentialTraitRef<'tcx> { self.skip_binder().def_id } - /// Object types don't have a self-type specified. Therefore, when + /// Object types don't have a self type specified. Therefore, when /// we convert the principal trait-ref into a normal trait-ref, - /// you must give *some* self-type. A common choice is `mk_err()` + /// you must give *some* self type. A common choice is `mk_err()` /// or some placeholder type. pub fn with_self_ty(&self, tcx: TyCtxt<'_, '_, 'tcx>, self_ty: Ty<'tcx>) @@ -828,7 +829,7 @@ impl Binder { /// Skips the binder and returns the "bound" value. This is a /// risky thing to do because it's easy to get confused about - /// debruijn indices and the like. It is usually better to + /// De Bruijn indices and the like. It is usually better to /// discharge the binder using `no_bound_vars` or /// `replace_late_bound_regions` or something like /// that. `skip_binder` is only valid when you are either @@ -839,7 +840,7 @@ impl Binder { /// /// Some examples where `skip_binder` is reasonable: /// - /// - extracting the def-id from a PolyTraitRef; + /// - extracting the `DefId` from a PolyTraitRef; /// - comparing the self type of a PolyTraitRef to see if it is equal to /// a type parameter `X`, since the type `X` does not reference any regions pub fn skip_binder(&self) -> &T { @@ -883,8 +884,8 @@ impl Binder { } /// Given two things that have the same binder level, - /// and an operation that wraps on their contents, execute the operation - /// and then wrap its result. + /// and an operation that wraps on their contents, executes the operation + /// and then wraps its result. /// /// `f` should consider bound regions at depth 1 to be free, and /// anything it produces with bound regions at depth 1 will be @@ -895,7 +896,7 @@ impl Binder { Binder(f(self.0, u.0)) } - /// Split the contents into two things that share the same binder + /// Splits the contents into two things that share the same binder /// level as the original, returning two distinct binders. /// /// `f` should consider bound regions at depth 1 to be free, and @@ -1117,14 +1118,14 @@ pub type Region<'tcx> = &'tcx RegionKind; /// ## Bound Regions /// /// These are regions that are stored behind a binder and must be substituted -/// with some concrete region before being used. There are 2 kind of -/// bound regions: early-bound, which are bound in an item's Generics, -/// and are substituted by a Substs, and late-bound, which are part of -/// higher-ranked types (e.g., `for<'a> fn(&'a ())`) and are substituted by +/// with some concrete region before being used. There are two kind of +/// bound regions: early-bound, which are bound in an item's `Generics`, +/// and are substituted by a `Substs`, and late-bound, which are part of +/// higher-ranked types (e.g., `for<'a> fn(&'a ())`), and are substituted by /// the likes of `liberate_late_bound_regions`. The distinction exists /// because higher-ranked lifetimes aren't supported in all places. See [1][2]. /// -/// Unlike Param-s, bound regions are not supposed to exist "in the wild" +/// Unlike `Param`s, bound regions are not supposed to exist "in the wild" /// outside their binder, e.g., in types passed to type inference, and /// should first be substituted (by placeholder regions, free regions, /// or region variables). @@ -1140,7 +1141,7 @@ pub type Region<'tcx> = &'tcx RegionKind; /// To do this, we replace the bound regions with placeholder markers, /// which don't satisfy any relation not explicitly provided. /// -/// There are 2 kinds of placeholder regions in rustc: `ReFree` and +/// There are two kinds of placeholder regions in rustc: `ReFree` and /// `RePlaceholder`. When checking an item's body, `ReFree` is supposed /// to be used. These also support explicit bounds: both the internally-stored /// *scope*, which the region is assumed to outlive, as well as other @@ -1166,13 +1167,13 @@ pub type Region<'tcx> = &'tcx RegionKind; /// [rustc guide]: https://rust-lang.github.io/rustc-guide/traits/hrtb.html #[derive(Clone, PartialEq, Eq, Hash, Copy, RustcEncodable, RustcDecodable, PartialOrd, Ord)] pub enum RegionKind { - // Region bound in a type or fn declaration which will be - // substituted 'early' -- that is, at the same time when type - // parameters are substituted. + /// Region bound in a type or fn declaration which will be + /// substituted 'early' -- that is, at the same time when type + /// parameters are substituted. ReEarlyBound(EarlyBoundRegion), - // Region bound in a function scope, which will be substituted when the - // function is called. + /// Region bound in a function scope, which will be substituted when the + /// function is called. ReLateBound(DebruijnIndex, BoundRegion), /// When checking a function body, the types of all arguments and so forth @@ -1188,7 +1189,7 @@ pub enum RegionKind { /// Static data that has an "infinite" lifetime. Top in the region lattice. ReStatic, - /// A region variable. Should not exist after typeck. + /// A region variable. Should not exist after typeck. ReVar(RegionVid), /// A placeholder region - basically the higher-ranked version of ReFree. @@ -1345,11 +1346,11 @@ impl<'a, 'tcx, 'gcx> PolyExistentialProjection<'tcx> { impl DebruijnIndex { /// Returns the resulting index when this value is moved into - /// `amount` number of new binders. So e.g., if you had + /// `amount` number of new binders. So, e.g., if you had /// /// for<'a> fn(&'a x) /// - /// and you wanted to change to + /// and you wanted to change it to /// /// for<'a> fn(for<'b> fn(&'a x)) /// @@ -1377,7 +1378,7 @@ impl DebruijnIndex { *self = self.shifted_out(amount); } - /// Adjusts any Debruijn Indices so as to make `to_binder` the + /// Adjusts any De Bruijn indices so as to make `to_binder` the /// innermost binder. That is, if we have something bound at `to_binder`, /// it will now be bound at INNERMOST. This is an appropriate thing to do /// when moving a region out from inside binders: @@ -1387,12 +1388,12 @@ impl DebruijnIndex { /// // Binder: D3 D2 D1 ^^ /// ``` /// - /// Here, the region `'a` would have the debruijn index D3, + /// Here, the region `'a` would have the De Bruijn index D3, /// because it is the bound 3 binders out. However, if we wanted /// to refer to that region `'a` in the second argument (the `_`), /// those two binders would not be in scope. In that case, we /// might invoke `shift_out_to_binder(D3)`. This would adjust the - /// debruijn index of `'a` to D1 (the innermost binder). + /// De Bruijn index of `'a` to D1 (the innermost binder). /// /// If we invoke `shift_out_to_binder` and the region is in fact /// bound by one of the binders we are shifting out of, that is an @@ -1443,7 +1444,7 @@ impl RegionKind { } } - /// Adjusts any Debruijn Indices so as to make `to_binder` the + /// Adjusts any De Bruijn indices so as to make `to_binder` the /// innermost binder. That is, if we have something bound at `to_binder`, /// it will now be bound at INNERMOST. This is an appropriate thing to do /// when moving a region out from inside binders: @@ -1453,12 +1454,12 @@ impl RegionKind { /// // Binder: D3 D2 D1 ^^ /// ``` /// - /// Here, the region `'a` would have the debruijn index D3, + /// Here, the region `'a` would have the De Bruijn index D3, /// because it is the bound 3 binders out. However, if we wanted /// to refer to that region `'a` in the second argument (the `_`), /// those two binders would not be in scope. In that case, we /// might invoke `shift_out_to_binder(D3)`. This would adjust the - /// debruijn index of `'a` to D1 (the innermost binder). + /// De Bruijn index of `'a` to D1 (the innermost binder). /// /// If we invoke `shift_out_to_binder` and the region is in fact /// bound by one of the binders we are shifting out of, that is an @@ -1527,7 +1528,7 @@ impl RegionKind { flags } - /// Given an early-bound or free region, returns the def-id where it was bound. + /// Given an early-bound or free region, returns the `DefId` where it was bound. /// For example, consider the regions in this snippet of code: /// /// ``` @@ -1542,10 +1543,10 @@ impl RegionKind { /// } /// ``` /// - /// Here, `free_region_binding_scope('a)` would return the def-id + /// Here, `free_region_binding_scope('a)` would return the `DefId` /// of the impl, and for all the other highlighted regions, it - /// would return the def-id of the function. In other cases (not shown), this - /// function might return the def-id of a closure. + /// would return the `DefId` of the function. In other cases (not shown), this + /// function might return the `DefId` of a closure. pub fn free_region_binding_scope(&self, tcx: TyCtxt<'_, '_, '_>) -> DefId { match self { ty::ReEarlyBound(br) => { @@ -1771,7 +1772,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } - /// Returns true if this type is a floating point type and false otherwise. + /// Returns `true` if this type is a floating point type. pub fn is_floating_point(&self) -> bool { match self.sty { Float(_) | @@ -2063,6 +2064,9 @@ pub enum LazyConst<'tcx> { Evaluated(Const<'tcx>), } +#[cfg(target_arch = "x86_64")] +static_assert!(LAZY_CONST_SIZE: ::std::mem::size_of::>() == 56); + impl<'tcx> LazyConst<'tcx> { pub fn map_evaluated(self, f: impl FnOnce(Const<'tcx>) -> Option) -> Option { match self { @@ -2089,6 +2093,9 @@ pub struct Const<'tcx> { pub val: ConstValue<'tcx>, } +#[cfg(target_arch = "x86_64")] +static_assert!(CONST_SIZE: ::std::mem::size_of::>() == 48); + impl<'tcx> Const<'tcx> { #[inline] pub fn from_scalar( diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index 64e7af815b4bf..7559ea90b1782 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -1,9 +1,9 @@ // Type substitutions. -use hir::def_id::DefId; -use infer::canonical::Canonical; -use ty::{self, Lift, List, Ty, TyCtxt}; -use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; +use crate::hir::def_id::DefId; +use crate::infer::canonical::Canonical; +use crate::ty::{self, Lift, List, Ty, TyCtxt}; +use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use serialize::{self, Encodable, Encoder, Decodable, Decoder}; use syntax_pos::{Span, DUMMY_SP}; @@ -171,7 +171,7 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { /// Creates a `Substs` that maps each generic parameter to a higher-ranked /// var bound at index `0`. For types, we use a `BoundVar` index equal to /// the type parameter index. For regions, we use the `BoundRegion::BrNamed` - /// variant (which has a def-id). + /// variant (which has a `DefId`). pub fn bound_vars_for_item( tcx: TyCtxt<'a, 'gcx, 'tcx>, def_id: DefId @@ -492,7 +492,7 @@ impl<'a, 'gcx, 'tcx> SubstFolder<'a, 'gcx, 'tcx> { self.shift_vars_through_binders(ty) } - /// It is sometimes necessary to adjust the debruijn indices during substitution. This occurs + /// It is sometimes necessary to adjust the De Bruijn indices during substitution. This occurs /// when we are substituting a type with escaping bound vars into a context where we have /// passed through binders. That's quite a mouthful. Let's see an example: /// @@ -511,9 +511,9 @@ impl<'a, 'gcx, 'tcx> SubstFolder<'a, 'gcx, 'tcx> { /// /// Here the `'a` lifetime is bound in the outer function, but appears as an argument of the /// inner one. Therefore, that appearance will have a DebruijnIndex of 2, because we must skip - /// over the inner binder (remember that we count Debruijn indices from 1). However, in the + /// over the inner binder (remember that we count De Bruijn indices from 1). However, in the /// definition of `MetaFunc`, the binder is not visible, so the type `&'a int` will have a - /// debruijn index of 1. It's only during the substitution that we can see we must increase the + /// De Bruijn index of 1. It's only during the substitution that we can see we must increase the /// depth by 1 to account for the binder that we passed through. /// /// As a second example, consider this twist: @@ -532,7 +532,7 @@ impl<'a, 'gcx, 'tcx> SubstFolder<'a, 'gcx, 'tcx> { /// DebruijnIndex of 2 /// /// As indicated in the diagram, here the same type `&'a int` is substituted once, but in the - /// first case we do not increase the Debruijn index and in the second case we do. The reason + /// first case we do not increase the De Bruijn index and in the second case we do. The reason /// is that only in the second case have we passed through a fn binder. fn shift_vars_through_binders(&self, ty: Ty<'tcx>) -> Ty<'tcx> { debug!("shift_vars(ty={:?}, binders_passed={:?}, has_escaping_bound_vars={:?})", @@ -565,7 +565,7 @@ pub struct UserSubsts<'tcx> { /// The substitutions for the item as given by the user. pub substs: &'tcx Substs<'tcx>, - /// The self-type, in the case of a `::Item` path (when applied + /// The self type, in the case of a `::Item` path (when applied /// to an inherent impl). See `UserSelfTy` below. pub user_self_ty: Option>, } @@ -585,8 +585,8 @@ BraceStructLiftImpl! { } } -/// Specifies the user-given self-type. In the case of a path that -/// refers to a member in an inherent impl, this self-type is +/// Specifies the user-given self type. In the case of a path that +/// refers to a member in an inherent impl, this self type is /// sometimes needed to constrain the type parameters on the impl. For /// example, in this code: /// @@ -596,11 +596,11 @@ BraceStructLiftImpl! { /// ``` /// /// when you then have a path like `>::method`, -/// this struct would carry the def-id of the impl along with the -/// self-type `Foo`. Then we can instantiate the parameters of +/// this struct would carry the `DefId` of the impl along with the +/// self type `Foo`. Then we can instantiate the parameters of /// the impl (with the substs from `UserSubsts`) and apply those to -/// the self-type, giving `Foo`. Finally, we unify that with -/// the self-type here, which contains `?A` to be `&'static u32` +/// the self type, giving `Foo`. Finally, we unify that with +/// the self type here, which contains `?A` to be `&'static u32` #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub struct UserSelfTy<'tcx> { pub impl_def_id: DefId, diff --git a/src/librustc/ty/trait_def.rs b/src/librustc/ty/trait_def.rs index 37ec560d6c19f..9ce8bf2e60a31 100644 --- a/src/librustc/ty/trait_def.rs +++ b/src/librustc/ty/trait_def.rs @@ -1,11 +1,11 @@ -use hir; -use hir::def_id::DefId; -use hir::map::DefPathHash; -use ich::{self, StableHashingContext}; -use traits::specialization_graph; -use ty::fast_reject; -use ty::fold::TypeFoldable; -use ty::{Ty, TyCtxt}; +use crate::hir; +use crate::hir::def_id::DefId; +use crate::hir::map::DefPathHash; +use crate::ich::{self, StableHashingContext}; +use crate::traits::specialization_graph; +use crate::ty::fast_reject; +use crate::ty::fold::TypeFoldable; +use crate::ty::{Ty, TyCtxt}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher, @@ -39,7 +39,7 @@ pub struct TraitDef { #[derive(Default)] pub struct TraitImpls { blanket_impls: Vec, - /// Impls indexed by their simplified self-type, for fast lookup. + /// Impls indexed by their simplified self type, for fast lookup. non_blanket_impls: FxHashMap>, } @@ -84,7 +84,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } /// Iterate over every impl that could possibly match the - /// self-type `self_ty`. + /// self type `self_ty`. pub fn for_each_relevant_impl(self, def_id: DefId, self_ty: Ty<'tcx>, @@ -134,7 +134,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } - /// Return a vector containing all impls + /// Returns a vector containing all impls pub fn all_impls(self, def_id: DefId) -> Vec { let impls = self.trait_impls_of(def_id); diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index e989ef823e979..1ba7c3bba797c 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -1,18 +1,18 @@ -//! misc. type-system utilities too small to deserve their own file - -use hir::def::Def; -use hir::def_id::DefId; -use hir::map::DefPathData; -use hir::{self, Node}; -use ich::NodeIdHashingMode; -use traits::{self, ObligationCause}; -use ty::{self, Ty, TyCtxt, GenericParamDefKind, TypeFoldable}; -use ty::subst::{Subst, Substs, UnpackedKind}; -use ty::query::TyCtxtAt; -use ty::TyKind::*; -use ty::layout::{Integer, IntegerExt}; -use util::common::ErrorReported; -use middle::lang_items; +//! Miscellaneous type-system utilities that are too small to deserve their own modules. + +use crate::hir::def::Def; +use crate::hir::def_id::DefId; +use crate::hir::map::DefPathData; +use crate::hir::{self, Node}; +use crate::ich::NodeIdHashingMode; +use crate::traits::{self, ObligationCause}; +use crate::ty::{self, Ty, TyCtxt, GenericParamDefKind, TypeFoldable}; +use crate::ty::subst::{Subst, Substs, UnpackedKind}; +use crate::ty::query::TyCtxtAt; +use crate::ty::TyKind::*; +use crate::ty::layout::{Integer, IntegerExt}; +use crate::util::common::ErrorReported; +use crate::middle::lang_items; use rustc_data_structures::stable_hasher::{StableHasher, HashStable}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -23,7 +23,7 @@ use syntax_pos::{Span, DUMMY_SP}; #[derive(Copy, Clone, Debug)] pub struct Discr<'tcx> { - /// bit representation of the discriminant, so `-128i8` is `0xFF_u128` + /// Bit representation of the discriminant (e.g., `-128i8` is `0xFF_u128`). pub val: u128, pub ty: Ty<'tcx> } @@ -46,7 +46,7 @@ impl<'tcx> fmt::Display for Discr<'tcx> { } impl<'tcx> Discr<'tcx> { - /// Adds 1 to the value and wraps around if the maximum for the type is reached + /// Adds `1` to the value and wraps around if the maximum for the type is reached. pub fn wrap_incr<'a, 'gcx>(self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Self { self.checked_add(tcx, 1).0 } @@ -342,9 +342,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// /// Requires that trait definitions have been processed so that we can /// elaborate predicates and walk supertraits. - /// - /// FIXME callers may only have a &[Predicate], not a Vec, so that's - /// what this code should accept. + // + // FIXME: callers may only have a `&[Predicate]`, not a `Vec`, so that's + // what this code should accept. pub fn required_region_bounds(self, erased_self_ty: Ty<'tcx>, predicates: Vec>) @@ -402,7 +402,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { return None; }; - ty::query::queries::coherent_trait::ensure(self, drop_trait); + self.ensure().coherent_trait(drop_trait); let mut dtor_did = None; let ty = self.type_of(adt_did); @@ -417,7 +417,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { Some(ty::Destructor { did: dtor_did? }) } - /// Return the set of types that are required to be alive in + /// Returns the set of types that are required to be alive in /// order to run the destructor of `def` (see RFCs 769 and /// 1238). /// @@ -507,17 +507,17 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { result } - /// True if `def_id` refers to a closure (e.g., `|x| x * 2`). Note - /// that closures have a def-id, but the closure *expression* also + /// Returns `true` if `def_id` refers to a closure (e.g., `|x| x * 2`). Note + /// that closures have a `DefId`, but the closure *expression* also /// has a `HirId` that is located within the context where the /// closure appears (and, sadly, a corresponding `NodeId`, since /// those are not yet phased out). The parent of the closure's - /// def-id will also be the context where it appears. + /// `DefId` will also be the context where it appears. pub fn is_closure(self, def_id: DefId) -> bool { self.def_key(def_id).disambiguated_data.data == DefPathData::ClosureExpr } - /// True if `def_id` refers to a trait (i.e., `trait Foo { ... }`). + /// Returns `true` if `def_id` refers to a trait (i.e., `trait Foo { ... }`). pub fn is_trait(self, def_id: DefId) -> bool { if let DefPathData::Trait(_) = self.def_key(def_id).disambiguated_data.data { true @@ -526,17 +526,27 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } - /// True if this def-id refers to the implicit constructor for - /// a tuple struct like `struct Foo(u32)`. + /// Returns `true` if `def_id` refers to a trait alias (i.e., `trait Foo = ...;`), + /// and `false` otherwise. + pub fn is_trait_alias(self, def_id: DefId) -> bool { + if let DefPathData::TraitAlias(_) = self.def_key(def_id).disambiguated_data.data { + true + } else { + false + } + } + + /// Returns `true` if this `DefId` refers to the implicit constructor for + /// a tuple struct like `struct Foo(u32)`, and `false` otherwise. pub fn is_struct_constructor(self, def_id: DefId) -> bool { self.def_key(def_id).disambiguated_data.data == DefPathData::StructCtor } /// Given the `DefId` of a fn or closure, returns the `DefId` of /// the innermost fn item that the closure is contained within. - /// This is a significant def-id because, when we do + /// This is a significant `DefId` because, when we do /// type-checking, we type-check this fn item and all of its - /// (transitive) closures together. Therefore, when we fetch the + /// (transitive) closures together. Therefore, when we fetch the /// `typeck_tables_of` the closure, for example, we really wind up /// fetching the `typeck_tables_of` the enclosing fn item. pub fn closure_base_def_id(self, def_id: DefId) -> DefId { @@ -549,10 +559,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { def_id } - /// Given the def-id and substs a closure, creates the type of + /// Given the `DefId` and substs a closure, creates the type of /// `self` argument that the closure expects. For example, for a /// `Fn` closure, this would return a reference type `&T` where - /// `T=closure_ty`. + /// `T = closure_ty`. /// /// Returns `None` if this closure's kind has not yet been inferred. /// This should only be possible during type checking. @@ -576,7 +586,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { Some(ty::Binder::bind(env_ty)) } - /// Given the def-id of some item that has no type parameters, make + /// Given the `DefId` of some item that has no type parameters, make /// a suitable "empty substs" for it. pub fn empty_substs_for_def_id(self, item_def_id: DefId) -> &'tcx Substs<'tcx> { Substs::for_item(self, item_def_id, |param, _| { @@ -589,7 +599,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { }) } - /// Return whether the node pointed to by def_id is a static item, and its mutability + /// Returns `true` if the node pointed to by `def_id` is a static item, and its mutability. pub fn is_static(&self, def_id: DefId) -> Option { if let Some(node) = self.hir().get_if_local(def_id) { match node { @@ -721,7 +731,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> { /// Checks whether values of this type `T` implement the `Freeze` /// trait -- frozen types are those that do not contain a - /// `UnsafeCell` anywhere. This is a language concept used to + /// `UnsafeCell` anywhere. This is a language concept used to /// distinguish "true immutability", which is relevant to /// optimization as well as the rules around static values. Note /// that the `Freeze` trait is not exposed to end users and is @@ -745,7 +755,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> { tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool { - tcx.needs_drop_raw(param_env.and(self)) + tcx.needs_drop_raw(param_env.and(self)).0 } pub fn same_type(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { @@ -982,29 +992,22 @@ fn is_freeze_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, )) } +#[derive(Clone)] +pub struct NeedsDrop(pub bool); + fn needs_drop_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) - -> bool + -> NeedsDrop { let (param_env, ty) = query.into_parts(); let needs_drop = |ty: Ty<'tcx>| -> bool { - tcx.try_needs_drop_raw(DUMMY_SP, param_env.and(ty)).unwrap_or_else(|mut bug| { - // Cycles should be reported as an error by `check_representable`. - // - // Consider the type as not needing drop in the meanwhile to - // avoid further errors. - // - // In case we forgot to emit a bug elsewhere, delay our - // diagnostic to get emitted as a compiler bug. - bug.delay_as_bug(); - false - }) + tcx.needs_drop_raw(param_env.and(ty)).0 }; assert!(!ty.needs_infer()); - match ty.sty { + NeedsDrop(match ty.sty { // Fast-path for primitive types ty::Infer(ty::FreshIntTy(_)) | ty::Infer(ty::FreshFloatTy(_)) | ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Never | @@ -1062,7 +1065,7 @@ fn needs_drop_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def.variants.iter().any( |variant| variant.fields.iter().any( |field| needs_drop(field.ty(tcx, substs)))), - } + }) } pub enum ExplicitSelf<'tcx> { diff --git a/src/librustc/ty/walk.rs b/src/librustc/ty/walk.rs index 6887d092fcd62..126f5290af513 100644 --- a/src/librustc/ty/walk.rs +++ b/src/librustc/ty/walk.rs @@ -1,7 +1,7 @@ //! An iterator over the type substructure. //! WARNING: this does not keep track of the region depth. -use ty::{self, Ty}; +use crate::ty::{self, Ty}; use smallvec::{self, SmallVec}; // The TypeWalker's stack is hot enough that it's worth going to some effort to diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index ef68394029680..282bf1219fa5c 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -1,12 +1,12 @@ -use hir::def_id::DefId; -use infer::InferCtxt; -use ty::subst::Substs; -use traits; -use ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable}; +use crate::hir; +use crate::hir::def_id::DefId; +use crate::infer::InferCtxt; +use crate::ty::subst::Substs; +use crate::traits; +use crate::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable}; use std::iter::once; -use syntax::ast; use syntax_pos::Span; -use middle::lang_items; +use crate::middle::lang_items; /// Returns the set of obligations needed to make `ty` well-formed. /// If `ty` contains unresolved inference variables, this may include @@ -16,7 +16,7 @@ use middle::lang_items; /// say "$0 is WF if $0 is WF". pub fn obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, - body_id: ast::NodeId, + body_id: hir::HirId, ty: Ty<'tcx>, span: Span) -> Option>> @@ -42,7 +42,7 @@ pub fn obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, /// if `Bar: Eq`. pub fn trait_obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, - body_id: ast::NodeId, + body_id: hir::HirId, trait_ref: &ty::TraitRef<'tcx>, span: Span) -> Vec> @@ -54,7 +54,7 @@ pub fn trait_obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, pub fn predicate_obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, - body_id: ast::NodeId, + body_id: hir::HirId, predicate: &ty::Predicate<'tcx>, span: Span) -> Vec> @@ -103,7 +103,7 @@ pub fn predicate_obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, struct WfPredicates<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, - body_id: ast::NodeId, + body_id: hir::HirId, span: Span, out: Vec>, } @@ -227,7 +227,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { } } - /// Push new obligations into `out`. Returns true if it was able + /// Pushes new obligations into `out`. Returns `true` if it was able /// to generate all the predicates needed to validate that `ty0` /// is WF. Returns false if `ty0` is an unresolved type variable, /// in which case we are not able to simplify at all. @@ -502,7 +502,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { } } -/// Given an object type like `SomeTrait+Send`, computes the lifetime +/// Given an object type like `SomeTrait + Send`, computes the lifetime /// bounds that must hold on the elided self type. These are derived /// from the declarations of `SomeTrait`, `Send`, and friends -- if /// they declare `trait SomeTrait : 'static`, for example, then diff --git a/src/librustc/util/bug.rs b/src/librustc/util/bug.rs index 7698f5ece98cc..02ddfab6d826e 100644 --- a/src/librustc/util/bug.rs +++ b/src/librustc/util/bug.rs @@ -1,6 +1,6 @@ // These functions are used by macro expansion for bug! and span_bug! -use ty::tls; +use crate::ty::tls; use std::fmt; use syntax_pos::{Span, MultiSpan}; diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs index cc0ca165053d3..dd635e5c946f0 100644 --- a/src/librustc/util/common.rs +++ b/src/librustc/util/common.rs @@ -12,10 +12,10 @@ use std::time::{Duration, Instant}; use std::sync::mpsc::{Sender}; use syntax_pos::{SpanData}; -use ty::TyCtxt; -use dep_graph::{DepNode}; +use crate::ty::TyCtxt; +use crate::dep_graph::{DepNode}; use lazy_static; -use session::Session; +use crate::session::Session; // The name of the associated type for `Fn` return types pub const FN_OUTPUT_NAME: &str = "Output"; @@ -63,11 +63,11 @@ pub fn install_panic_hook() { /// Parameters to the `Dump` variant of type `ProfileQueriesMsg`. #[derive(Clone,Debug)] pub struct ProfQDumpParams { - /// A base path for the files we will dump + /// A base path for the files we will dump. pub path:String, - /// To ensure that the compiler waits for us to finish our dumps + /// To ensure that the compiler waits for us to finish our dumps. pub ack:Sender<()>, - /// toggle dumping a log file with every `ProfileQueriesMsg` + /// Toggle dumping a log file with every `ProfileQueriesMsg`. pub dump_profq_msg_log:bool, } @@ -131,7 +131,7 @@ pub fn time_depth() -> usize { TIME_DEPTH.with(|slot| slot.get()) } -/// Set the current depth of `time()` calls. The idea is to call +/// Sets the current depth of `time()` calls. The idea is to call /// `set_time_depth()` with the result from `time_depth()` in the /// parent thread. pub fn set_time_depth(depth: usize) { diff --git a/src/librustc/util/nodemap.rs b/src/librustc/util/nodemap.rs index fe6ab075a1a8a..63c7b76d1b6a5 100644 --- a/src/librustc/util/nodemap.rs +++ b/src/librustc/util/nodemap.rs @@ -1,7 +1,7 @@ -//! An efficient hash map for node IDs +//! An efficient hash map for `NodeId`s. -use hir::def_id::DefId; -use hir::{HirId, ItemLocalId}; +use crate::hir::def_id::DefId; +use crate::hir::{HirId, ItemLocalId}; use syntax::ast; pub use rustc_data_structures::fx::FxHashMap; diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 04e571863d42f..768fd02e8238a 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -1,15 +1,15 @@ -use hir::def_id::DefId; -use hir::map::definitions::DefPathData; -use middle::region; -use ty::subst::{self, Subst}; -use ty::{BrAnon, BrEnv, BrFresh, BrNamed}; -use ty::{Bool, Char, Adt}; -use ty::{Error, Str, Array, Slice, Float, FnDef, FnPtr}; -use ty::{Param, Bound, RawPtr, Ref, Never, Tuple}; -use ty::{Closure, Generator, GeneratorWitness, Foreign, Projection, Opaque}; -use ty::{Placeholder, UnnormalizedProjection, Dynamic, Int, Uint, Infer}; -use ty::{self, Ty, TyCtxt, TypeFoldable, GenericParamCount, GenericParamDefKind}; -use util::nodemap::FxHashSet; +use crate::hir::def_id::DefId; +use crate::hir::map::definitions::DefPathData; +use crate::middle::region; +use crate::ty::subst::{self, Subst}; +use crate::ty::{BrAnon, BrEnv, BrFresh, BrNamed}; +use crate::ty::{Bool, Char, Adt}; +use crate::ty::{Error, Str, Array, Slice, Float, FnDef, FnPtr}; +use crate::ty::{Param, Bound, RawPtr, Ref, Never, Tuple}; +use crate::ty::{Closure, Generator, GeneratorWitness, Foreign, Projection, Opaque}; +use crate::ty::{Placeholder, UnnormalizedProjection, Dynamic, Int, Uint, Infer}; +use crate::ty::{self, Ty, TyCtxt, TypeFoldable, GenericParamCount, GenericParamDefKind}; +use crate::util::nodemap::FxHashSet; use std::cell::Cell; use std::fmt; @@ -18,23 +18,23 @@ use std::usize; use rustc_target::spec::abi::Abi; use syntax::ast::CRATE_NODE_ID; use syntax::symbol::{Symbol, InternedString}; -use hir; +use crate::hir; /// The "region highlights" are used to control region printing during /// specific error messages. When a "region highlight" is enabled, it /// gives an alternate way to print specific regions. For now, we -/// always print those regions using a number, so something like `'0`. +/// always print those regions using a number, so something like "`'0`". /// /// Regions not selected by the region highlight mode are presently /// unaffected. #[derive(Copy, Clone, Default)] pub struct RegionHighlightMode { - /// If enabled, when we see the selected region, use `"'N"` + /// If enabled, when we see the selected region, use "`'N`" /// instead of the ordinary behavior. highlight_regions: [Option<(ty::RegionKind, usize)>; 3], /// If enabled, when printing a "free region" that originated from - /// the given `ty::BoundRegion`, print it as `'1`. Free regions that would ordinarily + /// the given `ty::BoundRegion`, print it as "`'1`". Free regions that would ordinarily /// have names print as normal. /// /// This is used when you have a signature like `fn foo(x: &u32, @@ -51,12 +51,12 @@ thread_local! { } impl RegionHighlightMode { - /// Read and return current region highlight settings (accesses thread-local state).a + /// Reads and returns the current region highlight settings (accesses thread-local state). pub fn get() -> Self { REGION_HIGHLIGHT_MODE.with(|c| c.get()) } - /// Internal helper to update current settings during the execution of `op`. + // Internal helper to update current settings during the execution of `op`. fn set( old_mode: Self, new_mode: Self, @@ -70,8 +70,8 @@ impl RegionHighlightMode { }) } - /// If `region` and `number` are both `Some`, invoke - /// `highlighting_region`. Otherwise, just invoke `op` directly. + /// If `region` and `number` are both `Some`, invokes + /// `highlighting_region`; otherwise, just invokes `op` directly. pub fn maybe_highlighting_region( region: Option>, number: Option, @@ -86,8 +86,8 @@ impl RegionHighlightMode { op() } - /// During the execution of `op`, highlight the region inference - /// vairable `vid` as `'N`. We can only highlight one region vid + /// During the execution of `op`, highlights the region inference + /// variable `vid` as `'N`. We can only highlight one region `vid` /// at a time. pub fn highlighting_region( region: ty::Region<'_>, @@ -109,7 +109,7 @@ impl RegionHighlightMode { Self::set(old_mode, new_mode, op) } - /// Convenience wrapper for `highlighting_region` + /// Convenience wrapper for `highlighting_region`. pub fn highlighting_region_vid( vid: ty::RegionVid, number: usize, @@ -118,7 +118,7 @@ impl RegionHighlightMode { Self::highlighting_region(&ty::ReVar(vid), number, op) } - /// Returns true if any placeholders are highlighted. + /// Returns `true` if any placeholders are highlighted, and `false` otherwise. fn any_region_vids_highlighted(&self) -> bool { Self::get() .highlight_regions @@ -129,8 +129,7 @@ impl RegionHighlightMode { }) } - /// Returns `Some(n)` with the number to use for the given region, - /// if any. + /// Returns `Some(n)` with the number to use for the given region, if any. fn region_highlighted(&self, region: ty::Region<'_>) -> Option { Self::get() .highlight_regions @@ -143,7 +142,7 @@ impl RegionHighlightMode { } /// During the execution of `op`, highlight the given bound - /// region. We can only highlight one bound region at a time. See + /// region. We can only highlight one bound region at a time. See /// the field `highlight_bound_region` for more detailed notes. pub fn highlighting_bound_region( br: ty::BoundRegion, @@ -162,7 +161,7 @@ impl RegionHighlightMode { ) } - /// Returns true if any placeholders are highlighted. + /// Returns `true` if any placeholders are highlighted, and `false` otherwise. pub fn any_placeholders_highlighted(&self) -> bool { Self::get() .highlight_regions @@ -173,7 +172,7 @@ impl RegionHighlightMode { }) } - /// Returns `Some(N)` if the placeholder `p` is highlighted to print as `'N`. + /// Returns `Some(N)` if the placeholder `p` is highlighted to print as "`'N`". pub fn placeholder_highlight(&self, p: ty::PlaceholderRegion) -> Option { self.region_highlighted(&ty::RePlaceholder(p)) } @@ -409,6 +408,7 @@ impl PrintContext { DefPathData::AssocTypeInImpl(_) | DefPathData::AssocExistentialInImpl(_) | DefPathData::Trait(_) | + DefPathData::TraitAlias(_) | DefPathData::Impl | DefPathData::TypeNs(_) => { break; @@ -425,6 +425,7 @@ impl PrintContext { DefPathData::ClosureExpr | DefPathData::TypeParam(_) | DefPathData::LifetimeParam(_) | + DefPathData::ConstParam(_) | DefPathData::Field(_) | DefPathData::StructCtor | DefPathData::AnonConst | @@ -800,7 +801,7 @@ impl fmt::Debug for ty::UpvarId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "UpvarId({:?};`{}`;{:?})", self.var_path.hir_id, - ty::tls::with(|tcx| tcx.hir().name(tcx.hir().hir_to_node_id(self.var_path.hir_id))), + ty::tls::with(|tcx| tcx.hir().name_by_hir_id(self.var_path.hir_id)), self.closure_expr_id) } } @@ -1429,6 +1430,15 @@ define_print! { } } + if cx.is_verbose { + write!( + f, + " closure_kind_ty={:?} closure_sig_ty={:?}", + substs.closure_kind_ty(did, tcx), + substs.closure_sig_ty(did, tcx), + )?; + } + write!(f, "]") }), Array(ty, sz) => { diff --git a/src/librustc/util/profiling.rs b/src/librustc/util/profiling.rs index d31a06d6cb82d..c90bd12a3100f 100644 --- a/src/librustc/util/profiling.rs +++ b/src/librustc/util/profiling.rs @@ -1,146 +1,168 @@ -use session::config::Options; - +use std::collections::{BTreeMap, HashMap}; use std::fs; -use std::io::{self, StderrLock, Write}; +use std::io::{self, Write}; +use std::thread::ThreadId; use std::time::Instant; -macro_rules! define_categories { - ($($name:ident,)*) => { - #[derive(Clone, Copy, Debug, PartialEq, Eq)] - pub enum ProfileCategory { - $($name),* - } +use crate::session::config::{Options, OptLevel}; - #[allow(nonstandard_style)] - struct Categories { - $($name: T),* - } +#[derive(Clone, Copy, Debug, PartialEq, Eq, Ord, PartialOrd)] +pub enum ProfileCategory { + Parsing, + Expansion, + TypeChecking, + BorrowChecking, + Codegen, + Linking, + Other, +} - impl Categories { - fn new() -> Categories { - Categories { - $($name: T::default()),* - } - } +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum ProfilerEvent { + QueryStart { query_name: &'static str, category: ProfileCategory, time: Instant }, + QueryEnd { query_name: &'static str, category: ProfileCategory, time: Instant }, + GenericActivityStart { category: ProfileCategory, time: Instant }, + GenericActivityEnd { category: ProfileCategory, time: Instant }, + QueryCacheHit { query_name: &'static str, category: ProfileCategory }, + QueryCount { query_name: &'static str, category: ProfileCategory, count: usize }, + IncrementalLoadResultStart { query_name: &'static str, time: Instant }, + IncrementalLoadResultEnd { query_name: &'static str, time: Instant }, + QueryBlockedStart { query_name: &'static str, category: ProfileCategory, time: Instant }, + QueryBlockedEnd { query_name: &'static str, category: ProfileCategory, time: Instant }, +} + +impl ProfilerEvent { + fn is_start_event(&self) -> bool { + use self::ProfilerEvent::*; + + match self { + QueryStart { .. } | + GenericActivityStart { .. } | + IncrementalLoadResultStart { .. } | + QueryBlockedStart { .. } => true, + + QueryEnd { .. } | + GenericActivityEnd { .. } | + QueryCacheHit { .. } | + QueryCount { .. } | + IncrementalLoadResultEnd { .. } | + QueryBlockedEnd { .. } => false, } + } +} - impl Categories { - fn get(&self, category: ProfileCategory) -> &T { - match category { - $(ProfileCategory::$name => &self.$name),* - } - } +pub struct SelfProfiler { + events: HashMap>, +} - fn set(&mut self, category: ProfileCategory, value: T) { - match category { - $(ProfileCategory::$name => self.$name = value),* - } - } +struct CategoryResultData { + query_times: BTreeMap<&'static str, u64>, + query_cache_stats: BTreeMap<&'static str, (u64, u64)>, //(hits, total) +} + +impl CategoryResultData { + fn new() -> CategoryResultData { + CategoryResultData { + query_times: BTreeMap::new(), + query_cache_stats: BTreeMap::new(), } + } - struct CategoryData { - times: Categories, - query_counts: Categories<(u64, u64)>, + fn total_time(&self) -> u64 { + self.query_times.iter().map(|(_, time)| time).sum() + } + + fn total_cache_data(&self) -> (u64, u64) { + let (mut hits, mut total) = (0, 0); + + for (_, (h, t)) in &self.query_cache_stats { + hits += h; + total += t; } - impl CategoryData { - fn new() -> CategoryData { - CategoryData { - times: Categories::new(), - query_counts: Categories::new(), - } - } + (hits, total) + } +} - fn print(&self, lock: &mut StderrLock<'_>) { - writeln!(lock, "| Phase | Time (ms) \ - | Time (%) | Queries | Hits (%)") - .unwrap(); - writeln!(lock, "| ---------------- | -------------- \ - | -------- | -------------- | --------") - .unwrap(); - - let total_time = ($(self.times.$name + )* 0) as f32; - - $( - let (hits, computed) = self.query_counts.$name; - let total = hits + computed; - let (hits, total) = if total > 0 { - (format!("{:.2}", - (((hits as f32) / (total as f32)) * 100.0)), total.to_string()) - } else { - (String::new(), String::new()) - }; +impl Default for CategoryResultData { + fn default() -> CategoryResultData { + CategoryResultData::new() + } +} - writeln!( - lock, - "| {0: <16} | {1: <14} | {2: <8.2} | {3: <14} | {4: <8}", - stringify!($name), - self.times.$name / 1_000_000, - ((self.times.$name as f32) / total_time) * 100.0, - total, - hits, - ).unwrap(); - )* - } +struct CalculatedResults { + categories: BTreeMap, + crate_name: Option, + optimization_level: OptLevel, + incremental: bool, + verbose: bool, +} - fn json(&self) -> String { - let mut json = String::from("["); - - $( - let (hits, computed) = self.query_counts.$name; - let total = hits + computed; - - //normalize hits to 0% - let hit_percent = - if total > 0 { - ((hits as f32) / (total as f32)) * 100.0 - } else { - 0.0 - }; - - json.push_str(&format!( - "{{ \"category\": \"{}\", \"time_ms\": {},\ - \"query_count\": {}, \"query_hits\": {} }},", - stringify!($name), - self.times.$name / 1_000_000, - total, - format!("{:.2}", hit_percent) - )); - )* +impl CalculatedResults { + fn new() -> CalculatedResults { + CalculatedResults { + categories: BTreeMap::new(), + crate_name: None, + optimization_level: OptLevel::No, + incremental: false, + verbose: false, + } + } - //remove the trailing ',' character - json.pop(); + fn consolidate(mut cr1: CalculatedResults, cr2: CalculatedResults) -> CalculatedResults { + for (category, data) in cr2.categories { + let cr1_data = cr1.categories.entry(category).or_default(); - json.push(']'); + for (query, time) in data.query_times { + *cr1_data.query_times.entry(query).or_default() += time; + } - json + for (query, (hits, total)) in data.query_cache_stats { + let (h, t) = cr1_data.query_cache_stats.entry(query).or_insert((0, 0)); + *h += hits; + *t += total; } } + + cr1 + } + + fn total_time(&self) -> u64 { + self.categories.iter().map(|(_, data)| data.total_time()).sum() + } + + fn with_options(mut self, opts: &Options) -> CalculatedResults { + self.crate_name = opts.crate_name.clone(); + self.optimization_level = opts.optimize; + self.incremental = opts.incremental.is_some(); + self.verbose = opts.debugging_opts.verbose; + + self } } -define_categories! { - Parsing, - Expansion, - TypeChecking, - BorrowChecking, - Codegen, - Linking, - Other, +fn time_between_ns(start: Instant, end: Instant) -> u64 { + if start < end { + let time = end - start; + (time.as_secs() * 1_000_000_000) + (time.subsec_nanos() as u64) + } else { + debug!("time_between_ns: ignorning instance of end < start"); + 0 + } } -pub struct SelfProfiler { - timer_stack: Vec, - data: CategoryData, - current_timer: Instant, +fn calculate_percent(numerator: u64, denominator: u64) -> f32 { + if denominator > 0 { + ((numerator as f32) / (denominator as f32)) * 100.0 + } else { + 0.0 + } } impl SelfProfiler { pub fn new() -> SelfProfiler { let mut profiler = SelfProfiler { - timer_stack: Vec::new(), - data: CategoryData::new(), - current_timer: Instant::now(), + events: HashMap::new(), }; profiler.start_activity(ProfileCategory::Other); @@ -148,104 +170,301 @@ impl SelfProfiler { profiler } + #[inline] pub fn start_activity(&mut self, category: ProfileCategory) { - match self.timer_stack.last().cloned() { - None => { - self.current_timer = Instant::now(); - }, - Some(current_category) if current_category == category => { - //since the current category is the same as the new activity's category, - //we don't need to do anything with the timer, we just need to push it on the stack - } - Some(current_category) => { - let elapsed = self.stop_timer(); + self.record(ProfilerEvent::GenericActivityStart { + category, + time: Instant::now(), + }) + } - //record the current category's time - let new_time = self.data.times.get(current_category) + elapsed; - self.data.times.set(current_category, new_time); - } - } + #[inline] + pub fn end_activity(&mut self, category: ProfileCategory) { + self.record(ProfilerEvent::GenericActivityEnd { + category, + time: Instant::now(), + }) + } - //push the new category - self.timer_stack.push(category); + #[inline] + pub fn record_computed_queries( + &mut self, + query_name: &'static str, + category: ProfileCategory, + count: usize) + { + self.record(ProfilerEvent::QueryCount { + query_name, + category, + count, + }) } - pub fn record_computed_queries(&mut self, category: ProfileCategory, count: usize) { - let (hits, computed) = *self.data.query_counts.get(category); - self.data.query_counts.set(category, (hits, computed + count as u64)); + #[inline] + pub fn record_query_hit(&mut self, query_name: &'static str, category: ProfileCategory) { + self.record(ProfilerEvent::QueryCacheHit { + query_name, + category, + }) } - pub fn record_query_hit(&mut self, category: ProfileCategory) { - let (hits, computed) = *self.data.query_counts.get(category); - self.data.query_counts.set(category, (hits + 1, computed)); + #[inline] + pub fn start_query(&mut self, query_name: &'static str, category: ProfileCategory) { + self.record(ProfilerEvent::QueryStart { + query_name, + category, + time: Instant::now(), + }); } - pub fn end_activity(&mut self, category: ProfileCategory) { - match self.timer_stack.pop() { - None => bug!("end_activity() was called but there was no running activity"), - Some(c) => - assert!( - c == category, - "end_activity() was called but a different activity was running"), + #[inline] + pub fn end_query(&mut self, query_name: &'static str, category: ProfileCategory) { + self.record(ProfilerEvent::QueryEnd { + query_name, + category, + time: Instant::now(), + }) + } + + #[inline] + pub fn incremental_load_result_start(&mut self, query_name: &'static str) { + self.record(ProfilerEvent::IncrementalLoadResultStart { + query_name, + time: Instant::now(), + }) + } + + #[inline] + pub fn incremental_load_result_end(&mut self, query_name: &'static str) { + self.record(ProfilerEvent::IncrementalLoadResultEnd { + query_name, + time: Instant::now(), + }) + } + + #[inline] + pub fn query_blocked_start(&mut self, query_name: &'static str, category: ProfileCategory) { + self.record(ProfilerEvent::QueryBlockedStart { + query_name, + category, + time: Instant::now(), + }) + } + + #[inline] + pub fn query_blocked_end(&mut self, query_name: &'static str, category: ProfileCategory) { + self.record(ProfilerEvent::QueryBlockedEnd { + query_name, + category, + time: Instant::now(), + }) + } + + #[inline] + fn record(&mut self, event: ProfilerEvent) { + let thread_id = std::thread::current().id(); + let events = self.events.entry(thread_id).or_default(); + + events.push(event); + } + + fn calculate_thread_results(events: &Vec) -> CalculatedResults { + use self::ProfilerEvent::*; + + assert!( + events.last().map(|e| !e.is_start_event()).unwrap_or(true), + "there was an event running when calculate_reslts() was called" + ); + + let mut results = CalculatedResults::new(); + + //(event, child time to subtract) + let mut query_stack = Vec::new(); + + for event in events { + match event { + QueryStart { .. } | GenericActivityStart { .. } => { + query_stack.push((event, 0)); + }, + QueryEnd { query_name, category, time: end_time } => { + let previous_query = query_stack.pop(); + if let Some((QueryStart { + query_name: p_query_name, + time: start_time, + category: _ }, child_time_to_subtract)) = previous_query { + assert_eq!( + p_query_name, + query_name, + "Saw a query end but the previous query wasn't the corresponding start" + ); + + let time_ns = time_between_ns(*start_time, *end_time); + let self_time_ns = time_ns - child_time_to_subtract; + let result_data = results.categories.entry(*category).or_default(); + + *result_data.query_times.entry(query_name).or_default() += self_time_ns; + + if let Some((_, child_time_to_subtract)) = query_stack.last_mut() { + *child_time_to_subtract += time_ns; + } + } else { + bug!("Saw a query end but the previous event wasn't a query start"); + } + } + GenericActivityEnd { category, time: end_time } => { + let previous_event = query_stack.pop(); + if let Some((GenericActivityStart { + category: previous_category, + time: start_time }, child_time_to_subtract)) = previous_event { + assert_eq!( + previous_category, + category, + "Saw an end but the previous event wasn't the corresponding start" + ); + + let time_ns = time_between_ns(*start_time, *end_time); + let self_time_ns = time_ns - child_time_to_subtract; + let result_data = results.categories.entry(*category).or_default(); + + *result_data.query_times + .entry("{time spent not running queries}") + .or_default() += self_time_ns; + + if let Some((_, child_time_to_subtract)) = query_stack.last_mut() { + *child_time_to_subtract += time_ns; + } + } else { + bug!("Saw an activity end but the previous event wasn't an activity start"); + } + }, + QueryCacheHit { category, query_name } => { + let result_data = results.categories.entry(*category).or_default(); + + let (hits, total) = + result_data.query_cache_stats.entry(query_name).or_insert((0, 0)); + *hits += 1; + *total += 1; + }, + QueryCount { category, query_name, count } => { + let result_data = results.categories.entry(*category).or_default(); + + let (_, totals) = + result_data.query_cache_stats.entry(query_name).or_insert((0, 0)); + *totals += *count as u64; + }, + //we don't summarize incremental load result events in the simple output mode + IncrementalLoadResultStart { .. } | IncrementalLoadResultEnd { .. } => { }, + //we don't summarize parallel query blocking in the simple output mode + QueryBlockedStart { .. } | QueryBlockedEnd { .. } => { }, + } } - //check if the new running timer is in the same category as this one - //if it is, we don't need to do anything - if let Some(c) = self.timer_stack.last() { - if *c == category { - return; + //normalize the times to ms + for (_, data) in &mut results.categories { + for (_, time) in &mut data.query_times { + *time = *time / 1_000_000; } } - //the new timer is different than the previous, - //so record the elapsed time and start a new timer - let elapsed = self.stop_timer(); - let new_time = self.data.times.get(category) + elapsed; - self.data.times.set(category, new_time); + results } - fn stop_timer(&mut self) -> u64 { - let elapsed = self.current_timer.elapsed(); - - self.current_timer = Instant::now(); - - (elapsed.as_secs() * 1_000_000_000) + (elapsed.subsec_nanos() as u64) + fn get_results(&self, opts: &Options) -> CalculatedResults { + self.events + .iter() + .map(|(_, r)| SelfProfiler::calculate_thread_results(r)) + .fold(CalculatedResults::new(), CalculatedResults::consolidate) + .with_options(opts) } pub fn print_results(&mut self, opts: &Options) { self.end_activity(ProfileCategory::Other); - assert!( - self.timer_stack.is_empty(), - "there were timers running when print_results() was called"); + let results = self.get_results(opts); + + let total_time = results.total_time() as f32; let out = io::stderr(); let mut lock = out.lock(); - let crate_name = - opts.crate_name - .as_ref() - .map(|n| format!(" for {}", n)) - .unwrap_or_default(); + let crate_name = results.crate_name.map(|n| format!(" for {}", n)).unwrap_or_default(); writeln!(lock, "Self profiling results{}:", crate_name).unwrap(); writeln!(lock).unwrap(); - self.data.print(&mut lock); + writeln!(lock, "| Phase | Time (ms) \ + | Time (%) | Queries | Hits (%)") + .unwrap(); + writeln!(lock, "| ----------------------------------------- | -------------- \ + | -------- | -------------- | --------") + .unwrap(); + + let mut categories: Vec<_> = results.categories.iter().collect(); + categories.sort_by_cached_key(|(_, d)| d.total_time()); + + for (category, data) in categories.iter().rev() { + let (category_hits, category_total) = data.total_cache_data(); + let category_hit_percent = calculate_percent(category_hits, category_total); + + writeln!( + lock, + "| {0: <41} | {1: >14} | {2: >8.2} | {3: >14} | {4: >8}", + format!("{:?}", category), + data.total_time(), + ((data.total_time() as f32) / total_time) * 100.0, + category_total, + format!("{:.2}", category_hit_percent), + ).unwrap(); + + //in verbose mode, show individual query data + if results.verbose { + //don't show queries that took less than 1ms + let mut times: Vec<_> = data.query_times.iter().filter(|(_, t)| **t > 0).collect(); + times.sort_by(|(_, time1), (_, time2)| time2.cmp(time1)); + + for (query, time) in times { + let (hits, total) = data.query_cache_stats.get(query).unwrap_or(&(0, 0)); + let hit_percent = calculate_percent(*hits, *total); + + writeln!( + lock, + "| - {0: <39} | {1: >14} | {2: >8.2} | {3: >14} | {4: >8}", + query, + time, + ((*time as f32) / total_time) * 100.0, + total, + format!("{:.2}", hit_percent), + ).unwrap(); + } + } + } writeln!(lock).unwrap(); writeln!(lock, "Optimization level: {:?}", opts.optimize).unwrap(); - - let incremental = if opts.incremental.is_some() { "on" } else { "off" }; - writeln!(lock, "Incremental: {}", incremental).unwrap(); + writeln!(lock, "Incremental: {}", if results.incremental { "on" } else { "off" }).unwrap(); } pub fn save_results(&self, opts: &Options) { - let category_data = self.data.json(); + let results = self.get_results(opts); + let compilation_options = format!("{{ \"optimization_level\": \"{:?}\", \"incremental\": {} }}", - opts.optimize, - if opts.incremental.is_some() { "true" } else { "false" }); + results.optimization_level, + if results.incremental { "true" } else { "false" }); + + let mut category_data = String::new(); + + for (category, data) in &results.categories { + let (hits, total) = data.total_cache_data(); + let hit_percent = calculate_percent(hits, total); + + category_data.push_str(&format!("{{ \"category\": \"{:?}\", \"time_ms\": {}, \ + \"query_count\": {}, \"query_hits\": {} }}", + category, + data.total_time(), + total, + format!("{:.2}", hit_percent))); + } let json = format!("{{ \"category_data\": {}, \"compilation_options\": {} }}", category_data, diff --git a/src/librustc_allocator/Cargo.toml b/src/librustc_allocator/Cargo.toml index 03d33f413c807..cf6c598bfb17b 100644 --- a/src/librustc_allocator/Cargo.toml +++ b/src/librustc_allocator/Cargo.toml @@ -2,6 +2,7 @@ authors = ["The Rust Project Developers"] name = "rustc_allocator" version = "0.0.0" +edition = "2018" [lib] path = "lib.rs" diff --git a/src/librustc_allocator/expand.rs b/src/librustc_allocator/expand.rs index 73a35c7cdcd5f..758a0d63886b1 100644 --- a/src/librustc_allocator/expand.rs +++ b/src/librustc_allocator/expand.rs @@ -1,6 +1,6 @@ +use log::debug; use rustc::middle::allocator::AllocatorKind; -use rustc_errors; -use smallvec::SmallVec; +use smallvec::{smallvec, SmallVec}; use syntax::{ ast::{ self, Arg, Attribute, Crate, Expr, FnHeader, Generics, Ident, Item, ItemKind, @@ -16,22 +16,22 @@ use syntax::{ expand::ExpansionConfig, hygiene::{self, Mark, SyntaxContext}, }, - fold::{self, Folder}, + mut_visit::{self, MutVisitor}, parse::ParseSess, ptr::P, symbol::Symbol }; use syntax_pos::Span; -use {AllocatorMethod, AllocatorTy, ALLOCATOR_METHODS}; +use crate::{AllocatorMethod, AllocatorTy, ALLOCATOR_METHODS}; pub fn modify( sess: &ParseSess, resolver: &mut dyn Resolver, - krate: Crate, + krate: &mut Crate, crate_name: String, handler: &rustc_errors::Handler, -) -> ast::Crate { +) { ExpandAllocatorDirectives { handler, sess, @@ -39,7 +39,7 @@ pub fn modify( found: false, crate_name: Some(crate_name), in_submod: -1, // -1 to account for the "root" module - }.fold_crate(krate) + }.visit_crate(krate); } struct ExpandAllocatorDirectives<'a> { @@ -54,14 +54,14 @@ struct ExpandAllocatorDirectives<'a> { in_submod: isize, } -impl<'a> Folder for ExpandAllocatorDirectives<'a> { - fn fold_item(&mut self, item: P) -> SmallVec<[P; 1]> { +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 { - return fold::noop_fold_item(item, self); + return mut_visit::noop_flat_map_item(item, self); }; match item.node { ItemKind::Static(..) => {} @@ -91,7 +91,9 @@ impl<'a> Folder for ExpandAllocatorDirectives<'a> { call_site: item.span, // use the call site of the static def_site: None, format: MacroAttribute(Symbol::intern(name)), - allow_internal_unstable: true, + allow_internal_unstable: Some(vec![ + Symbol::intern("rustc_attrs"), + ].into()), allow_internal_unsafe: false, local_inner_macros: false, edition: hygiene::default_edition(), @@ -139,25 +141,24 @@ impl<'a> Folder for ExpandAllocatorDirectives<'a> { let name = f.kind.fn_name("allocator_abi"); let allocator_abi = Ident::with_empty_ctxt(Symbol::gensym(&name)); let module = f.cx.item_mod(span, span, allocator_abi, Vec::new(), items); - let module = f.cx.monotonic_expander().fold_item(module).pop().unwrap(); + let module = f.cx.monotonic_expander().flat_map_item(module).pop().unwrap(); // Return the item and new submodule smallvec![item, module] } // If we enter a submodule, take note. - fn fold_mod(&mut self, m: Mod) -> Mod { + fn visit_mod(&mut self, m: &mut Mod) { debug!("enter submodule"); self.in_submod += 1; - let ret = fold::noop_fold_mod(m, self); + mut_visit::noop_visit_mod(m, self); self.in_submod -= 1; debug!("exit submodule"); - ret } - // `fold_mac` is disabled by default. Enable it here. - fn fold_mac(&mut self, mac: Mac) -> Mac { - fold::noop_fold_mac(mac, self) + // `visit_mac` is disabled by default. Enable it here. + fn visit_mac(&mut self, mac: &mut Mac) { + mut_visit::noop_visit_mac(mac, self) } } @@ -169,7 +170,7 @@ struct AllocFnFactory<'a> { cx: ExtCtxt<'a>, } -impl<'a> AllocFnFactory<'a> { +impl AllocFnFactory<'_> { fn allocator_fn(&self, method: &AllocatorMethod) -> P { let mut abi_args = Vec::new(); let mut i = 0; diff --git a/src/librustc_allocator/lib.rs b/src/librustc_allocator/lib.rs index 41c0be615956e..9d6e728e13557 100644 --- a/src/librustc_allocator/lib.rs +++ b/src/librustc_allocator/lib.rs @@ -1,15 +1,7 @@ #![feature(nll)] #![feature(rustc_private)] -#[macro_use] extern crate log; -extern crate rustc; -extern crate rustc_data_structures; -extern crate rustc_errors; -extern crate rustc_target; -extern crate syntax; -extern crate syntax_pos; -#[macro_use] -extern crate smallvec; +#![deny(rust_2018_idioms)] pub mod expand; diff --git a/src/librustc_apfloat/Cargo.toml b/src/librustc_apfloat/Cargo.toml index 248f2d71f41e5..c7496a9547ea6 100644 --- a/src/librustc_apfloat/Cargo.toml +++ b/src/librustc_apfloat/Cargo.toml @@ -2,6 +2,7 @@ authors = ["The Rust Project Developers"] name = "rustc_apfloat" version = "0.0.0" +edition = "2018" [lib] name = "rustc_apfloat" diff --git a/src/librustc_apfloat/ieee.rs b/src/librustc_apfloat/ieee.rs index 7ad34bec899f4..9f68d770b9e87 100644 --- a/src/librustc_apfloat/ieee.rs +++ b/src/librustc_apfloat/ieee.rs @@ -1,5 +1,5 @@ -use {Category, ExpInt, IEK_INF, IEK_NAN, IEK_ZERO}; -use {Float, FloatConvert, ParseError, Round, Status, StatusAnd}; +use crate::{Category, ExpInt, IEK_INF, IEK_NAN, IEK_ZERO}; +use crate::{Float, FloatConvert, ParseError, Round, Status, StatusAnd}; use smallvec::{SmallVec, smallvec}; use std::cmp::{self, Ordering}; @@ -186,7 +186,7 @@ impl Semantics for X87DoubleExtendedS { /// exponent = all 1's, integer bit 0, significand 0 ("pseudoinfinity") /// exponent = all 1's, integer bit 0, significand nonzero ("pseudoNaN") /// exponent = 0, integer bit 1 ("pseudodenormal") - /// exponent!=0 nor all 1's, integer bit 0 ("unnormal") + /// exponent != 0 nor all 1's, integer bit 0 ("unnormal") /// At the moment, the first two are treated as NaNs, the second two as Normal. fn from_bits(bits: u128) -> IeeeFloat { let sign = bits & (1 << (Self::BITS - 1)); @@ -325,7 +325,7 @@ impl Neg for IeeeFloat { /// 1.01E-2 4 2 0.0101 /// 1.01E-2 4 1 1.01E-2 impl fmt::Display for IeeeFloat { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let width = f.width().unwrap_or(3); let alternate = f.alternate(); @@ -614,7 +614,7 @@ impl fmt::Display for IeeeFloat { } impl fmt::Debug for IeeeFloat { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}({:?} | {}{:?} * 2^{})", self, self.category, if self.sign { "-" } else { "+" }, @@ -1549,11 +1549,11 @@ impl IeeeFloat { } } - /// Returns TRUE if, when truncating the current number, with BIT the + /// Returns `true` if, when truncating the current number, with `bit` the /// new LSB, with the given lost fraction and rounding mode, the result /// would need to be rounded away from zero (i.e., by increasing the - /// signficand). This routine must work for Category::Zero of both signs, and - /// Category::Normal numbers. + /// signficand). This routine must work for `Category::Zero` of both signs, and + /// `Category::Normal` numbers. fn round_away_from_zero(&self, round: Round, loss: Loss, bit: usize) -> bool { // NaNs and infinities should not have lost fractions. assert!(self.is_finite_non_zero() || self.is_zero()); @@ -2257,7 +2257,7 @@ impl Loss { more_significant } - /// Return the fraction lost were a bignum truncated losing the least + /// Returns the fraction lost were a bignum truncated losing the least /// significant `bits` bits. fn through_truncation(limbs: &[Limb], bits: usize) -> Loss { if bits == 0 { @@ -2320,12 +2320,12 @@ mod sig { Ordering::Equal } - /// Extract the given bit. + /// Extracts the given bit. pub(super) fn get_bit(limbs: &[Limb], bit: usize) -> bool { limbs[bit / LIMB_BITS] & (1 << (bit % LIMB_BITS)) != 0 } - /// Set the given bit. + /// Sets the given bit. pub(super) fn set_bit(limbs: &mut [Limb], bit: usize) { limbs[bit / LIMB_BITS] |= 1 << (bit % LIMB_BITS); } @@ -2335,7 +2335,7 @@ mod sig { limbs[bit / LIMB_BITS] &= !(1 << (bit % LIMB_BITS)); } - /// Shift `dst` left `bits` bits, subtract `bits` from its exponent. + /// Shifts `dst` left `bits` bits, subtract `bits` from its exponent. pub(super) fn shift_left(dst: &mut [Limb], exp: &mut ExpInt, bits: usize) { if bits > 0 { // Our exponent should not underflow. @@ -2367,7 +2367,7 @@ mod sig { } } - /// Shift `dst` right `bits` bits noting lost fraction. + /// Shifts `dst` right `bits` bits noting lost fraction. pub(super) fn shift_right(dst: &mut [Limb], exp: &mut ExpInt, bits: usize) -> Loss { let loss = Loss::through_truncation(dst, bits); @@ -2403,7 +2403,7 @@ mod sig { loss } - /// Copy the bit vector of width `src_bits` from `src`, starting at bit SRC_LSB, + /// Copies the bit vector of width `src_bits` from `src`, starting at bit SRC_LSB, /// to `dst`, such that the bit SRC_LSB becomes the least significant bit of `dst`. /// All high bits above `src_bits` in `dst` are zero-filled. pub(super) fn extract(dst: &mut [Limb], src: &[Limb], src_bits: usize, src_lsb: usize) { diff --git a/src/librustc_apfloat/lib.rs b/src/librustc_apfloat/lib.rs index 6d2c54ca9ffe9..46d046d7b41b4 100644 --- a/src/librustc_apfloat/lib.rs +++ b/src/librustc_apfloat/lib.rs @@ -30,10 +30,9 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", - html_favicon_url = "https://doc.rust-lang.org/favicon.ico", - html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] #![forbid(unsafe_code)] +#![deny(rust_2018_idioms)] #![feature(nll)] #![feature(try_from)] @@ -41,17 +40,13 @@ #[allow(unused_extern_crates)] extern crate rustc_cratesio_shim; -#[macro_use] -extern crate bitflags; -extern crate smallvec; - use std::cmp::Ordering; use std::fmt; use std::ops::{Neg, Add, Sub, Mul, Div, Rem}; use std::ops::{AddAssign, SubAssign, MulAssign, DivAssign, RemAssign}; use std::str::FromStr; -bitflags! { +bitflags::bitflags! { /// IEEE-754R 7: Default exception handling. /// /// UNDERFLOW or OVERFLOW are always returned or-ed with INEXACT. @@ -380,7 +375,7 @@ pub trait Float fn from_str_r(s: &str, round: Round) -> Result, ParseError>; fn to_bits(self) -> u128; - /// Convert a floating point number to an integer according to the + /// Converts a floating point number to an integer according to the /// rounding mode. In case of an invalid operation exception, /// deterministic values are returned, namely zero for NaNs and the /// minimal or maximal value respectively for underflow or overflow. @@ -393,7 +388,7 @@ pub trait Float /// /// The *is_exact output tells whether the result is exact, in the sense /// that converting it back to the original floating point type produces - /// the original value. This is almost equivalent to result==Status::OK, + /// the original value. This is almost equivalent to `result == Status::OK`, /// except for negative zeroes. fn to_i128_r(self, width: usize, round: Round, is_exact: &mut bool) -> StatusAnd { let status; @@ -463,13 +458,13 @@ pub trait Float } } - /// IEEE-754R isSignMinus: Returns true if and only if the current value is + /// IEEE-754R isSignMinus: Returns whether the current value is /// negative. /// /// This applies to zeros and NaNs as well. fn is_negative(self) -> bool; - /// IEEE-754R isNormal: Returns true if and only if the current value is normal. + /// IEEE-754R isNormal: Returns whether the current value is normal. /// /// This implies that the current value of the float is not zero, subnormal, /// infinite, or NaN following the definition of normality from IEEE-754R. @@ -477,7 +472,7 @@ pub trait Float !self.is_denormal() && self.is_finite_non_zero() } - /// Returns true if and only if the current value is zero, subnormal, or + /// Returns `true` if the current value is zero, subnormal, or /// normal. /// /// This means that the value is not infinite or NaN. @@ -485,26 +480,26 @@ pub trait Float !self.is_nan() && !self.is_infinite() } - /// Returns true if and only if the float is plus or minus zero. + /// Returns `true` if the float is plus or minus zero. fn is_zero(self) -> bool { self.category() == Category::Zero } - /// IEEE-754R isSubnormal(): Returns true if and only if the float is a + /// IEEE-754R isSubnormal(): Returns whether the float is a /// denormal. fn is_denormal(self) -> bool; - /// IEEE-754R isInfinite(): Returns true if and only if the float is infinity. + /// IEEE-754R isInfinite(): Returns whether the float is infinity. fn is_infinite(self) -> bool { self.category() == Category::Infinity } - /// Returns true if and only if the float is a quiet or signaling NaN. + /// Returns `true` if the float is a quiet or signaling NaN. fn is_nan(self) -> bool { self.category() == Category::NaN } - /// Returns true if and only if the float is a signaling NaN. + /// Returns `true` if the float is a signaling NaN. fn is_signaling(self) -> bool; // Simple Queries @@ -523,19 +518,19 @@ pub trait Float self.is_zero() && self.is_negative() } - /// Returns true if and only if the number has the smallest possible non-zero + /// Returns `true` if the number has the smallest possible non-zero /// magnitude in the current semantics. fn is_smallest(self) -> bool { Self::SMALLEST.copy_sign(self).bitwise_eq(self) } - /// Returns true if and only if the number has the largest possible finite + /// Returns `true` if the number has the largest possible finite /// magnitude in the current semantics. fn is_largest(self) -> bool { Self::largest().copy_sign(self).bitwise_eq(self) } - /// Returns true if and only if the number is an exact integer. + /// Returns `true` if the number is an exact integer. fn is_integer(self) -> bool { // This could be made more efficient; I'm going for obviously correct. if !self.is_finite() { @@ -577,11 +572,11 @@ pub trait Float } pub trait FloatConvert: Float { - /// Convert a value of one floating point type to another. + /// Converts a value of one floating point type to another. /// The return value corresponds to the IEEE754 exceptions. *loses_info /// records whether the transformation lost information, i.e., whether /// converting the result back to the original type will produce the - /// original value (this is almost the same as return value==Status::OK, + /// original value (this is almost the same as return `value == Status::OK`, /// but there are edge cases where this is not so). fn convert_r(self, round: Round, loses_info: &mut bool) -> StatusAnd; fn convert(self, loses_info: &mut bool) -> StatusAnd { diff --git a/src/librustc_apfloat/ppc.rs b/src/librustc_apfloat/ppc.rs index 839e88cf34039..ddccfd6ca623b 100644 --- a/src/librustc_apfloat/ppc.rs +++ b/src/librustc_apfloat/ppc.rs @@ -1,5 +1,5 @@ -use {Category, ExpInt, Float, FloatConvert, Round, ParseError, Status, StatusAnd}; -use ieee; +use crate::{Category, ExpInt, Float, FloatConvert, Round, ParseError, Status, StatusAnd}; +use crate::ieee; use std::cmp::Ordering; use std::fmt; @@ -124,7 +124,7 @@ impl Neg for DoubleFloat { } impl>> fmt::Display for DoubleFloat { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(&Fallback::from(*self), f) } } diff --git a/src/librustc_apfloat/tests/ieee.rs b/src/librustc_apfloat/tests/ieee.rs index 96249020c1a6f..108b2114439d4 100644 --- a/src/librustc_apfloat/tests/ieee.rs +++ b/src/librustc_apfloat/tests/ieee.rs @@ -1,9 +1,7 @@ -#[macro_use] -extern crate rustc_apfloat; - 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}; +use rustc_apfloat::unpack; trait SingleExt { fn from_f32(input: f32) -> Self; diff --git a/src/librustc_apfloat/tests/ppc.rs b/src/librustc_apfloat/tests/ppc.rs index cfb453bd0617a..02cdeb90a12be 100644 --- a/src/librustc_apfloat/tests/ppc.rs +++ b/src/librustc_apfloat/tests/ppc.rs @@ -1,5 +1,3 @@ -extern crate rustc_apfloat; - use rustc_apfloat::{Category, Float, Round}; use rustc_apfloat::ppc::DoubleDouble; diff --git a/src/librustc_asan/Cargo.toml b/src/librustc_asan/Cargo.toml index 836caf22abfa5..7d9641c83ee7d 100644 --- a/src/librustc_asan/Cargo.toml +++ b/src/librustc_asan/Cargo.toml @@ -3,6 +3,7 @@ authors = ["The Rust Project Developers"] build = "build.rs" name = "rustc_asan" version = "0.0.0" +edition = "2018" [lib] name = "rustc_asan" diff --git a/src/librustc_asan/build.rs b/src/librustc_asan/build.rs index 2d921b666944b..a2b4b090efb4f 100644 --- a/src/librustc_asan/build.rs +++ b/src/librustc_asan/build.rs @@ -1,6 +1,3 @@ -extern crate build_helper; -extern crate cmake; - use std::env; use build_helper::sanitizer_lib_boilerplate; @@ -8,6 +5,8 @@ use cmake::Config; fn main() { if let Some(llvm_config) = env::var_os("LLVM_CONFIG") { + build_helper::restore_library_path(); + let (native, target) = match sanitizer_lib_boilerplate("asan") { Ok(native) => native, _ => return, diff --git a/src/librustc_asan/lib.rs b/src/librustc_asan/lib.rs index d6c8e54c18db7..3bdb86d313dcb 100644 --- a/src/librustc_asan/lib.rs +++ b/src/librustc_asan/lib.rs @@ -6,3 +6,5 @@ #![unstable(feature = "sanitizer_runtime_lib", reason = "internal implementation detail of sanitizers", issue = "0")] + +#![deny(rust_2018_idioms)] diff --git a/src/librustc_borrowck/Cargo.toml b/src/librustc_borrowck/Cargo.toml index 3368bbf3855a5..f293739dec727 100644 --- a/src/librustc_borrowck/Cargo.toml +++ b/src/librustc_borrowck/Cargo.toml @@ -2,6 +2,7 @@ authors = ["The Rust Project Developers"] name = "rustc_borrowck" version = "0.0.0" +edition = "2018" [lib] name = "rustc_borrowck" @@ -13,8 +14,10 @@ test = false log = "0.4" syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } -graphviz = { path = "../libgraphviz" } +# for "clarity", rename the graphviz crate to dot; graphviz within `borrowck` +# refers to the borrowck-specific graphviz adapter traits. +dot = { path = "../libgraphviz", package = "graphviz" } rustc = { path = "../librustc" } rustc_mir = { path = "../librustc_mir" } -rustc_errors = { path = "../librustc_errors" } -rustc_data_structures = { path = "../librustc_data_structures" } \ No newline at end of file +errors = { path = "../librustc_errors", package = "rustc_errors" } +rustc_data_structures = { path = "../librustc_data_structures" } diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs index cafb29ed99a41..b528967dd65ff 100644 --- a/src/librustc_borrowck/borrowck/check_loans.rs +++ b/src/librustc_borrowck/borrowck/check_loans.rs @@ -7,10 +7,10 @@ // 3. assignments do not affect things loaned out as immutable // 4. moves do not affect things loaned out in any way -use self::UseError::*; +use UseError::*; -use borrowck::*; -use borrowck::InteriorKind::{InteriorElement, InteriorField}; +use crate::borrowck::*; +use crate::borrowck::InteriorKind::{InteriorElement, InteriorField}; use rustc::middle::expr_use_visitor as euv; use rustc::middle::expr_use_visitor::MutateMode; use rustc::middle::mem_categorization as mc; @@ -22,6 +22,7 @@ use syntax_pos::Span; use rustc::hir; use rustc::hir::Node; use rustc_mir::util::borrowck_errors::{BorrowckErrors, Origin}; +use log::debug; use std::rc::Rc; @@ -101,7 +102,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> { fn matched_pat(&mut self, _matched_pat: &hir::Pat, - _cmt: &mc::cmt_, + _cmt: &mc::cmt_<'_>, _mode: euv::MatchMode) { } fn consume_pat(&mut self, @@ -238,7 +239,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { { //! Iterates over each loan that has been issued //! on entrance to `node`, regardless of whether it is - //! actually *in scope* at that point. Sometimes loans + //! actually *in scope* at that point. Sometimes loans //! are issued for future scopes and thus they may have been //! *issued* but not yet be in effect. @@ -910,7 +911,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { pub fn report_illegal_mutation(&self, span: Span, loan_path: &LoanPath<'tcx>, - loan: &Loan) { + loan: &Loan<'_>) { self.bccx.cannot_assign_to_borrowed( span, loan.span, &self.bccx.loan_path_to_string(loan_path), Origin::Ast) .emit(); diff --git a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs index 72437e270b092..6b050fd9ba230 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs @@ -1,9 +1,9 @@ //! Computes moves. -use borrowck::*; -use borrowck::gather_loans::move_error::MovePlace; -use borrowck::gather_loans::move_error::{MoveError, MoveErrorCollector}; -use borrowck::move_data::*; +use crate::borrowck::*; +use crate::borrowck::gather_loans::move_error::MovePlace; +use crate::borrowck::gather_loans::move_error::{MoveError, MoveErrorCollector}; +use crate::borrowck::move_data::*; use rustc::middle::expr_use_visitor as euv; use rustc::middle::mem_categorization as mc; use rustc::middle::mem_categorization::Categorization; @@ -15,6 +15,7 @@ use syntax::ast; use syntax_pos::Span; use rustc::hir::*; use rustc::hir::Node; +use log::debug; struct GatherMoveInfo<'c, 'tcx: 'c> { id: hir::ItemLocalId, @@ -99,7 +100,7 @@ pub fn gather_move_from_pat<'a, 'c, 'tcx: 'c>(bccx: &BorrowckCtxt<'a, 'tcx>, 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, diff --git a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs index 8fc0a3d63384a..ae1d49afd4931 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs @@ -1,7 +1,7 @@ //! This module implements the check that the lifetime of a borrow //! does not exceed the lifetime of the value being borrowed. -use borrowck::*; +use crate::borrowck::*; use rustc::middle::expr_use_visitor as euv; use rustc::middle::mem_categorization as mc; use rustc::middle::mem_categorization::Categorization; @@ -10,6 +10,7 @@ use rustc::ty; use syntax::ast; use syntax_pos::Span; +use log::debug; type R = Result<(),()>; @@ -52,7 +53,7 @@ struct GuaranteeLifetimeContext<'a, 'tcx: 'a> { impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> { 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 + //! "guarantor". Reports an error if `self.loan_region` is //! larger than scope of `cmt`. debug!("guarantee_lifetime.check(cmt={:?}, loan_region={:?})", cmt, diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs index d681c771d2fa9..cf6053b71b6a8 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs @@ -6,8 +6,8 @@ // their associated scopes. In phase two, checking loans, we will then make // sure that all of these loans are honored. -use borrowck::*; -use borrowck::move_data::MoveData; +use crate::borrowck::*; +use crate::borrowck::move_data::MoveData; use rustc::middle::expr_use_visitor as euv; use rustc::middle::mem_categorization as mc; use rustc::middle::mem_categorization::Categorization; @@ -17,8 +17,9 @@ use rustc::ty::{self, TyCtxt}; use syntax::ast; use syntax_pos::Span; use rustc::hir; +use log::debug; -use self::restrictions::RestrictionResult; +use restrictions::RestrictionResult; mod lifetime; mod restrictions; @@ -148,7 +149,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for GatherLoanCtxt<'a, 'tcx> { fn decl_without_init(&mut self, id: ast::NodeId, _span: Span) { let ty = self.bccx .tables - .node_id_to_type(self.bccx.tcx.hir().node_to_hir_id(id)); + .node_type(self.bccx.tcx.hir().node_to_hir_id(id)); gather_moves::gather_decl(self.bccx, &self.move_data, id, ty); } } @@ -284,7 +285,7 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> { } /// Guarantees that `addr_of(cmt)` will be valid for the duration of `static_scope_r`, or - /// reports an error. This may entail taking out loans, which will be added to the + /// reports an error. This may entail taking out loans, which will be added to the /// `req_loan_map`. fn guarantee_valid(&mut self, borrow_id: hir::ItemLocalId, @@ -427,7 +428,7 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> { // } } - pub fn mark_loan_path_as_mutated(&self, loan_path: &LoanPath) { + pub fn mark_loan_path_as_mutated(&self, loan_path: &LoanPath<'_>) { //! For mutable loans of content whose mutability derives //! from a local variable, mark the mutability decl as necessary. diff --git a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs index 588b2344a18e0..622dd8e891ac7 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs @@ -1,4 +1,4 @@ -use borrowck::BorrowckCtxt; +use crate::borrowck::BorrowckCtxt; use rustc::middle::mem_categorization as mc; use rustc::middle::mem_categorization::Categorization; use rustc::middle::mem_categorization::NoteClosureEnv; @@ -8,7 +8,8 @@ use rustc_mir::util::borrowck_errors::{BorrowckErrors, Origin}; use syntax::ast; use syntax_pos; use errors::{DiagnosticBuilder, Applicability}; -use borrowck::gather_loans::gather_moves::PatternSource; +use crate::borrowck::gather_loans::gather_moves::PatternSource; +use log::debug; pub struct MoveErrorCollector<'tcx> { errors: Vec> @@ -70,7 +71,7 @@ fn report_move_errors<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, errors: &[MoveErr let initializer = e.init.as_ref().expect("should have an initializer to get an error"); if let Ok(snippet) = bccx.tcx.sess.source_map().span_to_snippet(initializer.span) { - err.span_suggestion_with_applicability( + err.span_suggestion( initializer.span, "consider using a reference instead", format!("&{}", snippet), @@ -167,10 +168,10 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &'a BorrowckCtxt<'a, 'tcx>, } } -fn note_move_destination(mut err: DiagnosticBuilder, +fn note_move_destination(mut err: DiagnosticBuilder<'_>, move_to_span: syntax_pos::Span, pat_name: ast::Name, - is_first_note: bool) -> DiagnosticBuilder { + is_first_note: bool) -> DiagnosticBuilder<'_> { if is_first_note { err.span_label( move_to_span, diff --git a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs index a43a7f1e09ae1..9f4c05a6b255f 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs @@ -1,13 +1,14 @@ //! Computes the restrictions that result from a borrow. -use borrowck::*; +use crate::borrowck::*; use rustc::middle::expr_use_visitor as euv; use rustc::middle::mem_categorization as mc; use rustc::middle::mem_categorization::Categorization; use rustc::ty; use syntax_pos::Span; +use log::debug; -use borrowck::ToInteriorKind; +use crate::borrowck::ToInteriorKind; use std::rc::Rc; diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 66303ab71b25f..307df16386639 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -2,13 +2,13 @@ #![allow(non_camel_case_types)] -pub use self::LoanPathKind::*; -pub use self::LoanPathElem::*; -pub use self::bckerr_code::*; -pub use self::AliasableViolationKind::*; -pub use self::MovedValueUseKind::*; +pub use LoanPathKind::*; +pub use LoanPathElem::*; +pub use bckerr_code::*; +pub use AliasableViolationKind::*; +pub use MovedValueUseKind::*; -use self::InteriorKind::*; +use InteriorKind::*; use rustc::hir::HirId; use rustc::hir::Node; @@ -37,11 +37,11 @@ use std::hash::{Hash, Hasher}; use syntax::ast; use syntax_pos::{MultiSpan, Span}; use errors::{Applicability, DiagnosticBuilder, DiagnosticId}; +use log::debug; use rustc::hir; -use rustc::hir::intravisit::{self, Visitor}; -use dataflow::{DataFlowContext, BitwiseOperator, DataFlowOperator, KillFrom}; +use crate::dataflow::{DataFlowContext, BitwiseOperator, DataFlowOperator, KillFrom}; pub mod check_loans; @@ -58,11 +58,11 @@ pub type LoanDataFlow<'a, 'tcx> = DataFlowContext<'a, 'tcx, LoanDataFlowOperator pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { tcx.par_body_owners(|body_owner_def_id| { - tcx.borrowck(body_owner_def_id); + tcx.ensure().borrowck(body_owner_def_id); }); } -pub fn provide(providers: &mut Providers) { +pub fn provide(providers: &mut Providers<'_>) { *providers = Providers { borrowck, ..*providers @@ -122,7 +122,7 @@ fn borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, owner_def_id: DefId) // Note that `mir_validated` is a "stealable" result; the // thief, `optimized_mir()`, forces borrowck, so we know that // is not yet stolen. - ty::query::queries::mir_validated::ensure(tcx, owner_def_id); + tcx.ensure().mir_validated(owner_def_id); // option dance because you can't capture an uninitialized variable // by mut-ref. @@ -157,12 +157,6 @@ fn build_borrowck_dataflow_data<'a, 'c, 'tcx, F>(this: &mut BorrowckCtxt<'a, 'tc where F: FnOnce(&mut BorrowckCtxt<'a, 'tcx>) -> &'c cfg::CFG { // Check the body of fn items. - let tcx = this.tcx; - let id_range = { - let mut visitor = intravisit::IdRangeComputingVisitor::new(&tcx.hir()); - visitor.visit_body(this.body); - visitor.result() - }; let (all_loans, move_data) = gather_loans::gather_loans_in_fn(this, body_id); @@ -184,7 +178,6 @@ fn build_borrowck_dataflow_data<'a, 'c, 'tcx, F>(this: &mut BorrowckCtxt<'a, 'tc Some(this.body), cfg, LoanDataFlowOperator, - id_range, all_loans.len()); for (loan_idx, loan) in all_loans.iter().enumerate() { loan_dfcx.add_gen(loan.gen_scope.item_local_id(), loan_idx); @@ -198,7 +191,6 @@ fn build_borrowck_dataflow_data<'a, 'c, 'tcx, F>(this: &mut BorrowckCtxt<'a, 'tc let flowed_moves = move_data::FlowedMoveData::new(move_data, this, cfg, - id_range, this.body); Some(AnalysisData { all_loans, @@ -304,11 +296,11 @@ pub struct Loan<'tcx> { /// gen_scope indicates where loan is introduced. Typically the /// loan is introduced at the point of the borrow, but in some /// cases, notably method arguments, the loan may be introduced - /// only later, once it comes into scope. See also + /// only later, once it comes into scope. See also /// `GatherLoanCtxt::compute_gen_scope`. gen_scope: region::Scope, - /// kill_scope indicates when the loan goes out of scope. This is + /// kill_scope indicates when the loan goes out of scope. This is /// either when the lifetime expires or when the local variable /// which roots the loan-path goes out of scope, whichever happens /// faster. See also `GatherLoanCtxt::compute_kill_scope`. @@ -407,12 +399,12 @@ pub enum LoanPathElem<'tcx> { } fn closure_to_block(closure_id: LocalDefId, - tcx: TyCtxt) -> ast::NodeId { + tcx: TyCtxt<'_, '_, '_>) -> ast::NodeId { let closure_id = tcx.hir().local_def_id_to_node_id(closure_id); match tcx.hir().get(closure_id) { Node::Expr(expr) => match expr.node { hir::ExprKind::Closure(.., body_id, _, _) => { - body_id.node_id + tcx.hir().hir_to_node_id(body_id.hir_id) } _ => { bug!("encountered non-closure id: {}", closure_id) @@ -859,7 +851,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { }) = cmt.cat { db.note(fn_closure_msg); } else { - db.span_suggestion_with_applicability( + db.span_suggestion( sp, msg, suggestion, @@ -867,7 +859,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { ); } } else { - db.span_suggestion_with_applicability( + db.span_suggestion( sp, msg, suggestion, @@ -1223,8 +1215,8 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } fn note_immutability_blame(&self, - db: &mut DiagnosticBuilder, - blame: Option, + db: &mut DiagnosticBuilder<'_>, + blame: Option>, error_node_id: ast::NodeId) { match blame { None => {} @@ -1238,7 +1230,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { let let_span = self.tcx.hir().span(node_id); let suggestion = suggest_ref_mut(self.tcx, let_span); if let Some(replace_str) = suggestion { - db.span_suggestion_with_applicability( + db.span_suggestion( let_span, "use a mutable reference instead", replace_str, @@ -1280,7 +1272,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { // binding: either to make the binding mutable (if its type is // not a mutable reference) or to avoid borrowing altogether fn note_immutable_local(&self, - db: &mut DiagnosticBuilder, + db: &mut DiagnosticBuilder<'_>, borrowed_node_id: ast::NodeId, binding_node_id: ast::NodeId) { let let_span = self.tcx.hir().span(binding_node_id); @@ -1300,7 +1292,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); - db.span_suggestion_with_applicability( + db.span_suggestion( self.tcx.hir().span(borrow_expr_id), "consider removing the `&mut`, as it is an \ immutable binding to a mutable reference", @@ -1308,7 +1300,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { Applicability::MachineApplicable, ); } else { - db.span_suggestion_with_applicability( + db.span_suggestion( let_span, "make this binding mutable", format!("mut {}", snippet), @@ -1335,7 +1327,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { &cmt_path_or_string, capture_span, Origin::Ast) - .span_suggestion_with_applicability( + .span_suggestion( err.span, &format!("to force the closure to take ownership of {} \ (and any other referenced variables), \ @@ -1358,7 +1350,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } } - fn note_and_explain_mutbl_error(&self, db: &mut DiagnosticBuilder, err: &BckError<'a, 'tcx>, + fn note_and_explain_mutbl_error(&self, db: &mut DiagnosticBuilder<'_>, err: &BckError<'a, 'tcx>, error_span: &Span) { match err.cmt.note { mc::NoteClosureEnv(upvar_id) | mc::NoteUpvarRef(upvar_id) => { @@ -1496,7 +1488,7 @@ impl DataFlowOperator for LoanDataFlowOperator { } impl<'tcx> fmt::Debug for InteriorKind { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { InteriorField(mc::FieldIndex(_, info)) => write!(f, "{}", info), InteriorElement => write!(f, "[]"), @@ -1505,7 +1497,7 @@ impl<'tcx> fmt::Debug for InteriorKind { } impl<'tcx> fmt::Debug for Loan<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "Loan_{}({:?}, {:?}, {:?}-{:?}, {:?})", self.index, self.loan_path, @@ -1517,7 +1509,7 @@ impl<'tcx> fmt::Debug for Loan<'tcx> { } impl<'tcx> fmt::Debug for LoanPath<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.kind { LpVar(id) => { write!(f, "$({})", ty::tls::with(|tcx| tcx.hir().node_to_string(id))) @@ -1552,7 +1544,7 @@ impl<'tcx> fmt::Debug for LoanPath<'tcx> { } impl<'tcx> fmt::Display for LoanPath<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + 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))) diff --git a/src/librustc_borrowck/borrowck/move_data.rs b/src/librustc_borrowck/borrowck/move_data.rs index c5bee87e90fe4..325d3559f0ab6 100644 --- a/src/librustc_borrowck/borrowck/move_data.rs +++ b/src/librustc_borrowck/borrowck/move_data.rs @@ -1,11 +1,11 @@ //! Data structures used for tracking moves. Please see the extensive //! comments in the section "Moves and initialization" in `README.md`. -pub use self::MoveKind::*; +pub use MoveKind::*; -use dataflow::{DataFlowContext, BitwiseOperator, DataFlowOperator, KillFrom}; +use crate::dataflow::{DataFlowContext, BitwiseOperator, DataFlowOperator, KillFrom}; -use borrowck::*; +use crate::borrowck::*; use rustc::cfg; use rustc::ty::{self, TyCtxt}; use rustc::util::nodemap::FxHashMap; @@ -15,7 +15,7 @@ use std::rc::Rc; use std::usize; use syntax_pos::Span; use rustc::hir; -use rustc::hir::intravisit::IdRange; +use log::debug; #[derive(Default)] pub struct MoveData<'tcx> { @@ -114,7 +114,7 @@ pub struct Move { /// Path being moved. pub path: MovePathIndex, - /// id of node that is doing the move. + /// ID of node that is doing the move. pub id: hir::ItemLocalId, /// Kind of move, for error messages. @@ -129,7 +129,7 @@ pub struct Assignment { /// Path being assigned. pub path: MovePathIndex, - /// id where assignment occurs + /// ID where assignment occurs pub id: hir::ItemLocalId, /// span of node where assignment occurs @@ -146,7 +146,7 @@ pub struct AssignDataFlowOperator; pub type AssignDataFlow<'a, 'tcx> = DataFlowContext<'a, 'tcx, AssignDataFlowOperator>; -fn loan_path_is_precise(loan_path: &LoanPath) -> bool { +fn loan_path_is_precise(loan_path: &LoanPath<'_>) -> bool { match loan_path.kind { LpVar(_) | LpUpvar(_) => { true @@ -168,8 +168,8 @@ fn loan_path_is_precise(loan_path: &LoanPath) -> bool { } impl<'a, 'tcx> MoveData<'tcx> { - /// return true if there are no trackable assignments or moves - /// in this move data - that means that there is nothing that + /// 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. pub fn is_empty(&self) -> bool { self.moves.borrow().is_empty() && @@ -429,8 +429,8 @@ impl<'a, 'tcx> MoveData<'tcx> { /// 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) { + 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); } @@ -538,7 +538,7 @@ impl<'a, 'tcx> MoveData<'tcx> { path: MovePathIndex, kill_id: hir::ItemLocalId, kill_kind: KillFrom, - dfcx_moves: &mut MoveDataFlow) { + 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. @@ -559,7 +559,6 @@ impl<'a, 'tcx> FlowedMoveData<'a, 'tcx> { pub fn new(move_data: MoveData<'tcx>, bccx: &BorrowckCtxt<'a, 'tcx>, cfg: &cfg::CFG, - id_range: IdRange, body: &hir::Body) -> FlowedMoveData<'a, 'tcx> { let tcx = bccx.tcx; @@ -570,7 +569,6 @@ impl<'a, 'tcx> FlowedMoveData<'a, 'tcx> { Some(body), cfg, MoveDataFlowOperator, - id_range, move_data.moves.borrow().len()); let mut dfcx_assign = DataFlowContext::new(tcx, @@ -578,7 +576,6 @@ impl<'a, 'tcx> FlowedMoveData<'a, 'tcx> { Some(body), cfg, AssignDataFlowOperator, - id_range, move_data.var_assignments.borrow().len()); move_data.add_gen_kills(bccx, diff --git a/src/librustc_borrowck/borrowck/unused.rs b/src/librustc_borrowck/borrowck/unused.rs index 7340c7addb505..60a9c18e95ee9 100644 --- a/src/librustc_borrowck/borrowck/unused.rs +++ b/src/librustc_borrowck/borrowck/unused.rs @@ -7,7 +7,7 @@ use errors::Applicability; use std::slice; use syntax::ptr::P; -use borrowck::BorrowckCtxt; +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(); @@ -78,11 +78,12 @@ impl<'a, 'tcx> UnusedMutCx<'a, 'tcx> { hir_id, span, "variable does not need to be mutable") - .span_suggestion_short_with_applicability( + .span_suggestion_short( mut_span, "remove this `mut`", String::new(), - Applicability::MachineApplicable) + Applicability::MachineApplicable, + ) .emit(); } } diff --git a/src/librustc_borrowck/dataflow.rs b/src/librustc_borrowck/dataflow.rs index 56e25bd89c9ad..de2a3c4cb22a8 100644 --- a/src/librustc_borrowck/dataflow.rs +++ b/src/librustc_borrowck/dataflow.rs @@ -10,12 +10,13 @@ use std::io; use std::mem; use std::usize; use syntax::print::pprust::PrintState; +use log::debug; use rustc_data_structures::graph::implementation::OUTGOING; use rustc::util::nodemap::FxHashMap; use rustc::hir; -use rustc::hir::intravisit::{self, IdRange}; +use rustc::hir::intravisit; use rustc::hir::print as pprust; @@ -80,7 +81,7 @@ pub trait DataFlowOperator : BitwiseOperator { fn initial_value(&self) -> bool; } -struct PropagationContext<'a, 'b: 'a, 'tcx: 'b, O: 'a> { +struct PropagationContext<'a, 'b: 'a, 'tcx: 'b, O> { dfcx: &'a mut DataFlowContext<'b, 'tcx, O>, changed: bool } @@ -99,12 +100,12 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> { } impl<'a, 'tcx, O:DataFlowOperator> pprust::PpAnn for DataFlowContext<'a, 'tcx, O> { - fn nested(&self, state: &mut pprust::State, nested: pprust::Nested) -> io::Result<()> { + fn nested(&self, state: &mut pprust::State<'_>, nested: pprust::Nested) -> io::Result<()> { pprust::PpAnn::nested(self.tcx.hir(), state, nested) } fn pre(&self, - ps: &mut pprust::State, - node: pprust::AnnNode) -> io::Result<()> { + ps: &mut pprust::State<'_>, + node: pprust::AnnNode<'_>) -> io::Result<()> { let id = match node { pprust::AnnNode::Name(_) => return Ok(()), pprust::AnnNode::Expr(expr) => expr.hir_id.local_id, @@ -177,7 +178,7 @@ fn build_local_id_to_index(body: Option<&hir::Body>, return index; - /// Add mappings from the ast nodes for the formal bindings to + /// Adds mappings from the ast nodes for the formal bindings to /// the entry-node in the graph. fn add_entries_from_fn_body(index: &mut FxHashMap>, body: &hir::Body, @@ -230,16 +231,15 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> { body: Option<&hir::Body>, cfg: &cfg::CFG, oper: O, - id_range: IdRange, bits_per_id: usize) -> DataFlowContext<'a, '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(); - debug!("DataFlowContext::new(analysis_name: {}, id_range={:?}, \ + debug!("DataFlowContext::new(analysis_name: {}, \ bits_per_id={}, words_per_id={}) \ num_nodes: {}", - analysis_name, id_range, bits_per_id, words_per_id, + analysis_name, bits_per_id, words_per_id, num_nodes); let entry = if oper.initial_value() { usize::MAX } else {0}; diff --git a/src/librustc_borrowck/graphviz.rs b/src/librustc_borrowck/graphviz.rs index adad8c55f2159..77056d4d3eb15 100644 --- a/src/librustc_borrowck/graphviz.rs +++ b/src/librustc_borrowck/graphviz.rs @@ -2,16 +2,15 @@ //! libgraphviz traits, specialized to attaching borrowck analysis //! data to rendered labels. -pub use self::Variant::*; +pub use Variant::*; pub use rustc::cfg::graphviz::{Node, Edge}; use rustc::cfg::graphviz as cfg_dot; -use borrowck; -use borrowck::{BorrowckCtxt, LoanPath}; -use dot; +use crate::borrowck::{self, BorrowckCtxt, LoanPath}; +use crate::dataflow::{DataFlowOperator, DataFlowContext, EntryOrExit}; +use log::debug; use rustc::cfg::CFGIndex; -use dataflow::{DataFlowOperator, DataFlowContext, EntryOrExit}; use std::rc::Rc; #[derive(Debug, Copy, Clone)] @@ -53,7 +52,7 @@ impl<'a, 'tcx> DataflowLabeller<'a, 'tcx> { sets } - fn dataflow_for_variant(&self, e: EntryOrExit, n: &Node, v: Variant) -> String { + fn dataflow_for_variant(&self, e: EntryOrExit, n: &Node<'_>, v: Variant) -> String { let cfgidx = n.0; match v { Loans => self.dataflow_loans_for(e, cfgidx), @@ -89,7 +88,7 @@ impl<'a, 'tcx> DataflowLabeller<'a, 'tcx> { let dfcx = &self.analysis_data.loans; let loan_index_to_path = |loan_index| { let all_loans = &self.analysis_data.all_loans; - let l: &borrowck::Loan = &all_loans[loan_index]; + let l: &borrowck::Loan<'_> = &all_loans[loan_index]; l.loan_path() }; self.build_set(e, cfgidx, dfcx, loan_index_to_path) diff --git a/src/librustc_borrowck/lib.rs b/src/librustc_borrowck/lib.rs index 14e0381dad1a4..cf4669db87e5e 100644 --- a/src/librustc_borrowck/lib.rs +++ b/src/librustc_borrowck/lib.rs @@ -1,26 +1,14 @@ -#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", - html_favicon_url = "https://doc.rust-lang.org/favicon.ico", - html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] #![allow(non_camel_case_types)] +#![deny(rust_2018_idioms)] #![feature(nll)] -#![feature(quote)] #![recursion_limit="256"] -#[macro_use] extern crate log; -extern crate syntax; -extern crate syntax_pos; -extern crate rustc_errors as errors; -extern crate rustc_data_structures; - -// for "clarity", rename the graphviz crate to dot; graphviz within `borrowck` -// refers to the borrowck-specific graphviz adapter traits. -extern crate graphviz as dot; #[macro_use] extern crate rustc; -extern crate rustc_mir; pub use borrowck::check_crate; pub use borrowck::build_borrowck_dataflow_data_for_fn; diff --git a/src/librustc_codegen_llvm/Cargo.toml b/src/librustc_codegen_llvm/Cargo.toml index b711502b14b7f..841cf98164eb4 100644 --- a/src/librustc_codegen_llvm/Cargo.toml +++ b/src/librustc_codegen_llvm/Cargo.toml @@ -2,6 +2,7 @@ authors = ["The Rust Project Developers"] name = "rustc_codegen_llvm" version = "0.0.0" +edition = "2018" [lib] name = "rustc_codegen_llvm" @@ -10,7 +11,7 @@ crate-type = ["dylib"] test = false [dependencies] -cc = "1.0.1" +cc = "1.0.1" # Used to locate MSVC num_cpus = "1.0" rustc-demangle = "0.1.4" rustc_llvm = { path = "../librustc_llvm" } diff --git a/src/librustc_codegen_llvm/abi.rs b/src/librustc_codegen_llvm/abi.rs index 258d839d32e82..992149f7a47b5 100644 --- a/src/librustc_codegen_llvm/abi.rs +++ b/src/librustc_codegen_llvm/abi.rs @@ -1,12 +1,12 @@ -use llvm::{self, AttributePlace}; +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 rustc_codegen_ssa::MemFlags; -use builder::Builder; -use context::CodegenCx; use rustc_codegen_ssa::mir::place::PlaceRef; use rustc_codegen_ssa::mir::operand::OperandValue; -use type_::Type; -use type_of::{LayoutLlvmExt, PointerKind}; -use value::Value; use rustc_target::abi::call::ArgType; use rustc_codegen_ssa::traits::*; @@ -174,13 +174,13 @@ pub trait ArgTypeExt<'ll, 'tcx> { } impl ArgTypeExt<'ll, 'tcx> for ArgType<'tcx, Ty<'tcx>> { - /// Get the LLVM type for a place of the original Rust type of + /// Gets the LLVM type for a place of the original Rust type of /// this argument/return, i.e., the result of `type_of::type_of`. fn memory_ty(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type { self.layout.llvm_type(cx) } - /// Store a direct/indirect value described by this ArgType into a + /// Stores a direct/indirect value described by this ArgType into a /// place for the original Rust type of this argument/return. /// Can be used for both storing formal arguments into Rust variables /// or results of call/invoke instructions into their destinations. diff --git a/src/librustc_codegen_llvm/allocator.rs b/src/librustc_codegen_llvm/allocator.rs index 56bbaf55f75b4..7430cd3f70961 100644 --- a/src/librustc_codegen_llvm/allocator.rs +++ b/src/librustc_codegen_llvm/allocator.rs @@ -1,13 +1,13 @@ use std::ffi::CString; -use attributes; +use crate::attributes; use libc::c_uint; use rustc::middle::allocator::AllocatorKind; use rustc::ty::TyCtxt; use rustc_allocator::{ALLOCATOR_METHODS, AllocatorTy}; -use ModuleLlvm; -use llvm::{self, False, True}; +use crate::ModuleLlvm; +use crate::llvm::{self, False, True}; pub(crate) unsafe fn codegen(tcx: TyCtxt, mods: &ModuleLlvm, kind: AllocatorKind) { let llcx = &*mods.llcx; diff --git a/src/librustc_codegen_llvm/asm.rs b/src/librustc_codegen_llvm/asm.rs index 5c1a8b070c993..4427308f4155d 100644 --- a/src/librustc_codegen_llvm/asm.rs +++ b/src/librustc_codegen_llvm/asm.rs @@ -1,8 +1,8 @@ -use llvm; -use context::CodegenCx; -use type_of::LayoutLlvmExt; -use builder::Builder; -use value::Value; +use crate::llvm; +use crate::context::CodegenCx; +use crate::type_of::LayoutLlvmExt; +use crate::builder::Builder; +use crate::value::Value; use rustc::hir; use rustc_codegen_ssa::traits::*; diff --git a/src/librustc_codegen_llvm/attributes.rs b/src/librustc_codegen_llvm/attributes.rs index 226b03c99c043..827ebff10f51c 100644 --- a/src/librustc_codegen_llvm/attributes.rs +++ b/src/librustc_codegen_llvm/attributes.rs @@ -5,7 +5,7 @@ use std::ffi::CString; use rustc::hir::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use rustc::session::Session; -use rustc::session::config::Sanitizer; +use rustc::session::config::{Sanitizer, OptLevel}; use rustc::ty::{self, TyCtxt, PolyFnSig}; use rustc::ty::layout::HasTyCtxt; use rustc::ty::query::Providers; @@ -15,15 +15,15 @@ use rustc_data_structures::fx::FxHashMap; use rustc_target::spec::PanicStrategy; use rustc_codegen_ssa::traits::*; -use abi::Abi; -use attributes; -use llvm::{self, Attribute}; -use llvm::AttributePlace::Function; -use llvm_util; -pub use syntax::attr::{self, InlineAttr}; +use crate::abi::Abi; +use crate::attributes; +use crate::llvm::{self, Attribute}; +use crate::llvm::AttributePlace::Function; +use crate::llvm_util; +pub use syntax::attr::{self, InlineAttr, OptimizeAttr}; -use context::CodegenCx; -use value::Value; +use crate::context::CodegenCx; +use crate::value::Value; /// Mark LLVM function to use provided inline heuristic. #[inline] @@ -57,13 +57,6 @@ fn unwind(val: &'ll Value, can_unwind: bool) { Attribute::NoUnwind.toggle_llfn(Function, val, !can_unwind); } -/// Tell LLVM whether it should optimize function for size. -#[inline] -#[allow(dead_code)] // possibly useful function -pub fn set_optimize_for_size(val: &'ll Value, optimize: bool) { - Attribute::OptimizeForSize.toggle_llfn(Function, val, optimize); -} - /// Tell LLVM if this function should be 'naked', i.e., skip the epilogue and prologue. #[inline] pub fn naked(val: &'ll Value, is_naked: bool) { @@ -151,6 +144,28 @@ pub fn non_lazy_bind(sess: &Session, llfn: &'ll Value) { } } +pub(crate) fn default_optimisation_attrs(sess: &Session, llfn: &'ll Value) { + match sess.opts.optimize { + OptLevel::Size => { + llvm::Attribute::MinSize.unapply_llfn(Function, llfn); + llvm::Attribute::OptimizeForSize.apply_llfn(Function, llfn); + llvm::Attribute::OptimizeNone.unapply_llfn(Function, llfn); + }, + OptLevel::SizeMin => { + llvm::Attribute::MinSize.apply_llfn(Function, llfn); + llvm::Attribute::OptimizeForSize.apply_llfn(Function, llfn); + llvm::Attribute::OptimizeNone.unapply_llfn(Function, llfn); + } + OptLevel::No => { + llvm::Attribute::MinSize.unapply_llfn(Function, llfn); + llvm::Attribute::OptimizeForSize.unapply_llfn(Function, llfn); + llvm::Attribute::OptimizeNone.unapply_llfn(Function, llfn); + } + _ => {} + } +} + + /// Composite function which sets LLVM attributes for function depending on its AST (`#[attribute]`) /// attributes. pub fn from_fn_attrs( @@ -162,6 +177,22 @@ pub fn from_fn_attrs( let codegen_fn_attrs = id.map(|id| cx.tcx.codegen_fn_attrs(id)) .unwrap_or_else(|| CodegenFnAttrs::new()); + match codegen_fn_attrs.optimize { + OptimizeAttr::None => { + default_optimisation_attrs(cx.tcx.sess, llfn); + } + OptimizeAttr::Speed => { + llvm::Attribute::MinSize.unapply_llfn(Function, llfn); + llvm::Attribute::OptimizeForSize.unapply_llfn(Function, llfn); + llvm::Attribute::OptimizeNone.unapply_llfn(Function, llfn); + } + OptimizeAttr::Size => { + llvm::Attribute::MinSize.apply_llfn(Function, llfn); + llvm::Attribute::OptimizeForSize.apply_llfn(Function, llfn); + llvm::Attribute::OptimizeNone.unapply_llfn(Function, llfn); + } + } + inline(cx, llfn, codegen_fn_attrs.inline); // The `uwtable` attribute according to LLVM is: diff --git a/src/librustc_codegen_llvm/back/archive.rs b/src/librustc_codegen_llvm/back/archive.rs index 1cf150dad6025..1c090f1446965 100644 --- a/src/librustc_codegen_llvm/back/archive.rs +++ b/src/librustc_codegen_llvm/back/archive.rs @@ -7,12 +7,11 @@ use std::path::{Path, PathBuf}; use std::ptr; use std::str; -use back::bytecode::RLIB_BYTECODE_EXTENSION; +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 libc; -use llvm::archive_ro::{ArchiveRO, Child}; -use llvm::{self, ArchiveKind}; -use metadata::METADATA_FILENAME; use rustc::session::Session; pub struct ArchiveConfig<'a> { @@ -51,7 +50,7 @@ fn is_relevant_child(c: &Child) -> bool { } impl<'a> ArchiveBuilder<'a> { - /// Create a new static archive, ready for modifying the archive specified + /// Creates a new static archive, ready for modifying the archive specified /// by `config`. pub fn new(config: ArchiveConfig<'a>) -> ArchiveBuilder<'a> { ArchiveBuilder { diff --git a/src/librustc_codegen_llvm/back/link.rs b/src/librustc_codegen_llvm/back/link.rs index fc744201a332c..a3b34485715a7 100644 --- a/src/librustc_codegen_llvm/back/link.rs +++ b/src/librustc_codegen_llvm/back/link.rs @@ -1,13 +1,15 @@ -use back::wasm; 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 super::rpath::RPathConfig; -use super::rpath; -use metadata::METADATA_FILENAME; use rustc::session::config::{self, DebugInfo, OutputFilenames, OutputType, PrintRequest}; use rustc::session::config::{RUST_CGU_EXT, Lto, Sanitizer}; use rustc::session::filesearch; @@ -22,8 +24,6 @@ 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 context::get_reloc_model; -use llvm; use std::ascii; use std::char; @@ -42,7 +42,7 @@ pub use rustc_codegen_utils::link::{find_crate_name, filename_for_input, default out_filename, check_file_is_writeable}; -/// Perform the linkage portion of the compilation phase. This will generate all +/// 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, @@ -523,7 +523,7 @@ fn link_natively(sess: &Session, } { - let target_cpu = ::llvm_util::target_cpu(sess); + 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); @@ -857,7 +857,7 @@ fn link_args(cmd: &mut dyn Linker, codegen_results: &CodegenResults) { // Linker plugins should be specified early in the list of arguments - cmd.cross_lang_lto(); + cmd.linker_plugin_lto(); // The default library location, we need this to find the runtime. // The location of crates will be determined as needed. @@ -1491,7 +1491,7 @@ fn are_upstream_rust_objects_already_included(sess: &Session) -> bool { 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.debugging_opts.cross_lang_lto.enabled() + !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 5d5f1ceceb88c..944569c8b744b 100644 --- a/src/librustc_codegen_llvm/back/lto.rs +++ b/src/librustc_codegen_llvm/back/lto.rs @@ -1,12 +1,15 @@ -use back::bytecode::{DecodedBytecode, RLIB_BYTECODE_EXTENSION}; +use crate::back::bytecode::{DecodedBytecode, RLIB_BYTECODE_EXTENSION}; +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, pre_lto_bitcode_filename}; +use rustc_codegen_ssa::back::write::{ModuleConfig, CodegenContext, FatLTOInput}; use rustc_codegen_ssa::back::lto::{SerializedModule, LtoModuleCodegen, ThinShared, ThinModule}; use rustc_codegen_ssa::traits::*; -use back::write::{self, DiagnosticHandlers, with_llvm_pmb, save_temp_bitcode, get_llvm_opt_level}; use errors::{FatalError, Handler}; -use llvm::archive_ro::ArchiveRO; -use llvm::{self, True, False}; use rustc::dep_graph::WorkProduct; use rustc::dep_graph::cgu_reuse_tracker::CguReuse; use rustc::hir::def_id::LOCAL_CRATE; @@ -14,14 +17,9 @@ 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 time_graph::Timeline; -use {ModuleLlvm, LlvmCodegenBackend}; use rustc_codegen_ssa::{ModuleCodegen, ModuleKind}; -use libc; - use std::ffi::{CStr, CString}; -use std::fs; use std::ptr; use std::slice; use std::sync::Arc; @@ -133,7 +131,8 @@ fn prepare_lto(cgcx: &CodegenContext, /// Performs fat LTO by merging all modules into a single one and returning it /// for further optimization. pub(crate) fn run_fat(cgcx: &CodegenContext, - modules: Vec>, + modules: Vec>, + cached_modules: Vec<(SerializedModule, WorkProduct)>, timeline: &mut Timeline) -> Result, FatalError> { @@ -142,7 +141,15 @@ pub(crate) fn run_fat(cgcx: &CodegenContext, let symbol_white_list = symbol_white_list.iter() .map(|c| c.as_ptr()) .collect::>(); - fat_lto(cgcx, &diag_handler, modules, upstream_modules, &symbol_white_list, timeline) + fat_lto( + cgcx, + &diag_handler, + modules, + cached_modules, + upstream_modules, + &symbol_white_list, + timeline, + ) } /// Performs thin LTO by performing necessary global analysis and returning two @@ -159,7 +166,7 @@ pub(crate) fn run_thin(cgcx: &CodegenContext, let symbol_white_list = symbol_white_list.iter() .map(|c| c.as_ptr()) .collect::>(); - if cgcx.opts.debugging_opts.cross_lang_lto.enabled() { + if cgcx.opts.cg.linker_plugin_lto.enabled() { unreachable!("We should never reach this case if the LTO step \ is deferred to the linker"); } @@ -173,33 +180,17 @@ pub(crate) fn run_thin(cgcx: &CodegenContext, } pub(crate) fn prepare_thin( - cgcx: &CodegenContext, module: ModuleCodegen ) -> (String, ThinBuffer) { let name = module.name.clone(); let buffer = ThinBuffer::new(module.module_llvm.llmod()); - - // We emit the module after having serialized it into a ThinBuffer - // because only then it will contain the ThinLTO module summary. - if let Some(ref incr_comp_session_dir) = cgcx.incr_comp_session_dir { - if cgcx.config(module.kind).emit_pre_thin_lto_bc { - let path = incr_comp_session_dir - .join(pre_lto_bitcode_filename(&name)); - - fs::write(&path, buffer.data()).unwrap_or_else(|e| { - panic!("Error writing pre-lto-bitcode file `{}`: {}", - path.display(), - e); - }); - } - } - (name, buffer) } fn fat_lto(cgcx: &CodegenContext, diag_handler: &Handler, - mut modules: Vec>, + mut modules: Vec>, + cached_modules: Vec<(SerializedModule, WorkProduct)>, mut serialized_modules: Vec<(SerializedModule, CString)>, symbol_white_list: &[*const libc::c_char], timeline: &mut Timeline) @@ -216,8 +207,14 @@ fn fat_lto(cgcx: &CodegenContext, // file copy operations in the backend work correctly. The only other kind // of module here should be an allocator one, and if your crate is smaller // than the allocator module then the size doesn't really matter anyway. - let (_, costliest_module) = modules.iter() + let costliest_module = modules.iter() .enumerate() + .filter_map(|(i, module)| { + match module { + FatLTOInput::InMemory(m) => Some((i, m)), + FatLTOInput::Serialized { .. } => None, + } + }) .filter(|&(_, module)| module.kind == ModuleKind::Regular) .map(|(i, module)| { let cost = unsafe { @@ -225,9 +222,38 @@ fn fat_lto(cgcx: &CodegenContext, }; (cost, i) }) - .max() - .expect("must be codegen'ing at least one module"); - let module = modules.remove(costliest_module); + .max(); + + // If we found a costliest module, we're good to go. Otherwise all our + // inputs were serialized which could happen in the case, for example, that + // all our inputs were incrementally reread from the cache and we're just + // re-executing the LTO passes. If that's the case deserialize the first + // module and create a linker with it. + let module: ModuleCodegen = match costliest_module { + Some((_cost, i)) => { + match modules.remove(i) { + FatLTOInput::InMemory(m) => m, + FatLTOInput::Serialized { .. } => unreachable!(), + } + } + None => { + let pos = modules.iter().position(|m| { + match m { + FatLTOInput::InMemory(_) => false, + FatLTOInput::Serialized { .. } => true, + } + }).expect("must have at least one serialized module"); + let (name, buffer) = match modules.remove(pos) { + FatLTOInput::Serialized { name, buffer } => (name, buffer), + FatLTOInput::InMemory(_) => unreachable!(), + }; + ModuleCodegen { + module_llvm: ModuleLlvm::parse(cgcx, &name, &buffer, diag_handler)?, + name, + kind: ModuleKind::Regular, + } + } + }; let mut serialized_bitcode = Vec::new(); { let (llcx, llmod) = { @@ -247,10 +273,20 @@ fn fat_lto(cgcx: &CodegenContext, // way we know of to do that is to serialize them to a string and them parse // them later. Not great but hey, that's why it's "fat" LTO, right? serialized_modules.extend(modules.into_iter().map(|module| { - let buffer = ModuleBuffer::new(module.module_llvm.llmod()); - let llmod_id = CString::new(&module.name[..]).unwrap(); - - (SerializedModule::Local(buffer), llmod_id) + match module { + FatLTOInput::InMemory(module) => { + let buffer = ModuleBuffer::new(module.module_llvm.llmod()); + let llmod_id = CString::new(&module.name[..]).unwrap(); + (SerializedModule::Local(buffer), llmod_id) + } + FatLTOInput::Serialized { name, buffer } => { + let llmod_id = CString::new(name).unwrap(); + (SerializedModule::Local(buffer), llmod_id) + } + } + })); + serialized_modules.extend(cached_modules.into_iter().map(|(buffer, wp)| { + (buffer, CString::new(wp.cgu_name.clone()).unwrap()) })); // For all serialized bitcode files we parse them and link them in as we did @@ -532,7 +568,7 @@ pub(crate) fn run_pass_manager(cgcx: &CodegenContext, // Note that in general this shouldn't matter too much as you typically // only turn on ThinLTO when you're compiling with optimizations // otherwise. - let opt_level = config.opt_level.map(get_llvm_opt_level) + let opt_level = config.opt_level.map(|x| to_llvm_opt_settings(x).0) .unwrap_or(llvm::CodeGenOptLevel::None); let opt_level = match opt_level { llvm::CodeGenOptLevel::None => llvm::CodeGenOptLevel::Less, @@ -579,6 +615,16 @@ impl ModuleBuffer { llvm::LLVMRustModuleBufferCreate(m) }) } + + pub fn parse<'a>( + &self, + name: &str, + cx: &'a llvm::Context, + handler: &Handler, + ) -> Result<&'a llvm::Module, FatalError> { + let name = CString::new(name).unwrap(); + parse_module(cx, &name, self.data(), handler) + } } impl ModuleBufferMethods for ModuleBuffer { @@ -658,15 +704,12 @@ pub unsafe fn optimize_thin_module( // crates but for locally codegened modules we may be able to reuse // that LLVM Context and Module. let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names); - let llmod_raw = llvm::LLVMRustParseBitcodeForThinLTO( + let llmod_raw = parse_module( llcx, - thin_module.data().as_ptr(), - thin_module.data().len(), - thin_module.shared.module_names[thin_module.idx].as_ptr(), - ).ok_or_else(|| { - let msg = "failed to parse bitcode for thin LTO module"; - write::llvm_err(&diag_handler, msg) - })? as *const _; + &thin_module.shared.module_names[thin_module.idx], + thin_module.data(), + &diag_handler, + )? as *const _; let module = ModuleCodegen { module_llvm: ModuleLlvm { llmod_raw, @@ -791,7 +834,7 @@ impl ThinLTOImports { self.imports.get(llvm_module_name).map(|v| &v[..]).unwrap_or(&[]) } - /// Load the ThinLTO import map from ThinLTOData. + /// Loads the ThinLTO import map from ThinLTOData. unsafe fn from_thin_lto_data(data: *const llvm::ThinLTOData) -> ThinLTOImports { unsafe extern "C" fn imported_module_callback(payload: *mut libc::c_void, importing_module_name: *const libc::c_char, @@ -823,3 +866,22 @@ fn module_name_to_str(c_str: &CStr) -> &str { c_str.to_str().unwrap_or_else(|e| bug!("Encountered non-utf8 LLVM module name `{}`: {}", c_str.to_string_lossy(), e)) } + +fn parse_module<'a>( + cx: &'a llvm::Context, + name: &CStr, + data: &[u8], + diag_handler: &Handler, +) -> Result<&'a llvm::Module, FatalError> { + unsafe { + llvm::LLVMRustParseBitcodeForLTO( + cx, + data.as_ptr(), + data.len(), + name.as_ptr(), + ).ok_or_else(|| { + let msg = "failed to parse bitcode for LTO module"; + write::llvm_err(&diag_handler, msg) + }) + } +} diff --git a/src/librustc_codegen_llvm/back/rpath.rs b/src/librustc_codegen_llvm/back/rpath.rs index aeff23dec41bb..a5c828e089f39 100644 --- a/src/librustc_codegen_llvm/back/rpath.rs +++ b/src/librustc_codegen_llvm/back/rpath.rs @@ -101,9 +101,9 @@ fn get_rpath_relative_to_output(config: &mut RPathConfig, lib: &Path) -> String let cwd = env::current_dir().unwrap(); let mut lib = fs::canonicalize(&cwd.join(lib)).unwrap_or_else(|_| cwd.join(lib)); - lib.pop(); + lib.pop(); // strip filename let mut output = cwd.join(&config.out_filename); - output.pop(); + 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)); diff --git a/src/librustc_codegen_llvm/back/wasm.rs b/src/librustc_codegen_llvm/back/wasm.rs index 3501123a37f51..b403660fa512d 100644 --- a/src/librustc_codegen_llvm/back/wasm.rs +++ b/src/librustc_codegen_llvm/back/wasm.rs @@ -112,7 +112,7 @@ pub fn rewrite_imports(path: &Path, import_map: &FxHashMap) { } } -/// Add or augment the existing `producers` section to encode information about +/// Adds or augment the existing `producers` section to encode information about /// the Rust compiler used to produce the wasm file. pub fn add_producer_section( path: &Path, diff --git a/src/librustc_codegen_llvm/back/write.rs b/src/librustc_codegen_llvm/back/write.rs index c0a4f5aa44047..1b16080515235 100644 --- a/src/librustc_codegen_llvm/back/write.rs +++ b/src/librustc_codegen_llvm/back/write.rs @@ -1,26 +1,27 @@ -use attributes; -use back::bytecode::{self, RLIB_BYTECODE_EXTENSION}; -use back::lto::ThinBuffer; +use crate::attributes; +use crate::back::bytecode::{self, RLIB_BYTECODE_EXTENSION}; +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; +use crate::type_::Type; +use crate::context::{is_pie_binary, get_reloc_model}; +use crate::common; +use crate::LlvmCodegenBackend; use rustc_codegen_ssa::back::write::{CodegenContext, ModuleConfig, run_assembler}; use rustc_codegen_ssa::traits::*; -use base; -use consts; +use rustc::hir::def_id::LOCAL_CRATE; use rustc::session::config::{self, OutputType, Passes, Lto}; use rustc::session::Session; -use time_graph::Timeline; -use llvm::{self, DiagnosticInfo, PassManager, SMDiagnostic}; -use llvm_util; -use ModuleLlvm; +use rustc::ty::TyCtxt; use rustc_codegen_ssa::{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; -use errors::{self, Handler, FatalError}; -use type_::Type; -use context::{is_pie_binary, get_reloc_model}; -use common; -use LlvmCodegenBackend; -use rustc_demangle; +use errors::{Handler, FatalError}; use std::ffi::{CString, CStr}; use std::fs; @@ -81,42 +82,46 @@ pub fn write_output_file( } } -pub(crate) fn get_llvm_opt_level(optimize: config::OptLevel) -> llvm::CodeGenOptLevel { - match optimize { - config::OptLevel::No => llvm::CodeGenOptLevel::None, - config::OptLevel::Less => llvm::CodeGenOptLevel::Less, - config::OptLevel::Default => llvm::CodeGenOptLevel::Default, - config::OptLevel::Aggressive => llvm::CodeGenOptLevel::Aggressive, - _ => llvm::CodeGenOptLevel::Default, - } -} - -pub(crate) fn get_llvm_opt_size(optimize: config::OptLevel) -> llvm::CodeGenOptSize { - match optimize { - config::OptLevel::Size => llvm::CodeGenOptSizeDefault, - config::OptLevel::SizeMin => llvm::CodeGenOptSizeAggressive, - _ => llvm::CodeGenOptSizeNone, - } +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_target_machine( +pub fn create_informational_target_machine( sess: &Session, find_features: bool, ) -> &'static mut llvm::TargetMachine { - target_machine_factory(sess, find_features)().unwrap_or_else(|err| { + target_machine_factory(sess, config::OptLevel::No, find_features)().unwrap_or_else(|err| { llvm_err(sess.diagnostic(), &err).raise() }) } + +pub fn to_llvm_opt_settings(cfg: config::OptLevel) -> (llvm::CodeGenOptLevel, llvm::CodeGenOptSize) +{ + use self::config::OptLevel::*; + match cfg { + No => (llvm::CodeGenOptLevel::None, llvm::CodeGenOptSizeNone), + Less => (llvm::CodeGenOptLevel::Less, llvm::CodeGenOptSizeNone), + Default => (llvm::CodeGenOptLevel::Default, llvm::CodeGenOptSizeNone), + Aggressive => (llvm::CodeGenOptLevel::Aggressive, llvm::CodeGenOptSizeNone), + Size => (llvm::CodeGenOptLevel::Default, llvm::CodeGenOptSizeDefault), + SizeMin => (llvm::CodeGenOptLevel::Default, llvm::CodeGenOptSizeAggressive), + } +} + // 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. -pub fn target_machine_factory(sess: &Session, find_features: bool) +pub fn target_machine_factory(sess: &Session, optlvl: config::OptLevel, find_features: bool) -> Arc Result<&'static mut llvm::TargetMachine, String> + Send + Sync> { let reloc_model = get_reloc_model(sess); - let opt_level = get_llvm_opt_level(sess.opts.optimize); + let (opt_level, _) = to_llvm_opt_settings(optlvl); let use_softfp = sess.opts.cg.soft_float; let ffunction_sections = sess.target.target.options.function_sections; @@ -357,10 +362,10 @@ pub(crate) unsafe fn optimize(cgcx: &CodegenContext, if !config.no_prepopulate_passes { llvm::LLVMRustAddAnalysisPasses(tm, fpm, llmod); llvm::LLVMRustAddAnalysisPasses(tm, mpm, llmod); - let opt_level = config.opt_level.map(get_llvm_opt_level) + let opt_level = config.opt_level.map(|x| to_llvm_opt_settings(x).0) .unwrap_or(llvm::CodeGenOptLevel::None); let prepare_for_thin_lto = cgcx.lto == Lto::Thin || cgcx.lto == Lto::ThinLocal || - (cgcx.lto != Lto::Fat && cgcx.opts.debugging_opts.cross_lang_lto.enabled()); + (cgcx.lto != Lto::Fat && cgcx.opts.cg.linker_plugin_lto.enabled()); with_llvm_pmb(llmod, &config, opt_level, prepare_for_thin_lto, &mut |b| { llvm::LLVMPassManagerBuilderPopulateFunctionPassManager(b, fpm); llvm::LLVMPassManagerBuilderPopulateModulePassManager(b, mpm); @@ -689,7 +694,8 @@ pub unsafe fn with_llvm_pmb(llmod: &llvm::Module, // reasonable defaults and prepare it to actually populate the pass // manager. let builder = llvm::LLVMPassManagerBuilderCreate(); - let opt_size = config.opt_size.map(get_llvm_opt_size).unwrap_or(llvm::CodeGenOptSizeNone); + let opt_size = config.opt_size.map(|x| to_llvm_opt_settings(x).1) + .unwrap_or(llvm::CodeGenOptSizeNone); let inline_threshold = config.inline_threshold; let pgo_gen_path = config.pgo_gen.as_ref().map(|s| { diff --git a/src/librustc_codegen_llvm/base.rs b/src/librustc_codegen_llvm/base.rs index 6a0d5fa1e1fd8..33531bb69485b 100644 --- a/src/librustc_codegen_llvm/base.rs +++ b/src/librustc_codegen_llvm/base.rs @@ -7,28 +7,29 @@ //! //! Hopefully useful general knowledge about codegen: //! -//! * There's no way to find out the Ty type of a Value. Doing so -//! would be "trying to get the eggs out of an omelette" (credit: -//! pcwalton). You can, instead, find out its llvm::Type by calling val_ty, -//! 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. +//! * There's no way to find out the `Ty` type of a Value. Doing so +//! would be "trying to get the eggs out of an omelette" (credit: +//! pcwalton). You can, instead, find out its `llvm::Type` by calling `val_ty`, +//! 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 rustc_codegen_ssa::{ModuleCodegen, ModuleKind}; use rustc_codegen_ssa::base::maybe_create_entry_wrapper; use super::LlvmCodegenBackend; -use llvm; -use metadata; +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::middle::cstore::{EncodedMetadata}; use rustc::ty::TyCtxt; use rustc::middle::exported_symbols; use rustc::session::config::{self, DebugInfo}; -use builder::Builder; -use common; -use context::CodegenCx; -use monomorphize::partitioning::CodegenUnitExt; use rustc_codegen_ssa::mono_item::MonoItemExt; use rustc_data_structures::small_c_str::SmallCStr; @@ -40,7 +41,7 @@ use std::time::Instant; use syntax_pos::symbol::InternedString; use rustc::hir::CodegenFnAttrs; -use value::Value; +use crate::value::Value; pub fn write_metadata<'a, 'gcx>( @@ -136,7 +137,7 @@ pub fn iter_globals(llmod: &'ll llvm::Module) -> ValueIter<'ll> { } } -pub fn compile_codegen_unit<'ll, 'tcx>(tcx: TyCtxt<'ll, 'tcx, 'tcx>, +pub fn compile_codegen_unit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, cgu_name: InternedString) -> Stats { let start_time = Instant::now(); @@ -145,7 +146,8 @@ pub fn compile_codegen_unit<'ll, 'tcx>(tcx: TyCtxt<'ll, 'tcx, 'tcx>, let ((stats, module), _) = tcx.dep_graph.with_task(dep_node, tcx, cgu_name, - module_codegen); + 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 @@ -164,7 +166,7 @@ pub fn compile_codegen_unit<'ll, 'tcx>(tcx: TyCtxt<'ll, 'tcx, 'tcx>, let backend = LlvmCodegenBackend(()); let cgu = tcx.codegen_unit(cgu_name); // Instantiate monomorphizations without filling out definitions yet... - let llvm_module = backend.new_metadata(tcx.sess, &cgu_name.as_str()); + let llvm_module = backend.new_metadata(tcx, &cgu_name.as_str()); let stats = { let cx = CodegenCx::new(tcx, cgu, &llvm_module); let mono_items = cx.codegen_unit diff --git a/src/librustc_codegen_llvm/builder.rs b/src/librustc_codegen_llvm/builder.rs index b79d0da0bcd06..39c8f8a09400b 100644 --- a/src/librustc_codegen_llvm/builder.rs +++ b/src/librustc_codegen_llvm/builder.rs @@ -1,12 +1,12 @@ -use llvm::{AtomicRmwBinOp, AtomicOrdering, SynchronizationScope, AsmDialect}; -use llvm::{self, False, BasicBlock}; +use crate::llvm::{AtomicRmwBinOp, AtomicOrdering, SynchronizationScope, AsmDialect}; +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 rustc_codegen_ssa::common::{IntPredicate, TypeKind, RealPredicate}; -use rustc_codegen_ssa::{self, MemFlags}; -use common::Funclet; -use context::CodegenCx; -use type_::Type; -use type_of::LayoutLlvmExt; -use value::Value; +use rustc_codegen_ssa::MemFlags; use libc::{c_uint, c_char}; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::layout::{self, Align, Size, TyLayout}; @@ -14,7 +14,6 @@ use rustc::hir::def_id::DefId; use rustc::session::config; use rustc_data_structures::small_c_str::SmallCStr; use rustc_codegen_ssa::traits::*; -use syntax; use rustc_codegen_ssa::base::to_immediate; use rustc_codegen_ssa::mir::operand::{OperandValue, OperandRef}; use rustc_codegen_ssa::mir::place::PlaceRef; diff --git a/src/librustc_codegen_llvm/callee.rs b/src/librustc_codegen_llvm/callee.rs index 0d9d6aa5aa20f..43a5767e5c68d 100644 --- a/src/librustc_codegen_llvm/callee.rs +++ b/src/librustc_codegen_llvm/callee.rs @@ -1,14 +1,14 @@ //! Handles codegen of callees as well as other call-related -//! things. Callees are a superset of normal rust values and sometimes -//! have different representations. In particular, top-level fn items +//! things. Callees are a superset of normal rust values and sometimes +//! have different representations. In particular, top-level fn items //! and methods are represented as just a fn ptr and not a full //! closure. -use attributes; -use llvm; -use monomorphize::Instance; -use context::CodegenCx; -use value::Value; +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; diff --git a/src/librustc_codegen_llvm/common.rs b/src/librustc_codegen_llvm/common.rs index 675d6ccb5041d..4bd036ea3b17a 100644 --- a/src/librustc_codegen_llvm/common.rs +++ b/src/librustc_codegen_llvm/common.rs @@ -2,17 +2,17 @@ //! Code that is useful in various codegen modules. -use llvm::{self, True, False, Bool, BasicBlock, OperandBundleDef}; -use abi; -use consts; -use type_::Type; -use type_of::LayoutLlvmExt; -use value::Value; +use crate::llvm::{self, True, False, Bool, BasicBlock, OperandBundleDef}; +use crate::abi; +use crate::consts; +use crate::type_::Type; +use crate::type_of::LayoutLlvmExt; +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 consts::const_alloc_to_llvm; use rustc_codegen_ssa::mir::place::PlaceRef; use libc::{c_uint, c_char}; @@ -20,7 +20,7 @@ use libc::{c_uint, c_char}; use syntax::symbol::LocalInternedString; use syntax::ast::Mutability; -pub use context::CodegenCx; +pub use crate::context::CodegenCx; /* * A note on nomenclature of linking: "extern", "foreign", and "upcall". diff --git a/src/librustc_codegen_llvm/consts.rs b/src/librustc_codegen_llvm/consts.rs index b7a9382c338bd..6232d44df5e4e 100644 --- a/src/librustc_codegen_llvm/consts.rs +++ b/src/librustc_codegen_llvm/consts.rs @@ -1,20 +1,20 @@ +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; +use crate::value::Value; use libc::c_uint; -use llvm::{self, SetUnnamedAddr, True}; use rustc::hir::def_id::DefId; use rustc::mir::interpret::{ConstValue, Allocation, read_target_uint, Pointer, ErrorHandled, GlobalId}; use rustc::hir::Node; -use debuginfo; -use monomorphize::MonoItem; -use common::CodegenCx; -use monomorphize::Instance; use syntax_pos::Span; use rustc_target::abi::HasDataLayout; use syntax_pos::symbol::LocalInternedString; -use base; -use type_::Type; -use type_of::LayoutLlvmExt; -use value::Value; use rustc::ty::{self, Ty}; use rustc_codegen_ssa::traits::*; @@ -275,12 +275,12 @@ impl CodegenCx<'ll, 'tcx> { self.use_dll_storage_attrs && !self.tcx.is_foreign_item(def_id) && // ThinLTO can't handle this workaround in all cases, so we don't // emit the attrs. Instead we make them unnecessary by disallowing - // dynamic linking when cross-language LTO is enabled. - !self.tcx.sess.opts.debugging_opts.cross_lang_lto.enabled(); + // dynamic linking when linker plugin based LTO is enabled. + !self.tcx.sess.opts.cg.linker_plugin_lto.enabled(); // If this assertion triggers, there's something wrong with commandline // argument validation. - debug_assert!(!(self.tcx.sess.opts.debugging_opts.cross_lang_lto.enabled() && + debug_assert!(!(self.tcx.sess.opts.cg.linker_plugin_lto.enabled() && self.tcx.sess.target.target.options.is_like_msvc && self.tcx.sess.opts.cg.prefer_dynamic)); diff --git a/src/librustc_codegen_llvm/context.rs b/src/librustc_codegen_llvm/context.rs index 2b03e99161db8..d9c4d22b41100 100644 --- a/src/librustc_codegen_llvm/context.rs +++ b/src/librustc_codegen_llvm/context.rs @@ -1,14 +1,14 @@ -use attributes; -use llvm; +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 debuginfo; -use monomorphize::Instance; -use value::Value; -use monomorphize::partitioning::CodegenUnit; -use type_::Type; -use type_of::PointeeInfo; +use crate::monomorphize::partitioning::CodegenUnit; +use crate::type_::Type; +use crate::type_of::PointeeInfo; use rustc_codegen_ssa::traits::*; use libc::c_uint; @@ -23,7 +23,7 @@ use rustc::util::nodemap::FxHashMap; use rustc_target::spec::{HasTargetSpec, Target}; use rustc_codegen_ssa::callee::resolve_and_get_fn; use rustc_codegen_ssa::base::wants_msvc_seh; -use callee::get_fn; +use crate::callee::get_fn; use std::ffi::CStr; use std::cell::{Cell, RefCell}; @@ -31,7 +31,7 @@ use std::iter; use std::str; use std::sync::Arc; use syntax::symbol::LocalInternedString; -use abi::Abi; +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. @@ -75,7 +75,7 @@ pub struct CodegenCx<'ll, 'tcx: 'll> { pub statics_to_rauw: RefCell>, /// Statics that will be placed in the llvm.used variable - /// See http://llvm.org/docs/LangRef.html#the-llvm-used-global-variable for details + /// See for details pub used_statics: RefCell>, pub lltypes: RefCell, Option), &'ll Type>>, @@ -103,7 +103,7 @@ pub fn get_reloc_model(sess: &Session) -> llvm::RelocMode { None => &sess.target.target.options.relocation_model[..], }; - match ::back::write::RELOC_MODEL_ARGS.iter().find( + match crate::back::write::RELOC_MODEL_ARGS.iter().find( |&&arg| arg.0 == reloc_model_arg) { Some(x) => x.1, _ => { @@ -121,7 +121,7 @@ fn get_tls_model(sess: &Session) -> llvm::ThreadLocalMode { None => &sess.target.target.options.tls_model[..], }; - match ::back::write::TLS_MODEL_ARGS.iter().find( + match crate::back::write::TLS_MODEL_ARGS.iter().find( |&&arg| arg.0 == tls_model_arg) { Some(x) => x.1, _ => { @@ -144,16 +144,17 @@ pub fn is_pie_binary(sess: &Session) -> bool { } pub unsafe fn create_module( - sess: &Session, + tcx: TyCtxt, llcx: &'ll llvm::Context, mod_name: &str, ) -> &'ll llvm::Module { + let sess = tcx.sess; let mod_name = SmallCStr::new(mod_name); let llmod = llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx); // Ensure the data-layout values hardcoded remain the defaults. if sess.target.target.options.is_builtin { - let tm = ::back::write::create_target_machine(sess, false); + let tm = crate::back::write::create_target_machine(tcx, false); llvm::LLVMRustSetDataLayoutFromTargetMachine(llmod, tm); llvm::LLVMRustDisposeTargetMachine(tm); @@ -211,7 +212,7 @@ 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 ::ModuleLlvm) + 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` @@ -376,7 +377,7 @@ 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 attributes; + use crate::attributes; let unwresume = &self.eh_unwind_resume; if let Some(llfn) = unwresume.get() { return llfn; @@ -464,6 +465,20 @@ impl CodegenCx<'b, 'tcx> { self.declare_intrinsic(key).unwrap_or_else(|| bug!("unknown intrinsic '{}'", key)) } + fn insert_intrinsic( + &self, name: &'static str, args: Option<&[&'b llvm::Type]>, ret: &'b llvm::Type + ) -> &'b llvm::Value { + let fn_ty = if let Some(args) = args { + self.type_func(args, ret) + } else { + self.type_variadic_func(&[], ret) + }; + let f = self.declare_cfn(name, fn_ty); + llvm::SetUnnamedAddr(f, false); + self.intrinsics.borrow_mut().insert(name, f.clone()); + f + } + fn declare_intrinsic( &self, key: &str @@ -471,26 +486,17 @@ impl CodegenCx<'b, 'tcx> { macro_rules! ifn { ($name:expr, fn() -> $ret:expr) => ( if key == $name { - let f = self.declare_cfn($name, self.type_func(&[], $ret)); - llvm::SetUnnamedAddr(f, false); - self.intrinsics.borrow_mut().insert($name, f.clone()); - return Some(f); + return Some(self.insert_intrinsic($name, Some(&[]), $ret)); } ); ($name:expr, fn(...) -> $ret:expr) => ( if key == $name { - let f = self.declare_cfn($name, self.type_variadic_func(&[], $ret)); - llvm::SetUnnamedAddr(f, false); - self.intrinsics.borrow_mut().insert($name, f.clone()); - return Some(f); + return Some(self.insert_intrinsic($name, None, $ret)); } ); ($name:expr, fn($($arg:expr),*) -> $ret:expr) => ( if key == $name { - let f = self.declare_cfn($name, self.type_func(&[$($arg),*], $ret)); - llvm::SetUnnamedAddr(f, false); - self.intrinsics.borrow_mut().insert($name, f.clone()); - return Some(f); + return Some(self.insert_intrinsic($name, Some(&[$($arg),*]), $ret)); } ); } @@ -756,6 +762,30 @@ impl CodegenCx<'b, 'tcx> { ifn!("llvm.umul.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct!{t_i64, i1}); ifn!("llvm.umul.with.overflow.i128", fn(t_i128, t_i128) -> mk_struct!{t_i128, i1}); + ifn!("llvm.sadd.sat.i8", fn(t_i8, t_i8) -> t_i8); + ifn!("llvm.sadd.sat.i16", fn(t_i16, t_i16) -> t_i16); + ifn!("llvm.sadd.sat.i32", fn(t_i32, t_i32) -> t_i32); + ifn!("llvm.sadd.sat.i64", fn(t_i64, t_i64) -> t_i64); + ifn!("llvm.sadd.sat.i128", fn(t_i128, t_i128) -> t_i128); + + ifn!("llvm.uadd.sat.i8", fn(t_i8, t_i8) -> t_i8); + ifn!("llvm.uadd.sat.i16", fn(t_i16, t_i16) -> t_i16); + ifn!("llvm.uadd.sat.i32", fn(t_i32, t_i32) -> t_i32); + ifn!("llvm.uadd.sat.i64", fn(t_i64, t_i64) -> t_i64); + ifn!("llvm.uadd.sat.i128", fn(t_i128, t_i128) -> t_i128); + + ifn!("llvm.ssub.sat.i8", fn(t_i8, t_i8) -> t_i8); + ifn!("llvm.ssub.sat.i16", fn(t_i16, t_i16) -> t_i16); + ifn!("llvm.ssub.sat.i32", fn(t_i32, t_i32) -> t_i32); + ifn!("llvm.ssub.sat.i64", fn(t_i64, t_i64) -> t_i64); + ifn!("llvm.ssub.sat.i128", fn(t_i128, t_i128) -> t_i128); + + ifn!("llvm.usub.sat.i8", fn(t_i8, t_i8) -> t_i8); + ifn!("llvm.usub.sat.i16", fn(t_i16, t_i16) -> t_i16); + ifn!("llvm.usub.sat.i32", fn(t_i32, t_i32) -> t_i32); + ifn!("llvm.usub.sat.i64", fn(t_i64, t_i64) -> t_i64); + ifn!("llvm.usub.sat.i128", fn(t_i128, t_i128) -> t_i128); + ifn!("llvm.lifetime.start", fn(t_i64,i8p) -> void); ifn!("llvm.lifetime.end", fn(t_i64, i8p) -> void); @@ -782,7 +812,7 @@ impl CodegenCx<'b, 'tcx> { } impl<'b, 'tcx> CodegenCx<'b, 'tcx> { - /// Generate a new symbol name with the given prefix. This symbol name must + /// Generates a new symbol name with the given prefix. This symbol name must /// only be used for definitions with `internal` or `private` linkage. pub fn generate_local_symbol_name(&self, prefix: &str) -> String { let idx = self.local_gen_sym_counter.get(); diff --git a/src/librustc_codegen_llvm/debuginfo/create_scope_map.rs b/src/librustc_codegen_llvm/debuginfo/create_scope_map.rs index dbd821865f95f..3ba05bf1b5c91 100644 --- a/src/librustc_codegen_llvm/debuginfo/create_scope_map.rs +++ b/src/librustc_codegen_llvm/debuginfo/create_scope_map.rs @@ -2,9 +2,9 @@ use rustc_codegen_ssa::debuginfo::{FunctionDebugContext, FunctionDebugContextDat use super::metadata::file_metadata; use super::utils::{DIB, span_start}; -use llvm; -use llvm::debuginfo::{DIScope, DISubprogram}; -use common::CodegenCx; +use crate::llvm; +use crate::llvm::debuginfo::{DIScope, DISubprogram}; +use crate::common::CodegenCx; use rustc::mir::{Mir, SourceScope}; use libc::c_uint; @@ -16,7 +16,7 @@ use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use syntax_pos::BytePos; -/// Produce DIScope DIEs for each MIR Scope which has variables defined in it. +/// Produces DIScope DIEs for each MIR Scope which has variables defined in it. /// If debuginfo is disabled, the returned vector is empty. pub fn create_mir_scopes( cx: &CodegenCx<'ll, '_>, diff --git a/src/librustc_codegen_llvm/debuginfo/doc.rs b/src/librustc_codegen_llvm/debuginfo/doc.rs index a4acc58eca953..cf18b995b61da 100644 --- a/src/librustc_codegen_llvm/debuginfo/doc.rs +++ b/src/librustc_codegen_llvm/debuginfo/doc.rs @@ -160,7 +160,7 @@ //! //! This algorithm also provides a stable ID for types that are defined in one //! crate but instantiated from metadata within another crate. We just have to -//! take care to always map crate and node IDs back to the original crate +//! take care to always map crate and `NodeId`s back to the original crate //! context. //! //! As a side-effect these unique type IDs also help to solve a problem arising @@ -170,7 +170,7 @@ //! with different concrete substitutions for `'a`, and thus there will be N //! `Ty` instances for the type `Struct<'a>` even though it is not generic //! otherwise. Unfortunately this means that we cannot use `ty::type_id()` as -//! cheap identifier for type metadata---we have done this in the past, but it +//! cheap identifier for type metadata -- we have done this in the past, but it //! led to unnecessary metadata duplication in the best case and LLVM //! assertions in the worst. However, the unique type ID as described above //! *can* be used as identifier. Since it is comparatively expensive to diff --git a/src/librustc_codegen_llvm/debuginfo/gdb.rs b/src/librustc_codegen_llvm/debuginfo/gdb.rs index c883d6030951d..2555c92fb7c32 100644 --- a/src/librustc_codegen_llvm/debuginfo/gdb.rs +++ b/src/librustc_codegen_llvm/debuginfo/gdb.rs @@ -1,11 +1,11 @@ // .debug_gdb_scripts binary section. -use llvm; +use crate::llvm; -use common::CodegenCx; -use builder::Builder; +use crate::common::CodegenCx; +use crate::builder::Builder; +use crate::value::Value; use rustc::session::config::DebugInfo; -use value::Value; use rustc_codegen_ssa::traits::*; use syntax::attr; diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs index 6deedd0b5ea33..da9ff54b0626c 100644 --- a/src/librustc_codegen_llvm/debuginfo/metadata.rs +++ b/src/librustc_codegen_llvm/debuginfo/metadata.rs @@ -7,15 +7,16 @@ use super::utils::{debug_context, DIB, span_start, use super::namespace::mangled_name_of_instance; use super::type_names::compute_debuginfo_type_name; use super::{CrateDebugContext}; +use crate::abi; +use crate::value::Value; use rustc_codegen_ssa::traits::*; -use abi; -use value::Value; -use llvm; -use llvm::debuginfo::{DIArray, DIType, DIFile, DIScope, DIDescriptor, - DICompositeType, DILexicalBlock, DIFlags}; -use llvm_util; +use crate::llvm; +use crate::llvm::debuginfo::{DIArray, DIType, DIFile, DIScope, DIDescriptor, + DICompositeType, DILexicalBlock, DIFlags, DebugEmissionKind}; +use crate::llvm_util; +use crate::common::CodegenCx; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc::hir::CodegenFnAttrFlags; use rustc::hir::def::CtorKind; @@ -23,7 +24,6 @@ use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE}; use rustc::ich::NodeIdHashingMode; use rustc_data_structures::fingerprint::Fingerprint; use rustc::ty::Instance; -use common::CodegenCx; use rustc::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt}; use rustc::ty::layout::{self, Align, Integer, IntegerExt, LayoutOf, PrimitiveExt, Size, TyLayout}; @@ -846,6 +846,7 @@ 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); unsafe { let file_metadata = llvm::LLVMRustDIBuilderCreateFile( @@ -859,7 +860,8 @@ pub fn compile_unit_metadata(tcx: TyCtxt, tcx.sess.opts.optimize != config::OptLevel::No, flags.as_ptr() as *const _, 0, - split_name.as_ptr() as *const _); + split_name.as_ptr() as *const _, + kind); if tcx.sess.opts.debugging_opts.profile { let cu_desc_metadata = llvm::LLVMRustMetadataAsValue(debug_context.llcontext, @@ -1164,7 +1166,10 @@ 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. return cx.sess().target.target.options.is_like_msvc - || llvm_util::get_major_version() < 7; + // LLVM version 7 did not release with an important bug fix; + // but the required patch is in the LLVM 8. Rust LLVM reports + // 8 as well. + || llvm_util::get_major_version() < 8; } // Describes the members of an enum value: An enum is described as a union of diff --git a/src/librustc_codegen_llvm/debuginfo/mod.rs b/src/librustc_codegen_llvm/debuginfo/mod.rs index 2eab626ae8e6e..664ca2533878d 100644 --- a/src/librustc_codegen_llvm/debuginfo/mod.rs +++ b/src/librustc_codegen_llvm/debuginfo/mod.rs @@ -10,24 +10,24 @@ use self::type_names::compute_debuginfo_type_name; use self::metadata::{type_metadata, file_metadata, TypeMap}; use self::source_loc::InternalDebugLocation::{self, UnknownLocation}; -use llvm; -use llvm::debuginfo::{DIFile, DIType, DIScope, DIBuilder, DISubprogram, DIArray, DIFlags, - DILexicalBlock}; +use crate::llvm; +use crate::llvm::debuginfo::{DIFile, DIType, DIScope, DIBuilder, DISubprogram, DIArray, DIFlags, + DISPFlags, DILexicalBlock}; use rustc::hir::CodegenFnAttrFlags; -use rustc::hir::def_id::{DefId, CrateNum}; +use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE}; use rustc::ty::subst::{Substs, UnpackedKind}; -use abi::Abi; -use common::CodegenCx; -use builder::Builder; -use monomorphize::Instance; +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::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 value::Value; use rustc_codegen_ssa::debuginfo::{FunctionDebugContext, MirDebugScope, VariableAccess, VariableKind, FunctionDebugContextData}; @@ -102,7 +102,7 @@ impl<'a, 'tcx> CrateDebugContext<'a, 'tcx> { } } -/// Create any deferred debug metadata nodes +/// Creates any deferred debug metadata nodes pub fn finalize(cx: &CodegenCx) { if cx.dbg_cx.is_none() { return; @@ -283,16 +283,14 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { let linkage_name = mangled_name_of_instance(self, instance); let scope_line = span_start(self, span).line; - let is_local_to_unit = is_node_local_to_unit(self, def_id); let function_name = CString::new(name).unwrap(); let linkage_name = SmallCStr::new(&linkage_name.as_str()); let mut flags = DIFlags::FlagPrototyped; - let local_id = self.tcx().hir().as_local_node_id(def_id); - if let Some((id, _, _)) = *self.sess().entry_fn.borrow() { - if local_id == Some(id) { + if let Some((id, _)) = self.tcx.entry_fn(LOCAL_CRATE) { + if id == def_id { flags |= DIFlags::FlagMainSubprogram; } } @@ -301,6 +299,14 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { flags |= DIFlags::FlagNoReturn; } + let mut spflags = DISPFlags::SPFlagDefinition; + if is_node_local_to_unit(self, def_id) { + spflags |= DISPFlags::SPFlagLocalToUnit; + } + if self.sess().opts.optimize != config::OptLevel::No { + spflags |= DISPFlags::SPFlagOptimized; + } + let fn_metadata = unsafe { llvm::LLVMRustDIBuilderCreateFunction( DIB(self), @@ -310,11 +316,9 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { file_metadata, loc.line as c_uint, function_type_metadata, - is_local_to_unit, - true, scope_line as c_uint, flags, - self.sess().opts.optimize != config::OptLevel::No, + spflags, llfn, template_parameters, None) diff --git a/src/librustc_codegen_llvm/debuginfo/namespace.rs b/src/librustc_codegen_llvm/debuginfo/namespace.rs index 36188b8fc4797..f7c377adf3529 100644 --- a/src/librustc_codegen_llvm/debuginfo/namespace.rs +++ b/src/librustc_codegen_llvm/debuginfo/namespace.rs @@ -2,14 +2,14 @@ use super::metadata::{unknown_file_metadata, UNKNOWN_LINE_NUMBER}; use super::utils::{DIB, debug_context}; -use monomorphize::Instance; +use crate::monomorphize::Instance; use rustc::ty; -use llvm; -use llvm::debuginfo::DIScope; +use crate::llvm; +use crate::llvm::debuginfo::DIScope; +use crate::common::CodegenCx; use rustc::hir::def_id::DefId; use rustc::hir::map::DefPathData; -use common::CodegenCx; use rustc_data_structures::small_c_str::SmallCStr; diff --git a/src/librustc_codegen_llvm/debuginfo/source_loc.rs b/src/librustc_codegen_llvm/debuginfo/source_loc.rs index ccf56c11e735d..f7620e11c233d 100644 --- a/src/librustc_codegen_llvm/debuginfo/source_loc.rs +++ b/src/librustc_codegen_llvm/debuginfo/source_loc.rs @@ -4,9 +4,9 @@ use super::utils::{debug_context, span_start}; use super::metadata::UNKNOWN_COLUMN_NUMBER; use rustc_codegen_ssa::debuginfo::FunctionDebugContext; -use llvm; -use llvm::debuginfo::DIScope; -use builder::Builder; +use crate::llvm; +use crate::llvm::debuginfo::DIScope; +use crate::builder::Builder; use rustc_codegen_ssa::traits::*; use libc::c_uint; diff --git a/src/librustc_codegen_llvm/debuginfo/type_names.rs b/src/librustc_codegen_llvm/debuginfo/type_names.rs index 32432f7e4ec10..1697bb7b52dbd 100644 --- a/src/librustc_codegen_llvm/debuginfo/type_names.rs +++ b/src/librustc_codegen_llvm/debuginfo/type_names.rs @@ -1,6 +1,6 @@ // Type Names for Debug Info. -use common::CodegenCx; +use crate::common::CodegenCx; use rustc::hir::def_id::DefId; use rustc::ty::subst::Substs; use rustc::ty::{self, Ty}; @@ -125,7 +125,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, } let abi = sig.abi(); - if abi != ::abi::Abi::Rust { + if abi != crate::abi::Abi::Rust { output.push_str("extern \""); output.push_str(abi.name()); output.push_str("\" "); diff --git a/src/librustc_codegen_llvm/debuginfo/utils.rs b/src/librustc_codegen_llvm/debuginfo/utils.rs index 8b85df79d0484..e1b299df6c312 100644 --- a/src/librustc_codegen_llvm/debuginfo/utils.rs +++ b/src/librustc_codegen_llvm/debuginfo/utils.rs @@ -6,12 +6,12 @@ use super::namespace::item_namespace; use rustc::hir::def_id::DefId; use rustc::ty::DefIdTree; -use llvm; -use llvm::debuginfo::{DIScope, DIBuilder, DIDescriptor, DIArray}; -use common::{CodegenCx}; +use crate::llvm; +use crate::llvm::debuginfo::{DIScope, DIBuilder, DIDescriptor, DIArray}; +use crate::common::{CodegenCx}; use rustc_codegen_ssa::traits::*; -use syntax_pos::{self, Span}; +use syntax_pos::Span; pub fn is_node_local_to_unit(cx: &CodegenCx, def_id: DefId) -> bool { @@ -36,7 +36,7 @@ pub fn create_DIArray( }; } -/// Return syntax_pos::Loc corresponding to the beginning of the span +/// Returns syntax_pos::Loc corresponding to the beginning of the span pub fn span_start(cx: &CodegenCx, span: Span) -> syntax_pos::Loc { cx.sess().source_map().lookup_char_pos(span.lo()) } diff --git a/src/librustc_codegen_llvm/declare.rs b/src/librustc_codegen_llvm/declare.rs index aa2a0016b3e7a..3febcb019ce29 100644 --- a/src/librustc_codegen_llvm/declare.rs +++ b/src/librustc_codegen_llvm/declare.rs @@ -11,18 +11,18 @@ //! * Use define_* family of methods when you might be defining the Value. //! * When in doubt, define. -use llvm; -use llvm::AttributePlace::Function; +use crate::llvm; +use crate::llvm::AttributePlace::Function; +use crate::abi::{FnType, FnTypeExt}; +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::session::config::Sanitizer; use rustc_data_structures::small_c_str::SmallCStr; -use abi::{FnType, FnTypeExt}; -use attributes; -use context::CodegenCx; -use type_::Type; use rustc_codegen_ssa::traits::*; -use value::Value; /// Declare a function. /// @@ -65,19 +65,8 @@ fn declare_raw_fn( } } - match cx.tcx.sess.opts.cg.opt_level.as_ref().map(String::as_ref) { - Some("s") => { - llvm::Attribute::OptimizeForSize.apply_llfn(Function, llfn); - }, - Some("z") => { - llvm::Attribute::MinSize.apply_llfn(Function, llfn); - llvm::Attribute::OptimizeForSize.apply_llfn(Function, llfn); - }, - _ => {}, - } - + attributes::default_optimisation_attrs(cx.tcx.sess, llfn); attributes::non_lazy_bind(cx.sess(), llfn); - llfn } diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs index eeb6a64164e9c..3785e19af970f 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -1,26 +1,26 @@ #![allow(non_upper_case_globals)] -use attributes; -use llvm; -use llvm_util; -use abi::{Abi, FnType, LlvmType, PassMode}; +use crate::attributes; +use crate::llvm; +use crate::llvm_util; +use crate::abi::{Abi, FnType, LlvmType, PassMode}; +use crate::context::CodegenCx; +use crate::type_::Type; +use crate::type_of::LayoutLlvmExt; +use crate::builder::Builder; +use crate::value::Value; +use crate::va_arg::emit_va_arg; use rustc_codegen_ssa::MemFlags; use rustc_codegen_ssa::mir::place::PlaceRef; use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; use rustc_codegen_ssa::glue; use rustc_codegen_ssa::base::{to_immediate, wants_msvc_seh, compare_simd_types}; -use context::CodegenCx; -use type_::Type; -use type_of::LayoutLlvmExt; use rustc::ty::{self, Ty}; use rustc::ty::layout::{self, LayoutOf, HasTyCtxt, Primitive}; -use rustc_codegen_ssa::common::TypeKind; +use rustc_codegen_ssa::common::{IntPredicate, TypeKind}; use rustc::hir; use syntax::ast::{self, FloatTy}; use syntax::symbol::Symbol; -use builder::Builder; -use value::Value; -use va_arg::emit_va_arg; use rustc_codegen_ssa::traits::*; @@ -28,7 +28,7 @@ use rustc::session::Session; use syntax_pos::Span; use std::cmp::Ordering; -use std::iter; +use std::{iter, i128, u128}; fn get_simple_intrinsic(cx: &CodegenCx<'ll, '_>, name: &str) -> Option<&'ll Value> { let llvm_name = match name { @@ -192,8 +192,7 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { "size_of_val" => { let tp_ty = substs.type_at(0); if let OperandValue::Pair(_, meta) = args[0].val { - let (llsize, _) = - glue::size_and_align_of_dst(self, tp_ty, Some(meta)); + let (llsize, _) = glue::size_and_align_of_dst(self, tp_ty, Some(meta)); llsize } else { self.const_usize(self.size_of(tp_ty).bytes()) @@ -206,8 +205,7 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { "min_align_of_val" => { let tp_ty = substs.type_at(0); if let OperandValue::Pair(_, meta) = args[0].val { - let (_, llalign) = - glue::size_and_align_of_dst(self, tp_ty, Some(meta)); + let (_, llalign) = glue::size_and_align_of_dst(self, tp_ty, Some(meta)); llalign } else { self.const_usize(self.align_of(tp_ty).bytes()) @@ -342,7 +340,7 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { "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" | - "rotate_left" | "rotate_right" => { + "rotate_left" | "rotate_right" | "saturating_add" | "saturating_sub" => { let ty = arg_tys[0]; match int_type_width_signed(ty, self) { Some((width, signed)) => @@ -468,6 +466,44 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { self.or(shift1, shift2) } }, + "saturating_add" | "saturating_sub" => { + let is_add = name == "saturating_add"; + let lhs = args[0].immediate(); + let rhs = args[1].immediate(); + if llvm_util::get_major_version() >= 8 { + let llvm_name = &format!("llvm.{}{}.sat.i{}", + if signed { 's' } else { 'u' }, + if is_add { "add" } else { "sub" }, + width); + let llfn = self.get_intrinsic(llvm_name); + self.call(llfn, &[lhs, rhs], None) + } else { + let llvm_name = &format!("llvm.{}{}.with.overflow.i{}", + if signed { 's' } else { 'u' }, + if is_add { "add" } else { "sub" }, + width); + let llfn = self.get_intrinsic(llvm_name); + let pair = self.call(llfn, &[lhs, rhs], None); + let val = self.extract_value(pair, 0); + let overflow = self.extract_value(pair, 1); + let llty = self.type_ix(width); + + let limit = if signed { + let limit_lo = self.const_uint_big( + llty, (i128::MIN >> (128 - width)) as u128); + let limit_hi = self.const_uint_big( + llty, (i128::MAX >> (128 - width)) as u128); + let neg = self.icmp( + IntPredicate::IntSLT, val, self.const_uint(llty, 0)); + self.select(neg, limit_hi, limit_lo) + } else if is_add { + self.const_uint_big(llty, u128::MAX >> (128 - width)) + } else { + self.const_uint(llty, 0) + }; + self.select(overflow, limit, val) + } + }, _ => bug!(), }, None => { @@ -1167,6 +1203,52 @@ fn generic_simd_intrinsic( return Ok(bx.select(m_i1s, args[1].immediate(), args[2].immediate())); } + if name == "simd_bitmask" { + // The `fn simd_bitmask(vector) -> unsigned integer` intrinsic takes a + // vector mask and returns an unsigned integer containing the most + // significant bit (MSB) of each lane. + use rustc_target::abi::HasDataLayout; + + // If the vector has less than 8 lanes, an u8 is returned with zeroed + // trailing bits. + let expected_int_bits = in_len.max(8); + match ret_ty.sty { + ty::Uint(i) if i.bit_width() == Some(expected_int_bits) => (), + _ => return_error!( + "bitmask `{}`, expected `u{}`", + ret_ty, expected_int_bits + ), + } + + // Integer vector : + let (i_xn, in_elem_bitwidth) = match in_elem.sty { + ty::Int(i) => ( + args[0].immediate(), + i.bit_width().unwrap_or(bx.data_layout().pointer_size.bits() as _) + ), + ty::Uint(i) => ( + args[0].immediate(), + i.bit_width().unwrap_or(bx.data_layout().pointer_size.bits() as _) + ), + _ => return_error!( + "vector argument `{}`'s element type `{}`, expected integer element type", + in_ty, in_elem + ), + }; + + // Shift the MSB to the right by "in_elem_bitwidth - 1" into the first bit position. + let shift_indices = vec![ + bx.cx.const_int(bx.type_ix(in_elem_bitwidth as _), (in_elem_bitwidth - 1) as _); in_len + ]; + let i_xn_msb = bx.lshr(i_xn, bx.const_vector(shift_indices.as_slice())); + // Truncate vector to an + let i1xn = bx.trunc(i_xn_msb, bx.type_vector(bx.type_i1(), in_len as _)); + // Bitcast to iN: + let i_ = bx.bitcast(i1xn, bx.type_ix(in_len as _)); + // Zero-extend iN to the bitmask type: + return Ok(bx.zext(i_, bx.type_ix(expected_int_bits as _))); + } + fn simd_simple_float_intrinsic( name: &str, in_elem: &::rustc::ty::TyS, diff --git a/src/librustc_codegen_llvm/lib.rs b/src/librustc_codegen_llvm/lib.rs index 272f34b0b3f16..9219f42d69235 100644 --- a/src/librustc_codegen_llvm/lib.rs +++ b/src/librustc_codegen_llvm/lib.rs @@ -4,9 +4,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", - html_favicon_url = "https://doc.rust-lang.org/favicon.ico", - html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] #![feature(box_patterns)] #![feature(box_syntax)] @@ -17,14 +15,15 @@ #![allow(unused_attributes)] #![feature(libc)] #![feature(nll)] -#![feature(quote)] #![feature(range_contains)] #![feature(rustc_diagnostic_macros)] -#![feature(slice_sort_by_cached_key)] #![feature(optin_builtin_traits)] #![feature(concat_idents)] #![feature(link_args)] #![feature(static_nobundle)] +#![deny(rust_2018_idioms)] +#![allow(explicit_outlives_requirements)] +#![allow(elided_lifetimes_in_paths)] use back::write::create_target_machine; use syntax_pos::symbol::Symbol; @@ -33,16 +32,11 @@ extern crate flate2; #[macro_use] extern crate bitflags; extern crate libc; #[macro_use] extern crate rustc; -extern crate jobserver; -extern crate num_cpus; extern crate rustc_mir; extern crate rustc_allocator; -extern crate rustc_apfloat; extern crate rustc_target; #[macro_use] extern crate rustc_data_structures; -extern crate rustc_demangle; extern crate rustc_incremental; -extern crate rustc_llvm; extern crate rustc_codegen_utils; extern crate rustc_codegen_ssa; extern crate rustc_fs_util; @@ -52,12 +46,10 @@ extern crate rustc_fs_util; extern crate syntax_pos; extern crate rustc_errors as errors; extern crate serialize; -extern crate cc; // Used to locate MSVC extern crate tempfile; -extern crate memmap; use rustc_codegen_ssa::traits::*; -use rustc_codegen_ssa::back::write::{CodegenContext, ModuleConfig}; +use rustc_codegen_ssa::back::write::{CodegenContext, ModuleConfig, FatLTOInput}; use rustc_codegen_ssa::back::lto::{SerializedModule, LtoModuleCodegen, ThinModule}; use rustc_codegen_ssa::CompiledModule; use errors::{FatalError, Handler}; @@ -73,7 +65,7 @@ use rustc::dep_graph::DepGraph; use rustc::middle::allocator::AllocatorKind; use rustc::middle::cstore::{EncodedMetadata, MetadataLoader}; use rustc::session::{Session, CompileIncomplete}; -use rustc::session::config::{OutputFilenames, OutputType, PrintRequest}; +use rustc::session::config::{OutputFilenames, OutputType, PrintRequest, OptLevel}; use rustc::ty::{self, TyCtxt}; use rustc::util::time_graph; use rustc::util::profiling::ProfileCategory; @@ -122,8 +114,8 @@ mod va_arg; pub struct LlvmCodegenBackend(()); impl ExtraBackendMethods for LlvmCodegenBackend { - fn new_metadata(&self, sess: &Session, mod_name: &str) -> ModuleLlvm { - ModuleLlvm::new(sess, mod_name) + fn new_metadata(&self, tcx: TyCtxt, mod_name: &str) -> ModuleLlvm { + ModuleLlvm::new(tcx, mod_name) } fn write_metadata<'b, 'gcx>( &self, @@ -145,10 +137,11 @@ impl ExtraBackendMethods for LlvmCodegenBackend { fn target_machine_factory( &self, sess: &Session, + optlvl: OptLevel, find_features: bool ) -> Arc Result<&'static mut llvm::TargetMachine, String> + Send + Sync> { - back::write::target_machine_factory(sess, find_features) + back::write::target_machine_factory(sess, optlvl, find_features) } fn target_cpu<'b>(&self, sess: &'b Session) -> &'b str { llvm_util::target_cpu(sess) @@ -167,10 +160,11 @@ impl WriteBackendMethods for LlvmCodegenBackend { } fn run_fat_lto( cgcx: &CodegenContext, - modules: Vec>, + modules: Vec>, + cached_modules: Vec<(SerializedModule, WorkProduct)>, timeline: &mut Timeline ) -> Result, FatalError> { - back::lto::run_fat(cgcx, modules, timeline) + back::lto::run_fat(cgcx, modules, cached_modules, timeline) } fn run_thin_lto( cgcx: &CodegenContext, @@ -206,10 +200,14 @@ impl WriteBackendMethods for LlvmCodegenBackend { back::write::codegen(cgcx, diag_handler, module, config, timeline) } fn prepare_thin( - cgcx: &CodegenContext, module: ModuleCodegen ) -> (String, Self::ThinBuffer) { - back::lto::prepare_thin(cgcx, module) + back::lto::prepare_thin(module) + } + fn serialize_module( + module: ModuleCodegen + ) -> (String, Self::ModuleBuffer) { + (module.name, back::lto::ModuleBuffer::new(module.module_llvm.llmod())) } fn run_lto_pass_manager( cgcx: &CodegenContext, @@ -364,19 +362,44 @@ unsafe impl Send for ModuleLlvm { } unsafe impl Sync for ModuleLlvm { } impl ModuleLlvm { - fn new(sess: &Session, mod_name: &str) -> Self { + fn new(tcx: TyCtxt, mod_name: &str) -> Self { unsafe { - let llcx = llvm::LLVMRustContextCreate(sess.fewer_names()); - let llmod_raw = context::create_module(sess, llcx, mod_name) as *const _; + 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_target_machine(sess, false), + tm: create_target_machine(tcx, false), } } } + fn parse( + cgcx: &CodegenContext, + name: &str, + buffer: &back::lto::ModuleBuffer, + handler: &Handler, + ) -> Result { + unsafe { + let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names); + let llmod_raw = buffer.parse(name, llcx, handler)?; + let tm = match (cgcx.tm_factory.0)() { + Ok(m) => m, + Err(e) => { + handler.struct_err(&e).emit(); + return Err(FatalError) + } + }; + + Ok(ModuleLlvm { + llmod_raw, + llcx, + tm, + }) + } + } + fn llmod(&self) -> &llvm::Module { unsafe { &*self.llmod_raw diff --git a/src/librustc_codegen_llvm/llvm/diagnostic.rs b/src/librustc_codegen_llvm/llvm/diagnostic.rs index 0f5d28f9fec5e..a8d272f157ce3 100644 --- a/src/librustc_codegen_llvm/llvm/diagnostic.rs +++ b/src/librustc_codegen_llvm/llvm/diagnostic.rs @@ -4,7 +4,7 @@ pub use self::OptimizationDiagnosticKind::*; pub use self::Diagnostic::*; use libc::c_uint; -use value::Value; +use crate::value::Value; use super::{DiagnosticInfo, Twine}; diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/src/librustc_codegen_llvm/llvm/ffi.rs index 11e34f600c286..e761d2247a757 100644 --- a/src/librustc_codegen_llvm/llvm/ffi.rs +++ b/src/librustc_codegen_llvm/llvm/ffi.rs @@ -2,15 +2,13 @@ use super::debuginfo::{ DIBuilder, DIDescriptor, DIFile, DILexicalBlock, DISubprogram, DIType, DIBasicType, DIDerivedType, DICompositeType, DIScope, DIVariable, DIGlobalVariableExpression, DIArray, DISubrange, DITemplateTypeParameter, DIEnumerator, - DINameSpace, DIFlags, + DINameSpace, DIFlags, DISPFlags, DebugEmissionKind, }; use libc::{c_uint, c_int, size_t, c_char}; use libc::{c_ulonglong, c_void}; use std::marker::PhantomData; -use syntax; -use rustc_codegen_ssa; use super::RustString; @@ -115,6 +113,7 @@ pub enum Attribute { SanitizeAddress = 21, SanitizeMemory = 22, NonLazyBind = 23, + OptimizeNone = 24, } /// LLVMIntPredicate @@ -591,6 +590,40 @@ pub mod debuginfo { const FlagMainSubprogram = (1 << 21); } } + + // These values **must** match with LLVMRustDISPFlags!! + bitflags! { + #[repr(C)] + #[derive(Default)] + pub struct DISPFlags: ::libc::uint32_t { + const SPFlagZero = 0; + const SPFlagVirtual = 1; + const SPFlagPureVirtual = 2; + const SPFlagLocalToUnit = (1 << 2); + const SPFlagDefinition = (1 << 3); + const SPFlagOptimized = (1 << 4); + } + } + + /// LLVMRustDebugEmissionKind + #[derive(Copy, Clone)] + #[repr(C)] + pub enum DebugEmissionKind { + NoDebug, + FullDebug, + LineTablesOnly, + } + + impl DebugEmissionKind { + pub fn from_generic(kind: rustc::session::config::DebugInfo) -> Self { + use rustc::session::config::DebugInfo; + match kind { + DebugInfo::None => DebugEmissionKind::NoDebug, + DebugInfo::Limited => DebugEmissionKind::LineTablesOnly, + DebugInfo::Full => DebugEmissionKind::FullDebug, + } + } + } } extern { pub type ModuleBuffer; } @@ -1302,7 +1335,7 @@ extern "C" { pub fn LLVMGetSections(ObjFile: &'a ObjectFile) -> &'a mut SectionIterator<'a>; /// Destroys a section iterator. pub fn LLVMDisposeSectionIterator(SI: &'a mut SectionIterator<'a>); - /// Returns true if the section iterator is at the end of the section + /// Returns `true` if the section iterator is at the end of the section /// list: pub fn LLVMIsSectionIteratorAtEnd(ObjFile: &'a ObjectFile, SI: &SectionIterator<'a>) -> Bool; /// Moves the section iterator to point to the next section. @@ -1367,7 +1400,8 @@ extern "C" { isOptimized: bool, Flags: *const c_char, RuntimeVer: c_uint, - SplitName: *const c_char) + SplitName: *const c_char, + kind: DebugEmissionKind) -> &'a DIDescriptor; pub fn LLVMRustDIBuilderCreateFile(Builder: &DIBuilder<'a>, @@ -1387,11 +1421,9 @@ extern "C" { File: &'a DIFile, LineNo: c_uint, Ty: &'a DIType, - isLocalToUnit: bool, - isDefinition: bool, ScopeLine: c_uint, Flags: DIFlags, - isOptimized: bool, + SPFlags: DISPFlags, Fn: &'a Value, TParam: &'a DIArray, Decl: Option<&'a DIDescriptor>) @@ -1529,7 +1561,7 @@ extern "C" { AlignInBits: u32, Elements: &'a DIArray, ClassType: &'a DIType, - IsFixed: bool) + IsScoped: bool) -> &'a DIType; pub fn LLVMRustDIBuilderCreateUnionType(Builder: &DIBuilder<'a>, @@ -1770,7 +1802,7 @@ extern "C" { CallbackPayload: *mut c_void, ); pub fn LLVMRustFreeThinLTOData(Data: &'static mut ThinLTOData); - pub fn LLVMRustParseBitcodeForThinLTO( + pub fn LLVMRustParseBitcodeForLTO( Context: &Context, Data: *const u8, len: usize, diff --git a/src/librustc_codegen_llvm/llvm/mod.rs b/src/librustc_codegen_llvm/llvm/mod.rs index 6a596d78da285..543cc912930fd 100644 --- a/src/librustc_codegen_llvm/llvm/mod.rs +++ b/src/librustc_codegen_llvm/llvm/mod.rs @@ -16,7 +16,7 @@ use std::string::FromUtf8Error; use std::slice; use std::ffi::CStr; use std::cell::RefCell; -use libc::{self, c_uint, c_char, size_t}; +use libc::{c_uint, c_char, size_t}; use rustc_data_structures::small_c_str::SmallCStr; pub mod archive_ro; diff --git a/src/librustc_codegen_llvm/llvm_util.rs b/src/librustc_codegen_llvm/llvm_util.rs index ad9ebbcde8ab9..5fea9c8747e0f 100644 --- a/src/librustc_codegen_llvm/llvm_util.rs +++ b/src/librustc_codegen_llvm/llvm_util.rs @@ -1,8 +1,9 @@ +use crate::back::write::create_informational_target_machine; +use crate::llvm; use syntax_pos::symbol::Symbol; -use back::write::create_target_machine; -use llvm; use rustc::session::Session; use rustc::session::config::PrintRequest; +use rustc_target::spec::MergeFunctions; use libc::c_int; use std::ffi::CString; use syntax::feature_gate::UnstableFeatures; @@ -61,7 +62,14 @@ unsafe fn configure_llvm(sess: &Session) { add("-disable-preinline"); } if llvm::LLVMRustIsRustLLVM() { - add("-mergefunc-use-aliases"); + match sess.opts.debugging_opts.merge_functions + .unwrap_or(sess.target.target.options.merge_functions) { + MergeFunctions::Disabled | + MergeFunctions::Trampolines => {} + MergeFunctions::Aliases => { + add("-mergefunc-use-aliases"); + } + } } // HACK(eddyb) LLVM inserts `llvm.assume` calls to preserve align attributes @@ -92,9 +100,11 @@ const ARM_WHITELIST: &[(&str, Option<&str>)] = &[ ("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")), @@ -139,6 +149,7 @@ const X86_WHITELIST: &[(&str, Option<&str>)] = &[ ("fxsr", None), ("lzcnt", None), ("mmx", Some("mmx_target_feature")), + ("movbe", Some("movbe_target_feature")), ("pclmulqdq", None), ("popcnt", None), ("rdrand", None), @@ -215,7 +226,7 @@ pub fn to_llvm_feature<'a>(sess: &Session, s: &'a str) -> &'a str { } pub fn target_features(sess: &Session) -> Vec { - let target_machine = create_target_machine(sess, true); + let target_machine = create_informational_target_machine(sess, true); target_feature_whitelist(sess) .iter() .filter_map(|&(feature, gate)| { @@ -268,7 +279,7 @@ pub fn print_passes() { pub(crate) fn print(req: PrintRequest, sess: &Session) { require_inited(); - let tm = create_target_machine(sess, true); + let tm = create_informational_target_machine(sess, true); unsafe { match req { PrintRequest::TargetCPUs => llvm::LLVMRustPrintTargetCPUs(tm), diff --git a/src/librustc_codegen_llvm/metadata.rs b/src/librustc_codegen_llvm/metadata.rs index 6e77768b558d4..a2df687d58f5a 100644 --- a/src/librustc_codegen_llvm/metadata.rs +++ b/src/librustc_codegen_llvm/metadata.rs @@ -1,8 +1,8 @@ +use crate::llvm; +use crate::llvm::{False, ObjectFile, mk_section_iter}; +use crate::llvm::archive_ro::ArchiveRO; use rustc::middle::cstore::MetadataLoader; use rustc_target::spec::Target; -use llvm; -use llvm::{False, ObjectFile, mk_section_iter}; -use llvm::archive_ro::ArchiveRO; use rustc_data_structures::owning_ref::OwningRef; use std::path::Path; diff --git a/src/librustc_codegen_llvm/mono_item.rs b/src/librustc_codegen_llvm/mono_item.rs index 69fc8783dc8d2..4fe6a1f4f4b1c 100644 --- a/src/librustc_codegen_llvm/mono_item.rs +++ b/src/librustc_codegen_llvm/mono_item.rs @@ -1,9 +1,9 @@ -use attributes; -use base; -use context::CodegenCx; -use llvm; -use monomorphize::Instance; -use type_of::LayoutLlvmExt; +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; diff --git a/src/librustc_codegen_llvm/type_.rs b/src/librustc_codegen_llvm/type_.rs index 958e00506d62a..ca61987e12f7a 100644 --- a/src/librustc_codegen_llvm/type_.rs +++ b/src/librustc_codegen_llvm/type_.rs @@ -1,22 +1,22 @@ #![allow(non_upper_case_globals)] -pub use llvm::Type; +pub use crate::llvm::Type; -use llvm; -use llvm::{Bool, False, True}; -use context::CodegenCx; +use crate::llvm; +use crate::llvm::{Bool, False, True}; +use crate::context::CodegenCx; +use crate::value::Value; use rustc_codegen_ssa::traits::*; -use value::Value; +use crate::common; +use crate::type_of::LayoutLlvmExt; +use crate::abi::{LlvmType, FnTypeExt}; use rustc::util::nodemap::FxHashMap; use rustc::ty::Ty; use rustc::ty::layout::TyLayout; use rustc_target::abi::call::{CastTarget, FnType, Reg}; use rustc_data_structures::small_c_str::SmallCStr; -use common; use rustc_codegen_ssa::common::TypeKind; -use type_of::LayoutLlvmExt; -use abi::{LlvmType, FnTypeExt}; use std::fmt; use std::cell::RefCell; @@ -82,7 +82,6 @@ impl BaseTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> { fn type_i16(&self) -> &'ll Type { unsafe { - llvm::LLVMInt16TypeInContext(self.llcx) } } diff --git a/src/librustc_codegen_llvm/type_of.rs b/src/librustc_codegen_llvm/type_of.rs index 97128c2d2a2ce..fb5624d56078e 100644 --- a/src/librustc_codegen_llvm/type_of.rs +++ b/src/librustc_codegen_llvm/type_of.rs @@ -1,12 +1,12 @@ -use abi::{FnType, FnTypeExt}; -use common::*; +use crate::abi::{FnType, FnTypeExt}; +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_codegen_ssa::traits::*; -use type_::Type; use std::fmt::Write; @@ -55,7 +55,7 @@ fn uncached_llvm_type<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, ty::Str => { let mut name = String::with_capacity(32); let printer = DefPathBasedNames::new(cx.tcx, true, true); - printer.push_type_name(layout.ty, &mut name); + printer.push_type_name(layout.ty, &mut name, false); if let (&ty::Adt(def, _), &layout::Variants::Single { index }) = (&layout.ty.sty, &layout.variants) { @@ -226,7 +226,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> { } } - /// Get the LLVM type corresponding to a Rust type, i.e., `rustc::ty::Ty`. + /// Gets the LLVM type corresponding to a Rust type, i.e., `rustc::ty::Ty`. /// The pointee type of the pointer in `PlaceRef` is always this type. /// For sized types, it is also the right LLVM type for an `alloca` /// containing a value of that type, and most immediates (except `bool`). diff --git a/src/librustc_codegen_llvm/va_arg.rs b/src/librustc_codegen_llvm/va_arg.rs index 9239f85a8f230..8719390b51aca 100644 --- a/src/librustc_codegen_llvm/va_arg.rs +++ b/src/librustc_codegen_llvm/va_arg.rs @@ -1,11 +1,11 @@ -use builder::Builder; +use crate::builder::Builder; +use crate::type_::Type; +use crate::type_of::LayoutLlvmExt; +use crate::value::Value; use rustc_codegen_ssa::mir::operand::OperandRef; use rustc_codegen_ssa::traits::{BaseTypeMethods, BuilderMethods, ConstMethods, DerivedTypeMethods}; use rustc::ty::layout::{Align, HasDataLayout, HasTyCtxt, LayoutOf, Size}; use rustc::ty::Ty; -use type_::Type; -use type_of::LayoutLlvmExt; -use value::Value; #[allow(dead_code)] fn round_pointer_up_to_alignment( diff --git a/src/librustc_codegen_llvm/value.rs b/src/librustc_codegen_llvm/value.rs index 3ad1521be9393..68809284bb726 100644 --- a/src/librustc_codegen_llvm/value.rs +++ b/src/librustc_codegen_llvm/value.rs @@ -1,6 +1,6 @@ -pub use llvm::Value; +pub use crate::llvm::Value; -use llvm; +use crate::llvm; use std::fmt; use std::hash::{Hash, Hasher}; diff --git a/src/librustc_codegen_ssa/Cargo.toml b/src/librustc_codegen_ssa/Cargo.toml index 50994497c2843..0aba43580f1f6 100644 --- a/src/librustc_codegen_ssa/Cargo.toml +++ b/src/librustc_codegen_ssa/Cargo.toml @@ -2,6 +2,7 @@ authors = ["The Rust Project Developers"] name = "rustc_codegen_ssa" version = "0.0.0" +edition = "2018" [lib] name = "rustc_codegen_ssa" diff --git a/src/librustc_codegen_ssa/back/link.rs b/src/librustc_codegen_ssa/back/link.rs index d03bb0a3d73a4..7f1aebace8fc6 100644 --- a/src/librustc_codegen_ssa/back/link.rs +++ b/src/librustc_codegen_ssa/back/link.rs @@ -9,7 +9,7 @@ use rustc_target::spec::LinkerFlavor; use rustc::hir::def_id::CrateNum; use super::command::Command; -use CrateInfo; +use crate::CrateInfo; use cc::windows_registry; use std::fs; @@ -149,6 +149,7 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) { LinkerFlavor::Ld => "ld", LinkerFlavor::Msvc => "link.exe", LinkerFlavor::Lld(_) => "lld", + LinkerFlavor::PtxLinker => "rust-ptx-linker", }), flavor)), (Some(linker), None) => { let stem = if linker.extension().and_then(|ext| ext.to_str()) == Some("exe") { diff --git a/src/librustc_codegen_ssa/back/linker.rs b/src/librustc_codegen_ssa/back/linker.rs index 06d4f940436da..356bb8d50ad0d 100644 --- a/src/librustc_codegen_ssa/back/linker.rs +++ b/src/librustc_codegen_ssa/back/linker.rs @@ -13,7 +13,7 @@ use rustc::hir::def_id::{LOCAL_CRATE, CrateNum}; use rustc::middle::dependency_format::Linkage; use rustc::session::Session; use rustc::session::config::{self, CrateType, OptLevel, DebugInfo, - CrossLangLto}; + LinkerPluginLto, Lto}; use rustc::ty::TyCtxt; use rustc_target::spec::{LinkerFlavor, LldFlavor}; use serialize::{json, Encoder}; @@ -83,11 +83,15 @@ impl LinkerInfo { LinkerFlavor::Lld(LldFlavor::Wasm) => { Box::new(WasmLd::new(cmd, sess, self)) as Box } + + LinkerFlavor::PtxLinker => { + Box::new(PtxLinker { cmd, sess }) as Box + } } } } -/// Linker abstraction used by back::link to build up the command to invoke a +/// Linker abstraction used by `back::link` to build up the command to invoke a /// linker. /// /// This trait is the total list of requirements needed by `back::link` and @@ -123,7 +127,7 @@ pub trait Linker { fn subsystem(&mut self, subsystem: &str); fn group_start(&mut self); fn group_end(&mut self); - fn cross_lang_lto(&mut self); + fn linker_plugin_lto(&mut self); // Should have been finalize(self), but we don't support self-by-value on trait objects (yet?). fn finalize(&mut self) -> Command; } @@ -141,7 +145,7 @@ pub struct GccLinker<'a> { impl<'a> GccLinker<'a> { /// Argument that must be passed *directly* to the linker /// - /// These arguments need to be prepended with '-Wl,' when a gcc-style linker is used + /// These arguments need to be prepended with `-Wl`, when a GCC-style linker is used. fn linker_arg(&mut self, arg: S) -> &mut Self where S: AsRef { @@ -179,7 +183,7 @@ impl<'a> GccLinker<'a> { } } - fn push_cross_lang_lto_args(&mut self, plugin_path: Option<&OsStr>) { + fn push_linker_plugin_lto_args(&mut self, plugin_path: Option<&OsStr>) { if let Some(plugin_path) = plugin_path { let mut arg = OsString::from("-plugin="); arg.push(plugin_path); @@ -450,16 +454,16 @@ impl<'a> Linker for GccLinker<'a> { } } - fn cross_lang_lto(&mut self) { - match self.sess.opts.debugging_opts.cross_lang_lto { - CrossLangLto::Disabled => { + fn linker_plugin_lto(&mut self) { + match self.sess.opts.cg.linker_plugin_lto { + LinkerPluginLto::Disabled => { // Nothing to do } - CrossLangLto::LinkerPluginAuto => { - self.push_cross_lang_lto_args(None); + LinkerPluginLto::LinkerPluginAuto => { + self.push_linker_plugin_lto_args(None); } - CrossLangLto::LinkerPlugin(ref path) => { - self.push_cross_lang_lto_args(Some(path.as_os_str())); + LinkerPluginLto::LinkerPlugin(ref path) => { + self.push_linker_plugin_lto_args(Some(path.as_os_str())); } } } @@ -693,7 +697,7 @@ impl<'a> Linker for MsvcLinker<'a> { fn group_start(&mut self) {} fn group_end(&mut self) {} - fn cross_lang_lto(&mut self) { + fn linker_plugin_lto(&mut self) { // Do nothing } } @@ -861,7 +865,7 @@ impl<'a> Linker for EmLinker<'a> { fn group_start(&mut self) {} fn group_end(&mut self) {} - fn cross_lang_lto(&mut self) { + fn linker_plugin_lto(&mut self) { // Do nothing } } @@ -911,9 +915,6 @@ impl<'a> WasmLd<'a> { // For now we just never have an entry symbol cmd.arg("--no-entry"); - // Make the default table accessible - cmd.arg("--export-table"); - // Rust code should never have warnings, and warnings are often // indicative of bugs, let's prevent them. cmd.arg("--fatal-warnings"); @@ -1046,7 +1047,7 @@ impl<'a> Linker for WasmLd<'a> { fn group_start(&mut self) {} fn group_end(&mut self) {} - fn cross_lang_lto(&mut self) { + fn linker_plugin_lto(&mut self) { // Do nothing for now } } @@ -1083,3 +1084,129 @@ fn exported_symbols(tcx: TyCtxt, crate_type: CrateType) -> Vec { symbols } + +/// Much simplified and explicit CLI for the NVPTX linker. The linker operates +/// with bitcode and uses LLVM backend to generate a PTX assembly. +pub struct PtxLinker<'a> { + cmd: Command, + sess: &'a Session, +} + +impl<'a> Linker for PtxLinker<'a> { + fn link_rlib(&mut self, path: &Path) { + self.cmd.arg("--rlib").arg(path); + } + + fn link_whole_rlib(&mut self, path: &Path) { + self.cmd.arg("--rlib").arg(path); + } + + fn include_path(&mut self, path: &Path) { + self.cmd.arg("-L").arg(path); + } + + fn debuginfo(&mut self) { + self.cmd.arg("--debug"); + } + + fn add_object(&mut self, path: &Path) { + self.cmd.arg("--bitcode").arg(path); + } + + fn args(&mut self, args: &[String]) { + self.cmd.args(args); + } + + fn optimize(&mut self) { + match self.sess.lto() { + Lto::Thin | Lto::Fat | Lto::ThinLocal => { + self.cmd.arg("-Olto"); + }, + + Lto::No => { }, + }; + } + + fn output_filename(&mut self, path: &Path) { + self.cmd.arg("-o").arg(path); + } + + fn finalize(&mut self) -> Command { + // Provide the linker with fallback to internal `target-cpu`. + self.cmd.arg("--fallback-arch").arg(match self.sess.opts.cg.target_cpu { + Some(ref s) => s, + None => &self.sess.target.target.options.cpu + }); + + ::std::mem::replace(&mut self.cmd, Command::new("")) + } + + fn link_dylib(&mut self, _lib: &str) { + panic!("external dylibs not supported") + } + + fn link_rust_dylib(&mut self, _lib: &str, _path: &Path) { + panic!("external dylibs not supported") + } + + fn link_staticlib(&mut self, _lib: &str) { + panic!("staticlibs not supported") + } + + fn link_whole_staticlib(&mut self, _lib: &str, _search_path: &[PathBuf]) { + panic!("staticlibs not supported") + } + + fn framework_path(&mut self, _path: &Path) { + panic!("frameworks not supported") + } + + fn link_framework(&mut self, _framework: &str) { + panic!("frameworks not supported") + } + + fn position_independent_executable(&mut self) { + } + + fn full_relro(&mut self) { + } + + fn partial_relro(&mut self) { + } + + fn no_relro(&mut self) { + } + + fn build_static_executable(&mut self) { + } + + fn gc_sections(&mut self, _keep_metadata: bool) { + } + + fn pgo_gen(&mut self) { + } + + fn no_default_libraries(&mut self) { + } + + fn build_dylib(&mut self, _out_filename: &Path) { + } + + fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType) { + } + + fn subsystem(&mut self, _subsystem: &str) { + } + + fn no_position_independent_executable(&mut self) { + } + + fn group_start(&mut self) { + } + + fn group_end(&mut self) { + } + + fn linker_plugin_lto(&mut self) { + } +} diff --git a/src/librustc_codegen_ssa/back/lto.rs b/src/librustc_codegen_ssa/back/lto.rs index f0fb115f91b94..7f0eba7b0850b 100644 --- a/src/librustc_codegen_ssa/back/lto.rs +++ b/src/librustc_codegen_ssa/back/lto.rs @@ -1,6 +1,6 @@ use super::write::CodegenContext; -use traits::*; -use ModuleCodegen; +use crate::traits::*; +use crate::ModuleCodegen; use rustc::util::time_graph::Timeline; use rustc_errors::FatalError; diff --git a/src/librustc_codegen_ssa/back/symbol_export.rs b/src/librustc_codegen_ssa/back/symbol_export.rs index bf69089a254a4..c372892c521be 100644 --- a/src/librustc_codegen_ssa/back/symbol_export.rs +++ b/src/librustc_codegen_ssa/back/symbol_export.rs @@ -194,7 +194,7 @@ fn exported_symbols_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }) .collect(); - if tcx.sess.entry_fn.borrow().is_some() { + if tcx.entry_fn(LOCAL_CRATE).is_some() { let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new("main")); symbols.push((exported_symbol, SymbolExportLevel::C)); diff --git a/src/librustc_codegen_ssa/back/write.rs b/src/librustc_codegen_ssa/back/write.rs index fb3e7ea696363..20842553c2666 100644 --- a/src/librustc_codegen_ssa/back/write.rs +++ b/src/librustc_codegen_ssa/back/write.rs @@ -1,12 +1,12 @@ -use {ModuleCodegen, ModuleKind, CachedModuleCodegen, CompiledModule, CrateInfo, CodegenResults, - RLIB_BYTECODE_EXTENSION}; +use crate::{ModuleCodegen, ModuleKind, CachedModuleCodegen, CompiledModule, CrateInfo, + CodegenResults, RLIB_BYTECODE_EXTENSION}; use super::linker::LinkerInfo; use super::lto::{self, SerializedModule}; use super::link::{self, remove, get_linker}; use super::command::Command; use super::symbol_export::ExportedSymbols; -use memmap; +use crate::traits::*; use rustc_incremental::{copy_cgu_workproducts_to_incr_comp_cache_dir, in_incr_comp_dir, in_incr_comp_dir_sess}; use rustc::dep_graph::{WorkProduct, WorkProductId, WorkProductFileKind}; @@ -16,7 +16,6 @@ use rustc::session::config::{self, OutputFilenames, OutputType, Passes, Sanitize use rustc::session::Session; use rustc::util::nodemap::FxHashMap; use rustc::util::time_graph::{self, TimeGraph, Timeline}; -use traits::*; 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}; @@ -24,6 +23,7 @@ use rustc_fs_util::link_or_copy; use rustc_data_structures::svh::Svh; use rustc_errors::{Handler, Level, DiagnosticBuilder, FatalError, DiagnosticId}; use rustc_errors::emitter::{Emitter}; +use rustc_target::spec::MergeFunctions; use syntax::attr; use syntax::ext::hygiene::Mark; use syntax_pos::MultiSpan; @@ -41,7 +41,7 @@ use std::sync::mpsc::{channel, Sender, Receiver}; use std::time::Instant; use std::thread; -const PRE_THIN_LTO_BC_EXT: &str = "pre-thin-lto.bc"; +const PRE_LTO_BC_EXT: &str = "pre-lto.bc"; /// Module-specific configuration for `optimize_and_codegen`. pub struct ModuleConfig { @@ -58,7 +58,7 @@ pub struct ModuleConfig { pub pgo_use: String, // Flags indicating which outputs to produce. - pub emit_pre_thin_lto_bc: bool, + pub emit_pre_lto_bc: bool, pub emit_no_opt_bc: bool, pub emit_bc: bool, pub emit_bc_compressed: bool, @@ -96,7 +96,7 @@ impl ModuleConfig { pgo_use: String::new(), emit_no_opt_bc: false, - emit_pre_thin_lto_bc: false, + emit_pre_lto_bc: false, emit_bc: false, emit_bc_compressed: false, emit_lto_bc: false, @@ -126,7 +126,7 @@ impl ModuleConfig { self.time_passes = sess.time_passes(); self.inline_threshold = sess.opts.cg.inline_threshold; self.obj_is_bitcode = sess.target.target.options.obj_is_bitcode || - sess.opts.debugging_opts.cross_lang_lto.enabled(); + sess.opts.cg.linker_plugin_lto.enabled(); let embed_bitcode = sess.target.target.options.embed_bitcode || sess.opts.debugging_opts.embed_bitcode; if embed_bitcode { @@ -152,8 +152,24 @@ impl ModuleConfig { sess.opts.optimize == config::OptLevel::Aggressive && !sess.target.target.options.is_like_emscripten; - self.merge_functions = sess.opts.optimize == config::OptLevel::Default || - sess.opts.optimize == config::OptLevel::Aggressive; + // Some targets (namely, NVPTX) interact badly with the MergeFunctions + // pass. This is because MergeFunctions can generate new function calls + // which may interfere with the target calling convention; e.g. for the + // NVPTX target, PTX kernels should not call other PTX kernels. + // MergeFunctions can also be configured to generate aliases instead, + // but aliases are not supported by some backends (again, NVPTX). + // Therefore, allow targets to opt out of the MergeFunctions pass, + // but otherwise keep the pass enabled (at O2 and O3) since it can be + // useful for reducing code size. + self.merge_functions = match sess.opts.debugging_opts.merge_functions + .unwrap_or(sess.target.target.options.merge_functions) { + MergeFunctions::Disabled => false, + MergeFunctions::Trampolines | + MergeFunctions::Aliases => { + sess.opts.optimize == config::OptLevel::Default || + sess.opts.optimize == config::OptLevel::Aggressive + } + }; } pub fn bitcode_needed(&self) -> bool { @@ -242,7 +258,7 @@ impl CodegenContext { fn generate_lto_work( cgcx: &CodegenContext, - needs_fat_lto: Vec>, + needs_fat_lto: Vec>, needs_thin_lto: Vec<(String, B::ThinBuffer)>, import_only_modules: Vec<(SerializedModule, WorkProduct)> ) -> Vec<(WorkItem, u64)> { @@ -254,9 +270,13 @@ fn generate_lto_work( let (lto_modules, copy_jobs) = if !needs_fat_lto.is_empty() { assert!(needs_thin_lto.is_empty()); - assert!(import_only_modules.is_empty()); - let lto_module = B::run_fat_lto(cgcx, needs_fat_lto, &mut timeline) - .unwrap_or_else(|e| e.raise()); + let lto_module = B::run_fat_lto( + 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()); @@ -286,14 +306,14 @@ fn need_crate_bitcode_for_rlib(sess: &Session) -> bool { sess.opts.output_types.contains_key(&OutputType::Exe) } -fn need_pre_thin_lto_bitcode_for_incr_comp(sess: &Session) -> bool { +fn need_pre_lto_bitcode_for_incr_comp(sess: &Session) -> bool { if sess.opts.incremental.is_none() { return false } match sess.lto() { - Lto::Fat | Lto::No => false, + Lto::Fat | Lto::Thin | Lto::ThinLocal => true, } @@ -359,7 +379,7 @@ pub fn start_async_codegen( // Save all versions of the bytecode if we're saving our temporaries. if sess.opts.cg.save_temps { modules_config.emit_no_opt_bc = true; - modules_config.emit_pre_thin_lto_bc = true; + modules_config.emit_pre_lto_bc = true; modules_config.emit_bc = true; modules_config.emit_lto_bc = true; metadata_config.emit_bc = true; @@ -374,8 +394,8 @@ pub fn start_async_codegen( allocator_config.emit_bc_compressed = true; } - modules_config.emit_pre_thin_lto_bc = - need_pre_thin_lto_bitcode_for_incr_comp(sess); + modules_config.emit_pre_lto_bc = + need_pre_lto_bitcode_for_incr_comp(sess); modules_config.no_integrated_as = tcx.sess.opts.cg.no_integrated_as || tcx.sess.target.target.options.no_integrated_as; @@ -646,7 +666,7 @@ pub enum WorkItem { /// Copy the post-LTO artifacts from the incremental cache to the output /// directory. CopyPostLtoArtifacts(CachedModuleCodegen), - /// Perform (Thin)LTO on the given module. + /// Performs (Thin)LTO on the given module. LTO(lto::LtoModuleCodegen), } @@ -670,10 +690,18 @@ impl WorkItem { enum WorkItemResult { Compiled(CompiledModule), - NeedsFatLTO(ModuleCodegen), + NeedsFatLTO(FatLTOInput), NeedsThinLTO(String, B::ThinBuffer), } +pub enum FatLTOInput { + Serialized { + name: String, + buffer: B::ModuleBuffer, + }, + InMemory(ModuleCodegen), +} + fn execute_work_item( cgcx: &CodegenContext, work_item: WorkItem, @@ -721,7 +749,7 @@ fn execute_optimize_work_item( // If the linker does LTO, we don't have to do it. Note that we // keep doing full LTO, if it is requested, as not to break the // assumption that the output will be a single module. - let linker_does_lto = cgcx.opts.debugging_opts.cross_lang_lto.enabled(); + let linker_does_lto = cgcx.opts.cg.linker_plugin_lto.enabled(); // When we're automatically doing ThinLTO for multi-codegen-unit // builds we don't actually want to LTO the allocator modules if @@ -755,6 +783,15 @@ fn execute_optimize_work_item( } }; + // If we're doing some form of incremental LTO then we need to be sure to + // save our module to disk first. + let bitcode = if cgcx.config(module.kind).emit_pre_lto_bc { + let filename = pre_lto_bitcode_filename(&module.name); + cgcx.incr_comp_session_dir.as_ref().map(|path| path.join(&filename)) + } else { + None + }; + Ok(match lto_type { ComputedLtoType::No => { let module = unsafe { @@ -763,10 +800,30 @@ fn execute_optimize_work_item( WorkItemResult::Compiled(module) } ComputedLtoType::Thin => { - let (name, thin_buffer) = B::prepare_thin(cgcx, module); + let (name, thin_buffer) = B::prepare_thin(module); + if let Some(path) = bitcode { + fs::write(&path, thin_buffer.data()).unwrap_or_else(|e| { + panic!("Error writing pre-lto-bitcode file `{}`: {}", + path.display(), + e); + }); + } WorkItemResult::NeedsThinLTO(name, thin_buffer) } - ComputedLtoType::Fat => WorkItemResult::NeedsFatLTO(module), + ComputedLtoType::Fat => { + match bitcode { + Some(path) => { + let (name, buffer) = B::serialize_module(module); + fs::write(&path, buffer.data()).unwrap_or_else(|e| { + panic!("Error writing pre-lto-bitcode file `{}`: {}", + path.display(), + e); + }); + WorkItemResult::NeedsFatLTO(FatLTOInput::Serialized { name, buffer }) + } + None => WorkItemResult::NeedsFatLTO(FatLTOInput::InMemory(module)), + } + } }) } @@ -850,7 +907,7 @@ fn execute_lto_work_item( pub enum Message { Token(io::Result), NeedsFatLTO { - result: ModuleCodegen, + result: FatLTOInput, worker_id: usize, }, NeedsThinLTO { @@ -965,6 +1022,7 @@ fn start_executing_work( None }; + let ol = tcx.backend_optimization_level(LOCAL_CRATE); let cgcx = CodegenContext:: { backend: backend.clone(), crate_types: sess.crate_types.borrow().clone(), @@ -988,7 +1046,7 @@ fn start_executing_work( regular_module_config: modules_config, metadata_module_config: metadata_config, allocator_module_config: allocator_config, - tm_factory: TargetMachineFactory(backend.target_machine_factory(tcx.sess, false)), + tm_factory: TargetMachineFactory(backend.target_machine_factory(tcx.sess, ol, false)), total_cgus, msvc_imps_needed: msvc_imps_needed(tcx), target_pointer_width: tcx.sess.target.target.target_pointer_width.clone(), @@ -1780,7 +1838,7 @@ impl OngoingCodegen { drop(self.coordinator_send.send(Box::new(Message::CodegenComplete::))); } - /// Consume this context indicating that codegen was entirely aborted, and + /// Consumes this context indicating that codegen was entirely aborted, and /// we need to exit as quickly as possible. /// /// This method blocks the current thread until all worker threads have @@ -1860,13 +1918,13 @@ pub fn submit_pre_lto_module_to_llvm( } pub fn pre_lto_bitcode_filename(module_name: &str) -> String { - format!("{}.{}", module_name, PRE_THIN_LTO_BC_EXT) + format!("{}.{}", module_name, PRE_LTO_BC_EXT) } 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.debugging_opts.cross_lang_lto.enabled() && + assert!(!(tcx.sess.opts.cg.linker_plugin_lto.enabled() && tcx.sess.target.target.options.is_like_msvc && tcx.sess.opts.cg.prefer_dynamic)); @@ -1874,6 +1932,6 @@ fn msvc_imps_needed(tcx: TyCtxt) -> bool { tcx.sess.crate_types.borrow().iter().any(|ct| *ct == config::CrateType::Rlib) && // ThinLTO can't handle this workaround in all cases, so we don't // emit the `__imp_` symbols. Instead we make them unnecessary by disallowing - // dynamic linking when cross-language LTO is enabled. - !tcx.sess.opts.debugging_opts.cross_lang_lto.enabled() + // dynamic linking when linker plugin LTO is enabled. + !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 b88ec075653ba..7aa75f139d2ae 100644 --- a/src/librustc_codegen_ssa/base.rs +++ b/src/librustc_codegen_ssa/base.rs @@ -7,13 +7,13 @@ //! //! Hopefully useful general knowledge about codegen: //! -//! * There's no way to find out the Ty type of a Value. Doing so -//! would be "trying to get the eggs out of an omelette" (credit: -//! pcwalton). You can, instead, find out its llvm::Type by calling val_ty, -//! 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. +//! * There's no way to find out the `Ty` type of a Value. Doing so +//! would be "trying to get the eggs out of an omelette" (credit: +//! pcwalton). You can, instead, find out its `llvm::Type` by calling `val_ty`, +//! 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 {ModuleCodegen, ModuleKind, CachedModuleCodegen}; +use crate::{ModuleCodegen, ModuleKind, CachedModuleCodegen}; use rustc::dep_graph::cgu_reuse_tracker::CguReuse; use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; @@ -28,26 +28,26 @@ 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 mir::place::PlaceRef; -use back::write::{OngoingCodegen, start_async_codegen, submit_pre_lto_module_to_llvm, - submit_post_lto_module_to_llvm}; -use {MemFlags, CrateInfo}; -use callee; use rustc_mir::monomorphize::item::DefPathBasedNames; -use common::{RealPredicate, TypeKind, IntPredicate}; -use meth; -use mir; use rustc::util::time_graph; use rustc_mir::monomorphize::Instance; use rustc_mir::monomorphize::partitioning::{CodegenUnit, CodegenUnitExt}; -use mono_item::MonoItem; 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; +use crate::back::write::{OngoingCodegen, start_async_codegen, submit_pre_lto_module_to_llvm, + submit_post_lto_module_to_llvm}; +use crate::{MemFlags, CrateInfo}; +use crate::callee; +use crate::common::{RealPredicate, TypeKind, IntPredicate}; +use crate::meth; +use crate::mir; +use crate::mono_item::MonoItem; -use traits::*; +use crate::traits::*; use std::any::Any; use std::cmp; @@ -58,7 +58,7 @@ use syntax_pos::Span; use syntax::attr; use rustc::hir; -use mir::operand::OperandValue; +use crate::mir::operand::OperandValue; use std::marker::PhantomData; @@ -156,7 +156,7 @@ pub fn compare_simd_types<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( bx.sext(cmp, ret_ty) } -/// Retrieve the information we are losing (making dynamic) in an unsizing +/// Retrieves the information we are losing (making dynamic) in an unsizing /// adjustment. /// /// The `old_info` argument is a bit funny. It is intended for use @@ -347,7 +347,7 @@ fn cast_shift_rhs<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( } } -/// Returns whether this session's target will use SEH-based unwinding. +/// Returns `true` if this session's target will use SEH-based unwinding. /// /// This is only true for MSVC targets, and even then the 64-bit MSVC target /// currently uses SEH-ish unwinding with DWARF info tables to the side (same as @@ -436,15 +436,13 @@ pub fn codegen_instance<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( mir::codegen_mir::(cx, lldecl, &mir, instance, sig); } -/// Create the `main` function which will initialize the rust runtime and call +/// 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 ) { - let (main_def_id, span) = match *cx.sess().entry_fn.borrow() { - Some((id, span, _)) => { - (cx.tcx().hir().local_def_id(id), span) - } + 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, }; @@ -458,7 +456,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( let main_llfn = cx.get_fn(instance); - let et = cx.sess().entry_fn.get().map(|e| e.2); + let et = cx.tcx().entry_fn(LOCAL_CRATE).map(|e| e.1); match et { Some(EntryFnType::Main) => create_entry_fn::(cx, span, main_llfn, main_def_id, true), Some(EntryFnType::Start) => create_entry_fn::(cx, span, main_llfn, main_def_id, false), @@ -553,7 +551,7 @@ pub fn codegen_crate( &["crate"], Some("metadata")).as_str() .to_string(); - let metadata_llvm_module = backend.new_metadata(tcx.sess, &metadata_cgu_name); + let metadata_llvm_module = backend.new_metadata(tcx, &metadata_cgu_name); let metadata = time(tcx.sess, "write metadata", || { backend.write_metadata(tcx, &metadata_llvm_module) }); @@ -638,7 +636,7 @@ pub fn codegen_crate( &["crate"], Some("allocator")).as_str() .to_string(); - let modules = backend.new_metadata(tcx.sess, &llmod_id); + let modules = backend.new_metadata(tcx, &llmod_id); time(tcx.sess, "write allocator module", || { backend.codegen_allocator(tcx, &modules, kind) }); @@ -899,6 +897,39 @@ fn is_codegened_item(tcx: TyCtxt, id: DefId) -> bool { } pub fn provide_both(providers: &mut Providers) { + providers.backend_optimization_level = |tcx, cratenum| { + let for_speed = match tcx.sess.opts.optimize { + // If globally no optimisation is done, #[optimize] has no effect. + // + // This is done because if we ended up "upgrading" to `-O2` here, we’d populate the + // pass manager and it is likely that some module-wide passes (such as inliner or + // cross-function constant propagation) would ignore the `optnone` annotation we put + // on the functions, thus necessarily involving these functions into optimisations. + config::OptLevel::No => return config::OptLevel::No, + // If globally optimise-speed is already specified, just use that level. + config::OptLevel::Less => return config::OptLevel::Less, + config::OptLevel::Default => return config::OptLevel::Default, + config::OptLevel::Aggressive => return config::OptLevel::Aggressive, + // If globally optimize-for-size has been requested, use -O2 instead (if optimize(size) + // are present). + config::OptLevel::Size => config::OptLevel::Default, + config::OptLevel::SizeMin => config::OptLevel::Default, + }; + + let (defids, _) = tcx.collect_and_partition_mono_items(cratenum); + for id in &*defids { + let hir::CodegenFnAttrs { optimize, .. } = tcx.codegen_fn_attrs(*id); + match optimize { + attr::OptimizeAttr::None => continue, + attr::OptimizeAttr::Size => continue, + attr::OptimizeAttr::Speed => { + return for_speed; + } + } + } + return tcx.sess.opts.optimize; + }; + providers.dllimport_foreign_items = |tcx, krate| { let module_map = tcx.foreign_modules(krate); let module_map = module_map.iter() diff --git a/src/librustc_codegen_ssa/callee.rs b/src/librustc_codegen_ssa/callee.rs index aa13e525a73bf..3665d45d1e9c7 100644 --- a/src/librustc_codegen_ssa/callee.rs +++ b/src/librustc_codegen_ssa/callee.rs @@ -1,4 +1,4 @@ -use traits::*; +use crate::traits::*; use rustc::ty; use rustc::ty::subst::Substs; use rustc::hir::def_id::DefId; diff --git a/src/librustc_codegen_ssa/common.rs b/src/librustc_codegen_ssa/common.rs index cfb5d24fc12ef..1b87f160cc35d 100644 --- a/src/librustc_codegen_ssa/common.rs +++ b/src/librustc_codegen_ssa/common.rs @@ -5,11 +5,11 @@ use syntax_pos::{DUMMY_SP, Span}; use rustc::hir::def_id::DefId; use rustc::middle::lang_items::LangItem; -use base; -use traits::*; +use crate::base; +use crate::traits::*; use rustc::hir; -use traits::BuilderMethods; +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()) @@ -123,7 +123,7 @@ pub enum TypeKind { mod temp_stable_hash_impls { use rustc_data_structures::stable_hasher::{StableHasherResult, StableHasher, HashStable}; - use ModuleCodegen; + use crate::ModuleCodegen; impl HashStable for ModuleCodegen { fn hash_stable(&self, diff --git a/src/librustc_codegen_ssa/glue.rs b/src/librustc_codegen_ssa/glue.rs index ed63e1e62ee5f..e2b49de05bd11 100644 --- a/src/librustc_codegen_ssa/glue.rs +++ b/src/librustc_codegen_ssa/glue.rs @@ -2,12 +2,10 @@ // // Code relating to drop glue. -use std; - -use common::IntPredicate; -use meth; use rustc::ty::{self, Ty}; -use traits::*; +use crate::common::IntPredicate; +use crate::meth; +use crate::traits::*; pub fn size_and_align_of_dst<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( bx: &mut Bx, diff --git a/src/librustc_codegen_ssa/lib.rs b/src/librustc_codegen_ssa/lib.rs index d47bd23766f69..9e1744451465d 100644 --- a/src/librustc_codegen_ssa/lib.rs +++ b/src/librustc_codegen_ssa/lib.rs @@ -1,6 +1,4 @@ -#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", - html_favicon_url = "https://doc.rust-lang.org/favicon.ico", - html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] #![feature(box_patterns)] #![feature(box_syntax)] @@ -8,11 +6,12 @@ #![feature(libc)] #![feature(rustc_diagnostic_macros)] #![feature(in_band_lifetimes)] -#![feature(slice_sort_by_cached_key)] #![feature(nll)] #![allow(unused_attributes)] #![allow(dead_code)] -#![feature(quote)] +#![deny(rust_2018_idioms)] +#![allow(explicit_outlives_requirements)] +#![allow(elided_lifetimes_in_paths)] #![recursion_limit="256"] @@ -20,27 +19,9 @@ //! The backend-agnostic functions of this crate use functions defined in various traits that //! have to be implemented by each backends. -#[macro_use] extern crate bitflags; #[macro_use] extern crate log; -extern crate rustc_apfloat; -#[macro_use] extern crate rustc; -extern crate rustc_target; -extern crate rustc_mir; +#[macro_use] extern crate rustc; #[macro_use] extern crate syntax; -extern crate syntax_pos; -extern crate rustc_incremental; -extern crate rustc_codegen_utils; -extern crate rustc_data_structures; -extern crate rustc_allocator; -extern crate rustc_fs_util; -extern crate serialize; -extern crate rustc_errors; -extern crate rustc_demangle; -extern crate cc; -extern crate libc; -extern crate jobserver; -extern crate memmap; -extern crate num_cpus; use std::path::PathBuf; use rustc::dep_graph::WorkProduct; @@ -71,7 +52,7 @@ pub mod back; pub struct ModuleCodegen { /// The name of the module. When the crate may be saved between /// compilations, incremental compilation requires that name be - /// unique amongst **all** crates. Therefore, it should contain + /// unique amongst **all** crates. Therefore, it should contain /// something unique to this crate (e.g., a module path) as well /// as the crate name and disambiguator. /// We currently generate these names via CodegenUnit::build_cgu_name(). @@ -136,7 +117,7 @@ pub enum ModuleKind { Allocator, } -bitflags! { +bitflags::bitflags! { pub struct MemFlags: u8 { const VOLATILE = 1 << 0; const NONTEMPORAL = 1 << 1; @@ -144,7 +125,7 @@ bitflags! { } } -/// Misc info we load from metadata to persist beyond the tcx +/// Misc info we load from metadata to persist beyond the tcx. pub struct CrateInfo { pub panic_runtime: Option, pub compiler_builtins: Option, diff --git a/src/librustc_codegen_ssa/meth.rs b/src/librustc_codegen_ssa/meth.rs index 98ad2616eeaae..49f3c87ee2d9d 100644 --- a/src/librustc_codegen_ssa/meth.rs +++ b/src/librustc_codegen_ssa/meth.rs @@ -1,8 +1,8 @@ use rustc_target::abi::call::FnType; -use callee; use rustc_mir::monomorphize; -use traits::*; +use crate::callee; +use crate::traits::*; use rustc::ty::{self, Ty}; diff --git a/src/librustc_codegen_ssa/mir/analyze.rs b/src/librustc_codegen_ssa/mir/analyze.rs index f3475d1c48968..9fe2e58bc203c 100644 --- a/src/librustc_codegen_ssa/mir/analyze.rs +++ b/src/librustc_codegen_ssa/mir/analyze.rs @@ -10,7 +10,7 @@ use rustc::mir::traversal; use rustc::ty; use rustc::ty::layout::{LayoutOf, HasTyCtxt}; use super::FunctionCx; -use traits::*; +use crate::traits::*; pub fn non_ssa_locals<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( fx: &FunctionCx<'a, 'tcx, Bx> diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs index aa82c853257a3..caca1789fc98c 100644 --- a/src/librustc_codegen_ssa/mir/block.rs +++ b/src/librustc_codegen_ssa/mir/block.rs @@ -5,13 +5,13 @@ use rustc::mir; use rustc::mir::interpret::EvalErrorKind; use rustc_target::abi::call::{ArgType, FnType, PassMode}; use rustc_target::spec::abi::Abi; -use base; -use MemFlags; -use common::{self, IntPredicate}; -use meth; use rustc_mir::monomorphize; +use crate::base; +use crate::MemFlags; +use crate::common::{self, IntPredicate}; +use crate::meth; -use traits::*; +use crate::traits::*; use syntax::symbol::Symbol; use syntax_pos::Pos; @@ -884,7 +884,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } - /// Return the landingpad wrapper around the given basic block + /// Returns the landing-pad wrapper around the given basic block. /// /// No-op in MSVC SEH scheme. fn landing_pad_to( diff --git a/src/librustc_codegen_ssa/mir/constant.rs b/src/librustc_codegen_ssa/mir/constant.rs index e6d6ef1d7a38b..6bc69efa4a7d5 100644 --- a/src/librustc_codegen_ssa/mir/constant.rs +++ b/src/librustc_codegen_ssa/mir/constant.rs @@ -6,7 +6,7 @@ use rustc::mir::interpret::GlobalId; use rustc::ty::{self, Ty}; use rustc::ty::layout; use syntax::source_map::Span; -use traits::*; +use crate::traits::*; use super::FunctionCx; @@ -59,7 +59,6 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let field = const_field( bx.tcx(), ty::ParamEnv::reveal_all(), - self.instance, None, mir::Field::new(field as usize), c, diff --git a/src/librustc_codegen_ssa/mir/mod.rs b/src/librustc_codegen_ssa/mir/mod.rs index 85a663dacdcc5..203d84bff5bb3 100644 --- a/src/librustc_codegen_ssa/mir/mod.rs +++ b/src/librustc_codegen_ssa/mir/mod.rs @@ -4,11 +4,11 @@ use rustc::ty::layout::{TyLayout, HasTyCtxt}; use rustc::mir::{self, Mir}; use rustc::ty::subst::Substs; use rustc::session::config::DebugInfo; -use base; -use debuginfo::{self, VariableAccess, VariableKind, FunctionDebugContext}; use rustc_mir::monomorphize::Instance; use rustc_target::abi::call::{FnType, PassMode}; -use traits::*; +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; @@ -422,7 +422,7 @@ fn create_funclets<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( }).unzip() } -/// Produce, for each argument, a `Value` pointing at the +/// 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>>( @@ -586,10 +586,17 @@ fn arg_local_refs<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( return; } + let pin_did = tcx.lang_items().pin_type(); // Or is it the closure environment? let (closure_layout, env_ref) = match arg.layout.ty.sty { ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _) => (bx.layout_of(ty), true), + ty::Adt(def, substs) if Some(def.did) == pin_did => { + match substs.type_at(0).sty { + ty::Ref(_, ty, _) => (bx.layout_of(ty), true), + _ => (arg.layout, false), + } + } _ => (arg.layout, false) }; diff --git a/src/librustc_codegen_ssa/mir/operand.rs b/src/librustc_codegen_ssa/mir/operand.rs index 2026e042ef0eb..2c6d968bb032a 100644 --- a/src/librustc_codegen_ssa/mir/operand.rs +++ b/src/librustc_codegen_ssa/mir/operand.rs @@ -3,11 +3,11 @@ use rustc::mir; use rustc::ty; use rustc::ty::layout::{self, Align, LayoutOf, TyLayout}; -use base; -use MemFlags; -use glue; +use crate::base; +use crate::MemFlags; +use crate::glue; -use traits::*; +use crate::traits::*; use std::fmt; @@ -88,9 +88,9 @@ impl<'a, 'tcx: 'a, V: CodegenObject> OperandRef<'tcx, V> { ); OperandValue::Immediate(llval) }, - ConstValue::ScalarPair(a, b) => { - let (a_scalar, b_scalar) = match layout.abi { - layout::Abi::ScalarPair(ref a, ref b) => (a, b), + ConstValue::Slice(a, b) => { + 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( @@ -98,11 +98,7 @@ impl<'a, 'tcx: 'a, V: CodegenObject> OperandRef<'tcx, V> { a_scalar, bx.cx().scalar_pair_element_backend_type(layout, 0, true), ); - let b_llval = bx.cx().scalar_to_backend( - b, - b_scalar, - bx.cx().scalar_pair_element_backend_type(layout, 1, true), - ); + let b_llval = bx.cx().const_usize(b); OperandValue::Pair(a_llval, b_llval) }, ConstValue::ByRef(_, alloc, offset) => { diff --git a/src/librustc_codegen_ssa/mir/place.rs b/src/librustc_codegen_ssa/mir/place.rs index b10611e5ac797..9d6826d8756b7 100644 --- a/src/librustc_codegen_ssa/mir/place.rs +++ b/src/librustc_codegen_ssa/mir/place.rs @@ -2,27 +2,27 @@ use rustc::ty::{self, Ty}; use rustc::ty::layout::{self, Align, TyLayout, LayoutOf, VariantIdx, HasTyCtxt}; use rustc::mir; use rustc::mir::tcx::PlaceTy; -use MemFlags; -use common::IntPredicate; -use glue; +use crate::MemFlags; +use crate::common::IntPredicate; +use crate::glue; -use traits::*; +use crate::traits::*; use super::{FunctionCx, LocalRef}; use super::operand::OperandValue; #[derive(Copy, Clone, Debug)] pub struct PlaceRef<'tcx, V> { - /// Pointer to the contents of the place + /// Pointer to the contents of the place. pub llval: V, - /// This place's extra data if it is unsized, or null + /// This place's extra data if it is unsized, or null. pub llextra: Option, - /// Monomorphized type of this place, including variant information + /// Monomorphized type of this place, including variant information. pub layout: TyLayout<'tcx>, - /// What alignment we know for this place + /// What alignment we know for this place. pub align: Align, } @@ -41,6 +41,21 @@ impl<'a, 'tcx: 'a, V: CodegenObject> PlaceRef<'tcx, V> { } } + fn new_thin_place>( + bx: &mut Bx, + llval: V, + layout: TyLayout<'tcx>, + align: Align, + ) -> PlaceRef<'tcx, V> { + assert!(!bx.cx().type_has_metadata(layout.ty)); + PlaceRef { + llval, + llextra: None, + layout, + align + } + } + pub fn alloca>( bx: &mut Bx, layout: TyLayout<'tcx>, @@ -262,7 +277,7 @@ impl<'a, 'tcx: 'a, V: CodegenObject> PlaceRef<'tcx, V> { } } - /// Set the discriminant for a new value of the given case of the given + /// Sets the discriminant for a new value of the given case of the given /// representation. pub fn codegen_set_discr>( &self, @@ -421,8 +436,10 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } mir::Place::Static(box mir::Static { def_id, ty }) => { + // 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_sized(bx.get_static(def_id), layout, layout.align.abi) + PlaceRef::new_thin_place(bx, bx.get_static(def_id), layout, layout.align.abi) }, mir::Place::Projection(box mir::Projection { ref base, diff --git a/src/librustc_codegen_ssa/mir/rvalue.rs b/src/librustc_codegen_ssa/mir/rvalue.rs index 9ca5414fa717e..25a7754d118d7 100644 --- a/src/librustc_codegen_ssa/mir/rvalue.rs +++ b/src/librustc_codegen_ssa/mir/rvalue.rs @@ -6,13 +6,13 @@ use rustc::middle::lang_items::ExchangeMallocFnLangItem; use rustc_apfloat::{ieee, Float, Status, Round}; use std::{u128, i128}; -use base; -use MemFlags; -use callee; -use common::{self, RealPredicate, IntPredicate}; +use crate::base; +use crate::MemFlags; +use crate::callee; +use crate::common::{self, RealPredicate, IntPredicate}; use rustc_mir::monomorphize; -use traits::*; +use crate::traits::*; use super::{FunctionCx, LocalRef}; use super::operand::{OperandRef, OperandValue}; diff --git a/src/librustc_codegen_ssa/mir/statement.rs b/src/librustc_codegen_ssa/mir/statement.rs index 9561a57d0a7de..a1bd919c43354 100644 --- a/src/librustc_codegen_ssa/mir/statement.rs +++ b/src/librustc_codegen_ssa/mir/statement.rs @@ -1,10 +1,10 @@ use rustc::mir; -use traits::BuilderMethods; +use crate::traits::BuilderMethods; use super::FunctionCx; use super::LocalRef; use super::OperandValue; -use traits::*; +use crate::traits::*; impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { pub fn codegen_statement( diff --git a/src/librustc_codegen_ssa/mono_item.rs b/src/librustc_codegen_ssa/mono_item.rs index 21e0044759a5a..bfb6a9153809a 100644 --- a/src/librustc_codegen_ssa/mono_item.rs +++ b/src/librustc_codegen_ssa/mono_item.rs @@ -1,10 +1,10 @@ -use base; use rustc::hir; use rustc::hir::def::Def; use rustc::mir::mono::{Linkage, Visibility}; use rustc::ty::layout::HasTyCtxt; use std::fmt; -use traits::*; +use crate::base; +use crate::traits::*; pub use rustc::mir::mono::MonoItem; @@ -13,7 +13,7 @@ pub use rustc_mir::monomorphize::item::MonoItemExt as BaseMonoItemExt; pub trait MonoItemExt<'a, 'tcx: 'a>: fmt::Debug + BaseMonoItemExt<'a, 'tcx> { fn define>(&self, cx: &'a Bx::CodegenCx) { debug!("BEGIN IMPLEMENTING '{} ({})' in cgu {}", - self.to_string(cx.tcx()), + self.to_string(cx.tcx(), true), self.to_raw_string(), cx.codegen_unit().name()); @@ -45,7 +45,7 @@ pub trait MonoItemExt<'a, 'tcx: 'a>: fmt::Debug + BaseMonoItemExt<'a, 'tcx> { } debug!("END IMPLEMENTING '{} ({})' in cgu {}", - self.to_string(cx.tcx()), + self.to_string(cx.tcx(), true), self.to_raw_string(), cx.codegen_unit().name()); } @@ -57,7 +57,7 @@ pub trait MonoItemExt<'a, 'tcx: 'a>: fmt::Debug + BaseMonoItemExt<'a, 'tcx> { visibility: Visibility ) { debug!("BEGIN PREDEFINING '{} ({})' in cgu {}", - self.to_string(cx.tcx()), + self.to_string(cx.tcx(), true), self.to_raw_string(), cx.codegen_unit().name()); @@ -76,7 +76,7 @@ pub trait MonoItemExt<'a, 'tcx: 'a>: fmt::Debug + BaseMonoItemExt<'a, 'tcx> { } debug!("END PREDEFINING '{} ({})' in cgu {}", - self.to_string(cx.tcx()), + self.to_string(cx.tcx(), true), self.to_raw_string(), cx.codegen_unit().name()); } diff --git a/src/librustc_codegen_ssa/traits/asm.rs b/src/librustc_codegen_ssa/traits/asm.rs index 7fe16925a3f97..a95bf3af5bf27 100644 --- a/src/librustc_codegen_ssa/traits/asm.rs +++ b/src/librustc_codegen_ssa/traits/asm.rs @@ -1,5 +1,5 @@ use super::BackendTypes; -use mir::place::PlaceRef; +use crate::mir::place::PlaceRef; use rustc::hir::{GlobalAsm, InlineAsm}; pub trait AsmBuilderMethods<'tcx>: BackendTypes { diff --git a/src/librustc_codegen_ssa/traits/backend.rs b/src/librustc_codegen_ssa/traits/backend.rs index 8c026059dc490..73c7614d91393 100644 --- a/src/librustc_codegen_ssa/traits/backend.rs +++ b/src/librustc_codegen_ssa/traits/backend.rs @@ -6,7 +6,7 @@ use super::CodegenObject; use rustc::middle::allocator::AllocatorKind; use rustc::middle::cstore::EncodedMetadata; use rustc::mir::mono::Stats; -use rustc::session::Session; +use rustc::session::{Session, config}; use rustc::ty::TyCtxt; use rustc_codegen_utils::codegen_backend::CodegenBackend; use std::sync::Arc; @@ -32,7 +32,7 @@ impl<'tcx, T> Backend<'tcx> for T where } pub trait ExtraBackendMethods: CodegenBackend + WriteBackendMethods + Sized + Send { - fn new_metadata(&self, sess: &Session, mod_name: &str) -> Self::Module; + fn new_metadata(&self, sess: TyCtxt, mod_name: &str) -> Self::Module; fn write_metadata<'b, 'gcx>( &self, tcx: TyCtxt<'b, 'gcx, 'gcx>, @@ -50,6 +50,7 @@ pub trait ExtraBackendMethods: CodegenBackend + WriteBackendMethods + Sized + Se fn target_machine_factory( &self, sess: &Session, + opt_level: config::OptLevel, find_features: bool, ) -> Arc Result + Send + Sync>; fn target_cpu<'b>(&self, sess: &'b Session) -> &'b str; diff --git a/src/librustc_codegen_ssa/traits/builder.rs b/src/librustc_codegen_ssa/traits/builder.rs index bc66087d3ce70..bda0f3dc77966 100644 --- a/src/librustc_codegen_ssa/traits/builder.rs +++ b/src/librustc_codegen_ssa/traits/builder.rs @@ -4,13 +4,14 @@ use super::debuginfo::DebugInfoBuilderMethods; use super::intrinsic::IntrinsicCallMethods; use super::type_::ArgTypeMethods; use super::{HasCodegen, StaticBuilderMethods}; -use common::{AtomicOrdering, AtomicRmwBinOp, IntPredicate, RealPredicate, SynchronizationScope}; -use mir::operand::OperandRef; -use mir::place::PlaceRef; +use crate::common::{AtomicOrdering, AtomicRmwBinOp, IntPredicate, RealPredicate, + SynchronizationScope}; +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 MemFlags; use std::borrow::Cow; use std::ops::Range; diff --git a/src/librustc_codegen_ssa/traits/consts.rs b/src/librustc_codegen_ssa/traits/consts.rs index 482fb67e2b0c2..319f4b4e5e4b5 100644 --- a/src/librustc_codegen_ssa/traits/consts.rs +++ b/src/librustc_codegen_ssa/traits/consts.rs @@ -1,5 +1,5 @@ use super::BackendTypes; -use mir::place::PlaceRef; +use crate::mir::place::PlaceRef; use rustc::mir::interpret::Allocation; use rustc::mir::interpret::Scalar; use rustc::ty::layout; diff --git a/src/librustc_codegen_ssa/traits/debuginfo.rs b/src/librustc_codegen_ssa/traits/debuginfo.rs index 4163faa591462..0e606e744c629 100644 --- a/src/librustc_codegen_ssa/traits/debuginfo.rs +++ b/src/librustc_codegen_ssa/traits/debuginfo.rs @@ -1,5 +1,5 @@ use super::BackendTypes; -use debuginfo::{FunctionDebugContext, MirDebugScope, VariableAccess, VariableKind}; +use crate::debuginfo::{FunctionDebugContext, MirDebugScope, VariableAccess, VariableKind}; use rustc::hir::def_id::CrateNum; use rustc::mir; use rustc::ty::{self, Ty}; diff --git a/src/librustc_codegen_ssa/traits/declare.rs b/src/librustc_codegen_ssa/traits/declare.rs index 3cd3c4e48b998..6a400a7d7a45d 100644 --- a/src/librustc_codegen_ssa/traits/declare.rs +++ b/src/librustc_codegen_ssa/traits/declare.rs @@ -29,7 +29,7 @@ pub trait DeclareMethods<'tcx>: BackendTypes { /// Declare a global with an intention to define it. /// /// Use this function when you intend to define a global. This function will - /// return None if the name already has a definition associated with it. In that + /// return `None` if the name already has a definition associated with it. In that /// case an error should be reported to the user, because it usually happens due /// to user’s fault (e.g., misuse of #[no_mangle] or #[export_name] attributes). fn define_global(&self, name: &str, ty: Self::Type) -> Option; @@ -53,10 +53,10 @@ pub trait DeclareMethods<'tcx>: BackendTypes { /// can happen with #[no_mangle] or #[export_name], for example. fn define_internal_fn(&self, name: &str, fn_sig: ty::PolyFnSig<'tcx>) -> Self::Value; - /// Get declared value by name. + /// Gets declared value by name. fn get_declared_value(&self, name: &str) -> Option; - /// Get defined or externally defined (AvailableExternally linkage) value by + /// Gets defined or externally defined (AvailableExternally linkage) value by /// name. fn get_defined_value(&self, name: &str) -> Option; } diff --git a/src/librustc_codegen_ssa/traits/intrinsic.rs b/src/librustc_codegen_ssa/traits/intrinsic.rs index a2d6b0550f8ca..3cd0c39d4139a 100644 --- a/src/librustc_codegen_ssa/traits/intrinsic.rs +++ b/src/librustc_codegen_ssa/traits/intrinsic.rs @@ -1,5 +1,5 @@ use super::BackendTypes; -use mir::operand::OperandRef; +use crate::mir::operand::OperandRef; use rustc::ty::Ty; use rustc_target::abi::call::FnType; use syntax_pos::Span; diff --git a/src/librustc_codegen_ssa/traits/type_.rs b/src/librustc_codegen_ssa/traits/type_.rs index 2ec0c8e5a75cc..7c5e615f22452 100644 --- a/src/librustc_codegen_ssa/traits/type_.rs +++ b/src/librustc_codegen_ssa/traits/type_.rs @@ -1,8 +1,8 @@ use super::misc::MiscMethods; use super::Backend; use super::HasCodegen; -use common::{self, TypeKind}; -use mir::place::PlaceRef; +use crate::common::{self, TypeKind}; +use crate::mir::place::PlaceRef; use rustc::ty::layout::{self, Align, Size, TyLayout}; use rustc::ty::{self, Ty}; use rustc::util::nodemap::FxHashMap; @@ -39,13 +39,13 @@ pub trait BaseTypeMethods<'tcx>: Backend<'tcx> { fn type_ptr_to(&self, ty: Self::Type) -> Self::Type; fn element_type(&self, ty: Self::Type) -> Self::Type; - /// Return the number of elements in `self` if it is a LLVM vector type. + /// 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; - /// Retrieve the bit width of the integer type `self`. + /// 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; diff --git a/src/librustc_codegen_ssa/traits/write.rs b/src/librustc_codegen_ssa/traits/write.rs index cea89a7f99b1b..d8fb7c608c8af 100644 --- a/src/librustc_codegen_ssa/traits/write.rs +++ b/src/librustc_codegen_ssa/traits/write.rs @@ -1,6 +1,6 @@ -use back::lto::{LtoModuleCodegen, SerializedModule, ThinModule}; -use back::write::{CodegenContext, ModuleConfig}; -use {CompiledModule, ModuleCodegen}; +use crate::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule}; +use crate::back::write::{CodegenContext, ModuleConfig, FatLTOInput}; +use crate::{CompiledModule, ModuleCodegen}; use rustc::dep_graph::WorkProduct; use rustc::util::time_graph::Timeline; @@ -18,7 +18,8 @@ pub trait WriteBackendMethods: 'static + Sized + Clone { /// for further optimization. fn run_fat_lto( cgcx: &CodegenContext, - modules: Vec>, + modules: Vec>, + cached_modules: Vec<(SerializedModule, WorkProduct)>, timeline: &mut Timeline, ) -> Result, FatalError>; /// Performs thin LTO by performing necessary global analysis and returning two @@ -51,9 +52,11 @@ pub trait WriteBackendMethods: 'static + Sized + Clone { timeline: &mut Timeline, ) -> Result; fn prepare_thin( - cgcx: &CodegenContext, module: ModuleCodegen ) -> (String, Self::ThinBuffer); + fn serialize_module( + module: ModuleCodegen + ) -> (String, Self::ModuleBuffer); fn run_lto_pass_manager( cgcx: &CodegenContext, llmod: &ModuleCodegen, diff --git a/src/librustc_codegen_utils/Cargo.toml b/src/librustc_codegen_utils/Cargo.toml index 34a09f30b6411..5f241eb20fb55 100644 --- a/src/librustc_codegen_utils/Cargo.toml +++ b/src/librustc_codegen_utils/Cargo.toml @@ -2,6 +2,7 @@ authors = ["The Rust Project Developers"] name = "rustc_codegen_utils" version = "0.0.0" +edition = "2018" [lib] name = "rustc_codegen_utils" diff --git a/src/librustc_codegen_utils/codegen_backend.rs b/src/librustc_codegen_utils/codegen_backend.rs index 8981c542961e2..28d7d18422841 100644 --- a/src/librustc_codegen_utils/codegen_backend.rs +++ b/src/librustc_codegen_utils/codegen_backend.rs @@ -4,9 +4,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", - html_favicon_url = "https://doc.rust-lang.org/favicon.ico", - html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] #![deny(warnings)] #![feature(box_syntax)] @@ -31,7 +29,7 @@ use rustc::middle::cstore::EncodedMetadata; use rustc::middle::cstore::MetadataLoader; use rustc::dep_graph::DepGraph; use rustc_target::spec::Target; -use link::out_filename; +use crate::link::out_filename; pub use rustc_data_structures::sync::MetadataRef; @@ -44,8 +42,8 @@ pub trait CodegenBackend { fn diagnostics(&self) -> &[(&'static str, &'static str)] { &[] } fn metadata_loader(&self) -> Box; - fn provide(&self, _providers: &mut Providers); - fn provide_extern(&self, _providers: &mut Providers); + fn provide(&self, _providers: &mut Providers<'_>); + fn provide_extern(&self, _providers: &mut Providers<'_>); fn codegen_crate<'a, 'tcx>( &self, tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -111,8 +109,8 @@ impl CodegenBackend for MetadataOnlyCodegenBackend { box NoLlvmMetadataLoader } - fn provide(&self, providers: &mut Providers) { - ::symbol_names::provide(providers); + fn provide(&self, providers: &mut Providers<'_>) { + crate::symbol_names::provide(providers); providers.target_features_whitelist = |_tcx, _cnum| { Default::default() // Just a dummy @@ -120,7 +118,7 @@ impl CodegenBackend for MetadataOnlyCodegenBackend { providers.is_reachable_non_generic = |_tcx, _defid| true; providers.exported_symbols = |_tcx, _crate| Arc::new(Vec::new()); } - fn provide_extern(&self, providers: &mut Providers) { + fn provide_extern(&self, providers: &mut Providers<'_>) { providers.is_reachable_non_generic = |_tcx, _defid| true; } @@ -131,12 +129,12 @@ impl CodegenBackend for MetadataOnlyCodegenBackend { ) -> Box { use rustc_mir::monomorphize::item::MonoItem; - ::check_for_rustc_errors_attr(tcx); - ::symbol_names_test::report_symbol_names(tcx); - ::rustc_incremental::assert_dep_graph(tcx); - ::rustc_incremental::assert_module_sources::assert_module_sources(tcx); + 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); + // 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); diff --git a/src/librustc_codegen_utils/lib.rs b/src/librustc_codegen_utils/lib.rs index b59bca0ae0edb..2b70141894be9 100644 --- a/src/librustc_codegen_utils/lib.rs +++ b/src/librustc_codegen_utils/lib.rs @@ -2,35 +2,26 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", - html_favicon_url = "https://doc.rust-lang.org/favicon.ico", - html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] #![feature(box_patterns)] #![feature(box_syntax)] #![feature(custom_attribute)] #![feature(nll)] #![allow(unused_attributes)] -#![feature(quote)] #![feature(rustc_diagnostic_macros)] +#![feature(in_band_lifetimes)] #![recursion_limit="256"] -extern crate flate2; -#[macro_use] -extern crate log; +#![deny(rust_2018_idioms)] #[macro_use] extern crate rustc; -extern crate rustc_target; -extern crate rustc_metadata; -extern crate rustc_mir; -extern crate rustc_incremental; -extern crate syntax; -extern crate syntax_pos; #[macro_use] extern crate rustc_data_structures; use rustc::ty::TyCtxt; +use rustc::hir::def_id::LOCAL_CRATE; pub mod link; pub mod codegen_backend; @@ -41,12 +32,10 @@ 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) { - if let Some((id, span, _)) = *tcx.sess.entry_fn.borrow() { - let main_def_id = tcx.hir().local_def_id(id); - - if tcx.has_attr(main_def_id, "rustc_error") { - tcx.sess.span_fatal(span, "compilation successful"); +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") { + 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 09e22bd2c91a9..f3a1b219f8a84 100644 --- a/src/librustc_codegen_utils/link.rs +++ b/src/librustc_codegen_utils/link.rs @@ -41,7 +41,7 @@ pub fn find_crate_name(sess: Option<&Session>, attrs: &[ast::Attribute], input: &Input) -> String { let validate = |s: String, span: Option| { - ::rustc_metadata::validate_crate_name(sess, &s, span); + rustc_metadata::validate_crate_name(sess, &s, span); s }; diff --git a/src/librustc_codegen_utils/symbol_names.rs b/src/librustc_codegen_utils/symbol_names.rs index 9267f14f24234..8d105853d92f1 100644 --- a/src/librustc_codegen_utils/symbol_names.rs +++ b/src/librustc_codegen_utils/symbol_names.rs @@ -103,10 +103,12 @@ use rustc_mir::monomorphize::Instance; use syntax_pos::symbol::Symbol; +use log::debug; + use std::fmt::Write; use std::mem::discriminant; -pub fn provide(providers: &mut Providers) { +pub fn provide(providers: &mut Providers<'_>) { *providers = Providers { def_symbol_name, symbol_name, @@ -221,7 +223,7 @@ fn get_symbol_hash<'a, 'tcx>( } fn def_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ty::SymbolName { - let mut buffer = SymbolPathBuffer::new(); + let mut buffer = SymbolPathBuffer::new(tcx); item_path::with_forced_absolute_paths(|| { tcx.push_item_path(&mut buffer, def_id, false); }); @@ -317,7 +319,7 @@ fn compute_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance let hash = get_symbol_hash(tcx, def_id, instance, instance_ty, substs); - let mut buf = SymbolPathBuffer::from_interned(tcx.def_symbol_name(def_id)); + let mut buf = SymbolPathBuffer::from_interned(tcx.def_symbol_name(def_id), tcx); if instance.is_vtable_shim() { buf.push("{{vtable-shim}}"); @@ -343,22 +345,25 @@ fn compute_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance struct SymbolPathBuffer { result: String, temp_buf: String, + strict_naming: bool, } impl SymbolPathBuffer { - fn new() -> Self { + 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) -> Self { + 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(), }; result.result.push_str(&symbol.as_str()); result @@ -375,68 +380,88 @@ impl SymbolPathBuffer { let _ = write!(self.result, "17h{:016x}E", hash); self.result } -} -impl ItemPathBuffer for SymbolPathBuffer { - fn root_mode(&self) -> &RootMode { - const ABSOLUTE: &RootMode = &RootMode::Absolute; - ABSOLUTE - } - - fn push(&mut self, text: &str) { + // 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(); - let need_underscore = sanitize(&mut self.temp_buf, text); + + 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), + + _ => { + self.temp_buf.push('$'); + for c in c.escape_unicode().skip(1) { + match c { + '{' => {} + '}' => self.temp_buf.push('$'), + c => self.temp_buf.push(c), + } + } + } + } + } + + 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('_'); } + self.result.push_str(&self.temp_buf); } } -// 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, ., _, $ -// -// returns true if an underscore must be added at the start -pub fn sanitize(result: &mut String, s: &str) -> bool { - for c in s.chars() { - match c { - // Escape these with $ sequences - '@' => result.push_str("$SP$"), - '*' => result.push_str("$BP$"), - '&' => result.push_str("$RF$"), - '<' => result.push_str("$LT$"), - '>' => result.push_str("$GT$"), - '(' => result.push_str("$LP$"), - ')' => result.push_str("$RP$"), - ',' => result.push_str("$C$"), - - // '.' doesn't occur in types and functions, so reuse it - // for ':' and '-' - '-' | ':' => result.push('.'), - - // These are legal symbols - 'a'..='z' | 'A'..='Z' | '0'..='9' | '_' | '.' | '$' => result.push(c), - - _ => { - result.push('$'); - for c in c.escape_unicode().skip(1) { - match c { - '{' => {} - '}' => result.push('$'), - c => result.push(c), - } - } - } - } +impl ItemPathBuffer for SymbolPathBuffer { + fn root_mode(&self) -> &RootMode { + const ABSOLUTE: &RootMode = &RootMode::Absolute; + ABSOLUTE } - // Underscore-qualify anything that didn't start as an ident. - !result.is_empty() && result.as_bytes()[0] != '_' as u8 - && !(result.as_bytes()[0] as char).is_xid_start() + fn push(&mut self, text: &str) { + self.sanitize_and_append(text); + } } diff --git a/src/librustc_cratesio_shim/Cargo.toml b/src/librustc_cratesio_shim/Cargo.toml index b8e494e4040ec..6bdfbe09354b4 100644 --- a/src/librustc_cratesio_shim/Cargo.toml +++ b/src/librustc_cratesio_shim/Cargo.toml @@ -15,6 +15,7 @@ authors = ["The Rust Project Developers"] name = "rustc_cratesio_shim" version = "0.0.0" +edition = "2018" [lib] crate-type = ["dylib"] diff --git a/src/librustc_cratesio_shim/src/lib.rs b/src/librustc_cratesio_shim/src/lib.rs index 4024087f4d3ef..4c170f4f5f6f9 100644 --- a/src/librustc_cratesio_shim/src/lib.rs +++ b/src/librustc_cratesio_shim/src/lib.rs @@ -1,3 +1,5 @@ +#![deny(rust_2018_idioms)] + // See Cargo.toml for a comment explaining this crate. #![allow(unused_extern_crates)] diff --git a/src/librustc_data_structures/Cargo.toml b/src/librustc_data_structures/Cargo.toml index 1754376a5d7f9..f781952d4172c 100644 --- a/src/librustc_data_structures/Cargo.toml +++ b/src/librustc_data_structures/Cargo.toml @@ -2,6 +2,7 @@ authors = ["The Rust Project Developers"] name = "rustc_data_structures" version = "0.0.0" +edition = "2018" [lib] name = "rustc_data_structures" @@ -16,8 +17,8 @@ serialize = { path = "../libserialize" } graphviz = { path = "../libgraphviz" } cfg-if = "0.1.2" stable_deref_trait = "1.0.0" -rustc-rayon = "0.1.1" -rustc-rayon-core = "0.1.1" +rayon = { version = "0.1.1", package = "rustc-rayon" } +rayon-core = { version = "0.1.1", 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/base_n.rs b/src/librustc_data_structures/base_n.rs index c9c1933f25b2b..f1bd3f03aef8d 100644 --- a/src/librustc_data_structures/base_n.rs +++ b/src/librustc_data_structures/base_n.rs @@ -1,4 +1,4 @@ -/// Convert unsigned integers into a string representation with some base. +/// Converts unsigned integers into a string representation with some base. /// Bases up to and including 36 can be used for case-insensitive things. use std::str; diff --git a/src/librustc_data_structures/bit_set.rs b/src/librustc_data_structures/bit_set.rs index 8adfe3749af8e..ff7964646d608 100644 --- a/src/librustc_data_structures/bit_set.rs +++ b/src/librustc_data_structures/bit_set.rs @@ -1,4 +1,4 @@ -use indexed_vec::{Idx, IndexVec}; +use crate::indexed_vec::{Idx, IndexVec}; use smallvec::SmallVec; use std::fmt; use std::iter; @@ -27,7 +27,7 @@ pub struct BitSet { } impl BitSet { - /// Create a new, empty bitset with a given `domain_size`. + /// Creates a new, empty bitset with a given `domain_size`. #[inline] pub fn new_empty(domain_size: usize) -> BitSet { let num_words = num_words(domain_size); @@ -38,7 +38,7 @@ impl BitSet { } } - /// Create a new, filled bitset with a given `domain_size`. + /// Creates a new, filled bitset with a given `domain_size`. #[inline] pub fn new_filled(domain_size: usize) -> BitSet { let num_words = num_words(domain_size); @@ -51,7 +51,7 @@ impl BitSet { result } - /// Get the domain size. + /// Gets the domain size. pub fn domain_size(&self) -> usize { self.domain_size } @@ -85,7 +85,7 @@ impl BitSet { self.words.iter().map(|e| e.count_ones() as usize).sum() } - /// True if `self` contains `elem`. + /// Returns `true` if `self` contains `elem`. #[inline] pub fn contains(&self, elem: T) -> bool { assert!(elem.index() < self.domain_size); @@ -106,7 +106,7 @@ impl BitSet { self.words.iter().all(|a| *a == 0) } - /// Insert `elem`. Returns true if the set has changed. + /// Insert `elem`. Returns whether the set has changed. #[inline] pub fn insert(&mut self, elem: T) -> bool { assert!(elem.index() < self.domain_size); @@ -126,7 +126,7 @@ impl BitSet { self.clear_excess_bits(); } - /// Returns true if the set has changed. + /// Returns `true` if the set has changed. #[inline] pub fn remove(&mut self, elem: T) -> bool { assert!(elem.index() < self.domain_size); @@ -138,26 +138,26 @@ impl BitSet { new_word != word } - /// Set `self = self | other` and return true if `self` changed + /// Sets `self = self | other` and returns `true` if `self` changed /// (i.e., if new bits were added). pub fn union(&mut self, other: &impl UnionIntoBitSet) -> bool { other.union_into(self) } - /// Set `self = self - other` and return true if `self` changed. + /// Sets `self = self - other` and returns `true` if `self` changed. /// (i.e., if any bits were removed). pub fn subtract(&mut self, other: &impl SubtractFromBitSet) -> bool { other.subtract_from(self) } - /// Set `self = self & other` and return true if `self` changed. + /// Sets `self = self & other` and return `true` if `self` changed. /// (i.e., if any bits were removed). pub fn intersect(&mut self, other: &BitSet) -> bool { assert_eq!(self.domain_size, other.domain_size); bitwise(&mut self.words, &other.words, |a, b| { a & b }) } - /// Get a slice of the underlying words. + /// Gets a slice of the underlying words. pub fn words(&self) -> &[Word] { &self.words } @@ -208,7 +208,7 @@ impl SubtractFromBitSet for BitSet { } impl fmt::Debug for BitSet { - fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result { w.debug_list() .entries(self.iter()) .finish() @@ -366,7 +366,7 @@ impl SparseBitSet { dense } - fn iter(&self) -> slice::Iter { + fn iter(&self) -> slice::Iter<'_, T> { self.elems.iter() } } @@ -536,7 +536,7 @@ impl HybridBitSet { } } - pub fn iter(&self) -> HybridIter { + pub fn iter(&self) -> HybridIter<'_, T> { match self { HybridBitSet::Sparse(sparse) => HybridIter::Sparse(sparse.iter()), HybridBitSet::Dense(dense) => HybridIter::Dense(dense.iter()), @@ -611,7 +611,7 @@ impl GrowableBitSet { GrowableBitSet { bit_set: BitSet::new_empty(bits) } } - /// Returns true if the set has changed. + /// Returns `true` if the set has changed. #[inline] pub fn insert(&mut self, elem: T) -> bool { self.ensure(elem.index() + 1); @@ -645,7 +645,7 @@ pub struct BitMatrix { } impl BitMatrix { - /// Create a new `rows x columns` matrix, initially empty. + /// Creates a new `rows x columns` matrix, initially empty. pub fn new(num_rows: usize, num_columns: usize) -> BitMatrix { // For every element, we need one bit for every other // element. Round up to an even number of words. @@ -668,7 +668,7 @@ impl BitMatrix { /// Sets the cell at `(row, column)` to true. Put another way, insert /// `column` to the bitset for `row`. /// - /// Returns true if this changed the matrix, and false otherwise. + /// Returns `true` if this changed the matrix. pub fn insert(&mut self, row: R, column: C) -> bool { assert!(row.index() < self.num_rows && column.index() < self.num_columns); let (start, _) = self.range(row); @@ -691,7 +691,7 @@ impl BitMatrix { (self.words[start + word_index] & mask) != 0 } - /// Returns those indices that are true in rows `a` and `b`. This + /// Returns those indices that are true in rows `a` and `b`. This /// is an O(n) operation where `n` is the number of elements /// (somewhat independent from the actual size of the /// intersection, in particular). @@ -715,8 +715,8 @@ impl BitMatrix { result } - /// Add the bits from row `read` to the bits from row `write`, - /// return true if anything changed. + /// Adds the bits from row `read` to the bits from row `write`, and + /// returns `true` if anything changed. /// /// This is used when computing transitive reachability because if /// you have an edge `write -> read`, because in that case @@ -772,7 +772,7 @@ where } impl SparseBitMatrix { - /// Create a new empty sparse bit matrix with no rows or columns. + /// Creates a new empty sparse bit matrix with no rows or columns. pub fn new(num_columns: usize) -> Self { Self { num_columns, @@ -793,7 +793,7 @@ impl SparseBitMatrix { /// Sets the cell at `(row, column)` to true. Put another way, insert /// `column` to the bitset for `row`. /// - /// Returns true if this changed the matrix, and false otherwise. + /// Returns `true` if this changed the matrix. pub fn insert(&mut self, row: R, column: C) -> bool { self.ensure_row(row).insert(column) } @@ -806,8 +806,8 @@ impl SparseBitMatrix { self.row(row).map_or(false, |r| r.contains(column)) } - /// Add the bits from row `read` to the bits from row `write`, - /// return true if anything changed. + /// Adds the bits from row `read` to the bits from row `write`, and + /// returns `true` if anything changed. /// /// This is used when computing transitive reachability because if /// you have an edge `write -> read`, because in that case diff --git a/src/librustc_data_structures/fingerprint.rs b/src/librustc_data_structures/fingerprint.rs index 2e596ca3e44f1..c4c0db5801209 100644 --- a/src/librustc_data_structures/fingerprint.rs +++ b/src/librustc_data_structures/fingerprint.rs @@ -1,5 +1,5 @@ +use crate::stable_hasher; use std::mem; -use stable_hasher; use serialize; use serialize::opaque::{EncodeResult, Encoder, Decoder}; @@ -70,7 +70,7 @@ impl Fingerprint { } impl ::std::fmt::Display for Fingerprint { - fn fmt(&self, formatter: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, formatter: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { write!(formatter, "{:x}-{:x}", self.0, self.1) } } diff --git a/src/librustc_data_structures/flock.rs b/src/librustc_data_structures/flock.rs index 2dea249f1c07c..255c5fd7fe7ec 100644 --- a/src/librustc_data_structures/flock.rs +++ b/src/librustc_data_structures/flock.rs @@ -14,12 +14,9 @@ cfg_if! { if #[cfg(unix)] { use std::ffi::{CString, OsStr}; use std::os::unix::prelude::*; - use libc; #[cfg(any(target_os = "linux", target_os = "android"))] mod os { - use libc; - #[repr(C)] pub struct flock { pub l_type: libc::c_short, @@ -35,8 +32,6 @@ cfg_if! { #[cfg(target_os = "freebsd")] mod os { - use libc; - #[repr(C)] pub struct flock { pub l_start: libc::off_t, @@ -53,8 +48,6 @@ cfg_if! { target_os = "netbsd", target_os = "openbsd"))] mod os { - use libc; - #[repr(C)] pub struct flock { pub l_start: libc::off_t, @@ -70,8 +63,6 @@ cfg_if! { #[cfg(target_os = "haiku")] mod os { - use libc; - #[repr(C)] pub struct flock { pub l_type: libc::c_short, @@ -87,8 +78,6 @@ cfg_if! { #[cfg(any(target_os = "macos", target_os = "ios"))] mod os { - use libc; - #[repr(C)] pub struct flock { pub l_start: libc::off_t, @@ -104,8 +93,6 @@ cfg_if! { #[cfg(target_os = "solaris")] mod os { - use libc; - #[repr(C)] pub struct flock { pub l_type: libc::c_short, diff --git a/src/librustc_data_structures/graph/dominators/mod.rs b/src/librustc_data_structures/graph/dominators/mod.rs index 536efffbb22f4..aaed41d9fa362 100644 --- a/src/librustc_data_structures/graph/dominators/mod.rs +++ b/src/librustc_data_structures/graph/dominators/mod.rs @@ -117,7 +117,7 @@ impl Dominators { self.immediate_dominators[node].unwrap() } - pub fn dominators(&self, node: Node) -> Iter { + pub fn dominators(&self, node: Node) -> Iter<'_, Node> { assert!(self.is_reachable(node), "node {:?} is not reachable", node); Iter { dominators: self, @@ -136,7 +136,7 @@ impl Dominators { } } -pub struct Iter<'dom, Node: Idx + 'dom> { +pub struct Iter<'dom, Node: Idx> { dominators: &'dom Dominators, node: Option, } @@ -171,7 +171,7 @@ impl DominatorTree { } impl fmt::Debug for DominatorTree { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt( &DominatorTreeNode { tree: self, @@ -188,7 +188,7 @@ struct DominatorTreeNode<'tree, Node: Idx> { } impl<'tree, Node: Idx> fmt::Debug for DominatorTreeNode<'tree, Node> { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { let subtrees: Vec<_> = self.tree .children(self.node) .iter() diff --git a/src/librustc_data_structures/graph/implementation/mod.rs b/src/librustc_data_structures/graph/implementation/mod.rs index 0768873f83626..de4b1bcd0c2a1 100644 --- a/src/librustc_data_structures/graph/implementation/mod.rs +++ b/src/librustc_data_structures/graph/implementation/mod.rs @@ -14,16 +14,16 @@ //! stored. The edges are stored in a central array, but they are also //! threaded onto two linked lists for each node, one for incoming edges //! and one for outgoing edges. Note that every edge is a member of some -//! incoming list and some outgoing list. Basically you can load the +//! incoming list and some outgoing list. Basically you can load the //! first index of the linked list from the node data structures (the //! field `first_edge`) and then, for each edge, load the next index from //! the field `next_edge`). Each of those fields is an array that should //! be indexed by the direction (see the type `Direction`). -use bit_set::BitSet; +use crate::bit_set::BitSet; +use crate::snapshot_vec::{SnapshotVec, SnapshotVecDelegate}; use std::fmt::Debug; use std::usize; -use snapshot_vec::{SnapshotVec, SnapshotVecDelegate}; #[cfg(test)] mod tests; @@ -79,7 +79,7 @@ pub const OUTGOING: Direction = Direction { repr: 0 }; pub const INCOMING: Direction = Direction { repr: 1 }; impl NodeIndex { - /// Returns unique id (unique with respect to the graph holding associated node). + /// Returns unique ID (unique with respect to the graph holding associated node). pub fn node_id(self) -> usize { self.0 } @@ -212,15 +212,19 @@ impl Graph { .all(|(edge_idx, edge)| f(edge_idx, edge)) } - pub fn outgoing_edges(&self, source: NodeIndex) -> AdjacentEdges { + pub fn outgoing_edges(&self, source: NodeIndex) -> AdjacentEdges<'_, N, E> { self.adjacent_edges(source, OUTGOING) } - pub fn incoming_edges(&self, source: NodeIndex) -> AdjacentEdges { + pub fn incoming_edges(&self, source: NodeIndex) -> AdjacentEdges<'_, N, E> { self.adjacent_edges(source, INCOMING) } - pub fn adjacent_edges(&self, source: NodeIndex, direction: Direction) -> AdjacentEdges { + pub fn adjacent_edges( + &self, + source: NodeIndex, + direction: Direction + ) -> AdjacentEdges<'_, N, E> { let first_edge = self.node(source).first_edge[direction.repr]; AdjacentEdges { graph: self, @@ -291,11 +295,7 @@ impl Graph { // # Iterators -pub struct AdjacentEdges<'g, N, E> -where - N: 'g, - E: 'g, -{ +pub struct AdjacentEdges<'g, N, E> { graph: &'g Graph, direction: Direction, next: EdgeIndex, @@ -331,11 +331,7 @@ impl<'g, N: Debug, E: Debug> Iterator for AdjacentEdges<'g, N, E> { } } -pub struct DepthFirstTraversal<'g, N, E> -where - N: 'g, - E: 'g, -{ +pub struct DepthFirstTraversal<'g, N, E> { graph: &'g Graph, stack: Vec, visited: BitSet, diff --git a/src/librustc_data_structures/graph/implementation/tests.rs b/src/librustc_data_structures/graph/implementation/tests.rs index a7a2504239610..82c6da3f42711 100644 --- a/src/librustc_data_structures/graph/implementation/tests.rs +++ b/src/librustc_data_structures/graph/implementation/tests.rs @@ -1,4 +1,4 @@ -use graph::implementation::*; +use crate::graph::implementation::*; use std::fmt::Debug; type TestGraph = Graph<&'static str, &'static str>; diff --git a/src/librustc_data_structures/graph/scc/mod.rs b/src/librustc_data_structures/graph/scc/mod.rs index baab377ef1276..24c5448639e7d 100644 --- a/src/librustc_data_structures/graph/scc/mod.rs +++ b/src/librustc_data_structures/graph/scc/mod.rs @@ -3,9 +3,9 @@ //! node in the graph. This uses Tarjan's algorithm that completes in //! O(n) time. -use fx::FxHashSet; -use graph::{DirectedGraph, WithNumNodes, WithSuccessors}; -use indexed_vec::{Idx, IndexVec}; +use crate::fx::FxHashSet; +use crate::graph::{DirectedGraph, WithNumNodes, WithSuccessors}; +use crate::indexed_vec::{Idx, IndexVec}; use std::ops::Range; mod test; @@ -93,7 +93,7 @@ impl SccData { } } -struct SccsConstruction<'c, G: DirectedGraph + WithNumNodes + WithSuccessors + 'c, S: Idx> { +struct SccsConstruction<'c, G: DirectedGraph + WithNumNodes + WithSuccessors, S: Idx> { graph: &'c G, /// The state of each node; used during walk to record the stack @@ -200,7 +200,7 @@ where } } - /// Visit a node during the DFS. We first examine its current + /// Visits a node during the DFS. We first examine its current /// state -- if it is not yet visited (`NotVisited`), we can push /// it onto the stack and start walking its successors. /// diff --git a/src/librustc_data_structures/graph/scc/test.rs b/src/librustc_data_structures/graph/scc/test.rs index e23cb1348b015..da3a1ceefe94b 100644 --- a/src/librustc_data_structures/graph/scc/test.rs +++ b/src/librustc_data_structures/graph/scc/test.rs @@ -1,6 +1,6 @@ #![cfg(test)] -use graph::test::TestGraph; +use crate::graph::test::TestGraph; use super::*; #[test] diff --git a/src/librustc_data_structures/graph/test.rs b/src/librustc_data_structures/graph/test.rs index 3d482e448bdb7..b390c41957294 100644 --- a/src/librustc_data_structures/graph/test.rs +++ b/src/librustc_data_structures/graph/test.rs @@ -1,4 +1,4 @@ -use fx::FxHashMap; +use crate::fx::FxHashMap; use std::cmp::max; use std::slice; use std::iter; diff --git a/src/librustc_data_structures/indexed_vec.rs b/src/librustc_data_structures/indexed_vec.rs index 8d8fbe588a021..09aec50e4bb11 100644 --- a/src/librustc_data_structures/indexed_vec.rs +++ b/src/librustc_data_structures/indexed_vec.rs @@ -12,7 +12,7 @@ use rustc_serialize as serialize; /// Represents some newtyped `usize` wrapper. /// -/// (purpose: avoid mixing indexes for different bitvector domains.) +/// Purpose: avoid mixing indexes for different bitvector domains. pub trait Idx: Copy + 'static + Ord + Debug + Hash { fn new(idx: usize) -> Self; @@ -144,19 +144,19 @@ macro_rules! newtype_index { unsafe { $type { private: value } } } - /// Extract value of this index as an integer. + /// Extracts the value of this index as an integer. #[inline] $v fn index(self) -> usize { self.as_usize() } - /// Extract value of this index as a usize. + /// Extracts the value of this index as a `u32`. #[inline] $v fn as_u32(self) -> u32 { self.private } - /// Extract value of this index as a u32. + /// Extracts the value of this index as a `usize`. #[inline] $v fn as_usize(self) -> usize { self.as_u32() as usize @@ -257,7 +257,7 @@ macro_rules! newtype_index { @type [$type:ident] @debug_format [$debug_format:tt]) => ( impl ::std::fmt::Debug for $type { - fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { write!(fmt, $debug_format, self.as_u32()) } } @@ -495,7 +495,7 @@ impl serialize::Decodable for IndexVec { } impl fmt::Debug for IndexVec { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&self.raw, fmt) } } @@ -573,7 +573,7 @@ impl IndexVec { } #[inline] - pub fn iter(&self) -> slice::Iter { + pub fn iter(&self) -> slice::Iter<'_, T> { self.raw.iter() } @@ -589,7 +589,7 @@ impl IndexVec { } #[inline] - pub fn iter_mut(&mut self) -> slice::IterMut { + pub fn iter_mut(&mut self) -> slice::IterMut<'_, T> { self.raw.iter_mut() } @@ -641,7 +641,7 @@ impl IndexVec { self.raw.get_mut(index.index()) } - /// Return mutable references to two distinct elements, a and b. Panics if a == b. + /// Returns mutable references to two distinct elements, a and b. Panics if a == b. #[inline] pub fn pick2_mut(&mut self, a: I, b: I) -> (&mut T, &mut T) { let (ai, bi) = (a.index(), b.index()); diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index ec71f5158948c..2bfb1b24a81b9 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -6,9 +6,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", - html_favicon_url = "https://www.rust-lang.org/favicon.ico", - html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] #![feature(in_band_lifetimes)] #![feature(unboxed_closures)] @@ -26,23 +24,16 @@ #![cfg_attr(unix, feature(libc))] #![cfg_attr(test, feature(test))] -extern crate core; -extern crate ena; +#![deny(rust_2018_idioms)] + #[macro_use] extern crate log; +#[allow(unused_extern_crates)] extern crate serialize as rustc_serialize; // used by deriving #[cfg(unix)] extern crate libc; -extern crate parking_lot; #[macro_use] extern crate cfg_if; -extern crate stable_deref_trait; -extern crate rustc_rayon as rayon; -extern crate rustc_rayon_core as rayon_core; -extern crate rustc_hash; -extern crate serialize; -extern crate graphviz; -extern crate smallvec; // See librustc_cratesio_shim/Cargo.toml for a comment explaining this. #[allow(unused_extern_crates)] @@ -50,6 +41,12 @@ extern crate rustc_cratesio_shim; pub use rustc_serialize::hex::ToHex; +#[inline(never)] +#[cold] +pub fn cold_path R, R>(f: F) -> R { + f() +} + #[macro_export] macro_rules! likely { ($e:expr) => { diff --git a/src/librustc_data_structures/macros.rs b/src/librustc_data_structures/macros.rs index a661f0c78ab5d..af1f2910461ec 100644 --- a/src/librustc_data_structures/macros.rs +++ b/src/librustc_data_structures/macros.rs @@ -1,7 +1,8 @@ /// A simple static assertion macro. The first argument should be a unique /// ALL_CAPS identifier that describes the condition. #[macro_export] -#[allow_internal_unstable] +#[cfg_attr(stage0, allow_internal_unstable)] +#[cfg_attr(not(stage0), allow_internal_unstable(type_ascription))] macro_rules! static_assert { ($name:ident: $test:expr) => { // Use the bool to access an array such that if the bool is false, the access diff --git a/src/librustc_data_structures/obligation_forest/README.md b/src/librustc_data_structures/obligation_forest/README.md deleted file mode 100644 index 982a2bacce164..0000000000000 --- a/src/librustc_data_structures/obligation_forest/README.md +++ /dev/null @@ -1,81 +0,0 @@ -The `ObligationForest` is a utility data structure used in trait -matching to track the set of outstanding obligations (those not yet -resolved to success or error). It also tracks the "backtrace" of each -pending obligation (why we are trying to figure this out in the first -place). - -### External view - -`ObligationForest` supports two main public operations (there are a -few others not discussed here): - -1. Add a new root obligations (`push_tree`). -2. Process the pending obligations (`process_obligations`). - -When a new obligation `N` is added, it becomes the root of an -obligation tree. This tree can also carry some per-tree state `T`, -which is given at the same time. This tree is a singleton to start, so -`N` is both the root and the only leaf. Each time the -`process_obligations` method is called, it will invoke its callback -with every pending obligation (so that will include `N`, the first -time). The callback also receives a (mutable) reference to the -per-tree state `T`. The callback should process the obligation `O` -that it is given and return one of three results: - -- `Ok(None)` -> ambiguous result. Obligation was neither a success - nor a failure. It is assumed that further attempts to process the - obligation will yield the same result unless something in the - surrounding environment changes. -- `Ok(Some(C))` - the obligation was *shallowly successful*. The - vector `C` is a list of subobligations. The meaning of this is that - `O` was successful on the assumption that all the obligations in `C` - are also successful. Therefore, `O` is only considered a "true" - success if `C` is empty. Otherwise, `O` is put into a suspended - state and the obligations in `C` become the new pending - obligations. They will be processed the next time you call - `process_obligations`. -- `Err(E)` -> obligation failed with error `E`. We will collect this - error and return it from `process_obligations`, along with the - "backtrace" of obligations (that is, the list of obligations up to - and including the root of the failed obligation). No further - obligations from that same tree will be processed, since the tree is - now considered to be in error. - -When the call to `process_obligations` completes, you get back an `Outcome`, -which includes three bits of information: - -- `completed`: a list of obligations where processing was fully - completed without error (meaning that all transitive subobligations - have also been completed). So, for example, if the callback from - `process_obligations` returns `Ok(Some(C))` for some obligation `O`, - then `O` will be considered completed right away if `C` is the - empty vector. Otherwise it will only be considered completed once - all the obligations in `C` have been found completed. -- `errors`: a list of errors that occurred and associated backtraces - at the time of error, which can be used to give context to the user. -- `stalled`: if true, then none of the existing obligations were - *shallowly successful* (that is, no callback returned `Ok(Some(_))`). - This implies that all obligations were either errors or returned an - ambiguous result, which means that any further calls to - `process_obligations` would simply yield back further ambiguous - results. This is used by the `FulfillmentContext` to decide when it - has reached a steady state. - -#### Snapshots - -The `ObligationForest` supports a limited form of snapshots; see -`start_snapshot`; `commit_snapshot`; and `rollback_snapshot`. In -particular, you can use a snapshot to roll back new root -obligations. However, it is an error to attempt to -`process_obligations` during a snapshot. - -### Implementation details - -For the most part, comments specific to the implementation are in the -code. This file only contains a very high-level overview. Basically, -the forest is stored in a vector. Each element of the vector is a node -in some tree. Each node in the vector has the index of an (optional) -parent and (for convenience) its root (which may be itself). It also -has a current state, described by `NodeState`. After each -processing step, we compress the vector to remove completed and error -nodes, which aren't needed anymore. diff --git a/src/librustc_data_structures/obligation_forest/graphviz.rs b/src/librustc_data_structures/obligation_forest/graphviz.rs index c2e3938b305d2..a0363e165e049 100644 --- a/src/librustc_data_structures/obligation_forest/graphviz.rs +++ b/src/librustc_data_structures/obligation_forest/graphviz.rs @@ -1,5 +1,5 @@ +use crate::obligation_forest::{ForestObligation, ObligationForest}; use graphviz as dot; -use obligation_forest::{ForestObligation, ObligationForest}; use std::env::var_os; use std::fs::File; use std::path::Path; @@ -7,8 +7,8 @@ use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering; impl ObligationForest { - /// Create a graphviz representation of the obligation forest. Given a directory this will - /// create files with name of the format `_.gv`. The counter is + /// Creates a graphviz representation of the obligation forest. Given a directory this will + /// create files with name of the format `_.gv`. The counter is /// global and is maintained internally. /// /// Calling this will do nothing unless the environment variable @@ -41,22 +41,22 @@ impl<'a, O: ForestObligation + 'a> dot::Labeller<'a> for &'a ObligationForest type Node = usize; type Edge = (usize, usize); - fn graph_id(&self) -> dot::Id { + fn graph_id(&self) -> dot::Id<'_> { dot::Id::new("trait_obligation_forest").unwrap() } - fn node_id(&self, index: &Self::Node) -> dot::Id { + fn node_id(&self, index: &Self::Node) -> dot::Id<'_> { dot::Id::new(format!("obligation_{}", index)).unwrap() } - fn node_label(&self, index: &Self::Node) -> dot::LabelText { + fn node_label(&self, index: &Self::Node) -> dot::LabelText<'_> { let node = &self.nodes[*index]; let label = format!("{:?} ({:?})", node.obligation.as_predicate(), node.state.get()); dot::LabelText::LabelStr(label.into()) } - fn edge_label(&self, (_index_source, _index_target): &Self::Edge) -> dot::LabelText { + fn edge_label(&self, (_index_source, _index_target): &Self::Edge) -> dot::LabelText<'_> { dot::LabelText::LabelStr("".into()) } } @@ -65,11 +65,11 @@ impl<'a, O: ForestObligation + 'a> dot::GraphWalk<'a> for &'a ObligationForest dot::Nodes { + fn nodes(&self) -> dot::Nodes<'_, Self::Node> { (0..self.nodes.len()).collect() } - fn edges(&self) -> dot::Edges { + fn edges(&self) -> dot::Edges<'_, Self::Edge> { (0..self.nodes.len()) .flat_map(|i| { let node = &self.nodes[i]; diff --git a/src/librustc_data_structures/obligation_forest/mod.rs b/src/librustc_data_structures/obligation_forest/mod.rs index 59497f0df18e9..4490e5f86d2bd 100644 --- a/src/librustc_data_structures/obligation_forest/mod.rs +++ b/src/librustc_data_structures/obligation_forest/mod.rs @@ -1,11 +1,86 @@ //! The `ObligationForest` is a utility data structure used in trait -//! matching to track the set of outstanding obligations (those not -//! yet resolved to success or error). It also tracks the "backtrace" -//! of each pending obligation (why we are trying to figure this out -//! in the first place). See README.md for a general overview of how -//! to use this class. - -use fx::{FxHashMap, FxHashSet}; +//! matching to track the set of outstanding obligations (those not yet +//! resolved to success or error). It also tracks the "backtrace" of each +//! pending obligation (why we are trying to figure this out in the first +//! place). +//! +//! ### External view +//! +//! `ObligationForest` supports two main public operations (there are a +//! few others not discussed here): +//! +//! 1. Add a new root obligations (`push_tree`). +//! 2. Process the pending obligations (`process_obligations`). +//! +//! When a new obligation `N` is added, it becomes the root of an +//! obligation tree. This tree can also carry some per-tree state `T`, +//! which is given at the same time. This tree is a singleton to start, so +//! `N` is both the root and the only leaf. Each time the +//! `process_obligations` method is called, it will invoke its callback +//! with every pending obligation (so that will include `N`, the first +//! time). The callback also receives a (mutable) reference to the +//! per-tree state `T`. The callback should process the obligation `O` +//! that it is given and return one of three results: +//! +//! - `Ok(None)` -> ambiguous result. Obligation was neither a success +//! nor a failure. It is assumed that further attempts to process the +//! obligation will yield the same result unless something in the +//! surrounding environment changes. +//! - `Ok(Some(C))` - the obligation was *shallowly successful*. The +//! vector `C` is a list of subobligations. The meaning of this is that +//! `O` was successful on the assumption that all the obligations in `C` +//! are also successful. Therefore, `O` is only considered a "true" +//! success if `C` is empty. Otherwise, `O` is put into a suspended +//! state and the obligations in `C` become the new pending +//! obligations. They will be processed the next time you call +//! `process_obligations`. +//! - `Err(E)` -> obligation failed with error `E`. We will collect this +//! error and return it from `process_obligations`, along with the +//! "backtrace" of obligations (that is, the list of obligations up to +//! and including the root of the failed obligation). No further +//! obligations from that same tree will be processed, since the tree is +//! now considered to be in error. +//! +//! When the call to `process_obligations` completes, you get back an `Outcome`, +//! which includes three bits of information: +//! +//! - `completed`: a list of obligations where processing was fully +//! completed without error (meaning that all transitive subobligations +//! have also been completed). So, for example, if the callback from +//! `process_obligations` returns `Ok(Some(C))` for some obligation `O`, +//! then `O` will be considered completed right away if `C` is the +//! empty vector. Otherwise it will only be considered completed once +//! all the obligations in `C` have been found completed. +//! - `errors`: a list of errors that occurred and associated backtraces +//! at the time of error, which can be used to give context to the user. +//! - `stalled`: if true, then none of the existing obligations were +//! *shallowly successful* (that is, no callback returned `Ok(Some(_))`). +//! This implies that all obligations were either errors or returned an +//! ambiguous result, which means that any further calls to +//! `process_obligations` would simply yield back further ambiguous +//! results. This is used by the `FulfillmentContext` to decide when it +//! has reached a steady state. +//! +//! #### Snapshots +//! +//! The `ObligationForest` supports a limited form of snapshots; see +//! `start_snapshot`, `commit_snapshot`, and `rollback_snapshot`. In +//! particular, you can use a snapshot to roll back new root +//! obligations. However, it is an error to attempt to +//! `process_obligations` during a snapshot. +//! +//! ### Implementation details +//! +//! For the most part, comments specific to the implementation are in the +//! code. This file only contains a very high-level overview. Basically, +//! the forest is stored in a vector. Each element of the vector is a node +//! in some tree. Each node in the vector has the index of an (optional) +//! parent and (for convenience) its root (which may be itself). It also +//! has a current state, described by `NodeState`. After each +//! processing step, we compress the vector to remove completed and error +//! nodes, which aren't needed anymore. + +use crate::fx::{FxHashMap, FxHashSet}; use std::cell::Cell; use std::collections::hash_map::Entry; @@ -88,7 +163,7 @@ pub struct ObligationForest { obligation_tree_id_generator: ObligationTreeIdGenerator, - /// Per tree error cache. This is used to deduplicate errors, + /// Per tree error cache. This is used to deduplicate errors, /// which is necessary to avoid trait resolution overflow in /// some cases. /// @@ -193,13 +268,13 @@ impl ObligationForest { } } - /// Return the total number of nodes in the forest that have not + /// Returns the total number of nodes in the forest that have not /// yet been fully resolved. pub fn len(&self) -> usize { self.nodes.len() } - /// Registers an obligation + /// Registers an obligation. /// /// This CAN be done in a snapshot pub fn register_obligation(&mut self, obligation: O) { @@ -266,7 +341,7 @@ impl ObligationForest { } } - /// Convert all remaining obligations to the given error. + /// Converts all remaining obligations to the given error. /// /// This cannot be done during a snapshot. pub fn to_errors(&mut self, error: E) -> Vec> { @@ -305,10 +380,10 @@ impl ObligationForest { .insert(node.obligation.as_predicate().clone()); } - /// Perform a pass through the obligation list. This must + /// Performs a pass through the obligation list. This must /// be called in a loop until `outcome.stalled` is false. /// - /// This CANNOT be unrolled (presently, at least). + /// This _cannot_ be unrolled (presently, at least). pub fn process_obligations

(&mut self, processor: &mut P, do_completed: DoCompleted) -> Outcome where P: ObligationProcessor @@ -386,7 +461,7 @@ impl ObligationForest { } } - /// Mark all NodeState::Success nodes as NodeState::Done and + /// Mark all `NodeState::Success` nodes as `NodeState::Done` and /// report all cycles between them. This should be called /// after `mark_as_waiting` marks all nodes with pending /// subobligations as NodeState::Waiting. @@ -491,7 +566,7 @@ impl ObligationForest { } } - /// Marks all nodes that depend on a pending node as NodeState::Waiting. + /// Marks all nodes that depend on a pending node as `NodeState::Waiting`. fn mark_as_waiting(&self) { for node in &self.nodes { if node.state.get() == NodeState::Waiting { @@ -658,7 +733,7 @@ impl Node { // I need a Clone closure #[derive(Clone)] -struct GetObligation<'a, O: 'a>(&'a [Node]); +struct GetObligation<'a, O>(&'a [Node]); impl<'a, 'b, O> FnOnce<(&'b usize,)> for GetObligation<'a, O> { type Output = &'a O; diff --git a/src/librustc_data_structures/owning_ref/mod.rs b/src/librustc_data_structures/owning_ref/mod.rs index 0b126e5c572ed..236559dcd7c10 100644 --- a/src/librustc_data_structures/owning_ref/mod.rs +++ b/src/librustc_data_structures/owning_ref/mod.rs @@ -286,7 +286,7 @@ impl Erased for T {} pub unsafe trait IntoErased<'a> { /// Owner with the dereference type substituted to `Erased`. type Erased; - /// Perform the type erasure. + /// Performs the type erasure. fn into_erased(self) -> Self::Erased; } @@ -296,7 +296,7 @@ pub unsafe trait IntoErased<'a> { pub unsafe trait IntoErasedSend<'a> { /// Owner with the dereference type substituted to `Erased + Send`. type Erased: Send; - /// Perform the type erasure. + /// Performs the type erasure. fn into_erased_send(self) -> Self::Erased; } @@ -306,7 +306,7 @@ pub unsafe trait IntoErasedSend<'a> { pub unsafe trait IntoErasedSendSync<'a> { /// Owner with the dereference type substituted to `Erased + Send + Sync`. type Erased: Send + Sync; - /// Perform the type erasure. + /// Performs the type erasure. fn into_erased_send_sync(self) -> Self::Erased; } @@ -844,7 +844,7 @@ pub trait ToHandleMut { impl OwningHandle where O: StableAddress, O::Target: ToHandle, H: Deref, { - /// Create a new `OwningHandle` for a type that implements `ToHandle`. For types + /// Creates a new `OwningHandle` for a type that implements `ToHandle`. For types /// that don't implement `ToHandle`, callers may invoke `new_with_fn`, which accepts /// a callback to perform the conversion. pub fn new(o: O) -> Self { @@ -855,7 +855,7 @@ impl OwningHandle impl OwningHandle where O: StableAddress, O::Target: ToHandleMut, H: DerefMut, { - /// Create a new mutable `OwningHandle` for a type that implements `ToHandleMut`. + /// Creates a new mutable `OwningHandle` for a type that implements `ToHandleMut`. pub fn new_mut(o: O) -> Self { OwningHandle::new_with_fn(o, |x| unsafe { O::Target::to_handle_mut(x) }) } @@ -864,7 +864,7 @@ impl OwningHandle impl OwningHandle where O: StableAddress, H: Deref, { - /// Create a new OwningHandle. The provided callback will be invoked with + /// Creates a new OwningHandle. The provided callback will be invoked with /// a pointer to the object owned by `o`, and the returned value is stored /// as the object to which this `OwningHandle` will forward `Deref` and /// `DerefMut`. @@ -882,7 +882,7 @@ impl OwningHandle } } - /// Create a new OwningHandle. The provided callback will be invoked with + /// Creates a new OwningHandle. The provided callback will be invoked with /// a pointer to the object owned by `o`, and the returned value is stored /// as the object to which this `OwningHandle` will forward `Deref` and /// `DerefMut`. @@ -1002,7 +1002,7 @@ impl Debug for OwningRef where O: Debug, T: Debug, { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "OwningRef {{ owner: {:?}, reference: {:?} }}", self.owner(), @@ -1014,7 +1014,7 @@ impl Debug for OwningRefMut where O: Debug, T: Debug, { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "OwningRefMut {{ owner: {:?}, reference: {:?} }}", self.owner(), @@ -1047,7 +1047,7 @@ unsafe impl Sync for OwningRefMut where O: Sync, for<'a> (&'a mut T): Sync {} impl Debug for dyn Erased { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "",) } } diff --git a/src/librustc_data_structures/ptr_key.rs b/src/librustc_data_structures/ptr_key.rs index 322dcbe8f08fb..bf3ae2d7af58f 100644 --- a/src/librustc_data_structures/ptr_key.rs +++ b/src/librustc_data_structures/ptr_key.rs @@ -4,7 +4,7 @@ use std::ops::Deref; /// A wrapper around reference that compares and hashes like a pointer. /// Can be used as a key in sets/maps indexed by pointers to avoid `unsafe`. #[derive(Debug)] -pub struct PtrKey<'a, T: 'a>(pub &'a T); +pub struct PtrKey<'a, T>(pub &'a T); impl<'a, T> Clone for PtrKey<'a, T> { fn clone(&self) -> Self { *self } diff --git a/src/librustc_data_structures/sip128.rs b/src/librustc_data_structures/sip128.rs index 9ec9a39840032..06f157f972932 100644 --- a/src/librustc_data_structures/sip128.rs +++ b/src/librustc_data_structures/sip128.rs @@ -44,7 +44,7 @@ macro_rules! compress { }); } -/// Load an integer of the desired type from a byte stream, in LE order. Uses +/// Loads an integer of the desired type from a byte stream, in LE order. Uses /// `copy_nonoverlapping` to let the compiler generate the most efficient way /// to load it from a possibly unaligned address. /// @@ -61,7 +61,7 @@ macro_rules! load_int_le { }); } -/// Load an u64 using up to 7 bytes of a byte slice. +/// Loads an u64 using up to 7 bytes of a byte slice. /// /// Unsafe because: unchecked indexing at start..start+len #[inline] diff --git a/src/librustc_data_structures/snapshot_map/mod.rs b/src/librustc_data_structures/snapshot_map/mod.rs index d408727aea504..91d6e29237002 100644 --- a/src/librustc_data_structures/snapshot_map/mod.rs +++ b/src/librustc_data_structures/snapshot_map/mod.rs @@ -1,4 +1,4 @@ -use fx::FxHashMap; +use crate::fx::FxHashMap; use std::hash::Hash; use std::ops; use std::mem; diff --git a/src/librustc_data_structures/sorted_map.rs b/src/librustc_data_structures/sorted_map.rs index 64bbb8d7c08d1..1f674c1c664e4 100644 --- a/src/librustc_data_structures/sorted_map.rs +++ b/src/librustc_data_structures/sorted_map.rs @@ -111,7 +111,7 @@ impl SortedMap { /// Iterate over elements, sorted by key #[inline] - pub fn iter(&self) -> ::std::slice::Iter<(K, V)> { + pub fn iter(&self) -> ::std::slice::Iter<'_, (K, V)> { self.data.iter() } diff --git a/src/librustc_data_structures/stable_hasher.rs b/src/librustc_data_structures/stable_hasher.rs index 4583f12ec8cbc..19343a9250df3 100644 --- a/src/librustc_data_structures/stable_hasher.rs +++ b/src/librustc_data_structures/stable_hasher.rs @@ -1,7 +1,9 @@ use std::hash::{Hash, Hasher, BuildHasher}; use std::marker::PhantomData; use std::mem; -use sip128::SipHasher128; +use crate::sip128::SipHasher128; +use crate::indexed_vec; +use crate::bit_set; /// When hashing something that ends up affecting properties like symbol names, /// we want these symbol names to be calculated independently of other factors @@ -17,7 +19,7 @@ pub struct StableHasher { } impl ::std::fmt::Debug for StableHasher { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { write!(f, "{:?}", self.state) } } @@ -433,7 +435,7 @@ impl HashStable for ::std::mem::Discriminant { } } -impl HashStable for ::indexed_vec::IndexVec +impl HashStable for indexed_vec::IndexVec where T: HashStable, { fn hash_stable(&self, @@ -447,7 +449,7 @@ impl HashStable for ::indexed_vec::IndexVec< } -impl HashStable for ::bit_set::BitSet +impl HashStable for bit_set::BitSet { fn hash_stable(&self, ctx: &mut CTX, diff --git a/src/librustc_data_structures/svh.rs b/src/librustc_data_structures/svh.rs index 749479534979c..df4f61768375e 100644 --- a/src/librustc_data_structures/svh.rs +++ b/src/librustc_data_structures/svh.rs @@ -9,7 +9,7 @@ use std::fmt; use std::hash::{Hash, Hasher}; use serialize::{Encodable, Decodable, Encoder, Decoder}; -use stable_hasher; +use crate::stable_hasher; #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub struct Svh { @@ -17,7 +17,7 @@ pub struct Svh { } impl Svh { - /// Create a new `Svh` given the hash. If you actually want to + /// Creates a new `Svh` given the hash. If you actually want to /// compute the SVH from some HIR, you want the `calculate_svh` /// function found in `librustc_incremental`. pub fn new(hash: u64) -> Svh { @@ -40,7 +40,7 @@ impl Hash for Svh { } impl fmt::Display for Svh { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.pad(&self.to_string()) } } diff --git a/src/librustc_data_structures/sync.rs b/src/librustc_data_structures/sync.rs index f9f94f0be7b9a..ba1f6eb56fe88 100644 --- a/src/librustc_data_structures/sync.rs +++ b/src/librustc_data_structures/sync.rs @@ -1,27 +1,27 @@ -//! This module defines types which are thread safe if cfg!(parallel_queries) is true. +//! This module defines types which are thread safe if cfg!(parallel_compiler) is true. //! //! `Lrc` is an alias of either Rc or Arc. //! //! `Lock` is a mutex. -//! It internally uses `parking_lot::Mutex` if cfg!(parallel_queries) is true, +//! It internally uses `parking_lot::Mutex` if cfg!(parallel_compiler) is true, //! `RefCell` otherwise. //! //! `RwLock` is a read-write lock. -//! It internally uses `parking_lot::RwLock` if cfg!(parallel_queries) is true, +//! It internally uses `parking_lot::RwLock` if cfg!(parallel_compiler) is true, //! `RefCell` otherwise. //! -//! `MTLock` is a mutex which disappears if cfg!(parallel_queries) is false. +//! `MTLock` is a mutex which disappears if cfg!(parallel_compiler) is false. //! -//! `MTRef` is a immutable reference if cfg!(parallel_queries), and an mutable reference otherwise. +//! `MTRef` is a immutable reference if cfg!(parallel_compiler), and an mutable reference otherwise. //! //! `rustc_erase_owner!` erases a OwningRef owner into Erased or Erased + Send + Sync -//! depending on the value of cfg!(parallel_queries). +//! depending on the value of cfg!(parallel_compiler). use std::collections::HashMap; use std::hash::{Hash, BuildHasher}; use std::marker::PhantomData; use std::ops::{Deref, DerefMut}; -use owning_ref::{Erased, OwningRef}; +use crate::owning_ref::{Erased, OwningRef}; pub fn serial_join(oper_a: A, oper_b: B) -> (RA, RB) where A: FnOnce() -> RA, @@ -50,7 +50,7 @@ pub use std::sync::atomic::Ordering::SeqCst; pub use std::sync::atomic::Ordering; cfg_if! { - if #[cfg(not(parallel_queries))] { + if #[cfg(not(parallel_compiler))] { pub auto trait Send {} pub auto trait Sync {} @@ -70,6 +70,7 @@ cfg_if! { pub struct Atomic(Cell); impl Atomic { + #[inline] pub fn new(v: T) -> Self { Atomic(Cell::new(v)) } @@ -80,10 +81,12 @@ cfg_if! { self.0.into_inner() } + #[inline] pub fn load(&self, _: Ordering) -> T { self.0.get() } + #[inline] pub fn store(&self, val: T, _: Ordering) { self.0.set(val) } @@ -118,11 +121,19 @@ cfg_if! { pub type AtomicUsize = Atomic; pub type AtomicBool = Atomic; + pub type AtomicU32 = Atomic; pub type AtomicU64 = Atomic; pub use self::serial_join as join; pub use self::serial_scope as scope; + #[macro_export] + macro_rules! parallel { + ($($blocks:tt),*) => { + $($blocks)*; + } + } + pub use std::iter::Iterator as ParallelIterator; pub fn par_iter(t: T) -> T::IntoIter { @@ -223,7 +234,7 @@ cfg_if! { pub use parking_lot::MutexGuard as LockGuard; pub use parking_lot::MappedMutexGuard as MappedLockGuard; - pub use std::sync::atomic::{AtomicBool, AtomicUsize, AtomicU64}; + pub use std::sync::atomic::{AtomicBool, AtomicUsize, AtomicU32, AtomicU64}; pub use std::sync::Arc as Lrc; pub use std::sync::Weak as Weak; @@ -250,12 +261,12 @@ cfg_if! { } #[inline(always)] - pub fn lock(&self) -> LockGuard { + pub fn lock(&self) -> LockGuard<'_, T> { self.0.lock() } #[inline(always)] - pub fn lock_mut(&self) -> LockGuard { + pub fn lock_mut(&self) -> LockGuard<'_, T> { self.lock() } } @@ -267,6 +278,26 @@ cfg_if! { use std::thread; pub use rayon::{join, scope}; + #[macro_export] + macro_rules! parallel { + (impl [$($c:tt,)*] [$block:tt $(, $rest:tt)*]) => { + parallel!(impl [$block, $($c,)*] [$($rest),*]) + }; + (impl [$($blocks:tt,)*] []) => { + ::rustc_data_structures::sync::scope(|s| { + $( + s.spawn(|_| $blocks); + )* + }) + }; + ($($blocks:tt),*) => { + // Reverse the order of the 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),*]); + }; + } + pub use rayon_core::WorkerLocal; pub use rayon::iter::ParallelIterator; @@ -457,21 +488,21 @@ impl Lock { self.0.get_mut() } - #[cfg(parallel_queries)] + #[cfg(parallel_compiler)] #[inline(always)] - pub fn try_lock(&self) -> Option> { + pub fn try_lock(&self) -> Option> { self.0.try_lock() } - #[cfg(not(parallel_queries))] + #[cfg(not(parallel_compiler))] #[inline(always)] - pub fn try_lock(&self) -> Option> { + pub fn try_lock(&self) -> Option> { self.0.try_borrow_mut().ok() } - #[cfg(parallel_queries)] + #[cfg(parallel_compiler)] #[inline(always)] - pub fn lock(&self) -> LockGuard { + pub fn lock(&self) -> LockGuard<'_, T> { if ERROR_CHECKING { self.0.try_lock().expect("lock was already held") } else { @@ -479,9 +510,9 @@ impl Lock { } } - #[cfg(not(parallel_queries))] + #[cfg(not(parallel_compiler))] #[inline(always)] - pub fn lock(&self) -> LockGuard { + pub fn lock(&self) -> LockGuard<'_, T> { self.0.borrow_mut() } @@ -491,12 +522,12 @@ impl Lock { } #[inline(always)] - pub fn borrow(&self) -> LockGuard { + pub fn borrow(&self) -> LockGuard<'_, T> { self.lock() } #[inline(always)] - pub fn borrow_mut(&self) -> LockGuard { + pub fn borrow_mut(&self) -> LockGuard<'_, T> { self.lock() } } @@ -535,15 +566,15 @@ impl RwLock { self.0.get_mut() } - #[cfg(not(parallel_queries))] + #[cfg(not(parallel_compiler))] #[inline(always)] - pub fn read(&self) -> ReadGuard { + pub fn read(&self) -> ReadGuard<'_, T> { self.0.borrow() } - #[cfg(parallel_queries)] + #[cfg(parallel_compiler)] #[inline(always)] - pub fn read(&self) -> ReadGuard { + pub fn read(&self) -> ReadGuard<'_, T> { if ERROR_CHECKING { self.0.try_read().expect("lock was already held") } else { @@ -556,27 +587,27 @@ impl RwLock { f(&*self.read()) } - #[cfg(not(parallel_queries))] + #[cfg(not(parallel_compiler))] #[inline(always)] - pub fn try_write(&self) -> Result, ()> { + pub fn try_write(&self) -> Result, ()> { self.0.try_borrow_mut().map_err(|_| ()) } - #[cfg(parallel_queries)] + #[cfg(parallel_compiler)] #[inline(always)] - pub fn try_write(&self) -> Result, ()> { + pub fn try_write(&self) -> Result, ()> { self.0.try_write().ok_or(()) } - #[cfg(not(parallel_queries))] + #[cfg(not(parallel_compiler))] #[inline(always)] - pub fn write(&self) -> WriteGuard { + pub fn write(&self) -> WriteGuard<'_, T> { self.0.borrow_mut() } - #[cfg(parallel_queries)] + #[cfg(parallel_compiler)] #[inline(always)] - pub fn write(&self) -> WriteGuard { + pub fn write(&self) -> WriteGuard<'_, T> { if ERROR_CHECKING { self.0.try_write().expect("lock was already held") } else { @@ -590,12 +621,12 @@ impl RwLock { } #[inline(always)] - pub fn borrow(&self) -> ReadGuard { + pub fn borrow(&self) -> ReadGuard<'_, T> { self.read() } #[inline(always)] - pub fn borrow_mut(&self) -> WriteGuard { + pub fn borrow_mut(&self) -> WriteGuard<'_, T> { self.write() } } @@ -612,27 +643,27 @@ impl Clone for RwLock { /// It will panic if it is used on multiple threads. #[derive(Copy, Clone, Hash, Debug, Eq, PartialEq)] pub struct OneThread { - #[cfg(parallel_queries)] + #[cfg(parallel_compiler)] thread: thread::ThreadId, inner: T, } -#[cfg(parallel_queries)] +#[cfg(parallel_compiler)] unsafe impl std::marker::Sync for OneThread {} -#[cfg(parallel_queries)] +#[cfg(parallel_compiler)] unsafe impl std::marker::Send for OneThread {} impl OneThread { #[inline(always)] fn check(&self) { - #[cfg(parallel_queries)] + #[cfg(parallel_compiler)] assert_eq!(thread::current().id(), self.thread); } #[inline(always)] pub fn new(inner: T) -> Self { OneThread { - #[cfg(parallel_queries)] + #[cfg(parallel_compiler)] thread: thread::current().id(), inner, } diff --git a/src/librustc_data_structures/thin_vec.rs b/src/librustc_data_structures/thin_vec.rs index 359f9b7842da3..ed57c528f51e0 100644 --- a/src/librustc_data_structures/thin_vec.rs +++ b/src/librustc_data_structures/thin_vec.rs @@ -39,6 +39,15 @@ impl ::std::ops::Deref for ThinVec { } } +impl ::std::ops::DerefMut for ThinVec { + fn deref_mut(&mut self) -> &mut [T] { + match *self { + ThinVec(None) => &mut [], + ThinVec(Some(ref mut vec)) => vec, + } + } +} + impl Extend for ThinVec { fn extend>(&mut self, iter: I) { match *self { diff --git a/src/librustc_data_structures/tiny_list.rs b/src/librustc_data_structures/tiny_list.rs index d660486d58446..3d74516d9c326 100644 --- a/src/librustc_data_structures/tiny_list.rs +++ b/src/librustc_data_structures/tiny_list.rs @@ -123,7 +123,7 @@ impl Element { mod test { use super::*; extern crate test; - use self::test::Bencher; + use test::Bencher; #[test] fn test_contains_and_insert() { diff --git a/src/librustc_data_structures/transitive_relation.rs b/src/librustc_data_structures/transitive_relation.rs index 9d675ed3096e0..0974607fabea8 100644 --- a/src/librustc_data_structures/transitive_relation.rs +++ b/src/librustc_data_structures/transitive_relation.rs @@ -1,8 +1,8 @@ -use bit_set::BitMatrix; -use fx::FxHashMap; -use sync::Lock; +use crate::bit_set::BitMatrix; +use crate::fx::FxHashMap; +use crate::stable_hasher::{HashStable, StableHasher, StableHasherResult}; +use crate::sync::Lock; use rustc_serialize::{Encodable, Encoder, Decodable, Decoder}; -use stable_hasher::{HashStable, StableHasher, StableHasherResult}; use std::fmt::Debug; use std::hash::Hash; use std::mem; @@ -82,7 +82,7 @@ impl TransitiveRelation { } /// Applies the (partial) function to each edge and returns a new - /// relation. If `f` returns `None` for any end-point, returns + /// relation. If `f` returns `None` for any end-point, returns /// `None`. pub fn maybe_map(&self, mut f: F) -> Option> where F: FnMut(&T) -> Option, @@ -111,7 +111,7 @@ impl TransitiveRelation { } } - /// Check whether `a < target` (transitively) + /// Checks whether `a < target` (transitively) pub fn contains(&self, a: &T, b: &T) -> bool { match (self.index(a), self.index(b)) { (Some(a), Some(b)) => self.with_closure(|closure| closure.contains(a.0, b.0)), @@ -122,7 +122,7 @@ impl TransitiveRelation { /// Thinking of `x R y` as an edge `x -> y` in a graph, this /// returns all things reachable from `a`. /// - /// Really this probably ought to be `impl Iterator`, but + /// Really this probably ought to be `impl Iterator`, but /// I'm too lazy to make that work, and -- given the caching /// strategy -- it'd be a touch tricky anyhow. pub fn reachable_from(&self, a: &T) -> Vec<&T> { @@ -152,20 +152,20 @@ impl TransitiveRelation { /// the query is `postdom_upper_bound(a, b)`: /// /// ```text - /// // returns Some(x), which is also LUB + /// // Returns Some(x), which is also LUB. /// a -> a1 -> x /// ^ /// | /// b -> b1 ---+ /// - /// // returns Some(x), which is not LUB (there is none) - /// // diagonal edges run left-to-right + /// // Returns `Some(x)`, which is not LUB (there is none) + /// // diagonal edges run left-to-right. /// a -> a1 -> x /// \/ ^ /// /\ | /// b -> b1 ---+ /// - /// // returns None + /// // Returns `None`. /// a -> a1 /// b -> b1 /// ``` diff --git a/src/librustc_data_structures/vec_linked_list.rs b/src/librustc_data_structures/vec_linked_list.rs index 3b6984dd07599..c00c707a43542 100644 --- a/src/librustc_data_structures/vec_linked_list.rs +++ b/src/librustc_data_structures/vec_linked_list.rs @@ -1,4 +1,4 @@ -use indexed_vec::{Idx, IndexVec}; +use crate::indexed_vec::{Idx, IndexVec}; pub fn iter( first: Option, diff --git a/src/librustc_data_structures/work_queue.rs b/src/librustc_data_structures/work_queue.rs index 0a928de7961b5..193025aafad20 100644 --- a/src/librustc_data_structures/work_queue.rs +++ b/src/librustc_data_structures/work_queue.rs @@ -1,5 +1,5 @@ -use bit_set::BitSet; -use indexed_vec::Idx; +use crate::bit_set::BitSet; +use crate::indexed_vec::Idx; use std::collections::VecDeque; /// A work queue is a handy data structure for tracking work left to @@ -14,7 +14,7 @@ pub struct WorkQueue { } impl WorkQueue { - /// Create a new work queue with all the elements from (0..len). + /// Creates a new work queue with all the elements from (0..len). #[inline] pub fn with_all(len: usize) -> Self { WorkQueue { @@ -23,7 +23,7 @@ impl WorkQueue { } } - /// Create a new work queue that starts empty, where elements range from (0..len). + /// Creates a new work queue that starts empty, where elements range from (0..len). #[inline] pub fn with_none(len: usize) -> Self { WorkQueue { @@ -54,7 +54,7 @@ impl WorkQueue { } } - /// True if nothing is enqueued. + /// Returns `true` if nothing is enqueued. #[inline] pub fn is_empty(&self) -> bool { self.deque.is_empty() diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 1ecb8ef112c9e..b998b77a76b9c 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -22,7 +22,7 @@ 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, loops, rvalue_promotion}; +use rustc_passes::{self, ast_validation, hir_stats, loops, rvalue_promotion, layout_test}; use rustc_plugin as plugin; use rustc_plugin::registry::Registry; use rustc_privacy; @@ -32,7 +32,7 @@ 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::fold::Folder; +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; @@ -56,7 +56,7 @@ use proc_macro_decls; use profile; use super::Compilation; -#[cfg(not(parallel_queries))] +#[cfg(not(parallel_compiler))] pub fn spawn_thread_pool R + sync::Send, R: sync::Send>( opts: config::Options, f: F @@ -66,7 +66,7 @@ pub fn spawn_thread_pool R + sync::Send, R: sync:: }) } -#[cfg(parallel_queries)] +#[cfg(parallel_compiler)] pub fn spawn_thread_pool R + sync::Send, R: sync::Send>( opts: config::Options, f: F @@ -78,7 +78,7 @@ pub fn spawn_thread_pool R + sync::Send, R: sync:: let gcx_ptr = &Lock::new(0); let config = ThreadPoolBuilder::new() - .num_threads(Session::query_threads_from_opts(&opts)) + .num_threads(Session::threads_from_opts(&opts)) .deadlock_handler(|| unsafe { ty::query::handle_deadlock() }) .stack_size(::STACK_SIZE); @@ -168,7 +168,6 @@ pub fn compile_input( let ExpansionResult { expanded_crate, defs, - analysis, resolutions, mut hir_forest, } = { @@ -251,7 +250,6 @@ pub fn compile_input( output, &cstore, &hir_map, - &analysis, &resolutions, &expanded_crate, &hir_map.krate(), @@ -277,12 +275,11 @@ pub fn compile_input( sess, cstore, hir_map, - analysis, resolutions, &mut arenas, &crate_name, &outputs, - |tcx, analysis, rx, result| { + |tcx, rx, result| { { // Eventually, we will want to track plugins. tcx.dep_graph.with_ignore(|| { @@ -293,13 +290,17 @@ pub fn compile_input( output, opt_crate, tcx.hir().krate(), - &analysis, 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)); } @@ -527,7 +528,6 @@ pub struct CompileState<'a, 'tcx: 'a> { pub hir_crate: Option<&'a hir::Crate>, pub hir_map: Option<&'a hir_map::Map<'tcx>>, pub resolutions: Option<&'a Resolutions>, - pub analysis: Option<&'a ty::CrateAnalysis>, pub tcx: Option>, } @@ -547,7 +547,6 @@ impl<'a, 'tcx> CompileState<'a, 'tcx> { hir_crate: None, hir_map: None, resolutions: None, - analysis: None, tcx: None, } } @@ -595,7 +594,6 @@ impl<'a, 'tcx> CompileState<'a, 'tcx> { out_file: &'a Option, cstore: &'tcx CStore, hir_map: &'a hir_map::Map<'tcx>, - analysis: &'a ty::CrateAnalysis, resolutions: &'a Resolutions, krate: &'a ast::Crate, hir_crate: &'a hir::Crate, @@ -606,7 +604,6 @@ impl<'a, 'tcx> CompileState<'a, 'tcx> { crate_name: Some(crate_name), cstore: Some(cstore), hir_map: Some(hir_map), - analysis: Some(analysis), resolutions: Some(resolutions), expanded_crate: Some(krate), hir_crate: Some(hir_crate), @@ -623,12 +620,10 @@ impl<'a, 'tcx> CompileState<'a, 'tcx> { out_file: &'a Option, krate: Option<&'a ast::Crate>, hir_crate: &'a hir::Crate, - analysis: &'a ty::CrateAnalysis, tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_name: &'a str, ) -> Self { CompileState { - analysis: Some(analysis), tcx: Some(tcx), expanded_crate: krate, hir_crate: Some(hir_crate), @@ -711,7 +706,6 @@ fn count_nodes(krate: &ast::Crate) -> usize { pub struct ExpansionResult { pub expanded_crate: ast::Crate, pub defs: hir_map::Definitions, - pub analysis: ty::CrateAnalysis, pub resolutions: Resolutions, pub hir_forest: hir_map::Forest, } @@ -722,7 +716,7 @@ pub struct InnerExpansionResult<'a> { pub hir_forest: hir_map::Forest, } -/// Run the "early phases" of the compiler: initial `cfg` processing, +/// 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 @@ -772,16 +766,13 @@ where 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(), }, - - analysis: ty::CrateAnalysis { - glob_map: resolver.glob_map - }, }), Err(x) => Err(x), } @@ -898,7 +889,7 @@ where sess.track_errors(|| { let mut ls = sess.lint_store.borrow_mut(); for pass in early_lint_passes { - ls.register_early_pass(Some(sess), true, pass); + ls.register_early_pass(Some(sess), true, false, pass); } for pass in late_lint_passes { ls.register_late_pass(Some(sess), true, pass); @@ -919,7 +910,11 @@ where } time(sess, "pre ast expansion lint checks", || { - lint::check_ast_crate(sess, &krate, true) + lint::check_ast_crate( + sess, + &krate, + true, + rustc_lint::BuiltinCombinedPreExpansionLintPass::new()); }); let mut resolver = Resolver::new( @@ -930,7 +925,7 @@ where crate_loader, &resolver_arenas, ); - syntax_ext::register_builtins(&mut resolver, syntax_exts, sess.features_untracked().quote); + syntax_ext::register_builtins(&mut resolver, syntax_exts); // Expand all macros sess.profiler(|p| p.start_activity(ProfileCategory::Expansion)); @@ -1010,12 +1005,12 @@ where }); sess.profiler(|p| p.end_activity(ProfileCategory::Expansion)); - krate = time(sess, "maybe building test harness", || { + time(sess, "maybe building test harness", || { syntax::test::modify_for_testing( &sess.parse_sess, &mut resolver, sess.opts.test, - krate, + &mut krate, sess.diagnostic(), &sess.features_untracked(), ) @@ -1024,9 +1019,13 @@ where // 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 { - krate = ReplaceBodyWithLoop::new(sess).fold_crate(krate); + 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. @@ -1041,6 +1040,7 @@ where &mut resolver, krate, is_proc_macro_crate, + has_proc_macro_decls, is_test_crate, num_crate_types, sess.diagnostic(), @@ -1048,16 +1048,18 @@ where }); } - // Expand global allocators, which are treated as an in-tree proc macro - krate = time(sess, "creating allocators", || { - allocator::expand::modify( - &sess.parse_sess, - &mut resolver, - krate, - crate_name.to_string(), - 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! @@ -1075,10 +1077,6 @@ where println!("{}", json::as_json(&krate)); } - time(sess, "AST validation", || { - ast_validation::check_crate(sess, &krate) - }); - time(sess, "name resolution", || { resolver.resolve_crate(&krate); }); @@ -1131,7 +1129,7 @@ where }); time(sess, "early lint checks", || { - lint::check_ast_crate(sess, &krate, false) + lint::check_ast_crate(sess, &krate, false, rustc_lint::BuiltinCombinedEarlyLintPass::new()) }); // Discard hygiene data, which isn't required after lowering to HIR. @@ -1159,10 +1157,13 @@ pub fn default_provide(providers: &mut ty::query::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); } @@ -1171,7 +1172,7 @@ pub fn default_provide_extern(providers: &mut ty::query::Providers) { cstore::provide_extern(providers); } -/// Run the resolution, typechecking, region checking and other +/// 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>( @@ -1180,7 +1181,6 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>( sess: &'tcx Session, cstore: &'tcx CStore, hir_map: hir_map::Map<'tcx>, - analysis: ty::CrateAnalysis, resolutions: Resolutions, arenas: &'tcx mut AllArenas<'tcx>, name: &str, @@ -1190,7 +1190,6 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>( where F: for<'a> FnOnce( TyCtxt<'a, 'tcx, 'tcx>, - ty::CrateAnalysis, mpsc::Receiver>, CompileResult, ) -> R, @@ -1199,10 +1198,6 @@ where rustc_incremental::load_query_result_cache(sess) }); - time(sess, "looking for entry point", || { - middle::entry::find_entry_point(sess, &hir_map, name) - }); - let mut local_providers = ty::query::Providers::default(); default_provide(&mut local_providers); codegen_backend.provide(&mut local_providers); @@ -1232,54 +1227,64 @@ where // tcx available. time(sess, "dep graph tcx init", || rustc_incremental::dep_graph_tcx_init(tcx)); - time(sess, "looking for plugin registrar", || { - plugin::build::find_plugin_registrar(tcx) - }); - - time(sess, "looking for derive registrar", || { - proc_macro_decls::find(tcx) - }); - - time(sess, "loop checking", || loops::check_crate(tcx)); + parallel!({ + time(sess, "looking for entry point", || { + middle::entry::find_entry_point(tcx) + }); - time(sess, "attribute checking", || { - hir::check_attr::check_crate(tcx) - }); + time(sess, "looking for plugin registrar", || { + plugin::build::find_plugin_registrar(tcx) + }); - time(sess, "stability checking", || { - stability::check_unstable_api_usage(tcx) + time(sess, "looking for derive registrar", || { + proc_macro_decls::find(tcx) + }); + }, { + time(sess, "loop checking", || loops::check_crate(tcx)); + }, { + time(sess, "attribute checking", || { + hir::check_attr::check_crate(tcx) + }); + }, { + time(sess, "stability checking", || { + stability::check_unstable_api_usage(tcx) + }); }); // passes are timed inside typeck match typeck::check_crate(tcx) { Ok(x) => x, Err(x) => { - f(tcx, analysis, rx, Err(x)); + f(tcx, rx, Err(x)); return Err(x); } } - time(sess, "rvalue promotion", || { - rvalue_promotion::check_crate(tcx) - }); - - time(sess, "privacy checking", || { - rustc_privacy::check_crate(tcx) - }); - - time(sess, "intrinsic checking", || { - middle::intrinsicck::check_crate(tcx) + time(sess, "misc checking", || { + parallel!({ + time(sess, "rvalue promotion", || { + rvalue_promotion::check_crate(tcx) + }); + }, { + 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, "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) - }); + // 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() { @@ -1289,7 +1294,7 @@ where time(sess, "MIR borrow checking", - || tcx.par_body_owners(|def_id| { tcx.mir_borrowck(def_id); })); + || 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); @@ -1300,30 +1305,41 @@ where mir::transform::check_unsafety::check_unsafety(tcx, def_id) } }); - // Avoid overwhelming user with errors if type checking failed. + + 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 // 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 { - return Ok(f(tcx, analysis, rx, sess.compile_status())); + return Ok(f(tcx, rx, sess.compile_status())); } - time(sess, "death checking", || middle::dead::check_crate(tcx)); - - time(sess, "unused lib feature checking", || { - stability::check_unused_or_stable_features(tcx) + time(sess, "misc checking", || { + parallel!({ + time(sess, "privacy checking", || { + rustc_privacy::check_crate(tcx) + }); + }, { + 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)); + }); }); - time(sess, "lint checking", || lint::check_crate(tcx)); - - return Ok(f(tcx, analysis, rx, tcx.sess.compile_status())); + return Ok(f(tcx, rx, tcx.sess.compile_status())); }, ) } -/// Run the codegen backend, after which the AST and analysis can +/// Runs the codegen backend, after which the AST and analysis can /// be discarded. pub fn phase_4_codegen<'a, 'tcx>( codegen_backend: &dyn CodegenBackend, diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 010ac28cdc944..e022d3a3818a5 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -4,16 +4,12 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", - html_favicon_url = "https://doc.rust-lang.org/favicon.ico", - html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] #![feature(box_syntax)] #![cfg_attr(unix, feature(libc))] #![feature(nll)] -#![feature(quote)] #![feature(rustc_diagnostic_macros)] -#![feature(slice_sort_by_cached_key)] #![feature(set_stdio)] #![feature(no_debug)] #![feature(integer_atomics)] @@ -31,6 +27,7 @@ extern crate rustc; extern crate rustc_allocator; extern crate rustc_target; extern crate rustc_borrowck; +#[macro_use] extern crate rustc_data_structures; extern crate rustc_errors as errors; extern crate rustc_passes; @@ -92,7 +89,7 @@ use std::panic; use std::path::{PathBuf, Path}; use std::process::{self, Command, Stdio}; use std::str; -use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering}; +use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::{Once, ONCE_INIT}; use std::thread; @@ -116,7 +113,7 @@ pub mod target_features { use rustc::session::Session; use rustc_codegen_utils::codegen_backend::CodegenBackend; - /// Add `target_feature = "..."` cfgs for a variety of platform + /// Adds `target_feature = "..."` cfgs for a variety of platform /// specific features (SSE, NEON etc.). /// /// This is performed by checking whether a whitelisted set of @@ -255,7 +252,7 @@ fn get_codegen_sysroot(backend_name: &str) -> fn() -> Box { // general this assertion never trips due to the once guard in `get_codegen_backend`, // but there's a few manual calls to this function in this file we protect // against. - static LOADED: AtomicBool = ATOMIC_BOOL_INIT; + static LOADED: AtomicBool = AtomicBool::new(false); assert!(!LOADED.fetch_or(true, Ordering::SeqCst), "cannot load the default codegen backend twice"); @@ -840,7 +837,15 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { early_error(sopts.error_format, "no input filename given"); } 1 => panic!("make_input should have provided valid inputs"), - _ => early_error(sopts.error_format, "multiple input filenames provided"), + _ => + early_error( + sopts.error_format, + &format!( + "multiple input filenames provided (first two filenames are `{}` and `{}`)", + matches.free[0], + matches.free[1], + ), + ) } } @@ -871,15 +876,14 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { control.after_hir_lowering.stop = Compilation::Stop; control.after_parse.callback = box move |state| { - state.krate = Some(pretty::fold_crate(state.session, - state.krate.take().unwrap(), - ppm)); + 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.analysis.unwrap(), state.resolutions.unwrap(), state.input, &state.expanded_crate.take().unwrap(), @@ -893,7 +897,8 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { control.after_parse.stop = Compilation::Stop; control.after_parse.callback = box move |state| { - let krate = pretty::fold_crate(state.session, state.krate.take().unwrap(), ppm); + let mut krate = state.krate.take().unwrap(); + pretty::visit_crate(state.session, &mut krate, ppm); pretty::print_after_parsing(state.session, state.input, &krate, @@ -940,7 +945,6 @@ pub fn enable_save_analysis(control: &mut CompileController) { time(state.session, "save analysis", || { save::process_crate(state.tcx.unwrap(), state.expanded_crate.unwrap(), - state.analysis.unwrap(), state.crate_name.unwrap(), state.input, None, @@ -1319,7 +1323,7 @@ fn print_flag_list(cmdline_opt: &str, /// Process command line options. Emits messages as appropriate. If compilation /// should continue, returns a getopts::Matches object parsed from args, -/// otherwise returns None. +/// otherwise returns `None`. /// /// The compiler's handling of options is a little complicated as it ties into /// our stability story, and it's even *more* complicated by historical @@ -1483,7 +1487,7 @@ pub fn in_rustc_thread(f: F) -> Result> in_named_rustc_thread("rustc".to_string(), f) } -/// Get a list of extra command-line flags provided by the user, as strings. +/// 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 /// debugging, since some ICEs only happens with non-default compiler flags @@ -1548,7 +1552,7 @@ impl Display for CompilationFailure { } } -/// Run a procedure which will detect panics in the compiler and print nicer +/// 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 diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index a9ec99358c1b2..4caf2ec676f07 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -16,7 +16,7 @@ use rustc_metadata::cstore::CStore; use rustc_mir::util::{write_mir_pretty, write_mir_graphviz}; use syntax::ast::{self, BlockCheckMode}; -use syntax::fold::{self, Folder}; +use syntax::mut_visit::{*, MutVisitor, visit_clobber}; use syntax::print::{pprust}; use syntax::print::pprust::PrintState; use syntax::ptr::P; @@ -28,6 +28,7 @@ use smallvec::SmallVec; use std::cell::Cell; use std::fs::File; use std::io::{self, Write}; +use std::ops::DerefMut; use std::option; use std::path::Path; use std::str::FromStr; @@ -123,7 +124,8 @@ pub fn parse_pretty(sess: &Session, sess.fatal(&format!("argument to `unpretty` must be one of `normal`, \ `expanded`, `flowgraph[,unlabelled]=`, \ `identified`, `expanded,identified`, `everybody_loops`, \ - `hir`, `hir,identified`, `hir,typed`, or `mir`; got {}", + `hir`, `hir,identified`, `hir,typed`, `hir-tree`, \ + `mir` or `mir-cfg`; got {}", name)); } else { sess.fatal(&format!("argument to `pretty` must be one of `normal`, `expanded`, \ @@ -190,7 +192,6 @@ impl PpSourceMode { sess: &'tcx Session, cstore: &'tcx CStore, hir_map: &hir_map::Map<'tcx>, - analysis: &ty::CrateAnalysis, resolutions: &Resolutions, output_filenames: &OutputFilenames, id: &str, @@ -223,12 +224,11 @@ impl PpSourceMode { sess, cstore, hir_map.clone(), - analysis.clone(), resolutions.clone(), &mut arenas, id, output_filenames, - |tcx, _, _, _| { + |tcx, _, _| { let empty_tables = ty::TypeckTables::empty(None); let annotation = TypedAnnotation { tcx, @@ -704,42 +704,42 @@ impl<'a> ReplaceBodyWithLoop<'a> { } } -impl<'a> fold::Folder for ReplaceBodyWithLoop<'a> { - fn fold_item_kind(&mut self, i: ast::ItemKind) -> ast::ItemKind { +impl<'a> MutVisitor for ReplaceBodyWithLoop<'a> { + fn visit_item_kind(&mut self, i: &mut ast::ItemKind) { let is_const = match i { ast::ItemKind::Static(..) | ast::ItemKind::Const(..) => true, ast::ItemKind::Fn(ref decl, ref header, _, _) => header.constness.node == ast::Constness::Const || Self::should_ignore_fn(decl), _ => false, }; - self.run(is_const, |s| fold::noop_fold_item_kind(i, s)) + self.run(is_const, |s| noop_visit_item_kind(i, s)) } - fn fold_trait_item(&mut self, i: ast::TraitItem) -> SmallVec<[ast::TraitItem; 1]> { + fn flat_map_trait_item(&mut self, i: ast::TraitItem) -> SmallVec<[ast::TraitItem; 1]> { let is_const = match i.node { ast::TraitItemKind::Const(..) => true, ast::TraitItemKind::Method(ast::MethodSig { ref decl, ref header, .. }, _) => header.constness.node == ast::Constness::Const || Self::should_ignore_fn(decl), _ => false, }; - self.run(is_const, |s| fold::noop_fold_trait_item(i, s)) + self.run(is_const, |s| noop_flat_map_trait_item(i, s)) } - fn fold_impl_item(&mut self, i: ast::ImplItem) -> SmallVec<[ast::ImplItem; 1]> { + fn flat_map_impl_item(&mut self, i: ast::ImplItem) -> SmallVec<[ast::ImplItem; 1]> { let is_const = match i.node { ast::ImplItemKind::Const(..) => true, ast::ImplItemKind::Method(ast::MethodSig { ref decl, ref header, .. }, _) => header.constness.node == ast::Constness::Const || Self::should_ignore_fn(decl), _ => false, }; - self.run(is_const, |s| fold::noop_fold_impl_item(i, s)) + self.run(is_const, |s| noop_flat_map_impl_item(i, s)) } - fn fold_anon_const(&mut self, c: ast::AnonConst) -> ast::AnonConst { - self.run(true, |s| fold::noop_fold_anon_const(c, s)) + fn visit_anon_const(&mut self, c: &mut ast::AnonConst) { + self.run(true, |s| noop_visit_anon_const(c, s)) } - fn fold_block(&mut self, b: P) -> P { + fn visit_block(&mut self, b: &mut P) { fn stmt_to_block(rules: ast::BlockCheckMode, s: Option, sess: &Session) -> ast::Block { @@ -781,14 +781,14 @@ impl<'a> fold::Folder for ReplaceBodyWithLoop<'a> { }; if self.within_static_or_const { - fold::noop_fold_block(b, self) + noop_visit_block(b, self) } else { - b.map(|b| { + visit_clobber(b.deref_mut(), |b| { let mut stmts = vec![]; for s in b.stmts { let old_blocks = self.nested_blocks.replace(vec![]); - stmts.extend(self.fold_stmt(s).into_iter().filter(|s| s.is_item())); + stmts.extend(self.flat_map_stmt(s).into_iter().filter(|s| s.is_item())); // we put a Some in there earlier with that replace(), so this is valid let new_blocks = self.nested_blocks.take().unwrap(); @@ -819,9 +819,9 @@ impl<'a> fold::Folder for ReplaceBodyWithLoop<'a> { } // in general the pretty printer processes unexpanded code, so - // we override the default `fold_mac` method which panics. - fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { - fold::noop_fold_mac(mac, self) + // we override the default `visit_mac` method which panics. + fn visit_mac(&mut self, mac: &mut ast::Mac) { + noop_visit_mac(mac, self) } } @@ -890,12 +890,9 @@ fn print_flowgraph<'a, 'tcx, W: Write>(variants: Vec, } } -pub fn fold_crate(sess: &Session, krate: ast::Crate, ppm: PpMode) -> ast::Crate { +pub fn visit_crate(sess: &Session, krate: &mut ast::Crate, ppm: PpMode) { if let PpmSource(PpmEveryBodyLoops) = ppm { - let mut fold = ReplaceBodyWithLoop::new(sess); - fold.fold_crate(krate) - } else { - krate + ReplaceBodyWithLoop::new(sess).visit_crate(krate); } } @@ -959,7 +956,6 @@ pub fn print_after_parsing(sess: &Session, pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session, cstore: &'tcx CStore, hir_map: &hir_map::Map<'tcx>, - analysis: &ty::CrateAnalysis, resolutions: &Resolutions, input: &Input, krate: &ast::Crate, @@ -972,7 +968,6 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session, print_with_analysis(sess, cstore, hir_map, - analysis, resolutions, crate_name, output_filenames, @@ -1010,7 +1005,6 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session, s.call_with_pp_support_hir(sess, cstore, hir_map, - analysis, resolutions, output_filenames, crate_name, @@ -1033,7 +1027,6 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session, s.call_with_pp_support_hir(sess, cstore, hir_map, - analysis, resolutions, output_filenames, crate_name, @@ -1048,7 +1041,6 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session, s.call_with_pp_support_hir(sess, cstore, hir_map, - analysis, resolutions, output_filenames, crate_name, @@ -1081,7 +1073,6 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session, s.call_with_pp_support_hir(sess, cstore, hir_map, - analysis, resolutions, output_filenames, crate_name, @@ -1103,13 +1094,12 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session, } // In an ideal world, this would be a public function called by the driver after -// analsysis is performed. However, we want to call `phase_3_run_analysis_passes` +// 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>, - analysis: &ty::CrateAnalysis, resolutions: &Resolutions, crate_name: &str, output_filenames: &OutputFilenames, @@ -1134,12 +1124,11 @@ fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session, sess, cstore, hir_map.clone(), - analysis.clone(), resolutions.clone(), &mut arenas, crate_name, output_filenames, - |tcx, _, _, _| { + |tcx, _, _| { match ppm { PpmMir | PpmMirCFG => { if let Some(nodeid) = nodeid { diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index afcf08632a4f0..2ec755bd62691 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -1,4 +1,4 @@ -//! # Standalone Tests for the Inference Module +//! Standalone tests for the inference module. use driver; use errors; @@ -508,8 +508,8 @@ fn subst_ty_renumber_bound() { }) } -/// Test substituting a bound region into a function, which introduces another level of binding. -/// This requires adjusting the Debruijn index. +/// 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| { @@ -544,7 +544,7 @@ fn subst_ty_renumber_some_bounds() { }) } -/// Test that we correctly compute whether a type has escaping regions or not. +/// Tests that we correctly compute whether a type has escaping regions or not. #[test] fn escaping() { test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| { @@ -571,7 +571,7 @@ fn escaping() { }) } -/// Test applying a substitution where the value being substituted for an early-bound region is a +/// 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() { diff --git a/src/librustc_errors/Cargo.toml b/src/librustc_errors/Cargo.toml index b24f8ddf4d9f7..02c011857bd2a 100644 --- a/src/librustc_errors/Cargo.toml +++ b/src/librustc_errors/Cargo.toml @@ -2,6 +2,7 @@ authors = ["The Rust Project Developers"] name = "rustc_errors" version = "0.0.0" +edition = "2018" [lib] name = "rustc_errors" diff --git a/src/librustc_errors/diagnostic.rs b/src/librustc_errors/diagnostic.rs index 3fa391c84ab25..851b19e8177b5 100644 --- a/src/librustc_errors/diagnostic.rs +++ b/src/librustc_errors/diagnostic.rs @@ -1,11 +1,12 @@ -use CodeSuggestion; -use SubstitutionPart; -use Substitution; -use Applicability; -use Level; +use crate::CodeSuggestion; +use crate::SuggestionStyle; +use crate::SubstitutionPart; +use crate::Substitution; +use crate::Applicability; +use crate::Level; +use crate::snippet::Style; use std::fmt; use syntax_pos::{MultiSpan, Span}; -use snippet::Style; #[must_use] #[derive(Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)] @@ -118,7 +119,7 @@ impl Diagnostic { self.level == Level::Cancelled } - /// Add a span/label to be included in the resulting snippet. + /// Adds a span/label to be included in the resulting snippet. /// This is pushed onto the `MultiSpan` that was created when the /// diagnostic was first built. If you don't call this function at /// all, and you just supplied a `Span` to create the diagnostic, @@ -229,44 +230,72 @@ impl Diagnostic { self } - /// Prints out a message with a suggested edit of the code. If the suggestion is presented - /// inline it will only show the text message and not the text. + pub fn multipart_suggestion( + &mut self, + msg: &str, + suggestion: Vec<(Span, String)>, + applicability: Applicability, + ) -> &mut Self { + self.suggestions.push(CodeSuggestion { + substitutions: vec![Substitution { + parts: suggestion + .into_iter() + .map(|(span, snippet)| SubstitutionPart { snippet, span }) + .collect(), + }], + msg: msg.to_owned(), + style: SuggestionStyle::ShowCode, + applicability, + }); + self + } + + /// Prints out a message with for a multipart suggestion without showing the suggested code. /// - /// See `CodeSuggestion` for more information. - #[deprecated(note = "Use `span_suggestion_short_with_applicability`")] - pub fn span_suggestion_short(&mut self, sp: Span, msg: &str, suggestion: String) -> &mut Self { + /// This is intended to be used for suggestions that are obvious in what the changes need to + /// be from the message, showing the span label inline would be visually unpleasant + /// (marginally overlapping spans or multiline spans) and showing the snippet window wouldn't + /// improve understandability. + pub fn tool_only_multipart_suggestion( + &mut self, + msg: &str, + suggestion: Vec<(Span, String)>, + applicability: Applicability, + ) -> &mut Self { self.suggestions.push(CodeSuggestion { substitutions: vec![Substitution { - parts: vec![SubstitutionPart { - snippet: suggestion, - span: sp, - }], + parts: suggestion + .into_iter() + .map(|(span, snippet)| SubstitutionPart { snippet, span }) + .collect(), }], msg: msg.to_owned(), - show_code_when_inline: false, - applicability: Applicability::Unspecified, + style: SuggestionStyle::CompletelyHidden, + applicability, }); self } /// Prints out a message with a suggested edit of the code. /// - /// In case of short messages and a simple suggestion, - /// rustc displays it as a label like + /// In case of short messages and a simple suggestion, rustc displays it as a label: /// - /// "try adding parentheses: `(tup.0).1`" + /// ```text + /// try adding parentheses: `(tup.0).1` + /// ``` /// /// The message /// /// * should not end in any punctuation (a `:` is added automatically) - /// * should not be a question - /// * should not contain any parts like "the following", "as shown" + /// * should not be a question (avoid language like "did you mean") + /// * should not contain any phrases like "the following", "as shown", etc. /// * may look like "to do xyz, use" or "to do xyz, use abc" - /// * may contain a name of a function, variable or type, but not whole expressions + /// * may contain a name of a function, variable, or type, but not whole expressions /// /// See `CodeSuggestion` for more information. - #[deprecated(note = "Use `span_suggestion_with_applicability`")] - pub fn span_suggestion(&mut self, sp: Span, msg: &str, suggestion: String) -> &mut Self { + pub fn span_suggestion(&mut self, sp: Span, msg: &str, + suggestion: String, + applicability: Applicability) -> &mut Self { self.suggestions.push(CodeSuggestion { substitutions: vec![Substitution { parts: vec![SubstitutionPart { @@ -275,67 +304,37 @@ impl Diagnostic { }], }], msg: msg.to_owned(), - show_code_when_inline: true, - applicability: Applicability::Unspecified, - }); - self - } - - pub fn multipart_suggestion_with_applicability( - &mut self, - msg: &str, - suggestion: Vec<(Span, String)>, - applicability: Applicability, - ) -> &mut Self { - self.suggestions.push(CodeSuggestion { - substitutions: vec![Substitution { - parts: suggestion - .into_iter() - .map(|(span, snippet)| SubstitutionPart { snippet, span }) - .collect(), - }], - msg: msg.to_owned(), - show_code_when_inline: true, + style: SuggestionStyle::ShowCode, applicability, }); self } - #[deprecated(note = "Use `multipart_suggestion_with_applicability`")] - pub fn multipart_suggestion( - &mut self, - msg: &str, - suggestion: Vec<(Span, String)>, - ) -> &mut Self { - self.multipart_suggestion_with_applicability( - msg, - suggestion, - Applicability::Unspecified, - ) - } - /// Prints out a message with multiple suggested edits of the code. - #[deprecated(note = "Use `span_suggestions_with_applicability`")] - pub fn span_suggestions(&mut self, sp: Span, msg: &str, suggestions: Vec) -> &mut Self { + pub fn span_suggestions(&mut self, sp: Span, msg: &str, + suggestions: impl Iterator, applicability: Applicability) -> &mut Self + { self.suggestions.push(CodeSuggestion { - substitutions: suggestions.into_iter().map(|snippet| Substitution { + substitutions: suggestions.map(|snippet| Substitution { parts: vec![SubstitutionPart { snippet, span: sp, }], }).collect(), msg: msg.to_owned(), - show_code_when_inline: true, - applicability: Applicability::Unspecified, + style: SuggestionStyle::ShowCode, + applicability, }); self } - /// This is a suggestion that may contain mistakes or fillers and should - /// be read and understood by a human. - pub fn span_suggestion_with_applicability(&mut self, sp: Span, msg: &str, - suggestion: String, - applicability: Applicability) -> &mut Self { + /// Prints out a message with a suggested edit of the code. If the suggestion is presented + /// inline, it will only show the message and not the suggestion. + /// + /// See `CodeSuggestion` for more information. + pub fn span_suggestion_short( + &mut self, sp: Span, msg: &str, suggestion: String, applicability: Applicability + ) -> &mut Self { self.suggestions.push(CodeSuggestion { substitutions: vec![Substitution { parts: vec![SubstitutionPart { @@ -344,30 +343,40 @@ impl Diagnostic { }], }], msg: msg.to_owned(), - show_code_when_inline: true, + style: SuggestionStyle::HideCodeInline, applicability, }); self } - pub fn span_suggestions_with_applicability(&mut self, sp: Span, msg: &str, - suggestions: impl Iterator, applicability: Applicability) -> &mut Self - { + /// Prints out a message with for a suggestion without showing the suggested code. + /// + /// This is intended to be used for suggestions that are obvious in what the changes need to + /// be from the message, showing the span label inline would be visually unpleasant + /// (marginally overlapping spans or multiline spans) and showing the snippet window wouldn't + /// improve understandability. + pub fn span_suggestion_hidden( + &mut self, sp: Span, msg: &str, suggestion: String, applicability: Applicability + ) -> &mut Self { self.suggestions.push(CodeSuggestion { - substitutions: suggestions.map(|snippet| Substitution { + substitutions: vec![Substitution { parts: vec![SubstitutionPart { - snippet, + snippet: suggestion, span: sp, }], - }).collect(), + }], msg: msg.to_owned(), - show_code_when_inline: true, + style: SuggestionStyle::HideCodeInline, applicability, }); self } - pub fn span_suggestion_short_with_applicability( + /// Adds a suggestion to the json output, but otherwise remains silent/undisplayed in the cli. + /// + /// This is intended to be used for suggestions that are *very* obvious in what the changes + /// need to be from the message, but we still want other tools to be able to apply them. + pub fn tool_only_span_suggestion( &mut self, sp: Span, msg: &str, suggestion: String, applicability: Applicability ) -> &mut Self { self.suggestions.push(CodeSuggestion { @@ -378,7 +387,7 @@ impl Diagnostic { }], }], msg: msg.to_owned(), - show_code_when_inline: false, + style: SuggestionStyle::CompletelyHidden, applicability: applicability, }); self diff --git a/src/librustc_errors/diagnostic_builder.rs b/src/librustc_errors/diagnostic_builder.rs index 7449b2b758302..8a30790174d45 100644 --- a/src/librustc_errors/diagnostic_builder.rs +++ b/src/librustc_errors/diagnostic_builder.rs @@ -1,14 +1,15 @@ -use Diagnostic; -use DiagnosticId; -use DiagnosticStyledString; -use Applicability; +use crate::Diagnostic; +use crate::DiagnosticId; +use crate::DiagnosticStyledString; +use crate::Applicability; -use Level; -use Handler; +use crate::Level; +use crate::Handler; use std::fmt::{self, Debug}; use std::ops::{Deref, DerefMut}; use std::thread::panicking; use syntax_pos::{MultiSpan, Span}; +use log::debug; /// Used for emitting structured error messages and other diagnostic information. /// @@ -25,7 +26,7 @@ pub struct DiagnosticBuilder<'a> { /// In general, the `DiagnosticBuilder` uses deref to allow access to /// the fields and methods of the embedded `diagnostic` in a -/// transparent way. *However,* many of the methods are intended to +/// transparent way. *However,* many of the methods are intended to /// be used in a chained way, and hence ought to return `self`. In /// that case, we can't just naively forward to the method on the /// `diagnostic`, because the return type would be a `&Diagnostic` @@ -33,18 +34,24 @@ pub struct DiagnosticBuilder<'a> { /// it easy to declare such methods on the builder. macro_rules! forward { // Forward pattern for &self -> &Self - (pub fn $n:ident(&self, $($name:ident: $ty:ty),* $(,)*) -> &Self) => { + ( + $(#[$attrs:meta])* + pub fn $n:ident(&self, $($name:ident: $ty:ty),* $(,)*) -> &Self + ) => { + $(#[$attrs])* pub fn $n(&self, $($name: $ty),*) -> &Self { - #[allow(deprecated)] self.diagnostic.$n($($name),*); self } }; // Forward pattern for &mut self -> &mut Self - (pub fn $n:ident(&mut self, $($name:ident: $ty:ty),* $(,)*) -> &mut Self) => { + ( + $(#[$attrs:meta])* + pub fn $n:ident(&mut self, $($name:ident: $ty:ty),* $(,)*) -> &mut Self + ) => { + $(#[$attrs])* pub fn $n(&mut self, $($name: $ty),*) -> &mut Self { - #[allow(deprecated)] self.diagnostic.$n($($name),*); self } @@ -52,12 +59,16 @@ macro_rules! forward { // Forward pattern for &mut self -> &mut Self, with S: Into // type parameter. No obvious way to make this more generic. - (pub fn $n:ident>( - &mut self, - $($name:ident: $ty:ty),* - $(,)*) -> &mut Self) => { + ( + $(#[$attrs:meta])* + pub fn $n:ident>( + &mut self, + $($name:ident: $ty:ty),* + $(,)* + ) -> &mut Self + ) => { + $(#[$attrs])* pub fn $n>(&mut self, $($name: $ty),*) -> &mut Self { - #[allow(deprecated)] self.diagnostic.$n($($name),*); self } @@ -101,8 +112,8 @@ impl<'a> DiagnosticBuilder<'a> { // implements `Drop`. let diagnostic; unsafe { - diagnostic = ::std::ptr::read(&self.diagnostic); - ::std::mem::forget(self); + diagnostic = std::ptr::read(&self.diagnostic); + std::mem::forget(self); }; // Logging here is useful to help track down where in logs an error was // actually emitted. @@ -139,7 +150,7 @@ impl<'a> DiagnosticBuilder<'a> { self.cancel(); } - /// Add a span/label to be included in the resulting snippet. + /// Adds a span/label to be included in the resulting snippet. /// This is pushed onto the `MultiSpan` that was created when the /// diagnostic was first built. If you don't call this function at /// all, and you just supplied a `Span` to create the diagnostic, @@ -177,44 +188,33 @@ impl<'a> DiagnosticBuilder<'a> { msg: &str, ) -> &mut Self); - #[deprecated(note = "Use `span_suggestion_short_with_applicability`")] - forward!(pub fn span_suggestion_short( - &mut self, - sp: Span, - msg: &str, - suggestion: String, - ) -> &mut Self); + pub fn multipart_suggestion( + &mut self, + msg: &str, + suggestion: Vec<(Span, String)>, + applicability: Applicability, + ) -> &mut Self { + if !self.allow_suggestions { + return self + } + self.diagnostic.multipart_suggestion( + msg, + suggestion, + applicability, + ); + self + } - #[deprecated(note = "Use `multipart_suggestion_with_applicability`")] - forward!(pub fn multipart_suggestion( + pub fn tool_only_multipart_suggestion( &mut self, msg: &str, suggestion: Vec<(Span, String)>, - ) -> &mut Self); - - #[deprecated(note = "Use `span_suggestion_with_applicability`")] - forward!(pub fn span_suggestion(&mut self, - sp: Span, - msg: &str, - suggestion: String, - ) -> &mut Self); - - #[deprecated(note = "Use `span_suggestions_with_applicability`")] - forward!(pub fn span_suggestions(&mut self, - sp: Span, - msg: &str, - suggestions: Vec, - ) -> &mut Self); - - pub fn multipart_suggestion_with_applicability(&mut self, - msg: &str, - suggestion: Vec<(Span, String)>, - applicability: Applicability, - ) -> &mut Self { + applicability: Applicability, + ) -> &mut Self { if !self.allow_suggestions { return self } - self.diagnostic.multipart_suggestion_with_applicability( + self.diagnostic.tool_only_multipart_suggestion( msg, suggestion, applicability, @@ -222,16 +222,18 @@ impl<'a> DiagnosticBuilder<'a> { self } - pub fn span_suggestion_with_applicability(&mut self, - sp: Span, - msg: &str, - suggestion: String, - applicability: Applicability) - -> &mut Self { + + pub fn span_suggestion( + &mut self, + sp: Span, + msg: &str, + suggestion: String, + applicability: Applicability, + ) -> &mut Self { if !self.allow_suggestions { return self } - self.diagnostic.span_suggestion_with_applicability( + self.diagnostic.span_suggestion( sp, msg, suggestion, @@ -240,16 +242,17 @@ impl<'a> DiagnosticBuilder<'a> { self } - pub fn span_suggestions_with_applicability(&mut self, - sp: Span, - msg: &str, - suggestions: impl Iterator, - applicability: Applicability) - -> &mut Self { + pub fn span_suggestions( + &mut self, + sp: Span, + msg: &str, + suggestions: impl Iterator, + applicability: Applicability, + ) -> &mut Self { if !self.allow_suggestions { return self } - self.diagnostic.span_suggestions_with_applicability( + self.diagnostic.span_suggestions( sp, msg, suggestions, @@ -258,16 +261,17 @@ impl<'a> DiagnosticBuilder<'a> { self } - pub fn span_suggestion_short_with_applicability(&mut self, - sp: Span, - msg: &str, - suggestion: String, - applicability: Applicability) - -> &mut Self { + pub fn span_suggestion_short( + &mut self, + sp: Span, + msg: &str, + suggestion: String, + applicability: Applicability, + ) -> &mut Self { if !self.allow_suggestions { return self } - self.diagnostic.span_suggestion_short_with_applicability( + self.diagnostic.span_suggestion_short( sp, msg, suggestion, @@ -275,6 +279,45 @@ impl<'a> DiagnosticBuilder<'a> { ); self } + + pub fn span_suggestion_hidden( + &mut self, + sp: Span, + msg: &str, + suggestion: String, + applicability: Applicability, + ) -> &mut Self { + if !self.allow_suggestions { + return self + } + self.diagnostic.span_suggestion_hidden( + sp, + msg, + suggestion, + applicability, + ); + self + } + + pub fn tool_only_span_suggestion( + &mut self, + sp: Span, + msg: &str, + suggestion: String, + applicability: Applicability, + ) -> &mut Self { + if !self.allow_suggestions { + return self + } + self.diagnostic.tool_only_span_suggestion( + sp, + msg, + suggestion, + applicability, + ); + self + } + forward!(pub fn set_span>(&mut self, sp: S) -> &mut Self); forward!(pub fn code(&mut self, s: DiagnosticId) -> &mut Self); @@ -313,7 +356,7 @@ impl<'a> DiagnosticBuilder<'a> { } impl<'a> Debug for DiagnosticBuilder<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.diagnostic.fmt(f) } } diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index 0443b2228e5b4..e9f269b6e2410 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -1,37 +1,38 @@ -use self::Destination::*; +use Destination::*; use syntax_pos::{SourceFile, Span, MultiSpan}; -use {Level, CodeSuggestion, DiagnosticBuilder, SubDiagnostic, SourceMapperDyn, DiagnosticId}; -use snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, StyledString, Style}; -use styled_buffer::StyledBuffer; +use crate::{ + Level, CodeSuggestion, DiagnosticBuilder, SubDiagnostic, + SuggestionStyle, SourceMapperDyn, DiagnosticId, +}; +use crate::snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, StyledString, Style}; +use crate::styled_buffer::StyledBuffer; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; -use atty; use std::borrow::Cow; use std::io::prelude::*; use std::io; use std::cmp::{min, Reverse}; use termcolor::{StandardStream, ColorChoice, ColorSpec, BufferWriter}; use termcolor::{WriteColor, Color, Buffer}; -use unicode_width; 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(&mut self, db: &DiagnosticBuilder<'_>); - /// Check if should show explanations about "rustc --explain" + /// Checks if should show explanations about "rustc --explain" fn should_show_explain(&self) -> bool { true } } impl Emitter for EmitterWriter { - fn emit(&mut self, db: &DiagnosticBuilder) { + fn emit(&mut self, db: &DiagnosticBuilder<'_>) { let mut primary_span = db.span.clone(); let mut children = db.children.clone(); let mut suggestions: &[_] = &[]; @@ -45,9 +46,14 @@ impl Emitter for EmitterWriter { // don't display long messages as labels sugg.msg.split_whitespace().count() < 10 && // don't display multiline suggestions as labels - !sugg.substitutions[0].parts[0].snippet.contains('\n') { + !sugg.substitutions[0].parts[0].snippet.contains('\n') && + // when this style is set we want the suggestion to be a message, not inline + sugg.style != SuggestionStyle::HideCodeAlways && + // trivial suggestion for tooling's sake, never shown + sugg.style != SuggestionStyle::CompletelyHidden + { let substitution = &sugg.substitutions[0].parts[0].snippet.trim(); - let msg = if substitution.len() == 0 || !sugg.show_code_when_inline { + let msg = if substitution.len() == 0 || sugg.style.hide_inline() { // This substitution is only removal or we explicitly don't want to show the // code inline, don't show it format!("help: {}", sugg.msg) @@ -674,8 +680,8 @@ impl EmitterWriter { // | | something about `foo` // | something about `fn foo()` annotations_position.sort_by(|a, b| { - // Decreasing order - a.1.len().cmp(&b.1.len()).reverse() + // Decreasing order. When `a` and `b` are the same length, prefer `Primary`. + (a.1.len(), !a.1.is_primary).cmp(&(b.1.len(), !b.1.is_primary)).reverse() }); // Write the underlines. @@ -870,7 +876,7 @@ impl EmitterWriter { } } - /// Add a left margin to every line but the first, given a padding length and the label being + /// Adds a left margin to every line but the first, given a padding length and the label being /// displayed, keeping the provided highlighting. fn msg_to_buffer(&self, buffer: &mut StyledBuffer, @@ -897,7 +903,7 @@ impl EmitterWriter { // `max_line_num_len` let padding = " ".repeat(padding + label.len() + 5); - /// Return whether `style`, or the override if present and the style is `NoStyle`. + /// Returns `true` if `style`, or the override if present and the style is `NoStyle`. fn style_or_override(style: Style, override_style: Option