diff --git a/.gitmodules b/.gitmodules index d2e1fb868a99..7cd896b763f5 100644 --- a/.gitmodules +++ b/.gitmodules @@ -22,11 +22,14 @@ path = src/doc/nomicon url = https://github.com/rust-lang-nursery/nomicon.git [submodule "src/tools/cargo"] - path = cargo - url = https://github.com/rust-lang/cargo.git + path = src/tools/cargo + url = https://github.com/rust-lang/cargo [submodule "reference"] path = src/doc/reference url = https://github.com/rust-lang-nursery/reference.git [submodule "book"] path = src/doc/book - url = https://github.com/rust-lang/book + url = https://github.com/rust-lang/book.git +[submodule "src/tools/rls"] + path = src/tools/rls + url = https://github.com/rust-lang-nursery/rls diff --git a/.mailmap b/.mailmap index 4b4f343d15a9..ee5b6f257b55 100644 --- a/.mailmap +++ b/.mailmap @@ -139,6 +139,7 @@ Margaret Meyerhofer Mark Sinclair Mark Sinclair =Mark Sinclair <=125axel125@gmail.com> Markus Westerlind Markus +Martin Hafskjold Thoresen Matej Lach Matej Ľach Matt Brubeck Matthew Auld diff --git a/.travis.yml b/.travis.yml index 1faf860a3004..beb7b435cbad 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,19 +15,27 @@ matrix: - env: IMAGE=arm-android - env: IMAGE=armhf-gnu - env: IMAGE=cross DEPLOY=1 + - env: IMAGE=dist-aarch64-linux DEPLOY=1 - env: IMAGE=dist-android DEPLOY=1 - env: IMAGE=dist-arm-linux DEPLOY=1 - - env: IMAGE=dist-armv7-aarch64-linux DEPLOY=1 - - env: IMAGE=dist-freebsd DEPLOY=1 - - env: IMAGE=dist-i586-gnu-i686-musl DEPLOY=1 + - env: IMAGE=dist-armhf-linux DEPLOY=1 + - env: IMAGE=dist-armv7-linux DEPLOY=1 - env: IMAGE=dist-fuchsia DEPLOY=1 + - env: IMAGE=dist-i586-gnu-i686-musl DEPLOY=1 + - env: IMAGE=dist-i686-freebsd DEPLOY=1 + - env: IMAGE=dist-i686-linux DEPLOY=1 - env: IMAGE=dist-mips-linux DEPLOY=1 - env: IMAGE=dist-mips64-linux DEPLOY=1 + - env: IMAGE=dist-mips64el-linux DEPLOY=1 + - env: IMAGE=dist-mipsel-linux DEPLOY=1 - env: IMAGE=dist-powerpc-linux DEPLOY=1 - env: IMAGE=dist-powerpc64-linux DEPLOY=1 - - env: IMAGE=dist-s390x-linux-netbsd DEPLOY=1 - - env: IMAGE=dist-x86-linux DEPLOY=1 + - env: IMAGE=dist-powerpc64le-linux DEPLOY=1 + - env: IMAGE=dist-s390x-linux DEPLOY=1 + - env: IMAGE=dist-x86_64-freebsd DEPLOY=1 + - env: IMAGE=dist-x86_64-linux DEPLOY=1 - env: IMAGE=dist-x86_64-musl DEPLOY=1 + - env: IMAGE=dist-x86_64-netbsd DEPLOY=1 - env: IMAGE=emscripten - env: IMAGE=i686-gnu - env: IMAGE=i686-gnu-nopt @@ -40,10 +48,13 @@ matrix: - env: IMAGE=x86_64-gnu-distcheck - env: IMAGE=x86_64-gnu-incremental - # OSX builders + # OSX builders running tests, these run the full test suite. + # + # Note that the compiler is compiled to target 10.8 here because the Xcode + # version that we're using, 8.2, cannot compile LLVM for OSX 10.7. - env: > RUST_CHECK_TARGET=check - RUST_CONFIGURE_ARGS=--build=x86_64-apple-darwin + RUST_CONFIGURE_ARGS="--build=x86_64-apple-darwin --enable-sanitizers" SRC=. RUSTC_RETRY_LINKER_ON_SEGFAULT=1 SCCACHE_ERROR_LOG=/tmp/sccache.log @@ -52,7 +63,7 @@ matrix: os: osx osx_image: xcode8.2 install: &osx_install_sccache > - travis_retry curl -o /usr/local/bin/sccache https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-apple-darwin && + travis_retry curl -o /usr/local/bin/sccache https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-29-sccache-x86_64-apple-darwin && chmod +x /usr/local/bin/sccache && travis_retry curl -o /usr/local/bin/stamp https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-17-stamp-x86_64-apple-darwin && chmod +x /usr/local/bin/stamp @@ -68,6 +79,12 @@ matrix: osx_image: xcode8.2 install: *osx_install_sccache + # OSX builders producing releases. These do not run the full test suite and + # just produce a bunch of artifacts. + # + # Note that these are running in the `xcode7` image instead of the + # `xcode8.2` image as above. That's because we want to build releases for + # OSX 10.7 and `xcode7` is the latest Xcode able to compile LLVM for 10.7. - env: > RUST_CHECK_TARGET=dist RUST_CONFIGURE_ARGS="--build=i686-apple-darwin --enable-extended" @@ -75,29 +92,33 @@ matrix: DEPLOY=1 RUSTC_RETRY_LINKER_ON_SEGFAULT=1 SCCACHE_ERROR_LOG=/tmp/sccache.log - MACOSX_DEPLOYMENT_TARGET=10.8 - MACOSX_STD_DEPLOYMENT_TARGET=10.7 + MACOSX_DEPLOYMENT_TARGET=10.7 os: osx - osx_image: xcode8.2 - install: *osx_install_sccache + osx_image: xcode7 + install: + - travis_retry brew update + - travis_retry brew install xz + - *osx_install_sccache - env: > RUST_CHECK_TARGET=dist - RUST_CONFIGURE_ARGS="--target=aarch64-apple-ios,armv7-apple-ios,armv7s-apple-ios,i386-apple-ios,x86_64-apple-ios --enable-extended" + RUST_CONFIGURE_ARGS="--target=aarch64-apple-ios,armv7-apple-ios,armv7s-apple-ios,i386-apple-ios,x86_64-apple-ios --enable-extended --enable-sanitizers" SRC=. DEPLOY=1 RUSTC_RETRY_LINKER_ON_SEGFAULT=1 SCCACHE_ERROR_LOG=/tmp/sccache.log - MACOSX_DEPLOYMENT_TARGET=10.8 - MACOSX_STD_DEPLOYMENT_TARGET=10.7 + MACOSX_DEPLOYMENT_TARGET=10.7 os: osx - osx_image: xcode8.2 - install: *osx_install_sccache + osx_image: xcode7 + install: + - travis_retry brew update + - travis_retry brew install xz + - *osx_install_sccache # "alternate" deployments, these are "nightlies" but don't have assertions # turned on, they're deployed to a different location primarily for projects # which are stuck on nightly and don't want llvm assertions in the artifacts # that they use. - - env: IMAGE=dist-x86-linux DEPLOY_ALT=1 + - env: IMAGE=dist-x86_64-linux DEPLOY_ALT=1 - env: > RUST_CHECK_TARGET=dist RUST_CONFIGURE_ARGS="--enable-extended" @@ -105,11 +126,13 @@ matrix: DEPLOY_ALT=1 RUSTC_RETRY_LINKER_ON_SEGFAULT=1 SCCACHE_ERROR_LOG=/tmp/sccache.log - MACOSX_DEPLOYMENT_TARGET=10.8 - MACOSX_STD_DEPLOYMENT_TARGET=10.7 + MACOSX_DEPLOYMENT_TARGET=10.7 os: osx - osx_image: xcode8.2 - install: *osx_install_sccache + osx_image: xcode7 + install: + - travis_retry brew update + - travis_retry brew install xz + - *osx_install_sccache env: global: @@ -133,13 +156,14 @@ before_script: script: - > if [ "$ALLOW_PR" = "" ] && [ "$TRAVIS_BRANCH" != "auto" ]; then - echo skipping, not a full build; - elif [ "$TRAVIS_OS_NAME" = "osx" ]; then - travis_retry stamp sh -c 'git submodule deinit -f . && git submodule update --init' && - stamp src/ci/run.sh; + echo skipping, not a full build else - travis_retry stamp sh -c 'git submodule deinit -f . && git submodule update --init' && - stamp src/ci/docker/run.sh $IMAGE; + stamp src/ci/init_repo.sh . "$HOME/rustsrc" && + if [ "$TRAVIS_OS_NAME" = "osx" ]; then + stamp src/ci/run.sh; + else + stamp src/ci/docker/run.sh $IMAGE; + fi fi after_success: @@ -169,6 +193,9 @@ after_failure: - dmesg | grep -i kill # Save tagged docker images we created and load them if they're available +# Travis saves caches whether the build failed or not, nuke rustsrc if +# the failure was while updating it (as it may be in an bad state) +# https://github.com/travis-ci/travis-ci/issues/4472 before_cache: - docker history -q rust-ci | grep -v missing | @@ -176,6 +203,7 @@ before_cache: gzip > $HOME/docker/rust-ci.tar.gz before_install: - zcat $HOME/docker/rust-ci.tar.gz | docker load || true + - mkdir -p $HOME/rustsrc notifications: email: false diff --git a/README.md b/README.md index fca7d1cc5bd3..f387b4be6008 100644 --- a/README.md +++ b/README.md @@ -198,8 +198,8 @@ The Rust community congregates in a few places: * [users.rust-lang.org] - General discussion and broader questions. * [/r/rust] - News and general discussion. -[Stack Overflow]: http://stackoverflow.com/questions/tagged/rust -[/r/rust]: http://reddit.com/r/rust +[Stack Overflow]: https://stackoverflow.com/questions/tagged/rust +[/r/rust]: https://reddit.com/r/rust [users.rust-lang.org]: https://users.rust-lang.org/ ## Contributing diff --git a/RELEASES.md b/RELEASES.md index d7f28ae2909a..571389041d6b 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -949,44 +949,33 @@ Version 1.12.0 (2016-09-29) Highlights ---------- -* [`rustc` translates code to LLVM IR via its own "middle" IR (MIR)] - (https://github.com/rust-lang/rust/pull/34096). +* [`rustc` translates code to LLVM IR via its own "middle" IR (MIR)](https://github.com/rust-lang/rust/pull/34096). This translation pass is far simpler than the previous AST->LLVM pass, and creates opportunities to perform new optimizations directly on the MIR. It - was previously described [on the Rust blog] - (https://blog.rust-lang.org/2016/04/19/MIR.html). + was previously described [on the Rust blog](https://blog.rust-lang.org/2016/04/19/MIR.html). * [`rustc` presents a new, more readable error format, along with - machine-readable JSON error output for use by IDEs] - (https://github.com/rust-lang/rust/pull/35401). + machine-readable JSON error output for use by IDEs](https://github.com/rust-lang/rust/pull/35401). Most common editors supporting Rust have been updated to work with it. It was - previously described [on the Rust blog] - (https://blog.rust-lang.org/2016/08/10/Shape-of-errors-to-come.html). + previously described [on the Rust blog](https://blog.rust-lang.org/2016/08/10/Shape-of-errors-to-come.html). Compiler -------- -* [`rustc` translates code to LLVM IR via its own "middle" IR (MIR)] - (https://github.com/rust-lang/rust/pull/34096). +* [`rustc` translates code to LLVM IR via its own "middle" IR (MIR)](https://github.com/rust-lang/rust/pull/34096). This translation pass is far simpler than the previous AST->LLVM pass, and creates opportunities to perform new optimizations directly on the MIR. It - was previously described [on the Rust blog] - (https://blog.rust-lang.org/2016/04/19/MIR.html). + was previously described [on the Rust blog](https://blog.rust-lang.org/2016/04/19/MIR.html). * [Print the Rust target name, not the LLVM target name, with - `--print target-list`] - (https://github.com/rust-lang/rust/pull/35489) + `--print target-list`](https://github.com/rust-lang/rust/pull/35489) * [The computation of `TypeId` is correct in some cases where it was previously - producing inconsistent results] - (https://github.com/rust-lang/rust/pull/35267) -* [The `mips-unknown-linux-gnu` target uses hardware floating point by default] - (https://github.com/rust-lang/rust/pull/34910) + producing inconsistent results](https://github.com/rust-lang/rust/pull/35267) +* [The `mips-unknown-linux-gnu` target uses hardware floating point by default](https://github.com/rust-lang/rust/pull/34910) * [The `rustc` arguments, `--print target-cpus`, `--print target-features`, `--print relocation-models`, and `--print code-models` print the available options to the `-C target-cpu`, `-C target-feature`, `-C relocation-model` and - `-C code-model` code generation arguments] - (https://github.com/rust-lang/rust/pull/34845) + `-C code-model` code generation arguments](https://github.com/rust-lang/rust/pull/34845) * [`rustc` supports three new MUSL targets on ARM: `arm-unknown-linux-musleabi`, - `arm-unknown-linux-musleabihf`, and `armv7-unknown-linux-musleabihf`] - (https://github.com/rust-lang/rust/pull/35060). + `arm-unknown-linux-musleabihf`, and `armv7-unknown-linux-musleabihf`](https://github.com/rust-lang/rust/pull/35060). These targets produce statically-linked binaries. There are no binary release builds yet though. @@ -994,209 +983,134 @@ Diagnostics ----------- * [`rustc` presents a new, more readable error format, along with - machine-readable JSON error output for use by IDEs] - (https://github.com/rust-lang/rust/pull/35401). + machine-readable JSON error output for use by IDEs](https://github.com/rust-lang/rust/pull/35401). Most common editors supporting Rust have been updated to work with it. It was - previously described [on the Rust blog] - (https://blog.rust-lang.org/2016/08/10/Shape-of-errors-to-come.html). + previously described [on the Rust blog](https://blog.rust-lang.org/2016/08/10/Shape-of-errors-to-come.html). * [In error descriptions, references are now described in plain English, - instead of as "&-ptr"] - (https://github.com/rust-lang/rust/pull/35611) + instead of as "&-ptr"](https://github.com/rust-lang/rust/pull/35611) * [In error type descriptions, unknown numeric types are named `{integer}` or - `{float}` instead of `_`] - (https://github.com/rust-lang/rust/pull/35080) -* [`rustc` emits a clearer error when inner attributes follow a doc comment] - (https://github.com/rust-lang/rust/pull/34676) + `{float}` instead of `_`](https://github.com/rust-lang/rust/pull/35080) +* [`rustc` emits a clearer error when inner attributes follow a doc comment](https://github.com/rust-lang/rust/pull/34676) Language -------- -* [`macro_rules!` invocations can be made within `macro_rules!` invocations] - (https://github.com/rust-lang/rust/pull/34925) -* [`macro_rules!` meta-variables are hygienic] - (https://github.com/rust-lang/rust/pull/35453) +* [`macro_rules!` invocations can be made within `macro_rules!` invocations](https://github.com/rust-lang/rust/pull/34925) +* [`macro_rules!` meta-variables are hygienic](https://github.com/rust-lang/rust/pull/35453) * [`macro_rules!` `tt` matchers can be reparsed correctly, making them much more - useful] - (https://github.com/rust-lang/rust/pull/34908) + useful](https://github.com/rust-lang/rust/pull/34908) * [`macro_rules!` `stmt` matchers correctly consume the entire contents when - inside non-braces invocations] - (https://github.com/rust-lang/rust/pull/34886) + inside non-braces invocations](https://github.com/rust-lang/rust/pull/34886) * [Semicolons are properly required as statement delimeters inside - `macro_rules!` invocations] - (https://github.com/rust-lang/rust/pull/34660) -* [`cfg_attr` works on `path` attributes] - (https://github.com/rust-lang/rust/pull/34546) + `macro_rules!` invocations](https://github.com/rust-lang/rust/pull/34660) +* [`cfg_attr` works on `path` attributes](https://github.com/rust-lang/rust/pull/34546) Stabilized APIs --------------- -* [`Cell::as_ptr`] - (https://doc.rust-lang.org/std/cell/struct.Cell.html#method.as_ptr) -* [`RefCell::as_ptr`] - (https://doc.rust-lang.org/std/cell/struct.RefCell.html#method.as_ptr) -* [`IpAddr::is_unspecified`] - (https://doc.rust-lang.org/std/net/enum.IpAddr.html#method.is_unspecified) -* [`IpAddr::is_loopback`] - (https://doc.rust-lang.org/std/net/enum.IpAddr.html#method.is_loopback) -* [`IpAddr::is_multicast`] - (https://doc.rust-lang.org/std/net/enum.IpAddr.html#method.is_multicast) -* [`Ipv4Addr::is_unspecified`] - (https://doc.rust-lang.org/std/net/struct.Ipv4Addr.html#method.is_unspecified) -* [`Ipv6Addr::octets`] - (https://doc.rust-lang.org/std/net/struct.Ipv6Addr.html#method.octets) -* [`LinkedList::contains`] - (https://doc.rust-lang.org/std/collections/linked_list/struct.LinkedList.html#method.contains) -* [`VecDeque::contains`] - (https://doc.rust-lang.org/std/collections/vec_deque/struct.VecDeque.html#method.contains) -* [`ExitStatusExt::from_raw`] - (https://doc.rust-lang.org/std/os/unix/process/trait.ExitStatusExt.html#tymethod.from_raw). +* [`Cell::as_ptr`](https://doc.rust-lang.org/std/cell/struct.Cell.html#method.as_ptr) +* [`RefCell::as_ptr`](https://doc.rust-lang.org/std/cell/struct.RefCell.html#method.as_ptr) +* [`IpAddr::is_unspecified`](https://doc.rust-lang.org/std/net/enum.IpAddr.html#method.is_unspecified) +* [`IpAddr::is_loopback`](https://doc.rust-lang.org/std/net/enum.IpAddr.html#method.is_loopback) +* [`IpAddr::is_multicast`](https://doc.rust-lang.org/std/net/enum.IpAddr.html#method.is_multicast) +* [`Ipv4Addr::is_unspecified`](https://doc.rust-lang.org/std/net/struct.Ipv4Addr.html#method.is_unspecified) +* [`Ipv6Addr::octets`](https://doc.rust-lang.org/std/net/struct.Ipv6Addr.html#method.octets) +* [`LinkedList::contains`](https://doc.rust-lang.org/std/collections/linked_list/struct.LinkedList.html#method.contains) +* [`VecDeque::contains`](https://doc.rust-lang.org/std/collections/vec_deque/struct.VecDeque.html#method.contains) +* [`ExitStatusExt::from_raw`](https://doc.rust-lang.org/std/os/unix/process/trait.ExitStatusExt.html#tymethod.from_raw). Both on Unix and Windows. -* [`Receiver::recv_timeout`] - (https://doc.rust-lang.org/std/sync/mpsc/struct.Receiver.html#method.recv_timeout) -* [`RecvTimeoutError`] - (https://doc.rust-lang.org/std/sync/mpsc/enum.RecvTimeoutError.html) -* [`BinaryHeap::peek_mut`] - (https://doc.rust-lang.org/std/collections/binary_heap/struct.BinaryHeap.html#method.peek_mut) -* [`PeekMut`] - (https://doc.rust-lang.org/std/collections/binary_heap/struct.PeekMut.html) -* [`iter::Product`] - (https://doc.rust-lang.org/std/iter/trait.Product.html) -* [`iter::Sum`] - (https://doc.rust-lang.org/std/iter/trait.Sum.html) -* [`OccupiedEntry::remove_entry`] - (https://doc.rust-lang.org/std/collections/btree_map/struct.OccupiedEntry.html#method.remove_entry) -* [`VacantEntry::into_key`] - (https://doc.rust-lang.org/std/collections/btree_map/struct.VacantEntry.html#method.into_key) +* [`Receiver::recv_timeout`](https://doc.rust-lang.org/std/sync/mpsc/struct.Receiver.html#method.recv_timeout) +* [`RecvTimeoutError`](https://doc.rust-lang.org/std/sync/mpsc/enum.RecvTimeoutError.html) +* [`BinaryHeap::peek_mut`](https://doc.rust-lang.org/std/collections/binary_heap/struct.BinaryHeap.html#method.peek_mut) +* [`PeekMut`](https://doc.rust-lang.org/std/collections/binary_heap/struct.PeekMut.html) +* [`iter::Product`](https://doc.rust-lang.org/std/iter/trait.Product.html) +* [`iter::Sum`](https://doc.rust-lang.org/std/iter/trait.Sum.html) +* [`OccupiedEntry::remove_entry`](https://doc.rust-lang.org/std/collections/btree_map/struct.OccupiedEntry.html#method.remove_entry) +* [`VacantEntry::into_key`](https://doc.rust-lang.org/std/collections/btree_map/struct.VacantEntry.html#method.into_key) Libraries --------- * [The `format!` macro and friends now allow a single argument to be formatted - in multiple styles] - (https://github.com/rust-lang/rust/pull/33642) + in multiple styles](https://github.com/rust-lang/rust/pull/33642) * [The lifetime bounds on `[T]::binary_search_by` and - `[T]::binary_search_by_key` have been adjusted to be more flexible] - (https://github.com/rust-lang/rust/pull/34762) -* [`Option` implements `From` for its contained type] - (https://github.com/rust-lang/rust/pull/34828) -* [`Cell`, `RefCell` and `UnsafeCell` implement `From` for their contained type] - (https://github.com/rust-lang/rust/pull/35392) -* [`RwLock` panics if the reader count overflows] - (https://github.com/rust-lang/rust/pull/35378) -* [`vec_deque::Drain`, `hash_map::Drain` and `hash_set::Drain` are covariant] - (https://github.com/rust-lang/rust/pull/35354) -* [`vec::Drain` and `binary_heap::Drain` are covariant] - (https://github.com/rust-lang/rust/pull/34951) -* [`Cow` implements `FromIterator` for `char`, `&str` and `String`] - (https://github.com/rust-lang/rust/pull/35064) -* [Sockets on Linux are correctly closed in subprocesses via `SOCK_CLOEXEC`] - (https://github.com/rust-lang/rust/pull/34946) + `[T]::binary_search_by_key` have been adjusted to be more flexible](https://github.com/rust-lang/rust/pull/34762) +* [`Option` implements `From` for its contained type](https://github.com/rust-lang/rust/pull/34828) +* [`Cell`, `RefCell` and `UnsafeCell` implement `From` for their contained type](https://github.com/rust-lang/rust/pull/35392) +* [`RwLock` panics if the reader count overflows](https://github.com/rust-lang/rust/pull/35378) +* [`vec_deque::Drain`, `hash_map::Drain` and `hash_set::Drain` are covariant](https://github.com/rust-lang/rust/pull/35354) +* [`vec::Drain` and `binary_heap::Drain` are covariant](https://github.com/rust-lang/rust/pull/34951) +* [`Cow` implements `FromIterator` for `char`, `&str` and `String`](https://github.com/rust-lang/rust/pull/35064) +* [Sockets on Linux are correctly closed in subprocesses via `SOCK_CLOEXEC`](https://github.com/rust-lang/rust/pull/34946) * [`hash_map::Entry`, `hash_map::VacantEntry` and `hash_map::OccupiedEntry` - implement `Debug`] - (https://github.com/rust-lang/rust/pull/34937) + implement `Debug`](https://github.com/rust-lang/rust/pull/34937) * [`btree_map::Entry`, `btree_map::VacantEntry` and `btree_map::OccupiedEntry` - implement `Debug`] - (https://github.com/rust-lang/rust/pull/34885) -* [`String` implements `AddAssign`] - (https://github.com/rust-lang/rust/pull/34890) + implement `Debug`](https://github.com/rust-lang/rust/pull/34885) +* [`String` implements `AddAssign`](https://github.com/rust-lang/rust/pull/34890) * [Variadic `extern fn` pointers implement the `Clone`, `PartialEq`, `Eq`, - `PartialOrd`, `Ord`, `Hash`, `fmt::Pointer`, and `fmt::Debug` traits] - (https://github.com/rust-lang/rust/pull/34879) -* [`FileType` implements `Debug`] - (https://github.com/rust-lang/rust/pull/34757) -* [References to `Mutex` and `RwLock` are unwind-safe] - (https://github.com/rust-lang/rust/pull/34756) + `PartialOrd`, `Ord`, `Hash`, `fmt::Pointer`, and `fmt::Debug` traits](https://github.com/rust-lang/rust/pull/34879) +* [`FileType` implements `Debug`](https://github.com/rust-lang/rust/pull/34757) +* [References to `Mutex` and `RwLock` are unwind-safe](https://github.com/rust-lang/rust/pull/34756) * [`mpsc::sync_channel` `Receiver`s return any available message before - reporting a disconnect] - (https://github.com/rust-lang/rust/pull/34731) -* [Unicode definitions have been updated to 9.0] - (https://github.com/rust-lang/rust/pull/34599) -* [`env` iterators implement `DoubleEndedIterator`] - (https://github.com/rust-lang/rust/pull/33312) + reporting a disconnect](https://github.com/rust-lang/rust/pull/34731) +* [Unicode definitions have been updated to 9.0](https://github.com/rust-lang/rust/pull/34599) +* [`env` iterators implement `DoubleEndedIterator`](https://github.com/rust-lang/rust/pull/33312) Cargo ----- -* [Support local mirrors of registries] - (https://github.com/rust-lang/cargo/pull/2857) -* [Add support for command aliases] - (https://github.com/rust-lang/cargo/pull/2679) -* [Allow `opt-level="s"` / `opt-level="z"` in profile overrides] - (https://github.com/rust-lang/cargo/pull/3007) -* [Make `cargo doc --open --target` work as expected] - (https://github.com/rust-lang/cargo/pull/2988) -* [Speed up noop registry updates] - (https://github.com/rust-lang/cargo/pull/2974) -* [Update OpenSSL] - (https://github.com/rust-lang/cargo/pull/2971) -* [Fix `--panic=abort` with plugins] - (https://github.com/rust-lang/cargo/pull/2954) -* [Always pass `-C metadata` to the compiler] - (https://github.com/rust-lang/cargo/pull/2946) -* [Fix depending on git repos with workspaces] - (https://github.com/rust-lang/cargo/pull/2938) -* [Add a `--lib` flag to `cargo new`] - (https://github.com/rust-lang/cargo/pull/2921) -* [Add `http.cainfo` for custom certs] - (https://github.com/rust-lang/cargo/pull/2917) -* [Indicate the compilation profile after compiling] - (https://github.com/rust-lang/cargo/pull/2909) -* [Allow enabling features for dependencies with `--features`] - (https://github.com/rust-lang/cargo/pull/2876) -* [Add `--jobs` flag to `cargo package`] - (https://github.com/rust-lang/cargo/pull/2867) -* [Add `--dry-run` to `cargo publish`] - (https://github.com/rust-lang/cargo/pull/2849) -* [Add support for `RUSTDOCFLAGS`] - (https://github.com/rust-lang/cargo/pull/2794) +* [Support local mirrors of registries](https://github.com/rust-lang/cargo/pull/2857) +* [Add support for command aliases](https://github.com/rust-lang/cargo/pull/2679) +* [Allow `opt-level="s"` / `opt-level="z"` in profile overrides](https://github.com/rust-lang/cargo/pull/3007) +* [Make `cargo doc --open --target` work as expected](https://github.com/rust-lang/cargo/pull/2988) +* [Speed up noop registry updates](https://github.com/rust-lang/cargo/pull/2974) +* [Update OpenSSL](https://github.com/rust-lang/cargo/pull/2971) +* [Fix `--panic=abort` with plugins](https://github.com/rust-lang/cargo/pull/2954) +* [Always pass `-C metadata` to the compiler](https://github.com/rust-lang/cargo/pull/2946) +* [Fix depending on git repos with workspaces](https://github.com/rust-lang/cargo/pull/2938) +* [Add a `--lib` flag to `cargo new`](https://github.com/rust-lang/cargo/pull/2921) +* [Add `http.cainfo` for custom certs](https://github.com/rust-lang/cargo/pull/2917) +* [Indicate the compilation profile after compiling](https://github.com/rust-lang/cargo/pull/2909) +* [Allow enabling features for dependencies with `--features`](https://github.com/rust-lang/cargo/pull/2876) +* [Add `--jobs` flag to `cargo package`](https://github.com/rust-lang/cargo/pull/2867) +* [Add `--dry-run` to `cargo publish`](https://github.com/rust-lang/cargo/pull/2849) +* [Add support for `RUSTDOCFLAGS`](https://github.com/rust-lang/cargo/pull/2794) Performance ----------- -* [`panic::catch_unwind` is more optimized] - (https://github.com/rust-lang/rust/pull/35444) -* [`panic::catch_unwind` no longer accesses thread-local storage on entry] - (https://github.com/rust-lang/rust/pull/34866) +* [`panic::catch_unwind` is more optimized](https://github.com/rust-lang/rust/pull/35444) +* [`panic::catch_unwind` no longer accesses thread-local storage on entry](https://github.com/rust-lang/rust/pull/34866) Tooling ------- * [Test binaries now support a `--test-threads` argument to specify the number of threads used to run tests, and which acts the same as the - `RUST_TEST_THREADS` environment variable] - (https://github.com/rust-lang/rust/pull/35414) -* [The test runner now emits a warning when tests run over 60 seconds] - (https://github.com/rust-lang/rust/pull/35405) -* [rustdoc: Fix methods in search results] - (https://github.com/rust-lang/rust/pull/34752) -* [`rust-lldb` warns about unsupported versions of LLDB] - (https://github.com/rust-lang/rust/pull/34646) + `RUST_TEST_THREADS` environment variable](https://github.com/rust-lang/rust/pull/35414) +* [The test runner now emits a warning when tests run over 60 seconds](https://github.com/rust-lang/rust/pull/35405) +* [rustdoc: Fix methods in search results](https://github.com/rust-lang/rust/pull/34752) +* [`rust-lldb` warns about unsupported versions of LLDB](https://github.com/rust-lang/rust/pull/34646) * [Rust releases now come with source packages that can be installed by rustup - via `rustup component add rust-src`] - (https://github.com/rust-lang/rust/pull/34366). + via `rustup component add rust-src`](https://github.com/rust-lang/rust/pull/34366). The resulting source code can be used by tools and IDES, located in the sysroot under `lib/rustlib/src`. Misc ---- -* [The compiler can now be built against LLVM 3.9] - (https://github.com/rust-lang/rust/pull/35594) +* [The compiler can now be built against LLVM 3.9](https://github.com/rust-lang/rust/pull/35594) * Many minor improvements to the documentation. -* [The Rust exception handling "personality" routine is now written in Rust] - (https://github.com/rust-lang/rust/pull/34832) +* [The Rust exception handling "personality" routine is now written in Rust](https://github.com/rust-lang/rust/pull/34832) Compatibility Notes ------------------- * [When printing Windows `OsStr`s, unpaired surrogate codepoints are escaped - with the lowercase format instead of the uppercase] - (https://github.com/rust-lang/rust/pull/35084) + with the lowercase format instead of the uppercase](https://github.com/rust-lang/rust/pull/35084) * [When formatting strings, if "precision" is specified, the "fill", - "align" and "width" specifiers are no longer ignored] - (https://github.com/rust-lang/rust/pull/34544) -* [The `Debug` impl for strings no longer escapes all non-ASCII characters] - (https://github.com/rust-lang/rust/pull/34485) + "align" and "width" specifiers are no longer ignored](https://github.com/rust-lang/rust/pull/34544) +* [The `Debug` impl for strings no longer escapes all non-ASCII characters](https://github.com/rust-lang/rust/pull/34485) Version 1.11.0 (2016-08-18) @@ -1205,142 +1119,92 @@ Version 1.11.0 (2016-08-18) Language -------- -* [`cfg_attr` works on `path` attributes] - (https://github.com/rust-lang/rust/pull/34546) -* [Support nested `cfg_attr` attributes] - (https://github.com/rust-lang/rust/pull/34216) -* [Allow statement-generating braced macro invocations at the end of blocks] - (https://github.com/rust-lang/rust/pull/34436) -* [Macros can be expanded inside of trait definitions] - (https://github.com/rust-lang/rust/pull/34213) -* [`#[macro_use]` works properly when it is itself expanded from a macro] - (https://github.com/rust-lang/rust/pull/34032) +* [`cfg_attr` works on `path` attributes](https://github.com/rust-lang/rust/pull/34546) +* [Support nested `cfg_attr` attributes](https://github.com/rust-lang/rust/pull/34216) +* [Allow statement-generating braced macro invocations at the end of blocks](https://github.com/rust-lang/rust/pull/34436) +* [Macros can be expanded inside of trait definitions](https://github.com/rust-lang/rust/pull/34213) +* [`#[macro_use]` works properly when it is itself expanded from a macro](https://github.com/rust-lang/rust/pull/34032) Stabilized APIs --------------- -* [`BinaryHeap::append`] - (https://doc.rust-lang.org/std/collections/binary_heap/struct.BinaryHeap.html#method.append) -* [`BTreeMap::append`] - (https://doc.rust-lang.org/std/collections/btree_map/struct.BTreeMap.html#method.append) -* [`BTreeMap::split_off`] - (https://doc.rust-lang.org/std/collections/btree_map/struct.BTreeMap.html#method.split_off) -* [`BTreeSet::append`] - (https://doc.rust-lang.org/std/collections/btree_set/struct.BTreeSet.html#method.append) -* [`BTreeSet::split_off`] - (https://doc.rust-lang.org/std/collections/btree_set/struct.BTreeSet.html#method.split_off) -* [`f32::to_degrees`] - (https://doc.rust-lang.org/std/primitive.f32.html#method.to_degrees) +* [`BinaryHeap::append`](https://doc.rust-lang.org/std/collections/binary_heap/struct.BinaryHeap.html#method.append) +* [`BTreeMap::append`](https://doc.rust-lang.org/std/collections/btree_map/struct.BTreeMap.html#method.append) +* [`BTreeMap::split_off`](https://doc.rust-lang.org/std/collections/btree_map/struct.BTreeMap.html#method.split_off) +* [`BTreeSet::append`](https://doc.rust-lang.org/std/collections/btree_set/struct.BTreeSet.html#method.append) +* [`BTreeSet::split_off`](https://doc.rust-lang.org/std/collections/btree_set/struct.BTreeSet.html#method.split_off) +* [`f32::to_degrees`](https://doc.rust-lang.org/std/primitive.f32.html#method.to_degrees) (in libcore - previously stabilized in libstd) -* [`f32::to_radians`] - (https://doc.rust-lang.org/std/primitive.f32.html#method.to_radians) +* [`f32::to_radians`](https://doc.rust-lang.org/std/primitive.f32.html#method.to_radians) (in libcore - previously stabilized in libstd) -* [`f64::to_degrees`] - (https://doc.rust-lang.org/std/primitive.f64.html#method.to_degrees) +* [`f64::to_degrees`](https://doc.rust-lang.org/std/primitive.f64.html#method.to_degrees) (in libcore - previously stabilized in libstd) -* [`f64::to_radians`] - (https://doc.rust-lang.org/std/primitive.f64.html#method.to_radians) +* [`f64::to_radians`](https://doc.rust-lang.org/std/primitive.f64.html#method.to_radians) (in libcore - previously stabilized in libstd) -* [`Iterator::sum`] - (https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.sum) -* [`Iterator::product`] - (https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.sum) -* [`Cell::get_mut`] - (https://doc.rust-lang.org/std/cell/struct.Cell.html#method.get_mut) -* [`RefCell::get_mut`] - (https://doc.rust-lang.org/std/cell/struct.RefCell.html#method.get_mut) +* [`Iterator::sum`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.sum) +* [`Iterator::product`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.sum) +* [`Cell::get_mut`](https://doc.rust-lang.org/std/cell/struct.Cell.html#method.get_mut) +* [`RefCell::get_mut`](https://doc.rust-lang.org/std/cell/struct.RefCell.html#method.get_mut) Libraries --------- * [The `thread_local!` macro supports multiple definitions in a single - invocation, and can apply attributes] - (https://github.com/rust-lang/rust/pull/34077) -* [`Cow` implements `Default`] - (https://github.com/rust-lang/rust/pull/34305) + invocation, and can apply attributes](https://github.com/rust-lang/rust/pull/34077) +* [`Cow` implements `Default`](https://github.com/rust-lang/rust/pull/34305) * [`Wrapping` implements binary, octal, lower-hex and upper-hex - `Display` formatting] - (https://github.com/rust-lang/rust/pull/34190) -* [The range types implement `Hash`] - (https://github.com/rust-lang/rust/pull/34180) -* [`lookup_host` ignores unknown address types] - (https://github.com/rust-lang/rust/pull/34067) -* [`assert_eq!` accepts a custom error message, like `assert!` does] - (https://github.com/rust-lang/rust/pull/33976) -* [The main thread is now called "main" instead of "<main>"] - (https://github.com/rust-lang/rust/pull/33803) + `Display` formatting](https://github.com/rust-lang/rust/pull/34190) +* [The range types implement `Hash`](https://github.com/rust-lang/rust/pull/34180) +* [`lookup_host` ignores unknown address types](https://github.com/rust-lang/rust/pull/34067) +* [`assert_eq!` accepts a custom error message, like `assert!` does](https://github.com/rust-lang/rust/pull/33976) +* [The main thread is now called "main" instead of "<main>"](https://github.com/rust-lang/rust/pull/33803) Cargo ----- -* [Disallow specifying features of transitive deps] - (https://github.com/rust-lang/cargo/pull/2821) -* [Add color support for Windows consoles] - (https://github.com/rust-lang/cargo/pull/2804) -* [Fix `harness = false` on `[lib]` sections] - (https://github.com/rust-lang/cargo/pull/2795) -* [Don't panic when `links` contains a '.'] - (https://github.com/rust-lang/cargo/pull/2787) -* [Build scripts can emit warnings] - (https://github.com/rust-lang/cargo/pull/2630), +* [Disallow specifying features of transitive deps](https://github.com/rust-lang/cargo/pull/2821) +* [Add color support for Windows consoles](https://github.com/rust-lang/cargo/pull/2804) +* [Fix `harness = false` on `[lib]` sections](https://github.com/rust-lang/cargo/pull/2795) +* [Don't panic when `links` contains a '.'](https://github.com/rust-lang/cargo/pull/2787) +* [Build scripts can emit warnings](https://github.com/rust-lang/cargo/pull/2630), and `-vv` prints warnings for all crates. -* [Ignore file locks on OS X NFS mounts] - (https://github.com/rust-lang/cargo/pull/2720) -* [Don't warn about `package.metadata` keys] - (https://github.com/rust-lang/cargo/pull/2668). +* [Ignore file locks on OS X NFS mounts](https://github.com/rust-lang/cargo/pull/2720) +* [Don't warn about `package.metadata` keys](https://github.com/rust-lang/cargo/pull/2668). This provides room for expansion by arbitrary tools. -* [Add support for cdylib crate types] - (https://github.com/rust-lang/cargo/pull/2741) -* [Prevent publishing crates when files are dirty] - (https://github.com/rust-lang/cargo/pull/2781) -* [Don't fetch all crates on clean] - (https://github.com/rust-lang/cargo/pull/2704) -* [Propagate --color option to rustc] - (https://github.com/rust-lang/cargo/pull/2779) -* [Fix `cargo doc --open` on Windows] - (https://github.com/rust-lang/cargo/pull/2780) -* [Improve autocompletion] - (https://github.com/rust-lang/cargo/pull/2772) -* [Configure colors of stderr as well as stdout] - (https://github.com/rust-lang/cargo/pull/2739) +* [Add support for cdylib crate types](https://github.com/rust-lang/cargo/pull/2741) +* [Prevent publishing crates when files are dirty](https://github.com/rust-lang/cargo/pull/2781) +* [Don't fetch all crates on clean](https://github.com/rust-lang/cargo/pull/2704) +* [Propagate --color option to rustc](https://github.com/rust-lang/cargo/pull/2779) +* [Fix `cargo doc --open` on Windows](https://github.com/rust-lang/cargo/pull/2780) +* [Improve autocompletion](https://github.com/rust-lang/cargo/pull/2772) +* [Configure colors of stderr as well as stdout](https://github.com/rust-lang/cargo/pull/2739) Performance ----------- * [Caching projections speeds up type check dramatically for some - workloads] - (https://github.com/rust-lang/rust/pull/33816) -* [The default `HashMap` hasher is SipHash 1-3 instead of SipHash 2-4] - (https://github.com/rust-lang/rust/pull/33940) + workloads](https://github.com/rust-lang/rust/pull/33816) +* [The default `HashMap` hasher is SipHash 1-3 instead of SipHash 2-4](https://github.com/rust-lang/rust/pull/33940) This hasher is faster, but is believed to provide sufficient protection from collision attacks. -* [Comparison of `Ipv4Addr` is 10x faster] - (https://github.com/rust-lang/rust/pull/33891) +* [Comparison of `Ipv4Addr` is 10x faster](https://github.com/rust-lang/rust/pull/33891) Rustdoc ------- -* [Fix empty implementation section on some module pages] - (https://github.com/rust-lang/rust/pull/34536) -* [Fix inlined renamed reexports in import lists] - (https://github.com/rust-lang/rust/pull/34479) -* [Fix search result layout for enum variants and struct fields] - (https://github.com/rust-lang/rust/pull/34477) -* [Fix issues with source links to external crates] - (https://github.com/rust-lang/rust/pull/34387) -* [Fix redirect pages for renamed reexports] - (https://github.com/rust-lang/rust/pull/34245) +* [Fix empty implementation section on some module pages](https://github.com/rust-lang/rust/pull/34536) +* [Fix inlined renamed reexports in import lists](https://github.com/rust-lang/rust/pull/34479) +* [Fix search result layout for enum variants and struct fields](https://github.com/rust-lang/rust/pull/34477) +* [Fix issues with source links to external crates](https://github.com/rust-lang/rust/pull/34387) +* [Fix redirect pages for renamed reexports](https://github.com/rust-lang/rust/pull/34245) Tooling ------- -* [rustc is better at finding the MSVC toolchain] - (https://github.com/rust-lang/rust/pull/34492) +* [rustc is better at finding the MSVC toolchain](https://github.com/rust-lang/rust/pull/34492) * [When emitting debug info, rustc emits frame pointers for closures, - shims and glue, as it does for all other functions] - (https://github.com/rust-lang/rust/pull/33909) -* [rust-lldb warns about unsupported versions of LLDB] - (https://github.com/rust-lang/rust/pull/34646) + shims and glue, as it does for all other functions](https://github.com/rust-lang/rust/pull/33909) +* [rust-lldb warns about unsupported versions of LLDB](https://github.com/rust-lang/rust/pull/34646) * Many more errors have been given error codes and extended explanations * API documentation continues to be improved, with many new examples @@ -1349,30 +1213,22 @@ Misc ---- * [rustc no longer hangs when dependencies recursively re-export - submodules] - (https://github.com/rust-lang/rust/pull/34542) -* [rustc requires LLVM 3.7+] - (https://github.com/rust-lang/rust/pull/34104) + submodules](https://github.com/rust-lang/rust/pull/34542) +* [rustc requires LLVM 3.7+](https://github.com/rust-lang/rust/pull/34104) * [The 'How Safe and Unsafe Interact' chapter of The Rustonomicon was - rewritten] - (https://github.com/rust-lang/rust/pull/33895) -* [rustc support 16-bit pointer sizes] - (https://github.com/rust-lang/rust/pull/33460). + rewritten](https://github.com/rust-lang/rust/pull/33895) +* [rustc support 16-bit pointer sizes](https://github.com/rust-lang/rust/pull/33460). No targets use this yet, but it works toward AVR support. Compatibility Notes ------------------- -* [`const`s and `static`s may not have unsized types] - (https://github.com/rust-lang/rust/pull/34443) +* [`const`s and `static`s may not have unsized types](https://github.com/rust-lang/rust/pull/34443) * [The new follow-set rules that place restrictions on `macro_rules!` - in order to ensure syntax forward-compatibility have been enabled] - (https://github.com/rust-lang/rust/pull/33982) - This was an [ammendment to RFC 550] - (https://github.com/rust-lang/rfcs/pull/1384), + in order to ensure syntax forward-compatibility have been enabled](https://github.com/rust-lang/rust/pull/33982) + This was an [ammendment to RFC 550](https://github.com/rust-lang/rfcs/pull/1384), and has been a warning since 1.10. -* [`cfg` attribute process has been refactored to fix various bugs] - (https://github.com/rust-lang/rust/pull/33706). +* [`cfg` attribute process has been refactored to fix various bugs](https://github.com/rust-lang/rust/pull/33706). This causes breakage in some corner cases. @@ -1383,21 +1239,15 @@ Language -------- * [Allow `concat_idents!` in type positions as well as in expression - positions] - (https://github.com/rust-lang/rust/pull/33735). -* [`Copy` types are required to have a trivial implementation of `Clone`] - (https://github.com/rust-lang/rust/pull/33420). + positions](https://github.com/rust-lang/rust/pull/33735). +* [`Copy` types are required to have a trivial implementation of `Clone`](https://github.com/rust-lang/rust/pull/33420). [RFC 1521](https://github.com/rust-lang/rfcs/blob/master/text/1521-copy-clone-semantics.md). -* [Single-variant enums support the `#[repr(..)]` attribute] - (https://github.com/rust-lang/rust/pull/33355). -* [Fix `#[derive(RustcEncodable)]` in the presence of other `encode` methods] - (https://github.com/rust-lang/rust/pull/32908). +* [Single-variant enums support the `#[repr(..)]` attribute](https://github.com/rust-lang/rust/pull/33355). +* [Fix `#[derive(RustcEncodable)]` in the presence of other `encode` methods](https://github.com/rust-lang/rust/pull/32908). * [`panic!` can be converted to a runtime abort with the - `-C panic=abort` flag] - (https://github.com/rust-lang/rust/pull/32900). + `-C panic=abort` flag](https://github.com/rust-lang/rust/pull/32900). [RFC 1513](https://github.com/rust-lang/rfcs/blob/master/text/1513-less-unwinding.md). -* [Add a new crate type, 'cdylib'] - (https://github.com/rust-lang/rust/pull/33553). +* [Add a new crate type, 'cdylib'](https://github.com/rust-lang/rust/pull/33553). cdylibs are dynamic libraries suitable for loading by non-Rust hosts. [RFC 1510](https://github.com/rust-lang/rfcs/blob/master/text/1510-rdylib.md). Note that Cargo does not yet directly support cdylibs. @@ -1411,242 +1261,146 @@ Stabilized APIs * `os::windows::fs::OpenOptionsExt::attributes` * `os::windows::fs::OpenOptionsExt::security_qos_flags` * `os::unix::fs::OpenOptionsExt::custom_flags` -* [`sync::Weak::new`] - (http://doc.rust-lang.org/alloc/arc/struct.Weak.html#method.new) +* [`sync::Weak::new`](http://doc.rust-lang.org/alloc/arc/struct.Weak.html#method.new) * `Default for sync::Weak` -* [`panic::set_hook`] - (http://doc.rust-lang.org/std/panic/fn.set_hook.html) -* [`panic::take_hook`] - (http://doc.rust-lang.org/std/panic/fn.take_hook.html) -* [`panic::PanicInfo`] - (http://doc.rust-lang.org/std/panic/struct.PanicInfo.html) -* [`panic::PanicInfo::payload`] - (http://doc.rust-lang.org/std/panic/struct.PanicInfo.html#method.payload) -* [`panic::PanicInfo::location`] - (http://doc.rust-lang.org/std/panic/struct.PanicInfo.html#method.location) -* [`panic::Location`] - (http://doc.rust-lang.org/std/panic/struct.Location.html) -* [`panic::Location::file`] - (http://doc.rust-lang.org/std/panic/struct.Location.html#method.file) -* [`panic::Location::line`] - (http://doc.rust-lang.org/std/panic/struct.Location.html#method.line) -* [`ffi::CStr::from_bytes_with_nul`] - (http://doc.rust-lang.org/std/ffi/struct.CStr.html#method.from_bytes_with_nul) -* [`ffi::CStr::from_bytes_with_nul_unchecked`] - (http://doc.rust-lang.org/std/ffi/struct.CStr.html#method.from_bytes_with_nul_unchecked) -* [`ffi::FromBytesWithNulError`] - (http://doc.rust-lang.org/std/ffi/struct.FromBytesWithNulError.html) -* [`fs::Metadata::modified`] - (http://doc.rust-lang.org/std/fs/struct.Metadata.html#method.modified) -* [`fs::Metadata::accessed`] - (http://doc.rust-lang.org/std/fs/struct.Metadata.html#method.accessed) -* [`fs::Metadata::created`] - (http://doc.rust-lang.org/std/fs/struct.Metadata.html#method.created) +* [`panic::set_hook`](http://doc.rust-lang.org/std/panic/fn.set_hook.html) +* [`panic::take_hook`](http://doc.rust-lang.org/std/panic/fn.take_hook.html) +* [`panic::PanicInfo`](http://doc.rust-lang.org/std/panic/struct.PanicInfo.html) +* [`panic::PanicInfo::payload`](http://doc.rust-lang.org/std/panic/struct.PanicInfo.html#method.payload) +* [`panic::PanicInfo::location`](http://doc.rust-lang.org/std/panic/struct.PanicInfo.html#method.location) +* [`panic::Location`](http://doc.rust-lang.org/std/panic/struct.Location.html) +* [`panic::Location::file`](http://doc.rust-lang.org/std/panic/struct.Location.html#method.file) +* [`panic::Location::line`](http://doc.rust-lang.org/std/panic/struct.Location.html#method.line) +* [`ffi::CStr::from_bytes_with_nul`](http://doc.rust-lang.org/std/ffi/struct.CStr.html#method.from_bytes_with_nul) +* [`ffi::CStr::from_bytes_with_nul_unchecked`](http://doc.rust-lang.org/std/ffi/struct.CStr.html#method.from_bytes_with_nul_unchecked) +* [`ffi::FromBytesWithNulError`](http://doc.rust-lang.org/std/ffi/struct.FromBytesWithNulError.html) +* [`fs::Metadata::modified`](http://doc.rust-lang.org/std/fs/struct.Metadata.html#method.modified) +* [`fs::Metadata::accessed`](http://doc.rust-lang.org/std/fs/struct.Metadata.html#method.accessed) +* [`fs::Metadata::created`](http://doc.rust-lang.org/std/fs/struct.Metadata.html#method.created) * `sync::atomic::Atomic{Usize,Isize,Bool,Ptr}::compare_exchange` * `sync::atomic::Atomic{Usize,Isize,Bool,Ptr}::compare_exchange_weak` * `collections::{btree,hash}_map::{Occupied,Vacant,}Entry::key` * `os::unix::net::{UnixStream, UnixListener, UnixDatagram, SocketAddr}` -* [`SocketAddr::is_unnamed`] - (http://doc.rust-lang.org/std/os/unix/net/struct.SocketAddr.html#method.is_unnamed) -* [`SocketAddr::as_pathname`] - (http://doc.rust-lang.org/std/os/unix/net/struct.SocketAddr.html#method.as_pathname) -* [`UnixStream::connect`] - (http://doc.rust-lang.org/std/os/unix/net/struct.UnixStream.html#method.connect) -* [`UnixStream::pair`] - (http://doc.rust-lang.org/std/os/unix/net/struct.UnixStream.html#method.pair) -* [`UnixStream::try_clone`] - (http://doc.rust-lang.org/std/os/unix/net/struct.UnixStream.html#method.try_clone) -* [`UnixStream::local_addr`] - (http://doc.rust-lang.org/std/os/unix/net/struct.UnixStream.html#method.local_addr) -* [`UnixStream::peer_addr`] - (http://doc.rust-lang.org/std/os/unix/net/struct.UnixStream.html#method.peer_addr) -* [`UnixStream::set_read_timeout`] - (http://doc.rust-lang.org/std/os/unix/net/struct.UnixStream.html#method.read_timeout) -* [`UnixStream::set_write_timeout`] - (http://doc.rust-lang.org/std/os/unix/net/struct.UnixStream.html#method.write_timeout) -* [`UnixStream::read_timeout`] - (http://doc.rust-lang.org/std/os/unix/net/struct.UnixStream.html#method.read_timeout) -* [`UnixStream::write_timeout`] - (http://doc.rust-lang.org/std/os/unix/net/struct.UnixStream.html#method.write_timeout) -* [`UnixStream::set_nonblocking`] - (http://doc.rust-lang.org/std/os/unix/net/struct.UnixStream.html#method.set_nonblocking) -* [`UnixStream::take_error`] - (http://doc.rust-lang.org/std/os/unix/net/struct.UnixStream.html#method.take_error) -* [`UnixStream::shutdown`] - (http://doc.rust-lang.org/std/os/unix/net/struct.UnixStream.html#method.shutdown) +* [`SocketAddr::is_unnamed`](http://doc.rust-lang.org/std/os/unix/net/struct.SocketAddr.html#method.is_unnamed) +* [`SocketAddr::as_pathname`](http://doc.rust-lang.org/std/os/unix/net/struct.SocketAddr.html#method.as_pathname) +* [`UnixStream::connect`](http://doc.rust-lang.org/std/os/unix/net/struct.UnixStream.html#method.connect) +* [`UnixStream::pair`](http://doc.rust-lang.org/std/os/unix/net/struct.UnixStream.html#method.pair) +* [`UnixStream::try_clone`](http://doc.rust-lang.org/std/os/unix/net/struct.UnixStream.html#method.try_clone) +* [`UnixStream::local_addr`](http://doc.rust-lang.org/std/os/unix/net/struct.UnixStream.html#method.local_addr) +* [`UnixStream::peer_addr`](http://doc.rust-lang.org/std/os/unix/net/struct.UnixStream.html#method.peer_addr) +* [`UnixStream::set_read_timeout`](http://doc.rust-lang.org/std/os/unix/net/struct.UnixStream.html#method.read_timeout) +* [`UnixStream::set_write_timeout`](http://doc.rust-lang.org/std/os/unix/net/struct.UnixStream.html#method.write_timeout) +* [`UnixStream::read_timeout`](http://doc.rust-lang.org/std/os/unix/net/struct.UnixStream.html#method.read_timeout) +* [`UnixStream::write_timeout`](http://doc.rust-lang.org/std/os/unix/net/struct.UnixStream.html#method.write_timeout) +* [`UnixStream::set_nonblocking`](http://doc.rust-lang.org/std/os/unix/net/struct.UnixStream.html#method.set_nonblocking) +* [`UnixStream::take_error`](http://doc.rust-lang.org/std/os/unix/net/struct.UnixStream.html#method.take_error) +* [`UnixStream::shutdown`](http://doc.rust-lang.org/std/os/unix/net/struct.UnixStream.html#method.shutdown) * Read/Write/RawFd impls for `UnixStream` -* [`UnixListener::bind`] - (http://doc.rust-lang.org/std/os/unix/net/struct.UnixListener.html#method.bind) -* [`UnixListener::accept`] - (http://doc.rust-lang.org/std/os/unix/net/struct.UnixListener.html#method.accept) -* [`UnixListener::try_clone`] - (http://doc.rust-lang.org/std/os/unix/net/struct.UnixListener.html#method.try_clone) -* [`UnixListener::local_addr`] - (http://doc.rust-lang.org/std/os/unix/net/struct.UnixListener.html#method.local_addr) -* [`UnixListener::set_nonblocking`] - (http://doc.rust-lang.org/std/os/unix/net/struct.UnixListener.html#method.set_nonblocking) -* [`UnixListener::take_error`] - (http://doc.rust-lang.org/std/os/unix/net/struct.UnixListener.html#method.take_error) -* [`UnixListener::incoming`] - (http://doc.rust-lang.org/std/os/unix/net/struct.UnixListener.html#method.incoming) +* [`UnixListener::bind`](http://doc.rust-lang.org/std/os/unix/net/struct.UnixListener.html#method.bind) +* [`UnixListener::accept`](http://doc.rust-lang.org/std/os/unix/net/struct.UnixListener.html#method.accept) +* [`UnixListener::try_clone`](http://doc.rust-lang.org/std/os/unix/net/struct.UnixListener.html#method.try_clone) +* [`UnixListener::local_addr`](http://doc.rust-lang.org/std/os/unix/net/struct.UnixListener.html#method.local_addr) +* [`UnixListener::set_nonblocking`](http://doc.rust-lang.org/std/os/unix/net/struct.UnixListener.html#method.set_nonblocking) +* [`UnixListener::take_error`](http://doc.rust-lang.org/std/os/unix/net/struct.UnixListener.html#method.take_error) +* [`UnixListener::incoming`](http://doc.rust-lang.org/std/os/unix/net/struct.UnixListener.html#method.incoming) * RawFd impls for `UnixListener` -* [`UnixDatagram::bind`] - (http://doc.rust-lang.org/std/os/unix/net/struct.UnixDatagram.html#method.bind) -* [`UnixDatagram::unbound`] - (http://doc.rust-lang.org/std/os/unix/net/struct.UnixDatagram.html#method.unbound) -* [`UnixDatagram::pair`] - (http://doc.rust-lang.org/std/os/unix/net/struct.UnixDatagram.html#method.pair) -* [`UnixDatagram::connect`] - (http://doc.rust-lang.org/std/os/unix/net/struct.UnixDatagram.html#method.connect) -* [`UnixDatagram::try_clone`] - (http://doc.rust-lang.org/std/os/unix/net/struct.UnixDatagram.html#method.try_clone) -* [`UnixDatagram::local_addr`] - (http://doc.rust-lang.org/std/os/unix/net/struct.UnixDatagram.html#method.local_addr) -* [`UnixDatagram::peer_addr`] - (http://doc.rust-lang.org/std/os/unix/net/struct.UnixDatagram.html#method.peer_addr) -* [`UnixDatagram::recv_from`] - (http://doc.rust-lang.org/std/os/unix/net/struct.UnixDatagram.html#method.recv_from) -* [`UnixDatagram::recv`] - (http://doc.rust-lang.org/std/os/unix/net/struct.UnixDatagram.html#method.recv) -* [`UnixDatagram::send_to`] - (http://doc.rust-lang.org/std/os/unix/net/struct.UnixDatagram.html#method.send_to) -* [`UnixDatagram::send`] - (http://doc.rust-lang.org/std/os/unix/net/struct.UnixDatagram.html#method.send) -* [`UnixDatagram::set_read_timeout`] - (http://doc.rust-lang.org/std/os/unix/net/struct.UnixDatagram.html#method.set_read_timeout) -* [`UnixDatagram::set_write_timeout`] - (http://doc.rust-lang.org/std/os/unix/net/struct.UnixDatagram.html#method.set_write_timeout) -* [`UnixDatagram::read_timeout`] - (http://doc.rust-lang.org/std/os/unix/net/struct.UnixDatagram.html#method.read_timeout) -* [`UnixDatagram::write_timeout`] - (http://doc.rust-lang.org/std/os/unix/net/struct.UnixDatagram.html#method.write_timeout) -* [`UnixDatagram::set_nonblocking`] - (http://doc.rust-lang.org/std/os/unix/net/struct.UnixDatagram.html#method.set_nonblocking) -* [`UnixDatagram::take_error`] - (http://doc.rust-lang.org/std/os/unix/net/struct.UnixDatagram.html#method.take_error) -* [`UnixDatagram::shutdown`] - (http://doc.rust-lang.org/std/os/unix/net/struct.UnixDatagram.html#method.shutdown) +* [`UnixDatagram::bind`](http://doc.rust-lang.org/std/os/unix/net/struct.UnixDatagram.html#method.bind) +* [`UnixDatagram::unbound`](http://doc.rust-lang.org/std/os/unix/net/struct.UnixDatagram.html#method.unbound) +* [`UnixDatagram::pair`](http://doc.rust-lang.org/std/os/unix/net/struct.UnixDatagram.html#method.pair) +* [`UnixDatagram::connect`](http://doc.rust-lang.org/std/os/unix/net/struct.UnixDatagram.html#method.connect) +* [`UnixDatagram::try_clone`](http://doc.rust-lang.org/std/os/unix/net/struct.UnixDatagram.html#method.try_clone) +* [`UnixDatagram::local_addr`](http://doc.rust-lang.org/std/os/unix/net/struct.UnixDatagram.html#method.local_addr) +* [`UnixDatagram::peer_addr`](http://doc.rust-lang.org/std/os/unix/net/struct.UnixDatagram.html#method.peer_addr) +* [`UnixDatagram::recv_from`](http://doc.rust-lang.org/std/os/unix/net/struct.UnixDatagram.html#method.recv_from) +* [`UnixDatagram::recv`](http://doc.rust-lang.org/std/os/unix/net/struct.UnixDatagram.html#method.recv) +* [`UnixDatagram::send_to`](http://doc.rust-lang.org/std/os/unix/net/struct.UnixDatagram.html#method.send_to) +* [`UnixDatagram::send`](http://doc.rust-lang.org/std/os/unix/net/struct.UnixDatagram.html#method.send) +* [`UnixDatagram::set_read_timeout`](http://doc.rust-lang.org/std/os/unix/net/struct.UnixDatagram.html#method.set_read_timeout) +* [`UnixDatagram::set_write_timeout`](http://doc.rust-lang.org/std/os/unix/net/struct.UnixDatagram.html#method.set_write_timeout) +* [`UnixDatagram::read_timeout`](http://doc.rust-lang.org/std/os/unix/net/struct.UnixDatagram.html#method.read_timeout) +* [`UnixDatagram::write_timeout`](http://doc.rust-lang.org/std/os/unix/net/struct.UnixDatagram.html#method.write_timeout) +* [`UnixDatagram::set_nonblocking`](http://doc.rust-lang.org/std/os/unix/net/struct.UnixDatagram.html#method.set_nonblocking) +* [`UnixDatagram::take_error`](http://doc.rust-lang.org/std/os/unix/net/struct.UnixDatagram.html#method.take_error) +* [`UnixDatagram::shutdown`](http://doc.rust-lang.org/std/os/unix/net/struct.UnixDatagram.html#method.shutdown) * RawFd impls for `UnixDatagram` * `{BTree,Hash}Map::values_mut` -* [`<[_]>::binary_search_by_key`] - (http://doc.rust-lang.org/beta/std/primitive.slice.html#method.binary_search_by_key) +* [`<[_]>::binary_search_by_key`](http://doc.rust-lang.org/beta/std/primitive.slice.html#method.binary_search_by_key) Libraries --------- -* [The `abs_sub` method of floats is deprecated] - (https://github.com/rust-lang/rust/pull/33664). +* [The `abs_sub` method of floats is deprecated](https://github.com/rust-lang/rust/pull/33664). The semantics of this minor method are subtle and probably not what most people want. -* [Add implementation of Ord for Cell and RefCell where T: Ord] - (https://github.com/rust-lang/rust/pull/33306). +* [Add implementation of Ord for Cell and RefCell where T: Ord](https://github.com/rust-lang/rust/pull/33306). * [On Linux, if `HashMap`s can't be initialized with `getrandom` they will fall back to `/dev/urandom` temporarily to avoid blocking - during early boot] - (https://github.com/rust-lang/rust/pull/33086). -* [Implemented negation for wrapping numerals] - (https://github.com/rust-lang/rust/pull/33067). -* [Implement `Clone` for `binary_heap::IntoIter`] - (https://github.com/rust-lang/rust/pull/33050). -* [Implement `Display` and `Hash` for `std::num::Wrapping`] - (https://github.com/rust-lang/rust/pull/33023). -* [Add `Default` implementation for `&CStr`, `CString`] - (https://github.com/rust-lang/rust/pull/32990). -* [Implement `From>` and `Into>` for `VecDeque`] - (https://github.com/rust-lang/rust/pull/32866). + during early boot](https://github.com/rust-lang/rust/pull/33086). +* [Implemented negation for wrapping numerals](https://github.com/rust-lang/rust/pull/33067). +* [Implement `Clone` for `binary_heap::IntoIter`](https://github.com/rust-lang/rust/pull/33050). +* [Implement `Display` and `Hash` for `std::num::Wrapping`](https://github.com/rust-lang/rust/pull/33023). +* [Add `Default` implementation for `&CStr`, `CString`](https://github.com/rust-lang/rust/pull/32990). +* [Implement `From>` and `Into>` for `VecDeque`](https://github.com/rust-lang/rust/pull/32866). * [Implement `Default` for `UnsafeCell`, `fmt::Error`, `Condvar`, - `Mutex`, `RwLock`] - (https://github.com/rust-lang/rust/pull/32785). + `Mutex`, `RwLock`](https://github.com/rust-lang/rust/pull/32785). Cargo ----- -* [Cargo.toml supports the `profile.*.panic` option] - (https://github.com/rust-lang/cargo/pull/2687). +* [Cargo.toml supports the `profile.*.panic` option](https://github.com/rust-lang/cargo/pull/2687). This controls the runtime behavior of the `panic!` macro and can be either "unwind" (the default), or "abort". [RFC 1513](https://github.com/rust-lang/rfcs/blob/master/text/1513-less-unwinding.md). -* [Don't throw away errors with `-p` arguments] - (https://github.com/rust-lang/cargo/pull/2723). -* [Report status to stderr instead of stdout] - (https://github.com/rust-lang/cargo/pull/2693). +* [Don't throw away errors with `-p` arguments](https://github.com/rust-lang/cargo/pull/2723). +* [Report status to stderr instead of stdout](https://github.com/rust-lang/cargo/pull/2693). * [Build scripts are passed a `CARGO_MANIFEST_LINKS` environment - variable that corresponds to the `links` field of the manifest] - (https://github.com/rust-lang/cargo/pull/2710). -* [Ban keywords from crate names] - (https://github.com/rust-lang/cargo/pull/2707). -* [Canonicalize `CARGO_HOME` on Windows] - (https://github.com/rust-lang/cargo/pull/2604). -* [Retry network requests] - (https://github.com/rust-lang/cargo/pull/2396). + variable that corresponds to the `links` field of the manifest](https://github.com/rust-lang/cargo/pull/2710). +* [Ban keywords from crate names](https://github.com/rust-lang/cargo/pull/2707). +* [Canonicalize `CARGO_HOME` on Windows](https://github.com/rust-lang/cargo/pull/2604). +* [Retry network requests](https://github.com/rust-lang/cargo/pull/2396). By default they are retried twice, which can be customized with the `net.retry` value in `.cargo/config`. -* [Don't print extra error info for failing subcommands] - (https://github.com/rust-lang/cargo/pull/2674). -* [Add `--force` flag to `cargo install`] - (https://github.com/rust-lang/cargo/pull/2405). -* [Don't use `flock` on NFS mounts] - (https://github.com/rust-lang/cargo/pull/2623). -* [Prefer building `cargo install` artifacts in temporary directories] - (https://github.com/rust-lang/cargo/pull/2610). +* [Don't print extra error info for failing subcommands](https://github.com/rust-lang/cargo/pull/2674). +* [Add `--force` flag to `cargo install`](https://github.com/rust-lang/cargo/pull/2405). +* [Don't use `flock` on NFS mounts](https://github.com/rust-lang/cargo/pull/2623). +* [Prefer building `cargo install` artifacts in temporary directories](https://github.com/rust-lang/cargo/pull/2610). Makes it possible to install multiple crates in parallel. -* [Add `cargo test --doc`] - (https://github.com/rust-lang/cargo/pull/2578). -* [Add `cargo --explain`] - (https://github.com/rust-lang/cargo/pull/2551). -* [Don't print warnings when `-q` is passed] - (https://github.com/rust-lang/cargo/pull/2576). -* [Add `cargo doc --lib` and `--bin`] - (https://github.com/rust-lang/cargo/pull/2577). -* [Don't require build script output to be UTF-8] - (https://github.com/rust-lang/cargo/pull/2560). -* [Correctly attempt multiple git usernames] - (https://github.com/rust-lang/cargo/pull/2584). +* [Add `cargo test --doc`](https://github.com/rust-lang/cargo/pull/2578). +* [Add `cargo --explain`](https://github.com/rust-lang/cargo/pull/2551). +* [Don't print warnings when `-q` is passed](https://github.com/rust-lang/cargo/pull/2576). +* [Add `cargo doc --lib` and `--bin`](https://github.com/rust-lang/cargo/pull/2577). +* [Don't require build script output to be UTF-8](https://github.com/rust-lang/cargo/pull/2560). +* [Correctly attempt multiple git usernames](https://github.com/rust-lang/cargo/pull/2584). Performance ----------- * [rustc memory usage was reduced by refactoring the context used for - type checking] - (https://github.com/rust-lang/rust/pull/33425). + type checking](https://github.com/rust-lang/rust/pull/33425). * [Speed up creation of `HashMap`s by caching the random keys used - to initialize the hash state] - (https://github.com/rust-lang/rust/pull/33318). -* [The `find` implementation for `Chain` iterators is 2x faster] - (https://github.com/rust-lang/rust/pull/33289). -* [Trait selection optimizations speed up type checking by 15%] - (https://github.com/rust-lang/rust/pull/33138). -* [Efficient trie lookup for boolean Unicode properties] - (https://github.com/rust-lang/rust/pull/33098). + to initialize the hash state](https://github.com/rust-lang/rust/pull/33318). +* [The `find` implementation for `Chain` iterators is 2x faster](https://github.com/rust-lang/rust/pull/33289). +* [Trait selection optimizations speed up type checking by 15%](https://github.com/rust-lang/rust/pull/33138). +* [Efficient trie lookup for boolean Unicode properties](https://github.com/rust-lang/rust/pull/33098). 10x faster than the previous lookup tables. -* [Special case `#[derive(Copy, Clone)]` to avoid bloat] - (https://github.com/rust-lang/rust/pull/31414). +* [Special case `#[derive(Copy, Clone)]` to avoid bloat](https://github.com/rust-lang/rust/pull/31414). Usability --------- * Many incremental improvements to documentation and rustdoc. -* [rustdoc: List blanket trait impls] - (https://github.com/rust-lang/rust/pull/33514). -* [rustdoc: Clean up ABI rendering] - (https://github.com/rust-lang/rust/pull/33151). -* [Indexing with the wrong type produces a more informative error] - (https://github.com/rust-lang/rust/pull/33401). -* [Improve diagnostics for constants being used in irrefutable patterns] - (https://github.com/rust-lang/rust/pull/33406). -* [When many method candidates are in scope limit the suggestions to 10] - (https://github.com/rust-lang/rust/pull/33338). -* [Remove confusing suggestion when calling a `fn` type] - (https://github.com/rust-lang/rust/pull/33325). -* [Do not suggest changing `&mut self` to `&mut mut self`] - (https://github.com/rust-lang/rust/pull/33319). +* [rustdoc: List blanket trait impls](https://github.com/rust-lang/rust/pull/33514). +* [rustdoc: Clean up ABI rendering](https://github.com/rust-lang/rust/pull/33151). +* [Indexing with the wrong type produces a more informative error](https://github.com/rust-lang/rust/pull/33401). +* [Improve diagnostics for constants being used in irrefutable patterns](https://github.com/rust-lang/rust/pull/33406). +* [When many method candidates are in scope limit the suggestions to 10](https://github.com/rust-lang/rust/pull/33338). +* [Remove confusing suggestion when calling a `fn` type](https://github.com/rust-lang/rust/pull/33325). +* [Do not suggest changing `&mut self` to `&mut mut self`](https://github.com/rust-lang/rust/pull/33319). Misc ---- -* [Update i686-linux-android features to match Android ABI] - (https://github.com/rust-lang/rust/pull/33651). -* [Update aarch64-linux-android features to match Android ABI] - (https://github.com/rust-lang/rust/pull/33500). +* [Update i686-linux-android features to match Android ABI](https://github.com/rust-lang/rust/pull/33651). +* [Update aarch64-linux-android features to match Android ABI](https://github.com/rust-lang/rust/pull/33500). * [`std` no longer prints backtraces on platforms where the running module must be loaded with `env::current_exe`, which can't be relied on](https://github.com/rust-lang/rust/pull/33554). @@ -1657,34 +1411,24 @@ Misc * [The `rust-gdb` and `rust-lldb` scripts are distributed on all Unix platforms](https://github.com/rust-lang/rust/pull/32835). * [On Unix the runtime aborts by calling `libc::abort` instead of - generating an illegal instruction] - (https://github.com/rust-lang/rust/pull/31457). + generating an illegal instruction](https://github.com/rust-lang/rust/pull/31457). * [Rust is now bootstrapped from the previous release of Rust, - instead of a snapshot from an arbitrary commit] - (https://github.com/rust-lang/rust/pull/32942). + instead of a snapshot from an arbitrary commit](https://github.com/rust-lang/rust/pull/32942). Compatibility Notes ------------------- -* [`AtomicBool` is now bool-sized, not word-sized] - (https://github.com/rust-lang/rust/pull/33579). +* [`AtomicBool` is now bool-sized, not word-sized](https://github.com/rust-lang/rust/pull/33579). * [`target_env` for Linux ARM targets is just `gnu`, not - `gnueabihf`, `gnueabi`, etc] - (https://github.com/rust-lang/rust/pull/33403). -* [Consistently panic on overflow in `Duration::new`] - (https://github.com/rust-lang/rust/pull/33072). -* [Change `String::truncate` to panic less] - (https://github.com/rust-lang/rust/pull/32977). -* [Add `:block` to the follow set for `:ty` and `:path`] - (https://github.com/rust-lang/rust/pull/32945). + `gnueabihf`, `gnueabi`, etc](https://github.com/rust-lang/rust/pull/33403). +* [Consistently panic on overflow in `Duration::new`](https://github.com/rust-lang/rust/pull/33072). +* [Change `String::truncate` to panic less](https://github.com/rust-lang/rust/pull/32977). +* [Add `:block` to the follow set for `:ty` and `:path`](https://github.com/rust-lang/rust/pull/32945). Affects how macros are parsed. -* [Fix macro hygiene bug] - (https://github.com/rust-lang/rust/pull/32923). +* [Fix macro hygiene bug](https://github.com/rust-lang/rust/pull/32923). * [Feature-gated attributes on macro-generated macro invocations are - now rejected] - (https://github.com/rust-lang/rust/pull/32791). -* [Suppress fallback and ambiguity errors during type inference] - (https://github.com/rust-lang/rust/pull/32258). + now rejected](https://github.com/rust-lang/rust/pull/32791). +* [Suppress fallback and ambiguity errors during type inference](https://github.com/rust-lang/rust/pull/32258). This caused some minor changes to type inference. diff --git a/appveyor.yml b/appveyor.yml index c33e07fb17e5..8ace91c3d89e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -20,39 +20,28 @@ environment: # 32/64-bit MinGW builds. # - # The MinGW builds unfortunately have to both download a custom toolchain and - # avoid the one installed by AppVeyor by default. Interestingly, though, for - # different reasons! + # We are using MinGW with posix threads since LLVM does not compile with + # the win32 threads version due to missing support for C++'s std::thread. # - # For 32-bit the installed gcc toolchain on AppVeyor uses the pthread - # threading model. This is unfortunately not what we want, and if we compile - # with it then there's lots of link errors in the standard library (undefined - # references to pthread symbols). - # - # For 64-bit the installed gcc toolchain is currently 5.3.0 which - # unfortunately segfaults on Windows with --enable-llvm-assertions (segfaults - # in LLVM). See rust-lang/rust#28445 for more information, but to work around - # this we go back in time to 4.9.2 specifically. + # Instead of relying on the MinGW version installed on appveryor we download + # and install one ourselves so we won't be surprised by changes to appveyor's + # build image. # # Finally, note that the downloads below are all in the `rust-lang-ci` S3 # bucket, but they cleraly didn't originate there! The downloads originally # came from the mingw-w64 SourceForge download site. Unfortunately # SourceForge is notoriously flaky, so we mirror it on our own infrastructure. - # - # And as a final point of note, the 32-bit MinGW build using the makefiles do - # *not* use debug assertions and llvm assertions. This is because they take - # too long on appveyor and this is tested by rustbuild below. - MSYS_BITS: 32 - RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --enable-ninja + RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu SCRIPT: python x.py test MINGW_URL: https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror - MINGW_ARCHIVE: i686-6.3.0-release-win32-dwarf-rt_v5-rev1.7z + MINGW_ARCHIVE: i686-6.3.0-release-posix-dwarf-rt_v5-rev2.7z MINGW_DIR: mingw32 - MSYS_BITS: 64 SCRIPT: python x.py test - RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-ninja + RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu MINGW_URL: https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror - MINGW_ARCHIVE: x86_64-6.3.0-release-win32-seh-rt_v5-rev1.7z + MINGW_ARCHIVE: x86_64-6.3.0-release-posix-seh-rt_v5-rev2.7z MINGW_DIR: mingw64 # 32/64 bit MSVC and GNU deployment @@ -68,17 +57,17 @@ environment: SCRIPT: python x.py dist DEPLOY: 1 - MSYS_BITS: 32 - RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --enable-extended --enable-ninja + RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --enable-extended SCRIPT: python x.py dist MINGW_URL: https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror - MINGW_ARCHIVE: i686-6.3.0-release-win32-dwarf-rt_v5-rev1.7z + MINGW_ARCHIVE: i686-6.3.0-release-posix-dwarf-rt_v5-rev2.7z MINGW_DIR: mingw32 DEPLOY: 1 - MSYS_BITS: 64 SCRIPT: python x.py dist - RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-extended --enable-ninja + RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-extended MINGW_URL: https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror - MINGW_ARCHIVE: x86_64-6.3.0-release-win32-seh-rt_v5-rev1.7z + MINGW_ARCHIVE: x86_64-6.3.0-release-posix-seh-rt_v5-rev2.7z MINGW_DIR: mingw64 DEPLOY: 1 @@ -107,6 +96,26 @@ install: - if defined MINGW_URL 7z x -y %MINGW_ARCHIVE% > nul - if defined MINGW_URL set PATH=%CD%\%MINGW_DIR%\bin;C:\msys64\usr\bin;%PATH% + # Here we do a pretty heinous thing which is to mangle the MinGW installation + # we just had above. Currently, as of this writing, we're using MinGW-w64 + # builds of gcc, and that's currently at 6.3.0. We use 6.3.0 as it appears to + # be the first version which contains a fix for #40546, builds randomly + # failing during LLVM due to ar.exe/ranlib.exe failures. + # + # Unfortunately, though, 6.3.0 *also* is the first version of MinGW-w64 builds + # to contain a regression in gdb (#40184). As a result if we were to use the + # gdb provided (7.11.1) then we would fail all debuginfo tests. + # + # In order to fix spurious failures (pretty high priority) we use 6.3.0. To + # avoid disabling gdb tests we download an *old* version of gdb, specifically + # that found inside the 6.2.0 distribution. We then overwrite the 6.3.0 gdb + # with the 6.2.0 gdb to get tests passing. + # + # Note that we don't literally overwrite the gdb.exe binary because it appears + # to just use gdborig.exe, so that's the binary we deal with instead. + - if defined MINGW_URL appveyor-retry appveyor DownloadFile %MINGW_URL%/2017-04-20-%MSYS_BITS%bit-gdborig.exe + - if defined MINGW_URL mv 2017-04-20-%MSYS_BITS%bit-gdborig.exe %MINGW_DIR%\bin\gdborig.exe + # Otherwise pull in the MinGW installed on appveyor - if NOT defined MINGW_URL set PATH=C:\msys64\mingw%MSYS_BITS%\bin;C:\msys64\usr\bin;%PATH% @@ -115,8 +124,8 @@ install: - set PATH=C:\Python27;%PATH% # Download and install sccache - - appveyor-retry appveyor DownloadFile https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-pc-windows-msvc - - mv 2017-03-22-sccache-x86_64-pc-windows-msvc sccache.exe + - appveyor-retry appveyor DownloadFile https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-29-sccache-x86_64-pc-windows-msvc + - mv 2017-04-29-sccache-x86_64-pc-windows-msvc sccache.exe - set PATH=%PATH%;%CD% # Download and install ninja @@ -124,6 +133,7 @@ install: # Note that this is originally from the github releases patch of Ninja - appveyor-retry appveyor DownloadFile https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-15-ninja-win.zip - 7z x 2017-03-15-ninja-win.zip + - set RUST_CONFIGURE_ARGS=%RUST_CONFIGURE_ARGS% --enable-ninja # - set PATH=%PATH%;%CD% -- this already happens above for sccache # Install InnoSetup to get `iscc` used to produce installers @@ -141,19 +151,14 @@ install: - set SCCACHE_ERROR_LOG=%CD%/sccache.log test_script: - - appveyor-retry sh -c 'git submodule deinit -f . && git submodule update --init' + - if not exist C:\cache\rustsrc\NUL mkdir C:\cache\rustsrc + - sh src/ci/init_repo.sh . /c/cache/rustsrc - set SRC=. - set NO_CCACHE=1 - sh src/ci/run.sh on_failure: - - cat %CD%/sccache.log - -cache: - - "build/i686-pc-windows-msvc/llvm -> src/rustllvm/llvm-rebuild-trigger" - - "build/x86_64-pc-windows-msvc/llvm -> src/rustllvm/llvm-rebuild-trigger" - - "i686-pc-windows-msvc/llvm -> src/rustllvm/llvm-rebuild-trigger" - - "x86_64-pc-windows-msvc/llvm -> src/rustllvm/llvm-rebuild-trigger" + - cat %CD%\sccache.log || exit 0 branches: only: diff --git a/cargo b/cargo deleted file mode 160000 index c995e9eb5acf..000000000000 --- a/cargo +++ /dev/null @@ -1 +0,0 @@ -Subproject commit c995e9eb5acf3976ae8674a0dc6d9e958053d9fd diff --git a/configure b/configure index d6dded6dc5f7..db41f0dfb94f 100755 --- a/configure +++ b/configure @@ -445,7 +445,6 @@ opt dist-host-only 0 "only install bins for the host architecture" opt inject-std-version 1 "inject the current compiler version of libstd into programs" opt llvm-version-check 1 "check if the LLVM version is supported, build anyway" opt codegen-tests 1 "run the src/test/codegen tests" -opt save-analysis 0 "save API analysis data" opt option-checking 1 "complain about unrecognized options in this configure script" opt ninja 0 "build LLVM using the Ninja generator (for MSVC, requires building in the correct environment)" opt locked-deps 0 "force Cargo.lock to be up to date" @@ -480,6 +479,7 @@ valopt i686-linux-android-ndk "" "i686-linux-android NDK standalone path" valopt arm-linux-androideabi-ndk "" "arm-linux-androideabi NDK standalone path" valopt armv7-linux-androideabi-ndk "" "armv7-linux-androideabi NDK standalone path" valopt aarch64-linux-android-ndk "" "aarch64-linux-android NDK standalone path" +valopt x86_64-linux-android-ndk "" "x86_64-linux-android NDK standalone path" valopt nacl-cross-path "" "NaCl SDK path (Pepper Canary is recommended). Must be absolute!" valopt musl-root "/usr/local" "MUSL root installation directory (deprecated)" valopt musl-root-x86_64 "" "x86_64-unknown-linux-musl install directory" @@ -510,7 +510,6 @@ valopt default-ar "ar" "the default ar" opt_nosave manage-submodules 1 "let the build manage the git submodules" opt_nosave clang 0 "prefer clang to gcc for building the runtime" opt_nosave jemalloc 1 "build liballoc with jemalloc" -opt elf-tls 1 "elf thread local storage on platforms where supported" opt full-bootstrap 0 "build three compilers instead of two" opt extended 0 "build an extended rust tool set" @@ -747,6 +746,7 @@ putvar CFG_AARCH64_LINUX_ANDROID_NDK putvar CFG_ARM_LINUX_ANDROIDEABI_NDK putvar CFG_ARMV7_LINUX_ANDROIDEABI_NDK putvar CFG_I686_LINUX_ANDROID_NDK +putvar CFG_X86_64_LINUX_ANDROID_NDK putvar CFG_NACL_CROSS_PATH putvar CFG_MANDIR putvar CFG_DOCDIR diff --git a/man/rustc.1 b/man/rustc.1 index 165625595619..6c80f11fa720 100644 --- a/man/rustc.1 +++ b/man/rustc.1 @@ -50,7 +50,7 @@ Comma separated list of types of crates for the compiler to emit. \fB\-\-crate\-name\fR \fINAME\fR Specify the name of the crate being built. .TP -\fB\-\-emit\fR [asm|llvm\-bc|llvm\-ir|obj|link|dep\-info][=\fIPATH\fR] +\fB\-\-emit\fR [asm|llvm\-bc|llvm\-ir|obj|link|dep\-info|mir][=\fIPATH\fR] Configure the output that \fBrustc\fR will produce. Each emission may also have an optional explicit output \fIPATH\fR specified for that particular emission kind. This path takes precedence over the \fB-o\fR option. diff --git a/src/Cargo.lock b/src/Cargo.lock index 9ae894061a67..5fa0829f2f8d 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -8,7 +8,7 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -27,7 +27,7 @@ version = "0.0.0" dependencies = [ "build_helper 0.1.0", "core 0.0.0", - "gcc 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.0.0", ] @@ -65,7 +65,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bitflags" -version = "0.8.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -75,10 +75,10 @@ dependencies = [ "build_helper 0.1.0", "cmake 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "gcc 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -104,12 +104,12 @@ version = "0.1.0" [[package]] name = "clap" -version = "2.21.1" +version = "2.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", "strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "term_size 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-segmentation 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -122,7 +122,7 @@ name = "cmake" version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "gcc 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -140,14 +140,15 @@ version = "0.0.0" dependencies = [ "build_helper 0.1.0", "core 0.0.0", - "gcc 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "compiletest" version = "0.0.0" dependencies = [ - "env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "diff 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", @@ -158,17 +159,14 @@ name = "core" version = "0.0.0" [[package]] -name = "dtoa" -version = "0.4.1" +name = "diff" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "env_logger" -version = "0.3.5" +name = "dtoa" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "env_logger" @@ -196,7 +194,7 @@ name = "flate" version = "0.0.0" dependencies = [ "build_helper 0.1.0", - "gcc 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -205,7 +203,7 @@ version = "0.0.0" [[package]] name = "gcc" -version = "0.3.44" +version = "0.3.45" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -223,10 +221,10 @@ version = "0.0.0" [[package]] name = "handlebars" -version = "0.25.1" +version = "0.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "pest 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "quick-error 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -251,7 +249,7 @@ dependencies = [ [[package]] name = "lazy_static" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -270,10 +268,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "linkchecker" version = "0.1.0" -[[package]] -name = "log" -version = "0.0.0" - [[package]] name = "log" version = "0.3.7" @@ -281,12 +275,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "mdbook" -version = "0.0.18" +version = "0.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "clap 2.21.1 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.22.1 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "handlebars 0.25.1 (registry+https://github.com/rust-lang/crates.io-index)", + "handlebars 0.25.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "open 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "pulldown-cmark 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -311,7 +305,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "num_cpus" -version = "0.2.13" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", @@ -371,12 +365,12 @@ dependencies = [ ] [[package]] -name = "qemu-test-client" -version = "0.1.0" - -[[package]] -name = "qemu-test-server" -version = "0.1.0" +name = "pulldown-cmark" +version = "0.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "quick-error" @@ -395,7 +389,7 @@ name = "regex" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "aho-corasick 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "regex-syntax 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "thread_local 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -407,6 +401,14 @@ name = "regex-syntax" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "remote-test-client" +version = "0.1.0" + +[[package]] +name = "remote-test-server" +version = "0.1.0" + [[package]] name = "rls-data" version = "0.1.0" @@ -428,8 +430,8 @@ dependencies = [ name = "rustbook" version = "0.1.0" dependencies = [ - "clap 2.21.1 (registry+https://github.com/rust-lang/crates.io-index)", - "mdbook 0.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.22.1 (registry+https://github.com/rust-lang/crates.io-index)", + "mdbook 0.0.21 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -439,7 +441,7 @@ dependencies = [ "arena 0.0.0", "fmt_macros 0.0.0", "graphviz 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_back 0.0.0", "rustc_bitflags 0.0.0", "rustc_const_math 0.0.0", @@ -479,7 +481,7 @@ dependencies = [ name = "rustc_back" version = "0.0.0" dependencies = [ - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "serialize 0.0.0", "syntax 0.0.0", ] @@ -493,7 +495,7 @@ name = "rustc_borrowck" version = "0.0.0" dependencies = [ "graphviz 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", @@ -507,8 +509,7 @@ name = "rustc_const_eval" version = "0.0.0" dependencies = [ "arena 0.0.0", - "graphviz 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_back 0.0.0", "rustc_const_math 0.0.0", @@ -530,7 +531,7 @@ dependencies = [ name = "rustc_data_structures" version = "0.0.0" dependencies = [ - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "serialize 0.0.0", ] @@ -539,8 +540,9 @@ name = "rustc_driver" version = "0.0.0" dependencies = [ "arena 0.0.0", + "env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "graphviz 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "proc_macro_plugin 0.0.0", "rustc 0.0.0", "rustc_back 0.0.0", @@ -579,7 +581,7 @@ name = "rustc_incremental" version = "0.0.0" dependencies = [ "graphviz 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_data_structures 0.0.0", "serialize 0.0.0", @@ -591,7 +593,7 @@ dependencies = [ name = "rustc_lint" version = "0.0.0" dependencies = [ - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_back 0.0.0", "rustc_const_eval 0.0.0", @@ -604,7 +606,7 @@ name = "rustc_llvm" version = "0.0.0" dependencies = [ "build_helper 0.1.0", - "gcc 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_bitflags 0.0.0", ] @@ -623,7 +625,7 @@ name = "rustc_metadata" version = "0.0.0" dependencies = [ "flate 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "proc_macro 0.0.0", "rustc 0.0.0", "rustc_back 0.0.0", @@ -642,7 +644,7 @@ name = "rustc_mir" version = "0.0.0" dependencies = [ "graphviz 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_bitflags 0.0.0", "rustc_const_eval 0.0.0", @@ -666,7 +668,7 @@ dependencies = [ name = "rustc_passes" version = "0.0.0" dependencies = [ - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_const_eval 0.0.0", "rustc_const_math 0.0.0", @@ -705,7 +707,7 @@ name = "rustc_resolve" version = "0.0.0" dependencies = [ "arena 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_errors 0.0.0", "syntax 0.0.0", @@ -716,11 +718,12 @@ dependencies = [ name = "rustc_save_analysis" version = "0.0.0" dependencies = [ - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rls-data 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rls-span 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc-serialize 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_typeck 0.0.0", "syntax 0.0.0", "syntax_pos 0.0.0", ] @@ -730,11 +733,10 @@ name = "rustc_trans" version = "0.0.0" dependencies = [ "flate 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_back 0.0.0", "rustc_bitflags 0.0.0", - "rustc_const_eval 0.0.0", "rustc_const_math 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", @@ -762,10 +764,9 @@ version = "0.0.0" dependencies = [ "arena 0.0.0", "fmt_macros 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_back 0.0.0", - "rustc_const_eval 0.0.0", "rustc_const_math 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", @@ -780,11 +781,12 @@ version = "0.0.0" dependencies = [ "arena 0.0.0", "build_helper 0.1.0", - "gcc 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.0.0", + "env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "pulldown-cmark 0.0.14 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_back 0.0.0", - "rustc_const_eval 0.0.0", "rustc_data_structures 0.0.0", "rustc_driver 0.0.0", "rustc_errors 0.0.0", @@ -792,6 +794,7 @@ dependencies = [ "rustc_metadata 0.0.0", "rustc_resolve 0.0.0", "rustc_trans 0.0.0", + "rustc_typeck 0.0.0", "serialize 0.0.0", "syntax 0.0.0", "syntax_pos 0.0.0", @@ -828,7 +831,7 @@ dependencies = [ "collections 0.0.0", "compiler_builtins 0.0.0", "core 0.0.0", - "gcc 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.0.0", "panic_abort 0.0.0", "panic_unwind 0.0.0", @@ -857,7 +860,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "syntax" version = "0.0.0" dependencies = [ - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_bitflags 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", @@ -870,7 +873,7 @@ name = "syntax_ext" version = "0.0.0" dependencies = [ "fmt_macros 0.0.0", - "log 0.0.0", + "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "proc_macro 0.0.0", "rustc_errors 0.0.0", "syntax 0.0.0", @@ -988,31 +991,32 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] -"checksum aho-corasick 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0638fd549427caa90c499814196d1b9e3725eb4d15d7339d6de073a680ed0ca2" +"checksum aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "500909c4f87a9e52355b26626d890833e9e1d53ac566db76c36faa984b889699" "checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6" "checksum atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d912da0db7fa85514874458ca3651fe2cddace8d0b0505571dbdcd41ab490159" "checksum bitflags 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4f67931368edf3a9a51d29886d245f1c3db2f1ef0dcc9e35ff70341b78c10d23" -"checksum bitflags 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e1ab483fc81a8143faa7203c4a3c02888ebd1a782e37e41fa34753ba9a162" -"checksum clap 2.21.1 (registry+https://github.com/rust-lang/crates.io-index)" = "74a80f603221c9cd9aa27a28f52af452850051598537bb6b359c38a7d61e5cda" +"checksum bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1370e9fc2a6ae53aea8b7a5110edbd08836ed87c88736dfabccade1c2b44bff4" +"checksum clap 2.22.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e17a4a72ffea176f77d6e2db609c6c919ef221f23862c9915e687fb54d833485" "checksum cmake 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)" = "d18d68987ed4c516dcc3e7913659bfa4076f5182eea4a7e0038bb060953e76ac" +"checksum diff 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0a515461b6c8c08419850ced27bc29e86166dcdcde8fbe76f8b1f0589bb49472" "checksum dtoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "80c8b71fd71146990a9742fc06dcbbde19161a267e0ad4e572c35162f4578c90" -"checksum env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f" "checksum env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e3856f1697098606fc6cb97a93de88ca3f3bc35bb878c725920e6e82ecf05e83" "checksum filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922" -"checksum gcc 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)" = "a32cd40070d7611ab76343dcb3204b2bb28c8a9450989a83a3d590248142f439" +"checksum gcc 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)" = "40899336fb50db0c78710f53e87afc54d8c7266fb76262fecc78ca1a7f09deae" "checksum getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9047cfbd08a437050b363d35ef160452c5fe8ea5187ae0a624708c91581d685" -"checksum handlebars 0.25.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b2249f6f0dc5a3bb2b3b1a8f797dfccbc4b053344d773d654ad565e51427d335" +"checksum handlebars 0.25.2 (registry+https://github.com/rust-lang/crates.io-index)" = "663e1728d8037fb0d4e13bcd1b1909fb5d913690a9929eb385922df157c2ff8f" "checksum itoa 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eb2f404fbc66fd9aac13e998248505e7ecb2ad8e44ab6388684c5fb11c6c251c" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -"checksum lazy_static 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7291b1dd97d331f752620b02dfdbc231df7fc01bf282a00769e1cdb963c460dc" +"checksum lazy_static 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "4732c563b9a21a406565c4747daa7b46742f082911ae4753f390dc9ec7ee1a97" "checksum libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "88ee81885f9f04bff991e306fea7c1c60a5f0f9e409e99f6b40e3311a3363135" "checksum log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "5141eca02775a762cc6cd564d8d2c50f67c0ea3a372cbf1c51592b3e029e10ad" -"checksum mdbook 0.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "06a68e8738e42b38a02755d3ce5fa12d559e17acb238e4326cbc3cc056e65280" +"checksum mdbook 0.0.21 (registry+https://github.com/rust-lang/crates.io-index)" = "f1e2e9d848514dcfad4195788d0d42ae5153a477c191d75d5b84fab10f222fbd" "checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4" "checksum num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "e1cbfa3781f3fe73dc05321bed52a06d2d491eaa764c52335cf4399f046ece99" -"checksum num_cpus 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "cee7e88156f3f9e19bdd598f8d6c9db7bf4078f99f8381f43a55b09648d1a6e3" +"checksum num_cpus 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca313f1862c7ec3e0dfe8ace9fa91b1d9cb5c84ace3d00f5ec4216238e93c167" "checksum open 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3478ed1686bd1300c8a981a940abc92b06fac9cbef747f4c668d4e032ff7b842" "checksum pest 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0a6dda33d67c26f0aac90d324ab2eb7239c819fc7b2552fe9faa4fe88441edc8" +"checksum pulldown-cmark 0.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9ab1e588ef8efd702c7ed9d2bd774db5e6f4d878bb5a1a9f371828fbdff6973" "checksum pulldown-cmark 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1058d7bb927ca067656537eec4e02c2b4b70eaaa129664c5b90c111e20326f41" "checksum quick-error 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0aad603e8d7fb67da22dbdf1f4b826ce8829e406124109e73cf1b2454b93a71c" "checksum regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4278c17d0f6d62dfef0ab00028feb45bd7d2102843f80763474eeb1be8a10c01" diff --git a/src/Cargo.toml b/src/Cargo.toml index 0dafbb8428e3..9aca3e134d65 100644 --- a/src/Cargo.toml +++ b/src/Cargo.toml @@ -11,8 +11,14 @@ members = [ "tools/rustbook", "tools/tidy", "tools/build-manifest", - "tools/qemu-test-client", - "tools/qemu-test-server", + "tools/remote-test-client", + "tools/remote-test-server", +] + +# These projects have their own Cargo.lock +exclude = [ + "tools/cargo", + "tools/rls", ] # Curiously, compiletest will segfault if compiled with opt-level=3 on 64-bit diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index 1eda1608c470..1088067c2de5 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -23,11 +23,16 @@ name = "rustdoc" path = "bin/rustdoc.rs" test = false +[[bin]] +name = "sccache-plus-cl" +path = "bin/sccache-plus-cl.rs" +test = false + [dependencies] build_helper = { path = "../build_helper" } cmake = "0.1.17" filetime = "0.1" -num_cpus = "0.2" +num_cpus = "1.0" toml = "0.1" getopts = "0.2" rustc-serialize = "0.3" diff --git a/src/bootstrap/README.md b/src/bootstrap/README.md index 2f7757fb1d5b..1ce99eb893ef 100644 --- a/src/bootstrap/README.md +++ b/src/bootstrap/README.md @@ -4,10 +4,6 @@ This is an in-progress README which is targeted at helping to explain how Rust is bootstrapped and in general some of the technical details of the build system. -> **Note**: This build system is currently under active development and is not -> intended to be the primarily used one just yet. The makefiles are currently -> the ones that are still "guaranteed to work" as much as possible at least. - ## Using rustbuild The rustbuild build system has a primary entry point, a top level `x.py` script: diff --git a/src/bootstrap/bin/rustdoc.rs b/src/bootstrap/bin/rustdoc.rs index e9ca430f1582..3a1a9c3e40d6 100644 --- a/src/bootstrap/bin/rustdoc.rs +++ b/src/bootstrap/bin/rustdoc.rs @@ -40,6 +40,14 @@ fn main() { .arg(sysroot) .env(bootstrap::util::dylib_path_var(), env::join_paths(&dylib_path).unwrap()); + + // Pass the `rustbuild` feature flag to crates which rustbuild is + // building. See the comment in bootstrap/lib.rs where this env var is + // set for more details. + if env::var_os("RUSTBUILD_UNSTABLE").is_some() { + cmd.arg("--cfg").arg("rustbuild"); + } + std::process::exit(match cmd.status() { Ok(s) => s.code().unwrap_or(1), Err(e) => panic!("\n\nfailed to run {:?}: {}\n\n", cmd, e), diff --git a/src/bootstrap/bin/sccache-plus-cl.rs b/src/bootstrap/bin/sccache-plus-cl.rs new file mode 100644 index 000000000000..cf0c12749234 --- /dev/null +++ b/src/bootstrap/bin/sccache-plus-cl.rs @@ -0,0 +1,43 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +extern crate gcc; + +use std::env; +use std::process::{self, Command}; + +fn main() { + let target = env::var("SCCACHE_TARGET").unwrap(); + // Locate the actual compiler that we're invoking + env::remove_var("CC"); + env::remove_var("CXX"); + let mut cfg = gcc::Config::new(); + cfg.cargo_metadata(false) + .out_dir("/") + .target(&target) + .host(&target) + .opt_level(0) + .debug(false); + let compiler = cfg.get_compiler(); + + // Invoke sccache with said compiler + let sccache_path = env::var_os("SCCACHE_PATH").unwrap(); + let mut cmd = Command::new(&sccache_path); + cmd.arg(compiler.path()); + for &(ref k, ref v) in compiler.env() { + cmd.env(k, v); + } + for arg in env::args().skip(1) { + cmd.arg(arg); + } + + let status = cmd.status().expect("failed to spawn"); + process::exit(status.code().unwrap_or(2)) +} diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index b326f95e505f..ad3cf31c1b92 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -159,21 +159,20 @@ def format_build_time(duration): class RustBuild(object): def download_stage0(self): cache_dst = os.path.join(self.build_dir, "cache") - rustc_cache = os.path.join(cache_dst, self.stage0_rustc_date()) - cargo_cache = os.path.join(cache_dst, self.stage0_cargo_rev()) + rustc_cache = os.path.join(cache_dst, self.stage0_date()) if not os.path.exists(rustc_cache): os.makedirs(rustc_cache) - if not os.path.exists(cargo_cache): - os.makedirs(cargo_cache) + + rustc_channel = self.stage0_rustc_channel() + cargo_channel = self.stage0_cargo_channel() if self.rustc().startswith(self.bin_root()) and \ (not os.path.exists(self.rustc()) or self.rustc_out_of_date()): self.print_what_it_means_to_bootstrap() if os.path.exists(self.bin_root()): shutil.rmtree(self.bin_root()) - channel = self.stage0_rustc_channel() - filename = "rust-std-{}-{}.tar.gz".format(channel, self.build) - url = "https://static.rust-lang.org/dist/" + self.stage0_rustc_date() + filename = "rust-std-{}-{}.tar.gz".format(rustc_channel, self.build) + url = self._download_url + "/dist/" + self.stage0_date() tarball = os.path.join(rustc_cache, filename) if not os.path.exists(tarball): get("{}/{}".format(url, filename), tarball, verbose=self.verbose) @@ -181,8 +180,8 @@ class RustBuild(object): match="rust-std-" + self.build, verbose=self.verbose) - filename = "rustc-{}-{}.tar.gz".format(channel, self.build) - url = "https://static.rust-lang.org/dist/" + self.stage0_rustc_date() + filename = "rustc-{}-{}.tar.gz".format(rustc_channel, self.build) + url = self._download_url + "/dist/" + self.stage0_date() tarball = os.path.join(rustc_cache, filename) if not os.path.exists(tarball): get("{}/{}".format(url, filename), tarball, verbose=self.verbose) @@ -190,20 +189,28 @@ class RustBuild(object): self.fix_executable(self.bin_root() + "/bin/rustc") self.fix_executable(self.bin_root() + "/bin/rustdoc") with open(self.rustc_stamp(), 'w') as f: - f.write(self.stage0_rustc_date()) + f.write(self.stage0_date()) + + if "pc-windows-gnu" in self.build: + filename = "rust-mingw-{}-{}.tar.gz".format(rustc_channel, self.build) + url = self._download_url + "/dist/" + self.stage0_date() + tarball = os.path.join(rustc_cache, filename) + if not os.path.exists(tarball): + get("{}/{}".format(url, filename), tarball, verbose=self.verbose) + unpack(tarball, self.bin_root(), match="rust-mingw", verbose=self.verbose) if self.cargo().startswith(self.bin_root()) and \ (not os.path.exists(self.cargo()) or self.cargo_out_of_date()): self.print_what_it_means_to_bootstrap() - filename = "cargo-nightly-{}.tar.gz".format(self.build) - url = "https://s3.amazonaws.com/rust-lang-ci/cargo-builds/" + self.stage0_cargo_rev() - tarball = os.path.join(cargo_cache, filename) + filename = "cargo-{}-{}.tar.gz".format(cargo_channel, self.build) + url = self._download_url + "/dist/" + self.stage0_date() + tarball = os.path.join(rustc_cache, filename) if not os.path.exists(tarball): get("{}/{}".format(url, filename), tarball, verbose=self.verbose) unpack(tarball, self.bin_root(), match="cargo", verbose=self.verbose) self.fix_executable(self.bin_root() + "/bin/cargo") with open(self.cargo_stamp(), 'w') as f: - f.write(self.stage0_cargo_rev()) + f.write(self.stage0_date()) def fix_executable(self, fname): # If we're on NixOS we need to change the path to the dynamic loader @@ -258,15 +265,15 @@ class RustBuild(object): print("warning: failed to call patchelf: %s" % e) return - def stage0_cargo_rev(self): - return self._cargo_rev - - def stage0_rustc_date(self): - return self._rustc_date + def stage0_date(self): + return self._date def stage0_rustc_channel(self): return self._rustc_channel + def stage0_cargo_channel(self): + return self._cargo_channel + def rustc_stamp(self): return os.path.join(self.bin_root(), '.rustc-stamp') @@ -277,13 +284,13 @@ class RustBuild(object): if not os.path.exists(self.rustc_stamp()) or self.clean: return True with open(self.rustc_stamp(), 'r') as f: - return self.stage0_rustc_date() != f.read() + return self.stage0_date() != f.read() def cargo_out_of_date(self): if not os.path.exists(self.cargo_stamp()) or self.clean: return True with open(self.cargo_stamp(), 'r') as f: - return self.stage0_cargo_rev() != f.read() + return self.stage0_date() != f.read() def bin_root(self): return os.path.join(self.build_dir, self.build, "stage0") @@ -364,6 +371,9 @@ class RustBuild(object): env["DYLD_LIBRARY_PATH"] = os.path.join(self.bin_root(), "lib") + \ (os.pathsep + env["DYLD_LIBRARY_PATH"]) \ if "DYLD_LIBRARY_PATH" in env else "" + env["LIBRARY_PATH"] = os.path.join(self.bin_root(), "lib") + \ + (os.pathsep + env["LIBRARY_PATH"]) \ + if "LIBRARY_PATH" in env else "" env["PATH"] = os.path.join(self.bin_root(), "bin") + \ os.pathsep + env["PATH"] if not os.path.isfile(self.cargo()): @@ -401,18 +411,14 @@ class RustBuild(object): raise Exception(err) sys.exit(err) - # Darwin's `uname -s` lies and always returns i386. We have to use - # sysctl instead. - if ostype == 'Darwin' and cputype == 'i686': - args = ['sysctl', 'hw.optional.x86_64'] - sysctl = subprocess.check_output(args).decode(default_encoding) - if ': 1' in sysctl: - cputype = 'x86_64' - # The goal here is to come up with the same triple as LLVM would, # at least for the subset of platforms we're willing to target. if ostype == 'Linux': - ostype = 'unknown-linux-gnu' + os_from_sp = subprocess.check_output(['uname', '-o']).strip().decode(default_encoding) + if os_from_sp == 'Android': + ostype = 'linux-android' + else: + ostype = 'unknown-linux-gnu' elif ostype == 'FreeBSD': ostype = 'unknown-freebsd' elif ostype == 'DragonFly': @@ -469,15 +475,21 @@ class RustBuild(object): cputype = 'i686' elif cputype in {'xscale', 'arm'}: cputype = 'arm' - elif cputype in {'armv6l', 'armv7l', 'armv8l'}: + if ostype == 'linux-android': + ostype = 'linux-androideabi' + elif cputype == 'armv6l': cputype = 'arm' - ostype += 'eabihf' - elif cputype == 'armv7l': + if ostype == 'linux-android': + ostype = 'linux-androideabi' + else: + ostype += 'eabihf' + elif cputype in {'armv7l', 'armv8l'}: cputype = 'armv7' - ostype += 'eabihf' - elif cputype == 'aarch64': - cputype = 'aarch64' - elif cputype == 'arm64': + if ostype == 'linux-android': + ostype = 'linux-androideabi' + else: + ostype += 'eabihf' + elif cputype in {'aarch64', 'arm64'}: cputype = 'aarch64' elif cputype == 'mips': if sys.byteorder == 'big': @@ -577,8 +589,13 @@ def bootstrap(): shutil.rmtree('.cargo') data = stage0_data(rb.rust_root) - rb._rustc_channel, rb._rustc_date = data['rustc'].split('-', 1) - rb._cargo_rev = data['cargo'] + rb._date = data['date'] + rb._rustc_channel = data['rustc'] + rb._cargo_channel = data['cargo'] + if 'dev' in data: + rb._download_url = 'https://dev-static.rust-lang.org' + else: + rb._download_url = 'https://static.rust-lang.org' # Fetch/build the bootstrap rb.build = rb.build_triple() @@ -598,16 +615,19 @@ def bootstrap(): def main(): start_time = time() + help_triggered = ('-h' in sys.argv) or ('--help' in sys.argv) or (len(sys.argv) == 1) try: bootstrap() - print("Build completed successfully in %s" % format_build_time(time() - start_time)) + if not help_triggered: + print("Build completed successfully in %s" % format_build_time(time() - start_time)) except (SystemExit, KeyboardInterrupt) as e: if hasattr(e, 'code') and isinstance(e.code, int): exit_code = e.code else: exit_code = 1 print(e) - print("Build completed unsuccessfully in %s" % format_build_time(time() - start_time)) + if not help_triggered: + print("Build completed unsuccessfully in %s" % format_build_time(time() - start_time)) sys.exit(exit_code) if __name__ == '__main__': diff --git a/src/bootstrap/channel.rs b/src/bootstrap/channel.rs index 2607ce412f10..1b9536fba357 100644 --- a/src/bootstrap/channel.rs +++ b/src/bootstrap/channel.rs @@ -23,7 +23,7 @@ use build_helper::output; use Build; // The version number -pub const CFG_RELEASE_NUM: &'static str = "1.17.0"; +pub const CFG_RELEASE_NUM: &'static str = "1.19.0"; // An optional number to put after the label, e.g. '.2' -> '-beta.2' // Be sure to make this starts with a dot to conform to semver pre-release diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index 40cdb9242df1..d24bb074cd37 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -28,7 +28,7 @@ use {Build, Compiler, Mode}; use dist; use util::{self, dylib_path, dylib_path_var, exe}; -const ADB_TEST_DIR: &'static str = "/data/tmp"; +const ADB_TEST_DIR: &'static str = "/data/tmp/work"; /// The two modes of the test runner; tests or benchmarks. #[derive(Copy, Clone)] @@ -78,14 +78,6 @@ pub fn linkcheck(build: &Build, host: &str) { pub fn cargotest(build: &Build, stage: u32, host: &str) { let ref compiler = Compiler::new(stage, host); - // Configure PATH to find the right rustc. NB. we have to use PATH - // and not RUSTC because the Cargo test suite has tests that will - // fail if rustc is not spelled `rustc`. - let path = build.sysroot(compiler).join("bin"); - let old_path = ::std::env::var("PATH").expect(""); - let sep = if cfg!(windows) { ";" } else {":" }; - let ref newpath = format!("{}{}{}", path.display(), sep, old_path); - // Note that this is a short, cryptic, and not scoped directory name. This // is currently to minimize the length of path on Windows where we otherwise // quickly run into path name limit constraints. @@ -95,9 +87,35 @@ pub fn cargotest(build: &Build, stage: u32, host: &str) { let _time = util::timeit(); let mut cmd = Command::new(build.tool(&Compiler::new(0, host), "cargotest")); build.prepare_tool_cmd(compiler, &mut cmd); - build.run(cmd.env("PATH", newpath) - .arg(&build.cargo) - .arg(&out_dir)); + build.run(cmd.arg(&build.cargo) + .arg(&out_dir) + .env("RUSTC", build.compiler_path(compiler)) + .env("RUSTDOC", build.rustdoc(compiler))) +} + +/// Runs `cargo test` for `cargo` packaged with Rust. +pub fn cargo(build: &Build, stage: u32, host: &str) { + let ref compiler = Compiler::new(stage, host); + + // Configure PATH to find the right rustc. NB. we have to use PATH + // and not RUSTC because the Cargo test suite has tests that will + // fail if rustc is not spelled `rustc`. + let path = build.sysroot(compiler).join("bin"); + let old_path = ::std::env::var("PATH").expect(""); + let sep = if cfg!(windows) { ";" } else {":" }; + let ref newpath = format!("{}{}{}", path.display(), sep, old_path); + + let mut cargo = build.cargo(compiler, Mode::Tool, host, "test"); + cargo.arg("--manifest-path").arg(build.src.join("src/tools/cargo/Cargo.toml")); + + // Don't build tests dynamically, just a pain to work with + cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1"); + + // Don't run cross-compile tests, we may not have cross-compiled libstd libs + // available. + cargo.env("CFG_DISABLE_CROSS_TESTS", "1"); + + build.run(cargo.env("PATH", newpath)); } /// Runs the `tidy` tool as compiled in `stage` by the `host` compiler. @@ -225,10 +243,10 @@ pub fn compiletest(build: &Build, .arg("--llvm-cxxflags").arg(""); } - if build.qemu_rootfs(target).is_some() { - cmd.arg("--qemu-test-client") + if build.remote_tested(target) { + cmd.arg("--remote-test-client") .arg(build.tool(&Compiler::new(0, &build.config.build), - "qemu-test-client")); + "remote-test-client")); } // Running a C compiler on MSVC requires a few env vars to be set, to be @@ -427,9 +445,7 @@ pub fn krate(build: &Build, dylib_path.insert(0, build.sysroot_libdir(&compiler, target)); cargo.env(dylib_path_var(), env::join_paths(&dylib_path).unwrap()); - if target.contains("android") || - target.contains("emscripten") || - build.qemu_rootfs(target).is_some() { + if target.contains("emscripten") || build.remote_tested(target) { cargo.arg("--no-run"); } @@ -441,75 +457,24 @@ pub fn krate(build: &Build, let _time = util::timeit(); - if target.contains("android") { - build.run(&mut cargo); - krate_android(build, &compiler, target, mode); - } else if target.contains("emscripten") { + if target.contains("emscripten") { build.run(&mut cargo); krate_emscripten(build, &compiler, target, mode); - } else if build.qemu_rootfs(target).is_some() { + } else if build.remote_tested(target) { build.run(&mut cargo); - krate_qemu(build, &compiler, target, mode); + krate_remote(build, &compiler, target, mode); } else { cargo.args(&build.flags.cmd.test_args()); build.run(&mut cargo); } } -fn krate_android(build: &Build, - compiler: &Compiler, - target: &str, - mode: Mode) { - let mut tests = Vec::new(); - let out_dir = build.cargo_out(compiler, mode, target); - find_tests(&out_dir, target, &mut tests); - find_tests(&out_dir.join("deps"), target, &mut tests); - - for test in tests { - build.run(Command::new("adb").arg("push").arg(&test).arg(ADB_TEST_DIR)); - - let test_file_name = test.file_name().unwrap().to_string_lossy(); - let log = format!("{}/check-stage{}-T-{}-H-{}-{}.log", - ADB_TEST_DIR, - compiler.stage, - target, - compiler.host, - test_file_name); - let quiet = if build.config.quiet_tests { "--quiet" } else { "" }; - let program = format!("(cd {dir}; \ - LD_LIBRARY_PATH=./{target} ./{test} \ - --logfile {log} \ - {quiet} \ - {args})", - dir = ADB_TEST_DIR, - target = target, - test = test_file_name, - log = log, - quiet = quiet, - args = build.flags.cmd.test_args().join(" ")); - - let output = output(Command::new("adb").arg("shell").arg(&program)); - println!("{}", output); - - t!(fs::create_dir_all(build.out.join("tmp"))); - build.run(Command::new("adb") - .arg("pull") - .arg(&log) - .arg(build.out.join("tmp"))); - build.run(Command::new("adb").arg("shell").arg("rm").arg(&log)); - if !output.contains("result: ok") { - panic!("some tests failed"); - } - } -} - fn krate_emscripten(build: &Build, compiler: &Compiler, target: &str, mode: Mode) { let mut tests = Vec::new(); let out_dir = build.cargo_out(compiler, mode, target); - find_tests(&out_dir, target, &mut tests); find_tests(&out_dir.join("deps"), target, &mut tests); for test in tests { @@ -525,17 +490,16 @@ fn krate_emscripten(build: &Build, } } -fn krate_qemu(build: &Build, - compiler: &Compiler, - target: &str, - mode: Mode) { +fn krate_remote(build: &Build, + compiler: &Compiler, + target: &str, + mode: Mode) { let mut tests = Vec::new(); let out_dir = build.cargo_out(compiler, mode, target); - find_tests(&out_dir, target, &mut tests); find_tests(&out_dir.join("deps"), target, &mut tests); let tool = build.tool(&Compiler::new(0, &build.config.build), - "qemu-test-client"); + "remote-test-client"); for test in tests { let mut cmd = Command::new(&tool); cmd.arg("run") @@ -548,7 +512,6 @@ fn krate_qemu(build: &Build, } } - fn find_tests(dir: &Path, target: &str, dst: &mut Vec) { @@ -566,60 +529,29 @@ fn find_tests(dir: &Path, } } -pub fn emulator_copy_libs(build: &Build, compiler: &Compiler, target: &str) { - if target.contains("android") { - android_copy_libs(build, compiler, target) - } else if let Some(s) = build.qemu_rootfs(target) { - qemu_copy_libs(build, compiler, target, s) +pub fn remote_copy_libs(build: &Build, compiler: &Compiler, target: &str) { + if !build.remote_tested(target) { + return } -} -fn android_copy_libs(build: &Build, compiler: &Compiler, target: &str) { - println!("Android copy libs to emulator ({})", target); - build.run(Command::new("adb").arg("wait-for-device")); - build.run(Command::new("adb").arg("remount")); - build.run(Command::new("adb").args(&["shell", "rm", "-r", ADB_TEST_DIR])); - build.run(Command::new("adb").args(&["shell", "mkdir", ADB_TEST_DIR])); - build.run(Command::new("adb") - .arg("push") - .arg(build.src.join("src/etc/adb_run_wrapper.sh")) - .arg(ADB_TEST_DIR)); - - let target_dir = format!("{}/{}", ADB_TEST_DIR, target); - build.run(Command::new("adb").args(&["shell", "mkdir", &target_dir[..]])); - - for f in t!(build.sysroot_libdir(compiler, target).read_dir()) { - let f = t!(f); - let name = f.file_name().into_string().unwrap(); - if util::is_dylib(&name) { - build.run(Command::new("adb") - .arg("push") - .arg(f.path()) - .arg(&target_dir)); - } - } -} - -fn qemu_copy_libs(build: &Build, - compiler: &Compiler, - target: &str, - rootfs: &Path) { - println!("QEMU copy libs to emulator ({})", target); - assert!(target.starts_with("arm"), "only works with arm for now"); + println!("REMOTE copy libs to emulator ({})", target); t!(fs::create_dir_all(build.out.join("tmp"))); - // Copy our freshly compiled test server over to the rootfs let server = build.cargo_out(compiler, Mode::Tool, target) - .join(exe("qemu-test-server", target)); - t!(fs::copy(&server, rootfs.join("testd"))); + .join(exe("remote-test-server", target)); // Spawn the emulator and wait for it to come online let tool = build.tool(&Compiler::new(0, &build.config.build), - "qemu-test-client"); - build.run(Command::new(&tool) - .arg("spawn-emulator") - .arg(rootfs) - .arg(build.out.join("tmp"))); + "remote-test-client"); + let mut cmd = Command::new(&tool); + cmd.arg("spawn-emulator") + .arg(target) + .arg(&server) + .arg(build.out.join("tmp")); + if let Some(rootfs) = build.qemu_rootfs(target) { + cmd.arg(rootfs); + } + build.run(&mut cmd); // Push all our dylibs to the emulator for f in t!(build.sysroot_libdir(compiler, target).read_dir()) { @@ -645,6 +577,7 @@ pub fn distcheck(build: &Build) { return } + println!("Distcheck"); let dir = build.out.join("tmp").join("distcheck"); let _ = fs::remove_dir_all(&dir); t!(fs::create_dir_all(&dir)); @@ -662,6 +595,26 @@ pub fn distcheck(build: &Build) { build.run(Command::new(build_helper::make(&build.config.build)) .arg("check") .current_dir(&dir)); + + // Now make sure that rust-src has all of libstd's dependencies + println!("Distcheck rust-src"); + let dir = build.out.join("tmp").join("distcheck-src"); + let _ = fs::remove_dir_all(&dir); + t!(fs::create_dir_all(&dir)); + + let mut cmd = Command::new("tar"); + cmd.arg("-xzf") + .arg(dist::rust_src_installer(build)) + .arg("--strip-components=1") + .current_dir(&dir); + build.run(&mut cmd); + + let toml = dir.join("rust-src/lib/rustlib/src/rust/src/libstd/Cargo.toml"); + build.run(Command::new(&build.cargo) + .arg("generate-lockfile") + .arg("--manifest-path") + .arg(&toml) + .current_dir(&dir)); } /// Test the build system itself diff --git a/src/bootstrap/clean.rs b/src/bootstrap/clean.rs index e9547ee42d07..308a0ab3076d 100644 --- a/src/bootstrap/clean.rs +++ b/src/bootstrap/clean.rs @@ -44,26 +44,25 @@ pub fn clean(build: &Build) { } fn rm_rf(path: &Path) { - if !path.exists() { - return - } - if path.is_file() { - return do_op(path, "remove file", |p| fs::remove_file(p)); - } + match path.symlink_metadata() { + Err(e) => { + if e.kind() == ErrorKind::NotFound { + return; + } + panic!("failed to get metadata for file {}: {}", path.display(), e); + }, + Ok(metadata) => { + if metadata.file_type().is_file() || metadata.file_type().is_symlink() { + do_op(path, "remove file", |p| fs::remove_file(p)); + return; + } - for file in t!(fs::read_dir(path)) { - let file = t!(file).path(); - - if file.is_dir() { - rm_rf(&file); - } else { - // On windows we can't remove a readonly file, and git will - // often clone files as readonly. As a result, we have some - // special logic to remove readonly files on windows. - do_op(&file, "remove file", |p| fs::remove_file(p)); - } - } - do_op(path, "remove dir", |p| fs::remove_dir(p)); + for file in t!(fs::read_dir(path)) { + rm_rf(&t!(file).path()); + } + do_op(path, "remove dir", |p| fs::remove_dir(p)); + }, + }; } fn do_op(path: &Path, desc: &str, mut f: F) @@ -71,9 +70,12 @@ fn do_op(path: &Path, desc: &str, mut f: F) { match f(path) { Ok(()) => {} + // On windows we can't remove a readonly file, and git will often clone files as readonly. + // As a result, we have some special logic to remove readonly files on windows. + // This is also the reason that we can't use things like fs::remove_dir_all(). Err(ref e) if cfg!(windows) && e.kind() == ErrorKind::PermissionDenied => { - let mut p = t!(path.metadata()).permissions(); + let mut p = t!(path.symlink_metadata()).permissions(); p.set_readonly(false); t!(fs::set_permissions(path, p)); f(path).unwrap_or_else(|e| { diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index eeec7eb029e5..c810a0e05d4d 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -115,6 +115,13 @@ pub fn std_link(build: &Build, if target.contains("musl") && !target.contains("mips") { copy_musl_third_party_objects(build, target, &libdir); } + + if build.config.sanitizers && compiler.stage != 0 && target == "x86_64-apple-darwin" { + // The sanitizers are only built in stage1 or above, so the dylibs will + // be missing in stage0 and causes panic. See the `std()` function above + // for reason why the sanitizers are not built in stage0. + copy_apple_sanitizer_dylibs(&build.native_dir(target), "osx", &libdir); + } } /// Copies the crt(1,i,n).o startup objects @@ -126,6 +133,18 @@ fn copy_musl_third_party_objects(build: &Build, target: &str, into: &Path) { } } +fn copy_apple_sanitizer_dylibs(native_dir: &Path, platform: &str, into: &Path) { + for &sanitizer in &["asan", "tsan"] { + let filename = format!("libclang_rt.{}_{}_dynamic.dylib", sanitizer, platform); + let mut src_path = native_dir.join(sanitizer); + src_path.push("build"); + src_path.push("lib"); + src_path.push("darwin"); + src_path.push(&filename); + copy(&src_path, &into.join(filename)); + } +} + /// Build and prepare startup objects like rsbegin.o and rsend.o /// /// These are primarily used on Windows right now for linking executables/dlls. @@ -151,6 +170,7 @@ pub fn build_startup_objects(build: &Build, for_compiler: &Compiler, target: &st if !up_to_date(src_file, dst_file) { let mut cmd = Command::new(&compiler_path); build.run(cmd.env("RUSTC_BOOTSTRAP", "1") + .arg("--cfg").arg(format!("stage{}", compiler.stage)) .arg("--target").arg(target) .arg("--emit=obj") .arg("--out-dir").arg(dst_dir) @@ -275,6 +295,7 @@ pub fn rustc(build: &Build, target: &str, compiler: &Compiler) { cargo.env("CFG_DEFAULT_AR", s); } build.run(&mut cargo); + update_mtime(build, &librustc_stamp(build, compiler, target)); } /// Same as `std_link`, only for librustc @@ -305,6 +326,12 @@ fn libtest_stamp(build: &Build, compiler: &Compiler, target: &str) -> PathBuf { build.cargo_out(compiler, Mode::Libtest, target).join(".libtest.stamp") } +/// Cargo's output path for librustc in a given stage, compiled by a particular +/// compiler for the specified target. +fn librustc_stamp(build: &Build, compiler: &Compiler, target: &str) -> PathBuf { + build.cargo_out(compiler, Mode::Librustc, target).join(".librustc.stamp") +} + fn compiler_file(compiler: &Path, file: &str) -> PathBuf { let out = output(Command::new(compiler) .arg(format!("-print-file-name={}", file))); @@ -407,6 +434,23 @@ fn add_to_sysroot(out_dir: &Path, sysroot_dst: &Path) { } } +/// Build a tool in `src/tools` +/// +/// This will build the specified tool with the specified `host` compiler in +/// `stage` into the normal cargo output directory. +pub fn maybe_clean_tools(build: &Build, stage: u32, target: &str, mode: Mode) { + let compiler = Compiler::new(stage, &build.config.build); + + let stamp = match mode { + Mode::Libstd => libstd_stamp(build, &compiler, target), + Mode::Libtest => libtest_stamp(build, &compiler, target), + Mode::Librustc => librustc_stamp(build, &compiler, target), + _ => panic!(), + }; + let out_dir = build.cargo_out(&compiler, Mode::Tool, target); + build.clear_if_dirty(&out_dir, &stamp); +} + /// Build a tool in `src/tools` /// /// This will build the specified tool with the specified `host` compiler in @@ -416,20 +460,8 @@ pub fn tool(build: &Build, stage: u32, target: &str, tool: &str) { let compiler = Compiler::new(stage, &build.config.build); - // FIXME: need to clear out previous tool and ideally deps, may require - // isolating output directories or require a pseudo shim step to - // clear out all the info. - // - // Maybe when libstd is compiled it should clear out the rustc of the - // corresponding stage? - // let out_dir = build.cargo_out(stage, &host, Mode::Librustc, target); - // build.clear_if_dirty(&out_dir, &libstd_stamp(build, stage, &host, target)); - let mut cargo = build.cargo(&compiler, Mode::Tool, target, "build"); - let mut dir = build.src.join(tool); - if !dir.exists() { - dir = build.src.join("src/tools").join(tool); - } + let dir = build.src.join("src/tools").join(tool); cargo.arg("--manifest-path").arg(dir.join("Cargo.toml")); // We don't want to build tools dynamically as they'll be running across diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 52ebf401aefd..34fbc33d981a 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -74,7 +74,6 @@ pub struct Config { pub rustc_default_ar: Option, pub rust_optimize_tests: bool, pub rust_debuginfo_tests: bool, - pub rust_save_analysis: bool, pub rust_dist_src: bool, pub build: String, @@ -226,7 +225,6 @@ struct Rust { optimize_tests: Option, debuginfo_tests: Option, codegen_tests: Option, - save_analysis: Option, } /// TOML representation of how each build target is configured. @@ -352,7 +350,6 @@ impl Config { set(&mut config.rust_optimize_tests, rust.optimize_tests); set(&mut config.rust_debuginfo_tests, rust.debuginfo_tests); set(&mut config.codegen_tests, rust.codegen_tests); - set(&mut config.rust_save_analysis, rust.save_analysis); set(&mut config.rust_rpath, rust.rpath); set(&mut config.debug_jemalloc, rust.debug_jemalloc); set(&mut config.use_jemalloc, rust.use_jemalloc); @@ -460,7 +457,6 @@ impl Config { ("LOCAL_REBUILD", self.local_rebuild), ("NINJA", self.ninja), ("CODEGEN_TESTS", self.codegen_tests), - ("SAVE_ANALYSIS", self.rust_save_analysis), ("LOCKED_DEPS", self.locked_deps), ("VENDOR", self.vendor), ("FULL_BOOTSTRAP", self.full_bootstrap), @@ -574,6 +570,12 @@ impl Config { .or_insert(Target::default()); target.ndk = Some(parse_configure_path(value)); } + "CFG_X86_64_LINUX_ANDROID_NDK" if value.len() > 0 => { + let target = "x86_64-linux-android".to_string(); + let target = self.target_config.entry(target) + .or_insert(Target::default()); + target.ndk = Some(parse_configure_path(value)); + } "CFG_LOCAL_RUST_ROOT" if value.len() > 0 => { let path = parse_configure_path(value); self.rustc = Some(push_exe_path(path.clone(), &["bin", "rustc"])); diff --git a/src/bootstrap/config.toml.example b/src/bootstrap/config.toml.example index 6b2cc6eb6474..0309eca0e5de 100644 --- a/src/bootstrap/config.toml.example +++ b/src/bootstrap/config.toml.example @@ -51,7 +51,7 @@ # support. You'll need to write a target specification at least, and most # likely, teach rustc about the C ABI of the target. Get in touch with the # Rust team and file an issue if you need assistance in porting! -#targets = "X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend;MSP430;Sparc;NVPTX" +#targets = "X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend;MSP430;Sparc;NVPTX;Hexagon" # Cap the number of parallel linker invocations when compiling LLVM. # This can be useful when building LLVM with debug info, which significantly @@ -234,9 +234,6 @@ # saying that the FileCheck executable is missing, you may want to disable this. #codegen-tests = true -# Flag indicating whether the API analysis data should be saved. -#save-analysis = false - # ============================================================================= # Options for specific targets # diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index ec992b47a6e4..1b69f7413b56 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -39,6 +39,8 @@ use util::{cp_r, libdir, is_dylib, cp_filtered, copy, exe}; fn pkgname(build: &Build, component: &str) -> String { if component == "cargo" { format!("{}-{}", component, build.cargo_package_vers()) + } else if component == "rls" { + format!("{}-{}", component, build.package_vers(&build.release_num("rls"))) } else { assert!(component.starts_with("rust")); format!("{}-{}", component, build.rust_package_vers()) @@ -252,7 +254,12 @@ pub fn debugger_scripts(build: &Build, install(&build.src.join("src/etc/").join(file), &dst, 0o644); }; if host.contains("windows-msvc") { - // no debugger scripts + // windbg debugger scripts + install(&build.src.join("src/etc/rust-windbg.cmd"), &sysroot.join("bin"), + 0o755); + + cp_debugger_script("natvis/libcore.natvis"); + cp_debugger_script("natvis/libcollections.natvis"); } else { cp_debugger_script("debugger_pretty_printers_common.py"); @@ -308,22 +315,26 @@ pub fn std(build: &Build, compiler: &Compiler, target: &str) { t!(fs::remove_dir_all(&image)); } +/// The path to the complete rustc-src tarball pub fn rust_src_location(build: &Build) -> PathBuf { let plain_name = format!("rustc-{}-src", build.rust_package_vers()); distdir(build).join(&format!("{}.tar.gz", plain_name)) } +/// The path to the rust-src component installer +pub fn rust_src_installer(build: &Build) -> PathBuf { + let name = pkgname(build, "rust-src"); + distdir(build).join(&format!("{}.tar.gz", name)) +} + /// Creates a tarball of save-analysis metadata, if available. pub fn analysis(build: &Build, compiler: &Compiler, target: &str) { - if !build.config.rust_save_analysis { - return - } - + assert!(build.config.extended); println!("Dist analysis"); if compiler.host != build.config.build { println!("\tskipping, not a build host"); - return + return; } // Package save-analysis from stage1 if not doing a full bootstrap, as the @@ -370,13 +381,11 @@ pub fn rust_src(build: &Build) { println!("Dist src"); - let name = pkgname(build, "rust-src"); - let image = tmpdir(build).join(format!("{}-image", name)); - let _ = fs::remove_dir_all(&image); - - let dst = image.join("lib/rustlib/src"); - let dst_src = dst.join("rust"); - t!(fs::create_dir_all(&dst_src)); + // Make sure that the root folder of tarball has the correct name + let plain_name = format!("rustc-{}-src", build.rust_package_vers()); + let plain_dst_src = tmpdir(build).join(&plain_name); + let _ = fs::remove_dir_all(&plain_dst_src); + t!(fs::create_dir_all(&plain_dst_src)); // This is the set of root paths which will become part of the source package let src_files = [ @@ -392,7 +401,6 @@ pub fn rust_src(build: &Build) { let src_dirs = [ "man", "src", - "cargo", ]; let filter_fn = move |path: &Path| { @@ -424,38 +432,94 @@ pub fn rust_src(build: &Build) { // Copy the directories using our filter for item in &src_dirs { - let dst = &dst_src.join(item); + let dst = &plain_dst_src.join(item); t!(fs::create_dir(dst)); cp_filtered(&build.src.join(item), dst, &filter_fn); } // Copy the files normally for item in &src_files { - copy(&build.src.join(item), &dst_src.join(item)); + copy(&build.src.join(item), &plain_dst_src.join(item)); } - // Get cargo-vendor installed, if it isn't already. - let mut has_cargo_vendor = false; - let mut cmd = Command::new(&build.cargo); - for line in output(cmd.arg("install").arg("--list")).lines() { - has_cargo_vendor |= line.starts_with("cargo-vendor "); - } - if !has_cargo_vendor { + // If we're building from git sources, we need to vendor a complete distribution. + if build.src_is_git { + // Get cargo-vendor installed, if it isn't already. + let mut has_cargo_vendor = false; let mut cmd = Command::new(&build.cargo); - cmd.arg("install") - .arg("--force") - .arg("--debug") - .arg("--vers").arg(CARGO_VENDOR_VERSION) - .arg("cargo-vendor") - .env("RUSTC", &build.rustc); + for line in output(cmd.arg("install").arg("--list")).lines() { + has_cargo_vendor |= line.starts_with("cargo-vendor "); + } + if !has_cargo_vendor { + let mut cmd = Command::new(&build.cargo); + cmd.arg("install") + .arg("--force") + .arg("--debug") + .arg("--vers").arg(CARGO_VENDOR_VERSION) + .arg("cargo-vendor") + .env("RUSTC", &build.rustc); + build.run(&mut cmd); + } + + // Vendor all Cargo dependencies + let mut cmd = Command::new(&build.cargo); + cmd.arg("vendor") + .current_dir(&plain_dst_src.join("src")); build.run(&mut cmd); } - // Vendor all Cargo dependencies - let mut cmd = Command::new(&build.cargo); - cmd.arg("vendor") - .current_dir(&dst_src.join("src")); + // Create the version file + write_file(&plain_dst_src.join("version"), build.rust_version().as_bytes()); + + // Create plain source tarball + let tarball = rust_src_location(build); + if let Some(dir) = tarball.parent() { + t!(fs::create_dir_all(dir)); + } + let mut cmd = Command::new("tar"); + cmd.arg("-czf").arg(sanitize_sh(&tarball)) + .arg(&plain_name) + .current_dir(tmpdir(build)); build.run(&mut cmd); + + let name = pkgname(build, "rust-src"); + let image = tmpdir(build).join(format!("{}-image", name)); + let _ = fs::remove_dir_all(&image); + + let dst = image.join("lib/rustlib/src"); + let dst_src = dst.join("rust"); + t!(fs::create_dir_all(&dst_src)); + + // This is the reduced set of paths which will become the rust-src component + // (essentially libstd and all of its path dependencies) + let std_src_dirs = [ + "src/build_helper", + "src/liballoc", + "src/liballoc_jemalloc", + "src/liballoc_system", + "src/libcollections", + "src/libcompiler_builtins", + "src/libcore", + "src/liblibc", + "src/libpanic_abort", + "src/libpanic_unwind", + "src/librand", + "src/librustc_asan", + "src/librustc_lsan", + "src/librustc_msan", + "src/librustc_tsan", + "src/libstd", + "src/libstd_unicode", + "src/libunwind", + "src/rustc/libc_shim", + ]; + + for item in &std_src_dirs { + let dst = &dst_src.join(item); + t!(fs::create_dir_all(dst)); + cp_r(&plain_dst_src.join(item), dst); + } + // Create source tarball in rust-installer format let mut cmd = Command::new(SH_CMD); cmd.arg(sanitize_sh(&build.src.join("src/rust-installer/gen-installer.sh"))) @@ -470,23 +534,6 @@ pub fn rust_src(build: &Build) { .arg("--legacy-manifest-dirs=rustlib,cargo"); build.run(&mut cmd); - // Rename directory, so that root folder of tarball has the correct name - let plain_name = format!("rustc-{}-src", build.rust_package_vers()); - let plain_dst_src = tmpdir(build).join(&plain_name); - let _ = fs::remove_dir_all(&plain_dst_src); - t!(fs::create_dir_all(&plain_dst_src)); - cp_r(&dst_src, &plain_dst_src); - - // Create the version file - write_file(&plain_dst_src.join("version"), build.rust_version().as_bytes()); - - // Create plain source tarball - let mut cmd = Command::new("tar"); - cmd.arg("-czf").arg(sanitize_sh(&rust_src_location(build))) - .arg(&plain_name) - .current_dir(tmpdir(build)); - build.run(&mut cmd); - t!(fs::remove_dir_all(&image)); t!(fs::remove_dir_all(&plain_dst_src)); } @@ -534,9 +581,9 @@ pub fn cargo(build: &Build, stage: u32, target: &str) { println!("Dist cargo stage{} ({})", stage, target); let compiler = Compiler::new(stage, &build.config.build); - let src = build.src.join("cargo"); + let src = build.src.join("src/tools/cargo"); let etc = src.join("src/etc"); - let release_num = build.cargo_release_num(); + let release_num = build.release_num("cargo"); let name = pkgname(build, "cargo"); let version = build.cargo_info.version(build, &release_num); @@ -590,6 +637,55 @@ pub fn cargo(build: &Build, stage: u32, target: &str) { build.run(&mut cmd); } +pub fn rls(build: &Build, stage: u32, target: &str) { + assert!(build.config.extended); + println!("Dist RLS stage{} ({})", stage, target); + let compiler = Compiler::new(stage, &build.config.build); + + let src = build.src.join("src/tools/rls"); + let release_num = build.release_num("rls"); + let name = pkgname(build, "rls"); + let version = build.rls_info.version(build, &release_num); + + let tmp = tmpdir(build); + let image = tmp.join("rls-image"); + drop(fs::remove_dir_all(&image)); + t!(fs::create_dir_all(&image)); + + // Prepare the image directory + let rls = build.cargo_out(&compiler, Mode::Tool, target) + .join(exe("rls", target)); + install(&rls, &image.join("bin"), 0o755); + let doc = image.join("share/doc/rls"); + install(&src.join("README.md"), &doc, 0o644); + install(&src.join("LICENSE-MIT"), &doc, 0o644); + install(&src.join("LICENSE-APACHE"), &doc, 0o644); + + // Prepare the overlay + let overlay = tmp.join("rls-overlay"); + drop(fs::remove_dir_all(&overlay)); + t!(fs::create_dir_all(&overlay)); + install(&src.join("README.md"), &overlay, 0o644); + install(&src.join("LICENSE-MIT"), &overlay, 0o644); + install(&src.join("LICENSE-APACHE"), &overlay, 0o644); + t!(t!(File::create(overlay.join("version"))).write_all(version.as_bytes())); + + // Generate the installer tarball + let mut cmd = Command::new("sh"); + cmd.arg(sanitize_sh(&build.src.join("src/rust-installer/gen-installer.sh"))) + .arg("--product-name=Rust") + .arg("--rel-manifest-dir=rustlib") + .arg("--success-message=RLS-ready-to-serve.") + .arg(format!("--image-dir={}", sanitize_sh(&image))) + .arg(format!("--work-dir={}", sanitize_sh(&tmpdir(build)))) + .arg(format!("--output-dir={}", sanitize_sh(&distdir(build)))) + .arg(format!("--non-installed-overlay={}", sanitize_sh(&overlay))) + .arg(format!("--package-name={}-{}", name, target)) + .arg("--component-name=rls") + .arg("--legacy-manifest-dirs=rustlib,cargo"); + build.run(&mut cmd); +} + /// Creates a combined installer for the specified target in the provided stage. pub fn extended(build: &Build, stage: u32, target: &str) { println!("Dist extended stage{} ({})", stage, target); @@ -601,6 +697,12 @@ pub fn extended(build: &Build, stage: u32, target: &str) { let cargo_installer = dist.join(format!("{}-{}.tar.gz", pkgname(build, "cargo"), target)); + let rls_installer = dist.join(format!("{}-{}.tar.gz", + pkgname(build, "rls"), + target)); + let analysis_installer = dist.join(format!("{}-{}.tar.gz", + pkgname(build, "rust-analysis"), + target)); let docs_installer = dist.join(format!("{}-{}.tar.gz", pkgname(build, "rust-docs"), target)); @@ -628,9 +730,11 @@ pub fn extended(build: &Build, stage: u32, target: &str) { // upgrades rustc was upgraded before rust-std. To avoid rustc clobbering // the std files during uninstall. To do this ensure that rustc comes // before rust-std in the list below. - let mut input_tarballs = format!("{},{},{},{}", + let mut input_tarballs = format!("{},{},{},{},{},{}", sanitize_sh(&rustc_installer), sanitize_sh(&cargo_installer), + sanitize_sh(&rls_installer), + sanitize_sh(&analysis_installer), sanitize_sh(&docs_installer), sanitize_sh(&std_installer)); if target.contains("pc-windows-gnu") { @@ -943,7 +1047,8 @@ pub fn hash_and_sign(build: &Build) { cmd.arg(distdir(build)); cmd.arg(today.trim()); cmd.arg(build.rust_package_vers()); - cmd.arg(build.package_vers(&build.cargo_release_num())); + cmd.arg(build.package_vers(&build.release_num("cargo"))); + cmd.arg(build.package_vers(&build.release_num("rls"))); cmd.arg(addr); t!(fs::create_dir_all(distdir(build))); diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index b55f3d710ca7..a1466d68a135 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -18,7 +18,7 @@ use std::fs; use std::path::PathBuf; use std::process; -use getopts::{Matches, Options}; +use getopts::Options; use Build; use config::Config; @@ -75,7 +75,22 @@ pub enum Subcommand { impl Flags { pub fn parse(args: &[String]) -> Flags { + let mut extra_help = String::new(); + let mut subcommand_help = format!("\ +Usage: x.py [options] [...] + +Subcommands: + build Compile either the compiler or libraries + test Build and run some test suites + bench Build and run some benchmarks + doc Build documentation + clean Clean out build directories + dist Build and/or install distribution artifacts + +To learn more about a subcommand, run `./x.py -h`"); + let mut opts = Options::new(); + // Options common to all subcommands opts.optflagmulti("v", "verbose", "use verbose output (-vv for very verbose)"); opts.optflag("i", "incremental", "use incremental compilation"); opts.optopt("", "config", "TOML configuration file for build", "FILE"); @@ -89,21 +104,83 @@ impl Flags { opts.optopt("j", "jobs", "number of jobs to run in parallel", "JOBS"); opts.optflag("h", "help", "print this help message"); - let usage = |n, opts: &Options| -> ! { - let command = args.get(0).map(|s| &**s); - let brief = format!("Usage: x.py {} [options] [...]", - command.unwrap_or("")); + // fn usage() + let usage = |exit_code: i32, opts: &Options, subcommand_help: &str, extra_help: &str| -> ! { + println!("{}", opts.usage(subcommand_help)); + if !extra_help.is_empty() { + println!("{}", extra_help); + } + process::exit(exit_code); + }; - println!("{}", opts.usage(&brief)); - match command { - Some("build") => { - println!("\ + // We can't use getopt to parse the options until we have completed specifying which + // options are valid, but under the current implementation, some options are conditional on + // the subcommand. Therefore we must manually identify the subcommand first, so that we can + // complete the definition of the options. Then we can use the getopt::Matches object from + // there on out. + let mut possible_subcommands = args.iter().collect::>(); + possible_subcommands.retain(|&s| + (s == "build") + || (s == "test") + || (s == "bench") + || (s == "doc") + || (s == "clean") + || (s == "dist")); + let subcommand = match possible_subcommands.first() { + Some(s) => s, + None => { + // No subcommand -- show the general usage and subcommand help + println!("{}\n", subcommand_help); + process::exit(0); + } + }; + + // Some subcommands get extra options + match subcommand.as_str() { + "test" => { opts.optmulti("", "test-args", "extra arguments", "ARGS"); }, + "bench" => { opts.optmulti("", "test-args", "extra arguments", "ARGS"); }, + "dist" => { opts.optflag("", "install", "run installer as well"); }, + _ => { }, + }; + + // Done specifying what options are possible, so do the getopts parsing + let matches = opts.parse(&args[..]).unwrap_or_else(|e| { + // Invalid argument/option format + println!("\n{}\n", e); + usage(1, &opts, &subcommand_help, &extra_help); + }); + // Extra sanity check to make sure we didn't hit this crazy corner case: + // + // ./x.py --frobulate clean build + // ^-- option ^ ^- actual subcommand + // \_ arg to option could be mistaken as subcommand + let mut pass_sanity_check = true; + match matches.free.get(0) { + Some(check_subcommand) => { + if &check_subcommand != subcommand { + pass_sanity_check = false; + } + }, + None => { + pass_sanity_check = false; + } + } + if !pass_sanity_check { + println!("{}\n", subcommand_help); + println!("Sorry, I couldn't figure out which subcommand you were trying to specify.\n\ + You may need to move some options to after the subcommand.\n"); + process::exit(1); + } + // Extra help text for some commands + match subcommand.as_str() { + "build" => { + subcommand_help.push_str("\n Arguments: - This subcommand accepts a number of positional arguments of directories to - the crates and/or artifacts to compile. For example: + This subcommand accepts a number of paths to directories to the crates + and/or artifacts to compile. For example: ./x.py build src/libcore - ./x.py build src/libproc_macro + ./x.py build src/libcore src/libproc_macro ./x.py build src/libstd --stage 1 If no arguments are passed then the complete artifacts for that stage are @@ -114,15 +191,13 @@ Arguments: For a quick build with a usable compile, you can pass: - ./x.py build --stage 1 src/libtest -"); - } - - Some("test") => { - println!("\ + ./x.py build --stage 1 src/libtest"); + } + "test" => { + subcommand_help.push_str("\n Arguments: - This subcommand accepts a number of positional arguments of directories to - tests that should be compiled and run. For example: + This subcommand accepts a number of paths to directories to tests that + should be compiled and run. For example: ./x.py test src/test/run-pass ./x.py test src/libstd --test-args hash_map @@ -132,139 +207,90 @@ Arguments: compiled and tested. ./x.py test - ./x.py test --stage 1 -"); - } - - Some("doc") => { - println!("\ + ./x.py test --stage 1"); + } + "doc" => { + subcommand_help.push_str("\n Arguments: - This subcommand accepts a number of positional arguments of directories of - documentation to build. For example: + This subcommand accepts a number of paths to directories of documentation + to build. For example: ./x.py doc src/doc/book ./x.py doc src/doc/nomicon - ./x.py doc src/libstd + ./x.py doc src/doc/book src/libstd If no arguments are passed then everything is documented: ./x.py doc - ./x.py doc --stage 1 -"); - } - - _ => {} + ./x.py doc --stage 1"); } - - if let Some(command) = command { - if command == "build" || - command == "dist" || - command == "doc" || - command == "test" || - command == "bench" || - command == "clean" { - println!("Available invocations:"); - if args.iter().any(|a| a == "-v") { - let flags = Flags::parse(&["build".to_string()]); - let mut config = Config::default(); - config.build = flags.build.clone(); - let mut build = Build::new(flags, config); - metadata::build(&mut build); - step::build_rules(&build).print_help(command); - } else { - println!(" ... elided, run `./x.py {} -h -v` to see", - command); - } - - println!(""); - } - } - -println!("\ -Subcommands: - build Compile either the compiler or libraries - test Build and run some test suites - bench Build and run some benchmarks - doc Build documentation - clean Clean out build directories - dist Build and/or install distribution artifacts - -To learn more about a subcommand, run `./x.py -h` -"); - - process::exit(n); + _ => { } }; - if args.len() == 0 { - println!("a command must be passed"); - usage(1, &opts); - } - let parse = |opts: &Options| { - let m = opts.parse(&args[1..]).unwrap_or_else(|e| { - println!("failed to parse options: {}", e); - usage(1, opts); - }); - if m.opt_present("h") { - usage(0, opts); - } - return m - }; - + // Get any optional paths which occur after the subcommand let cwd = t!(env::current_dir()); - let remaining_as_path = |m: &Matches| { - m.free.iter().map(|p| cwd.join(p)).collect::>() - }; + let paths = matches.free[1..].iter().map(|p| cwd.join(p)).collect::>(); - let m: Matches; - let cmd = match &args[0][..] { - "build" => { - m = parse(&opts); - Subcommand::Build { paths: remaining_as_path(&m) } + + // All subcommands can have an optional "Available paths" section + if matches.opt_present("verbose") { + let flags = Flags::parse(&["build".to_string()]); + let mut config = Config::default(); + config.build = flags.build.clone(); + let mut build = Build::new(flags, config); + metadata::build(&mut build); + let maybe_rules_help = step::build_rules(&build).get_help(subcommand); + if maybe_rules_help.is_some() { + extra_help.push_str(maybe_rules_help.unwrap().as_str()); } - "doc" => { - m = parse(&opts); - Subcommand::Doc { paths: remaining_as_path(&m) } + } else { + extra_help.push_str(format!("Run `./x.py {} -h -v` to see a list of available paths.", + subcommand).as_str()); + } + + // User passed in -h/--help? + if matches.opt_present("help") { + usage(0, &opts, &subcommand_help, &extra_help); + } + + let cmd = match subcommand.as_str() { + "build" => { + Subcommand::Build { paths: paths } } "test" => { - opts.optmulti("", "test-args", "extra arguments", "ARGS"); - m = parse(&opts); Subcommand::Test { - paths: remaining_as_path(&m), - test_args: m.opt_strs("test-args"), + paths: paths, + test_args: matches.opt_strs("test-args"), } } "bench" => { - opts.optmulti("", "test-args", "extra arguments", "ARGS"); - m = parse(&opts); Subcommand::Bench { - paths: remaining_as_path(&m), - test_args: m.opt_strs("test-args"), + paths: paths, + test_args: matches.opt_strs("test-args"), } } + "doc" => { + Subcommand::Doc { paths: paths } + } "clean" => { - m = parse(&opts); - if m.free.len() > 0 { - println!("clean takes no arguments"); - usage(1, &opts); + if paths.len() > 0 { + println!("\nclean takes no arguments\n"); + usage(1, &opts, &subcommand_help, &extra_help); } Subcommand::Clean } "dist" => { - opts.optflag("", "install", "run installer as well"); - m = parse(&opts); Subcommand::Dist { - paths: remaining_as_path(&m), - install: m.opt_present("install"), + paths: paths, + install: matches.opt_present("install"), } } - "--help" => usage(0, &opts), - cmd => { - println!("unknown command: {}", cmd); - usage(1, &opts); + _ => { + usage(1, &opts, &subcommand_help, &extra_help); } }; - let cfg_file = m.opt_str("config").map(PathBuf::from).or_else(|| { + let cfg_file = matches.opt_str("config").map(PathBuf::from).or_else(|| { if fs::metadata("config.toml").is_ok() { Some(PathBuf::from("config.toml")) } else { @@ -272,31 +298,29 @@ To learn more about a subcommand, run `./x.py -h` } }); - let mut stage = m.opt_str("stage").map(|j| j.parse().unwrap()); + let mut stage = matches.opt_str("stage").map(|j| j.parse().unwrap()); - let incremental = m.opt_present("i"); - - if incremental { + if matches.opt_present("incremental") { if stage.is_none() { stage = Some(1); } } Flags { - verbose: m.opt_count("v"), + verbose: matches.opt_count("verbose"), stage: stage, - on_fail: m.opt_str("on-fail"), - keep_stage: m.opt_str("keep-stage").map(|j| j.parse().unwrap()), - build: m.opt_str("build").unwrap_or_else(|| { + on_fail: matches.opt_str("on-fail"), + keep_stage: matches.opt_str("keep-stage").map(|j| j.parse().unwrap()), + build: matches.opt_str("build").unwrap_or_else(|| { env::var("BUILD").unwrap() }), - host: split(m.opt_strs("host")), - target: split(m.opt_strs("target")), + host: split(matches.opt_strs("host")), + target: split(matches.opt_strs("target")), config: cfg_file, - src: m.opt_str("src").map(PathBuf::from), - jobs: m.opt_str("jobs").map(|j| j.parse().unwrap()), + src: matches.opt_str("src").map(PathBuf::from), + jobs: matches.opt_str("jobs").map(|j| j.parse().unwrap()), cmd: cmd, - incremental: incremental, + incremental: matches.opt_present("incremental"), } } } diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs index 249f241a151b..c805522fbf58 100644 --- a/src/bootstrap/install.rs +++ b/src/bootstrap/install.rs @@ -46,24 +46,32 @@ pub fn install(build: &Build, stage: u32, host: &str) { let empty_dir = build.out.join("tmp/empty_dir"); t!(fs::create_dir_all(&empty_dir)); if build.config.docs { - install_sh(&build, "docs", "rust-docs", stage, host, &prefix, - &docdir, &libdir, &mandir, &empty_dir); + install_sh(&build, "docs", "rust-docs", &build.rust_package_vers(), + stage, host, &prefix, &docdir, &libdir, &mandir, &empty_dir); } - if build.config.rust_save_analysis { - install_sh(&build, "analysis", "rust-analysis", stage, host, &prefix, - &docdir, &libdir, &mandir, &empty_dir); + + for target in build.config.target.iter() { + install_sh(&build, "std", "rust-std", &build.rust_package_vers(), + stage, target, &prefix, &docdir, &libdir, &mandir, &empty_dir); } - install_sh(&build, "std", "rust-std", stage, host, &prefix, - &docdir, &libdir, &mandir, &empty_dir); - install_sh(&build, "rustc", "rustc", stage, host, &prefix, - &docdir, &libdir, &mandir, &empty_dir); + + if build.config.extended { + install_sh(&build, "cargo", "cargo", &build.cargo_package_vers(), + stage, host, &prefix, &docdir, &libdir, &mandir, &empty_dir); + install_sh(&build, "rls", "rls", &build.rls_package_vers(), + stage, host, &prefix, &docdir, &libdir, &mandir, &empty_dir); + } + + install_sh(&build, "rustc", "rustc", &build.rust_package_vers(), + stage, host, &prefix, &docdir, &libdir, &mandir, &empty_dir); + t!(fs::remove_dir_all(&empty_dir)); } -fn install_sh(build: &Build, package: &str, name: &str, stage: u32, host: &str, +fn install_sh(build: &Build, package: &str, name: &str, version: &str, stage: u32, host: &str, prefix: &Path, docdir: &Path, libdir: &Path, mandir: &Path, empty_dir: &Path) { println!("Install {} stage{} ({})", package, stage, host); - let package_name = format!("{}-{}-{}", name, build.rust_package_vers(), host); + let package_name = format!("{}-{}-{}", name, version, host); let mut cmd = Command::new("sh"); cmd.current_dir(empty_dir) diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 84254d7d6ae5..017d4015134d 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -151,6 +151,7 @@ pub struct Build { out: PathBuf, rust_info: channel::GitInfo, cargo_info: channel::GitInfo, + rls_info: channel::GitInfo, local_rebuild: bool, // Probed tools at runtime @@ -162,6 +163,7 @@ pub struct Build { cxx: HashMap, crates: HashMap, is_sudo: bool, + src_is_git: bool, } #[derive(Debug)] @@ -232,7 +234,9 @@ impl Build { None => false, }; let rust_info = channel::GitInfo::new(&src); - let cargo_info = channel::GitInfo::new(&src.join("cargo")); + let cargo_info = channel::GitInfo::new(&src.join("src/tools/cargo")); + let rls_info = channel::GitInfo::new(&src.join("src/tools/rls")); + let src_is_git = src.join(".git").exists(); Build { flags: flags, @@ -244,6 +248,7 @@ impl Build { rust_info: rust_info, cargo_info: cargo_info, + rls_info: rls_info, local_rebuild: local_rebuild, cc: HashMap::new(), cxx: HashMap::new(), @@ -251,6 +256,7 @@ impl Build { lldb_version: None, lldb_python_dir: None, is_sudo: is_sudo, + src_is_git: src_is_git, } } @@ -307,10 +313,7 @@ impl Build { OutOfSync, } - if !self.config.submodules { - return - } - if fs::metadata(self.src.join(".git")).is_err() { + if !self.src_is_git || !self.config.submodules { return } let git = || { @@ -461,8 +464,6 @@ impl Build { .env("RUSTC", self.out.join("bootstrap/debug/rustc")) .env("RUSTC_REAL", self.compiler_path(compiler)) .env("RUSTC_STAGE", stage.to_string()) - .env("RUSTC_DEBUGINFO", self.config.rust_debuginfo.to_string()) - .env("RUSTC_DEBUGINFO_LINES", self.config.rust_debuginfo_lines.to_string()) .env("RUSTC_CODEGEN_UNITS", self.config.rust_codegen_units.to_string()) .env("RUSTC_DEBUG_ASSERTIONS", @@ -474,6 +475,13 @@ impl Build { .env("RUSTDOC_REAL", self.rustdoc(compiler)) .env("RUSTC_FLAGS", self.rustc_flags(target).join(" ")); + // Tools don't get debuginfo right now, e.g. cargo and rls don't get + // compiled with debuginfo. + if mode != Mode::Tool { + cargo.env("RUSTC_DEBUGINFO", self.config.rust_debuginfo.to_string()) + .env("RUSTC_DEBUGINFO_LINES", self.config.rust_debuginfo_lines.to_string()); + } + // Enable usage of unstable features cargo.env("RUSTC_BOOTSTRAP", "1"); self.add_rust_test_threads(&mut cargo); @@ -545,10 +553,23 @@ impl Build { .env(format!("CFLAGS_{}", target), self.cflags(target).join(" ")); } - if self.config.rust_save_analysis && compiler.is_final_stage(self) { + if self.config.extended && compiler.is_final_stage(self) { cargo.env("RUSTC_SAVE_ANALYSIS", "api".to_string()); } + // When being built Cargo will at some point call `nmake.exe` on Windows + // MSVC. Unfortunately `nmake` will read these two environment variables + // below and try to intepret them. We're likely being run, however, from + // MSYS `make` which uses the same variables. + // + // As a result, to prevent confusion and errors, we remove these + // variables from our environment to prevent passing MSYS make flags to + // nmake, causing it to blow up. + if cfg!(target_env = "msvc") { + cargo.env_remove("MAKE"); + cargo.env_remove("MAKEFLAGS"); + } + // Environment variables *required* needed throughout the build // // FIXME: should update code to not require this env var @@ -874,6 +895,13 @@ impl Build { if target.contains("apple-darwin") { base.push("-stdlib=libc++".into()); } + + // Work around an apparently bad MinGW / GCC optimization, + // See: http://lists.llvm.org/pipermail/cfe-dev/2016-December/051980.html + // See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=78936 + if target == "i686-pc-windows-gnu" { + base.push("-fno-omit-frame-pointer".into()); + } return base } @@ -917,6 +945,12 @@ impl Build { .map(|p| &**p) } + /// Returns whether the target will be tested using the `remote-test-client` + /// and `remote-test-server` binaries. + fn remote_tested(&self, target: &str) -> bool { + self.qemu_rootfs(target).is_some() || target.contains("android") + } + /// Returns the root of the "rootfs" image that this target will be using, /// if one was configured. /// @@ -1017,7 +1051,12 @@ impl Build { /// Returns the value of `package_vers` above for Cargo fn cargo_package_vers(&self) -> String { - self.package_vers(&self.cargo_release_num()) + self.package_vers(&self.release_num("cargo")) + } + + /// Returns the value of `package_vers` above for rls + fn rls_package_vers(&self) -> String { + self.package_vers(&self.release_num("rls")) } /// Returns the `version` string associated with this compiler for Rust @@ -1029,10 +1068,11 @@ impl Build { self.rust_info.version(self, channel::CFG_RELEASE_NUM) } - /// Returns the `a.b.c` version that Cargo is at. - fn cargo_release_num(&self) -> String { + /// Returns the `a.b.c` version that the given package is at. + fn release_num(&self, package: &str) -> String { let mut toml = String::new(); - t!(t!(File::open(self.src.join("cargo/Cargo.toml"))).read_to_string(&mut toml)); + let toml_file_name = self.src.join(&format!("src/tools/{}/Cargo.toml", package)); + t!(t!(File::open(toml_file_name)).read_to_string(&mut toml)); for line in toml.lines() { let prefix = "version = \""; let suffix = "\""; @@ -1041,7 +1081,7 @@ impl Build { } } - panic!("failed to find version in cargo's Cargo.toml") + panic!("failed to find version in {}'s Cargo.toml", package) } /// Returns whether unstable features should be enabled for the compiler diff --git a/src/bootstrap/metadata.rs b/src/bootstrap/metadata.rs index 5918fe41e7c8..7b6b01655df5 100644 --- a/src/bootstrap/metadata.rs +++ b/src/bootstrap/metadata.rs @@ -58,6 +58,7 @@ fn build_krate(build: &mut Build, krate: &str) { // the dependency graph and what `-p` arguments there are. let mut cargo = Command::new(&build.cargo); cargo.arg("metadata") + .arg("--format-version").arg("1") .arg("--manifest-path").arg(build.src.join(krate).join("Cargo.toml")); let output = output(&mut cargo); let output: Output = json::decode(&output).unwrap(); diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in index 457ac825832c..a5df741e2bfc 100644 --- a/src/bootstrap/mk/Makefile.in +++ b/src/bootstrap/mk/Makefile.in @@ -55,6 +55,7 @@ check: check-aux: $(Q)$(BOOTSTRAP) test \ src/tools/cargotest \ + cargo \ src/test/pretty \ src/test/run-pass/pretty \ src/test/run-fail/pretty \ diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 62eed8be3ccb..3d87f701b2a5 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -19,6 +19,7 @@ //! ensure that they're always in place if needed. use std::env; +use std::ffi::OsString; use std::fs::{self, File}; use std::io::{Read, Write}; use std::path::Path; @@ -81,7 +82,7 @@ pub fn llvm(build: &Build, target: &str) { // NOTE: remember to also update `config.toml.example` when changing the defaults! let llvm_targets = match build.config.llvm_targets { Some(ref s) => s, - None => "X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend;MSP430;Sparc;NVPTX", + None => "X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend;MSP430;Sparc;NVPTX;Hexagon", }; let assertions = if build.config.llvm_assertions {"ON"} else {"OFF"}; @@ -129,25 +130,59 @@ pub fn llvm(build: &Build, target: &str) { .define("LLVM_TABLEGEN", &host); } - // MSVC handles compiler business itself - if !target.contains("msvc") { - if let Some(ref ccache) = build.config.ccache { - cfg.define("CMAKE_C_COMPILER", ccache) - .define("CMAKE_C_COMPILER_ARG1", build.cc(target)) - .define("CMAKE_CXX_COMPILER", ccache) - .define("CMAKE_CXX_COMPILER_ARG1", build.cxx(target)); + let sanitize_cc = |cc: &Path| { + if target.contains("msvc") { + OsString::from(cc.to_str().unwrap().replace("\\", "/")) } else { - cfg.define("CMAKE_C_COMPILER", build.cc(target)) - .define("CMAKE_CXX_COMPILER", build.cxx(target)); + cc.as_os_str().to_owned() } - cfg.build_arg("-j").build_arg(build.jobs().to_string()); + }; + let configure_compilers = |cfg: &mut cmake::Config| { + // MSVC with CMake uses msbuild by default which doesn't respect these + // vars that we'd otherwise configure. In that case we just skip this + // entirely. + if target.contains("msvc") && !build.config.ninja { + return + } + + let cc = build.cc(target); + let cxx = build.cxx(target); + + // Handle msvc + ninja + ccache specially (this is what the bots use) + if target.contains("msvc") && + build.config.ninja && + build.config.ccache.is_some() { + let mut cc = env::current_exe().expect("failed to get cwd"); + cc.set_file_name("sccache-plus-cl.exe"); + + cfg.define("CMAKE_C_COMPILER", sanitize_cc(&cc)) + .define("CMAKE_CXX_COMPILER", sanitize_cc(&cc)); + cfg.env("SCCACHE_PATH", + build.config.ccache.as_ref().unwrap()) + .env("SCCACHE_TARGET", target); + + // If ccache is configured we inform the build a little differently hwo + // to invoke ccache while also invoking our compilers. + } else if let Some(ref ccache) = build.config.ccache { + cfg.define("CMAKE_C_COMPILER", ccache) + .define("CMAKE_C_COMPILER_ARG1", sanitize_cc(cc)) + .define("CMAKE_CXX_COMPILER", ccache) + .define("CMAKE_CXX_COMPILER_ARG1", sanitize_cc(cxx)); + } else { + cfg.define("CMAKE_C_COMPILER", sanitize_cc(cc)) + .define("CMAKE_CXX_COMPILER", sanitize_cc(cxx)); + } + + cfg.build_arg("-j").build_arg(build.jobs().to_string()); cfg.define("CMAKE_C_FLAGS", build.cflags(target).join(" ")); cfg.define("CMAKE_CXX_FLAGS", build.cflags(target).join(" ")); - } + }; + + configure_compilers(&mut cfg); if env::var_os("SCCACHE_ERROR_LOG").is_some() { - cfg.env("RUST_LOG", "sccache=debug"); + cfg.env("RUST_LOG", "sccache=info"); } // FIXME: we don't actually need to build all LLVM tools and all LLVM @@ -306,7 +341,7 @@ pub fn openssl(build: &Build, target: &str) { println!("Configuring openssl for {}", target); build.run_quiet(&mut configure); println!("Building openssl for {}", target); - build.run_quiet(Command::new("make").current_dir(&obj)); + build.run_quiet(Command::new("make").arg("-j1").current_dir(&obj)); println!("Installing openssl for {}", target); build.run_quiet(Command::new("make").arg("install").current_dir(&obj)); diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index 235ce9360eff..df6378a970bd 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -65,26 +65,25 @@ pub fn check(build: &mut Build) { // If we've got a git directory we're gona need git to update // submodules and learn about various other aspects. - if fs::metadata(build.src.join(".git")).is_ok() { + if build.src_is_git { need_cmd("git".as_ref()); } - // We need cmake, but only if we're actually building LLVM - for host in build.config.host.iter() { - if let Some(config) = build.config.target_config.get(host) { - if config.llvm_config.is_some() { - continue - } - } + // We need cmake, but only if we're actually building LLVM or sanitizers. + let building_llvm = build.config.host.iter() + .filter_map(|host| build.config.target_config.get(host)) + .any(|config| config.llvm_config.is_none()); + if building_llvm || build.config.sanitizers { need_cmd("cmake".as_ref()); - if build.config.ninja { - // Some Linux distros rename `ninja` to `ninja-build`. - // CMake can work with either binary name. - if have_cmd("ninja-build".as_ref()).is_none() { - need_cmd("ninja".as_ref()); - } + } + + // Ninja is currently only used for LLVM itself. + if building_llvm && build.config.ninja { + // Some Linux distros rename `ninja` to `ninja-build`. + // CMake can work with either binary name. + if have_cmd("ninja-build".as_ref()).is_none() { + need_cmd("ninja".as_ref()); } - break } if build.config.python.is_none() { diff --git a/src/bootstrap/step.rs b/src/bootstrap/step.rs index 6eb12fed5abb..970c0bc565d8 100644 --- a/src/bootstrap/step.rs +++ b/src/bootstrap/step.rs @@ -26,7 +26,7 @@ //! along with the actual implementation elsewhere. You can find more comments //! about how to define rules themselves below. -use std::collections::{BTreeMap, HashSet}; +use std::collections::{BTreeMap, HashSet, HashMap}; use std::mem; use check::{self, TestKind}; @@ -137,7 +137,9 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { while let Some(krate) = list.pop() { let default = krate == name; let krate = &build.crates[krate]; - let path = krate.path.strip_prefix(&build.src).unwrap(); + let path = krate.path.strip_prefix(&build.src) + // This handles out of tree paths + .unwrap_or(&krate.path); ret.push((krate, path.to_str().unwrap(), default)); for dep in krate.deps.iter() { if visited.insert(dep) && dep != "build_helper" { @@ -305,7 +307,7 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { .dep(|s| s.name("libtest")) .dep(|s| s.name("tool-compiletest").target(s.host).stage(0)) .dep(|s| s.name("test-helpers")) - .dep(|s| s.name("emulator-copy-libs")) + .dep(|s| s.name("remote-copy-libs")) .default(mode != "pretty") // pretty tests don't run everywhere .run(move |s| { check::compiletest(build, &s.compiler(), s.target, mode, dir) @@ -344,7 +346,7 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { .dep(|s| s.name("tool-compiletest").target(s.host).stage(0)) .dep(|s| s.name("test-helpers")) .dep(|s| s.name("debugger-scripts")) - .dep(|s| s.name("emulator-copy-libs")) + .dep(|s| s.name("remote-copy-libs")) .run(move |s| check::compiletest(build, &s.compiler(), s.target, "debuginfo-gdb", "debuginfo")); let mut rule = rules.test("check-debuginfo", "src/test/debuginfo"); @@ -398,14 +400,14 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { for (krate, path, _default) in krates("std") { rules.test(&krate.test_step, path) .dep(|s| s.name("libtest")) - .dep(|s| s.name("emulator-copy-libs")) + .dep(|s| s.name("remote-copy-libs")) .run(move |s| check::krate(build, &s.compiler(), s.target, Mode::Libstd, TestKind::Test, Some(&krate.name))); } rules.test("check-std-all", "path/to/nowhere") .dep(|s| s.name("libtest")) - .dep(|s| s.name("emulator-copy-libs")) + .dep(|s| s.name("remote-copy-libs")) .default(true) .run(move |s| check::krate(build, &s.compiler(), s.target, Mode::Libstd, TestKind::Test, None)); @@ -414,14 +416,14 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { for (krate, path, _default) in krates("std") { rules.bench(&krate.bench_step, path) .dep(|s| s.name("libtest")) - .dep(|s| s.name("emulator-copy-libs")) + .dep(|s| s.name("remote-copy-libs")) .run(move |s| check::krate(build, &s.compiler(), s.target, Mode::Libstd, TestKind::Bench, Some(&krate.name))); } rules.bench("bench-std-all", "path/to/nowhere") .dep(|s| s.name("libtest")) - .dep(|s| s.name("emulator-copy-libs")) + .dep(|s| s.name("remote-copy-libs")) .default(true) .run(move |s| check::krate(build, &s.compiler(), s.target, Mode::Libstd, TestKind::Bench, None)); @@ -429,21 +431,21 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { for (krate, path, _default) in krates("test") { rules.test(&krate.test_step, path) .dep(|s| s.name("libtest")) - .dep(|s| s.name("emulator-copy-libs")) + .dep(|s| s.name("remote-copy-libs")) .run(move |s| check::krate(build, &s.compiler(), s.target, Mode::Libtest, TestKind::Test, Some(&krate.name))); } rules.test("check-test-all", "path/to/nowhere") .dep(|s| s.name("libtest")) - .dep(|s| s.name("emulator-copy-libs")) + .dep(|s| s.name("remote-copy-libs")) .default(true) .run(move |s| check::krate(build, &s.compiler(), s.target, Mode::Libtest, TestKind::Test, None)); for (krate, path, _default) in krates("rustc-main") { rules.test(&krate.test_step, path) .dep(|s| s.name("librustc")) - .dep(|s| s.name("emulator-copy-libs")) + .dep(|s| s.name("remote-copy-libs")) .host(true) .run(move |s| check::krate(build, &s.compiler(), s.target, Mode::Librustc, TestKind::Test, @@ -451,7 +453,7 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { } rules.test("check-rustc-all", "path/to/nowhere") .dep(|s| s.name("librustc")) - .dep(|s| s.name("emulator-copy-libs")) + .dep(|s| s.name("remote-copy-libs")) .default(true) .host(true) .run(move |s| check::krate(build, &s.compiler(), s.target, @@ -468,6 +470,10 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { .dep(|s| s.name("librustc")) .host(true) .run(move |s| check::cargotest(build, s.stage, s.target)); + rules.test("check-cargo", "cargo") + .dep(|s| s.name("tool-cargo")) + .host(true) + .run(move |s| check::cargo(build, s.stage, s.target)); rules.test("check-tidy", "src/tools/tidy") .dep(|s| s.name("tool-tidy").stage(0)) .default(true) @@ -494,33 +500,33 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { rules.build("openssl", "path/to/nowhere") .run(move |s| native::openssl(build, s.target)); - // Some test suites are run inside emulators, and most of our test binaries - // are linked dynamically which means we need to ship the standard library - // and such to the emulator ahead of time. This step represents this and is - // a dependency of all test suites. + // Some test suites are run inside emulators or on remote devices, and most + // of our test binaries are linked dynamically which means we need to ship + // 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 step is a noop (the `check::emulator_copy_libs` // only does work if necessary). 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 QEMU client is built for the - // build target (us) and the server is built for the target. - rules.test("emulator-copy-libs", "path/to/nowhere") + // 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. + rules.test("remote-copy-libs", "path/to/nowhere") .dep(|s| s.name("libtest")) .dep(move |s| { - if build.qemu_rootfs(s.target).is_some() { - s.name("tool-qemu-test-client").target(s.host).stage(0) + if build.remote_tested(s.target) { + s.name("tool-remote-test-client").target(s.host).stage(0) } else { Step::noop() } }) .dep(move |s| { - if build.qemu_rootfs(s.target).is_some() { - s.name("tool-qemu-test-server") + if build.remote_tested(s.target) { + s.name("tool-remote-test-server") } else { Step::noop() } }) - .run(move |s| check::emulator_copy_libs(build, &s.compiler(), s.target)); + .run(move |s| check::remote_copy_libs(build, &s.compiler(), s.target)); rules.test("check-bootstrap", "src/bootstrap") .default(true) @@ -533,34 +539,46 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { // // Tools used during the build system but not shipped rules.build("tool-rustbook", "src/tools/rustbook") - .dep(|s| s.name("librustc")) + .dep(|s| s.name("maybe-clean-tools")) + .dep(|s| s.name("librustc-tool")) .run(move |s| compile::tool(build, s.stage, s.target, "rustbook")); rules.build("tool-error-index", "src/tools/error_index_generator") - .dep(|s| s.name("librustc")) + .dep(|s| s.name("maybe-clean-tools")) + .dep(|s| s.name("librustc-tool")) .run(move |s| compile::tool(build, s.stage, s.target, "error_index_generator")); rules.build("tool-tidy", "src/tools/tidy") - .dep(|s| s.name("libstd")) + .dep(|s| s.name("maybe-clean-tools")) + .dep(|s| s.name("libstd-tool")) .run(move |s| compile::tool(build, s.stage, s.target, "tidy")); rules.build("tool-linkchecker", "src/tools/linkchecker") - .dep(|s| s.name("libstd")) + .dep(|s| s.name("maybe-clean-tools")) + .dep(|s| s.name("libstd-tool")) .run(move |s| compile::tool(build, s.stage, s.target, "linkchecker")); rules.build("tool-cargotest", "src/tools/cargotest") - .dep(|s| s.name("libstd")) + .dep(|s| s.name("maybe-clean-tools")) + .dep(|s| s.name("libstd-tool")) .run(move |s| compile::tool(build, s.stage, s.target, "cargotest")); rules.build("tool-compiletest", "src/tools/compiletest") - .dep(|s| s.name("libtest")) + .dep(|s| s.name("maybe-clean-tools")) + .dep(|s| s.name("libtest-tool")) .run(move |s| compile::tool(build, s.stage, s.target, "compiletest")); rules.build("tool-build-manifest", "src/tools/build-manifest") - .dep(|s| s.name("libstd")) + .dep(|s| s.name("maybe-clean-tools")) + .dep(|s| s.name("libstd-tool")) .run(move |s| compile::tool(build, s.stage, s.target, "build-manifest")); - rules.build("tool-qemu-test-server", "src/tools/qemu-test-server") - .dep(|s| s.name("libstd")) - .run(move |s| compile::tool(build, s.stage, s.target, "qemu-test-server")); - rules.build("tool-qemu-test-client", "src/tools/qemu-test-client") - .dep(|s| s.name("libstd")) - .run(move |s| compile::tool(build, s.stage, s.target, "qemu-test-client")); - rules.build("tool-cargo", "cargo") - .dep(|s| s.name("libstd")) + rules.build("tool-remote-test-server", "src/tools/remote-test-server") + .dep(|s| s.name("maybe-clean-tools")) + .dep(|s| s.name("libstd-tool")) + .run(move |s| compile::tool(build, s.stage, s.target, "remote-test-server")); + rules.build("tool-remote-test-client", "src/tools/remote-test-client") + .dep(|s| s.name("maybe-clean-tools")) + .dep(|s| s.name("libstd-tool")) + .run(move |s| compile::tool(build, s.stage, s.target, "remote-test-client")); + rules.build("tool-cargo", "src/tools/cargo") + .host(true) + .default(build.config.extended) + .dep(|s| s.name("maybe-clean-tools")) + .dep(|s| s.name("libstd-tool")) .dep(|s| s.stage(0).host(s.target).name("openssl")) .dep(move |s| { // Cargo depends on procedural macros, which requires a full host @@ -570,6 +588,37 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { .host(&build.config.build) }) .run(move |s| compile::tool(build, s.stage, s.target, "cargo")); + rules.build("tool-rls", "src/tools/rls") + .host(true) + .default(build.config.extended) + .dep(|s| s.name("librustc-tool")) + .dep(|s| s.stage(0).host(s.target).name("openssl")) + .dep(move |s| { + // rls, like cargo, uses procedural macros + s.name("librustc-link") + .target(&build.config.build) + .host(&build.config.build) + }) + .run(move |s| compile::tool(build, s.stage, s.target, "rls")); + + // "pseudo rule" which represents completely cleaning out the tools dir in + // one stage. This needs to happen whenever a dependency changes (e.g. + // libstd, libtest, librustc) and all of the tool compilations above will + // be sequenced after this rule. + rules.build("maybe-clean-tools", "path/to/nowhere") + .after("librustc-tool") + .after("libtest-tool") + .after("libstd-tool"); + + rules.build("librustc-tool", "path/to/nowhere") + .dep(|s| s.name("librustc")) + .run(move |s| compile::maybe_clean_tools(build, s.stage, s.target, Mode::Librustc)); + rules.build("libtest-tool", "path/to/nowhere") + .dep(|s| s.name("libtest")) + .run(move |s| compile::maybe_clean_tools(build, s.stage, s.target, Mode::Libtest)); + rules.build("libstd-tool", "path/to/nowhere") + .dep(|s| s.name("libstd")) + .run(move |s| compile::maybe_clean_tools(build, s.stage, s.target, Mode::Libstd)); // ======================================================================== // Documentation targets @@ -690,10 +739,15 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { .dep(|s| s.name("default:doc")) .run(move |s| dist::docs(build, s.stage, s.target)); rules.dist("dist-analysis", "analysis") + .default(build.config.extended) .dep(|s| s.name("dist-std")) - .default(true) .only_host_build(true) .run(move |s| dist::analysis(build, &s.compiler(), s.target)); + rules.dist("dist-rls", "rls") + .host(true) + .only_host_build(true) + .dep(|s| s.name("tool-rls")) + .run(move |s| dist::rls(build, s.stage, s.target)); rules.dist("install", "path/to/nowhere") .dep(|s| s.name("default:dist")) .run(move |s| install::install(build, s.stage, s.target)); @@ -711,6 +765,8 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { .dep(|d| d.name("dist-mingw")) .dep(|d| d.name("dist-docs")) .dep(|d| d.name("dist-cargo")) + .dep(|d| d.name("dist-rls")) + .dep(|d| d.name("dist-analysis")) .run(move |s| dist::extended(build, s.stage, s.target)); rules.dist("dist-sign", "hash-and-sign") @@ -811,6 +867,11 @@ struct Rule<'a> { /// Whether this rule is only for the build triple, not anything in hosts or /// targets. only_build: bool, + + /// A list of "order only" dependencies. This rules does not actually + /// depend on these rules, but if they show up in the dependency graph then + /// this rule must be executed after all these rules. + after: Vec<&'a str>, } #[derive(PartialEq)] @@ -834,6 +895,7 @@ impl<'a> Rule<'a> { host: false, only_host_build: false, only_build: false, + after: Vec::new(), } } } @@ -853,6 +915,11 @@ impl<'a, 'b> RuleBuilder<'a, 'b> { self } + fn after(&mut self, step: &'a str) -> &mut Self { + self.rule.after.push(step); + self + } + fn run(&mut self, f: F) -> &mut Self where F: Fn(&Step<'a>) + 'a, { @@ -978,26 +1045,25 @@ invalid rule dependency graph detected, was a rule added and maybe typo'd? } } - pub fn print_help(&self, command: &str) { + pub fn get_help(&self, command: &str) -> Option { let kind = match command { "build" => Kind::Build, "doc" => Kind::Doc, "test" => Kind::Test, "bench" => Kind::Bench, "dist" => Kind::Dist, - _ => return, + _ => return None, }; let rules = self.rules.values().filter(|r| r.kind == kind); let rules = rules.filter(|r| !r.path.contains("nowhere")); let mut rules = rules.collect::>(); rules.sort_by_key(|r| r.path); - println!("Available paths:\n"); + let mut help_string = String::from("Available paths:\n"); for rule in rules { - print!(" ./x.py {} {}", command, rule.path); - - println!(""); + help_string.push_str(format!(" ./x.py {} {}\n", command, rule.path).as_str()); } + Some(help_string) } /// Construct the top-level build steps that we're going to be executing, @@ -1137,31 +1203,52 @@ invalid rule dependency graph detected, was a rule added and maybe typo'd? /// From the top level targets `steps` generate a topological ordering of /// all steps needed to run those steps. fn expand(&self, steps: &[Step<'a>]) -> Vec> { + // First up build a graph of steps and their dependencies. The `nodes` + // map is a map from step to a unique number. The `edges` map is a + // map from these unique numbers to a list of other numbers, + // representing dependencies. + let mut nodes = HashMap::new(); + nodes.insert(Step::noop(), 0); + let mut edges = HashMap::new(); + edges.insert(0, HashSet::new()); + for step in steps { + self.build_graph(step.clone(), &mut nodes, &mut edges); + } + + // Now that we've built up the actual dependency graph, draw more + // dependency edges to satisfy the `after` dependencies field for each + // rule. + self.satisfy_after_deps(&nodes, &mut edges); + + // And finally, perform a topological sort to return a list of steps to + // execute. let mut order = Vec::new(); - let mut added = HashSet::new(); - added.insert(Step::noop()); - for step in steps.iter().cloned() { - self.fill(step, &mut order, &mut added); + let mut visited = HashSet::new(); + visited.insert(0); + let idx_to_node = nodes.iter().map(|p| (*p.1, p.0)).collect::>(); + for idx in 0..nodes.len() { + self.topo_sort(idx, &idx_to_node, &edges, &mut visited, &mut order); } return order } - /// Performs topological sort of dependencies rooted at the `step` - /// specified, pushing all results onto the `order` vector provided. + /// Builds the dependency graph rooted at `step`. /// - /// In other words, when this method returns, the `order` vector will - /// contain a list of steps which if executed in order will eventually - /// complete the `step` specified as well. - /// - /// The `added` set specified here is the set of steps that are already - /// present in `order` (and hence don't need to be added again). - fn fill(&self, - step: Step<'a>, - order: &mut Vec>, - added: &mut HashSet>) { - if !added.insert(step.clone()) { - return + /// The `nodes` and `edges` maps are filled out according to the rule + /// described by `step.name`. + fn build_graph(&self, + step: Step<'a>, + nodes: &mut HashMap, usize>, + edges: &mut HashMap>) -> usize { + use std::collections::hash_map::Entry; + + let idx = nodes.len(); + match nodes.entry(step.clone()) { + Entry::Vacant(e) => { e.insert(idx); } + Entry::Occupied(e) => return *e.get(), } + + let mut deps = Vec::new(); for dep in self.rules[step.name].deps.iter() { let dep = dep(&step); if dep.name.starts_with("default:") { @@ -1173,13 +1260,61 @@ invalid rule dependency graph detected, was a rule added and maybe typo'd? let host = self.build.config.host.iter().any(|h| h == dep.target); let rules = self.rules.values().filter(|r| r.default); for rule in rules.filter(|r| r.kind == kind && (!r.host || host)) { - self.fill(dep.name(rule.name), order, added); + deps.push(self.build_graph(dep.name(rule.name), nodes, edges)); } } else { - self.fill(dep, order, added); + deps.push(self.build_graph(dep, nodes, edges)); } } - order.push(step); + + edges.entry(idx).or_insert(HashSet::new()).extend(deps); + return idx + } + + /// Given a dependency graph with a finished list of `nodes`, fill out more + /// dependency `edges`. + /// + /// This is the step which satisfies all `after` listed dependencies in + /// `Rule` above. + fn satisfy_after_deps(&self, + nodes: &HashMap, usize>, + edges: &mut HashMap>) { + // Reverse map from the name of a step to the node indices that it + // appears at. + let mut name_to_idx = HashMap::new(); + for (step, &idx) in nodes { + name_to_idx.entry(step.name).or_insert(Vec::new()).push(idx); + } + + for (step, idx) in nodes { + if *step == Step::noop() { + continue + } + for after in self.rules[step.name].after.iter() { + // This is the critical piece of an `after` dependency. If the + // dependency isn't actually in our graph then no edge is drawn, + // only if it's already present do we draw the edges. + if let Some(idxs) = name_to_idx.get(after) { + edges.get_mut(idx).unwrap() + .extend(idxs.iter().cloned()); + } + } + } + } + + fn topo_sort(&self, + cur: usize, + nodes: &HashMap>, + edges: &HashMap>, + visited: &mut HashSet, + order: &mut Vec>) { + if !visited.insert(cur) { + return + } + for dep in edges[&cur].iter() { + self.topo_sort(*dep, nodes, edges, visited, order); + } + order.push(nodes[&cur].clone()); } } diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs index dab20f44bc36..e01c06b10fcd 100644 --- a/src/bootstrap/util.rs +++ b/src/bootstrap/util.rs @@ -139,6 +139,8 @@ pub fn dylib_path_var() -> &'static str { "PATH" } else if cfg!(target_os = "macos") { "DYLD_LIBRARY_PATH" + } else if cfg!(target_os = "haiku") { + "LIBRARY_PATH" } else { "LD_LIBRARY_PATH" } diff --git a/src/build_helper/lib.rs b/src/build_helper/lib.rs index cb58a916fb79..da00b970da97 100644 --- a/src/build_helper/lib.rs +++ b/src/build_helper/lib.rs @@ -198,7 +198,11 @@ pub fn native_lib_boilerplate(src_name: &str, let out_dir = env::var_os("RUSTBUILD_NATIVE_DIR").unwrap_or(env::var_os("OUT_DIR").unwrap()); let out_dir = PathBuf::from(out_dir).join(out_name); t!(create_dir_racy(&out_dir)); - println!("cargo:rustc-link-lib=static={}", link_name); + if link_name.contains('=') { + println!("cargo:rustc-link-lib={}", link_name); + } else { + println!("cargo:rustc-link-lib=static={}", link_name); + } println!("cargo:rustc-link-search=native={}", out_dir.join(search_subdir).display()); let timestamp = out_dir.join("rustbuild.timestamp"); @@ -209,6 +213,21 @@ pub fn native_lib_boilerplate(src_name: &str, } } +pub fn sanitizer_lib_boilerplate(sanitizer_name: &str) -> Result { + let (link_name, search_path) = match &*env::var("TARGET").unwrap() { + "x86_64-unknown-linux-gnu" => ( + format!("clang_rt.{}-x86_64", sanitizer_name), + "build/lib/linux", + ), + "x86_64-apple-darwin" => ( + format!("dylib=clang_rt.{}_osx_dynamic", sanitizer_name), + "build/lib/darwin", + ), + _ => return Err(()), + }; + native_lib_boilerplate("compiler-rt", sanitizer_name, &link_name, search_path) +} + fn dir_up_to_date(src: &Path, threshold: &FileTime) -> bool { t!(fs::read_dir(src)).map(|e| t!(e)).all(|e| { let meta = t!(e.metadata()); diff --git a/src/ci/docker/README.md b/src/ci/docker/README.md index 52f74ba90de6..6f3a7e091e1e 100644 --- a/src/ci/docker/README.md +++ b/src/ci/docker/README.md @@ -152,18 +152,13 @@ For targets: `powerpc-unknown-linux-gnu` - Path and misc options > Patches origin = Bundled, then local - Path and misc options > Local patch directory = /tmp/patches - Target options > Target Architecture = powerpc -- Target options > Emit assembly for CPU = power4 -- (+) -- Target options > Tune for CPU = power6 -- (+) +- Target options > Emit assembly for CPU = powerpc -- pure 32-bit PowerPC - 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 > Core gcc extra config = --with-cpu-32=power4 --with-cpu=default32 -- (+) -- C compiler > gcc extra config = --with-cpu-32=power4 --with-cpu=default32 -- (+) - C compiler > C++ = ENABLE -- to cross compile LLVM -(+) These CPU options match the configuration of the toolchains in RHEL6. - ## `powerpc64-linux-gnu.config` For targets: `powerpc64-unknown-linux-gnu` diff --git a/src/ci/docker/arm-android/Dockerfile b/src/ci/docker/arm-android/Dockerfile index 4c89ce12531b..04ca6d76c557 100644 --- a/src/ci/docker/arm-android/Dockerfile +++ b/src/ci/docker/arm-android/Dockerfile @@ -13,7 +13,7 @@ RUN dpkg --add-architecture i386 && \ cmake \ unzip \ expect \ - openjdk-9-jre \ + openjdk-9-jre-headless \ sudo \ libstdc++6:i386 \ xz-utils \ diff --git a/src/ci/docker/arm-android/start-emulator.sh b/src/ci/docker/arm-android/start-emulator.sh index 24c477d87f1a..4a73637e9ddb 100755 --- a/src/ci/docker/arm-android/start-emulator.sh +++ b/src/ci/docker/arm-android/start-emulator.sh @@ -10,7 +10,9 @@ # except according to those terms. set -ex -ANDROID_EMULATOR_FORCE_32BIT=true \ - nohup nohup emulator @arm-18 -no-window -partition-size 2047 \ - 0<&- &>/dev/null & + +# Setting SHELL to a file instead on a symlink helps android +# emulator identify the system +export SHELL=/bin/bash +nohup nohup emulator @arm-18 -no-window -partition-size 2047 0<&- &>/dev/null & exec "$@" diff --git a/src/ci/docker/armhf-gnu/Dockerfile b/src/ci/docker/armhf-gnu/Dockerfile index a5126cb3c3f2..5dfdf093081c 100644 --- a/src/ci/docker/armhf-gnu/Dockerfile +++ b/src/ci/docker/armhf-gnu/Dockerfile @@ -74,7 +74,7 @@ RUN arm-linux-gnueabihf-gcc addentropy.c -o rootfs/addentropy -static RUN curl -O http://ftp.nl.debian.org/debian/dists/jessie/main/installer-armhf/current/images/device-tree/vexpress-v2p-ca15-tc1.dtb RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-29-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/cross/Dockerfile b/src/ci/docker/cross/Dockerfile index 9e7abb8b36e3..5de00d5b0215 100644 --- a/src/ci/docker/cross/Dockerfile +++ b/src/ci/docker/cross/Dockerfile @@ -22,7 +22,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-29-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ @@ -74,6 +74,7 @@ ENV CC_mipsel_unknown_linux_musl=mipsel-openwrt-linux-gcc \ ENV STAGING_DIR=/tmp ENV RUST_CONFIGURE_ARGS \ + --enable-extended \ --target=$TARGETS \ --musl-root-arm=/usr/local/arm-linux-musleabi \ --musl-root-armhf=/usr/local/arm-linux-musleabihf \ diff --git a/src/ci/docker/dist-armv7-aarch64-linux/Dockerfile b/src/ci/docker/dist-aarch64-linux/Dockerfile similarity index 78% rename from src/ci/docker/dist-armv7-aarch64-linux/Dockerfile rename to src/ci/docker/dist-aarch64-linux/Dockerfile index ed9b4a592918..a694bf84b18c 100644 --- a/src/ci/docker/dist-armv7-aarch64-linux/Dockerfile +++ b/src/ci/docker/dist-aarch64-linux/Dockerfile @@ -56,28 +56,22 @@ RUN mkdir /x-tools && chown rustbuild:rustbuild /x-tools USER rustbuild WORKDIR /tmp -COPY armv7-linux-gnueabihf.config /tmp/ -COPY armv7-linux-gnueabihf.config aarch64-linux-gnu.config build-toolchains.sh /tmp/ +COPY aarch64-linux-gnu.config build-toolchains.sh /tmp/ RUN ./build-toolchains.sh USER root RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-29-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV PATH=$PATH:/x-tools/aarch64-unknown-linux-gnueabi/bin -ENV PATH=$PATH:/x-tools/armv7-unknown-linux-gnueabihf/bin ENV CC_aarch64_unknown_linux_gnu=aarch64-unknown-linux-gnueabi-gcc \ AR_aarch64_unknown_linux_gnu=aarch64-unknown-linux-gnueabi-ar \ - CXX_aarch64_unknown_linux_gnu=aarch64-unknown-linux-gnueabi-g++ \ - CC_armv7_unknown_linux_gnueabihf=armv7-unknown-linux-gnueabihf-gcc \ - AR_armv7_unknown_linux_gnueabihf=armv7-unknown-linux-gnueabihf-ar \ - CXX_armv7_unknown_linux_gnueabihf=armv7-unknown-linux-gnueabihf-g++ + CXX_aarch64_unknown_linux_gnu=aarch64-unknown-linux-gnueabi-g++ -ENV HOSTS=armv7-unknown-linux-gnueabihf -ENV HOSTS=$HOSTS,aarch64-unknown-linux-gnu +ENV HOSTS=aarch64-unknown-linux-gnu ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-armv7-aarch64-linux/aarch64-linux-gnu.config b/src/ci/docker/dist-aarch64-linux/aarch64-linux-gnu.config similarity index 100% rename from src/ci/docker/dist-armv7-aarch64-linux/aarch64-linux-gnu.config rename to src/ci/docker/dist-aarch64-linux/aarch64-linux-gnu.config diff --git a/src/ci/docker/dist-aarch64-linux/build-toolchains.sh b/src/ci/docker/dist-aarch64-linux/build-toolchains.sh new file mode 100755 index 000000000000..94f785c96f81 --- /dev/null +++ b/src/ci/docker/dist-aarch64-linux/build-toolchains.sh @@ -0,0 +1,37 @@ +#!/bin/bash +# Copyright 2017 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +set -ex + +hide_output() { + set +x + on_err=" +echo ERROR: An error was encountered with the build. +cat /tmp/build.log +exit 1 +" + trap "$on_err" ERR + bash -c "while true; do sleep 30; echo \$(date) - building ...; done" & + PING_LOOP_PID=$! + $@ &> /tmp/build.log + rm /tmp/build.log + trap - ERR + kill $PING_LOOP_PID + set -x +} + +mkdir build +cd build +cp ../aarch64-linux-gnu.config .config +ct-ng oldconfig +hide_output ct-ng build +cd .. +rm -rf build diff --git a/src/ci/docker/dist-android/Dockerfile b/src/ci/docker/dist-android/Dockerfile index 2785d2135f86..1dd97fd4e047 100644 --- a/src/ci/docker/dist-android/Dockerfile +++ b/src/ci/docker/dist-android/Dockerfile @@ -32,19 +32,22 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini ENTRYPOINT ["/usr/bin/dumb-init", "--"] RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-29-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV TARGETS=arm-linux-androideabi +ENV TARGETS=$TARGETS,armv7-linux-androideabi ENV TARGETS=$TARGETS,i686-linux-android ENV TARGETS=$TARGETS,aarch64-linux-android -ENV TARGETS=$TARGETS,armv7-linux-androideabi +ENV TARGETS=$TARGETS,x86_64-linux-android ENV RUST_CONFIGURE_ARGS \ --target=$TARGETS \ + --enable-extended \ --arm-linux-androideabi-ndk=/android/ndk-arm-9 \ --armv7-linux-androideabi-ndk=/android/ndk-arm-9 \ --i686-linux-android-ndk=/android/ndk-x86-9 \ - --aarch64-linux-android-ndk=/android/ndk-aarch64 + --aarch64-linux-android-ndk=/android/ndk-arm64-21 \ + --x86_64-linux-android-ndk=/android/ndk-x86_64-21 ENV SCRIPT python2.7 ../x.py dist --target $TARGETS diff --git a/src/ci/docker/dist-android/install-ndk.sh b/src/ci/docker/dist-android/install-ndk.sh index 19c1b94e784c..d3a2d3175454 100644 --- a/src/ci/docker/dist-android/install-ndk.sh +++ b/src/ci/docker/dist-android/install-ndk.sh @@ -25,7 +25,7 @@ bash android-ndk-r11c/build/tools/make-standalone-toolchain.sh \ bash android-ndk-r11c/build/tools/make-standalone-toolchain.sh \ --platform=android-21 \ --toolchain=aarch64-linux-android-4.9 \ - --install-dir=/android/ndk-aarch64 \ + --install-dir=/android/ndk-arm64-21 \ --ndk-dir=/android/android-ndk-r11c \ --arch=arm64 bash android-ndk-r11c/build/tools/make-standalone-toolchain.sh \ @@ -34,5 +34,11 @@ bash android-ndk-r11c/build/tools/make-standalone-toolchain.sh \ --install-dir=/android/ndk-x86-9 \ --ndk-dir=/android/android-ndk-r11c \ --arch=x86 +bash android-ndk-r11c/build/tools/make-standalone-toolchain.sh \ + --platform=android-21 \ + --toolchain=x86_64-4.9 \ + --install-dir=/android/ndk-x86_64-21 \ + --ndk-dir=/android/android-ndk-r11c \ + --arch=x86_64 rm -rf ./android-ndk-r11c-linux-x86_64.zip ./android-ndk-r11c diff --git a/src/ci/docker/dist-arm-linux/Dockerfile b/src/ci/docker/dist-arm-linux/Dockerfile index 6cdb5cfca74b..3ee183115724 100644 --- a/src/ci/docker/dist-arm-linux/Dockerfile +++ b/src/ci/docker/dist-arm-linux/Dockerfile @@ -56,27 +56,22 @@ RUN mkdir /x-tools && chown rustbuild:rustbuild /x-tools USER rustbuild WORKDIR /tmp -COPY arm-linux-gnueabihf.config arm-linux-gnueabi.config build-toolchains.sh /tmp/ +COPY arm-linux-gnueabi.config build-toolchains.sh /tmp/ RUN ./build-toolchains.sh USER root RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-29-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV PATH=$PATH:/x-tools/arm-unknown-linux-gnueabi/bin -ENV PATH=$PATH:/x-tools/arm-unknown-linux-gnueabihf/bin ENV CC_arm_unknown_linux_gnueabi=arm-unknown-linux-gnueabi-gcc \ AR_arm_unknown_linux_gnueabi=arm-unknown-linux-gnueabi-ar \ - CXX_arm_unknown_linux_gnueabi=arm-unknown-linux-gnueabi-g++ \ - CC_arm_unknown_linux_gnueabihf=arm-unknown-linux-gnueabihf-gcc \ - AR_arm_unknown_linux_gnueabihf=arm-unknown-linux-gnueabihf-ar \ - CXX_arm_unknown_linux_gnueabihf=arm-unknown-linux-gnueabihf-g++ + CXX_arm_unknown_linux_gnueabi=arm-unknown-linux-gnueabi-g++ ENV HOSTS=arm-unknown-linux-gnueabi -ENV HOSTS=$HOSTS,arm-unknown-linux-gnueabihf ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-arm-linux/build-toolchains.sh b/src/ci/docker/dist-arm-linux/build-toolchains.sh index ed1406bd7cfa..f78ecf9381a1 100755 --- a/src/ci/docker/dist-arm-linux/build-toolchains.sh +++ b/src/ci/docker/dist-arm-linux/build-toolchains.sh @@ -35,11 +35,3 @@ ct-ng oldconfig hide_output ct-ng build cd .. rm -rf build - -mkdir build -cd build -cp ../arm-linux-gnueabihf.config .config -ct-ng oldconfig -hide_output ct-ng build -cd .. -rm -rf build diff --git a/src/ci/docker/dist-armhf-linux/Dockerfile b/src/ci/docker/dist-armhf-linux/Dockerfile new file mode 100644 index 000000000000..902e2e7e6e14 --- /dev/null +++ b/src/ci/docker/dist-armhf-linux/Dockerfile @@ -0,0 +1,77 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + automake \ + bison \ + bzip2 \ + ca-certificates \ + cmake \ + curl \ + file \ + flex \ + g++ \ + gawk \ + gdb \ + git \ + gperf \ + help2man \ + libncurses-dev \ + libtool-bin \ + make \ + patch \ + python2.7 \ + sudo \ + texinfo \ + wget \ + xz-utils \ + libssl-dev \ + pkg-config + +RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ + dpkg -i dumb-init_*.deb && \ + rm dumb-init_*.deb +ENTRYPOINT ["/usr/bin/dumb-init", "--"] + +# Ubuntu 16.04 (this contianer) ships with make 4, but something in the +# toolchains we build below chokes on that, so go back to make 3 +RUN curl https://ftp.gnu.org/gnu/make/make-3.81.tar.gz | tar xzf - && \ + cd make-3.81 && \ + ./configure --prefix=/usr && \ + make && \ + make install && \ + cd .. && \ + rm -rf make-3.81 + +RUN curl http://crosstool-ng.org/download/crosstool-ng/crosstool-ng-1.22.0.tar.bz2 | \ + tar xjf - && \ + cd crosstool-ng && \ + ./configure --prefix=/usr/local && \ + make -j$(nproc) && \ + make install && \ + cd .. && \ + rm -rf crosstool-ng + +RUN groupadd -r rustbuild && useradd -m -r -g rustbuild rustbuild +RUN mkdir /x-tools && chown rustbuild:rustbuild /x-tools +USER rustbuild +WORKDIR /tmp + +COPY arm-linux-gnueabihf.config build-toolchains.sh /tmp/ +RUN ./build-toolchains.sh + +USER root + +RUN curl -o /usr/local/bin/sccache \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-29-sccache-x86_64-unknown-linux-musl && \ + chmod +x /usr/local/bin/sccache + +ENV PATH=$PATH:/x-tools/arm-unknown-linux-gnueabihf/bin + +ENV CC_arm_unknown_linux_gnueabihf=arm-unknown-linux-gnueabihf-gcc \ + AR_arm_unknown_linux_gnueabihf=arm-unknown-linux-gnueabihf-ar \ + CXX_arm_unknown_linux_gnueabihf=arm-unknown-linux-gnueabihf-g++ + +ENV HOSTS=arm-unknown-linux-gnueabihf + +ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended +ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-arm-linux/arm-linux-gnueabihf.config b/src/ci/docker/dist-armhf-linux/arm-linux-gnueabihf.config similarity index 100% rename from src/ci/docker/dist-arm-linux/arm-linux-gnueabihf.config rename to src/ci/docker/dist-armhf-linux/arm-linux-gnueabihf.config diff --git a/src/ci/docker/dist-armhf-linux/build-toolchains.sh b/src/ci/docker/dist-armhf-linux/build-toolchains.sh new file mode 100755 index 000000000000..df1134d5483c --- /dev/null +++ b/src/ci/docker/dist-armhf-linux/build-toolchains.sh @@ -0,0 +1,37 @@ +#!/bin/bash +# Copyright 2017 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +set -ex + +hide_output() { + set +x + on_err=" +echo ERROR: An error was encountered with the build. +cat /tmp/build.log +exit 1 +" + trap "$on_err" ERR + bash -c "while true; do sleep 30; echo \$(date) - building ...; done" & + PING_LOOP_PID=$! + $@ &> /tmp/build.log + rm /tmp/build.log + trap - ERR + kill $PING_LOOP_PID + set -x +} + +mkdir build +cd build +cp ../arm-linux-gnueabihf.config .config +ct-ng oldconfig +hide_output ct-ng build +cd .. +rm -rf build diff --git a/src/ci/docker/dist-armv7-linux/Dockerfile b/src/ci/docker/dist-armv7-linux/Dockerfile new file mode 100644 index 000000000000..d6a66c2f4a33 --- /dev/null +++ b/src/ci/docker/dist-armv7-linux/Dockerfile @@ -0,0 +1,77 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + automake \ + bison \ + bzip2 \ + ca-certificates \ + cmake \ + curl \ + file \ + flex \ + g++ \ + gawk \ + gdb \ + git \ + gperf \ + help2man \ + libncurses-dev \ + libtool-bin \ + make \ + patch \ + python2.7 \ + sudo \ + texinfo \ + wget \ + xz-utils \ + libssl-dev \ + pkg-config + +RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ + dpkg -i dumb-init_*.deb && \ + rm dumb-init_*.deb +ENTRYPOINT ["/usr/bin/dumb-init", "--"] + +# Ubuntu 16.04 (this contianer) ships with make 4, but something in the +# toolchains we build below chokes on that, so go back to make 3 +RUN curl https://ftp.gnu.org/gnu/make/make-3.81.tar.gz | tar xzf - && \ + cd make-3.81 && \ + ./configure --prefix=/usr && \ + make && \ + make install && \ + cd .. && \ + rm -rf make-3.81 + +RUN curl http://crosstool-ng.org/download/crosstool-ng/crosstool-ng-1.22.0.tar.bz2 | \ + tar xjf - && \ + cd crosstool-ng && \ + ./configure --prefix=/usr/local && \ + make -j$(nproc) && \ + make install && \ + cd .. && \ + rm -rf crosstool-ng + +RUN groupadd -r rustbuild && useradd -m -r -g rustbuild rustbuild +RUN mkdir /x-tools && chown rustbuild:rustbuild /x-tools +USER rustbuild +WORKDIR /tmp + +COPY build-toolchains.sh armv7-linux-gnueabihf.config /tmp/ +RUN ./build-toolchains.sh + +USER root + +RUN curl -o /usr/local/bin/sccache \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-29-sccache-x86_64-unknown-linux-musl && \ + chmod +x /usr/local/bin/sccache + +ENV PATH=$PATH:/x-tools/armv7-unknown-linux-gnueabihf/bin + +ENV CC_armv7_unknown_linux_gnueabihf=armv7-unknown-linux-gnueabihf-gcc \ + AR_armv7_unknown_linux_gnueabihf=armv7-unknown-linux-gnueabihf-ar \ + CXX_armv7_unknown_linux_gnueabihf=armv7-unknown-linux-gnueabihf-g++ + +ENV HOSTS=armv7-unknown-linux-gnueabihf + +ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended +ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-armv7-aarch64-linux/armv7-linux-gnueabihf.config b/src/ci/docker/dist-armv7-linux/armv7-linux-gnueabihf.config similarity index 100% rename from src/ci/docker/dist-armv7-aarch64-linux/armv7-linux-gnueabihf.config rename to src/ci/docker/dist-armv7-linux/armv7-linux-gnueabihf.config diff --git a/src/ci/docker/dist-armv7-aarch64-linux/build-toolchains.sh b/src/ci/docker/dist-armv7-linux/build-toolchains.sh similarity index 88% rename from src/ci/docker/dist-armv7-aarch64-linux/build-toolchains.sh rename to src/ci/docker/dist-armv7-linux/build-toolchains.sh index ebd5ef4cfc49..2d395fee792e 100755 --- a/src/ci/docker/dist-armv7-aarch64-linux/build-toolchains.sh +++ b/src/ci/docker/dist-armv7-linux/build-toolchains.sh @@ -35,11 +35,3 @@ ct-ng oldconfig hide_output ct-ng build cd .. rm -rf build - -mkdir build -cd build -cp ../aarch64-linux-gnu.config .config -ct-ng oldconfig -hide_output ct-ng build -cd .. -rm -rf build diff --git a/src/ci/docker/dist-fuchsia/Dockerfile b/src/ci/docker/dist-fuchsia/Dockerfile index dcb9aa905f14..b079f12f7e5e 100644 --- a/src/ci/docker/dist-fuchsia/Dockerfile +++ b/src/ci/docker/dist-fuchsia/Dockerfile @@ -14,13 +14,14 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils \ swig \ libedit-dev \ - libncurses5-dev + libncurses5-dev \ + patch RUN curl -L https://cmake.org/files/v3.8/cmake-3.8.0-rc1-Linux-x86_64.tar.gz | \ tar xzf - -C /usr/local --strip-components=1 WORKDIR /tmp -COPY shared.sh build-toolchain.sh /tmp/ +COPY shared.sh build-toolchain.sh compiler-rt-dso-handle.patch /tmp/ RUN /tmp/build-toolchain.sh RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ @@ -29,7 +30,7 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini ENTRYPOINT ["/usr/bin/dumb-init", "--"] RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-29-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV \ @@ -43,5 +44,5 @@ ENV \ ENV TARGETS=x86_64-unknown-fuchsia ENV TARGETS=$TARGETS,aarch64-unknown-fuchsia -ENV RUST_CONFIGURE_ARGS --target=$TARGETS +ENV RUST_CONFIGURE_ARGS --target=$TARGETS --enable-extended ENV SCRIPT python2.7 ../x.py dist --target $TARGETS diff --git a/src/ci/docker/dist-fuchsia/build-toolchain.sh b/src/ci/docker/dist-fuchsia/build-toolchain.sh index cad73eee1e01..10b285a54665 100755 --- a/src/ci/docker/dist-fuchsia/build-toolchain.sh +++ b/src/ci/docker/dist-fuchsia/build-toolchain.sh @@ -9,26 +9,31 @@ # option. This file may not be copied, modified, or distributed # except according to those terms. +# ignore-tidy-linelength + set -ex source shared.sh # Download sources SRCS=( - "https://fuchsia.googlesource.com/magenta magenta ac69119" - "https://fuchsia.googlesource.com/third_party/llvm llvm 5463083" - "https://fuchsia.googlesource.com/third_party/clang llvm/tools/clang 4ff7b4b" - "https://fuchsia.googlesource.com/third_party/lld llvm/tools/lld fd465a3" - "https://fuchsia.googlesource.com/third_party/lldb llvm/tools/lldb 6bb11f8" - "https://fuchsia.googlesource.com/third_party/compiler-rt llvm/runtimes/compiler-rt 52d4ecc" - "https://fuchsia.googlesource.com/third_party/libcxx llvm/runtimes/libcxx e891cc8" - "https://fuchsia.googlesource.com/third_party/libcxxabi llvm/runtimes/libcxxabi f0f0257" - "https://fuchsia.googlesource.com/third_party/libunwind llvm/runtimes/libunwind 50bddc1" + "https://fuchsia.googlesource.com/magenta magenta d17073dc8de344ead3b65e8cc6a12280dec38c84" + "https://llvm.googlesource.com/llvm llvm 3f58a16d8eec385e2b3ebdfbb84ff9d3bf27e025" + "https://llvm.googlesource.com/clang llvm/tools/clang 727ea63e6e82677f6e10e05e08bc7d6bdbae3111" + "https://llvm.googlesource.com/lld llvm/tools/lld a31286c1366e5e89b8872803fded13805a1a084b" + "https://llvm.googlesource.com/lldb llvm/tools/lldb 0b2384abec4cb99ad66687712e07dee4dd9d187e" + "https://llvm.googlesource.com/compiler-rt llvm/runtimes/compiler-rt 9093a35c599fe41278606a20b51095ea8bd5a081" + "https://llvm.googlesource.com/libcxx llvm/runtimes/libcxx 607e0c71ec4f7fd377ad3f6c47b08dbe89f66eaa" + "https://llvm.googlesource.com/libcxxabi llvm/runtimes/libcxxabi 0a3a1a8a5ca5ef69e0f6b7d5b9d13e63e6fd2c19" + "https://llvm.googlesource.com/libunwind llvm/runtimes/libunwind e128003563d99d9ee62247c4cee40f07d21c03e3" ) fetch() { mkdir -p $2 pushd $2 > /dev/null - curl -sL $1/+archive/$3.tar.gz | tar xzf - + git init + git remote add origin $1 + git fetch --depth=1 origin $3 + git reset --hard FETCH_HEAD popd > /dev/null } @@ -36,6 +41,11 @@ for i in "${SRCS[@]}"; do fetch $i done +# Remove this once https://reviews.llvm.org/D28791 is resolved +cd llvm/runtimes/compiler-rt +patch -Np1 < /tmp/compiler-rt-dso-handle.patch +cd ../../.. + # Build toolchain cd llvm mkdir build diff --git a/src/ci/docker/dist-fuchsia/compiler-rt-dso-handle.patch b/src/ci/docker/dist-fuchsia/compiler-rt-dso-handle.patch new file mode 100644 index 000000000000..0b702894bb21 --- /dev/null +++ b/src/ci/docker/dist-fuchsia/compiler-rt-dso-handle.patch @@ -0,0 +1,41 @@ +diff --git a/lib/builtins/CMakeLists.txt b/lib/builtins/CMakeLists.txt +index fc4384af2..b442264c0 100644 +--- a/lib/builtins/CMakeLists.txt ++++ b/lib/builtins/CMakeLists.txt +@@ -194,6 +194,12 @@ if(APPLE) + atomic_thread_fence.c) + endif() + ++if(FUCHSIA) ++ set(GENERIC_SOURCES ++ ${GENERIC_SOURCES} ++ dso_handle.c) ++endif() ++ + if(NOT WIN32 OR MINGW) + set(GENERIC_SOURCES + ${GENERIC_SOURCES} +diff --git a/lib/builtins/dso_handle.c b/lib/builtins/dso_handle.c +new file mode 100644 +index 000000000..7766cd0aa +--- /dev/null ++++ b/lib/builtins/dso_handle.c +@@ -0,0 +1,18 @@ ++/* ===-- dso_handle.c - Provide __dso_handle -------------------------------=== ++ * ++ * The LLVM Compiler Infrastructure ++ * ++ * This file is dual licensed under the MIT and the University of Illinois Open ++ * Source Licenses. See LICENSE.TXT for details. ++ * ++ * ===----------------------------------------------------------------------=== ++ */ ++ ++/* __dso_handle symbol is mandated by C++ ABI with a value which is an address ++ * in one of the object's segments, and as such this symbol has to be included ++ * statically and cannot be a part of a shared library. Traditionally, it has ++ * been defined in crtbegin.o but there's no principled reason for it to be ++ * there. We defined this symbol in the builtin library which is built as a ++ * static library and always included in the final link. ++ */ ++__attribute__((visibility("hidden"))) void *const __dso_handle; diff --git a/src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile b/src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile index 205139698858..6ea7db03cd51 100644 --- a/src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile +++ b/src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile @@ -26,12 +26,13 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini ENTRYPOINT ["/usr/bin/dumb-init", "--"] RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-29-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV RUST_CONFIGURE_ARGS \ --target=i686-unknown-linux-musl,i586-unknown-linux-gnu \ - --musl-root-i686=/musl-i686 + --musl-root-i686=/musl-i686 \ + --enable-extended # Newer binutils broke things on some vms/distros (i.e., linking against # unknown relocs disabled by the following flag), so we need to go out of our diff --git a/src/ci/docker/dist-i586-gnu-i686-musl/build-musl.sh b/src/ci/docker/dist-i586-gnu-i686-musl/build-musl.sh index a50a25c79134..ad285a57a84a 100644 --- a/src/ci/docker/dist-i586-gnu-i686-musl/build-musl.sh +++ b/src/ci/docker/dist-i586-gnu-i686-musl/build-musl.sh @@ -15,11 +15,14 @@ set -ex export CFLAGS="-fPIC -Wa,-mrelax-relocations=no" export CXXFLAGS="-Wa,-mrelax-relocations=no" -MUSL=musl-1.1.14 +MUSL=musl-1.1.16 curl https://www.musl-libc.org/releases/$MUSL.tar.gz | tar xzf - cd $MUSL -CFLAGS="$CFLAGS -m32" ./configure --prefix=/musl-i686 --disable-shared --target=i686 -make -j10 +CC=gcc \ + CFLAGS="$CFLAGS -m32" \ + ./configure --prefix=/musl-i686 --disable-shared \ + --target=i686 +make AR=ar RANLIB=ranlib -j10 make install cd .. diff --git a/src/ci/docker/dist-freebsd/Dockerfile b/src/ci/docker/dist-i686-freebsd/Dockerfile similarity index 73% rename from src/ci/docker/dist-freebsd/Dockerfile rename to src/ci/docker/dist-i686-freebsd/Dockerfile index 332a1fa73a4d..b9e5f91b373a 100644 --- a/src/ci/docker/dist-freebsd/Dockerfile +++ b/src/ci/docker/dist-i686-freebsd/Dockerfile @@ -17,7 +17,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config COPY build-toolchain.sh /tmp/ -RUN /tmp/build-toolchain.sh x86_64 RUN /tmp/build-toolchain.sh i686 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ @@ -26,19 +25,15 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini ENTRYPOINT ["/usr/bin/dumb-init", "--"] RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-29-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV \ - AR_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-ar \ - CC_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-gcc \ - CXX_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-g++ \ AR_i686_unknown_freebsd=i686-unknown-freebsd10-ar \ CC_i686_unknown_freebsd=i686-unknown-freebsd10-gcc \ CXX_i686_unknown_freebsd=i686-unknown-freebsd10-g++ -ENV HOSTS=x86_64-unknown-freebsd -ENV HOSTS=$HOSTS,i686-unknown-freebsd +ENV HOSTS=i686-unknown-freebsd ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-freebsd/build-toolchain.sh b/src/ci/docker/dist-i686-freebsd/build-toolchain.sh similarity index 100% rename from src/ci/docker/dist-freebsd/build-toolchain.sh rename to src/ci/docker/dist-i686-freebsd/build-toolchain.sh diff --git a/src/ci/docker/dist-x86-linux/Dockerfile b/src/ci/docker/dist-i686-linux/Dockerfile similarity index 87% rename from src/ci/docker/dist-x86-linux/Dockerfile rename to src/ci/docker/dist-i686-linux/Dockerfile index 100b6dcf9937..a15d6c4e53db 100644 --- a/src/ci/docker/dist-x86-linux/Dockerfile +++ b/src/ci/docker/dist-i686-linux/Dockerfile @@ -2,6 +2,12 @@ FROM centos:5 WORKDIR /build +# Centos 5 is EOL and is no longer available from the usual mirrors, so switch +# to http://vault.centos.org/ +RUN sed -i 's/enabled=1/enabled=0/' /etc/yum/pluginconf.d/fastestmirror.conf +RUN sed -i 's/mirrorlist/#mirrorlist/' /etc/yum.repos.d/*.repo +RUN sed -i 's|#\(baseurl.*\)mirror.centos.org/centos/$releasever|\1vault.centos.org/5.11|' /etc/yum.repos.d/*.repo + RUN yum upgrade -y && yum install -y \ curl \ bzip2 \ @@ -76,11 +82,10 @@ RUN curl -Lo /rustroot/dumb-init \ ENTRYPOINT ["/rustroot/dumb-init", "--"] RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-29-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV HOSTS=i686-unknown-linux-gnu -ENV HOSTS=$HOSTS,x86_64-unknown-linux-gnu ENV RUST_CONFIGURE_ARGS \ --host=$HOSTS \ diff --git a/src/ci/docker/dist-x86-linux/build-binutils.sh b/src/ci/docker/dist-i686-linux/build-binutils.sh similarity index 100% rename from src/ci/docker/dist-x86-linux/build-binutils.sh rename to src/ci/docker/dist-i686-linux/build-binutils.sh diff --git a/src/ci/docker/dist-x86-linux/build-cmake.sh b/src/ci/docker/dist-i686-linux/build-cmake.sh similarity index 100% rename from src/ci/docker/dist-x86-linux/build-cmake.sh rename to src/ci/docker/dist-i686-linux/build-cmake.sh diff --git a/src/ci/docker/dist-x86-linux/build-curl.sh b/src/ci/docker/dist-i686-linux/build-curl.sh similarity index 100% rename from src/ci/docker/dist-x86-linux/build-curl.sh rename to src/ci/docker/dist-i686-linux/build-curl.sh diff --git a/src/ci/docker/dist-x86-linux/build-gcc.sh b/src/ci/docker/dist-i686-linux/build-gcc.sh similarity index 100% rename from src/ci/docker/dist-x86-linux/build-gcc.sh rename to src/ci/docker/dist-i686-linux/build-gcc.sh diff --git a/src/ci/docker/dist-x86-linux/build-git.sh b/src/ci/docker/dist-i686-linux/build-git.sh similarity index 100% rename from src/ci/docker/dist-x86-linux/build-git.sh rename to src/ci/docker/dist-i686-linux/build-git.sh diff --git a/src/ci/docker/dist-x86-linux/build-headers.sh b/src/ci/docker/dist-i686-linux/build-headers.sh similarity index 100% rename from src/ci/docker/dist-x86-linux/build-headers.sh rename to src/ci/docker/dist-i686-linux/build-headers.sh diff --git a/src/ci/docker/dist-x86-linux/build-openssl.sh b/src/ci/docker/dist-i686-linux/build-openssl.sh similarity index 100% rename from src/ci/docker/dist-x86-linux/build-openssl.sh rename to src/ci/docker/dist-i686-linux/build-openssl.sh diff --git a/src/ci/docker/dist-x86-linux/build-python.sh b/src/ci/docker/dist-i686-linux/build-python.sh similarity index 100% rename from src/ci/docker/dist-x86-linux/build-python.sh rename to src/ci/docker/dist-i686-linux/build-python.sh diff --git a/src/ci/docker/dist-x86-linux/shared.sh b/src/ci/docker/dist-i686-linux/shared.sh similarity index 100% rename from src/ci/docker/dist-x86-linux/shared.sh rename to src/ci/docker/dist-i686-linux/shared.sh diff --git a/src/ci/docker/dist-mips-linux/Dockerfile b/src/ci/docker/dist-mips-linux/Dockerfile index 3123e69e7e1d..dbcdf2eb9d6a 100644 --- a/src/ci/docker/dist-mips-linux/Dockerfile +++ b/src/ci/docker/dist-mips-linux/Dockerfile @@ -13,12 +13,11 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ gdb \ xz-utils \ g++-mips-linux-gnu \ - g++-mipsel-linux-gnu \ libssl-dev \ pkg-config RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-29-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ @@ -27,7 +26,6 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini ENTRYPOINT ["/usr/bin/dumb-init", "--"] ENV HOSTS=mips-unknown-linux-gnu -ENV HOSTS=$HOSTS,mipsel-unknown-linux-gnu ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-mips64-linux/Dockerfile b/src/ci/docker/dist-mips64-linux/Dockerfile index 52db932dcdc3..d0e59253a0f3 100644 --- a/src/ci/docker/dist-mips64-linux/Dockerfile +++ b/src/ci/docker/dist-mips64-linux/Dockerfile @@ -13,12 +13,11 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ gdb \ xz-utils \ g++-mips64-linux-gnuabi64 \ - g++-mips64el-linux-gnuabi64 \ libssl-dev \ pkg-config RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-29-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ @@ -27,7 +26,6 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini ENTRYPOINT ["/usr/bin/dumb-init", "--"] ENV HOSTS=mips64-unknown-linux-gnuabi64 -ENV HOSTS=$HOSTS,mips64el-unknown-linux-gnuabi64 ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-mips64el-linux/Dockerfile b/src/ci/docker/dist-mips64el-linux/Dockerfile new file mode 100644 index 000000000000..6645d0cbaad5 --- /dev/null +++ b/src/ci/docker/dist-mips64el-linux/Dockerfile @@ -0,0 +1,31 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++ \ + make \ + file \ + curl \ + ca-certificates \ + python2.7 \ + git \ + cmake \ + sudo \ + gdb \ + xz-utils \ + g++-mips64el-linux-gnuabi64 \ + libssl-dev \ + pkg-config + +RUN curl -o /usr/local/bin/sccache \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-29-sccache-x86_64-unknown-linux-musl && \ + chmod +x /usr/local/bin/sccache + +RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ + dpkg -i dumb-init_*.deb && \ + rm dumb-init_*.deb +ENTRYPOINT ["/usr/bin/dumb-init", "--"] + +ENV HOSTS=mips64el-unknown-linux-gnuabi64 + +ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended +ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-mipsel-linux/Dockerfile b/src/ci/docker/dist-mipsel-linux/Dockerfile new file mode 100644 index 000000000000..dae1972e4968 --- /dev/null +++ b/src/ci/docker/dist-mipsel-linux/Dockerfile @@ -0,0 +1,31 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++ \ + make \ + file \ + curl \ + ca-certificates \ + python2.7 \ + git \ + cmake \ + sudo \ + gdb \ + xz-utils \ + g++-mipsel-linux-gnu \ + libssl-dev \ + pkg-config + +RUN curl -o /usr/local/bin/sccache \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-29-sccache-x86_64-unknown-linux-musl && \ + chmod +x /usr/local/bin/sccache + +RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ + dpkg -i dumb-init_*.deb && \ + rm dumb-init_*.deb +ENTRYPOINT ["/usr/bin/dumb-init", "--"] + +ENV HOSTS=mipsel-unknown-linux-gnu + +ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended +ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-powerpc-linux/Dockerfile b/src/ci/docker/dist-powerpc-linux/Dockerfile index fca931596853..b43bf8beb26e 100644 --- a/src/ci/docker/dist-powerpc-linux/Dockerfile +++ b/src/ci/docker/dist-powerpc-linux/Dockerfile @@ -63,7 +63,7 @@ RUN ./build-powerpc-toolchain.sh USER root RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-29-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV PATH=$PATH:/x-tools/powerpc-unknown-linux-gnu/bin 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 26e2de863a0f..984a0a0304e4 100644 --- a/src/ci/docker/dist-powerpc-linux/powerpc-linux-gnu.config +++ b/src/ci/docker/dist-powerpc-linux/powerpc-linux-gnu.config @@ -101,8 +101,8 @@ CT_ARCH_SUPPORTS_WITH_FLOAT=y CT_ARCH_DEFAULT_BE=y CT_ARCH_DEFAULT_32=y CT_ARCH_ABI="" -CT_ARCH_CPU="power4" -CT_ARCH_TUNE="power6" +CT_ARCH_CPU="powerpc" +CT_ARCH_TUNE="" CT_ARCH_BE=y # CT_ARCH_LE is not set CT_ARCH_32=y @@ -391,8 +391,8 @@ CT_CC_GCC_HAS_LIBSANITIZER=y CT_CC_GCC_VERSION="4.9.3" # CT_CC_LANG_FORTRAN is not set CT_CC_GCC_ENABLE_CXX_FLAGS="" -CT_CC_GCC_CORE_EXTRA_CONFIG_ARRAY="--with-cpu-32=power4 --with-cpu=default32" -CT_CC_GCC_EXTRA_CONFIG_ARRAY="--with-cpu-32=power4 --with-cpu=default32" +CT_CC_GCC_CORE_EXTRA_CONFIG_ARRAY="" +CT_CC_GCC_EXTRA_CONFIG_ARRAY="" CT_CC_GCC_EXTRA_ENV_ARRAY="" CT_CC_GCC_STATIC_LIBSTDCXX=y # CT_CC_GCC_SYSTEM_ZLIB is not set diff --git a/src/ci/docker/dist-powerpc64-linux/Dockerfile b/src/ci/docker/dist-powerpc64-linux/Dockerfile index 17a4734aba7d..540415e7e272 100644 --- a/src/ci/docker/dist-powerpc64-linux/Dockerfile +++ b/src/ci/docker/dist-powerpc64-linux/Dockerfile @@ -62,12 +62,8 @@ RUN ./build-powerpc64-toolchain.sh USER root -RUN apt-get install -y --no-install-recommends rpm2cpio cpio -COPY build-powerpc64le-toolchain.sh /tmp/ -RUN ./build-powerpc64le-toolchain.sh - RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-29-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV PATH=$PATH:/x-tools/powerpc64-unknown-linux-gnu/bin @@ -75,13 +71,9 @@ ENV PATH=$PATH:/x-tools/powerpc64-unknown-linux-gnu/bin ENV \ AR_powerpc64_unknown_linux_gnu=powerpc64-unknown-linux-gnu-ar \ CC_powerpc64_unknown_linux_gnu=powerpc64-unknown-linux-gnu-gcc \ - CXX_powerpc64_unknown_linux_gnu=powerpc64-unknown-linux-gnu-g++ \ - AR_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-ar \ - CC_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-gcc \ - CXX_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-g++ + CXX_powerpc64_unknown_linux_gnu=powerpc64-unknown-linux-gnu-g++ ENV HOSTS=powerpc64-unknown-linux-gnu -ENV HOSTS=$HOSTS,powerpc64le-unknown-linux-gnu ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-powerpc64le-linux/Dockerfile b/src/ci/docker/dist-powerpc64le-linux/Dockerfile new file mode 100644 index 000000000000..08ab0f37b625 --- /dev/null +++ b/src/ci/docker/dist-powerpc64le-linux/Dockerfile @@ -0,0 +1,77 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + automake \ + bison \ + bzip2 \ + ca-certificates \ + cmake \ + curl \ + file \ + flex \ + g++ \ + gawk \ + gdb \ + git \ + gperf \ + help2man \ + libncurses-dev \ + libtool-bin \ + make \ + patch \ + python2.7 \ + sudo \ + texinfo \ + wget \ + xz-utils \ + libssl-dev \ + pkg-config + +RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ + dpkg -i dumb-init_*.deb && \ + rm dumb-init_*.deb +ENTRYPOINT ["/usr/bin/dumb-init", "--"] + +# Ubuntu 16.04 (this contianer) ships with make 4, but something in the +# toolchains we build below chokes on that, so go back to make 3 +RUN curl https://ftp.gnu.org/gnu/make/make-3.81.tar.gz | tar xzf - && \ + cd make-3.81 && \ + ./configure --prefix=/usr && \ + make && \ + make install && \ + cd .. && \ + rm -rf make-3.81 + +RUN curl http://crosstool-ng.org/download/crosstool-ng/crosstool-ng-1.22.0.tar.bz2 | \ + tar xjf - && \ + cd crosstool-ng && \ + ./configure --prefix=/usr/local && \ + make -j$(nproc) && \ + make install && \ + cd .. && \ + rm -rf crosstool-ng + +RUN groupadd -r rustbuild && useradd -m -r -g rustbuild rustbuild +RUN mkdir /x-tools && chown rustbuild:rustbuild /x-tools +USER rustbuild +WORKDIR /tmp + +USER root + +RUN apt-get install -y --no-install-recommends rpm2cpio cpio +COPY shared.sh build-powerpc64le-toolchain.sh /tmp/ +RUN ./build-powerpc64le-toolchain.sh + +RUN curl -o /usr/local/bin/sccache \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-29-sccache-x86_64-unknown-linux-musl && \ + chmod +x /usr/local/bin/sccache + +ENV \ + AR_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-ar \ + CC_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-gcc \ + CXX_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-g++ + +ENV HOSTS=powerpc64le-unknown-linux-gnu + +ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended +ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-powerpc64-linux/build-powerpc64le-toolchain.sh b/src/ci/docker/dist-powerpc64le-linux/build-powerpc64le-toolchain.sh similarity index 100% rename from src/ci/docker/dist-powerpc64-linux/build-powerpc64le-toolchain.sh rename to src/ci/docker/dist-powerpc64le-linux/build-powerpc64le-toolchain.sh diff --git a/src/ci/docker/dist-powerpc64le-linux/shared.sh b/src/ci/docker/dist-powerpc64le-linux/shared.sh new file mode 100644 index 000000000000..97e6d2908cf8 --- /dev/null +++ b/src/ci/docker/dist-powerpc64le-linux/shared.sh @@ -0,0 +1,25 @@ +# Copyright 2017 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +hide_output() { + set +x + on_err=" +echo ERROR: An error was encountered with the build. +cat /tmp/build.log +exit 1 +" + trap "$on_err" ERR + bash -c "while true; do sleep 30; echo \$(date) - building ...; done" & + PING_LOOP_PID=$! + $@ &> /tmp/build.log + trap - ERR + kill $PING_LOOP_PID + set -x +} diff --git a/src/ci/docker/dist-s390x-linux-netbsd/Dockerfile b/src/ci/docker/dist-s390x-linux/Dockerfile similarity index 81% rename from src/ci/docker/dist-s390x-linux-netbsd/Dockerfile rename to src/ci/docker/dist-s390x-linux/Dockerfile index c2877b081d5d..a758559e0c10 100644 --- a/src/ci/docker/dist-s390x-linux-netbsd/Dockerfile +++ b/src/ci/docker/dist-s390x-linux/Dockerfile @@ -60,27 +60,20 @@ COPY patches/ /tmp/patches/ COPY s390x-linux-gnu.config build-s390x-toolchain.sh /tmp/ RUN ./build-s390x-toolchain.sh -COPY build-netbsd-toolchain.sh /tmp/ -RUN ./build-netbsd-toolchain.sh - USER root RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-29-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache -ENV PATH=$PATH:/x-tools/s390x-ibm-linux-gnu/bin:/x-tools/x86_64-unknown-netbsd/bin +ENV PATH=$PATH:/x-tools/s390x-ibm-linux-gnu/bin ENV \ - AR_x86_64_unknown_netbsd=x86_64--netbsd-ar \ - CC_x86_64_unknown_netbsd=x86_64--netbsd-gcc-sysroot \ - CXX_x86_64_unknown_netbsd=x86_64--netbsd-g++-sysroot \ CC_s390x_unknown_linux_gnu=s390x-ibm-linux-gnu-gcc \ AR_s390x_unknown_linux_gnu=s390x-ibm-linux-gnu-ar \ CXX_s390x_unknown_linux_gnu=s390x-ibm-linux-gnu-g++ -ENV HOSTS=x86_64-unknown-netbsd -ENV HOSTS=$HOSTS,s390x-unknown-linux-gnu +ENV HOSTS=s390x-unknown-linux-gnu ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-s390x-linux-netbsd/build-s390x-toolchain.sh b/src/ci/docker/dist-s390x-linux/build-s390x-toolchain.sh similarity index 100% rename from src/ci/docker/dist-s390x-linux-netbsd/build-s390x-toolchain.sh rename to src/ci/docker/dist-s390x-linux/build-s390x-toolchain.sh diff --git a/src/ci/docker/dist-s390x-linux-netbsd/patches/glibc/2.12.2/001-Use-.machine-to-prevent-AS-from-complaining-about-z9.patch b/src/ci/docker/dist-s390x-linux/patches/glibc/2.12.2/001-Use-.machine-to-prevent-AS-from-complaining-about-z9.patch similarity index 100% rename from src/ci/docker/dist-s390x-linux-netbsd/patches/glibc/2.12.2/001-Use-.machine-to-prevent-AS-from-complaining-about-z9.patch rename to src/ci/docker/dist-s390x-linux/patches/glibc/2.12.2/001-Use-.machine-to-prevent-AS-from-complaining-about-z9.patch diff --git a/src/ci/docker/dist-s390x-linux-netbsd/s390x-linux-gnu.config b/src/ci/docker/dist-s390x-linux/s390x-linux-gnu.config similarity index 100% rename from src/ci/docker/dist-s390x-linux-netbsd/s390x-linux-gnu.config rename to src/ci/docker/dist-s390x-linux/s390x-linux-gnu.config diff --git a/src/ci/docker/dist-x86_64-freebsd/Dockerfile b/src/ci/docker/dist-x86_64-freebsd/Dockerfile new file mode 100644 index 000000000000..8c3e86fd9ad7 --- /dev/null +++ b/src/ci/docker/dist-x86_64-freebsd/Dockerfile @@ -0,0 +1,39 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++ \ + make \ + file \ + curl \ + ca-certificates \ + python2.7 \ + git \ + cmake \ + sudo \ + bzip2 \ + xz-utils \ + wget \ + libssl-dev \ + pkg-config + +COPY build-toolchain.sh /tmp/ +RUN /tmp/build-toolchain.sh x86_64 + +RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ + dpkg -i dumb-init_*.deb && \ + rm dumb-init_*.deb +ENTRYPOINT ["/usr/bin/dumb-init", "--"] + +RUN curl -o /usr/local/bin/sccache \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-29-sccache-x86_64-unknown-linux-musl && \ + chmod +x /usr/local/bin/sccache + +ENV \ + AR_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-ar \ + CC_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-gcc \ + CXX_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-g++ + +ENV HOSTS=x86_64-unknown-freebsd + +ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended +ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-x86_64-freebsd/build-toolchain.sh b/src/ci/docker/dist-x86_64-freebsd/build-toolchain.sh new file mode 100755 index 000000000000..5642e6fc937f --- /dev/null +++ b/src/ci/docker/dist-x86_64-freebsd/build-toolchain.sh @@ -0,0 +1,112 @@ +#!/bin/bash +# Copyright 2016 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +set -ex + +ARCH=$1 +BINUTILS=2.25.1 +GCC=5.3.0 + +hide_output() { + set +x + on_err=" +echo ERROR: An error was encountered with the build. +cat /tmp/build.log +exit 1 +" + trap "$on_err" ERR + bash -c "while true; do sleep 30; echo \$(date) - building ...; done" & + PING_LOOP_PID=$! + $@ &> /tmp/build.log + trap - ERR + kill $PING_LOOP_PID + set -x +} + +mkdir binutils +cd binutils + +# First up, build binutils +curl https://ftp.gnu.org/gnu/binutils/binutils-$BINUTILS.tar.bz2 | tar xjf - +mkdir binutils-build +cd binutils-build +hide_output ../binutils-$BINUTILS/configure \ + --target=$ARCH-unknown-freebsd10 +hide_output make -j10 +hide_output make install +cd ../.. +rm -rf binutils + +# Next, download the FreeBSD libc and relevant header files + +mkdir freebsd +case "$ARCH" in + x86_64) + URL=ftp://ftp.freebsd.org/pub/FreeBSD/releases/amd64/10.2-RELEASE/base.txz + ;; + i686) + URL=ftp://ftp.freebsd.org/pub/FreeBSD/releases/i386/10.2-RELEASE/base.txz + ;; +esac +curl $URL | tar xJf - -C freebsd ./usr/include ./usr/lib ./lib + +dst=/usr/local/$ARCH-unknown-freebsd10 + +cp -r freebsd/usr/include $dst/ +cp freebsd/usr/lib/crt1.o $dst/lib +cp freebsd/usr/lib/Scrt1.o $dst/lib +cp freebsd/usr/lib/crti.o $dst/lib +cp freebsd/usr/lib/crtn.o $dst/lib +cp freebsd/usr/lib/libc.a $dst/lib +cp freebsd/usr/lib/libutil.a $dst/lib +cp freebsd/usr/lib/libutil_p.a $dst/lib +cp freebsd/usr/lib/libm.a $dst/lib +cp freebsd/usr/lib/librt.so.1 $dst/lib +cp freebsd/usr/lib/libexecinfo.so.1 $dst/lib +cp freebsd/lib/libc.so.7 $dst/lib +cp freebsd/lib/libm.so.5 $dst/lib +cp freebsd/lib/libutil.so.9 $dst/lib +cp freebsd/lib/libthr.so.3 $dst/lib/libpthread.so + +ln -s libc.so.7 $dst/lib/libc.so +ln -s libm.so.5 $dst/lib/libm.so +ln -s librt.so.1 $dst/lib/librt.so +ln -s libutil.so.9 $dst/lib/libutil.so +ln -s libexecinfo.so.1 $dst/lib/libexecinfo.so +rm -rf freebsd + +# Finally, download and build gcc to target FreeBSD +mkdir gcc +cd gcc +curl https://ftp.gnu.org/gnu/gcc/gcc-$GCC/gcc-$GCC.tar.bz2 | tar xjf - +cd gcc-$GCC +./contrib/download_prerequisites + +mkdir ../gcc-build +cd ../gcc-build +hide_output ../gcc-$GCC/configure \ + --enable-languages=c,c++ \ + --target=$ARCH-unknown-freebsd10 \ + --disable-multilib \ + --disable-nls \ + --disable-libgomp \ + --disable-libquadmath \ + --disable-libssp \ + --disable-libvtv \ + --disable-libcilkrts \ + --disable-libada \ + --disable-libsanitizer \ + --disable-libquadmath-support \ + --disable-lto +hide_output make -j10 +hide_output make install +cd ../.. +rm -rf gcc diff --git a/src/ci/docker/dist-x86_64-linux/Dockerfile b/src/ci/docker/dist-x86_64-linux/Dockerfile new file mode 100644 index 000000000000..d3db8bde0391 --- /dev/null +++ b/src/ci/docker/dist-x86_64-linux/Dockerfile @@ -0,0 +1,101 @@ +FROM centos:5 + +WORKDIR /build + +# Centos 5 is EOL and is no longer available from the usual mirrors, so switch +# to http://vault.centos.org/ +RUN sed -i 's/enabled=1/enabled=0/' /etc/yum/pluginconf.d/fastestmirror.conf +RUN sed -i 's/mirrorlist/#mirrorlist/' /etc/yum.repos.d/*.repo +RUN sed -i 's|#\(baseurl.*\)mirror.centos.org/centos/$releasever|\1vault.centos.org/5.11|' /etc/yum.repos.d/*.repo + +RUN yum upgrade -y && yum install -y \ + curl \ + bzip2 \ + gcc \ + gcc-c++ \ + make \ + glibc-devel \ + perl \ + zlib-devel \ + file \ + xz \ + which \ + pkgconfig \ + wget \ + autoconf \ + gettext + +ENV PATH=/rustroot/bin:$PATH +ENV LD_LIBRARY_PATH=/rustroot/lib64:/rustroot/lib +ENV PKG_CONFIG_PATH=/rustroot/lib/pkgconfig +WORKDIR /tmp +COPY shared.sh build-binutils.sh /tmp/ + +# We need a build of openssl which supports SNI to download artifacts from +# static.rust-lang.org. This'll be used to link into libcurl below (and used +# later as well), so build a copy of OpenSSL with dynamic libraries into our +# generic root. +COPY build-openssl.sh /tmp/ +RUN ./build-openssl.sh + +# The `curl` binary on CentOS doesn't support SNI which is needed for fetching +# some https urls we have, so install a new version of libcurl + curl which is +# using the openssl we just built previously. +# +# Note that we also disable a bunch of optional features of curl that we don't +# really need. +COPY build-curl.sh /tmp/ +RUN ./build-curl.sh + +# binutils < 2.22 has a bug where the 32-bit executables it generates +# immediately segfault in Rust, so we need to install our own binutils. +# +# See https://github.com/rust-lang/rust/issues/20440 for more info +RUN ./build-binutils.sh + +# Need a newer version of gcc than centos has to compile LLVM nowadays +COPY build-gcc.sh /tmp/ +RUN ./build-gcc.sh + +# CentOS 5.5 has Python 2.4 by default, but LLVM needs 2.7+ +COPY build-python.sh /tmp/ +RUN ./build-python.sh + +# Apparently CentOS 5.5 desn't have `git` in yum, but we're gonna need it for +# cloning, so download and build it here. +COPY build-git.sh /tmp/ +RUN ./build-git.sh + +# libssh2 (a dependency of Cargo) requires cmake 2.8.11 or higher but CentOS +# only has 2.6.4, so build our own +COPY build-cmake.sh /tmp/ +RUN ./build-cmake.sh + +# for sanitizers, we need kernel headers files newer than the ones CentOS ships +# with so we install newer ones here +COPY build-headers.sh /tmp/ +RUN ./build-headers.sh + +RUN curl -Lo /rustroot/dumb-init \ + https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64 && \ + chmod +x /rustroot/dumb-init +ENTRYPOINT ["/rustroot/dumb-init", "--"] + +RUN curl -o /usr/local/bin/sccache \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-29-sccache-x86_64-unknown-linux-musl && \ + chmod +x /usr/local/bin/sccache + +ENV HOSTS=x86_64-unknown-linux-gnu + +ENV RUST_CONFIGURE_ARGS \ + --host=$HOSTS \ + --enable-extended \ + --enable-sanitizers +ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS + +# This is the only builder which will create source tarballs +ENV DIST_SRC 1 + +# When we build cargo in this container, we don't want it to use the system +# libcurl, instead it should compile its own. +ENV LIBCURL_NO_PKG_CONFIG 1 diff --git a/src/ci/docker/dist-x86_64-linux/build-binutils.sh b/src/ci/docker/dist-x86_64-linux/build-binutils.sh new file mode 100755 index 000000000000..80aa1f2a0161 --- /dev/null +++ b/src/ci/docker/dist-x86_64-linux/build-binutils.sh @@ -0,0 +1,26 @@ +#!/bin/bash +# Copyright 2017 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +set -ex + +source shared.sh + +curl https://ftp.gnu.org/gnu/binutils/binutils-2.25.1.tar.bz2 | tar xfj - + +mkdir binutils-build +cd binutils-build +hide_output ../binutils-2.25.1/configure --prefix=/rustroot +hide_output make -j10 +hide_output make install + +cd .. +rm -rf binutils-build +rm -rf binutils-2.25.1 diff --git a/src/ci/docker/dist-x86_64-linux/build-cmake.sh b/src/ci/docker/dist-x86_64-linux/build-cmake.sh new file mode 100755 index 000000000000..82e46455cb0f --- /dev/null +++ b/src/ci/docker/dist-x86_64-linux/build-cmake.sh @@ -0,0 +1,25 @@ +#!/bin/bash +# Copyright 2017 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +set -ex +source shared.sh + +curl https://cmake.org/files/v3.6/cmake-3.6.3.tar.gz | tar xzf - + +mkdir cmake-build +cd cmake-build +hide_output ../cmake-3.6.3/configure --prefix=/rustroot +hide_output make -j10 +hide_output make install + +cd .. +rm -rf cmake-build +rm -rf cmake-3.6.3 diff --git a/src/ci/docker/dist-x86_64-linux/build-curl.sh b/src/ci/docker/dist-x86_64-linux/build-curl.sh new file mode 100755 index 000000000000..b7d22755a571 --- /dev/null +++ b/src/ci/docker/dist-x86_64-linux/build-curl.sh @@ -0,0 +1,43 @@ +#!/bin/bash +# Copyright 2017 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +set -ex +source shared.sh + +VERSION=7.51.0 + +curl http://cool.haxx.se/download/curl-$VERSION.tar.bz2 | tar xjf - + +mkdir curl-build +cd curl-build +hide_output ../curl-$VERSION/configure \ + --prefix=/rustroot \ + --with-ssl=/rustroot \ + --disable-sspi \ + --disable-gopher \ + --disable-smtp \ + --disable-smb \ + --disable-imap \ + --disable-pop3 \ + --disable-tftp \ + --disable-telnet \ + --disable-manual \ + --disable-dict \ + --disable-rtsp \ + --disable-ldaps \ + --disable-ldap +hide_output make -j10 +hide_output make install + +cd .. +rm -rf curl-build +rm -rf curl-$VERSION +yum erase -y curl diff --git a/src/ci/docker/dist-x86_64-linux/build-gcc.sh b/src/ci/docker/dist-x86_64-linux/build-gcc.sh new file mode 100755 index 000000000000..ab2562538d6d --- /dev/null +++ b/src/ci/docker/dist-x86_64-linux/build-gcc.sh @@ -0,0 +1,33 @@ +#!/bin/bash +# Copyright 2017 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +set -ex + +source shared.sh + +GCC=4.8.5 + +curl https://ftp.gnu.org/gnu/gcc/gcc-$GCC/gcc-$GCC.tar.bz2 | tar xjf - +cd gcc-$GCC +./contrib/download_prerequisites +mkdir ../gcc-build +cd ../gcc-build +hide_output ../gcc-$GCC/configure \ + --prefix=/rustroot \ + --enable-languages=c,c++ +hide_output make -j10 +hide_output make install +ln -nsf gcc /rustroot/bin/cc + +cd .. +rm -rf gcc-build +rm -rf gcc-$GCC +yum erase -y gcc gcc-c++ binutils diff --git a/src/ci/docker/dist-x86_64-linux/build-git.sh b/src/ci/docker/dist-x86_64-linux/build-git.sh new file mode 100755 index 000000000000..92fa66b496d9 --- /dev/null +++ b/src/ci/docker/dist-x86_64-linux/build-git.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# Copyright 2017 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +set -ex +source shared.sh + +curl https://www.kernel.org/pub/software/scm/git/git-2.10.0.tar.gz | tar xzf - + +cd git-2.10.0 +make configure +hide_output ./configure --prefix=/rustroot +hide_output make -j10 +hide_output make install + +cd .. +rm -rf git-2.10.0 diff --git a/src/ci/docker/dist-x86_64-linux/build-headers.sh b/src/ci/docker/dist-x86_64-linux/build-headers.sh new file mode 100755 index 000000000000..4ce38fd9205e --- /dev/null +++ b/src/ci/docker/dist-x86_64-linux/build-headers.sh @@ -0,0 +1,25 @@ +#!/bin/bash +# Copyright 2017 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +set -ex +source shared.sh + +curl https://cdn.kernel.org/pub/linux/kernel/v3.x/linux-3.2.84.tar.xz | unxz | tar x + +cd linux-3.2.84 +hide_output make mrproper +hide_output make INSTALL_HDR_PATH=dest headers_install + +find dest/include \( -name .install -o -name ..install.cmd \) -delete +yes | cp -fr dest/include/* /usr/include + +cd .. +rm -rf linux-3.2.84 diff --git a/src/ci/docker/dist-x86_64-linux/build-openssl.sh b/src/ci/docker/dist-x86_64-linux/build-openssl.sh new file mode 100755 index 000000000000..64b1abf82a82 --- /dev/null +++ b/src/ci/docker/dist-x86_64-linux/build-openssl.sh @@ -0,0 +1,27 @@ +#!/bin/bash +# Copyright 2017 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +set -ex +source shared.sh + +VERSION=1.0.2j + +curl https://www.openssl.org/source/openssl-$VERSION.tar.gz | tar xzf - + +cd openssl-$VERSION +hide_output ./config --prefix=/rustroot shared -fPIC +hide_output make -j10 +hide_output make install +cd .. +rm -rf openssl-$VERSION + +# Make the system cert collection available to the new install. +ln -nsf /etc/pki/tls/cert.pem /rustroot/ssl/ diff --git a/src/ci/docker/dist-x86_64-linux/build-python.sh b/src/ci/docker/dist-x86_64-linux/build-python.sh new file mode 100755 index 000000000000..a7a450f3c8de --- /dev/null +++ b/src/ci/docker/dist-x86_64-linux/build-python.sh @@ -0,0 +1,30 @@ +#!/bin/bash +# Copyright 2017 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +set -ex +source shared.sh + +curl https://www.python.org/ftp/python/2.7.12/Python-2.7.12.tgz | \ + tar xzf - + +mkdir python-build +cd python-build + +# Gotta do some hackery to tell python about our custom OpenSSL build, but other +# than that fairly normal. +CFLAGS='-I /rustroot/include' LDFLAGS='-L /rustroot/lib -L /rustroot/lib64' \ + hide_output ../Python-2.7.12/configure --prefix=/rustroot +hide_output make -j10 +hide_output make install + +cd .. +rm -rf python-build +rm -rf Python-2.7.12 diff --git a/src/ci/docker/dist-x86_64-linux/shared.sh b/src/ci/docker/dist-x86_64-linux/shared.sh new file mode 100644 index 000000000000..97e6d2908cf8 --- /dev/null +++ b/src/ci/docker/dist-x86_64-linux/shared.sh @@ -0,0 +1,25 @@ +# Copyright 2017 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +hide_output() { + set +x + on_err=" +echo ERROR: An error was encountered with the build. +cat /tmp/build.log +exit 1 +" + trap "$on_err" ERR + bash -c "while true; do sleep 30; echo \$(date) - building ...; done" & + PING_LOOP_PID=$! + $@ &> /tmp/build.log + trap - ERR + kill $PING_LOOP_PID + set -x +} diff --git a/src/ci/docker/dist-x86_64-musl/Dockerfile b/src/ci/docker/dist-x86_64-musl/Dockerfile index 7ebd34ee904b..d58741132dcc 100644 --- a/src/ci/docker/dist-x86_64-musl/Dockerfile +++ b/src/ci/docker/dist-x86_64-musl/Dockerfile @@ -26,12 +26,13 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini ENTRYPOINT ["/usr/bin/dumb-init", "--"] RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-29-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache ENV RUST_CONFIGURE_ARGS \ --target=x86_64-unknown-linux-musl \ - --musl-root-x86_64=/musl-x86_64 + --musl-root-x86_64=/musl-x86_64 \ + --enable-extended # Newer binutils broke things on some vms/distros (i.e., linking against # unknown relocs disabled by the following flag), so we need to go out of our diff --git a/src/ci/docker/dist-x86_64-musl/build-musl.sh b/src/ci/docker/dist-x86_64-musl/build-musl.sh index 86bb259c8549..776da0093974 100644 --- a/src/ci/docker/dist-x86_64-musl/build-musl.sh +++ b/src/ci/docker/dist-x86_64-musl/build-musl.sh @@ -15,7 +15,7 @@ set -ex export CFLAGS="-fPIC -Wa,-mrelax-relocations=no" export CXXFLAGS="-Wa,-mrelax-relocations=no" -MUSL=musl-1.1.14 +MUSL=musl-1.1.16 curl https://www.musl-libc.org/releases/$MUSL.tar.gz | tar xzf - cd $MUSL ./configure --prefix=/musl-x86_64 --disable-shared diff --git a/src/ci/docker/dist-x86_64-netbsd/Dockerfile b/src/ci/docker/dist-x86_64-netbsd/Dockerfile new file mode 100644 index 000000000000..5c2fbbdf30f3 --- /dev/null +++ b/src/ci/docker/dist-x86_64-netbsd/Dockerfile @@ -0,0 +1,78 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + automake \ + bison \ + bzip2 \ + ca-certificates \ + cmake \ + curl \ + file \ + flex \ + g++ \ + gawk \ + gdb \ + git \ + gperf \ + help2man \ + libncurses-dev \ + libtool-bin \ + make \ + patch \ + python2.7 \ + sudo \ + texinfo \ + wget \ + xz-utils \ + libssl-dev \ + pkg-config + +RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ + dpkg -i dumb-init_*.deb && \ + rm dumb-init_*.deb +ENTRYPOINT ["/usr/bin/dumb-init", "--"] + +# Ubuntu 16.04 (this contianer) ships with make 4, but something in the +# toolchains we build below chokes on that, so go back to make 3 +RUN curl https://ftp.gnu.org/gnu/make/make-3.81.tar.gz | tar xzf - && \ + cd make-3.81 && \ + ./configure --prefix=/usr && \ + make && \ + make install && \ + cd .. && \ + rm -rf make-3.81 + +RUN curl http://crosstool-ng.org/download/crosstool-ng/crosstool-ng-1.22.0.tar.bz2 | \ + tar xjf - && \ + cd crosstool-ng && \ + ./configure --prefix=/usr/local && \ + make -j$(nproc) && \ + make install && \ + cd .. && \ + rm -rf crosstool-ng + +RUN groupadd -r rustbuild && useradd -m -r -g rustbuild rustbuild +RUN mkdir /x-tools && chown rustbuild:rustbuild /x-tools +USER rustbuild +WORKDIR /tmp + +COPY build-netbsd-toolchain.sh /tmp/ +RUN ./build-netbsd-toolchain.sh + +USER root + +RUN curl -o /usr/local/bin/sccache \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-29-sccache-x86_64-unknown-linux-musl && \ + chmod +x /usr/local/bin/sccache + +ENV PATH=$PATH:/x-tools/x86_64-unknown-netbsd/bin + +ENV \ + AR_x86_64_unknown_netbsd=x86_64--netbsd-ar \ + CC_x86_64_unknown_netbsd=x86_64--netbsd-gcc-sysroot \ + CXX_x86_64_unknown_netbsd=x86_64--netbsd-g++-sysroot + +ENV HOSTS=x86_64-unknown-netbsd + +ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended +ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-s390x-linux-netbsd/build-netbsd-toolchain.sh b/src/ci/docker/dist-x86_64-netbsd/build-netbsd-toolchain.sh similarity index 100% rename from src/ci/docker/dist-s390x-linux-netbsd/build-netbsd-toolchain.sh rename to src/ci/docker/dist-x86_64-netbsd/build-netbsd-toolchain.sh diff --git a/src/ci/docker/emscripten/Dockerfile b/src/ci/docker/emscripten/Dockerfile index 630b122c9359..dcbf1c739637 100644 --- a/src/ci/docker/emscripten/Dockerfile +++ b/src/ci/docker/emscripten/Dockerfile @@ -15,7 +15,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ lib32stdc++6 RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-29-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ @@ -27,10 +27,10 @@ WORKDIR /tmp COPY build-emscripten.sh /tmp/ RUN ./build-emscripten.sh ENV PATH=$PATH:/tmp/emsdk_portable -ENV PATH=$PATH:/tmp/emsdk_portable/clang/tag-e1.37.1/build_tag-e1.37.1_32/bin +ENV PATH=$PATH:/tmp/emsdk_portable/clang/tag-e1.37.10/build_tag-e1.37.10_32/bin ENV PATH=$PATH:/tmp/emsdk_portable/node/4.1.1_32bit/bin -ENV PATH=$PATH:/tmp/emsdk_portable/emscripten/tag-1.37.1 -ENV EMSCRIPTEN=/tmp/emsdk_portable/emscripten/tag-1.37.1 +ENV PATH=$PATH:/tmp/emsdk_portable/emscripten/tag-1.37.10 +ENV EMSCRIPTEN=/tmp/emsdk_portable/emscripten/tag-1.37.10 ENV RUST_CONFIGURE_ARGS --target=asmjs-unknown-emscripten diff --git a/src/ci/docker/emscripten/build-emscripten.sh b/src/ci/docker/emscripten/build-emscripten.sh index 88bf583007ce..8d6a28f418bf 100755 --- a/src/ci/docker/emscripten/build-emscripten.sh +++ b/src/ci/docker/emscripten/build-emscripten.sh @@ -29,8 +29,25 @@ exit 1 } curl https://s3.amazonaws.com/mozilla-games/emscripten/releases/emsdk-portable.tar.gz | \ - tar xzf - + tar xzf - + +# Some versions of the EMSDK archive have their contents in .emsdk-portable +# and others in emsdk_portable. Make sure the EMSDK ends up in a fixed path. +if [ -d emsdk-portable ]; then + mv emsdk-portable emsdk_portable +fi + +if [ ! -d emsdk_portable ]; then + echo "ERROR: Invalid emsdk archive. Dumping working directory." >&2 + ls -l + exit 1 +fi + +# Some versions of the EMSDK set the permissions of the root directory to +# 0700. Ensure the directory is readable by all users. +chmod 755 emsdk_portable + source emsdk_portable/emsdk_env.sh hide_output emsdk update -hide_output emsdk install --build=Release sdk-tag-1.37.1-32bit -hide_output emsdk activate --build=Release sdk-tag-1.37.1-32bit +hide_output emsdk install --build=Release sdk-tag-1.37.10-32bit +hide_output emsdk activate --build=Release sdk-tag-1.37.10-32bit diff --git a/src/ci/docker/i686-gnu-nopt/Dockerfile b/src/ci/docker/i686-gnu-nopt/Dockerfile index b9f47731eee7..945541111044 100644 --- a/src/ci/docker/i686-gnu-nopt/Dockerfile +++ b/src/ci/docker/i686-gnu-nopt/Dockerfile @@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-29-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/i686-gnu/Dockerfile b/src/ci/docker/i686-gnu/Dockerfile index e4a9c5b258fe..12c9cdf4a112 100644 --- a/src/ci/docker/i686-gnu/Dockerfile +++ b/src/ci/docker/i686-gnu/Dockerfile @@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-29-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh index c418d427b15b..59b93b784b2f 100755 --- a/src/ci/docker/run.sh +++ b/src/ci/docker/run.sh @@ -38,7 +38,6 @@ if [ "$SCCACHE_BUCKET" != "" ]; then args="$args --env AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID" args="$args --env AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY" args="$args --env SCCACHE_ERROR_LOG=/tmp/sccache/sccache.log" - args="$args --env SCCACHE_LOG_LEVEL=debug" args="$args --volume $objdir/tmp:/tmp/sccache" else mkdir -p $HOME/.cache/sccache @@ -57,6 +56,7 @@ exec docker \ --env DEPLOY_ALT=$DEPLOY_ALT \ --env LOCAL_USER_ID=`id -u` \ --volume "$HOME/.cargo:/cargo" \ + --volume "$HOME/rustsrc:$HOME/rustsrc" \ --privileged \ --rm \ rust-ci \ diff --git a/src/ci/docker/x86_64-gnu-aux/Dockerfile b/src/ci/docker/x86_64-gnu-aux/Dockerfile index 104361830e1c..d1f421248df5 100644 --- a/src/ci/docker/x86_64-gnu-aux/Dockerfile +++ b/src/ci/docker/x86_64-gnu-aux/Dockerfile @@ -15,7 +15,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-29-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu-debug/Dockerfile b/src/ci/docker/x86_64-gnu-debug/Dockerfile index 1575efdb4cb7..86704126700b 100644 --- a/src/ci/docker/x86_64-gnu-debug/Dockerfile +++ b/src/ci/docker/x86_64-gnu-debug/Dockerfile @@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-29-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu-distcheck/Dockerfile b/src/ci/docker/x86_64-gnu-distcheck/Dockerfile index 94847712094d..26d1f82efcc5 100644 --- a/src/ci/docker/x86_64-gnu-distcheck/Dockerfile +++ b/src/ci/docker/x86_64-gnu-distcheck/Dockerfile @@ -16,7 +16,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-29-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu-full-bootstrap/Dockerfile b/src/ci/docker/x86_64-gnu-full-bootstrap/Dockerfile index 542b4f90b119..3626301d7e9a 100644 --- a/src/ci/docker/x86_64-gnu-full-bootstrap/Dockerfile +++ b/src/ci/docker/x86_64-gnu-full-bootstrap/Dockerfile @@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-29-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu-incremental/Dockerfile b/src/ci/docker/x86_64-gnu-incremental/Dockerfile index 4d9b218c7654..42b2d98d332e 100644 --- a/src/ci/docker/x86_64-gnu-incremental/Dockerfile +++ b/src/ci/docker/x86_64-gnu-incremental/Dockerfile @@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-29-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile b/src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile index 04358ff97484..8bff767609f4 100644 --- a/src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile +++ b/src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile @@ -17,7 +17,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-29-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu-nopt/Dockerfile b/src/ci/docker/x86_64-gnu-nopt/Dockerfile index dddeb82e6bfb..c2c1ac878790 100644 --- a/src/ci/docker/x86_64-gnu-nopt/Dockerfile +++ b/src/ci/docker/x86_64-gnu-nopt/Dockerfile @@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-29-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/docker/x86_64-gnu/Dockerfile b/src/ci/docker/x86_64-gnu/Dockerfile index 393bcf023ea5..727cc84643fb 100644 --- a/src/ci/docker/x86_64-gnu/Dockerfile +++ b/src/ci/docker/x86_64-gnu/Dockerfile @@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-22-sccache-x86_64-unknown-linux-musl && \ + https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-29-sccache-x86_64-unknown-linux-musl && \ chmod +x /usr/local/bin/sccache RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \ diff --git a/src/ci/init_repo.sh b/src/ci/init_repo.sh new file mode 100755 index 000000000000..1db2135eb6d8 --- /dev/null +++ b/src/ci/init_repo.sh @@ -0,0 +1,86 @@ +#!/bin/bash +# Copyright 2016 The Rust Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution and at +# http://rust-lang.org/COPYRIGHT. +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +set -o errexit +set -o pipefail +set -o nounset + +set -o xtrace + +ci_dir=$(cd $(dirname $0) && pwd) +. "$ci_dir/shared.sh" + +REPO_DIR="$1" +CACHE_DIR="$2" + +cache_src_dir="$CACHE_DIR/src" +# If the layout of the cache directory changes, bump the number here +# (and anywhere else this file is referenced) so the cache is wiped +cache_valid_file="$CACHE_DIR/cache_valid1" + +if [ ! -d "$REPO_DIR" -o ! -d "$REPO_DIR/.git" ]; then + echo "Error: $REPO_DIR does not exist or is not a git repo" + exit 1 +fi +cd $REPO_DIR +if [ ! -d "$CACHE_DIR" ]; then + echo "Error: $CACHE_DIR does not exist or is not an absolute path" + exit 1 +fi + +# Wipe the cache if it's not valid, or mark it as invalid while we update it +if [ ! -f "$cache_valid_file" ]; then + rm -rf "$CACHE_DIR" + mkdir "$CACHE_DIR" +else + # Ignore errors while gathering information about the possible brokenness + # of the git repo since our gathered info will tell us something is wrong + set +o errexit + stat_lines=$(cd "$cache_src_dir" && git status --porcelain | wc -l) + stat_ec=$(cd "$cache_src_dir" && git status >/dev/null 2>&1; echo $?) + set -o errexit + if [ ! -d "$cache_src_dir/.git" -o $stat_lines != 0 -o $stat_ec != 0 ]; then + # Something is badly wrong - the cache valid file is here, but something + # about the git repo is fishy. Nuke it all, just in case + echo "WARNING: $cache_valid_file exists but bad repo: l:$stat_lines, ec:$stat_ec" + rm -rf "$CACHE_DIR" + mkdir "$CACHE_DIR" + else + rm "$cache_valid_file" + fi +fi + +# Update the cache (a pristine copy of the rust source master) +if [ ! -d "$cache_src_dir/.git" ]; then + retry sh -c "rm -rf $cache_src_dir && mkdir -p $cache_src_dir && \ + git clone https://github.com/rust-lang/rust.git $cache_src_dir" +fi +retry sh -c "cd $cache_src_dir && git reset --hard && git pull" +retry sh -c "cd $cache_src_dir && \ + git submodule deinit -f . && git submodule sync && git submodule update --init" + +# Cache was updated without errors, mark it as valid +touch "$cache_valid_file" + +# Update the submodules of the repo we're in, using the pristine repo as +# a cache for any object files +# No, `git submodule foreach` won't work: +# http://stackoverflow.com/questions/12641469/list-submodules-in-a-git-repository +modules="$(git config --file .gitmodules --get-regexp '\.path$' | cut -d' ' -f2)" +for module in $modules; do + if [ ! -d "$cache_src_dir/$module" ]; then + echo "WARNING: $module not found in pristine repo" + retry sh -c "git submodule deinit -f $module && git submodule update --init $module" + continue + fi + retry sh -c "git submodule deinit -f $module && \ + git submodule update --init --reference $cache_src_dir/$module $module" +done diff --git a/src/ci/run.sh b/src/ci/run.sh index 6c6a49ada15d..c6510120b47a 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -42,7 +42,6 @@ fi if [ "$DEPLOY$DEPLOY_ALT" != "" ]; then RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --release-channel=nightly" RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-llvm-static-stdcpp" - RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-save-analysis" if [ "$NO_LLVM_ASSERTIONS" = "1" ]; then RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --disable-llvm-assertions" diff --git a/src/ci/shared.sh b/src/ci/shared.sh index ecd9b7e98a48..f2e13fc73ae4 100644 --- a/src/ci/shared.sh +++ b/src/ci/shared.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/false # Copyright 2016 The Rust Project Developers. See the COPYRIGHT # file at the top-level directory of this distribution and at # http://rust-lang.org/COPYRIGHT. @@ -9,13 +9,16 @@ # option. This file may not be copied, modified, or distributed # except according to those terms. +# This file is intended to be sourced with `. shared.sh` or +# `source shared.sh`, hence the invalid shebang and not being +# marked as an executable file in git. + # See http://unix.stackexchange.com/questions/82598 function retry { + echo "Attempting with retry:" "$@" local n=1 local max=5 - local delay=15 while true; do - echo "Attempting:" "$@" "$@" && break || { if [[ $n -lt $max ]]; then ((n++)) diff --git a/src/compiler-rt b/src/compiler-rt index d30da544a8af..c8a8767c56ad 160000 --- a/src/compiler-rt +++ b/src/compiler-rt @@ -1 +1 @@ -Subproject commit d30da544a8afc5d78391dee270bdf40e74a215d3 +Subproject commit c8a8767c56ad3d3f4eb45c87b95026936fb9aa35 diff --git a/src/doc/book b/src/doc/book index 9bd223ca406b..ad7de198561b 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit 9bd223ca406b1170a24942d6474f9e8a56f4a420 +Subproject commit ad7de198561b3a12217ea2da76d796d9c7fc0ed3 diff --git a/src/doc/grammar.md b/src/doc/grammar.md index 8e803aff4d6f..12daa24e857f 100644 --- a/src/doc/grammar.md +++ b/src/doc/grammar.md @@ -761,8 +761,6 @@ closure_type := [ 'unsafe' ] [ '<' lifetime-list '>' ] '|' arg-list '|' [ ':' bound-list ] [ '->' type ] lifetime-list := lifetime | lifetime ',' lifetime-list arg-list := ident ':' type | ident ':' type ',' arg-list -bound-list := bound | bound '+' bound-list -bound := path | lifetime ``` ### Never type @@ -780,6 +778,16 @@ never_type : "!" ; **FIXME:** grammar? +### Type parameter bounds + +```antlr +bound-list := bound | bound '+' bound-list '+' ? +bound := ty_bound | lt_bound +lt_bound := lifetime +ty_bound := ty_bound_noparen | (ty_bound_noparen) +ty_bound_noparen := [?] [ for ] simple_path +``` + ### Self types **FIXME:** grammar? diff --git a/src/doc/guide-plugins.md b/src/doc/guide-plugins.md index 1ba28c0117db..6c511548789b 100644 --- a/src/doc/guide-plugins.md +++ b/src/doc/guide-plugins.md @@ -1,4 +1,4 @@ % The (old) Rust Compiler Plugins Guide This content has moved into -[the Unstable Book](unstable-book/plugin.html). +[the Unstable Book](unstable-book/language-features/plugin.html). diff --git a/src/doc/index.md b/src/doc/index.md index 1294c1a8c59e..fd5b120e81fa 100644 --- a/src/doc/index.md +++ b/src/doc/index.md @@ -32,16 +32,21 @@ nicknamed 'The Rust Bookshelf.' * [The Rustonomicon][nomicon] is your guidebook to the dark arts of unsafe Rust. * [The Reference][ref] is not a formal spec, but is more detailed and comprehensive than the book. +Initially, documentation lands in the Unstable Book, and then, as part of the +stabilization process, is moved into the Book, Nomicon, or Reference. + Another few words about the reference: it is guaranteed to be accurate, but not -complete. We now have a policy that all new features must be included in the -reference before stabilization; however, we are still back-filling things that -landed before then. That work is being tracked [here][38643]. +complete. We have a policy that features must have documentation to be stabilized, +but we did not always have this policy, and so there are some stable things that +are not yet in the reference. We're working on back-filling things that landed +before this policy was put into place. That work is being tracked +[here][refchecklist]. [Rust Learning]: https://github.com/ctjhoa/rust-learning [Docs.rs]: https://docs.rs/ [api]: std/index.html [ref]: reference/index.html -[38643]: https://github.com/rust-lang/rust/issues/38643 +[refchecklist]: https://github.com/rust-lang-nursery/reference/issues/9 [err]: error-index.html [book]: book/index.html [nomicon]: nomicon/index.html diff --git a/src/doc/nomicon b/src/doc/nomicon index d08fe97d12b4..616b98444ff4 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit d08fe97d12b41c1ed8cc7701e545864132783941 +Subproject commit 616b98444ff4eb5260deee95ee3e090dfd98b947 diff --git a/src/doc/reference b/src/doc/reference index 516549972d61..6b0de90d87dd 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 516549972d61c8946542d1a34afeae97167ff77b +Subproject commit 6b0de90d87dda15e323ef24cdf7ed873ac5cf4d3 diff --git a/src/doc/rust.md b/src/doc/rust.md index 7f02260cd2cd..5008b228c5c8 100644 --- a/src/doc/rust.md +++ b/src/doc/rust.md @@ -1,3 +1,3 @@ % The Rust Reference Manual -The manual has moved, and is now called [the reference](reference.html). +The manual has moved, and is now called [the reference](reference/index.html). diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md index 456c76d43a6e..3d9e7c7fd860 100644 --- a/src/doc/unstable-book/src/SUMMARY.md +++ b/src/doc/unstable-book/src/SUMMARY.md @@ -1,96 +1,224 @@ [The Unstable Book](the-unstable-book.md) -- [abi_msp430_interrupt](abi-msp430-interrupt.md) -- [abi_ptx](abi-ptx.md) -- [abi_sysv64](abi-sysv64.md) -- [abi_unadjusted](abi-unadjusted.md) -- [abi_vectorcall](abi-vectorcall.md) -- [abi_x86_interrupt](abi-x86-interrupt.md) -- [advanced_slice_patterns](advanced-slice-patterns.md) -- [alloc_jemalloc](alloc-jemalloc.md) -- [alloc_system](alloc-system.md) -- [allocator](allocator.md) -- [allow_internal_unstable](allow-internal-unstable.md) -- [asm](asm.md) -- [associated_consts](associated-consts.md) -- [associated_type_defaults](associated-type-defaults.md) -- [attr_literals](attr-literals.md) -- [box_patterns](box-patterns.md) -- [box_syntax](box-syntax.md) -- [cfg_target_feature](cfg-target-feature.md) -- [cfg_target_has_atomic](cfg-target-has-atomic.md) -- [cfg_target_thread_local](cfg-target-thread-local.md) -- [cfg_target_vendor](cfg-target-vendor.md) -- [compiler_builtins](compiler-builtins.md) -- [concat_idents](concat-idents.md) -- [conservative_impl_trait](conservative-impl-trait.md) -- [const_fn](const-fn.md) -- [const_indexing](const-indexing.md) -- [custom_attribute](custom-attribute.md) -- [custom_derive](custom-derive.md) -- [default_type_parameter_fallback](default-type-parameter-fallback.md) -- [drop_types_in_const](drop-types-in-const.md) -- [dropck_eyepatch](dropck-eyepatch.md) -- [dropck_parametricity](dropck-parametricity.md) -- [exclusive_range_pattern](exclusive-range-pattern.md) -- [field_init_shorthand](field-init-shorthand.md) -- [fundamental](fundamental.md) -- [generic_param_attrs](generic-param-attrs.md) -- [i128_type](i128-type.md) -- [inclusive_range_syntax](inclusive-range-syntax.md) -- [intrinsics](intrinsics.md) -- [lang_items](lang-items.md) -- [link_args](link-args.md) -- [link_cfg](link-cfg.md) -- [link_llvm_intrinsics](link-llvm-intrinsics.md) -- [linkage](linkage.md) -- [log_syntax](log-syntax.md) -- [loop_break_value](loop-break-value.md) -- [macro_reexport](macro-reexport.md) -- [main](main.md) -- [naked_functions](naked-functions.md) -- [needs_allocator](needs-allocator.md) -- [needs_panic_runtime](needs-panic-runtime.md) -- [never_type](never-type.md) -- [no_core](no-core.md) -- [no_debug](no-debug.md) -- [non_ascii_idents](non-ascii-idents.md) -- [omit_gdb_pretty_printer_section](omit-gdb-pretty-printer-section.md) -- [on_unimplemented](on-unimplemented.md) -- [optin_builtin_traits](optin-builtin-traits.md) -- [panic_runtime](panic-runtime.md) -- [placement_in_syntax](placement-in-syntax.md) -- [platform_intrinsics](platform-intrinsics.md) -- [plugin](plugin.md) -- [plugin_registrar](plugin-registrar.md) -- [prelude_import](prelude-import.md) -- [proc_macro](proc-macro.md) -- [quote](quote.md) -- [relaxed_adts](relaxed-adts.md) -- [repr_simd](repr-simd.md) -- [rustc_attrs](rustc-attrs.md) -- [rustc_diagnostic_macros](rustc-diagnostic-macros.md) -- [rvalue_static_promotion](rvalue-static-promotion.md) -- [sanitizer_runtime](sanitizer-runtime.md) -- [simd](simd.md) -- [simd_ffi](simd-ffi.md) -- [slice_patterns](slice-patterns.md) -- [sort_unstable](sort-unstable.md) -- [specialization](specialization.md) -- [staged_api](staged-api.md) -- [start](start.md) -- [static_nobundle](static-nobundle.md) -- [static_recursion](static-recursion.md) -- [stmt_expr_attributes](stmt-expr-attributes.md) -- [struct_field_attributes](struct-field-attributes.md) -- [structural_match](structural-match.md) -- [target_feature](target-feature.md) -- [test](test.md) -- [thread_local](thread-local.md) -- [trace_macros](trace-macros.md) -- [type_ascription](type-ascription.md) -- [unboxed_closures](unboxed-closures.md) -- [untagged_unions](untagged-unions.md) -- [unwind_attributes](unwind-attributes.md) -- [use_extern_macros](use-extern-macros.md) -- [windows_subsystem](windows-subsystem.md) +- [Compiler flags](compiler-flags.md) + - [linker_flavor](compiler-flags/linker-flavor.md) + - [remap_path_prefix](compiler-flags/remap-path-prefix.md) +- [Language features](language-features.md) + - [abi_msp430_interrupt](language-features/abi-msp430-interrupt.md) + - [abi_ptx](language-features/abi-ptx.md) + - [abi_sysv64](language-features/abi-sysv64.md) + - [abi_unadjusted](language-features/abi-unadjusted.md) + - [abi_vectorcall](language-features/abi-vectorcall.md) + - [abi_x86_interrupt](language-features/abi-x86-interrupt.md) + - [advanced_slice_patterns](language-features/advanced-slice-patterns.md) + - [allocator](language-features/allocator.md) + - [allow_internal_unstable](language-features/allow-internal-unstable.md) + - [asm](language-features/asm.md) + - [associated_consts](language-features/associated-consts.md) + - [associated_type_defaults](language-features/associated-type-defaults.md) + - [attr_literals](language-features/attr-literals.md) + - [box_patterns](language-features/box-patterns.md) + - [box_syntax](language-features/box-syntax.md) + - [catch_expr](language-features/catch-expr.md) + - [cfg_target_feature](language-features/cfg-target-feature.md) + - [cfg_target_has_atomic](language-features/cfg-target-has-atomic.md) + - [cfg_target_thread_local](language-features/cfg-target-thread-local.md) + - [cfg_target_vendor](language-features/cfg-target-vendor.md) + - [closure_to_fn_coercion](language-features/closure-to-fn-coercion.md) + - [compiler_builtins](language-features/compiler-builtins.md) + - [concat_idents](language-features/concat-idents.md) + - [conservative_impl_trait](language-features/conservative-impl-trait.md) + - [const_fn](language-features/const-fn.md) + - [const_indexing](language-features/const-indexing.md) + - [custom_attribute](language-features/custom-attribute.md) + - [custom_derive](language-features/custom-derive.md) + - [default_type_parameter_fallback](language-features/default-type-parameter-fallback.md) + - [drop_types_in_const](language-features/drop-types-in-const.md) + - [dropck_eyepatch](language-features/dropck-eyepatch.md) + - [dropck_parametricity](language-features/dropck-parametricity.md) + - [exclusive_range_pattern](language-features/exclusive-range-pattern.md) + - [fundamental](language-features/fundamental.md) + - [generic_param_attrs](language-features/generic-param-attrs.md) + - [global_asm](language-features/global_asm.md) + - [i128_type](language-features/i128-type.md) + - [inclusive_range_syntax](language-features/inclusive-range-syntax.md) + - [intrinsics](language-features/intrinsics.md) + - [lang_items](language-features/lang-items.md) + - [link_args](language-features/link-args.md) + - [link_cfg](language-features/link-cfg.md) + - [link_llvm_intrinsics](language-features/link-llvm-intrinsics.md) + - [linkage](language-features/linkage.md) + - [log_syntax](language-features/log-syntax.md) + - [loop_break_value](language-features/loop-break-value.md) + - [macro_reexport](language-features/macro-reexport.md) + - [macro_vis_matcher](language-features/macro-vis-matcher.md) + - [main](language-features/main.md) + - [naked_functions](language-features/naked-functions.md) + - [needs_allocator](language-features/needs-allocator.md) + - [needs_panic_runtime](language-features/needs-panic-runtime.md) + - [never_type](language-features/never-type.md) + - [no_core](language-features/no-core.md) + - [no_debug](language-features/no-debug.md) + - [non_ascii_idents](language-features/non-ascii-idents.md) + - [omit_gdb_pretty_printer_section](language-features/omit-gdb-pretty-printer-section.md) + - [on_unimplemented](language-features/on-unimplemented.md) + - [optin_builtin_traits](language-features/optin-builtin-traits.md) + - [overlapping_marker_traits](language-features/overlapping-marker-traits.md) + - [panic_runtime](language-features/panic-runtime.md) + - [placement_in_syntax](language-features/placement-in-syntax.md) + - [platform_intrinsics](language-features/platform-intrinsics.md) + - [plugin](language-features/plugin.md) + - [plugin_registrar](language-features/plugin-registrar.md) + - [prelude_import](language-features/prelude-import.md) + - [proc_macro](language-features/proc-macro.md) + - [quote](language-features/quote.md) + - [relaxed_adts](language-features/relaxed-adts.md) + - [repr_align](language-features/repr-align.md) + - [repr_simd](language-features/repr-simd.md) + - [rustc_attrs](language-features/rustc-attrs.md) + - [rustc_diagnostic_macros](language-features/rustc-diagnostic-macros.md) + - [rvalue_static_promotion](language-features/rvalue-static-promotion.md) + - [sanitizer_runtime](language-features/sanitizer-runtime.md) + - [simd](language-features/simd.md) + - [simd_ffi](language-features/simd-ffi.md) + - [slice_patterns](language-features/slice-patterns.md) + - [specialization](language-features/specialization.md) + - [staged_api](language-features/staged-api.md) + - [start](language-features/start.md) + - [static_nobundle](language-features/static-nobundle.md) + - [stmt_expr_attributes](language-features/stmt-expr-attributes.md) + - [struct_field_attributes](language-features/struct-field-attributes.md) + - [structural_match](language-features/structural-match.md) + - [target_feature](language-features/target-feature.md) + - [thread_local](language-features/thread-local.md) + - [trace_macros](language-features/trace-macros.md) + - [type_ascription](language-features/type-ascription.md) + - [unboxed_closures](language-features/unboxed-closures.md) + - [untagged_unions](language-features/untagged-unions.md) + - [unwind_attributes](language-features/unwind-attributes.md) + - [use_extern_macros](language-features/use-extern-macros.md) + - [used](language-features/used.md) +- [Library Features](library-features.md) + - [alloc_jemalloc](library-features/alloc-jemalloc.md) + - [alloc_system](library-features/alloc-system.md) + - [alloc](library-features/alloc.md) + - [as_c_str](library-features/as-c-str.md) + - [ascii_ctype](library-features/ascii-ctype.md) + - [binary_heap_peek_mut_pop](library-features/binary-heap-peek-mut-pop.md) + - [box_heap](library-features/box-heap.md) + - [c_void_variant](library-features/c-void-variant.md) + - [char_escape_debug](library-features/char-escape-debug.md) + - [coerce_unsized](library-features/coerce-unsized.md) + - [collection_placement](library-features/collection-placement.md) + - [collections_range](library-features/collections-range.md) + - [collections](library-features/collections.md) + - [command_envs](library-features/command-envs.md) + - [compiler_builtins_lib](library-features/compiler-builtins-lib.md) + - [compiler_fences](library-features/compiler-fences.md) + - [concat_idents_macro](library-features/concat-idents-macro.md) + - [core_char_ext](library-features/core-char-ext.md) + - [core_float](library-features/core-float.md) + - [core_intrinsics](library-features/core-intrinsics.md) + - [core_panic](library-features/core-panic.md) + - [core_private_bignum](library-features/core-private-bignum.md) + - [core_private_diy_float](library-features/core-private-diy-float.md) + - [core_slice_ext](library-features/core-slice-ext.md) + - [core_str_ext](library-features/core-str-ext.md) + - [dec2flt](library-features/dec2flt.md) + - [decode_utf8](library-features/decode-utf8.md) + - [derive_clone_copy](library-features/derive-clone-copy.md) + - [derive_eq](library-features/derive-eq.md) + - [discriminant_value](library-features/discriminant-value.md) + - [error_type_id](library-features/error-type-id.md) + - [exact_size_is_empty](library-features/exact-size-is-empty.md) + - [fd](library-features/fd.md) + - [fd_read](library-features/fd-read.md) + - [fixed_size_array](library-features/fixed-size-array.md) + - [float_bits_conv](library-features/float-bits-conv.md) + - [flt2dec](library-features/flt2dec.md) + - [fmt_flags_align](library-features/fmt-flags-align.md) + - [fmt_internals](library-features/fmt-internals.md) + - [fn_traits](library-features/fn-traits.md) + - [fnbox](library-features/fnbox.md) + - [from_utf8_error_as_bytes](library-features/from_utf8_error_as_bytes.md) + - [fused](library-features/fused.md) + - [future_atomic_orderings](library-features/future-atomic-orderings.md) + - [get_type_id](library-features/get-type-id.md) + - [heap_api](library-features/heap-api.md) + - [hint_core_should_pause](library-features/hint-core-should-pause.md) + - [i128](library-features/i128.md) + - [inclusive_range](library-features/inclusive-range.md) + - [integer_atomics](library-features/integer-atomics.md) + - [into_boxed_c_str](library-features/into-boxed-c-str.md) + - [into_boxed_os_str](library-features/into-boxed-os-str.md) + - [into_boxed_path](library-features/into-boxed-path.md) + - [io_error_internals](library-features/io-error-internals.md) + - [io](library-features/io.md) + - [ip](library-features/ip.md) + - [iter_rfind](library-features/iter-rfind.md) + - [libstd_io_internals](library-features/libstd-io-internals.md) + - [libstd_sys_internals](library-features/libstd-sys-internals.md) + - [libstd_thread_internals](library-features/libstd-thread-internals.md) + - [linked_list_extras](library-features/linked-list-extras.md) + - [lookup_host](library-features/lookup-host.md) + - [manually_drop](library-features/manually-drop.md) + - [more_io_inner_methods](library-features/more-io-inner-methods.md) + - [mpsc_select](library-features/mpsc-select.md) + - [n16](library-features/n16.md) + - [never_type_impls](library-features/never-type-impls.md) + - [nonzero](library-features/nonzero.md) + - [offset_to](library-features/offset-to.md) + - [once_poison](library-features/once-poison.md) + - [oom](library-features/oom.md) + - [option_entry](library-features/option-entry.md) + - [osstring_shrink_to_fit](library-features/osstring-shrink-to-fit.md) + - [panic_abort](library-features/panic-abort.md) + - [panic_unwind](library-features/panic-unwind.md) + - [pattern](library-features/pattern.md) + - [peek](library-features/peek.md) + - [placement_in](library-features/placement-in.md) + - [placement_new_protocol](library-features/placement-new-protocol.md) + - [print](library-features/print.md) + - [proc_macro_internals](library-features/proc-macro-internals.md) + - [process_try_wait](library-features/process-try-wait.md) + - [question_mark_carrier](library-features/question-mark-carrier.md) + - [rand](library-features/rand.md) + - [range_contains](library-features/range-contains.md) + - [raw](library-features/raw.md) + - [retain_hash_collection](library-features/retain-hash-collection.md) + - [reverse_cmp_key](library-features/reverse-cmp-key.md) + - [rt](library-features/rt.md) + - [rustc_private](library-features/rustc-private.md) + - [sanitizer_runtime_lib](library-features/sanitizer-runtime-lib.md) + - [set_stdio](library-features/set-stdio.md) + - [shared](library-features/shared.md) + - [sip_hash_13](library-features/sip-hash-13.md) + - [slice_concat_ext](library-features/slice-concat-ext.md) + - [slice_get_slice](library-features/slice-get-slice.md) + - [slice_rsplit](library-features/slice-rsplit.md) + - [sort_internals](library-features/sort-internals.md) + - [sort_unstable](library-features/sort-unstable.md) + - [splice](library-features/splice.md) + - [step_by](library-features/step-by.md) + - [step_trait](library-features/step-trait.md) + - [str_checked_slicing](library-features/str-checked-slicing.md) + - [str_escape](library-features/str-escape.md) + - [str_internals](library-features/str-internals.md) + - [str_box_extras](library-features/str-box-extras.md) + - [str_mut_extras](library-features/str-mut-extras.md) + - [test](library-features/test.md) + - [thread_id](library-features/thread-id.md) + - [thread_local_internals](library-features/thread-local-internals.md) + - [thread_local_state](library-features/thread-local-state.md) + - [toowned_clone_into](library-features/toowned-clone-into.md) + - [trusted_len](library-features/trusted-len.md) + - [try_from](library-features/try-from.md) + - [unicode](library-features/unicode.md) + - [unique](library-features/unique.md) + - [unsize](library-features/unsize.md) + - [utf8_error_error_len](library-features/utf8-error-error-len.md) + - [vec_remove_item](library-features/vec-remove-item.md) + - [windows_c](library-features/windows-c.md) + - [windows_handle](library-features/windows-handle.md) + - [windows_net](library-features/windows-net.md) + - [windows_stdio](library-features/windows-stdio.md) diff --git a/src/doc/unstable-book/src/abi-msp430-interrupt.md b/src/doc/unstable-book/src/abi-msp430-interrupt.md deleted file mode 100644 index 9b2c7f298979..000000000000 --- a/src/doc/unstable-book/src/abi-msp430-interrupt.md +++ /dev/null @@ -1,7 +0,0 @@ -# `abi_msp430_interrupt` - -The tracking issue for this feature is: [#38487] - -[#38487]: https://github.com/rust-lang/rust/issues/38487 - ------------------------- diff --git a/src/doc/unstable-book/src/abi-ptx.md b/src/doc/unstable-book/src/abi-ptx.md deleted file mode 100644 index 9c1b8868aceb..000000000000 --- a/src/doc/unstable-book/src/abi-ptx.md +++ /dev/null @@ -1,5 +0,0 @@ -# `abi_ptx` - -The tracking issue for this feature is: None. - ------------------------- diff --git a/src/doc/unstable-book/src/compiler-builtins.md b/src/doc/unstable-book/src/compiler-builtins.md deleted file mode 100644 index 3ec3cba257a9..000000000000 --- a/src/doc/unstable-book/src/compiler-builtins.md +++ /dev/null @@ -1,6 +0,0 @@ -# `compiler_builtins` - -The tracking issue for this feature is: None. - ------------------------- - diff --git a/src/doc/unstable-book/src/compiler-flags.md b/src/doc/unstable-book/src/compiler-flags.md new file mode 100644 index 000000000000..43eadb351016 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags.md @@ -0,0 +1 @@ +# Compiler flags diff --git a/src/doc/unstable-book/src/compiler-flags/linker-flavor.md b/src/doc/unstable-book/src/compiler-flags/linker-flavor.md new file mode 100644 index 000000000000..39659602e015 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/linker-flavor.md @@ -0,0 +1,61 @@ +# `linker-flavor` + +The tracking issue for this feature is: None + +------------------------ + +Every `rustc` target defaults to some linker. For example, Linux targets default +to gcc. In some cases, you may want to override the default; you can do that +with the unstable CLI argument: `-Z linker-flavor`. + +Here how you would use this flag to link a Rust binary for the +`thumbv7m-none-eabi` using LLD instead of GCC. + +``` text +$ xargo rustc --target thumbv7m-none-eabi -- \ + -C linker=ld.lld \ + -Z linker-flavor=ld \ + -Z print-link-args | tr ' ' '\n' +"ld.lld" +"-L" +"$SYSROOT/lib/rustlib/thumbv7m-none-eabi/lib" +"$PWD/target/thumbv7m-none-eabi/debug/deps/app-512e9dbf385f233c.0.o" +"-o" +"$PWD/target/thumbv7m-none-eabi/debug/deps/app-512e9dbf385f233c" +"--gc-sections" +"-L" +"$PWD/target/thumbv7m-none-eabi/debug/deps" +"-L" +"$PWD/target/debug/deps" +"-L" +"$SYSROOT/lib/rustlib/thumbv7m-none-eabi/lib" +"-Bstatic" +"$SYSROOT/lib/rustlib/thumbv7m-none-eabi/lib/libcore-e1ccb7dfb1cb9ebb.rlib" +"-Bdynamic" +``` + +Whereas the default is: + +``` text +$ xargo rustc --target thumbv7m-none-eabi -- \ + -C link-arg=-nostartfiles \ + -Z print-link-args | tr ' ' '\n' +"arm-none-eabi-gcc" +"-L" +"$SYSROOT/lib/rustlib/thumbv7m-none-eabi/lib" +"$PWD/target/thumbv7m-none-eabi/debug/deps/app-961e39416baa38d9.0.o" +"-o" +"$PWD/target/thumbv7m-none-eabi/debug/deps/app-961e39416baa38d9" +"-Wl,--gc-sections" +"-nodefaultlibs" +"-L" +"$PWD/target/thumbv7m-none-eabi/debug/deps" +"-L" +"$PWD/target/debug/deps" +"-L" +"$SYSROOT/lib/rustlib/thumbv7m-none-eabi/lib" +"-Wl,-Bstatic" +"$SYSROOT/lib/rustlib/thumbv7m-none-eabi/lib/libcore-e1ccb7dfb1cb9ebb.rlib" +"-nostartfiles" +"-Wl,-Bdynamic" +``` diff --git a/src/doc/unstable-book/src/compiler-flags/remap-path-prefix.md b/src/doc/unstable-book/src/compiler-flags/remap-path-prefix.md new file mode 100644 index 000000000000..8ca04d253259 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/remap-path-prefix.md @@ -0,0 +1,37 @@ +# `remap-path-prefix` + +The tracking issue for this feature is: [#41555](https://github.com/rust-lang/rust/issues/41555) + +------------------------ + +The `-Z remap-path-prefix-from`, `-Z remap-path-prefix-to` commandline option +pair allows to replace prefixes of any file paths the compiler emits in various +places. This is useful for bringing debuginfo paths into a well-known form and +for achieving reproducible builds independent of the directory the compiler was +executed in. All paths emitted by the compiler are affected, including those in +error messages. + +In order to map all paths starting with `/home/foo/my-project/src` to +`/sources/my-project`, one would invoke the compiler as follows: + +```text +rustc -Zremap-path-prefix-from="/home/foo/my-project/src" -Zremap-path-prefix-to="/sources/my-project" +``` + +Debuginfo for code from the file `/home/foo/my-project/src/foo/mod.rs`, +for example, would then point debuggers to `/sources/my-project/foo/mod.rs` +instead of the original file. + +The options can be specified multiple times when multiple prefixes should be +mapped: + +```text +rustc -Zremap-path-prefix-from="/home/foo/my-project/src" \ + -Zremap-path-prefix-to="/sources/my-project" \ + -Zremap-path-prefix-from="/home/foo/my-project/build-dir" \ + -Zremap-path-prefix-to="/stable-build-dir" +``` + +When the options are given multiple times, the nth `-from` will be matched up +with the nth `-to` and they can appear anywhere on the commandline. Mappings +specified later on the line will take precedence over earlier ones. diff --git a/src/doc/unstable-book/src/field-init-shorthand.md b/src/doc/unstable-book/src/field-init-shorthand.md deleted file mode 100644 index e737dbaa4ec0..000000000000 --- a/src/doc/unstable-book/src/field-init-shorthand.md +++ /dev/null @@ -1,10 +0,0 @@ -# `field_init_shorthand` - -The tracking issue for this feature is: [#37340] - -[#37340]: https://github.com/rust-lang/rust/issues/37340 - ------------------------- - - - diff --git a/src/doc/unstable-book/src/language-features.md b/src/doc/unstable-book/src/language-features.md new file mode 100644 index 000000000000..a27514df97d6 --- /dev/null +++ b/src/doc/unstable-book/src/language-features.md @@ -0,0 +1 @@ +# Language features diff --git a/src/doc/unstable-book/src/language-features/abi-msp430-interrupt.md b/src/doc/unstable-book/src/language-features/abi-msp430-interrupt.md new file mode 100644 index 000000000000..b10bc41cb143 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/abi-msp430-interrupt.md @@ -0,0 +1,42 @@ +# `abi_msp430_interrupt` + +The tracking issue for this feature is: [#38487] + +[#38487]: https://github.com/rust-lang/rust/issues/38487 + +------------------------ + +In the MSP430 architecture, interrupt handlers have a special calling +convention. You can use the `"msp430-interrupt"` ABI to make the compiler apply +the right calling convention to the interrupt handlers you define. + + + +``` rust,ignore +#![feature(abi_msp430_interrupt)] +#![no_std] + +// Place the interrupt handler at the appropriate memory address +// (Alternatively, you can use `#[used]` and remove `pub` and `#[no_mangle]`) +#[link_section = "__interrupt_vector_10"] +#[no_mangle] +pub static TIM0_VECTOR: extern "msp430-interrupt" fn() = tim0; + +// The interrupt handler +extern "msp430-interrupt" fn tim0() { + // .. +} +``` + +``` text +$ msp430-elf-objdump -CD ./target/msp430/release/app +Disassembly of section __interrupt_vector_10: + +0000fff2 : + fff2: 00 c0 interrupt service routine at 0xc000 + +Disassembly of section .text: + +0000c000 : + c000: 00 13 reti +``` diff --git a/src/doc/unstable-book/src/language-features/abi-ptx.md b/src/doc/unstable-book/src/language-features/abi-ptx.md new file mode 100644 index 000000000000..0ded3ceeaef2 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/abi-ptx.md @@ -0,0 +1,60 @@ +# `abi_ptx` + +The tracking issue for this feature is: [#38788] + +[#38788]: https://github.com/rust-lang/rust/issues/38788 + +------------------------ + +When emitting PTX code, all vanilla Rust functions (`fn`) get translated to +"device" functions. These functions are *not* callable from the host via the +CUDA API so a crate with only device functions is not too useful! + +OTOH, "global" functions *can* be called by the host; you can think of them +as the real public API of your crate. To produce a global function use the +`"ptx-kernel"` ABI. + + + +``` rust,ignore +#![feature(abi_ptx)] +#![no_std] + +pub unsafe extern "ptx-kernel" fn global_function() { + device_function(); +} + +pub fn device_function() { + // .. +} +``` + +``` text +$ xargo rustc --target nvptx64-nvidia-cuda --release -- --emit=asm + +$ cat $(find -name '*.s') +// +// Generated by LLVM NVPTX Back-End +// + +.version 3.2 +.target sm_20 +.address_size 64 + + // .globl _ZN6kernel15global_function17h46111ebe6516b382E + +.visible .entry _ZN6kernel15global_function17h46111ebe6516b382E() +{ + + + ret; +} + + // .globl _ZN6kernel15device_function17hd6a0e4993bbf3f78E +.visible .func _ZN6kernel15device_function17hd6a0e4993bbf3f78E() +{ + + + ret; +} +``` diff --git a/src/doc/unstable-book/src/abi-sysv64.md b/src/doc/unstable-book/src/language-features/abi-sysv64.md similarity index 100% rename from src/doc/unstable-book/src/abi-sysv64.md rename to src/doc/unstable-book/src/language-features/abi-sysv64.md diff --git a/src/doc/unstable-book/src/abi-unadjusted.md b/src/doc/unstable-book/src/language-features/abi-unadjusted.md similarity index 100% rename from src/doc/unstable-book/src/abi-unadjusted.md rename to src/doc/unstable-book/src/language-features/abi-unadjusted.md diff --git a/src/doc/unstable-book/src/abi-vectorcall.md b/src/doc/unstable-book/src/language-features/abi-vectorcall.md similarity index 100% rename from src/doc/unstable-book/src/abi-vectorcall.md rename to src/doc/unstable-book/src/language-features/abi-vectorcall.md diff --git a/src/doc/unstable-book/src/abi-x86-interrupt.md b/src/doc/unstable-book/src/language-features/abi-x86-interrupt.md similarity index 100% rename from src/doc/unstable-book/src/abi-x86-interrupt.md rename to src/doc/unstable-book/src/language-features/abi-x86-interrupt.md diff --git a/src/doc/unstable-book/src/advanced-slice-patterns.md b/src/doc/unstable-book/src/language-features/advanced-slice-patterns.md similarity index 100% rename from src/doc/unstable-book/src/advanced-slice-patterns.md rename to src/doc/unstable-book/src/language-features/advanced-slice-patterns.md diff --git a/src/doc/unstable-book/src/allocator.md b/src/doc/unstable-book/src/language-features/allocator.md similarity index 96% rename from src/doc/unstable-book/src/allocator.md rename to src/doc/unstable-book/src/language-features/allocator.md index 7261641698f4..cfcf8e22d708 100644 --- a/src/doc/unstable-book/src/allocator.md +++ b/src/doc/unstable-book/src/language-features/allocator.md @@ -51,6 +51,11 @@ pub extern fn __rust_allocate(size: usize, _align: usize) -> *mut u8 { unsafe { libc::malloc(size as libc::size_t) as *mut u8 } } +#[no_mangle] +pub extern fn __rust_allocate_zeroed(size: usize, _align: usize) -> *mut u8 { + unsafe { libc::calloc(size as libc::size_t, 1) as *mut u8 } +} + #[no_mangle] pub extern fn __rust_deallocate(ptr: *mut u8, _old_size: usize, _align: usize) { unsafe { libc::free(ptr as *mut libc::c_void) } diff --git a/src/doc/unstable-book/src/allow-internal-unstable.md b/src/doc/unstable-book/src/language-features/allow-internal-unstable.md similarity index 100% rename from src/doc/unstable-book/src/allow-internal-unstable.md rename to src/doc/unstable-book/src/language-features/allow-internal-unstable.md diff --git a/src/doc/unstable-book/src/asm.md b/src/doc/unstable-book/src/language-features/asm.md similarity index 97% rename from src/doc/unstable-book/src/asm.md rename to src/doc/unstable-book/src/language-features/asm.md index 032d9d812402..5e68be633e7a 100644 --- a/src/doc/unstable-book/src/asm.md +++ b/src/doc/unstable-book/src/language-features/asm.md @@ -189,3 +189,5 @@ constraints, etc. [llvm-docs]: http://llvm.org/docs/LangRef.html#inline-assembler-expressions +If you need more power and don't mind losing some of the niceties of +`asm!`, check out [global_asm](global_asm.html). diff --git a/src/doc/unstable-book/src/associated-consts.md b/src/doc/unstable-book/src/language-features/associated-consts.md similarity index 100% rename from src/doc/unstable-book/src/associated-consts.md rename to src/doc/unstable-book/src/language-features/associated-consts.md diff --git a/src/doc/unstable-book/src/associated-type-defaults.md b/src/doc/unstable-book/src/language-features/associated-type-defaults.md similarity index 100% rename from src/doc/unstable-book/src/associated-type-defaults.md rename to src/doc/unstable-book/src/language-features/associated-type-defaults.md diff --git a/src/doc/unstable-book/src/attr-literals.md b/src/doc/unstable-book/src/language-features/attr-literals.md similarity index 100% rename from src/doc/unstable-book/src/attr-literals.md rename to src/doc/unstable-book/src/language-features/attr-literals.md diff --git a/src/doc/unstable-book/src/box-patterns.md b/src/doc/unstable-book/src/language-features/box-patterns.md similarity index 100% rename from src/doc/unstable-book/src/box-patterns.md rename to src/doc/unstable-book/src/language-features/box-patterns.md diff --git a/src/doc/unstable-book/src/box-syntax.md b/src/doc/unstable-book/src/language-features/box-syntax.md similarity index 100% rename from src/doc/unstable-book/src/box-syntax.md rename to src/doc/unstable-book/src/language-features/box-syntax.md diff --git a/src/doc/unstable-book/src/language-features/catch-expr.md b/src/doc/unstable-book/src/language-features/catch-expr.md new file mode 100644 index 000000000000..44eb2a6dd4fd --- /dev/null +++ b/src/doc/unstable-book/src/language-features/catch-expr.md @@ -0,0 +1,7 @@ +# `catch_expr` + +The tracking issue for this feature is: [#31436] + +[#31436]: https://github.com/rust-lang/rust/issues/31436 + +------------------------ diff --git a/src/doc/unstable-book/src/cfg-target-feature.md b/src/doc/unstable-book/src/language-features/cfg-target-feature.md similarity index 100% rename from src/doc/unstable-book/src/cfg-target-feature.md rename to src/doc/unstable-book/src/language-features/cfg-target-feature.md diff --git a/src/doc/unstable-book/src/cfg-target-has-atomic.md b/src/doc/unstable-book/src/language-features/cfg-target-has-atomic.md similarity index 100% rename from src/doc/unstable-book/src/cfg-target-has-atomic.md rename to src/doc/unstable-book/src/language-features/cfg-target-has-atomic.md diff --git a/src/doc/unstable-book/src/cfg-target-thread-local.md b/src/doc/unstable-book/src/language-features/cfg-target-thread-local.md similarity index 100% rename from src/doc/unstable-book/src/cfg-target-thread-local.md rename to src/doc/unstable-book/src/language-features/cfg-target-thread-local.md diff --git a/src/doc/unstable-book/src/cfg-target-vendor.md b/src/doc/unstable-book/src/language-features/cfg-target-vendor.md similarity index 100% rename from src/doc/unstable-book/src/cfg-target-vendor.md rename to src/doc/unstable-book/src/language-features/cfg-target-vendor.md diff --git a/src/doc/unstable-book/src/language-features/closure-to-fn-coercion.md b/src/doc/unstable-book/src/language-features/closure-to-fn-coercion.md new file mode 100644 index 000000000000..4e3b735e24fb --- /dev/null +++ b/src/doc/unstable-book/src/language-features/closure-to-fn-coercion.md @@ -0,0 +1,7 @@ +# `closure_to_fn_coercion` + +The tracking issue for this feature is: [#39817] + +[#39817]: https://github.com/rust-lang/rust/issues/39817 + +------------------------ diff --git a/src/doc/unstable-book/src/language-features/compiler-builtins.md b/src/doc/unstable-book/src/language-features/compiler-builtins.md new file mode 100644 index 000000000000..52fac575b6e8 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/compiler-builtins.md @@ -0,0 +1,5 @@ +# `compiler_builtins` + +This feature is internal to the Rust compiler and is not intended for general use. + +------------------------ diff --git a/src/doc/unstable-book/src/concat-idents.md b/src/doc/unstable-book/src/language-features/concat-idents.md similarity index 100% rename from src/doc/unstable-book/src/concat-idents.md rename to src/doc/unstable-book/src/language-features/concat-idents.md diff --git a/src/doc/unstable-book/src/conservative-impl-trait.md b/src/doc/unstable-book/src/language-features/conservative-impl-trait.md similarity index 100% rename from src/doc/unstable-book/src/conservative-impl-trait.md rename to src/doc/unstable-book/src/language-features/conservative-impl-trait.md diff --git a/src/doc/unstable-book/src/const-fn.md b/src/doc/unstable-book/src/language-features/const-fn.md similarity index 100% rename from src/doc/unstable-book/src/const-fn.md rename to src/doc/unstable-book/src/language-features/const-fn.md diff --git a/src/doc/unstable-book/src/const-indexing.md b/src/doc/unstable-book/src/language-features/const-indexing.md similarity index 100% rename from src/doc/unstable-book/src/const-indexing.md rename to src/doc/unstable-book/src/language-features/const-indexing.md diff --git a/src/doc/unstable-book/src/custom-attribute.md b/src/doc/unstable-book/src/language-features/custom-attribute.md similarity index 100% rename from src/doc/unstable-book/src/custom-attribute.md rename to src/doc/unstable-book/src/language-features/custom-attribute.md diff --git a/src/doc/unstable-book/src/custom-derive.md b/src/doc/unstable-book/src/language-features/custom-derive.md similarity index 100% rename from src/doc/unstable-book/src/custom-derive.md rename to src/doc/unstable-book/src/language-features/custom-derive.md diff --git a/src/doc/unstable-book/src/default-type-parameter-fallback.md b/src/doc/unstable-book/src/language-features/default-type-parameter-fallback.md similarity index 100% rename from src/doc/unstable-book/src/default-type-parameter-fallback.md rename to src/doc/unstable-book/src/language-features/default-type-parameter-fallback.md diff --git a/src/doc/unstable-book/src/drop-types-in-const.md b/src/doc/unstable-book/src/language-features/drop-types-in-const.md similarity index 100% rename from src/doc/unstable-book/src/drop-types-in-const.md rename to src/doc/unstable-book/src/language-features/drop-types-in-const.md diff --git a/src/doc/unstable-book/src/dropck-eyepatch.md b/src/doc/unstable-book/src/language-features/dropck-eyepatch.md similarity index 100% rename from src/doc/unstable-book/src/dropck-eyepatch.md rename to src/doc/unstable-book/src/language-features/dropck-eyepatch.md diff --git a/src/doc/unstable-book/src/dropck-parametricity.md b/src/doc/unstable-book/src/language-features/dropck-parametricity.md similarity index 100% rename from src/doc/unstable-book/src/dropck-parametricity.md rename to src/doc/unstable-book/src/language-features/dropck-parametricity.md diff --git a/src/doc/unstable-book/src/exclusive-range-pattern.md b/src/doc/unstable-book/src/language-features/exclusive-range-pattern.md similarity index 100% rename from src/doc/unstable-book/src/exclusive-range-pattern.md rename to src/doc/unstable-book/src/language-features/exclusive-range-pattern.md diff --git a/src/doc/unstable-book/src/fundamental.md b/src/doc/unstable-book/src/language-features/fundamental.md similarity index 100% rename from src/doc/unstable-book/src/fundamental.md rename to src/doc/unstable-book/src/language-features/fundamental.md diff --git a/src/doc/unstable-book/src/generic-param-attrs.md b/src/doc/unstable-book/src/language-features/generic-param-attrs.md similarity index 100% rename from src/doc/unstable-book/src/generic-param-attrs.md rename to src/doc/unstable-book/src/language-features/generic-param-attrs.md diff --git a/src/doc/unstable-book/src/language-features/global_asm.md b/src/doc/unstable-book/src/language-features/global_asm.md new file mode 100644 index 000000000000..44921aa309f8 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/global_asm.md @@ -0,0 +1,78 @@ +# `global_asm` + +The tracking issue for this feature is: [#35119] + +[#35119]: https://github.com/rust-lang/rust/issues/35119 + +------------------------ + +The `global_asm!` macro allows the programmer to write arbitrary +assembly outside the scope of a function body, passing it through +`rustc` and `llvm` to the assembler. The macro is a no-frills +interface to LLVM's concept of [module-level inline assembly]. That is, +all caveats applicable to LLVM's module-level inline assembly apply +to `global_asm!`. + +[module-level inline assembly]: http://llvm.org/docs/LangRef.html#module-level-inline-assembly + +`global_asm!` fills a role not currently satisfied by either `asm!` +or `#[naked]` functions. The programmer has _all_ features of the +assembler at their disposal. The linker will expect to resolve any +symbols defined in the inline assembly, modulo any symbols marked as +external. It also means syntax for directives and assembly follow the +conventions of the assembler in your toolchain. + +A simple usage looks like this: + +```rust,ignore +# #![feature(global_asm)] +# you also need relevant target_arch cfgs +global_asm!(include_str!("something_neato.s")); +``` + +And a more complicated usage looks like this: + +```rust,ignore +# #![feature(global_asm)] +# #![cfg(any(target_arch = "x86", target_arch = "x86_64"))] + +pub mod sally { + global_asm!(r#" + .global foo + foo: + jmp baz + "#); + + #[no_mangle] + pub unsafe extern "C" fn baz() {} +} + +// the symbols `foo` and `bar` are global, no matter where +// `global_asm!` was used. +extern "C" { + fn foo(); + fn bar(); +} + +pub mod harry { + global_asm!(r#" + .global bar + bar: + jmp quux + "#); + + #[no_mangle] + pub unsafe extern "C" fn quux() {} +} +``` + +You may use `global_asm!` multiple times, anywhere in your crate, in +whatever way suits you. The effect is as if you concatenated all +usages and placed the larger, single usage in the crate root. + +------------------------ + +If you don't need quite as much power and flexibility as +`global_asm!` provides, and you don't mind restricting your inline +assembly to `fn` bodies only, you might try the [asm](asm.html) +feature instead. diff --git a/src/doc/unstable-book/src/i128-type.md b/src/doc/unstable-book/src/language-features/i128-type.md similarity index 100% rename from src/doc/unstable-book/src/i128-type.md rename to src/doc/unstable-book/src/language-features/i128-type.md diff --git a/src/doc/unstable-book/src/language-features/inclusive-range-syntax.md b/src/doc/unstable-book/src/language-features/inclusive-range-syntax.md new file mode 100644 index 000000000000..255445c318dc --- /dev/null +++ b/src/doc/unstable-book/src/language-features/inclusive-range-syntax.md @@ -0,0 +1,20 @@ +# `inclusive_range_syntax` + +The tracking issue for this feature is: [#28237] + +[#28237]: https://github.com/rust-lang/rust/issues/28237 + +------------------------ + +To get a range that goes from 0 to 10 and includes the value 10, you +can write `0...10`: + +```rust +#![feature(inclusive_range_syntax)] + +fn main() { + for i in 0...10 { + println!("{}", i); + } +} +``` diff --git a/src/doc/unstable-book/src/intrinsics.md b/src/doc/unstable-book/src/language-features/intrinsics.md similarity index 100% rename from src/doc/unstable-book/src/intrinsics.md rename to src/doc/unstable-book/src/language-features/intrinsics.md diff --git a/src/doc/unstable-book/src/lang-items.md b/src/doc/unstable-book/src/language-features/lang-items.md similarity index 100% rename from src/doc/unstable-book/src/lang-items.md rename to src/doc/unstable-book/src/language-features/lang-items.md diff --git a/src/doc/unstable-book/src/link-args.md b/src/doc/unstable-book/src/language-features/link-args.md similarity index 100% rename from src/doc/unstable-book/src/link-args.md rename to src/doc/unstable-book/src/language-features/link-args.md diff --git a/src/doc/unstable-book/src/link-cfg.md b/src/doc/unstable-book/src/language-features/link-cfg.md similarity index 100% rename from src/doc/unstable-book/src/link-cfg.md rename to src/doc/unstable-book/src/language-features/link-cfg.md diff --git a/src/doc/unstable-book/src/link-llvm-intrinsics.md b/src/doc/unstable-book/src/language-features/link-llvm-intrinsics.md similarity index 100% rename from src/doc/unstable-book/src/link-llvm-intrinsics.md rename to src/doc/unstable-book/src/language-features/link-llvm-intrinsics.md diff --git a/src/doc/unstable-book/src/linkage.md b/src/doc/unstable-book/src/language-features/linkage.md similarity index 100% rename from src/doc/unstable-book/src/linkage.md rename to src/doc/unstable-book/src/language-features/linkage.md diff --git a/src/doc/unstable-book/src/log-syntax.md b/src/doc/unstable-book/src/language-features/log-syntax.md similarity index 100% rename from src/doc/unstable-book/src/log-syntax.md rename to src/doc/unstable-book/src/language-features/log-syntax.md diff --git a/src/doc/unstable-book/src/loop-break-value.md b/src/doc/unstable-book/src/language-features/loop-break-value.md similarity index 100% rename from src/doc/unstable-book/src/loop-break-value.md rename to src/doc/unstable-book/src/language-features/loop-break-value.md diff --git a/src/doc/unstable-book/src/macro-reexport.md b/src/doc/unstable-book/src/language-features/macro-reexport.md similarity index 100% rename from src/doc/unstable-book/src/macro-reexport.md rename to src/doc/unstable-book/src/language-features/macro-reexport.md diff --git a/src/doc/unstable-book/src/language-features/macro-vis-matcher.md b/src/doc/unstable-book/src/language-features/macro-vis-matcher.md new file mode 100644 index 000000000000..7918a3568432 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/macro-vis-matcher.md @@ -0,0 +1,14 @@ +# `macro_vis_matcher` + +The tracking issue for this feature is: [#41022] + +With this feature gate enabled, the [list of fragment specifiers][frags] gains one more entry: + +* `vis`: a visibility qualifier. Examples: nothing (default visibility); `pub`; `pub(crate)`. + +A `vis` variable may be followed by a comma, ident, type, or path. + +[#41022]: https://github.com/rust-lang/rust/issues/41022 +[frags]: ../book/first-edition/macros.html#syntactic-requirements + +------------------------ diff --git a/src/doc/unstable-book/src/main.md b/src/doc/unstable-book/src/language-features/main.md similarity index 100% rename from src/doc/unstable-book/src/main.md rename to src/doc/unstable-book/src/language-features/main.md diff --git a/src/doc/unstable-book/src/naked-functions.md b/src/doc/unstable-book/src/language-features/naked-functions.md similarity index 100% rename from src/doc/unstable-book/src/naked-functions.md rename to src/doc/unstable-book/src/language-features/naked-functions.md diff --git a/src/doc/unstable-book/src/needs-allocator.md b/src/doc/unstable-book/src/language-features/needs-allocator.md similarity index 100% rename from src/doc/unstable-book/src/needs-allocator.md rename to src/doc/unstable-book/src/language-features/needs-allocator.md diff --git a/src/doc/unstable-book/src/needs-panic-runtime.md b/src/doc/unstable-book/src/language-features/needs-panic-runtime.md similarity index 100% rename from src/doc/unstable-book/src/needs-panic-runtime.md rename to src/doc/unstable-book/src/language-features/needs-panic-runtime.md diff --git a/src/doc/unstable-book/src/never-type.md b/src/doc/unstable-book/src/language-features/never-type.md similarity index 100% rename from src/doc/unstable-book/src/never-type.md rename to src/doc/unstable-book/src/language-features/never-type.md diff --git a/src/doc/unstable-book/src/no-core.md b/src/doc/unstable-book/src/language-features/no-core.md similarity index 100% rename from src/doc/unstable-book/src/no-core.md rename to src/doc/unstable-book/src/language-features/no-core.md diff --git a/src/doc/unstable-book/src/no-debug.md b/src/doc/unstable-book/src/language-features/no-debug.md similarity index 100% rename from src/doc/unstable-book/src/no-debug.md rename to src/doc/unstable-book/src/language-features/no-debug.md diff --git a/src/doc/unstable-book/src/non-ascii-idents.md b/src/doc/unstable-book/src/language-features/non-ascii-idents.md similarity index 100% rename from src/doc/unstable-book/src/non-ascii-idents.md rename to src/doc/unstable-book/src/language-features/non-ascii-idents.md diff --git a/src/doc/unstable-book/src/omit-gdb-pretty-printer-section.md b/src/doc/unstable-book/src/language-features/omit-gdb-pretty-printer-section.md similarity index 100% rename from src/doc/unstable-book/src/omit-gdb-pretty-printer-section.md rename to src/doc/unstable-book/src/language-features/omit-gdb-pretty-printer-section.md diff --git a/src/doc/unstable-book/src/on-unimplemented.md b/src/doc/unstable-book/src/language-features/on-unimplemented.md similarity index 100% rename from src/doc/unstable-book/src/on-unimplemented.md rename to src/doc/unstable-book/src/language-features/on-unimplemented.md diff --git a/src/doc/unstable-book/src/optin-builtin-traits.md b/src/doc/unstable-book/src/language-features/optin-builtin-traits.md similarity index 100% rename from src/doc/unstable-book/src/optin-builtin-traits.md rename to src/doc/unstable-book/src/language-features/optin-builtin-traits.md diff --git a/src/doc/unstable-book/src/language-features/overlapping-marker-traits.md b/src/doc/unstable-book/src/language-features/overlapping-marker-traits.md new file mode 100644 index 000000000000..a4920839c6ca --- /dev/null +++ b/src/doc/unstable-book/src/language-features/overlapping-marker-traits.md @@ -0,0 +1,7 @@ +# `overlapping_marker_traits` + +The tracking issue for this feature is: [#29864] + +[#29864]: https://github.com/rust-lang/rust/issues/29864 + +------------------------ diff --git a/src/doc/unstable-book/src/panic-runtime.md b/src/doc/unstable-book/src/language-features/panic-runtime.md similarity index 100% rename from src/doc/unstable-book/src/panic-runtime.md rename to src/doc/unstable-book/src/language-features/panic-runtime.md diff --git a/src/doc/unstable-book/src/placement-in-syntax.md b/src/doc/unstable-book/src/language-features/placement-in-syntax.md similarity index 100% rename from src/doc/unstable-book/src/placement-in-syntax.md rename to src/doc/unstable-book/src/language-features/placement-in-syntax.md diff --git a/src/doc/unstable-book/src/platform-intrinsics.md b/src/doc/unstable-book/src/language-features/platform-intrinsics.md similarity index 100% rename from src/doc/unstable-book/src/platform-intrinsics.md rename to src/doc/unstable-book/src/language-features/platform-intrinsics.md diff --git a/src/doc/unstable-book/src/plugin-registrar.md b/src/doc/unstable-book/src/language-features/plugin-registrar.md similarity index 100% rename from src/doc/unstable-book/src/plugin-registrar.md rename to src/doc/unstable-book/src/language-features/plugin-registrar.md diff --git a/src/doc/unstable-book/src/plugin.md b/src/doc/unstable-book/src/language-features/plugin.md similarity index 100% rename from src/doc/unstable-book/src/plugin.md rename to src/doc/unstable-book/src/language-features/plugin.md diff --git a/src/doc/unstable-book/src/prelude-import.md b/src/doc/unstable-book/src/language-features/prelude-import.md similarity index 100% rename from src/doc/unstable-book/src/prelude-import.md rename to src/doc/unstable-book/src/language-features/prelude-import.md diff --git a/src/doc/unstable-book/src/proc-macro.md b/src/doc/unstable-book/src/language-features/proc-macro.md similarity index 100% rename from src/doc/unstable-book/src/proc-macro.md rename to src/doc/unstable-book/src/language-features/proc-macro.md diff --git a/src/doc/unstable-book/src/quote.md b/src/doc/unstable-book/src/language-features/quote.md similarity index 100% rename from src/doc/unstable-book/src/quote.md rename to src/doc/unstable-book/src/language-features/quote.md diff --git a/src/doc/unstable-book/src/relaxed-adts.md b/src/doc/unstable-book/src/language-features/relaxed-adts.md similarity index 100% rename from src/doc/unstable-book/src/relaxed-adts.md rename to src/doc/unstable-book/src/language-features/relaxed-adts.md diff --git a/src/doc/unstable-book/src/language-features/repr-align.md b/src/doc/unstable-book/src/language-features/repr-align.md new file mode 100644 index 000000000000..deea04f4c51c --- /dev/null +++ b/src/doc/unstable-book/src/language-features/repr-align.md @@ -0,0 +1,11 @@ +# `repr_align` + +The tracking issue for this feature is: [#33626] + +[#33626]: https://github.com/rust-lang/rust/issues/33626 + +------------------------ + + + + diff --git a/src/doc/unstable-book/src/repr-simd.md b/src/doc/unstable-book/src/language-features/repr-simd.md similarity index 100% rename from src/doc/unstable-book/src/repr-simd.md rename to src/doc/unstable-book/src/language-features/repr-simd.md diff --git a/src/doc/unstable-book/src/rustc-attrs.md b/src/doc/unstable-book/src/language-features/rustc-attrs.md similarity index 100% rename from src/doc/unstable-book/src/rustc-attrs.md rename to src/doc/unstable-book/src/language-features/rustc-attrs.md diff --git a/src/doc/unstable-book/src/rustc-diagnostic-macros.md b/src/doc/unstable-book/src/language-features/rustc-diagnostic-macros.md similarity index 100% rename from src/doc/unstable-book/src/rustc-diagnostic-macros.md rename to src/doc/unstable-book/src/language-features/rustc-diagnostic-macros.md diff --git a/src/doc/unstable-book/src/rvalue-static-promotion.md b/src/doc/unstable-book/src/language-features/rvalue-static-promotion.md similarity index 100% rename from src/doc/unstable-book/src/rvalue-static-promotion.md rename to src/doc/unstable-book/src/language-features/rvalue-static-promotion.md diff --git a/src/doc/unstable-book/src/sanitizer-runtime.md b/src/doc/unstable-book/src/language-features/sanitizer-runtime.md similarity index 100% rename from src/doc/unstable-book/src/sanitizer-runtime.md rename to src/doc/unstable-book/src/language-features/sanitizer-runtime.md diff --git a/src/doc/unstable-book/src/simd-ffi.md b/src/doc/unstable-book/src/language-features/simd-ffi.md similarity index 100% rename from src/doc/unstable-book/src/simd-ffi.md rename to src/doc/unstable-book/src/language-features/simd-ffi.md diff --git a/src/doc/unstable-book/src/simd.md b/src/doc/unstable-book/src/language-features/simd.md similarity index 100% rename from src/doc/unstable-book/src/simd.md rename to src/doc/unstable-book/src/language-features/simd.md diff --git a/src/doc/unstable-book/src/slice-patterns.md b/src/doc/unstable-book/src/language-features/slice-patterns.md similarity index 100% rename from src/doc/unstable-book/src/slice-patterns.md rename to src/doc/unstable-book/src/language-features/slice-patterns.md diff --git a/src/doc/unstable-book/src/specialization.md b/src/doc/unstable-book/src/language-features/specialization.md similarity index 62% rename from src/doc/unstable-book/src/specialization.md rename to src/doc/unstable-book/src/language-features/specialization.md index 59f27343b66d..efc380df6e11 100644 --- a/src/doc/unstable-book/src/specialization.md +++ b/src/doc/unstable-book/src/language-features/specialization.md @@ -2,6 +2,8 @@ The tracking issue for this feature is: [#31844] +[#31844]: https://github.com/rust-lang/rust/issues/31844 + ------------------------ diff --git a/src/doc/unstable-book/src/staged-api.md b/src/doc/unstable-book/src/language-features/staged-api.md similarity index 100% rename from src/doc/unstable-book/src/staged-api.md rename to src/doc/unstable-book/src/language-features/staged-api.md diff --git a/src/doc/unstable-book/src/start.md b/src/doc/unstable-book/src/language-features/start.md similarity index 100% rename from src/doc/unstable-book/src/start.md rename to src/doc/unstable-book/src/language-features/start.md diff --git a/src/doc/unstable-book/src/static-nobundle.md b/src/doc/unstable-book/src/language-features/static-nobundle.md similarity index 100% rename from src/doc/unstable-book/src/static-nobundle.md rename to src/doc/unstable-book/src/language-features/static-nobundle.md diff --git a/src/doc/unstable-book/src/stmt-expr-attributes.md b/src/doc/unstable-book/src/language-features/stmt-expr-attributes.md similarity index 100% rename from src/doc/unstable-book/src/stmt-expr-attributes.md rename to src/doc/unstable-book/src/language-features/stmt-expr-attributes.md diff --git a/src/doc/unstable-book/src/struct-field-attributes.md b/src/doc/unstable-book/src/language-features/struct-field-attributes.md similarity index 100% rename from src/doc/unstable-book/src/struct-field-attributes.md rename to src/doc/unstable-book/src/language-features/struct-field-attributes.md diff --git a/src/doc/unstable-book/src/structural-match.md b/src/doc/unstable-book/src/language-features/structural-match.md similarity index 100% rename from src/doc/unstable-book/src/structural-match.md rename to src/doc/unstable-book/src/language-features/structural-match.md diff --git a/src/doc/unstable-book/src/target-feature.md b/src/doc/unstable-book/src/language-features/target-feature.md similarity index 100% rename from src/doc/unstable-book/src/target-feature.md rename to src/doc/unstable-book/src/language-features/target-feature.md diff --git a/src/doc/unstable-book/src/thread-local.md b/src/doc/unstable-book/src/language-features/thread-local.md similarity index 100% rename from src/doc/unstable-book/src/thread-local.md rename to src/doc/unstable-book/src/language-features/thread-local.md diff --git a/src/doc/unstable-book/src/trace-macros.md b/src/doc/unstable-book/src/language-features/trace-macros.md similarity index 100% rename from src/doc/unstable-book/src/trace-macros.md rename to src/doc/unstable-book/src/language-features/trace-macros.md diff --git a/src/doc/unstable-book/src/type-ascription.md b/src/doc/unstable-book/src/language-features/type-ascription.md similarity index 100% rename from src/doc/unstable-book/src/type-ascription.md rename to src/doc/unstable-book/src/language-features/type-ascription.md diff --git a/src/doc/unstable-book/src/unboxed-closures.md b/src/doc/unstable-book/src/language-features/unboxed-closures.md similarity index 100% rename from src/doc/unstable-book/src/unboxed-closures.md rename to src/doc/unstable-book/src/language-features/unboxed-closures.md diff --git a/src/doc/unstable-book/src/untagged-unions.md b/src/doc/unstable-book/src/language-features/untagged-unions.md similarity index 100% rename from src/doc/unstable-book/src/untagged-unions.md rename to src/doc/unstable-book/src/language-features/untagged-unions.md diff --git a/src/doc/unstable-book/src/unwind-attributes.md b/src/doc/unstable-book/src/language-features/unwind-attributes.md similarity index 100% rename from src/doc/unstable-book/src/unwind-attributes.md rename to src/doc/unstable-book/src/language-features/unwind-attributes.md diff --git a/src/doc/unstable-book/src/use-extern-macros.md b/src/doc/unstable-book/src/language-features/use-extern-macros.md similarity index 100% rename from src/doc/unstable-book/src/use-extern-macros.md rename to src/doc/unstable-book/src/language-features/use-extern-macros.md diff --git a/src/doc/unstable-book/src/language-features/used.md b/src/doc/unstable-book/src/language-features/used.md new file mode 100644 index 000000000000..75a8b2774f42 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/used.md @@ -0,0 +1,153 @@ +# `used` + +The tracking issue for this feature +is: [40289](https://github.com/rust-lang/rust/issues/40289). + +------------------------ + +The `#[used]` attribute can be applied to `static` variables to prevent the Rust +compiler from optimizing them away even if they appear to be unused by the crate +(appear to be "dead code"). + +``` rust +#![feature(used)] + +#[used] +static FOO: i32 = 1; + +static BAR: i32 = 2; + +fn main() {} +``` + +If you compile this program into an object file, you'll see that `FOO` makes it +to the object file but `BAR` doesn't. Neither static variable is used by the +program. + +``` text +$ rustc -C opt-level=3 --emit=obj used.rs + +$ nm -C used.o +0000000000000000 T main + U std::rt::lang_start +0000000000000000 r used::FOO +0000000000000000 t used::main +``` + +Note that the *linker* knows nothing about the `#[used]` attribute and will +remove `#[used]` symbols if they are not referenced by other parts of the +program: + +``` text +$ rustc -C opt-level=3 used.rs + +$ nm -C used | grep FOO +``` + +"This doesn't sound too useful then!" you may think but keep reading. + +To preserve the symbols all the way to the final binary, you'll need the +cooperation of the linker. Here's one example: + +The ELF standard defines two special sections, `.init_array` and +`.pre_init_array`, that may contain function pointers which will be executed +*before* the `main` function is invoked. The linker will preserve symbols placed +in these sections (at least when linking programs that target the `*-*-linux-*` +targets). + +``` rust,ignore +#![feature(used)] + +extern "C" fn before_main() { + println!("Hello, world!"); +} + +#[link_section = ".init_array"] +#[used] +static INIT_ARRAY: [extern "C" fn(); 1] = [before_main]; + +fn main() {} +``` + +So, `#[used]` and `#[link_section]` can be combined to obtain "life before +main". + +``` text +$ rustc -C opt-level=3 before-main.rs + +$ ./before-main +Hello, world! +``` + +Another example: ARM Cortex-M microcontrollers need their reset handler, a +pointer to the function that will executed right after the microcontroller is +turned on, to be placed near the start of their FLASH memory to boot properly. + +This condition can be met using `#[used]` and `#[link_section]` plus a linker +script. + +``` rust,ignore +#![feature(lang_items)] +#![feature(used)] +#![no_main] +#![no_std] + +extern "C" fn reset_handler() -> ! { + loop {} +} + +#[link_section = ".reset_handler"] +#[used] +static RESET_HANDLER: extern "C" fn() -> ! = reset_handler; + +#[lang = "panic_fmt"] +fn panic_fmt() {} +``` + +``` text +MEMORY +{ + FLASH : ORIGIN = 0x08000000, LENGTH = 128K + RAM : ORIGIN = 0x20000000, LENGTH = 20K +} + +SECTIONS +{ + .text ORIGIN(FLASH) : + { + /* Vector table */ + LONG(ORIGIN(RAM) + LENGTH(RAM)); /* initial SP value */ + KEEP(*(.reset_handler)); + + /* Omitted: The rest of the vector table */ + + *(.text.*); + } > FLASH + + /DISCARD/ : + { + /* Unused unwinding stuff */ + *(.ARM.exidx.*) + } +} +``` + +``` text +$ xargo rustc --target thumbv7m-none-eabi --release -- \ + -C link-arg=-Tlink.x -C link-arg=-nostartfiles + +$ arm-none-eabi-objdump -Cd target/thumbv7m-none-eabi/release/app +./target/thumbv7m-none-eabi/release/app: file format elf32-littlearm + + +Disassembly of section .text: + +08000000 : + 8000000: 20005000 .word 0x20005000 + +08000004 : + 8000004: 08000009 .... + +08000008 : + 8000008: e7fe b.n 8000008 +``` diff --git a/src/doc/unstable-book/src/library-features.md b/src/doc/unstable-book/src/library-features.md new file mode 100644 index 000000000000..9f537e26132b --- /dev/null +++ b/src/doc/unstable-book/src/library-features.md @@ -0,0 +1 @@ +# Library Features diff --git a/src/doc/unstable-book/src/alloc-jemalloc.md b/src/doc/unstable-book/src/library-features/alloc-jemalloc.md similarity index 100% rename from src/doc/unstable-book/src/alloc-jemalloc.md rename to src/doc/unstable-book/src/library-features/alloc-jemalloc.md diff --git a/src/doc/unstable-book/src/alloc-system.md b/src/doc/unstable-book/src/library-features/alloc-system.md similarity index 100% rename from src/doc/unstable-book/src/alloc-system.md rename to src/doc/unstable-book/src/library-features/alloc-system.md diff --git a/src/doc/unstable-book/src/library-features/alloc.md b/src/doc/unstable-book/src/library-features/alloc.md new file mode 100644 index 000000000000..47eeb0874fba --- /dev/null +++ b/src/doc/unstable-book/src/library-features/alloc.md @@ -0,0 +1,7 @@ +# `alloc` + +The tracking issue for this feature is: [#27783] + +[#27783]: https://github.com/rust-lang/rust/issues/27783 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/as-c-str.md b/src/doc/unstable-book/src/library-features/as-c-str.md new file mode 100644 index 000000000000..ed32eedb3481 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/as-c-str.md @@ -0,0 +1,8 @@ +# `as_c_str` + +The tracking issue for this feature is: [#40380] + +[#40380]: https://github.com/rust-lang/rust/issues/40380 + +------------------------ + diff --git a/src/doc/unstable-book/src/library-features/ascii-ctype.md b/src/doc/unstable-book/src/library-features/ascii-ctype.md new file mode 100644 index 000000000000..e253b4dcd9b5 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/ascii-ctype.md @@ -0,0 +1,5 @@ +# `ascii_ctype` + +The tracking issue for this feature is: [#39658] + +[#39658]: https://github.com/rust-lang/rust/issues/39658 diff --git a/src/doc/unstable-book/src/library-features/binary-heap-peek-mut-pop.md b/src/doc/unstable-book/src/library-features/binary-heap-peek-mut-pop.md new file mode 100644 index 000000000000..f3863ab2a2ab --- /dev/null +++ b/src/doc/unstable-book/src/library-features/binary-heap-peek-mut-pop.md @@ -0,0 +1,7 @@ +# `binary_heap_peek_mut_pop` + +The tracking issue for this feature is: [#38863] + +[#38863]: https://github.com/rust-lang/rust/issues/38863 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/box-heap.md b/src/doc/unstable-book/src/library-features/box-heap.md new file mode 100644 index 000000000000..0f3f01ba0e16 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/box-heap.md @@ -0,0 +1,7 @@ +# `box_heap` + +The tracking issue for this feature is: [#27779] + +[#27779]: https://github.com/rust-lang/rust/issues/27779 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/c-void-variant.md b/src/doc/unstable-book/src/library-features/c-void-variant.md new file mode 100644 index 000000000000..a2fdc9936300 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/c-void-variant.md @@ -0,0 +1,5 @@ +# `c_void_variant` + +This feature is internal to the Rust compiler and is not intended for general use. + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/char-escape-debug.md b/src/doc/unstable-book/src/library-features/char-escape-debug.md new file mode 100644 index 000000000000..21aa486219e0 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/char-escape-debug.md @@ -0,0 +1,7 @@ +# `char_escape_debug` + +The tracking issue for this feature is: [#35068] + +[#35068]: https://github.com/rust-lang/rust/issues/35068 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/coerce-unsized.md b/src/doc/unstable-book/src/library-features/coerce-unsized.md new file mode 100644 index 000000000000..078d3faf42a7 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/coerce-unsized.md @@ -0,0 +1,7 @@ +# `coerce_unsized` + +The tracking issue for this feature is: [#27732] + +[#27732]: https://github.com/rust-lang/rust/issues/27732 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/collection-placement.md b/src/doc/unstable-book/src/library-features/collection-placement.md new file mode 100644 index 000000000000..268ca6ea590d --- /dev/null +++ b/src/doc/unstable-book/src/library-features/collection-placement.md @@ -0,0 +1,7 @@ +# `collection_placement` + +The tracking issue for this feature is: [#30172] + +[#30172]: https://github.com/rust-lang/rust/issues/30172 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/collections-range.md b/src/doc/unstable-book/src/library-features/collections-range.md new file mode 100644 index 000000000000..ea4f999ba0f9 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/collections-range.md @@ -0,0 +1,7 @@ +# `collections_range` + +The tracking issue for this feature is: [#30877] + +[#30877]: https://github.com/rust-lang/rust/issues/30877 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/collections.md b/src/doc/unstable-book/src/library-features/collections.md new file mode 100644 index 000000000000..5c937833c9e2 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/collections.md @@ -0,0 +1,5 @@ +# `collections` + +This feature is internal to the Rust compiler and is not intended for general use. + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/command-envs.md b/src/doc/unstable-book/src/library-features/command-envs.md new file mode 100644 index 000000000000..0ab89e278cdf --- /dev/null +++ b/src/doc/unstable-book/src/library-features/command-envs.md @@ -0,0 +1,7 @@ +# `command_envs` + +The tracking issue for this feature is: [#38526] + +[#38526]: https://github.com/rust-lang/rust/issues/38526 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/compiler-builtins-lib.md b/src/doc/unstable-book/src/library-features/compiler-builtins-lib.md new file mode 100644 index 000000000000..5da8968fd0ce --- /dev/null +++ b/src/doc/unstable-book/src/library-features/compiler-builtins-lib.md @@ -0,0 +1,35 @@ +# `compiler_builtins_lib` + +The tracking issue for this feature is: None. + +------------------------ + +This feature is required to link to the `compiler_builtins` crate which contains +"compiler intrinsics". Compiler intrinsics are software implementations of basic +operations like multiplication of `u64`s. These intrinsics are only required on +platforms where these operations don't directly map to a hardware instruction. + +You should never need to explicitly link to the `compiler_builtins` crate when +building "std" programs as `compiler_builtins` is already in the dependency +graph of `std`. But you may need it when building `no_std` **binary** crates. If +you get a *linker* error like: + +``` text +$PWD/src/main.rs:11: undefined reference to `__aeabi_lmul' +$PWD/src/main.rs:11: undefined reference to `__aeabi_uldivmod' +``` + +That means that you need to link to this crate. + +When you link to this crate, make sure it only appears once in your crate +dependency graph. Also, it doesn't matter where in the dependency graph, you +place the `compiler_builtins` crate. + + + +``` rust,ignore +#![feature(compiler_builtins_lib)] +#![no_std] + +extern crate compiler_builtins; +``` diff --git a/src/doc/unstable-book/src/library-features/compiler-fences.md b/src/doc/unstable-book/src/library-features/compiler-fences.md new file mode 100644 index 000000000000..b1e36ab13d5a --- /dev/null +++ b/src/doc/unstable-book/src/library-features/compiler-fences.md @@ -0,0 +1,106 @@ +# `compiler_fences` + +The tracking issue for this feature is: [#41091] + +[#41091]: https://github.com/rust-lang/rust/issues/41091 + +------------------------ + +The `compiler_fences` feature exposes the `compiler_fence` function +in `std::sync::atomic`. This function is conceptually similar to C++'s +`atomic_signal_fence`, which can currently only be accessed in nightly +Rust using the `atomic_singlethreadfence_*` instrinsic functions in +`core`, or through the mostly equivalent literal assembly: + +```rust +#![feature(asm)] +unsafe { asm!("" ::: "memory" : "volatile") }; +``` + +A `compiler_fence` restricts the kinds of memory re-ordering the +compiler is allowed to do. Specifically, depending on the given ordering +semantics, the compiler may be disallowed from moving reads or writes +from before or after the call to the other side of the call to +`compiler_fence`. Note that it does **not** prevent the *hardware* +from doing such re-ordering. This is not a problem in a single-threaded, +execution context, but when other threads may modify memory at the same +time, stronger synchronization primitives are required. + +## Examples + +`compiler_fence` is generally only useful for preventing a thread from +racing *with itself*. That is, if a given thread is executing one piece +of code, and is then interrupted, and starts executing code elsewhere +(while still in the same thread, and conceptually still on the same +core). In traditional programs, this can only occur when a signal +handler is registered. In more low-level code, such situations can also +arise when handling interrupts, when implementing green threads with +pre-emption, etc. + +To give a straightforward example of when a `compiler_fence` is +necessary, consider the following example: + +```rust +# use std::sync::atomic::{AtomicBool, AtomicUsize}; +# use std::sync::atomic::{ATOMIC_BOOL_INIT, ATOMIC_USIZE_INIT}; +# use std::sync::atomic::Ordering; +static IMPORTANT_VARIABLE: AtomicUsize = ATOMIC_USIZE_INIT; +static IS_READY: AtomicBool = ATOMIC_BOOL_INIT; + +fn main() { + IMPORTANT_VARIABLE.store(42, Ordering::Relaxed); + IS_READY.store(true, Ordering::Relaxed); +} + +fn signal_handler() { + if IS_READY.load(Ordering::Relaxed) { + assert_eq!(IMPORTANT_VARIABLE.load(Ordering::Relaxed), 42); + } +} +``` + +The way it is currently written, the `assert_eq!` is *not* guaranteed to +succeed, despite everything happening in a single thread. To see why, +remember that the compiler is free to swap the stores to +`IMPORTANT_VARIABLE` and `IS_READ` since they are both +`Ordering::Relaxed`. If it does, and the signal handler is invoked right +after `IS_READY` is updated, then the signal handler will see +`IS_READY=1`, but `IMPORTANT_VARIABLE=0`. + +Using a `compiler_fence`, we can remedy this situation: + +```rust +#![feature(compiler_fences)] +# 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; + +fn main() { + IMPORTANT_VARIABLE.store(42, Ordering::Relaxed); + // prevent earlier writes from being moved beyond this point + compiler_fence(Ordering::Release); + IS_READY.store(true, Ordering::Relaxed); +} + +fn signal_handler() { + if IS_READY.load(Ordering::Relaxed) { + assert_eq!(IMPORTANT_VARIABLE.load(Ordering::Relaxed), 42); + } +} +``` + +A deeper discussion of compiler barriers with various re-ordering +semantics (such as `Ordering::SeqCst`) is beyond the scope of this text. +Curious readers are encouraged to read the Linux kernel's discussion of +[memory barriers][1], the C++ references on [`std::memory_order`][2] and +[`atomic_signal_fence`][3], and [this StackOverflow answer][4] for +further details. + +[1]: https://www.kernel.org/doc/Documentation/memory-barriers.txt +[2]: http://en.cppreference.com/w/cpp/atomic/memory_order +[3]: http://www.cplusplus.com/reference/atomic/atomic_signal_fence/ +[4]: http://stackoverflow.com/a/18454971/472927 diff --git a/src/doc/unstable-book/src/library-features/concat-idents-macro.md b/src/doc/unstable-book/src/library-features/concat-idents-macro.md new file mode 100644 index 000000000000..ac2fdd4fceb6 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/concat-idents-macro.md @@ -0,0 +1,7 @@ +# `concat_idents_macro` + +The tracking issue for this feature is: [#29599] + +[#29599]: https://github.com/rust-lang/rust/issues/29599 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/core-char-ext.md b/src/doc/unstable-book/src/library-features/core-char-ext.md new file mode 100644 index 000000000000..d37d6b5c6d0b --- /dev/null +++ b/src/doc/unstable-book/src/library-features/core-char-ext.md @@ -0,0 +1,7 @@ +# `core_char_ext` + +The tracking issue for this feature is: [#32110] + +[#32110]: https://github.com/rust-lang/rust/issues/32110 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/core-float.md b/src/doc/unstable-book/src/library-features/core-float.md new file mode 100644 index 000000000000..194b2608dd02 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/core-float.md @@ -0,0 +1,7 @@ +# `core_float` + +The tracking issue for this feature is: [#32110] + +[#32110]: https://github.com/rust-lang/rust/issues/32110 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/core-intrinsics.md b/src/doc/unstable-book/src/library-features/core-intrinsics.md new file mode 100644 index 000000000000..28ad3525ef7a --- /dev/null +++ b/src/doc/unstable-book/src/library-features/core-intrinsics.md @@ -0,0 +1,5 @@ +# `core_intrinsics` + +This feature is internal to the Rust compiler and is not intended for general use. + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/core-panic.md b/src/doc/unstable-book/src/library-features/core-panic.md new file mode 100644 index 000000000000..c197588404c9 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/core-panic.md @@ -0,0 +1,5 @@ +# `core_panic` + +This feature is internal to the Rust compiler and is not intended for general use. + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/core-private-bignum.md b/src/doc/unstable-book/src/library-features/core-private-bignum.md new file mode 100644 index 000000000000..f85811c545e4 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/core-private-bignum.md @@ -0,0 +1,5 @@ +# `core_private_bignum` + +This feature is internal to the Rust compiler and is not intended for general use. + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/core-private-diy-float.md b/src/doc/unstable-book/src/library-features/core-private-diy-float.md new file mode 100644 index 000000000000..8465921d673b --- /dev/null +++ b/src/doc/unstable-book/src/library-features/core-private-diy-float.md @@ -0,0 +1,5 @@ +# `core_private_diy_float` + +This feature is internal to the Rust compiler and is not intended for general use. + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/core-slice-ext.md b/src/doc/unstable-book/src/library-features/core-slice-ext.md new file mode 100644 index 000000000000..c50d44ac0ce3 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/core-slice-ext.md @@ -0,0 +1,7 @@ +# `core_slice_ext` + +The tracking issue for this feature is: [#32110] + +[#32110]: https://github.com/rust-lang/rust/issues/32110 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/core-str-ext.md b/src/doc/unstable-book/src/library-features/core-str-ext.md new file mode 100644 index 000000000000..08c68f11c6ec --- /dev/null +++ b/src/doc/unstable-book/src/library-features/core-str-ext.md @@ -0,0 +1,7 @@ +# `core_str_ext` + +The tracking issue for this feature is: [#32110] + +[#32110]: https://github.com/rust-lang/rust/issues/32110 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/dec2flt.md b/src/doc/unstable-book/src/library-features/dec2flt.md new file mode 100644 index 000000000000..311ab4adcfd7 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/dec2flt.md @@ -0,0 +1,5 @@ +# `dec2flt` + +This feature is internal to the Rust compiler and is not intended for general use. + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/decode-utf8.md b/src/doc/unstable-book/src/library-features/decode-utf8.md new file mode 100644 index 000000000000..b96854ebcd46 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/decode-utf8.md @@ -0,0 +1,7 @@ +# `decode_utf8` + +The tracking issue for this feature is: [#27783] + +[#27783]: https://github.com/rust-lang/rust/issues/27783 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/derive-clone-copy.md b/src/doc/unstable-book/src/library-features/derive-clone-copy.md new file mode 100644 index 000000000000..cc603911cbd2 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/derive-clone-copy.md @@ -0,0 +1,5 @@ +# `derive_clone_copy` + +This feature is internal to the Rust compiler and is not intended for general use. + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/derive-eq.md b/src/doc/unstable-book/src/library-features/derive-eq.md new file mode 100644 index 000000000000..68a275f5419d --- /dev/null +++ b/src/doc/unstable-book/src/library-features/derive-eq.md @@ -0,0 +1,5 @@ +# `derive_eq` + +This feature is internal to the Rust compiler and is not intended for general use. + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/discriminant-value.md b/src/doc/unstable-book/src/library-features/discriminant-value.md new file mode 100644 index 000000000000..2f99f5ecab39 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/discriminant-value.md @@ -0,0 +1,7 @@ +# `discriminant_value` + +The tracking issue for this feature is: [#24263] + +[#24263]: https://github.com/rust-lang/rust/issues/24263 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/error-type-id.md b/src/doc/unstable-book/src/library-features/error-type-id.md new file mode 100644 index 000000000000..be7a3ffd4dc4 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/error-type-id.md @@ -0,0 +1,7 @@ +# `error_type_id` + +The tracking issue for this feature is: [#27745] + +[#27745]: https://github.com/rust-lang/rust/issues/27745 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/exact-size-is-empty.md b/src/doc/unstable-book/src/library-features/exact-size-is-empty.md new file mode 100644 index 000000000000..200ec3872517 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/exact-size-is-empty.md @@ -0,0 +1,7 @@ +# `exact_size_is_empty` + +The tracking issue for this feature is: [#35428] + +[#35428]: https://github.com/rust-lang/rust/issues/35428 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/fd-read.md b/src/doc/unstable-book/src/library-features/fd-read.md new file mode 100644 index 000000000000..e78d4330abfc --- /dev/null +++ b/src/doc/unstable-book/src/library-features/fd-read.md @@ -0,0 +1,5 @@ +# `fd_read` + +This feature is internal to the Rust compiler and is not intended for general use. + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/fd.md b/src/doc/unstable-book/src/library-features/fd.md new file mode 100644 index 000000000000..0414244285ba --- /dev/null +++ b/src/doc/unstable-book/src/library-features/fd.md @@ -0,0 +1,5 @@ +# `fd` + +This feature is internal to the Rust compiler and is not intended for general use. + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/fixed-size-array.md b/src/doc/unstable-book/src/library-features/fixed-size-array.md new file mode 100644 index 000000000000..9e24e6a0850d --- /dev/null +++ b/src/doc/unstable-book/src/library-features/fixed-size-array.md @@ -0,0 +1,7 @@ +# `fixed_size_array` + +The tracking issue for this feature is: [#27778] + +[#27778]: https://github.com/rust-lang/rust/issues/27778 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/float-bits-conv.md b/src/doc/unstable-book/src/library-features/float-bits-conv.md new file mode 100644 index 000000000000..f519545ac78b --- /dev/null +++ b/src/doc/unstable-book/src/library-features/float-bits-conv.md @@ -0,0 +1,7 @@ +# `float_bits_conv` + +The tracking issue for this feature is: [#40470] + +[#40470]: https://github.com/rust-lang/rust/issues/40470 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/flt2dec.md b/src/doc/unstable-book/src/library-features/flt2dec.md new file mode 100644 index 000000000000..15e62a3a7dad --- /dev/null +++ b/src/doc/unstable-book/src/library-features/flt2dec.md @@ -0,0 +1,5 @@ +# `flt2dec` + +This feature is internal to the Rust compiler and is not intended for general use. + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/fmt-flags-align.md b/src/doc/unstable-book/src/library-features/fmt-flags-align.md new file mode 100644 index 000000000000..755263bd9a61 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/fmt-flags-align.md @@ -0,0 +1,7 @@ +# `fmt_flags_align` + +The tracking issue for this feature is: [#27726] + +[#27726]: https://github.com/rust-lang/rust/issues/27726 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/fmt-internals.md b/src/doc/unstable-book/src/library-features/fmt-internals.md new file mode 100644 index 000000000000..7cbe3c89a644 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/fmt-internals.md @@ -0,0 +1,5 @@ +# `fmt_internals` + +This feature is internal to the Rust compiler and is not intended for general use. + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/fn-traits.md b/src/doc/unstable-book/src/library-features/fn-traits.md new file mode 100644 index 000000000000..3942cda55388 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/fn-traits.md @@ -0,0 +1,7 @@ +# `fn_traits` + +The tracking issue for this feature is: [#29625] + +[#29625]: https://github.com/rust-lang/rust/issues/29625 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/fnbox.md b/src/doc/unstable-book/src/library-features/fnbox.md new file mode 100644 index 000000000000..a9b74d4f0047 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/fnbox.md @@ -0,0 +1,7 @@ +# `fnbox` + +The tracking issue for this feature is: [#28796] + +[#28796]: https://github.com/rust-lang/rust/issues/28796 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/from_utf8_error_as_bytes.md b/src/doc/unstable-book/src/library-features/from_utf8_error_as_bytes.md new file mode 100644 index 000000000000..570f779417f0 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/from_utf8_error_as_bytes.md @@ -0,0 +1,7 @@ +# `from_utf8_error_as_bytes` + +The tracking issue for this feature is: [#40895] + +[#40895]: https://github.com/rust-lang/rust/issues/40895 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/fused.md b/src/doc/unstable-book/src/library-features/fused.md new file mode 100644 index 000000000000..460555bf1b0d --- /dev/null +++ b/src/doc/unstable-book/src/library-features/fused.md @@ -0,0 +1,7 @@ +# `fused` + +The tracking issue for this feature is: [#35602] + +[#35602]: https://github.com/rust-lang/rust/issues/35602 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/future-atomic-orderings.md b/src/doc/unstable-book/src/library-features/future-atomic-orderings.md new file mode 100644 index 000000000000..40c2ef2db055 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/future-atomic-orderings.md @@ -0,0 +1,5 @@ +# `future_atomic_orderings` + +This feature is internal to the Rust compiler and is not intended for general use. + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/get-type-id.md b/src/doc/unstable-book/src/library-features/get-type-id.md new file mode 100644 index 000000000000..afdb030c406d --- /dev/null +++ b/src/doc/unstable-book/src/library-features/get-type-id.md @@ -0,0 +1,7 @@ +# `get_type_id` + +The tracking issue for this feature is: [#27745] + +[#27745]: https://github.com/rust-lang/rust/issues/27745 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/heap-api.md b/src/doc/unstable-book/src/library-features/heap-api.md new file mode 100644 index 000000000000..01404e49dbda --- /dev/null +++ b/src/doc/unstable-book/src/library-features/heap-api.md @@ -0,0 +1,7 @@ +# `heap_api` + +The tracking issue for this feature is: [#27700] + +[#27700]: https://github.com/rust-lang/rust/issues/27700 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/hint-core-should-pause.md b/src/doc/unstable-book/src/library-features/hint-core-should-pause.md new file mode 100644 index 000000000000..05e057be4932 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/hint-core-should-pause.md @@ -0,0 +1,41 @@ +# `hint_core_should_pause` + +The tracking issue for this feature is: [#41196] + +[#41196]: https://github.com/rust-lang/rust/issues/41196 + +------------------------ + +Many programs have spin loops like the following: + +```rust,no_run +use std::sync::atomic::{AtomicBool,Ordering}; + +fn spin_loop(value: &AtomicBool) { + loop { + if value.load(Ordering::Acquire) { + break; + } + } +} +``` + +These programs can be improved in performance like so: + +```rust,no_run +#![feature(hint_core_should_pause)] +use std::sync::atomic; +use std::sync::atomic::{AtomicBool,Ordering}; + +fn spin_loop(value: &AtomicBool) { + loop { + if value.load(Ordering::Acquire) { + break; + } + atomic::hint_core_should_pause(); + } +} +``` + +Further improvements could combine `hint_core_should_pause` with +exponential backoff or `std::thread::yield_now`. diff --git a/src/doc/unstable-book/src/library-features/i128.md b/src/doc/unstable-book/src/library-features/i128.md new file mode 100644 index 000000000000..a1a7ce8e63f4 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/i128.md @@ -0,0 +1,7 @@ +# `i128` + +The tracking issue for this feature is: [#35118] + +[#35118]: https://github.com/rust-lang/rust/issues/35118 + +------------------------ diff --git a/src/doc/unstable-book/src/inclusive-range-syntax.md b/src/doc/unstable-book/src/library-features/inclusive-range.md similarity index 81% rename from src/doc/unstable-book/src/inclusive-range-syntax.md rename to src/doc/unstable-book/src/library-features/inclusive-range.md index 74d85536399d..2e88e2047868 100644 --- a/src/doc/unstable-book/src/inclusive-range-syntax.md +++ b/src/doc/unstable-book/src/library-features/inclusive-range.md @@ -1,10 +1,7 @@ -# `inclusive_range_syntax` +# `inclusive_range` The tracking issue for this feature is: [#28237] [#28237]: https://github.com/rust-lang/rust/issues/28237 ------------------------ - - - diff --git a/src/doc/unstable-book/src/library-features/int-error-internals.md b/src/doc/unstable-book/src/library-features/int-error-internals.md new file mode 100644 index 000000000000..402e4fa5ef6d --- /dev/null +++ b/src/doc/unstable-book/src/library-features/int-error-internals.md @@ -0,0 +1,5 @@ +# `int_error_internals` + +This feature is internal to the Rust compiler and is not intended for general use. + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/integer-atomics.md b/src/doc/unstable-book/src/library-features/integer-atomics.md new file mode 100644 index 000000000000..50db9fd4ca45 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/integer-atomics.md @@ -0,0 +1,7 @@ +# `integer_atomics` + +The tracking issue for this feature is: [#32976] + +[#32976]: https://github.com/rust-lang/rust/issues/32976 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/into-boxed-c-str.md b/src/doc/unstable-book/src/library-features/into-boxed-c-str.md new file mode 100644 index 000000000000..0d94b4fc5605 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/into-boxed-c-str.md @@ -0,0 +1,7 @@ +# `into_boxed_c_str` + +The tracking issue for this feature is: [#40380] + +[#40380]: https://github.com/rust-lang/rust/issues/40380 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/into-boxed-os-str.md b/src/doc/unstable-book/src/library-features/into-boxed-os-str.md new file mode 100644 index 000000000000..7636e20b14d8 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/into-boxed-os-str.md @@ -0,0 +1,7 @@ +# `into_boxed_os_str` + +The tracking issue for this feature is: [#into_boxed_os_str] + +[#into_boxed_os_str]: https://github.com/rust-lang/rust/issues/40380 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/into-boxed-path.md b/src/doc/unstable-book/src/library-features/into-boxed-path.md new file mode 100644 index 000000000000..754c6042f07f --- /dev/null +++ b/src/doc/unstable-book/src/library-features/into-boxed-path.md @@ -0,0 +1,7 @@ +# `into_boxed_path` + +The tracking issue for this feature is: [#40380] + +[#40380]: https://github.com/rust-lang/rust/issues/40380 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/io-error-internals.md b/src/doc/unstable-book/src/library-features/io-error-internals.md new file mode 100644 index 000000000000..5bee18d33d61 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/io-error-internals.md @@ -0,0 +1,5 @@ +# `io_error_internals` + +This feature is internal to the Rust compiler and is not intended for general use. + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/io.md b/src/doc/unstable-book/src/library-features/io.md new file mode 100644 index 000000000000..ed6cae24e32d --- /dev/null +++ b/src/doc/unstable-book/src/library-features/io.md @@ -0,0 +1,7 @@ +# `io` + +The tracking issue for this feature is: [#27802] + +[#27802]: https://github.com/rust-lang/rust/issues/27802 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/ip.md b/src/doc/unstable-book/src/library-features/ip.md new file mode 100644 index 000000000000..7e7d52adbdb0 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/ip.md @@ -0,0 +1,7 @@ +# `ip` + +The tracking issue for this feature is: [#27709] + +[#27709]: https://github.com/rust-lang/rust/issues/27709 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/iter-rfind.md b/src/doc/unstable-book/src/library-features/iter-rfind.md new file mode 100644 index 000000000000..444714490345 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/iter-rfind.md @@ -0,0 +1,7 @@ +# `iter_rfind` + +The tracking issue for this feature is: [#39480] + +[#39480]: https://github.com/rust-lang/rust/issues/39480 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/libstd-io-internals.md b/src/doc/unstable-book/src/library-features/libstd-io-internals.md new file mode 100644 index 000000000000..8bcc2769db71 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/libstd-io-internals.md @@ -0,0 +1,5 @@ +# `libstd_io_internals` + +This feature is internal to the Rust compiler and is not intended for general use. + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/libstd-sys-internals.md b/src/doc/unstable-book/src/library-features/libstd-sys-internals.md new file mode 100644 index 000000000000..1b53faa8a007 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/libstd-sys-internals.md @@ -0,0 +1,5 @@ +# `libstd_sys_internals` + +This feature is internal to the Rust compiler and is not intended for general use. + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/libstd-thread-internals.md b/src/doc/unstable-book/src/library-features/libstd-thread-internals.md new file mode 100644 index 000000000000..b682d12e7cdd --- /dev/null +++ b/src/doc/unstable-book/src/library-features/libstd-thread-internals.md @@ -0,0 +1,5 @@ +# `libstd_thread_internals` + +This feature is internal to the Rust compiler and is not intended for general use. + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/linked-list-extras.md b/src/doc/unstable-book/src/library-features/linked-list-extras.md new file mode 100644 index 000000000000..be3b96aea70d --- /dev/null +++ b/src/doc/unstable-book/src/library-features/linked-list-extras.md @@ -0,0 +1,7 @@ +# `linked_list_extras` + +The tracking issue for this feature is: [#27794] + +[#27794]: https://github.com/rust-lang/rust/issues/27794 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/lookup-host.md b/src/doc/unstable-book/src/library-features/lookup-host.md new file mode 100644 index 000000000000..b60e7a010945 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/lookup-host.md @@ -0,0 +1,7 @@ +# `lookup_host` + +The tracking issue for this feature is: [#27705] + +[#27705]: https://github.com/rust-lang/rust/issues/27705 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/manually-drop.md b/src/doc/unstable-book/src/library-features/manually-drop.md new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/src/doc/unstable-book/src/library-features/more-io-inner-methods.md b/src/doc/unstable-book/src/library-features/more-io-inner-methods.md new file mode 100644 index 000000000000..c84f40e7ee55 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/more-io-inner-methods.md @@ -0,0 +1,11 @@ +# `more_io_inner_methods` + +The tracking issue for this feature is: [#41519] + +[#41519]: https://github.com/rust-lang/rust/issues/41519 + +------------------------ + +This feature enables several internal accessor methods on structures in +`std::io` including `Take::{get_ref, get_mut}` and `Chain::{into_inner, get_ref, +get_mut}`. diff --git a/src/doc/unstable-book/src/library-features/mpsc-select.md b/src/doc/unstable-book/src/library-features/mpsc-select.md new file mode 100644 index 000000000000..1405b6c5cb24 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/mpsc-select.md @@ -0,0 +1,5 @@ +# `mpsc_select` + +The tracking issue for this feature is: [#27800] + +[#27800]: https://github.com/rust-lang/rust/issues/27800 diff --git a/src/doc/unstable-book/src/library-features/n16.md b/src/doc/unstable-book/src/library-features/n16.md new file mode 100644 index 000000000000..e556adaa13ea --- /dev/null +++ b/src/doc/unstable-book/src/library-features/n16.md @@ -0,0 +1,5 @@ +# `n16` + +This feature is internal to the Rust compiler and is not intended for general use. + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/never-type-impls.md b/src/doc/unstable-book/src/library-features/never-type-impls.md new file mode 100644 index 000000000000..4063cd0db01d --- /dev/null +++ b/src/doc/unstable-book/src/library-features/never-type-impls.md @@ -0,0 +1,7 @@ +# `never_type_impls` + +The tracking issue for this feature is: [#35121] + +[#35121]: https://github.com/rust-lang/rust/issues/35121 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/nonzero.md b/src/doc/unstable-book/src/library-features/nonzero.md new file mode 100644 index 000000000000..f200f8e2786f --- /dev/null +++ b/src/doc/unstable-book/src/library-features/nonzero.md @@ -0,0 +1,7 @@ +# `nonzero` + +The tracking issue for this feature is: [#27730] + +[#27730]: https://github.com/rust-lang/rust/issues/27730 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/offset-to.md b/src/doc/unstable-book/src/library-features/offset-to.md new file mode 100644 index 000000000000..03d990eb4ae9 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/offset-to.md @@ -0,0 +1,7 @@ +# `offset_to` + +The tracking issue for this feature is: [#41079] + +[#41079]: https://github.com/rust-lang/rust/issues/41079 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/once-poison.md b/src/doc/unstable-book/src/library-features/once-poison.md new file mode 100644 index 000000000000..3c16cafae501 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/once-poison.md @@ -0,0 +1,7 @@ +# `once_poison` + +The tracking issue for this feature is: [#33577] + +[#33577]: https://github.com/rust-lang/rust/issues/33577 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/oom.md b/src/doc/unstable-book/src/library-features/oom.md new file mode 100644 index 000000000000..908caeb75c60 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/oom.md @@ -0,0 +1,7 @@ +# `oom` + +The tracking issue for this feature is: [#27700] + +[#27700]: https://github.com/rust-lang/rust/issues/27700 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/option-entry.md b/src/doc/unstable-book/src/library-features/option-entry.md new file mode 100644 index 000000000000..edb4efc09e58 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/option-entry.md @@ -0,0 +1,7 @@ +# `option_entry` + +The tracking issue for this feature is: [#39288] + +[#39288]: https://github.com/rust-lang/rust/issues/39288 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/osstring-shrink-to-fit.md b/src/doc/unstable-book/src/library-features/osstring-shrink-to-fit.md new file mode 100644 index 000000000000..21dc7d095c80 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/osstring-shrink-to-fit.md @@ -0,0 +1,7 @@ +# `osstring_shrink_to_fit` + +The tracking issue for this feature is: [#40421] + +[#40421]: https://github.com/rust-lang/rust/issues/40421 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/panic-abort.md b/src/doc/unstable-book/src/library-features/panic-abort.md new file mode 100644 index 000000000000..07a957626905 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/panic-abort.md @@ -0,0 +1,7 @@ +# `panic_abort` + +The tracking issue for this feature is: [#32837] + +[#32837]: https://github.com/rust-lang/rust/issues/32837 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/panic-unwind.md b/src/doc/unstable-book/src/library-features/panic-unwind.md new file mode 100644 index 000000000000..840e492597b5 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/panic-unwind.md @@ -0,0 +1,7 @@ +# `panic_unwind` + +The tracking issue for this feature is: [#32837] + +[#32837]: https://github.com/rust-lang/rust/issues/32837 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/pattern.md b/src/doc/unstable-book/src/library-features/pattern.md new file mode 100644 index 000000000000..e76ee6beb675 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/pattern.md @@ -0,0 +1,7 @@ +# `pattern` + +The tracking issue for this feature is: [#27721] + +[#27721]: https://github.com/rust-lang/rust/issues/27721 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/peek.md b/src/doc/unstable-book/src/library-features/peek.md new file mode 100644 index 000000000000..c42b4e995ec5 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/peek.md @@ -0,0 +1,7 @@ +# `peek` + +The tracking issue for this feature is: [#38980] + +[#38980]: https://github.com/rust-lang/rust/issues/38980 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/placement-in.md b/src/doc/unstable-book/src/library-features/placement-in.md new file mode 100644 index 000000000000..6ff010b7e385 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/placement-in.md @@ -0,0 +1,7 @@ +# `placement_in` + +The tracking issue for this feature is: [#27779] + +[#27779]: https://github.com/rust-lang/rust/issues/27779 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/placement-new-protocol.md b/src/doc/unstable-book/src/library-features/placement-new-protocol.md new file mode 100644 index 000000000000..d53225f0a352 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/placement-new-protocol.md @@ -0,0 +1,7 @@ +# `placement_new_protocol` + +The tracking issue for this feature is: [#27779] + +[#27779]: https://github.com/rust-lang/rust/issues/27779 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/print.md b/src/doc/unstable-book/src/library-features/print.md new file mode 100644 index 000000000000..dc25cb237e3b --- /dev/null +++ b/src/doc/unstable-book/src/library-features/print.md @@ -0,0 +1,5 @@ +# `print` + +This feature is internal to the Rust compiler and is not intended for general use. + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/proc-macro-internals.md b/src/doc/unstable-book/src/library-features/proc-macro-internals.md new file mode 100644 index 000000000000..ea087c0a4f7b --- /dev/null +++ b/src/doc/unstable-book/src/library-features/proc-macro-internals.md @@ -0,0 +1,7 @@ +# `proc_macro_internals` + +The tracking issue for this feature is: [#27812] + +[#27812]: https://github.com/rust-lang/rust/issues/27812 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/process-try-wait.md b/src/doc/unstable-book/src/library-features/process-try-wait.md new file mode 100644 index 000000000000..3593b6423495 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/process-try-wait.md @@ -0,0 +1,7 @@ +# `process_try_wait` + +The tracking issue for this feature is: [#38903] + +[#38903]: https://github.com/rust-lang/rust/issues/38903 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/question-mark-carrier.md b/src/doc/unstable-book/src/library-features/question-mark-carrier.md new file mode 100644 index 000000000000..56154acc02bb --- /dev/null +++ b/src/doc/unstable-book/src/library-features/question-mark-carrier.md @@ -0,0 +1,7 @@ +# `question_mark_carrier` + +The tracking issue for this feature is: [#31436] + +[#31436]: https://github.com/rust-lang/rust/issues/31436 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/rand.md b/src/doc/unstable-book/src/library-features/rand.md new file mode 100644 index 000000000000..d0229d94c20b --- /dev/null +++ b/src/doc/unstable-book/src/library-features/rand.md @@ -0,0 +1,5 @@ +# `rand` + +This feature is internal to the Rust compiler and is not intended for general use. + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/range-contains.md b/src/doc/unstable-book/src/library-features/range-contains.md new file mode 100644 index 000000000000..ac4581faf2ae --- /dev/null +++ b/src/doc/unstable-book/src/library-features/range-contains.md @@ -0,0 +1,7 @@ +# `range_contains` + +The tracking issue for this feature is: [#32311] + +[#32311]: https://github.com/rust-lang/rust/issues/32311 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/raw.md b/src/doc/unstable-book/src/library-features/raw.md new file mode 100644 index 000000000000..d7caf22813dc --- /dev/null +++ b/src/doc/unstable-book/src/library-features/raw.md @@ -0,0 +1,7 @@ +# `raw` + +The tracking issue for this feature is: [#27751] + +[#27751]: https://github.com/rust-lang/rust/issues/27751 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/retain-hash-collection.md b/src/doc/unstable-book/src/library-features/retain-hash-collection.md new file mode 100644 index 000000000000..c9ba5acf0200 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/retain-hash-collection.md @@ -0,0 +1,7 @@ +# `retain_hash_collection` + +The tracking issue for this feature is: [#36648] + +[#36648]: https://github.com/rust-lang/rust/issues/36648 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/reverse-cmp-key.md b/src/doc/unstable-book/src/library-features/reverse-cmp-key.md new file mode 100644 index 000000000000..a1a851d6ed63 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/reverse-cmp-key.md @@ -0,0 +1,7 @@ +# `reverse_cmp_key` + +The tracking issue for this feature is: [#40893] + +[#40893]: https://github.com/rust-lang/rust/issues/40893 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/rt.md b/src/doc/unstable-book/src/library-features/rt.md new file mode 100644 index 000000000000..007acc207a65 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/rt.md @@ -0,0 +1,5 @@ +# `rt` + +This feature is internal to the Rust compiler and is not intended for general use. + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/rustc-private.md b/src/doc/unstable-book/src/library-features/rustc-private.md new file mode 100644 index 000000000000..2453475efe59 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/rustc-private.md @@ -0,0 +1,7 @@ +# `rustc_private` + +The tracking issue for this feature is: [#27812] + +[#27812]: https://github.com/rust-lang/rust/issues/27812 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/sanitizer-runtime-lib.md b/src/doc/unstable-book/src/library-features/sanitizer-runtime-lib.md new file mode 100644 index 000000000000..82ae67fc05ac --- /dev/null +++ b/src/doc/unstable-book/src/library-features/sanitizer-runtime-lib.md @@ -0,0 +1,5 @@ +# `sanitizer_runtime_lib` + +This feature is internal to the Rust compiler and is not intended for general use. + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/set-stdio.md b/src/doc/unstable-book/src/library-features/set-stdio.md new file mode 100644 index 000000000000..7dbdcdaa1a2f --- /dev/null +++ b/src/doc/unstable-book/src/library-features/set-stdio.md @@ -0,0 +1,5 @@ +# `set_stdio` + +This feature is internal to the Rust compiler and is not intended for general use. + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/shared.md b/src/doc/unstable-book/src/library-features/shared.md new file mode 100644 index 000000000000..b79d1212c62f --- /dev/null +++ b/src/doc/unstable-book/src/library-features/shared.md @@ -0,0 +1,7 @@ +# `shared` + +The tracking issue for this feature is: [#27730] + +[#27730]: https://github.com/rust-lang/rust/issues/27730 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/sip-hash-13.md b/src/doc/unstable-book/src/library-features/sip-hash-13.md new file mode 100644 index 000000000000..8f69c3ab2def --- /dev/null +++ b/src/doc/unstable-book/src/library-features/sip-hash-13.md @@ -0,0 +1,7 @@ +# `sip_hash_13` + +The tracking issue for this feature is: [#34767] + +[#34767]: https://github.com/rust-lang/rust/issues/34767 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/slice-concat-ext.md b/src/doc/unstable-book/src/library-features/slice-concat-ext.md new file mode 100644 index 000000000000..9ba2de5adc72 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/slice-concat-ext.md @@ -0,0 +1,7 @@ +# `slice_concat_ext` + +The tracking issue for this feature is: [#27747] + +[#27747]: https://github.com/rust-lang/rust/issues/27747 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/slice-get-slice.md b/src/doc/unstable-book/src/library-features/slice-get-slice.md new file mode 100644 index 000000000000..57e2c148e796 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/slice-get-slice.md @@ -0,0 +1,7 @@ +# `slice_get_slice` + +The tracking issue for this feature is: [#35729] + +[#35729]: https://github.com/rust-lang/rust/issues/35729 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/slice-rsplit.md b/src/doc/unstable-book/src/library-features/slice-rsplit.md new file mode 100644 index 000000000000..8c2954f7294e --- /dev/null +++ b/src/doc/unstable-book/src/library-features/slice-rsplit.md @@ -0,0 +1,10 @@ +# `slice_rsplit` + +The tracking issue for this feature is: [#41020] + +[#41020]: https://github.com/rust-lang/rust/issues/41020 + +------------------------ + +The `slice_rsplit` feature enables two methods on slices: +`slice.rsplit(predicate)` and `slice.rsplit_mut(predicate)`. diff --git a/src/doc/unstable-book/src/library-features/sort-internals.md b/src/doc/unstable-book/src/library-features/sort-internals.md new file mode 100644 index 000000000000..6f2385e53008 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/sort-internals.md @@ -0,0 +1,5 @@ +# `sort_internals` + +This feature is internal to the Rust compiler and is not intended for general use. + +------------------------ diff --git a/src/doc/unstable-book/src/sort-unstable.md b/src/doc/unstable-book/src/library-features/sort-unstable.md similarity index 100% rename from src/doc/unstable-book/src/sort-unstable.md rename to src/doc/unstable-book/src/library-features/sort-unstable.md diff --git a/src/doc/unstable-book/src/library-features/splice.md b/src/doc/unstable-book/src/library-features/splice.md new file mode 100644 index 000000000000..ca7f78a8f79e --- /dev/null +++ b/src/doc/unstable-book/src/library-features/splice.md @@ -0,0 +1,24 @@ +# `splice` + +The tracking issue for this feature is: [#32310] + +[#32310]: https://github.com/rust-lang/rust/issues/32310 + +------------------------ + +The `splice()` method on `Vec` and `String` allows you to replace a range +of values in a vector or string with another range of values, and returns +the replaced values. + +A simple example: + +```rust +#![feature(splice)] +let mut s = String::from("α is alpha, β is beta"); +let beta_offset = s.find('β').unwrap_or(s.len()); + +// Replace the range up until the β from the string +let t: String = s.splice(..beta_offset, "Α is capital alpha; ").collect(); +assert_eq!(t, "α is alpha, "); +assert_eq!(s, "Α is capital alpha; β is beta"); +``` \ No newline at end of file diff --git a/src/doc/unstable-book/src/library-features/step-by.md b/src/doc/unstable-book/src/library-features/step-by.md new file mode 100644 index 000000000000..b649496cdd80 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/step-by.md @@ -0,0 +1,7 @@ +# `step_by` + +The tracking issue for this feature is: [#27741] + +[#27741]: https://github.com/rust-lang/rust/issues/27741 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/step-trait.md b/src/doc/unstable-book/src/library-features/step-trait.md new file mode 100644 index 000000000000..e53ca13f7b6f --- /dev/null +++ b/src/doc/unstable-book/src/library-features/step-trait.md @@ -0,0 +1,7 @@ +# `step_trait` + +The tracking issue for this feature is: [#27741] + +[#27741]: https://github.com/rust-lang/rust/issues/27741 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/str-box-extras.md b/src/doc/unstable-book/src/library-features/str-box-extras.md new file mode 100644 index 000000000000..d05dcafa84da --- /dev/null +++ b/src/doc/unstable-book/src/library-features/str-box-extras.md @@ -0,0 +1,9 @@ +# `str_box_extras` + +The tracking issue for this feature is: [#str_box_extras] + +[#str_box_extras]: https://github.com/rust-lang/rust/issues/41119 + +------------------------ + + diff --git a/src/doc/unstable-book/src/library-features/str-checked-slicing.md b/src/doc/unstable-book/src/library-features/str-checked-slicing.md new file mode 100644 index 000000000000..d390139a6bef --- /dev/null +++ b/src/doc/unstable-book/src/library-features/str-checked-slicing.md @@ -0,0 +1,7 @@ +# `str_checked_slicing` + +The tracking issue for this feature is: [#39932] + +[#39932]: https://github.com/rust-lang/rust/issues/39932 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/str-escape.md b/src/doc/unstable-book/src/library-features/str-escape.md new file mode 100644 index 000000000000..61e31c894432 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/str-escape.md @@ -0,0 +1,7 @@ +# `str_escape` + +The tracking issue for this feature is: [#27791] + +[#27791]: https://github.com/rust-lang/rust/issues/27791 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/str-internals.md b/src/doc/unstable-book/src/library-features/str-internals.md new file mode 100644 index 000000000000..af8ef056dbe2 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/str-internals.md @@ -0,0 +1,5 @@ +# `str_internals` + +This feature is internal to the Rust compiler and is not intended for general use. + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/str-mut-extras.md b/src/doc/unstable-book/src/library-features/str-mut-extras.md new file mode 100644 index 000000000000..df4f35832cdc --- /dev/null +++ b/src/doc/unstable-book/src/library-features/str-mut-extras.md @@ -0,0 +1,8 @@ +# `str_mut_extras` + +The tracking issue for this feature is: [#str_mut_extras] + +[#str_mut_extras]: https://github.com/rust-lang/rust/issues/41119 + +------------------------ + diff --git a/src/doc/unstable-book/src/test.md b/src/doc/unstable-book/src/library-features/test.md similarity index 100% rename from src/doc/unstable-book/src/test.md rename to src/doc/unstable-book/src/library-features/test.md diff --git a/src/doc/unstable-book/src/library-features/thread-id.md b/src/doc/unstable-book/src/library-features/thread-id.md new file mode 100644 index 000000000000..af3ea991025f --- /dev/null +++ b/src/doc/unstable-book/src/library-features/thread-id.md @@ -0,0 +1,7 @@ +# `thread_id` + +The tracking issue for this feature is: [#21507] + +[#21507]: https://github.com/rust-lang/rust/issues/21507 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/thread-local-internals.md b/src/doc/unstable-book/src/library-features/thread-local-internals.md new file mode 100644 index 000000000000..e1cdcc339d22 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/thread-local-internals.md @@ -0,0 +1,5 @@ +# `thread_local_internals` + +This feature is internal to the Rust compiler and is not intended for general use. + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/thread-local-state.md b/src/doc/unstable-book/src/library-features/thread-local-state.md new file mode 100644 index 000000000000..113c1e910dca --- /dev/null +++ b/src/doc/unstable-book/src/library-features/thread-local-state.md @@ -0,0 +1,7 @@ +# `thread_local_state` + +The tracking issue for this feature is: [#27716] + +[#27716]: https://github.com/rust-lang/rust/issues/27716 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/toowned-clone-into.md b/src/doc/unstable-book/src/library-features/toowned-clone-into.md new file mode 100644 index 000000000000..eccc7e0e4dda --- /dev/null +++ b/src/doc/unstable-book/src/library-features/toowned-clone-into.md @@ -0,0 +1,7 @@ +# `toowned_clone_into` + +The tracking issue for this feature is: [#41263] + +[#41263]: https://github.com/rust-lang/rust/issues/41263 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/trusted-len.md b/src/doc/unstable-book/src/library-features/trusted-len.md new file mode 100644 index 000000000000..80213cf1fdbb --- /dev/null +++ b/src/doc/unstable-book/src/library-features/trusted-len.md @@ -0,0 +1,7 @@ +# `trusted_len` + +The tracking issue for this feature is: [#37572] + +[#37572]: https://github.com/rust-lang/rust/issues/37572 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/try-from.md b/src/doc/unstable-book/src/library-features/try-from.md new file mode 100644 index 000000000000..d763caff5aac --- /dev/null +++ b/src/doc/unstable-book/src/library-features/try-from.md @@ -0,0 +1,7 @@ +# `try_from` + +The tracking issue for this feature is: [#33417] + +[#33417]: https://github.com/rust-lang/rust/issues/33417 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/unicode.md b/src/doc/unstable-book/src/library-features/unicode.md new file mode 100644 index 000000000000..9fecec2ac36d --- /dev/null +++ b/src/doc/unstable-book/src/library-features/unicode.md @@ -0,0 +1,7 @@ +# `unicode` + +The tracking issue for this feature is: [#27783] + +[#27783]: https://github.com/rust-lang/rust/issues/27783 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/unique.md b/src/doc/unstable-book/src/library-features/unique.md new file mode 100644 index 000000000000..99a3490d106b --- /dev/null +++ b/src/doc/unstable-book/src/library-features/unique.md @@ -0,0 +1,7 @@ +# `unique` + +The tracking issue for this feature is: [#27730] + +[#27730]: https://github.com/rust-lang/rust/issues/27730 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/unsize.md b/src/doc/unstable-book/src/library-features/unsize.md new file mode 100644 index 000000000000..92807e2858ff --- /dev/null +++ b/src/doc/unstable-book/src/library-features/unsize.md @@ -0,0 +1,7 @@ +# `unsize` + +The tracking issue for this feature is: [#27732] + +[#27732]: https://github.com/rust-lang/rust/issues/27732 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/update-panic-count.md b/src/doc/unstable-book/src/library-features/update-panic-count.md new file mode 100644 index 000000000000..d315647ba104 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/update-panic-count.md @@ -0,0 +1,5 @@ +# `update_panic_count` + +This feature is internal to the Rust compiler and is not intended for general use. + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/utf8-error-error-len.md b/src/doc/unstable-book/src/library-features/utf8-error-error-len.md new file mode 100644 index 000000000000..1c14a5a9fa08 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/utf8-error-error-len.md @@ -0,0 +1,7 @@ +# `utf8_error_error_len` + +The tracking issue for this feature is: [#40494] + +[#40494]: https://github.com/rust-lang/rust/issues/40494 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/vec-remove-item.md b/src/doc/unstable-book/src/library-features/vec-remove-item.md new file mode 100644 index 000000000000..2b8c9f046eef --- /dev/null +++ b/src/doc/unstable-book/src/library-features/vec-remove-item.md @@ -0,0 +1,7 @@ +# `vec_remove_item` + +The tracking issue for this feature is: [#40062] + +[#40062]: https://github.com/rust-lang/rust/issues/40062 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/windows-c.md b/src/doc/unstable-book/src/library-features/windows-c.md new file mode 100644 index 000000000000..3f833eb3d093 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/windows-c.md @@ -0,0 +1,5 @@ +# `windows_c` + +This feature is internal to the Rust compiler and is not intended for general use. + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/windows-handle.md b/src/doc/unstable-book/src/library-features/windows-handle.md new file mode 100644 index 000000000000..f47a8425045b --- /dev/null +++ b/src/doc/unstable-book/src/library-features/windows-handle.md @@ -0,0 +1,5 @@ +# `windows_handle` + +This feature is internal to the Rust compiler and is not intended for general use. + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/windows-net.md b/src/doc/unstable-book/src/library-features/windows-net.md new file mode 100644 index 000000000000..174960d4f004 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/windows-net.md @@ -0,0 +1,5 @@ +# `windows_net` + +This feature is internal to the Rust compiler and is not intended for general use. + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/windows-stdio.md b/src/doc/unstable-book/src/library-features/windows-stdio.md new file mode 100644 index 000000000000..4d361442386a --- /dev/null +++ b/src/doc/unstable-book/src/library-features/windows-stdio.md @@ -0,0 +1,5 @@ +# `windows_stdio` + +This feature is internal to the Rust compiler and is not intended for general use. + +------------------------ diff --git a/src/doc/unstable-book/src/static-recursion.md b/src/doc/unstable-book/src/static-recursion.md deleted file mode 100644 index d419ea41c6ff..000000000000 --- a/src/doc/unstable-book/src/static-recursion.md +++ /dev/null @@ -1,10 +0,0 @@ -# `static_recursion` - -The tracking issue for this feature is: [#29719] - -[#29719]: https://github.com/rust-lang/rust/issues/29719 - ------------------------- - - - diff --git a/src/doc/unstable-book/src/the-unstable-book.md b/src/doc/unstable-book/src/the-unstable-book.md index dfbfe4cab973..604b449f1637 100644 --- a/src/doc/unstable-book/src/the-unstable-book.md +++ b/src/doc/unstable-book/src/the-unstable-book.md @@ -14,7 +14,7 @@ fn main() { The `box_syntax` feature [has a chapter][box] describing how to use it. -[box]: box-syntax.html +[box]: language-features/box-syntax.html Because this documentation relates to unstable features, we make no guarantees that what is contained here is accurate or up to date. It's developed on a diff --git a/src/doc/unstable-book/src/windows-subsystem.md b/src/doc/unstable-book/src/windows-subsystem.md deleted file mode 100644 index 80583352fbf9..000000000000 --- a/src/doc/unstable-book/src/windows-subsystem.md +++ /dev/null @@ -1,10 +0,0 @@ -# `windows_subsystem` - -The tracking issue for this feature is: [#37499] - -[#37499]: https://github.com/rust-lang/rust/issues/37499 - ------------------------- - - - diff --git a/src/etc/adb_run_wrapper.sh b/src/etc/adb_run_wrapper.sh deleted file mode 100755 index bd6c483156f8..000000000000 --- a/src/etc/adb_run_wrapper.sh +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2014 The Rust Project Developers. See the COPYRIGHT -# file at the top-level directory of this distribution and at -# http://rust-lang.org/COPYRIGHT. -# -# Licensed under the Apache License, Version 2.0 or the MIT license -# , at your -# option. This file may not be copied, modified, or distributed -# except according to those terms. -# -# ignore-tidy-linelength -# -# usage : adb_run_wrapper [test dir - where test executables exist] [test executable] -# - -TEST_PATH=$1 -BIN_PATH=/system/bin -if [ -d "$TEST_PATH" ] -then - shift - RUN=$1 - - if [ ! -z "$RUN" ] - then - shift - - # The length of binary path (i.e. ./$RUN) should be shorter than 128 characters. - cd $TEST_PATH - TEST_EXEC_ENV=22 LD_LIBRARY_PATH=$TEST_PATH PATH=$BIN_PATH:$TEST_PATH ./$RUN $@ 1>$TEST_PATH/$RUN.stdout 2>$TEST_PATH/$RUN.stderr - L_RET=$? - - echo $L_RET > $TEST_PATH/$RUN.exitcode - - fi -fi diff --git a/src/etc/char_private.py b/src/etc/char_private.py index 9d15f98e0670..75ab3f1a17be 100644 --- a/src/etc/char_private.py +++ b/src/etc/char_private.py @@ -76,6 +76,66 @@ def get_codepoints(f): for c in range(prev_codepoint + 1, NUM_CODEPOINTS): yield Codepoint(c, None) +def compress_singletons(singletons): + uppers = [] # (upper, # items in lowers) + lowers = [] + + for i in singletons: + upper = i >> 8 + lower = i & 0xff + if len(uppers) == 0 or uppers[-1][0] != upper: + uppers.append((upper, 1)) + else: + upper, count = uppers[-1] + uppers[-1] = upper, count + 1 + lowers.append(lower) + + return uppers, lowers + +def compress_normal(normal): + # lengths 0x00..0x7f are encoded as 00, 01, ..., 7e, 7f + # lengths 0x80..0x7fff are encoded as 80 80, 80 81, ..., ff fe, ff ff + compressed = [] # [truelen, (truelenaux), falselen, (falselenaux)] + + prev_start = 0 + for start, count in normal: + truelen = start - prev_start + falselen = count + prev_start = start + count + + assert truelen < 0x8000 and falselen < 0x8000 + entry = [] + if truelen > 0x7f: + entry.append(0x80 | (truelen >> 8)) + entry.append(truelen & 0xff) + else: + entry.append(truelen & 0x7f) + if falselen > 0x7f: + entry.append(0x80 | (falselen >> 8)) + entry.append(falselen & 0xff) + else: + entry.append(falselen & 0x7f) + + compressed.append(entry) + + return compressed + +def print_singletons(uppers, lowers, uppersname, lowersname): + print("const {}: &'static [(u8, u8)] = &[".format(uppersname)) + for u, c in uppers: + print(" ({:#04x}, {}),".format(u, c)) + print("];") + print("const {}: &'static [u8] = &[".format(lowersname)) + for i in range(0, len(lowers), 8): + print(" {}".format(" ".join("{:#04x},".format(l) for l in lowers[i:i+8]))) + print("];") + +def print_normal(normal, normalname): + print("const {}: &'static [u8] = &[".format(normalname)) + for v in normal: + print(" {}".format(" ".join("{:#04x},".format(i) for i in v))) + print("];") + def main(): file = get_file("http://www.unicode.org/Public/UNIDATA/UnicodeData.txt") @@ -111,6 +171,11 @@ def main(): else: normal0.append((a, b - a)) + singletons0u, singletons0l = compress_singletons(singletons0) + singletons1u, singletons1l = compress_singletons(singletons1) + normal0 = compress_normal(normal0) + normal1 = compress_normal(normal1) + print("""\ // Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at @@ -125,38 +190,49 @@ def main(): // NOTE: The following code was generated by "src/etc/char_private.py", // do not edit directly! -use slice::SliceExt; - -fn check(x: u16, singletons: &[u16], normal: &[u16]) -> bool { - for &s in singletons { - if x == s { - return false; - } else if x < s { - break; - } - } - for w in normal.chunks(2) { - let start = w[0]; - let len = w[1]; - let difference = (x as i32) - (start as i32); - if 0 <= difference { - if difference < len as i32 { - return false; +fn check(x: u16, singletonuppers: &[(u8, u8)], singletonlowers: &[u8], + normal: &[u8]) -> bool { + let xupper = (x >> 8) as u8; + let mut lowerstart = 0; + for &(upper, lowercount) in singletonuppers { + let lowerend = lowerstart + lowercount as usize; + if xupper == upper { + for &lower in &singletonlowers[lowerstart..lowerend] { + if lower == x as u8 { + return false; + } } - } else { + } else if xupper < upper { break; } + lowerstart = lowerend; } - true + + let mut x = x as i32; + let mut normal = normal.iter().cloned(); + let mut current = true; + while let Some(v) = normal.next() { + let len = if v & 0x80 != 0 { + ((v & 0x7f) as i32) << 8 | normal.next().unwrap() as i32 + } else { + v as i32 + }; + x -= len; + if x < 0 { + break; + } + current = !current; + } + current } pub fn is_printable(x: char) -> bool { let x = x as u32; let lower = x as u16; if x < 0x10000 { - check(lower, SINGLETONS0, NORMAL0) + check(lower, SINGLETONS0U, SINGLETONS0L, NORMAL0) } else if x < 0x20000 { - check(lower, SINGLETONS1, NORMAL1) + check(lower, SINGLETONS1U, SINGLETONS1L, NORMAL1) } else {\ """) for a, b in extra: @@ -169,22 +245,10 @@ pub fn is_printable(x: char) -> bool { }\ """) print() - print("const SINGLETONS0: &'static [u16] = &[") - for s in singletons0: - print(" 0x{:x},".format(s)) - print("];") - print("const SINGLETONS1: &'static [u16] = &[") - for s in singletons1: - print(" 0x{:x},".format(s)) - print("];") - print("const NORMAL0: &'static [u16] = &[") - for a, b in normal0: - print(" 0x{:x}, 0x{:x},".format(a, b)) - print("];") - print("const NORMAL1: &'static [u16] = &[") - for a, b in normal1: - print(" 0x{:x}, 0x{:x},".format(a, b)) - print("];") + print_singletons(singletons0u, singletons0l, 'SINGLETONS0U', 'SINGLETONS0L') + print_singletons(singletons1u, singletons1l, 'SINGLETONS1U', 'SINGLETONS1L') + print_normal(normal0, 'NORMAL0') + print_normal(normal1, 'NORMAL1') if __name__ == '__main__': main() diff --git a/src/etc/make-win-dist.py b/src/etc/make-win-dist.py index eda5f8540857..4699fefbb20e 100644 --- a/src/etc/make-win-dist.py +++ b/src/etc/make-win-dist.py @@ -49,9 +49,10 @@ def make_win_dist(rust_root, plat_root, target_triple): elif key == "libraries": lib_path.extend(val.lstrip(' =').split(';')) - target_tools = ["gcc.exe", "ld.exe", "ar.exe", "dlltool.exe"] + target_tools = ["gcc.exe", "ld.exe", "ar.exe", "dlltool.exe", + "libwinpthread-1.dll"] - rustc_dlls = ["libstdc++-6.dll"] + rustc_dlls = ["libstdc++-6.dll", "libwinpthread-1.dll"] if target_triple.startswith("i686-"): rustc_dlls.append("libgcc_s_dw2-1.dll") else: @@ -67,6 +68,7 @@ def make_win_dist(rust_root, plat_root, target_triple): "libstdc++.a", "libiconv.a", "libmoldname.a", + "libpthread.a", # Windows import libs "libadvapi32.a", "libbcrypt.a", diff --git a/src/etc/natvis/libcollections.natvis b/src/etc/natvis/libcollections.natvis index 821c52361f86..e7e93be98695 100644 --- a/src/etc/natvis/libcollections.natvis +++ b/src/etc/natvis/libcollections.natvis @@ -1,16 +1,16 @@ -    {{ size={len} }} -     + {{ size={len} }} + len buf.cap len buf.ptr.pointer.__0 -     -   + + {{ size={tail <= head ? head - tail : buf.cap - tail + head} }} diff --git a/src/etc/rust-gdb b/src/etc/rust-gdb index 520a108da914..52601cd96f80 100755 --- a/src/etc/rust-gdb +++ b/src/etc/rust-gdb @@ -17,7 +17,10 @@ RUSTC_SYSROOT=`rustc --print=sysroot` GDB_PYTHON_MODULE_DIRECTORY="$RUSTC_SYSROOT/lib/rustlib/etc" # Run GDB with the additional arguments that load the pretty printers -PYTHONPATH="$PYTHONPATH:$GDB_PYTHON_MODULE_DIRECTORY" gdb \ +# Set the environment variable `RUST_GDB` to overwrite the call to a +# different/specific command (defaults to `gdb`). +RUST_GDB="${RUST_GDB:-gdb}" +PYTHONPATH="$PYTHONPATH:$GDB_PYTHON_MODULE_DIRECTORY" ${RUST_GDB} \ -d "$GDB_PYTHON_MODULE_DIRECTORY" \ -iex "add-auto-load-safe-path $GDB_PYTHON_MODULE_DIRECTORY" \ "$@" diff --git a/src/etc/rust-windbg.cmd b/src/etc/rust-windbg.cmd new file mode 100644 index 000000000000..4cdd6b986099 --- /dev/null +++ b/src/etc/rust-windbg.cmd @@ -0,0 +1,18 @@ +@echo off +setlocal + +REM Copyright 2014 The Rust Project Developers. See the COPYRIGHT +REM file at the top-level directory of this distribution and at +REM http://rust-lang.org/COPYRIGHT. +REM +REM Licensed under the Apache License, Version 2.0 or the MIT license +REM , at your +REM option. This file may not be copied, modified, or distributed +REM except according to those terms. + +for /f "delims=" %%i in ('rustc --print=sysroot') do set rustc_sysroot=%%i + +set rust_etc=%rustc_sysroot%\lib\rustlib\etc + +windbg -c ".nvload %rust_etc%\libcore.natvis;.nvload %rust_etc%\libcollections.natvis;" %* \ No newline at end of file diff --git a/src/grammar/.gitignore b/src/grammar/.gitignore deleted file mode 100644 index e77db28967e3..000000000000 --- a/src/grammar/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -verify -*.class -*.java -*.tokens diff --git a/src/grammar/README.md b/src/grammar/README.md deleted file mode 100644 index 83808108ff83..000000000000 --- a/src/grammar/README.md +++ /dev/null @@ -1,33 +0,0 @@ -# Reference grammar. - -Uses [antlr4](http://www.antlr.org/) and a custom Rust tool to compare -ASTs/token streams generated. You can use the `make check-lexer` target to -run all of the available tests. - -The build of the rust part is included with `make tidy` and can be run with `make check-build-lexer-verifier`. - -# Manual build - -To use manually, assuming antlr4 is installed at `/usr/share/java/antlr-complete.jar`: - -``` -antlr4 RustLexer.g4 -javac -classpath /usr/share/java/antlr-complete.jar *.java -rustc -O verify.rs -for file in ../*/**.rs; do - echo $file; - grun RustLexer tokens -tokens < "$file" | ./verify "$file" RustLexer.tokens || break -done -``` - -Note that the `../*/**.rs` glob will match every `*.rs` file in the above -directory and all of its recursive children. This is a Zsh extension. - - -## Cleanup - -To cleanup you can use a command like this: - -```bash -rm -f verify *.class *.java *.tokens -``` diff --git a/src/grammar/RustLexer.g4 b/src/grammar/RustLexer.g4 deleted file mode 100644 index a63fc59e50b0..000000000000 --- a/src/grammar/RustLexer.g4 +++ /dev/null @@ -1,197 +0,0 @@ -lexer grammar RustLexer; - -@lexer::members { - public boolean is_at(int pos) { - return _input.index() == pos; - } -} - - -tokens { - EQ, LT, LE, EQEQ, NE, GE, GT, ANDAND, OROR, NOT, TILDE, PLUS, - MINUS, STAR, SLASH, PERCENT, CARET, AND, OR, SHL, SHR, BINOP, - BINOPEQ, LARROW, AT, DOT, DOTDOT, DOTDOTDOT, COMMA, SEMI, COLON, - MOD_SEP, RARROW, FAT_ARROW, LPAREN, RPAREN, LBRACKET, RBRACKET, - LBRACE, RBRACE, POUND, DOLLAR, UNDERSCORE, LIT_CHAR, LIT_BYTE, - LIT_INTEGER, LIT_FLOAT, LIT_STR, LIT_STR_RAW, LIT_BYTE_STR, - LIT_BYTE_STR_RAW, QUESTION, IDENT, LIFETIME, WHITESPACE, DOC_COMMENT, - COMMENT, SHEBANG, UTF8_BOM -} - -import xidstart , xidcontinue; - - -/* Expression-operator symbols */ - -EQ : '=' ; -LT : '<' ; -LE : '<=' ; -EQEQ : '==' ; -NE : '!=' ; -GE : '>=' ; -GT : '>' ; -ANDAND : '&&' ; -OROR : '||' ; -NOT : '!' ; -TILDE : '~' ; -PLUS : '+' ; -MINUS : '-' ; -STAR : '*' ; -SLASH : '/' ; -PERCENT : '%' ; -CARET : '^' ; -AND : '&' ; -OR : '|' ; -SHL : '<<' ; -SHR : '>>' ; -LARROW : '<-' ; - -BINOP - : PLUS - | SLASH - | MINUS - | STAR - | PERCENT - | CARET - | AND - | OR - | SHL - | SHR - | LARROW - ; - -BINOPEQ : BINOP EQ ; - -/* "Structural symbols" */ - -AT : '@' ; -DOT : '.' ; -DOTDOT : '..' ; -DOTDOTDOT : '...' ; -COMMA : ',' ; -SEMI : ';' ; -COLON : ':' ; -MOD_SEP : '::' ; -RARROW : '->' ; -FAT_ARROW : '=>' ; -LPAREN : '(' ; -RPAREN : ')' ; -LBRACKET : '[' ; -RBRACKET : ']' ; -LBRACE : '{' ; -RBRACE : '}' ; -POUND : '#'; -DOLLAR : '$' ; -UNDERSCORE : '_' ; - -// Literals - -fragment HEXIT - : [0-9a-fA-F] - ; - -fragment CHAR_ESCAPE - : [nrt\\'"0] - | [xX] HEXIT HEXIT - | 'u' HEXIT HEXIT HEXIT HEXIT - | 'U' HEXIT HEXIT HEXIT HEXIT HEXIT HEXIT HEXIT HEXIT - | 'u{' HEXIT '}' - | 'u{' HEXIT HEXIT '}' - | 'u{' HEXIT HEXIT HEXIT '}' - | 'u{' HEXIT HEXIT HEXIT HEXIT '}' - | 'u{' HEXIT HEXIT HEXIT HEXIT HEXIT '}' - | 'u{' HEXIT HEXIT HEXIT HEXIT HEXIT HEXIT '}' - ; - -fragment SUFFIX - : IDENT - ; - -fragment INTEGER_SUFFIX - : { _input.LA(1) != 'e' && _input.LA(1) != 'E' }? SUFFIX - ; - -LIT_CHAR - : '\'' ( '\\' CHAR_ESCAPE - | ~[\\'\n\t\r] - | '\ud800' .. '\udbff' '\udc00' .. '\udfff' - ) - '\'' SUFFIX? - ; - -LIT_BYTE - : 'b\'' ( '\\' ( [xX] HEXIT HEXIT - | [nrt\\'"0] ) - | ~[\\'\n\t\r] '\udc00'..'\udfff'? - ) - '\'' SUFFIX? - ; - -LIT_INTEGER - - : [0-9][0-9_]* INTEGER_SUFFIX? - | '0b' [01_]+ INTEGER_SUFFIX? - | '0o' [0-7_]+ INTEGER_SUFFIX? - | '0x' [0-9a-fA-F_]+ INTEGER_SUFFIX? - ; - -LIT_FLOAT - : [0-9][0-9_]* ('.' { - /* dot followed by another dot is a range, not a float */ - _input.LA(1) != '.' && - /* dot followed by an identifier is an integer with a function call, not a float */ - _input.LA(1) != '_' && - !(_input.LA(1) >= 'a' && _input.LA(1) <= 'z') && - !(_input.LA(1) >= 'A' && _input.LA(1) <= 'Z') - }? | ('.' [0-9][0-9_]*)? ([eE] [-+]? [0-9][0-9_]*)? SUFFIX?) - ; - -LIT_STR - : '"' ('\\\n' | '\\\r\n' | '\\' CHAR_ESCAPE | .)*? '"' SUFFIX? - ; - -LIT_BYTE_STR : 'b' LIT_STR ; -LIT_BYTE_STR_RAW : 'b' LIT_STR_RAW ; - -/* this is a bit messy */ - -fragment LIT_STR_RAW_INNER - : '"' .*? '"' - | LIT_STR_RAW_INNER2 - ; - -fragment LIT_STR_RAW_INNER2 - : POUND LIT_STR_RAW_INNER POUND - ; - -LIT_STR_RAW - : 'r' LIT_STR_RAW_INNER SUFFIX? - ; - - -QUESTION : '?'; - -IDENT : XID_Start XID_Continue* ; - -fragment QUESTION_IDENTIFIER : QUESTION? IDENT; - -LIFETIME : '\'' IDENT ; - -WHITESPACE : [ \r\n\t]+ ; - -UNDOC_COMMENT : '////' ~[\n]* -> type(COMMENT) ; -YESDOC_COMMENT : '///' ~[\r\n]* -> type(DOC_COMMENT) ; -OUTER_DOC_COMMENT : '//!' ~[\r\n]* -> type(DOC_COMMENT) ; -LINE_COMMENT : '//' ( ~[/\n] ~[\n]* )? -> type(COMMENT) ; - -DOC_BLOCK_COMMENT - : ('/**' ~[*] | '/*!') (DOC_BLOCK_COMMENT | .)*? '*/' -> type(DOC_COMMENT) - ; - -BLOCK_COMMENT : '/*' (BLOCK_COMMENT | .)*? '*/' -> type(COMMENT) ; - -/* these appear at the beginning of a file */ - -SHEBANG : '#!' { is_at(2) && _input.LA(1) != '[' }? ~[\r\n]* -> type(SHEBANG) ; - -UTF8_BOM : '\ufeff' { is_at(1) }? -> skip ; diff --git a/src/grammar/check.sh b/src/grammar/check.sh deleted file mode 100755 index 70a8f6fca2e5..000000000000 --- a/src/grammar/check.sh +++ /dev/null @@ -1,52 +0,0 @@ -#!/bin/sh - -# ignore-license - -# Run the reference lexer against libsyntax and compare the tokens and spans. -# If "// ignore-lexer-test" is present in the file, it will be ignored. - - -# Argument $1 is the file to check, $2 is the classpath to use, $3 is the path -# to the grun binary, $4 is the path to the verify binary, $5 is the path to -# RustLexer.tokens -if [ "${VERBOSE}" == "1" ]; then - set -x -fi - -passed=0 -failed=0 -skipped=0 - -check() { - grep --silent "// ignore-lexer-test" "$1"; - - # if it is *not* found... - if [ $? -eq 1 ]; then - cd $2 # This `cd` is so java will pick up RustLexer.class. I could not - # figure out how to wrangle the CLASSPATH, just adding build/grammar - # did not seem to have any effect. - if $3 RustLexer tokens -tokens < $1 | $4 $1 $5; then - echo "pass: $1" - passed=`expr $passed + 1` - else - echo "fail: $1" - failed=`expr $failed + 1` - fi - else - echo "skip: $1" - skipped=`expr $skipped + 1` - fi -} - -for file in $(find $1 -iname '*.rs' ! -path '*/test/compile-fail*'); do - check "$file" $2 $3 $4 $5 -done - -printf "\ntest result: " - -if [ $failed -eq 0 ]; then - printf "ok. $passed passed; $failed failed; $skipped skipped\n\n" -else - printf "failed. $passed passed; $failed failed; $skipped skipped\n\n" - exit 1 -fi diff --git a/src/grammar/lexer.l b/src/grammar/lexer.l deleted file mode 100644 index 77737c99496f..000000000000 --- a/src/grammar/lexer.l +++ /dev/null @@ -1,343 +0,0 @@ -%{ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#include -#include - -static int num_hashes; -static int end_hashes; -static int saw_non_hash; - -%} - -%option stack -%option yylineno - -%x str -%x rawstr -%x rawstr_esc_begin -%x rawstr_esc_body -%x rawstr_esc_end -%x byte -%x bytestr -%x rawbytestr -%x rawbytestr_nohash -%x pound -%x shebang_or_attr -%x ltorchar -%x linecomment -%x doc_line -%x blockcomment -%x doc_block -%x suffix - -ident [a-zA-Z\x80-\xff_][a-zA-Z0-9\x80-\xff_]* - -%% - -{ident} { BEGIN(INITIAL); } -(.|\n) { yyless(0); BEGIN(INITIAL); } - -[ \n\t\r] { } - -\xef\xbb\xbf { - // UTF-8 byte order mark (BOM), ignore if in line 1, error otherwise - if (yyget_lineno() != 1) { - return -1; - } -} - -\/\/(\/|\!) { BEGIN(doc_line); yymore(); } -\n { BEGIN(INITIAL); - yyleng--; - yytext[yyleng] = 0; - return ((yytext[2] == '!') ? INNER_DOC_COMMENT : OUTER_DOC_COMMENT); - } -[^\n]* { yymore(); } - -\/\/|\/\/\/\/ { BEGIN(linecomment); } -\n { BEGIN(INITIAL); } -[^\n]* { } - -\/\*(\*|\!)[^*] { yy_push_state(INITIAL); yy_push_state(doc_block); yymore(); } -\/\* { yy_push_state(doc_block); yymore(); } -\*\/ { - yy_pop_state(); - if (yy_top_state() == doc_block) { - yymore(); - } else { - return ((yytext[2] == '!') ? INNER_DOC_COMMENT : OUTER_DOC_COMMENT); - } -} -(.|\n) { yymore(); } - -\/\* { yy_push_state(blockcomment); } -\/\* { yy_push_state(blockcomment); } -\*\/ { yy_pop_state(); } -(.|\n) { } - -_ { return UNDERSCORE; } -as { return AS; } -box { return BOX; } -break { return BREAK; } -const { return CONST; } -continue { return CONTINUE; } -crate { return CRATE; } -else { return ELSE; } -enum { return ENUM; } -extern { return EXTERN; } -false { return FALSE; } -fn { return FN; } -for { return FOR; } -if { return IF; } -impl { return IMPL; } -in { return IN; } -let { return LET; } -loop { return LOOP; } -match { return MATCH; } -mod { return MOD; } -move { return MOVE; } -mut { return MUT; } -priv { return PRIV; } -proc { return PROC; } -pub { return PUB; } -ref { return REF; } -return { return RETURN; } -self { return SELF; } -static { return STATIC; } -struct { return STRUCT; } -trait { return TRAIT; } -true { return TRUE; } -type { return TYPE; } -typeof { return TYPEOF; } -unsafe { return UNSAFE; } -use { return USE; } -where { return WHERE; } -while { return WHILE; } - -{ident} { return IDENT; } - -0x[0-9a-fA-F_]+ { BEGIN(suffix); return LIT_INTEGER; } -0o[0-8_]+ { BEGIN(suffix); return LIT_INTEGER; } -0b[01_]+ { BEGIN(suffix); return LIT_INTEGER; } -[0-9][0-9_]* { BEGIN(suffix); return LIT_INTEGER; } -[0-9][0-9_]*\.(\.|[a-zA-Z]) { yyless(yyleng - 2); BEGIN(suffix); return LIT_INTEGER; } - -[0-9][0-9_]*\.[0-9_]*([eE][-\+]?[0-9_]+)? { BEGIN(suffix); return LIT_FLOAT; } -[0-9][0-9_]*(\.[0-9_]*)?[eE][-\+]?[0-9_]+ { BEGIN(suffix); return LIT_FLOAT; } - -; { return ';'; } -, { return ','; } -\.\.\. { return DOTDOTDOT; } -\.\. { return DOTDOT; } -\. { return '.'; } -\( { return '('; } -\) { return ')'; } -\{ { return '{'; } -\} { return '}'; } -\[ { return '['; } -\] { return ']'; } -@ { return '@'; } -# { BEGIN(pound); yymore(); } -\! { BEGIN(shebang_or_attr); yymore(); } -\[ { - BEGIN(INITIAL); - yyless(2); - return SHEBANG; -} -[^\[\n]*\n { - // Since the \n was eaten as part of the token, yylineno will have - // been incremented to the value 2 if the shebang was on the first - // line. This yyless undoes that, setting yylineno back to 1. - yyless(yyleng - 1); - if (yyget_lineno() == 1) { - BEGIN(INITIAL); - return SHEBANG_LINE; - } else { - BEGIN(INITIAL); - yyless(2); - return SHEBANG; - } -} -. { BEGIN(INITIAL); yyless(1); return '#'; } - -\~ { return '~'; } -:: { return MOD_SEP; } -: { return ':'; } -\$ { return '$'; } -\? { return '?'; } - -== { return EQEQ; } -=> { return FAT_ARROW; } -= { return '='; } -\!= { return NE; } -\! { return '!'; } -\<= { return LE; } -\<\< { return SHL; } -\<\<= { return SHLEQ; } -\< { return '<'; } -\>= { return GE; } -\>\> { return SHR; } -\>\>= { return SHREQ; } -\> { return '>'; } - -\x27 { BEGIN(ltorchar); yymore(); } -static { BEGIN(INITIAL); return STATIC_LIFETIME; } -{ident} { BEGIN(INITIAL); return LIFETIME; } -\\[nrt\\\x27\x220]\x27 { BEGIN(suffix); return LIT_CHAR; } -\\x[0-9a-fA-F]{2}\x27 { BEGIN(suffix); return LIT_CHAR; } -\\u\{[0-9a-fA-F]?{6}\}\x27 { BEGIN(suffix); return LIT_CHAR; } -.\x27 { BEGIN(suffix); return LIT_CHAR; } -[\x80-\xff]{2,4}\x27 { BEGIN(suffix); return LIT_CHAR; } -<> { BEGIN(INITIAL); return -1; } - -b\x22 { BEGIN(bytestr); yymore(); } -\x22 { BEGIN(suffix); return LIT_BYTE_STR; } - -<> { return -1; } -\\[n\nrt\\\x27\x220] { yymore(); } -\\x[0-9a-fA-F]{2} { yymore(); } -\\u\{[0-9a-fA-F]?{6}\} { yymore(); } -\\[^n\nrt\\\x27\x220] { return -1; } -(.|\n) { yymore(); } - -br\x22 { BEGIN(rawbytestr_nohash); yymore(); } -\x22 { BEGIN(suffix); return LIT_BYTE_STR_RAW; } -(.|\n) { yymore(); } -<> { return -1; } - -br/# { - BEGIN(rawbytestr); - yymore(); - num_hashes = 0; - saw_non_hash = 0; - end_hashes = 0; -} -# { - if (!saw_non_hash) { - num_hashes++; - } else if (end_hashes != 0) { - end_hashes++; - if (end_hashes == num_hashes) { - BEGIN(INITIAL); - return LIT_BYTE_STR_RAW; - } - } - yymore(); -} -\x22# { - end_hashes = 1; - if (end_hashes == num_hashes) { - BEGIN(INITIAL); - return LIT_BYTE_STR_RAW; - } - yymore(); -} -(.|\n) { - if (!saw_non_hash) { - saw_non_hash = 1; - } - if (end_hashes != 0) { - end_hashes = 0; - } - yymore(); -} -<> { return -1; } - -b\x27 { BEGIN(byte); yymore(); } -\\[nrt\\\x27\x220]\x27 { BEGIN(INITIAL); return LIT_BYTE; } -\\x[0-9a-fA-F]{2}\x27 { BEGIN(INITIAL); return LIT_BYTE; } -\\u[0-9a-fA-F]{4}\x27 { BEGIN(INITIAL); return LIT_BYTE; } -\\U[0-9a-fA-F]{8}\x27 { BEGIN(INITIAL); return LIT_BYTE; } -.\x27 { BEGIN(INITIAL); return LIT_BYTE; } -<> { BEGIN(INITIAL); return -1; } - -r\x22 { BEGIN(rawstr); yymore(); } -\x22 { BEGIN(suffix); return LIT_STR_RAW; } -(.|\n) { yymore(); } -<> { return -1; } - -r/# { - BEGIN(rawstr_esc_begin); - yymore(); - num_hashes = 0; - saw_non_hash = 0; - end_hashes = 0; -} - -# { - num_hashes++; - yymore(); -} -\x22 { - BEGIN(rawstr_esc_body); - yymore(); -} -(.|\n) { return -1; } - -\x22/# { - BEGIN(rawstr_esc_end); - yymore(); - } -(.|\n) { - yymore(); - } - -# { - end_hashes++; - if (end_hashes == num_hashes) { - BEGIN(INITIAL); - return LIT_STR_RAW; - } - yymore(); - } -[^#] { - end_hashes = 0; - BEGIN(rawstr_esc_body); - yymore(); - } - -<> { return -1; } - -\x22 { BEGIN(str); yymore(); } -\x22 { BEGIN(suffix); return LIT_STR; } - -<> { return -1; } -\\[n\nr\rt\\\x27\x220] { yymore(); } -\\x[0-9a-fA-F]{2} { yymore(); } -\\u\{[0-9a-fA-F]?{6}\} { yymore(); } -\\[^n\nrt\\\x27\x220] { return -1; } -(.|\n) { yymore(); } - -\<- { return LARROW; } --\> { return RARROW; } -- { return '-'; } --= { return MINUSEQ; } -&& { return ANDAND; } -& { return '&'; } -&= { return ANDEQ; } -\|\| { return OROR; } -\| { return '|'; } -\|= { return OREQ; } -\+ { return '+'; } -\+= { return PLUSEQ; } -\* { return '*'; } -\*= { return STAREQ; } -\/ { return '/'; } -\/= { return SLASHEQ; } -\^ { return '^'; } -\^= { return CARETEQ; } -% { return '%'; } -%= { return PERCENTEQ; } - -<> { return 0; } - -%% diff --git a/src/grammar/parser-lalr-main.c b/src/grammar/parser-lalr-main.c deleted file mode 100644 index db88a1f2999a..000000000000 --- a/src/grammar/parser-lalr-main.c +++ /dev/null @@ -1,203 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#include -#include -#include -#include - -extern int yylex(); -extern int rsparse(); - -#define PUSHBACK_LEN 4 - -static char pushback[PUSHBACK_LEN]; -static int verbose; - -void print(const char* format, ...) { - va_list args; - va_start(args, format); - if (verbose) { - vprintf(format, args); - } - va_end(args); -} - -// If there is a non-null char at the head of the pushback queue, -// dequeue it and shift the rest of the queue forwards. Otherwise, -// return the token from calling yylex. -int rslex() { - if (pushback[0] == '\0') { - return yylex(); - } else { - char c = pushback[0]; - memmove(pushback, pushback + 1, PUSHBACK_LEN - 1); - pushback[PUSHBACK_LEN - 1] = '\0'; - return c; - } -} - -// Note: this does nothing if the pushback queue is full. As long as -// there aren't more than PUSHBACK_LEN consecutive calls to push_back -// in an action, this shouldn't be a problem. -void push_back(char c) { - for (int i = 0; i < PUSHBACK_LEN; ++i) { - if (pushback[i] == '\0') { - pushback[i] = c; - break; - } - } -} - -extern int rsdebug; - -struct node { - struct node *next; - struct node *prev; - int own_string; - char const *name; - int n_elems; - struct node *elems[]; -}; - -struct node *nodes = NULL; -int n_nodes; - -struct node *mk_node(char const *name, int n, ...) { - va_list ap; - int i = 0; - unsigned sz = sizeof(struct node) + (n * sizeof(struct node *)); - struct node *nn, *nd = (struct node *)malloc(sz); - - print("# New %d-ary node: %s = %p\n", n, name, nd); - - nd->own_string = 0; - nd->prev = NULL; - nd->next = nodes; - if (nodes) { - nodes->prev = nd; - } - nodes = nd; - - nd->name = name; - nd->n_elems = n; - - va_start(ap, n); - while (i < n) { - nn = va_arg(ap, struct node *); - print("# arg[%d]: %p\n", i, nn); - print("# (%s ...)\n", nn->name); - nd->elems[i++] = nn; - } - va_end(ap); - n_nodes++; - return nd; -} - -struct node *mk_atom(char *name) { - struct node *nd = mk_node((char const *)strdup(name), 0); - nd->own_string = 1; - return nd; -} - -struct node *mk_none() { - return mk_atom(""); -} - -struct node *ext_node(struct node *nd, int n, ...) { - va_list ap; - int i = 0, c = nd->n_elems + n; - unsigned sz = sizeof(struct node) + (c * sizeof(struct node *)); - struct node *nn; - - print("# Extending %d-ary node by %d nodes: %s = %p", - nd->n_elems, c, nd->name, nd); - - if (nd->next) { - nd->next->prev = nd->prev; - } - if (nd->prev) { - nd->prev->next = nd->next; - } - nd = realloc(nd, sz); - nd->prev = NULL; - nd->next = nodes; - nodes->prev = nd; - nodes = nd; - - print(" ==> %p\n", nd); - - va_start(ap, n); - while (i < n) { - nn = va_arg(ap, struct node *); - print("# arg[%d]: %p\n", i, nn); - print("# (%s ...)\n", nn->name); - nd->elems[nd->n_elems++] = nn; - ++i; - } - va_end(ap); - return nd; -} - -int const indent_step = 4; - -void print_indent(int depth) { - while (depth) { - if (depth-- % indent_step == 0) { - print("|"); - } else { - print(" "); - } - } -} - -void print_node(struct node *n, int depth) { - int i = 0; - print_indent(depth); - if (n->n_elems == 0) { - print("%s\n", n->name); - } else { - print("(%s\n", n->name); - for (i = 0; i < n->n_elems; ++i) { - print_node(n->elems[i], depth + indent_step); - } - print_indent(depth); - print(")\n"); - } -} - -int main(int argc, char **argv) { - if (argc == 2 && strcmp(argv[1], "-v") == 0) { - verbose = 1; - } else { - verbose = 0; - } - int ret = 0; - struct node *tmp; - memset(pushback, '\0', PUSHBACK_LEN); - ret = rsparse(); - print("--- PARSE COMPLETE: ret:%d, n_nodes:%d ---\n", ret, n_nodes); - if (nodes) { - print_node(nodes, 0); - } - while (nodes) { - tmp = nodes; - nodes = tmp->next; - if (tmp->own_string) { - free((void*)tmp->name); - } - free(tmp); - } - return ret; -} - -void rserror(char const *s) { - fprintf(stderr, "%s\n", s); -} diff --git a/src/grammar/parser-lalr.y b/src/grammar/parser-lalr.y deleted file mode 100644 index 3aa76d168df0..000000000000 --- a/src/grammar/parser-lalr.y +++ /dev/null @@ -1,1938 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -%{ -#define YYERROR_VERBOSE -#define YYSTYPE struct node * -struct node; -extern int yylex(); -extern void yyerror(char const *s); -extern struct node *mk_node(char const *name, int n, ...); -extern struct node *mk_atom(char *text); -extern struct node *mk_none(); -extern struct node *ext_node(struct node *nd, int n, ...); -extern void push_back(char c); -extern char *yytext; -%} -%debug - -%token SHL -%token SHR -%token LE -%token EQEQ -%token NE -%token GE -%token ANDAND -%token OROR -%token SHLEQ -%token SHREQ -%token MINUSEQ -%token ANDEQ -%token OREQ -%token PLUSEQ -%token STAREQ -%token SLASHEQ -%token CARETEQ -%token PERCENTEQ -%token DOTDOT -%token DOTDOTDOT -%token MOD_SEP -%token RARROW -%token LARROW -%token FAT_ARROW -%token LIT_BYTE -%token LIT_CHAR -%token LIT_INTEGER -%token LIT_FLOAT -%token LIT_STR -%token LIT_STR_RAW -%token LIT_BYTE_STR -%token LIT_BYTE_STR_RAW -%token IDENT -%token UNDERSCORE -%token LIFETIME - -// keywords -%token SELF -%token STATIC -%token AS -%token BREAK -%token CRATE -%token ELSE -%token ENUM -%token EXTERN -%token FALSE -%token FN -%token FOR -%token IF -%token IMPL -%token IN -%token LET -%token LOOP -%token MATCH -%token MOD -%token MOVE -%token MUT -%token PRIV -%token PUB -%token REF -%token RETURN -%token STRUCT -%token TRUE -%token TRAIT -%token TYPE -%token UNSAFE -%token USE -%token WHILE -%token CONTINUE -%token PROC -%token BOX -%token CONST -%token WHERE -%token TYPEOF -%token INNER_DOC_COMMENT -%token OUTER_DOC_COMMENT - -%token SHEBANG -%token SHEBANG_LINE -%token STATIC_LIFETIME - - /* - Quoting from the Bison manual: - - "Finally, the resolution of conflicts works by comparing the precedence - of the rule being considered with that of the lookahead token. If the - token's precedence is higher, the choice is to shift. If the rule's - precedence is higher, the choice is to reduce. If they have equal - precedence, the choice is made based on the associativity of that - precedence level. The verbose output file made by ‘-v’ (see Invoking - Bison) says how each conflict was resolved" - */ - -// We expect no shift/reduce or reduce/reduce conflicts in this grammar; -// all potential ambiguities are scrutinized and eliminated manually. -%expect 0 - -// fake-precedence symbol to cause '|' bars in lambda context to parse -// at low precedence, permit things like |x| foo = bar, where '=' is -// otherwise lower-precedence than '|'. Also used for proc() to cause -// things like proc() a + b to parse as proc() { a + b }. -%precedence LAMBDA - -%precedence SELF - -// MUT should be lower precedence than IDENT so that in the pat rule, -// "& MUT pat" has higher precedence than "binding_mode ident [@ pat]" -%precedence MUT - -// IDENT needs to be lower than '{' so that 'foo {' is shifted when -// trying to decide if we've got a struct-construction expr (esp. in -// contexts like 'if foo { .') -// -// IDENT also needs to be lower precedence than '<' so that '<' in -// 'foo:bar . <' is shifted (in a trait reference occurring in a -// bounds list), parsing as foo:(bar) rather than (foo:bar). -%precedence IDENT - -// A couple fake-precedence symbols to use in rules associated with + -// and < in trailing type contexts. These come up when you have a type -// in the RHS of operator-AS, such as "foo as bar". The "<" there -// has to be shifted so the parser keeps trying to parse a type, even -// though it might well consider reducing the type "bar" and then -// going on to "<" as a subsequent binop. The "+" case is with -// trailing type-bounds ("foo as bar:A+B"), for the same reason. -%precedence SHIFTPLUS - -%precedence MOD_SEP -%precedence RARROW ':' - -// In where clauses, "for" should have greater precedence when used as -// a higher ranked constraint than when used as the beginning of a -// for_in_type (which is a ty) -%precedence FORTYPE -%precedence FOR - -// Binops & unops, and their precedences -%precedence BOX -%precedence BOXPLACE -%nonassoc DOTDOT - -// RETURN needs to be lower-precedence than tokens that start -// prefix_exprs -%precedence RETURN - -%right '=' SHLEQ SHREQ MINUSEQ ANDEQ OREQ PLUSEQ STAREQ SLASHEQ CARETEQ PERCENTEQ -%right LARROW -%left OROR -%left ANDAND -%left EQEQ NE -%left '<' '>' LE GE -%left '|' -%left '^' -%left '&' -%left SHL SHR -%left '+' '-' -%precedence AS -%left '*' '/' '%' -%precedence '!' - -%precedence '{' '[' '(' '.' - -%precedence RANGE - -%start crate - -%% - -//////////////////////////////////////////////////////////////////////// -// Part 1: Items and attributes -//////////////////////////////////////////////////////////////////////// - -crate -: maybe_shebang inner_attrs maybe_mod_items { mk_node("crate", 2, $2, $3); } -| maybe_shebang maybe_mod_items { mk_node("crate", 1, $2); } -; - -maybe_shebang -: SHEBANG_LINE -| %empty -; - -maybe_inner_attrs -: inner_attrs -| %empty { $$ = mk_none(); } -; - -inner_attrs -: inner_attr { $$ = mk_node("InnerAttrs", 1, $1); } -| inner_attrs inner_attr { $$ = ext_node($1, 1, $2); } -; - -inner_attr -: SHEBANG '[' meta_item ']' { $$ = mk_node("InnerAttr", 1, $3); } -| INNER_DOC_COMMENT { $$ = mk_node("InnerAttr", 1, mk_node("doc-comment", 1, mk_atom(yytext))); } -; - -maybe_outer_attrs -: outer_attrs -| %empty { $$ = mk_none(); } -; - -outer_attrs -: outer_attr { $$ = mk_node("OuterAttrs", 1, $1); } -| outer_attrs outer_attr { $$ = ext_node($1, 1, $2); } -; - -outer_attr -: '#' '[' meta_item ']' { $$ = $3; } -| OUTER_DOC_COMMENT { $$ = mk_node("doc-comment", 1, mk_atom(yytext)); } -; - -meta_item -: ident { $$ = mk_node("MetaWord", 1, $1); } -| ident '=' lit { $$ = mk_node("MetaNameValue", 2, $1, $3); } -| ident '(' meta_seq ')' { $$ = mk_node("MetaList", 2, $1, $3); } -| ident '(' meta_seq ',' ')' { $$ = mk_node("MetaList", 2, $1, $3); } -; - -meta_seq -: %empty { $$ = mk_none(); } -| meta_item { $$ = mk_node("MetaItems", 1, $1); } -| meta_seq ',' meta_item { $$ = ext_node($1, 1, $3); } -; - -maybe_mod_items -: mod_items -| %empty { $$ = mk_none(); } -; - -mod_items -: mod_item { $$ = mk_node("Items", 1, $1); } -| mod_items mod_item { $$ = ext_node($1, 1, $2); } -; - -attrs_and_vis -: maybe_outer_attrs visibility { $$ = mk_node("AttrsAndVis", 2, $1, $2); } -; - -mod_item -: attrs_and_vis item { $$ = mk_node("Item", 2, $1, $2); } -; - -// items that can appear outside of a fn block -item -: stmt_item -| item_macro -; - -// items that can appear in "stmts" -stmt_item -: item_static -| item_const -| item_type -| block_item -| view_item -; - -item_static -: STATIC ident ':' ty '=' expr ';' { $$ = mk_node("ItemStatic", 3, $2, $4, $6); } -| STATIC MUT ident ':' ty '=' expr ';' { $$ = mk_node("ItemStatic", 3, $3, $5, $7); } -; - -item_const -: CONST ident ':' ty '=' expr ';' { $$ = mk_node("ItemConst", 3, $2, $4, $6); } -; - -item_macro -: path_expr '!' maybe_ident parens_delimited_token_trees ';' { $$ = mk_node("ItemMacro", 3, $1, $3, $4); } -| path_expr '!' maybe_ident braces_delimited_token_trees { $$ = mk_node("ItemMacro", 3, $1, $3, $4); } -| path_expr '!' maybe_ident brackets_delimited_token_trees ';'{ $$ = mk_node("ItemMacro", 3, $1, $3, $4); } -; - -view_item -: use_item -| extern_fn_item -| EXTERN CRATE ident ';' { $$ = mk_node("ViewItemExternCrate", 1, $3); } -| EXTERN CRATE ident AS ident ';' { $$ = mk_node("ViewItemExternCrate", 2, $3, $5); } -; - -extern_fn_item -: EXTERN maybe_abi item_fn { $$ = mk_node("ViewItemExternFn", 2, $2, $3); } -; - -use_item -: USE view_path ';' { $$ = mk_node("ViewItemUse", 1, $2); } -; - -view_path -: path_no_types_allowed { $$ = mk_node("ViewPathSimple", 1, $1); } -| path_no_types_allowed MOD_SEP '{' '}' { $$ = mk_node("ViewPathList", 2, $1, mk_atom("ViewPathListEmpty")); } -| MOD_SEP '{' '}' { $$ = mk_node("ViewPathList", 1, mk_atom("ViewPathListEmpty")); } -| path_no_types_allowed MOD_SEP '{' idents_or_self '}' { $$ = mk_node("ViewPathList", 2, $1, $4); } -| MOD_SEP '{' idents_or_self '}' { $$ = mk_node("ViewPathList", 1, $3); } -| path_no_types_allowed MOD_SEP '{' idents_or_self ',' '}' { $$ = mk_node("ViewPathList", 2, $1, $4); } -| MOD_SEP '{' idents_or_self ',' '}' { $$ = mk_node("ViewPathList", 1, $3); } -| path_no_types_allowed MOD_SEP '*' { $$ = mk_node("ViewPathGlob", 1, $1); } -| '{' '}' { $$ = mk_atom("ViewPathListEmpty"); } -| '{' idents_or_self '}' { $$ = mk_node("ViewPathList", 1, $2); } -| '{' idents_or_self ',' '}' { $$ = mk_node("ViewPathList", 1, $2); } -| path_no_types_allowed AS ident { $$ = mk_node("ViewPathSimple", 2, $1, $3); } -; - -block_item -: item_fn -| item_unsafe_fn -| item_mod -| item_foreign_mod { $$ = mk_node("ItemForeignMod", 1, $1); } -| item_struct -| item_enum -| item_trait -| item_impl -; - -maybe_ty_ascription -: ':' ty_sum { $$ = $2; } -| %empty { $$ = mk_none(); } -; - -maybe_init_expr -: '=' expr { $$ = $2; } -| %empty { $$ = mk_none(); } -; - -// structs -item_struct -: STRUCT ident generic_params maybe_where_clause struct_decl_args -{ - $$ = mk_node("ItemStruct", 4, $2, $3, $4, $5); -} -| STRUCT ident generic_params struct_tuple_args maybe_where_clause ';' -{ - $$ = mk_node("ItemStruct", 4, $2, $3, $4, $5); -} -| STRUCT ident generic_params maybe_where_clause ';' -{ - $$ = mk_node("ItemStruct", 3, $2, $3, $4); -} -; - -struct_decl_args -: '{' struct_decl_fields '}' { $$ = $2; } -| '{' struct_decl_fields ',' '}' { $$ = $2; } -; - -struct_tuple_args -: '(' struct_tuple_fields ')' { $$ = $2; } -| '(' struct_tuple_fields ',' ')' { $$ = $2; } -; - -struct_decl_fields -: struct_decl_field { $$ = mk_node("StructFields", 1, $1); } -| struct_decl_fields ',' struct_decl_field { $$ = ext_node($1, 1, $3); } -| %empty { $$ = mk_none(); } -; - -struct_decl_field -: attrs_and_vis ident ':' ty_sum { $$ = mk_node("StructField", 3, $1, $2, $4); } -; - -struct_tuple_fields -: struct_tuple_field { $$ = mk_node("StructFields", 1, $1); } -| struct_tuple_fields ',' struct_tuple_field { $$ = ext_node($1, 1, $3); } -; - -struct_tuple_field -: attrs_and_vis ty_sum { $$ = mk_node("StructField", 2, $1, $2); } -; - -// enums -item_enum -: ENUM ident generic_params maybe_where_clause '{' enum_defs '}' { $$ = mk_node("ItemEnum", 0); } -| ENUM ident generic_params maybe_where_clause '{' enum_defs ',' '}' { $$ = mk_node("ItemEnum", 0); } -; - -enum_defs -: enum_def { $$ = mk_node("EnumDefs", 1, $1); } -| enum_defs ',' enum_def { $$ = ext_node($1, 1, $3); } -| %empty { $$ = mk_none(); } -; - -enum_def -: attrs_and_vis ident enum_args { $$ = mk_node("EnumDef", 3, $1, $2, $3); } -; - -enum_args -: '{' struct_decl_fields '}' { $$ = mk_node("EnumArgs", 1, $2); } -| '{' struct_decl_fields ',' '}' { $$ = mk_node("EnumArgs", 1, $2); } -| '(' maybe_ty_sums ')' { $$ = mk_node("EnumArgs", 1, $2); } -| '=' expr { $$ = mk_node("EnumArgs", 1, $2); } -| %empty { $$ = mk_none(); } -; - -item_mod -: MOD ident ';' { $$ = mk_node("ItemMod", 1, $2); } -| MOD ident '{' maybe_mod_items '}' { $$ = mk_node("ItemMod", 2, $2, $4); } -| MOD ident '{' inner_attrs maybe_mod_items '}' { $$ = mk_node("ItemMod", 3, $2, $4, $5); } -; - -item_foreign_mod -: EXTERN maybe_abi '{' maybe_foreign_items '}' { $$ = mk_node("ItemForeignMod", 1, $4); } -| EXTERN maybe_abi '{' inner_attrs maybe_foreign_items '}' { $$ = mk_node("ItemForeignMod", 2, $4, $5); } -; - -maybe_abi -: str -| %empty { $$ = mk_none(); } -; - -maybe_foreign_items -: foreign_items -| %empty { $$ = mk_none(); } -; - -foreign_items -: foreign_item { $$ = mk_node("ForeignItems", 1, $1); } -| foreign_items foreign_item { $$ = ext_node($1, 1, $2); } -; - -foreign_item -: attrs_and_vis STATIC item_foreign_static { $$ = mk_node("ForeignItem", 2, $1, $3); } -| attrs_and_vis item_foreign_fn { $$ = mk_node("ForeignItem", 2, $1, $2); } -| attrs_and_vis UNSAFE item_foreign_fn { $$ = mk_node("ForeignItem", 2, $1, $3); } -; - -item_foreign_static -: maybe_mut ident ':' ty ';' { $$ = mk_node("StaticItem", 3, $1, $2, $4); } -; - -item_foreign_fn -: FN ident generic_params fn_decl_allow_variadic maybe_where_clause ';' { $$ = mk_node("ForeignFn", 4, $2, $3, $4, $5); } -; - -fn_decl_allow_variadic -: fn_params_allow_variadic ret_ty { $$ = mk_node("FnDecl", 2, $1, $2); } -; - -fn_params_allow_variadic -: '(' ')' { $$ = mk_none(); } -| '(' params ')' { $$ = $2; } -| '(' params ',' ')' { $$ = $2; } -| '(' params ',' DOTDOTDOT ')' { $$ = $2; } -; - -visibility -: PUB { $$ = mk_atom("Public"); } -| %empty { $$ = mk_atom("Inherited"); } -; - -idents_or_self -: ident_or_self { $$ = mk_node("IdentsOrSelf", 1, $1); } -| ident_or_self AS ident { $$ = mk_node("IdentsOrSelf", 2, $1, $3); } -| idents_or_self ',' ident_or_self { $$ = ext_node($1, 1, $3); } -; - -ident_or_self -: ident -| SELF { $$ = mk_atom(yytext); } -; - -item_type -: TYPE ident generic_params maybe_where_clause '=' ty_sum ';' { $$ = mk_node("ItemTy", 4, $2, $3, $4, $6); } -; - -for_sized -: FOR '?' ident { $$ = mk_node("ForSized", 1, $3); } -| FOR ident '?' { $$ = mk_node("ForSized", 1, $2); } -| %empty { $$ = mk_none(); } -; - -item_trait -: maybe_unsafe TRAIT ident generic_params for_sized maybe_ty_param_bounds maybe_where_clause '{' maybe_trait_items '}' -{ - $$ = mk_node("ItemTrait", 7, $1, $3, $4, $5, $6, $7, $9); -} -; - -maybe_trait_items -: trait_items -| %empty { $$ = mk_none(); } -; - -trait_items -: trait_item { $$ = mk_node("TraitItems", 1, $1); } -| trait_items trait_item { $$ = ext_node($1, 1, $2); } -; - -trait_item -: trait_const -| trait_type -| trait_method -; - -trait_const -: maybe_outer_attrs CONST ident maybe_ty_ascription maybe_const_default ';' { $$ = mk_node("ConstTraitItem", 4, $1, $3, $4, $5); } -; - -maybe_const_default -: '=' expr { $$ = mk_node("ConstDefault", 1, $2); } -| %empty { $$ = mk_none(); } -; - -trait_type -: maybe_outer_attrs TYPE ty_param ';' { $$ = mk_node("TypeTraitItem", 2, $1, $3); } -; - -maybe_unsafe -: UNSAFE { $$ = mk_atom("Unsafe"); } -| %empty { $$ = mk_none(); } -; - -trait_method -: type_method { $$ = mk_node("Required", 1, $1); } -| method { $$ = mk_node("Provided", 1, $1); } -; - -type_method -: attrs_and_vis maybe_unsafe FN ident generic_params fn_decl_with_self_allow_anon_params maybe_where_clause ';' -{ - $$ = mk_node("TypeMethod", 6, $1, $2, $4, $5, $6, $7); -} -| attrs_and_vis maybe_unsafe EXTERN maybe_abi FN ident generic_params fn_decl_with_self_allow_anon_params maybe_where_clause ';' -{ - $$ = mk_node("TypeMethod", 7, $1, $2, $4, $6, $7, $8, $9); -} -; - -method -: attrs_and_vis maybe_unsafe FN ident generic_params fn_decl_with_self_allow_anon_params maybe_where_clause inner_attrs_and_block -{ - $$ = mk_node("Method", 7, $1, $2, $4, $5, $6, $7, $8); -} -| attrs_and_vis maybe_unsafe EXTERN maybe_abi FN ident generic_params fn_decl_with_self_allow_anon_params maybe_where_clause inner_attrs_and_block -{ - $$ = mk_node("Method", 8, $1, $2, $4, $6, $7, $8, $9, $10); -} -; - -impl_method -: attrs_and_vis maybe_unsafe FN ident generic_params fn_decl_with_self maybe_where_clause inner_attrs_and_block -{ - $$ = mk_node("Method", 7, $1, $2, $4, $5, $6, $7, $8); -} -| attrs_and_vis maybe_unsafe EXTERN maybe_abi FN ident generic_params fn_decl_with_self maybe_where_clause inner_attrs_and_block -{ - $$ = mk_node("Method", 8, $1, $2, $4, $6, $7, $8, $9, $10); -} -; - -// There are two forms of impl: -// -// impl (<...>)? TY { ... } -// impl (<...>)? TRAIT for TY { ... } -// -// Unfortunately since TY can begin with '<' itself -- as part of a -// TyQualifiedPath type -- there's an s/r conflict when we see '<' after IMPL: -// should we reduce one of the early rules of TY (such as maybe_once) -// or shall we continue shifting into the generic_params list for the -// impl? -// -// The production parser disambiguates a different case here by -// permitting / requiring the user to provide parens around types when -// they are ambiguous with traits. We do the same here, regrettably, -// by splitting ty into ty and ty_prim. -item_impl -: maybe_unsafe IMPL generic_params ty_prim_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}' -{ - $$ = mk_node("ItemImpl", 6, $1, $3, $4, $5, $7, $8); -} -| maybe_unsafe IMPL generic_params '(' ty ')' maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}' -{ - $$ = mk_node("ItemImpl", 6, $1, $3, 5, $6, $9, $10); -} -| maybe_unsafe IMPL generic_params trait_ref FOR ty_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}' -{ - $$ = mk_node("ItemImpl", 6, $3, $4, $6, $7, $9, $10); -} -| maybe_unsafe IMPL generic_params '!' trait_ref FOR ty_sum maybe_where_clause '{' maybe_inner_attrs maybe_impl_items '}' -{ - $$ = mk_node("ItemImplNeg", 7, $1, $3, $5, $7, $8, $10, $11); -} -| maybe_unsafe IMPL generic_params trait_ref FOR DOTDOT '{' '}' -{ - $$ = mk_node("ItemImplDefault", 3, $1, $3, $4); -} -| maybe_unsafe IMPL generic_params '!' trait_ref FOR DOTDOT '{' '}' -{ - $$ = mk_node("ItemImplDefaultNeg", 3, $1, $3, $4); -} -; - -maybe_impl_items -: impl_items -| %empty { $$ = mk_none(); } -; - -impl_items -: impl_item { $$ = mk_node("ImplItems", 1, $1); } -| impl_item impl_items { $$ = ext_node($1, 1, $2); } -; - -impl_item -: impl_method -| attrs_and_vis item_macro { $$ = mk_node("ImplMacroItem", 2, $1, $2); } -| impl_const -| impl_type -; - -impl_const -: attrs_and_vis item_const { $$ = mk_node("ImplConst", 1, $1, $2); } -; - -impl_type -: attrs_and_vis TYPE ident generic_params '=' ty_sum ';' { $$ = mk_node("ImplType", 4, $1, $3, $4, $6); } -; - -item_fn -: FN ident generic_params fn_decl maybe_where_clause inner_attrs_and_block -{ - $$ = mk_node("ItemFn", 5, $2, $3, $4, $5, $6); -} -; - -item_unsafe_fn -: UNSAFE FN ident generic_params fn_decl maybe_where_clause inner_attrs_and_block -{ - $$ = mk_node("ItemUnsafeFn", 5, $3, $4, $5, $6, $7); -} -| UNSAFE EXTERN maybe_abi FN ident generic_params fn_decl maybe_where_clause inner_attrs_and_block -{ - $$ = mk_node("ItemUnsafeFn", 6, $3, $5, $6, $7, $8, $9); -} -; - -fn_decl -: fn_params ret_ty { $$ = mk_node("FnDecl", 2, $1, $2); } -; - -fn_decl_with_self -: fn_params_with_self ret_ty { $$ = mk_node("FnDecl", 2, $1, $2); } -; - -fn_decl_with_self_allow_anon_params -: fn_anon_params_with_self ret_ty { $$ = mk_node("FnDecl", 2, $1, $2); } -; - -fn_params -: '(' maybe_params ')' { $$ = $2; } -; - -fn_anon_params -: '(' anon_param anon_params_allow_variadic_tail ')' { $$ = ext_node($2, 1, $3); } -| '(' ')' { $$ = mk_none(); } -; - -fn_params_with_self -: '(' maybe_mut SELF maybe_ty_ascription maybe_comma_params ')' { $$ = mk_node("SelfValue", 3, $2, $4, $5); } -| '(' '&' maybe_mut SELF maybe_ty_ascription maybe_comma_params ')' { $$ = mk_node("SelfRegion", 3, $3, $5, $6); } -| '(' '&' lifetime maybe_mut SELF maybe_ty_ascription maybe_comma_params ')' { $$ = mk_node("SelfRegion", 4, $3, $4, $6, $7); } -| '(' maybe_params ')' { $$ = mk_node("SelfStatic", 1, $2); } -; - -fn_anon_params_with_self -: '(' maybe_mut SELF maybe_ty_ascription maybe_comma_anon_params ')' { $$ = mk_node("SelfValue", 3, $2, $4, $5); } -| '(' '&' maybe_mut SELF maybe_ty_ascription maybe_comma_anon_params ')' { $$ = mk_node("SelfRegion", 3, $3, $5, $6); } -| '(' '&' lifetime maybe_mut SELF maybe_ty_ascription maybe_comma_anon_params ')' { $$ = mk_node("SelfRegion", 4, $3, $4, $6, $7); } -| '(' maybe_anon_params ')' { $$ = mk_node("SelfStatic", 1, $2); } -; - -maybe_params -: params -| params ',' -| %empty { $$ = mk_none(); } -; - -params -: param { $$ = mk_node("Args", 1, $1); } -| params ',' param { $$ = ext_node($1, 1, $3); } -; - -param -: pat ':' ty_sum { $$ = mk_node("Arg", 2, $1, $3); } -; - -inferrable_params -: inferrable_param { $$ = mk_node("InferrableParams", 1, $1); } -| inferrable_params ',' inferrable_param { $$ = ext_node($1, 1, $3); } -; - -inferrable_param -: pat maybe_ty_ascription { $$ = mk_node("InferrableParam", 2, $1, $2); } -; - -maybe_unboxed_closure_kind -: %empty -| ':' -| '&' maybe_mut ':' -; - -maybe_comma_params -: ',' { $$ = mk_none(); } -| ',' params { $$ = $2; } -| ',' params ',' { $$ = $2; } -| %empty { $$ = mk_none(); } -; - -maybe_comma_anon_params -: ',' { $$ = mk_none(); } -| ',' anon_params { $$ = $2; } -| ',' anon_params ',' { $$ = $2; } -| %empty { $$ = mk_none(); } -; - -maybe_anon_params -: anon_params -| anon_params ',' -| %empty { $$ = mk_none(); } -; - -anon_params -: anon_param { $$ = mk_node("Args", 1, $1); } -| anon_params ',' anon_param { $$ = ext_node($1, 1, $3); } -; - -// anon means it's allowed to be anonymous (type-only), but it can -// still have a name -anon_param -: named_arg ':' ty { $$ = mk_node("Arg", 2, $1, $3); } -| ty -; - -anon_params_allow_variadic_tail -: ',' DOTDOTDOT { $$ = mk_none(); } -| ',' anon_param anon_params_allow_variadic_tail { $$ = mk_node("Args", 2, $2, $3); } -| %empty { $$ = mk_none(); } -; - -named_arg -: ident -| UNDERSCORE { $$ = mk_atom("PatWild"); } -| '&' ident { $$ = $2; } -| '&' UNDERSCORE { $$ = mk_atom("PatWild"); } -| ANDAND ident { $$ = $2; } -| ANDAND UNDERSCORE { $$ = mk_atom("PatWild"); } -| MUT ident { $$ = $2; } -; - -ret_ty -: RARROW '!' { $$ = mk_none(); } -| RARROW ty { $$ = mk_node("ret-ty", 1, $2); } -| %prec IDENT %empty { $$ = mk_none(); } -; - -generic_params -: '<' lifetimes '>' { $$ = mk_node("Generics", 2, $2, mk_none()); } -| '<' lifetimes ',' '>' { $$ = mk_node("Generics", 2, $2, mk_none()); } -| '<' lifetimes SHR { push_back('>'); $$ = mk_node("Generics", 2, $2, mk_none()); } -| '<' lifetimes ',' SHR { push_back('>'); $$ = mk_node("Generics", 2, $2, mk_none()); } -| '<' lifetimes ',' ty_params '>' { $$ = mk_node("Generics", 2, $2, $4); } -| '<' lifetimes ',' ty_params ',' '>' { $$ = mk_node("Generics", 2, $2, $4); } -| '<' lifetimes ',' ty_params SHR { push_back('>'); $$ = mk_node("Generics", 2, $2, $4); } -| '<' lifetimes ',' ty_params ',' SHR { push_back('>'); $$ = mk_node("Generics", 2, $2, $4); } -| '<' ty_params '>' { $$ = mk_node("Generics", 2, mk_none(), $2); } -| '<' ty_params ',' '>' { $$ = mk_node("Generics", 2, mk_none(), $2); } -| '<' ty_params SHR { push_back('>'); $$ = mk_node("Generics", 2, mk_none(), $2); } -| '<' ty_params ',' SHR { push_back('>'); $$ = mk_node("Generics", 2, mk_none(), $2); } -| %empty { $$ = mk_none(); } -; - -maybe_where_clause -: %empty { $$ = mk_none(); } -| where_clause -; - -where_clause -: WHERE where_predicates { $$ = mk_node("WhereClause", 1, $2); } -| WHERE where_predicates ',' { $$ = mk_node("WhereClause", 1, $2); } -; - -where_predicates -: where_predicate { $$ = mk_node("WherePredicates", 1, $1); } -| where_predicates ',' where_predicate { $$ = ext_node($1, 1, $3); } -; - -where_predicate -: maybe_for_lifetimes lifetime ':' bounds { $$ = mk_node("WherePredicate", 3, $1, $2, $4); } -| maybe_for_lifetimes ty ':' ty_param_bounds { $$ = mk_node("WherePredicate", 3, $1, $2, $4); } -; - -maybe_for_lifetimes -: FOR '<' lifetimes '>' { $$ = mk_none(); } -| %prec FORTYPE %empty { $$ = mk_none(); } - -ty_params -: ty_param { $$ = mk_node("TyParams", 1, $1); } -| ty_params ',' ty_param { $$ = ext_node($1, 1, $3); } -; - -// A path with no type parameters; e.g. `foo::bar::Baz` -// -// These show up in 'use' view-items, because these are processed -// without respect to types. -path_no_types_allowed -: ident { $$ = mk_node("ViewPath", 1, $1); } -| MOD_SEP ident { $$ = mk_node("ViewPath", 1, $2); } -| SELF { $$ = mk_node("ViewPath", 1, mk_atom("Self")); } -| MOD_SEP SELF { $$ = mk_node("ViewPath", 1, mk_atom("Self")); } -| path_no_types_allowed MOD_SEP ident { $$ = ext_node($1, 1, $3); } -; - -// A path with a lifetime and type parameters, with no double colons -// before the type parameters; e.g. `foo::bar<'a>::Baz` -// -// These show up in "trait references", the components of -// type-parameter bounds lists, as well as in the prefix of the -// path_generic_args_and_bounds rule, which is the full form of a -// named typed expression. -// -// They do not have (nor need) an extra '::' before '<' because -// unlike in expr context, there are no "less-than" type exprs to -// be ambiguous with. -path_generic_args_without_colons -: %prec IDENT - ident { $$ = mk_node("components", 1, $1); } -| %prec IDENT - ident generic_args { $$ = mk_node("components", 2, $1, $2); } -| %prec IDENT - ident '(' maybe_ty_sums ')' ret_ty { $$ = mk_node("components", 2, $1, $3); } -| %prec IDENT - path_generic_args_without_colons MOD_SEP ident { $$ = ext_node($1, 1, $3); } -| %prec IDENT - path_generic_args_without_colons MOD_SEP ident generic_args { $$ = ext_node($1, 2, $3, $4); } -| %prec IDENT - path_generic_args_without_colons MOD_SEP ident '(' maybe_ty_sums ')' ret_ty { $$ = ext_node($1, 2, $3, $5); } -; - -generic_args -: '<' generic_values '>' { $$ = $2; } -| '<' generic_values SHR { push_back('>'); $$ = $2; } -| '<' generic_values GE { push_back('='); $$ = $2; } -| '<' generic_values SHREQ { push_back('>'); push_back('='); $$ = $2; } -// If generic_args starts with "<<", the first arg must be a -// TyQualifiedPath because that's the only type that can start with a -// '<'. This rule parses that as the first ty_sum and then continues -// with the rest of generic_values. -| SHL ty_qualified_path_and_generic_values '>' { $$ = $2; } -| SHL ty_qualified_path_and_generic_values SHR { push_back('>'); $$ = $2; } -| SHL ty_qualified_path_and_generic_values GE { push_back('='); $$ = $2; } -| SHL ty_qualified_path_and_generic_values SHREQ { push_back('>'); push_back('='); $$ = $2; } -; - -generic_values -: maybe_lifetimes maybe_ty_sums_and_or_bindings { $$ = mk_node("GenericValues", 2, $1, $2); } -; - -maybe_ty_sums_and_or_bindings -: ty_sums -| ty_sums ',' -| ty_sums ',' bindings { $$ = mk_node("TySumsAndBindings", 2, $1, $3); } -| bindings -| bindings ',' -| %empty { $$ = mk_none(); } -; - -maybe_bindings -: ',' bindings { $$ = $2; } -| %empty { $$ = mk_none(); } -; - -//////////////////////////////////////////////////////////////////////// -// Part 2: Patterns -//////////////////////////////////////////////////////////////////////// - -pat -: UNDERSCORE { $$ = mk_atom("PatWild"); } -| '&' pat { $$ = mk_node("PatRegion", 1, $2); } -| '&' MUT pat { $$ = mk_node("PatRegion", 1, $3); } -| ANDAND pat { $$ = mk_node("PatRegion", 1, mk_node("PatRegion", 1, $2)); } -| '(' ')' { $$ = mk_atom("PatUnit"); } -| '(' pat_tup ')' { $$ = mk_node("PatTup", 1, $2); } -| '(' pat_tup ',' ')' { $$ = mk_node("PatTup", 1, $2); } -| '[' pat_vec ']' { $$ = mk_node("PatVec", 1, $2); } -| lit_or_path -| lit_or_path DOTDOTDOT lit_or_path { $$ = mk_node("PatRange", 2, $1, $3); } -| path_expr '{' pat_struct '}' { $$ = mk_node("PatStruct", 2, $1, $3); } -| path_expr '(' DOTDOT ')' { $$ = mk_node("PatEnum", 1, $1); } -| path_expr '(' pat_tup ')' { $$ = mk_node("PatEnum", 2, $1, $3); } -| path_expr '!' maybe_ident delimited_token_trees { $$ = mk_node("PatMac", 3, $1, $3, $4); } -| binding_mode ident { $$ = mk_node("PatIdent", 2, $1, $2); } -| ident '@' pat { $$ = mk_node("PatIdent", 3, mk_node("BindByValue", 1, mk_atom("MutImmutable")), $1, $3); } -| binding_mode ident '@' pat { $$ = mk_node("PatIdent", 3, $1, $2, $4); } -| BOX pat { $$ = mk_node("PatUniq", 1, $2); } -| '<' ty_sum maybe_as_trait_ref '>' MOD_SEP ident { $$ = mk_node("PatQualifiedPath", 3, $2, $3, $6); } -| SHL ty_sum maybe_as_trait_ref '>' MOD_SEP ident maybe_as_trait_ref '>' MOD_SEP ident -{ - $$ = mk_node("PatQualifiedPath", 3, mk_node("PatQualifiedPath", 3, $2, $3, $6), $7, $10); -} -; - -pats_or -: pat { $$ = mk_node("Pats", 1, $1); } -| pats_or '|' pat { $$ = ext_node($1, 1, $3); } -; - -binding_mode -: REF { $$ = mk_node("BindByRef", 1, mk_atom("MutImmutable")); } -| REF MUT { $$ = mk_node("BindByRef", 1, mk_atom("MutMutable")); } -| MUT { $$ = mk_node("BindByValue", 1, mk_atom("MutMutable")); } -; - -lit_or_path -: path_expr { $$ = mk_node("PatLit", 1, $1); } -| lit { $$ = mk_node("PatLit", 1, $1); } -| '-' lit { $$ = mk_node("PatLit", 1, $2); } -; - -pat_field -: ident { $$ = mk_node("PatField", 1, $1); } -| binding_mode ident { $$ = mk_node("PatField", 2, $1, $2); } -| BOX ident { $$ = mk_node("PatField", 2, mk_atom("box"), $2); } -| BOX binding_mode ident { $$ = mk_node("PatField", 3, mk_atom("box"), $2, $3); } -| ident ':' pat { $$ = mk_node("PatField", 2, $1, $3); } -| binding_mode ident ':' pat { $$ = mk_node("PatField", 3, $1, $2, $4); } -; - -pat_fields -: pat_field { $$ = mk_node("PatFields", 1, $1); } -| pat_fields ',' pat_field { $$ = ext_node($1, 1, $3); } -; - -pat_struct -: pat_fields { $$ = mk_node("PatStruct", 2, $1, mk_atom("false")); } -| pat_fields ',' { $$ = mk_node("PatStruct", 2, $1, mk_atom("false")); } -| pat_fields ',' DOTDOT { $$ = mk_node("PatStruct", 2, $1, mk_atom("true")); } -| DOTDOT { $$ = mk_node("PatStruct", 1, mk_atom("true")); } -; - -pat_tup -: pat { $$ = mk_node("pat_tup", 1, $1); } -| pat_tup ',' pat { $$ = ext_node($1, 1, $3); } -; - -pat_vec -: pat_vec_elts { $$ = mk_node("PatVec", 2, $1, mk_none()); } -| pat_vec_elts ',' { $$ = mk_node("PatVec", 2, $1, mk_none()); } -| pat_vec_elts DOTDOT { $$ = mk_node("PatVec", 2, $1, mk_none()); } -| pat_vec_elts ',' DOTDOT { $$ = mk_node("PatVec", 2, $1, mk_none()); } -| pat_vec_elts DOTDOT ',' pat_vec_elts { $$ = mk_node("PatVec", 2, $1, $4); } -| pat_vec_elts DOTDOT ',' pat_vec_elts ',' { $$ = mk_node("PatVec", 2, $1, $4); } -| pat_vec_elts ',' DOTDOT ',' pat_vec_elts { $$ = mk_node("PatVec", 2, $1, $5); } -| pat_vec_elts ',' DOTDOT ',' pat_vec_elts ',' { $$ = mk_node("PatVec", 2, $1, $5); } -| DOTDOT ',' pat_vec_elts { $$ = mk_node("PatVec", 2, mk_none(), $3); } -| DOTDOT ',' pat_vec_elts ',' { $$ = mk_node("PatVec", 2, mk_none(), $3); } -| DOTDOT { $$ = mk_node("PatVec", 2, mk_none(), mk_none()); } -| %empty { $$ = mk_node("PatVec", 2, mk_none(), mk_none()); } -; - -pat_vec_elts -: pat { $$ = mk_node("PatVecElts", 1, $1); } -| pat_vec_elts ',' pat { $$ = ext_node($1, 1, $3); } -; - -//////////////////////////////////////////////////////////////////////// -// Part 3: Types -//////////////////////////////////////////////////////////////////////// - -ty -: ty_prim -| ty_closure -| '<' ty_sum maybe_as_trait_ref '>' MOD_SEP ident { $$ = mk_node("TyQualifiedPath", 3, $2, $3, $6); } -| SHL ty_sum maybe_as_trait_ref '>' MOD_SEP ident maybe_as_trait_ref '>' MOD_SEP ident { $$ = mk_node("TyQualifiedPath", 3, mk_node("TyQualifiedPath", 3, $2, $3, $6), $7, $10); } -| '(' ty_sums ')' { $$ = mk_node("TyTup", 1, $2); } -| '(' ty_sums ',' ')' { $$ = mk_node("TyTup", 1, $2); } -| '(' ')' { $$ = mk_atom("TyNil"); } -; - -ty_prim -: %prec IDENT path_generic_args_without_colons { $$ = mk_node("TyPath", 2, mk_node("global", 1, mk_atom("false")), $1); } -| %prec IDENT MOD_SEP path_generic_args_without_colons { $$ = mk_node("TyPath", 2, mk_node("global", 1, mk_atom("true")), $2); } -| %prec IDENT SELF MOD_SEP path_generic_args_without_colons { $$ = mk_node("TyPath", 2, mk_node("self", 1, mk_atom("true")), $3); } -| BOX ty { $$ = mk_node("TyBox", 1, $2); } -| '*' maybe_mut_or_const ty { $$ = mk_node("TyPtr", 2, $2, $3); } -| '&' ty { $$ = mk_node("TyRptr", 2, mk_atom("MutImmutable"), $2); } -| '&' MUT ty { $$ = mk_node("TyRptr", 2, mk_atom("MutMutable"), $3); } -| ANDAND ty { $$ = mk_node("TyRptr", 1, mk_node("TyRptr", 2, mk_atom("MutImmutable"), $2)); } -| ANDAND MUT ty { $$ = mk_node("TyRptr", 1, mk_node("TyRptr", 2, mk_atom("MutMutable"), $3)); } -| '&' lifetime maybe_mut ty { $$ = mk_node("TyRptr", 3, $2, $3, $4); } -| ANDAND lifetime maybe_mut ty { $$ = mk_node("TyRptr", 1, mk_node("TyRptr", 3, $2, $3, $4)); } -| '[' ty ']' { $$ = mk_node("TyVec", 1, $2); } -| '[' ty ',' DOTDOT expr ']' { $$ = mk_node("TyFixedLengthVec", 2, $2, $5); } -| '[' ty ';' expr ']' { $$ = mk_node("TyFixedLengthVec", 2, $2, $4); } -| TYPEOF '(' expr ')' { $$ = mk_node("TyTypeof", 1, $3); } -| UNDERSCORE { $$ = mk_atom("TyInfer"); } -| ty_bare_fn -| ty_proc -| for_in_type -; - -ty_bare_fn -: FN ty_fn_decl { $$ = $2; } -| UNSAFE FN ty_fn_decl { $$ = $3; } -| EXTERN maybe_abi FN ty_fn_decl { $$ = $4; } -| UNSAFE EXTERN maybe_abi FN ty_fn_decl { $$ = $5; } -; - -ty_fn_decl -: generic_params fn_anon_params ret_ty { $$ = mk_node("TyFnDecl", 3, $1, $2, $3); } -; - -ty_closure -: UNSAFE '|' anon_params '|' maybe_bounds ret_ty { $$ = mk_node("TyClosure", 3, $3, $5, $6); } -| '|' anon_params '|' maybe_bounds ret_ty { $$ = mk_node("TyClosure", 3, $2, $4, $5); } -| UNSAFE OROR maybe_bounds ret_ty { $$ = mk_node("TyClosure", 2, $3, $4); } -| OROR maybe_bounds ret_ty { $$ = mk_node("TyClosure", 2, $2, $3); } -; - -ty_proc -: PROC generic_params fn_params maybe_bounds ret_ty { $$ = mk_node("TyProc", 4, $2, $3, $4, $5); } -; - -for_in_type -: FOR '<' maybe_lifetimes '>' for_in_type_suffix { $$ = mk_node("ForInType", 2, $3, $5); } -; - -for_in_type_suffix -: ty_proc -| ty_bare_fn -| trait_ref -| ty_closure -; - -maybe_mut -: MUT { $$ = mk_atom("MutMutable"); } -| %prec MUT %empty { $$ = mk_atom("MutImmutable"); } -; - -maybe_mut_or_const -: MUT { $$ = mk_atom("MutMutable"); } -| CONST { $$ = mk_atom("MutImmutable"); } -| %empty { $$ = mk_atom("MutImmutable"); } -; - -ty_qualified_path_and_generic_values -: ty_qualified_path maybe_bindings -{ - $$ = mk_node("GenericValues", 3, mk_none(), mk_node("TySums", 1, mk_node("TySum", 1, $1)), $2); -} -| ty_qualified_path ',' ty_sums maybe_bindings -{ - $$ = mk_node("GenericValues", 3, mk_none(), mk_node("TySums", 2, $1, $3), $4); -} -; - -ty_qualified_path -: ty_sum AS trait_ref '>' MOD_SEP ident { $$ = mk_node("TyQualifiedPath", 3, $1, $3, $6); } -| ty_sum AS trait_ref '>' MOD_SEP ident '+' ty_param_bounds { $$ = mk_node("TyQualifiedPath", 3, $1, $3, $6); } -; - -maybe_ty_sums -: ty_sums -| ty_sums ',' -| %empty { $$ = mk_none(); } -; - -ty_sums -: ty_sum { $$ = mk_node("TySums", 1, $1); } -| ty_sums ',' ty_sum { $$ = ext_node($1, 1, $3); } -; - -ty_sum -: ty { $$ = mk_node("TySum", 1, $1); } -| ty '+' ty_param_bounds { $$ = mk_node("TySum", 2, $1, $3); } -; - -ty_prim_sum -: ty_prim { $$ = mk_node("TySum", 1, $1); } -| ty_prim '+' ty_param_bounds { $$ = mk_node("TySum", 2, $1, $3); } -; - -maybe_ty_param_bounds -: ':' ty_param_bounds { $$ = $2; } -| %empty { $$ = mk_none(); } -; - -ty_param_bounds -: boundseq -| %empty { $$ = mk_none(); } -; - -boundseq -: polybound -| boundseq '+' polybound { $$ = ext_node($1, 1, $3); } -; - -polybound -: FOR '<' maybe_lifetimes '>' bound { $$ = mk_node("PolyBound", 2, $3, $5); } -| bound -| '?' bound { $$ = $2; } -; - -bindings -: binding { $$ = mk_node("Bindings", 1, $1); } -| bindings ',' binding { $$ = ext_node($1, 1, $3); } -; - -binding -: ident '=' ty { mk_node("Binding", 2, $1, $3); } -; - -ty_param -: ident maybe_ty_param_bounds maybe_ty_default { $$ = mk_node("TyParam", 3, $1, $2, $3); } -| ident '?' ident maybe_ty_param_bounds maybe_ty_default { $$ = mk_node("TyParam", 4, $1, $3, $4, $5); } -; - -maybe_bounds -: %prec SHIFTPLUS - ':' bounds { $$ = $2; } -| %prec SHIFTPLUS %empty { $$ = mk_none(); } -; - -bounds -: bound { $$ = mk_node("bounds", 1, $1); } -| bounds '+' bound { $$ = ext_node($1, 1, $3); } -; - -bound -: lifetime -| trait_ref -; - -maybe_ltbounds -: %prec SHIFTPLUS - ':' ltbounds { $$ = $2; } -| %empty { $$ = mk_none(); } -; - -ltbounds -: lifetime { $$ = mk_node("ltbounds", 1, $1); } -| ltbounds '+' lifetime { $$ = ext_node($1, 1, $3); } -; - -maybe_ty_default -: '=' ty_sum { $$ = mk_node("TyDefault", 1, $2); } -| %empty { $$ = mk_none(); } -; - -maybe_lifetimes -: lifetimes -| lifetimes ',' -| %empty { $$ = mk_none(); } -; - -lifetimes -: lifetime_and_bounds { $$ = mk_node("Lifetimes", 1, $1); } -| lifetimes ',' lifetime_and_bounds { $$ = ext_node($1, 1, $3); } -; - -lifetime_and_bounds -: LIFETIME maybe_ltbounds { $$ = mk_node("lifetime", 2, mk_atom(yytext), $2); } -| STATIC_LIFETIME { $$ = mk_atom("static_lifetime"); } -; - -lifetime -: LIFETIME { $$ = mk_node("lifetime", 1, mk_atom(yytext)); } -| STATIC_LIFETIME { $$ = mk_atom("static_lifetime"); } -; - -trait_ref -: %prec IDENT path_generic_args_without_colons -| %prec IDENT MOD_SEP path_generic_args_without_colons { $$ = $2; } -; - -//////////////////////////////////////////////////////////////////////// -// Part 4: Blocks, statements, and expressions -//////////////////////////////////////////////////////////////////////// - -inner_attrs_and_block -: '{' maybe_inner_attrs maybe_stmts '}' { $$ = mk_node("ExprBlock", 2, $2, $3); } -; - -block -: '{' maybe_stmts '}' { $$ = mk_node("ExprBlock", 1, $2); } -; - -maybe_stmts -: stmts -| stmts nonblock_expr { $$ = ext_node($1, 1, $2); } -| nonblock_expr -| %empty { $$ = mk_none(); } -; - -// There are two sub-grammars within a "stmts: exprs" derivation -// depending on whether each stmt-expr is a block-expr form; this is to -// handle the "semicolon rule" for stmt sequencing that permits -// writing -// -// if foo { bar } 10 -// -// as a sequence of two stmts (one if-expr stmt, one lit-10-expr -// stmt). Unfortunately by permitting juxtaposition of exprs in -// sequence like that, the non-block expr grammar has to have a -// second limited sub-grammar that excludes the prefix exprs that -// are ambiguous with binops. That is to say: -// -// {10} - 1 -// -// should parse as (progn (progn 10) (- 1)) not (- (progn 10) 1), that -// is to say, two statements rather than one, at least according to -// the mainline rust parser. -// -// So we wind up with a 3-way split in exprs that occur in stmt lists: -// block, nonblock-prefix, and nonblock-nonprefix. -// -// In non-stmts contexts, expr can relax this trichotomy. -// -// There is also one other expr subtype: nonparen_expr disallows exprs -// surrounded by parens (including tuple expressions), this is -// necessary for BOX (place) expressions, so a parens expr following -// the BOX is always parsed as the place. - -stmts -: stmt { $$ = mk_node("stmts", 1, $1); } -| stmts stmt { $$ = ext_node($1, 1, $2); } -; - -stmt -: let -| stmt_item -| PUB stmt_item { $$ = $2; } -| outer_attrs stmt_item { $$ = $2; } -| outer_attrs PUB stmt_item { $$ = $3; } -| full_block_expr -| block -| nonblock_expr ';' -| ';' { $$ = mk_none(); } -; - -maybe_exprs -: exprs -| exprs ',' -| %empty { $$ = mk_none(); } -; - -maybe_expr -: expr -| %empty { $$ = mk_none(); } -; - -exprs -: expr { $$ = mk_node("exprs", 1, $1); } -| exprs ',' expr { $$ = ext_node($1, 1, $3); } -; - -path_expr -: path_generic_args_with_colons -| MOD_SEP path_generic_args_with_colons { $$ = $2; } -| SELF MOD_SEP path_generic_args_with_colons { $$ = mk_node("SelfPath", 1, $3); } -; - -// A path with a lifetime and type parameters with double colons before -// the type parameters; e.g. `foo::bar::<'a>::Baz::` -// -// These show up in expr context, in order to disambiguate from "less-than" -// expressions. -path_generic_args_with_colons -: ident { $$ = mk_node("components", 1, $1); } -| path_generic_args_with_colons MOD_SEP ident { $$ = ext_node($1, 1, $3); } -| path_generic_args_with_colons MOD_SEP generic_args { $$ = ext_node($1, 1, $3); } -; - -// the braces-delimited macro is a block_expr so it doesn't appear here -macro_expr -: path_expr '!' maybe_ident parens_delimited_token_trees { $$ = mk_node("MacroExpr", 3, $1, $3, $4); } -| path_expr '!' maybe_ident brackets_delimited_token_trees { $$ = mk_node("MacroExpr", 3, $1, $3, $4); } -; - -nonblock_expr -: lit { $$ = mk_node("ExprLit", 1, $1); } -| %prec IDENT - path_expr { $$ = mk_node("ExprPath", 1, $1); } -| SELF { $$ = mk_node("ExprPath", 1, mk_node("ident", 1, mk_atom("self"))); } -| macro_expr { $$ = mk_node("ExprMac", 1, $1); } -| path_expr '{' struct_expr_fields '}' { $$ = mk_node("ExprStruct", 2, $1, $3); } -| nonblock_expr '.' path_generic_args_with_colons { $$ = mk_node("ExprField", 2, $1, $3); } -| nonblock_expr '.' LIT_INTEGER { $$ = mk_node("ExprTupleIndex", 1, $1); } -| nonblock_expr '[' maybe_expr ']' { $$ = mk_node("ExprIndex", 2, $1, $3); } -| nonblock_expr '(' maybe_exprs ')' { $$ = mk_node("ExprCall", 2, $1, $3); } -| '[' vec_expr ']' { $$ = mk_node("ExprVec", 1, $2); } -| '(' maybe_exprs ')' { $$ = mk_node("ExprParen", 1, $2); } -| CONTINUE { $$ = mk_node("ExprAgain", 0); } -| CONTINUE lifetime { $$ = mk_node("ExprAgain", 1, $2); } -| RETURN { $$ = mk_node("ExprRet", 0); } -| RETURN expr { $$ = mk_node("ExprRet", 1, $2); } -| BREAK { $$ = mk_node("ExprBreak", 0); } -| BREAK lifetime { $$ = mk_node("ExprBreak", 1, $2); } -| nonblock_expr LARROW expr { $$ = mk_node("ExprInPlace", 2, $1, $3); } -| nonblock_expr '=' expr { $$ = mk_node("ExprAssign", 2, $1, $3); } -| nonblock_expr SHLEQ expr { $$ = mk_node("ExprAssignShl", 2, $1, $3); } -| nonblock_expr SHREQ expr { $$ = mk_node("ExprAssignShr", 2, $1, $3); } -| nonblock_expr MINUSEQ expr { $$ = mk_node("ExprAssignSub", 2, $1, $3); } -| nonblock_expr ANDEQ expr { $$ = mk_node("ExprAssignBitAnd", 2, $1, $3); } -| nonblock_expr OREQ expr { $$ = mk_node("ExprAssignBitOr", 2, $1, $3); } -| nonblock_expr PLUSEQ expr { $$ = mk_node("ExprAssignAdd", 2, $1, $3); } -| nonblock_expr STAREQ expr { $$ = mk_node("ExprAssignMul", 2, $1, $3); } -| nonblock_expr SLASHEQ expr { $$ = mk_node("ExprAssignDiv", 2, $1, $3); } -| nonblock_expr CARETEQ expr { $$ = mk_node("ExprAssignBitXor", 2, $1, $3); } -| nonblock_expr PERCENTEQ expr { $$ = mk_node("ExprAssignRem", 2, $1, $3); } -| nonblock_expr OROR expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiOr"), $1, $3); } -| nonblock_expr ANDAND expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiAnd"), $1, $3); } -| nonblock_expr EQEQ expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiEq"), $1, $3); } -| nonblock_expr NE expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiNe"), $1, $3); } -| nonblock_expr '<' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiLt"), $1, $3); } -| nonblock_expr '>' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiGt"), $1, $3); } -| nonblock_expr LE expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiLe"), $1, $3); } -| nonblock_expr GE expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiGe"), $1, $3); } -| nonblock_expr '|' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitOr"), $1, $3); } -| nonblock_expr '^' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitXor"), $1, $3); } -| nonblock_expr '&' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitAnd"), $1, $3); } -| nonblock_expr SHL expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiShl"), $1, $3); } -| nonblock_expr SHR expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiShr"), $1, $3); } -| nonblock_expr '+' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiAdd"), $1, $3); } -| nonblock_expr '-' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiSub"), $1, $3); } -| nonblock_expr '*' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiMul"), $1, $3); } -| nonblock_expr '/' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiDiv"), $1, $3); } -| nonblock_expr '%' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiRem"), $1, $3); } -| nonblock_expr DOTDOT { $$ = mk_node("ExprRange", 2, $1, mk_none()); } -| nonblock_expr DOTDOT expr { $$ = mk_node("ExprRange", 2, $1, $3); } -| DOTDOT expr { $$ = mk_node("ExprRange", 2, mk_none(), $2); } -| DOTDOT { $$ = mk_node("ExprRange", 2, mk_none(), mk_none()); } -| nonblock_expr AS ty { $$ = mk_node("ExprCast", 2, $1, $3); } -| BOX nonparen_expr { $$ = mk_node("ExprBox", 1, $2); } -| %prec BOXPLACE BOX '(' maybe_expr ')' nonblock_expr { $$ = mk_node("ExprBox", 2, $3, $5); } -| expr_qualified_path -| nonblock_prefix_expr -; - -expr -: lit { $$ = mk_node("ExprLit", 1, $1); } -| %prec IDENT - path_expr { $$ = mk_node("ExprPath", 1, $1); } -| SELF { $$ = mk_node("ExprPath", 1, mk_node("ident", 1, mk_atom("self"))); } -| macro_expr { $$ = mk_node("ExprMac", 1, $1); } -| path_expr '{' struct_expr_fields '}' { $$ = mk_node("ExprStruct", 2, $1, $3); } -| expr '.' path_generic_args_with_colons { $$ = mk_node("ExprField", 2, $1, $3); } -| expr '.' LIT_INTEGER { $$ = mk_node("ExprTupleIndex", 1, $1); } -| expr '[' maybe_expr ']' { $$ = mk_node("ExprIndex", 2, $1, $3); } -| expr '(' maybe_exprs ')' { $$ = mk_node("ExprCall", 2, $1, $3); } -| '(' maybe_exprs ')' { $$ = mk_node("ExprParen", 1, $2); } -| '[' vec_expr ']' { $$ = mk_node("ExprVec", 1, $2); } -| CONTINUE { $$ = mk_node("ExprAgain", 0); } -| CONTINUE ident { $$ = mk_node("ExprAgain", 1, $2); } -| RETURN { $$ = mk_node("ExprRet", 0); } -| RETURN expr { $$ = mk_node("ExprRet", 1, $2); } -| BREAK { $$ = mk_node("ExprBreak", 0); } -| BREAK ident { $$ = mk_node("ExprBreak", 1, $2); } -| expr LARROW expr { $$ = mk_node("ExprInPlace", 2, $1, $3); } -| expr '=' expr { $$ = mk_node("ExprAssign", 2, $1, $3); } -| expr SHLEQ expr { $$ = mk_node("ExprAssignShl", 2, $1, $3); } -| expr SHREQ expr { $$ = mk_node("ExprAssignShr", 2, $1, $3); } -| expr MINUSEQ expr { $$ = mk_node("ExprAssignSub", 2, $1, $3); } -| expr ANDEQ expr { $$ = mk_node("ExprAssignBitAnd", 2, $1, $3); } -| expr OREQ expr { $$ = mk_node("ExprAssignBitOr", 2, $1, $3); } -| expr PLUSEQ expr { $$ = mk_node("ExprAssignAdd", 2, $1, $3); } -| expr STAREQ expr { $$ = mk_node("ExprAssignMul", 2, $1, $3); } -| expr SLASHEQ expr { $$ = mk_node("ExprAssignDiv", 2, $1, $3); } -| expr CARETEQ expr { $$ = mk_node("ExprAssignBitXor", 2, $1, $3); } -| expr PERCENTEQ expr { $$ = mk_node("ExprAssignRem", 2, $1, $3); } -| expr OROR expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiOr"), $1, $3); } -| expr ANDAND expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiAnd"), $1, $3); } -| expr EQEQ expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiEq"), $1, $3); } -| expr NE expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiNe"), $1, $3); } -| expr '<' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiLt"), $1, $3); } -| expr '>' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiGt"), $1, $3); } -| expr LE expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiLe"), $1, $3); } -| expr GE expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiGe"), $1, $3); } -| expr '|' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitOr"), $1, $3); } -| expr '^' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitXor"), $1, $3); } -| expr '&' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitAnd"), $1, $3); } -| expr SHL expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiShl"), $1, $3); } -| expr SHR expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiShr"), $1, $3); } -| expr '+' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiAdd"), $1, $3); } -| expr '-' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiSub"), $1, $3); } -| expr '*' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiMul"), $1, $3); } -| expr '/' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiDiv"), $1, $3); } -| expr '%' expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiRem"), $1, $3); } -| expr DOTDOT { $$ = mk_node("ExprRange", 2, $1, mk_none()); } -| expr DOTDOT expr { $$ = mk_node("ExprRange", 2, $1, $3); } -| DOTDOT expr { $$ = mk_node("ExprRange", 2, mk_none(), $2); } -| DOTDOT { $$ = mk_node("ExprRange", 2, mk_none(), mk_none()); } -| expr AS ty { $$ = mk_node("ExprCast", 2, $1, $3); } -| BOX nonparen_expr { $$ = mk_node("ExprBox", 1, $2); } -| %prec BOXPLACE BOX '(' maybe_expr ')' expr { $$ = mk_node("ExprBox", 2, $3, $5); } -| expr_qualified_path -| block_expr -| block -| nonblock_prefix_expr -; - -nonparen_expr -: lit { $$ = mk_node("ExprLit", 1, $1); } -| %prec IDENT - path_expr { $$ = mk_node("ExprPath", 1, $1); } -| SELF { $$ = mk_node("ExprPath", 1, mk_node("ident", 1, mk_atom("self"))); } -| macro_expr { $$ = mk_node("ExprMac", 1, $1); } -| path_expr '{' struct_expr_fields '}' { $$ = mk_node("ExprStruct", 2, $1, $3); } -| nonparen_expr '.' path_generic_args_with_colons { $$ = mk_node("ExprField", 2, $1, $3); } -| nonparen_expr '.' LIT_INTEGER { $$ = mk_node("ExprTupleIndex", 1, $1); } -| nonparen_expr '[' maybe_expr ']' { $$ = mk_node("ExprIndex", 2, $1, $3); } -| nonparen_expr '(' maybe_exprs ')' { $$ = mk_node("ExprCall", 2, $1, $3); } -| '[' vec_expr ']' { $$ = mk_node("ExprVec", 1, $2); } -| CONTINUE { $$ = mk_node("ExprAgain", 0); } -| CONTINUE ident { $$ = mk_node("ExprAgain", 1, $2); } -| RETURN { $$ = mk_node("ExprRet", 0); } -| RETURN expr { $$ = mk_node("ExprRet", 1, $2); } -| BREAK { $$ = mk_node("ExprBreak", 0); } -| BREAK ident { $$ = mk_node("ExprBreak", 1, $2); } -| nonparen_expr LARROW nonparen_expr { $$ = mk_node("ExprInPlace", 2, $1, $3); } -| nonparen_expr '=' nonparen_expr { $$ = mk_node("ExprAssign", 2, $1, $3); } -| nonparen_expr SHLEQ nonparen_expr { $$ = mk_node("ExprAssignShl", 2, $1, $3); } -| nonparen_expr SHREQ nonparen_expr { $$ = mk_node("ExprAssignShr", 2, $1, $3); } -| nonparen_expr MINUSEQ nonparen_expr { $$ = mk_node("ExprAssignSub", 2, $1, $3); } -| nonparen_expr ANDEQ nonparen_expr { $$ = mk_node("ExprAssignBitAnd", 2, $1, $3); } -| nonparen_expr OREQ nonparen_expr { $$ = mk_node("ExprAssignBitOr", 2, $1, $3); } -| nonparen_expr PLUSEQ nonparen_expr { $$ = mk_node("ExprAssignAdd", 2, $1, $3); } -| nonparen_expr STAREQ nonparen_expr { $$ = mk_node("ExprAssignMul", 2, $1, $3); } -| nonparen_expr SLASHEQ nonparen_expr { $$ = mk_node("ExprAssignDiv", 2, $1, $3); } -| nonparen_expr CARETEQ nonparen_expr { $$ = mk_node("ExprAssignBitXor", 2, $1, $3); } -| nonparen_expr PERCENTEQ nonparen_expr { $$ = mk_node("ExprAssignRem", 2, $1, $3); } -| nonparen_expr OROR nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiOr"), $1, $3); } -| nonparen_expr ANDAND nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiAnd"), $1, $3); } -| nonparen_expr EQEQ nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiEq"), $1, $3); } -| nonparen_expr NE nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiNe"), $1, $3); } -| nonparen_expr '<' nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiLt"), $1, $3); } -| nonparen_expr '>' nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiGt"), $1, $3); } -| nonparen_expr LE nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiLe"), $1, $3); } -| nonparen_expr GE nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiGe"), $1, $3); } -| nonparen_expr '|' nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitOr"), $1, $3); } -| nonparen_expr '^' nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitXor"), $1, $3); } -| nonparen_expr '&' nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitAnd"), $1, $3); } -| nonparen_expr SHL nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiShl"), $1, $3); } -| nonparen_expr SHR nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiShr"), $1, $3); } -| nonparen_expr '+' nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiAdd"), $1, $3); } -| nonparen_expr '-' nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiSub"), $1, $3); } -| nonparen_expr '*' nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiMul"), $1, $3); } -| nonparen_expr '/' nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiDiv"), $1, $3); } -| nonparen_expr '%' nonparen_expr { $$ = mk_node("ExprBinary", 3, mk_atom("BiRem"), $1, $3); } -| nonparen_expr DOTDOT { $$ = mk_node("ExprRange", 2, $1, mk_none()); } -| nonparen_expr DOTDOT nonparen_expr { $$ = mk_node("ExprRange", 2, $1, $3); } -| DOTDOT nonparen_expr { $$ = mk_node("ExprRange", 2, mk_none(), $2); } -| DOTDOT { $$ = mk_node("ExprRange", 2, mk_none(), mk_none()); } -| nonparen_expr AS ty { $$ = mk_node("ExprCast", 2, $1, $3); } -| BOX nonparen_expr { $$ = mk_node("ExprBox", 1, $2); } -| %prec BOXPLACE BOX '(' maybe_expr ')' expr { $$ = mk_node("ExprBox", 1, $3, $5); } -| expr_qualified_path -| block_expr -| block -| nonblock_prefix_expr -; - -expr_nostruct -: lit { $$ = mk_node("ExprLit", 1, $1); } -| %prec IDENT - path_expr { $$ = mk_node("ExprPath", 1, $1); } -| SELF { $$ = mk_node("ExprPath", 1, mk_node("ident", 1, mk_atom("self"))); } -| macro_expr { $$ = mk_node("ExprMac", 1, $1); } -| expr_nostruct '.' path_generic_args_with_colons { $$ = mk_node("ExprField", 2, $1, $3); } -| expr_nostruct '.' LIT_INTEGER { $$ = mk_node("ExprTupleIndex", 1, $1); } -| expr_nostruct '[' maybe_expr ']' { $$ = mk_node("ExprIndex", 2, $1, $3); } -| expr_nostruct '(' maybe_exprs ')' { $$ = mk_node("ExprCall", 2, $1, $3); } -| '[' vec_expr ']' { $$ = mk_node("ExprVec", 1, $2); } -| '(' maybe_exprs ')' { $$ = mk_node("ExprParen", 1, $2); } -| CONTINUE { $$ = mk_node("ExprAgain", 0); } -| CONTINUE ident { $$ = mk_node("ExprAgain", 1, $2); } -| RETURN { $$ = mk_node("ExprRet", 0); } -| RETURN expr { $$ = mk_node("ExprRet", 1, $2); } -| BREAK { $$ = mk_node("ExprBreak", 0); } -| BREAK ident { $$ = mk_node("ExprBreak", 1, $2); } -| expr_nostruct LARROW expr_nostruct { $$ = mk_node("ExprInPlace", 2, $1, $3); } -| expr_nostruct '=' expr_nostruct { $$ = mk_node("ExprAssign", 2, $1, $3); } -| expr_nostruct SHLEQ expr_nostruct { $$ = mk_node("ExprAssignShl", 2, $1, $3); } -| expr_nostruct SHREQ expr_nostruct { $$ = mk_node("ExprAssignShr", 2, $1, $3); } -| expr_nostruct MINUSEQ expr_nostruct { $$ = mk_node("ExprAssignSub", 2, $1, $3); } -| expr_nostruct ANDEQ expr_nostruct { $$ = mk_node("ExprAssignBitAnd", 2, $1, $3); } -| expr_nostruct OREQ expr_nostruct { $$ = mk_node("ExprAssignBitOr", 2, $1, $3); } -| expr_nostruct PLUSEQ expr_nostruct { $$ = mk_node("ExprAssignAdd", 2, $1, $3); } -| expr_nostruct STAREQ expr_nostruct { $$ = mk_node("ExprAssignMul", 2, $1, $3); } -| expr_nostruct SLASHEQ expr_nostruct { $$ = mk_node("ExprAssignDiv", 2, $1, $3); } -| expr_nostruct CARETEQ expr_nostruct { $$ = mk_node("ExprAssignBitXor", 2, $1, $3); } -| expr_nostruct PERCENTEQ expr_nostruct { $$ = mk_node("ExprAssignRem", 2, $1, $3); } -| expr_nostruct OROR expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiOr"), $1, $3); } -| expr_nostruct ANDAND expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiAnd"), $1, $3); } -| expr_nostruct EQEQ expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiEq"), $1, $3); } -| expr_nostruct NE expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiNe"), $1, $3); } -| expr_nostruct '<' expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiLt"), $1, $3); } -| expr_nostruct '>' expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiGt"), $1, $3); } -| expr_nostruct LE expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiLe"), $1, $3); } -| expr_nostruct GE expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiGe"), $1, $3); } -| expr_nostruct '|' expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitOr"), $1, $3); } -| expr_nostruct '^' expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitXor"), $1, $3); } -| expr_nostruct '&' expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiBitAnd"), $1, $3); } -| expr_nostruct SHL expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiShl"), $1, $3); } -| expr_nostruct SHR expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiShr"), $1, $3); } -| expr_nostruct '+' expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiAdd"), $1, $3); } -| expr_nostruct '-' expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiSub"), $1, $3); } -| expr_nostruct '*' expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiMul"), $1, $3); } -| expr_nostruct '/' expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiDiv"), $1, $3); } -| expr_nostruct '%' expr_nostruct { $$ = mk_node("ExprBinary", 3, mk_atom("BiRem"), $1, $3); } -| expr_nostruct DOTDOT %prec RANGE { $$ = mk_node("ExprRange", 2, $1, mk_none()); } -| expr_nostruct DOTDOT expr_nostruct { $$ = mk_node("ExprRange", 2, $1, $3); } -| DOTDOT expr_nostruct { $$ = mk_node("ExprRange", 2, mk_none(), $2); } -| DOTDOT { $$ = mk_node("ExprRange", 2, mk_none(), mk_none()); } -| expr_nostruct AS ty { $$ = mk_node("ExprCast", 2, $1, $3); } -| BOX nonparen_expr { $$ = mk_node("ExprBox", 1, $2); } -| %prec BOXPLACE BOX '(' maybe_expr ')' expr_nostruct { $$ = mk_node("ExprBox", 1, $3, $5); } -| expr_qualified_path -| block_expr -| block -| nonblock_prefix_expr_nostruct -; - -nonblock_prefix_expr_nostruct -: '-' expr_nostruct { $$ = mk_node("ExprUnary", 2, mk_atom("UnNeg"), $2); } -| '!' expr_nostruct { $$ = mk_node("ExprUnary", 2, mk_atom("UnNot"), $2); } -| '*' expr_nostruct { $$ = mk_node("ExprUnary", 2, mk_atom("UnDeref"), $2); } -| '&' maybe_mut expr_nostruct { $$ = mk_node("ExprAddrOf", 2, $2, $3); } -| ANDAND maybe_mut expr_nostruct { $$ = mk_node("ExprAddrOf", 1, mk_node("ExprAddrOf", 2, $2, $3)); } -| lambda_expr_nostruct -| MOVE lambda_expr_nostruct { $$ = $2; } -| proc_expr_nostruct -; - -nonblock_prefix_expr -: '-' expr { $$ = mk_node("ExprUnary", 2, mk_atom("UnNeg"), $2); } -| '!' expr { $$ = mk_node("ExprUnary", 2, mk_atom("UnNot"), $2); } -| '*' expr { $$ = mk_node("ExprUnary", 2, mk_atom("UnDeref"), $2); } -| '&' maybe_mut expr { $$ = mk_node("ExprAddrOf", 2, $2, $3); } -| ANDAND maybe_mut expr { $$ = mk_node("ExprAddrOf", 1, mk_node("ExprAddrOf", 2, $2, $3)); } -| lambda_expr -| MOVE lambda_expr { $$ = $2; } -| proc_expr -; - -expr_qualified_path -: '<' ty_sum maybe_as_trait_ref '>' MOD_SEP ident maybe_qpath_params -{ - $$ = mk_node("ExprQualifiedPath", 4, $2, $3, $6, $7); -} -| SHL ty_sum maybe_as_trait_ref '>' MOD_SEP ident maybe_as_trait_ref '>' MOD_SEP ident -{ - $$ = mk_node("ExprQualifiedPath", 3, mk_node("ExprQualifiedPath", 3, $2, $3, $6), $7, $10); -} -| SHL ty_sum maybe_as_trait_ref '>' MOD_SEP ident generic_args maybe_as_trait_ref '>' MOD_SEP ident -{ - $$ = mk_node("ExprQualifiedPath", 3, mk_node("ExprQualifiedPath", 4, $2, $3, $6, $7), $8, $11); -} -| SHL ty_sum maybe_as_trait_ref '>' MOD_SEP ident maybe_as_trait_ref '>' MOD_SEP ident generic_args -{ - $$ = mk_node("ExprQualifiedPath", 4, mk_node("ExprQualifiedPath", 3, $2, $3, $6), $7, $10, $11); -} -| SHL ty_sum maybe_as_trait_ref '>' MOD_SEP ident generic_args maybe_as_trait_ref '>' MOD_SEP ident generic_args -{ - $$ = mk_node("ExprQualifiedPath", 4, mk_node("ExprQualifiedPath", 4, $2, $3, $6, $7), $8, $11, $12); -} - -maybe_qpath_params -: MOD_SEP generic_args { $$ = $2; } -| %empty { $$ = mk_none(); } -; - -maybe_as_trait_ref -: AS trait_ref { $$ = $2; } -| %empty { $$ = mk_none(); } -; - -lambda_expr -: %prec LAMBDA - OROR ret_ty expr { $$ = mk_node("ExprFnBlock", 3, mk_none(), $2, $3); } -| %prec LAMBDA - '|' maybe_unboxed_closure_kind '|' ret_ty expr { $$ = mk_node("ExprFnBlock", 3, mk_none(), $4, $5); } -| %prec LAMBDA - '|' inferrable_params '|' ret_ty expr { $$ = mk_node("ExprFnBlock", 3, $2, $4, $5); } -| %prec LAMBDA - '|' '&' maybe_mut ':' inferrable_params '|' ret_ty expr { $$ = mk_node("ExprFnBlock", 3, $5, $7, $8); } -| %prec LAMBDA - '|' ':' inferrable_params '|' ret_ty expr { $$ = mk_node("ExprFnBlock", 3, $3, $5, $6); } -; - -lambda_expr_nostruct -: %prec LAMBDA - OROR expr_nostruct { $$ = mk_node("ExprFnBlock", 2, mk_none(), $2); } -| %prec LAMBDA - '|' maybe_unboxed_closure_kind '|' expr_nostruct { $$ = mk_node("ExprFnBlock", 2, mk_none(), $4); } -| %prec LAMBDA - '|' inferrable_params '|' expr_nostruct { $$ = mk_node("ExprFnBlock", 2, $2, $4); } -| %prec LAMBDA - '|' '&' maybe_mut ':' inferrable_params '|' expr_nostruct { $$ = mk_node("ExprFnBlock", 2, $5, $7); } -| %prec LAMBDA - '|' ':' inferrable_params '|' expr_nostruct { $$ = mk_node("ExprFnBlock", 2, $3, $5); } - -; - -proc_expr -: %prec LAMBDA - PROC '(' ')' expr { $$ = mk_node("ExprProc", 2, mk_none(), $4); } -| %prec LAMBDA - PROC '(' inferrable_params ')' expr { $$ = mk_node("ExprProc", 2, $3, $5); } -; - -proc_expr_nostruct -: %prec LAMBDA - PROC '(' ')' expr_nostruct { $$ = mk_node("ExprProc", 2, mk_none(), $4); } -| %prec LAMBDA - PROC '(' inferrable_params ')' expr_nostruct { $$ = mk_node("ExprProc", 2, $3, $5); } -; - -vec_expr -: maybe_exprs -| exprs ';' expr { $$ = mk_node("VecRepeat", 2, $1, $3); } -; - -struct_expr_fields -: field_inits -| field_inits ',' -| maybe_field_inits default_field_init { $$ = ext_node($1, 1, $2); } -; - -maybe_field_inits -: field_inits -| field_inits ',' -| %empty { $$ = mk_none(); } -; - -field_inits -: field_init { $$ = mk_node("FieldInits", 1, $1); } -| field_inits ',' field_init { $$ = ext_node($1, 1, $3); } -; - -field_init -: ident ':' expr { $$ = mk_node("FieldInit", 2, $1, $3); } -; - -default_field_init -: DOTDOT expr { $$ = mk_node("DefaultFieldInit", 1, $2); } -; - -block_expr -: expr_match -| expr_if -| expr_if_let -| expr_while -| expr_while_let -| expr_loop -| expr_for -| UNSAFE block { $$ = mk_node("UnsafeBlock", 1, $2); } -| path_expr '!' maybe_ident braces_delimited_token_trees { $$ = mk_node("Macro", 3, $1, $3, $4); } -; - -full_block_expr -: block_expr -| full_block_expr '.' path_generic_args_with_colons %prec IDENT { $$ = mk_node("ExprField", 2, $1, $3); } -| full_block_expr '.' path_generic_args_with_colons '[' maybe_expr ']' { $$ = mk_node("ExprIndex", 3, $1, $3, $5); } -| full_block_expr '.' path_generic_args_with_colons '(' maybe_exprs ')' { $$ = mk_node("ExprCall", 3, $1, $3, $5); } -| full_block_expr '.' LIT_INTEGER { $$ = mk_node("ExprTupleIndex", 1, $1); } -; - -expr_match -: MATCH expr_nostruct '{' '}' { $$ = mk_node("ExprMatch", 1, $2); } -| MATCH expr_nostruct '{' match_clauses '}' { $$ = mk_node("ExprMatch", 2, $2, $4); } -| MATCH expr_nostruct '{' match_clauses nonblock_match_clause '}' { $$ = mk_node("ExprMatch", 2, $2, ext_node($4, 1, $5)); } -| MATCH expr_nostruct '{' nonblock_match_clause '}' { $$ = mk_node("ExprMatch", 2, $2, mk_node("Arms", 1, $4)); } -; - -match_clauses -: match_clause { $$ = mk_node("Arms", 1, $1); } -| match_clauses match_clause { $$ = ext_node($1, 1, $2); } -; - -match_clause -: nonblock_match_clause ',' -| block_match_clause -| block_match_clause ',' -; - -nonblock_match_clause -: maybe_outer_attrs pats_or maybe_guard FAT_ARROW nonblock_expr { $$ = mk_node("Arm", 4, $1, $2, $3, $5); } -| maybe_outer_attrs pats_or maybe_guard FAT_ARROW full_block_expr { $$ = mk_node("Arm", 4, $1, $2, $3, $5); } -; - -block_match_clause -: maybe_outer_attrs pats_or maybe_guard FAT_ARROW block { $$ = mk_node("Arm", 4, $1, $2, $3, $5); } -; - -maybe_guard -: IF expr_nostruct { $$ = $2; } -| %empty { $$ = mk_none(); } -; - -expr_if -: IF expr_nostruct block { $$ = mk_node("ExprIf", 2, $2, $3); } -| IF expr_nostruct block ELSE block_or_if { $$ = mk_node("ExprIf", 3, $2, $3, $5); } -; - -expr_if_let -: IF LET pat '=' expr_nostruct block { $$ = mk_node("ExprIfLet", 3, $3, $5, $6); } -| IF LET pat '=' expr_nostruct block ELSE block_or_if { $$ = mk_node("ExprIfLet", 4, $3, $5, $6, $8); } -; - -block_or_if -: block -| expr_if -| expr_if_let -; - -expr_while -: maybe_label WHILE expr_nostruct block { $$ = mk_node("ExprWhile", 3, $1, $3, $4); } -; - -expr_while_let -: maybe_label WHILE LET pat '=' expr_nostruct block { $$ = mk_node("ExprWhileLet", 4, $1, $4, $6, $7); } -; - -expr_loop -: maybe_label LOOP block { $$ = mk_node("ExprLoop", 2, $1, $3); } -; - -expr_for -: maybe_label FOR pat IN expr_nostruct block { $$ = mk_node("ExprForLoop", 4, $1, $3, $5, $6); } -; - -maybe_label -: lifetime ':' -| %empty { $$ = mk_none(); } -; - -let -: LET pat maybe_ty_ascription maybe_init_expr ';' { $$ = mk_node("DeclLocal", 3, $2, $3, $4); } -; - -//////////////////////////////////////////////////////////////////////// -// Part 5: Macros and misc. rules -//////////////////////////////////////////////////////////////////////// - -lit -: LIT_BYTE { $$ = mk_node("LitByte", 1, mk_atom(yytext)); } -| LIT_CHAR { $$ = mk_node("LitChar", 1, mk_atom(yytext)); } -| LIT_INTEGER { $$ = mk_node("LitInteger", 1, mk_atom(yytext)); } -| LIT_FLOAT { $$ = mk_node("LitFloat", 1, mk_atom(yytext)); } -| TRUE { $$ = mk_node("LitBool", 1, mk_atom(yytext)); } -| FALSE { $$ = mk_node("LitBool", 1, mk_atom(yytext)); } -| str -; - -str -: LIT_STR { $$ = mk_node("LitStr", 1, mk_atom(yytext), mk_atom("CookedStr")); } -| LIT_STR_RAW { $$ = mk_node("LitStr", 1, mk_atom(yytext), mk_atom("RawStr")); } -| LIT_BYTE_STR { $$ = mk_node("LitByteStr", 1, mk_atom(yytext), mk_atom("ByteStr")); } -| LIT_BYTE_STR_RAW { $$ = mk_node("LitByteStr", 1, mk_atom(yytext), mk_atom("RawByteStr")); } -; - -maybe_ident -: %empty { $$ = mk_none(); } -| ident -; - -ident -: IDENT { $$ = mk_node("ident", 1, mk_atom(yytext)); } -; - -unpaired_token -: SHL { $$ = mk_atom(yytext); } -| SHR { $$ = mk_atom(yytext); } -| LE { $$ = mk_atom(yytext); } -| EQEQ { $$ = mk_atom(yytext); } -| NE { $$ = mk_atom(yytext); } -| GE { $$ = mk_atom(yytext); } -| ANDAND { $$ = mk_atom(yytext); } -| OROR { $$ = mk_atom(yytext); } -| LARROW { $$ = mk_atom(yytext); } -| SHLEQ { $$ = mk_atom(yytext); } -| SHREQ { $$ = mk_atom(yytext); } -| MINUSEQ { $$ = mk_atom(yytext); } -| ANDEQ { $$ = mk_atom(yytext); } -| OREQ { $$ = mk_atom(yytext); } -| PLUSEQ { $$ = mk_atom(yytext); } -| STAREQ { $$ = mk_atom(yytext); } -| SLASHEQ { $$ = mk_atom(yytext); } -| CARETEQ { $$ = mk_atom(yytext); } -| PERCENTEQ { $$ = mk_atom(yytext); } -| DOTDOT { $$ = mk_atom(yytext); } -| DOTDOTDOT { $$ = mk_atom(yytext); } -| MOD_SEP { $$ = mk_atom(yytext); } -| RARROW { $$ = mk_atom(yytext); } -| FAT_ARROW { $$ = mk_atom(yytext); } -| LIT_BYTE { $$ = mk_atom(yytext); } -| LIT_CHAR { $$ = mk_atom(yytext); } -| LIT_INTEGER { $$ = mk_atom(yytext); } -| LIT_FLOAT { $$ = mk_atom(yytext); } -| LIT_STR { $$ = mk_atom(yytext); } -| LIT_STR_RAW { $$ = mk_atom(yytext); } -| LIT_BYTE_STR { $$ = mk_atom(yytext); } -| LIT_BYTE_STR_RAW { $$ = mk_atom(yytext); } -| IDENT { $$ = mk_atom(yytext); } -| UNDERSCORE { $$ = mk_atom(yytext); } -| LIFETIME { $$ = mk_atom(yytext); } -| SELF { $$ = mk_atom(yytext); } -| STATIC { $$ = mk_atom(yytext); } -| AS { $$ = mk_atom(yytext); } -| BREAK { $$ = mk_atom(yytext); } -| CRATE { $$ = mk_atom(yytext); } -| ELSE { $$ = mk_atom(yytext); } -| ENUM { $$ = mk_atom(yytext); } -| EXTERN { $$ = mk_atom(yytext); } -| FALSE { $$ = mk_atom(yytext); } -| FN { $$ = mk_atom(yytext); } -| FOR { $$ = mk_atom(yytext); } -| IF { $$ = mk_atom(yytext); } -| IMPL { $$ = mk_atom(yytext); } -| IN { $$ = mk_atom(yytext); } -| LET { $$ = mk_atom(yytext); } -| LOOP { $$ = mk_atom(yytext); } -| MATCH { $$ = mk_atom(yytext); } -| MOD { $$ = mk_atom(yytext); } -| MOVE { $$ = mk_atom(yytext); } -| MUT { $$ = mk_atom(yytext); } -| PRIV { $$ = mk_atom(yytext); } -| PUB { $$ = mk_atom(yytext); } -| REF { $$ = mk_atom(yytext); } -| RETURN { $$ = mk_atom(yytext); } -| STRUCT { $$ = mk_atom(yytext); } -| TRUE { $$ = mk_atom(yytext); } -| TRAIT { $$ = mk_atom(yytext); } -| TYPE { $$ = mk_atom(yytext); } -| UNSAFE { $$ = mk_atom(yytext); } -| USE { $$ = mk_atom(yytext); } -| WHILE { $$ = mk_atom(yytext); } -| CONTINUE { $$ = mk_atom(yytext); } -| PROC { $$ = mk_atom(yytext); } -| BOX { $$ = mk_atom(yytext); } -| CONST { $$ = mk_atom(yytext); } -| WHERE { $$ = mk_atom(yytext); } -| TYPEOF { $$ = mk_atom(yytext); } -| INNER_DOC_COMMENT { $$ = mk_atom(yytext); } -| OUTER_DOC_COMMENT { $$ = mk_atom(yytext); } -| SHEBANG { $$ = mk_atom(yytext); } -| STATIC_LIFETIME { $$ = mk_atom(yytext); } -| ';' { $$ = mk_atom(yytext); } -| ',' { $$ = mk_atom(yytext); } -| '.' { $$ = mk_atom(yytext); } -| '@' { $$ = mk_atom(yytext); } -| '#' { $$ = mk_atom(yytext); } -| '~' { $$ = mk_atom(yytext); } -| ':' { $$ = mk_atom(yytext); } -| '$' { $$ = mk_atom(yytext); } -| '=' { $$ = mk_atom(yytext); } -| '?' { $$ = mk_atom(yytext); } -| '!' { $$ = mk_atom(yytext); } -| '<' { $$ = mk_atom(yytext); } -| '>' { $$ = mk_atom(yytext); } -| '-' { $$ = mk_atom(yytext); } -| '&' { $$ = mk_atom(yytext); } -| '|' { $$ = mk_atom(yytext); } -| '+' { $$ = mk_atom(yytext); } -| '*' { $$ = mk_atom(yytext); } -| '/' { $$ = mk_atom(yytext); } -| '^' { $$ = mk_atom(yytext); } -| '%' { $$ = mk_atom(yytext); } -; - -token_trees -: %empty { $$ = mk_node("TokenTrees", 0); } -| token_trees token_tree { $$ = ext_node($1, 1, $2); } -; - -token_tree -: delimited_token_trees -| unpaired_token { $$ = mk_node("TTTok", 1, $1); } -; - -delimited_token_trees -: parens_delimited_token_trees -| braces_delimited_token_trees -| brackets_delimited_token_trees -; - -parens_delimited_token_trees -: '(' token_trees ')' -{ - $$ = mk_node("TTDelim", 3, - mk_node("TTTok", 1, mk_atom("(")), - $2, - mk_node("TTTok", 1, mk_atom(")"))); -} -; - -braces_delimited_token_trees -: '{' token_trees '}' -{ - $$ = mk_node("TTDelim", 3, - mk_node("TTTok", 1, mk_atom("{")), - $2, - mk_node("TTTok", 1, mk_atom("}"))); -} -; - -brackets_delimited_token_trees -: '[' token_trees ']' -{ - $$ = mk_node("TTDelim", 3, - mk_node("TTTok", 1, mk_atom("[")), - $2, - mk_node("TTTok", 1, mk_atom("]"))); -} -; diff --git a/src/grammar/raw-string-literal-ambiguity.md b/src/grammar/raw-string-literal-ambiguity.md deleted file mode 100644 index c909f2333148..000000000000 --- a/src/grammar/raw-string-literal-ambiguity.md +++ /dev/null @@ -1,64 +0,0 @@ -Rust's lexical grammar is not context-free. Raw string literals are the source -of the problem. Informally, a raw string literal is an `r`, followed by `N` -hashes (where N can be zero), a quote, any characters, then a quote followed -by `N` hashes. Critically, once inside the first pair of quotes, -another quote cannot be followed by `N` consecutive hashes. e.g. -`r###""###"###` is invalid. - -This grammar describes this as best possible: - - R -> 'r' S - S -> '"' B '"' - S -> '#' S '#' - B -> . B - B -> ε - -Where `.` represents any character, and `ε` the empty string. Consider the -string `r#""#"#`. This string is not a valid raw string literal, but can be -accepted as one by the above grammar, using the derivation: - - R : #""#"# - S : ""#" - S : "# - B : # - B : ε - -(Where `T : U` means the rule `T` is applied, and `U` is the remainder of the -string.) The difficulty arises from the fact that it is fundamentally -context-sensitive. In particular, the context needed is the number of hashes. - -To prove that Rust's string literals are not context-free, we will use -the fact that context-free languages are closed under intersection with -regular languages, and the -[pumping lemma for context-free languages](https://en.wikipedia.org/wiki/Pumping_lemma_for_context-free_languages). - -Consider the regular language `R = r#+""#*"#+`. If Rust's raw string literals are -context-free, then their intersection with `R`, `R'`, should also be context-free. -Therefore, to prove that raw string literals are not context-free, -it is sufficient to prove that `R'` is not context-free. - -The language `R'` is `{r#^n""#^m"#^n | m < n}`. - -Assume `R'` *is* context-free. Then `R'` has some pumping length `p > 0` for which -the pumping lemma applies. Consider the following string `s` in `R'`: - -`r#^p""#^{p-1}"#^p` - -e.g. for `p = 2`: `s = r##""#"##` - -Then `s = uvwxy` for some choice of `uvwxy` such that `vx` is non-empty, -`|vwx| < p+1`, and `uv^iwx^iy` is in `R'` for all `i >= 0`. - -Neither `v` nor `x` can contain a `"` or `r`, as the number of these characters -in any string in `R'` is fixed. So `v` and `x` contain only hashes. -Consequently, of the three sequences of hashes, `v` and `x` combined -can only pump two of them. -If we ever choose the central sequence of hashes, then one of the outer sequences -will not grow when we pump, leading to an imbalance between the outer sequences. -Therefore, we must pump both outer sequences of hashes. However, -there are `p+2` characters between these two sequences of hashes, and `|vwx|` must -be less than `p+1`. Therefore we have a contradiction, and `R'` must not be -context-free. - -Since `R'` is not context-free, it follows that the Rust's raw string literals -must not be context-free. diff --git a/src/grammar/testparser.py b/src/grammar/testparser.py deleted file mode 100755 index 37be41b935f8..000000000000 --- a/src/grammar/testparser.py +++ /dev/null @@ -1,76 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2015 The Rust Project Developers. See the COPYRIGHT -# file at the top-level directory of this distribution and at -# http://rust-lang.org/COPYRIGHT. -# -# Licensed under the Apache License, Version 2.0 or the MIT license -# , at your -# option. This file may not be copied, modified, or distributed -# except according to those terms. - -# ignore-tidy-linelength - -import sys - -import os -import subprocess -import argparse - -# usage: testparser.py [-h] [-p PARSER [PARSER ...]] -s SOURCE_DIR - -# Parsers should read from stdin and return exit status 0 for a -# successful parse, and nonzero for an unsuccessful parse - -parser = argparse.ArgumentParser() -parser.add_argument('-p', '--parser', nargs='+') -parser.add_argument('-s', '--source-dir', nargs=1, required=True) -args = parser.parse_args(sys.argv[1:]) - -total = 0 -ok = {} -bad = {} -for parser in args.parser: - ok[parser] = 0 - bad[parser] = [] -devnull = open(os.devnull, 'w') -print("\n") - -for base, dirs, files in os.walk(args.source_dir[0]): - for f in filter(lambda p: p.endswith('.rs'), files): - p = os.path.join(base, f) - parse_fail = 'parse-fail' in p - if sys.version_info.major == 3: - lines = open(p, encoding='utf-8').readlines() - else: - lines = open(p).readlines() - if any('ignore-test' in line or 'ignore-lexer-test' in line for line in lines): - continue - total += 1 - for parser in args.parser: - if subprocess.call(parser, stdin=open(p), stderr=subprocess.STDOUT, stdout=devnull) == 0: - if parse_fail: - bad[parser].append(p) - else: - ok[parser] += 1 - else: - if parse_fail: - ok[parser] += 1 - else: - bad[parser].append(p) - parser_stats = ', '.join(['{}: {}'.format(parser, ok[parser]) for parser in args.parser]) - sys.stdout.write("\033[K\r total: {}, {}, scanned {}" - .format(total, os.path.relpath(parser_stats), os.path.relpath(p))) - -devnull.close() - -print("\n") - -for parser in args.parser: - filename = os.path.basename(parser) + '.bad' - print("writing {} files that did not yield the correct result with {} to {}".format(len(bad[parser]), parser, filename)) - with open(filename, "w") as f: - for p in bad[parser]: - f.write(p) - f.write("\n") diff --git a/src/grammar/tokens.h b/src/grammar/tokens.h deleted file mode 100644 index 081bd0502596..000000000000 --- a/src/grammar/tokens.h +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -enum Token { - SHL = 257, // Parser generators reserve 0-256 for char literals - SHR, - LE, - EQEQ, - NE, - GE, - ANDAND, - OROR, - SHLEQ, - SHREQ, - MINUSEQ, - ANDEQ, - OREQ, - PLUSEQ, - STAREQ, - SLASHEQ, - CARETEQ, - PERCENTEQ, - DOTDOT, - DOTDOTDOT, - MOD_SEP, - RARROW, - FAT_ARROW, - LIT_BYTE, - LIT_CHAR, - LIT_INTEGER, - LIT_FLOAT, - LIT_STR, - LIT_STR_RAW, - LIT_BYTE_STR, - LIT_BYTE_STR_RAW, - IDENT, - UNDERSCORE, - LIFETIME, - - // keywords - SELF, - STATIC, - AS, - BREAK, - CRATE, - ELSE, - ENUM, - EXTERN, - FALSE, - FN, - FOR, - IF, - IMPL, - IN, - LET, - LOOP, - MATCH, - MOD, - MOVE, - MUT, - PRIV, - PUB, - REF, - RETURN, - STRUCT, - TRUE, - TRAIT, - TYPE, - UNSAFE, - USE, - WHILE, - CONTINUE, - PROC, - BOX, - CONST, - WHERE, - TYPEOF, - INNER_DOC_COMMENT, - OUTER_DOC_COMMENT, - - SHEBANG, - SHEBANG_LINE, - STATIC_LIFETIME -}; diff --git a/src/grammar/verify.rs b/src/grammar/verify.rs deleted file mode 100644 index 919fc98e438c..000000000000 --- a/src/grammar/verify.rs +++ /dev/null @@ -1,361 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(plugin, rustc_private)] - -extern crate syntax; -extern crate syntax_pos; -extern crate rustc; - -#[macro_use] -extern crate log; - -use std::collections::HashMap; -use std::env; -use std::fs::File; -use std::io::{BufRead, Read}; -use std::path::Path; - -use syntax::parse::lexer; -use rustc::dep_graph::DepGraph; -use rustc::session::{self, config}; -use rustc::middle::cstore::DummyCrateStore; - -use std::rc::Rc; -use syntax::ast; -use syntax::codemap; -use syntax::parse::token::{self, BinOpToken, DelimToken, Lit, Token}; -use syntax::parse::lexer::TokenAndSpan; -use syntax_pos::Pos; - -use syntax::symbol::{Symbol, keywords}; - -fn parse_token_list(file: &str) -> HashMap { - fn id() -> token::Token { - Token::Ident(ast::Ident::with_empty_ctxt(keywords::Invalid.name())) - } - - let mut res = HashMap::new(); - - res.insert("-1".to_string(), Token::Eof); - - for line in file.split('\n') { - let eq = match line.trim().rfind('=') { - Some(val) => val, - None => continue - }; - - let val = &line[..eq]; - let num = &line[eq + 1..]; - - let tok = match val { - "SHR" => Token::BinOp(BinOpToken::Shr), - "DOLLAR" => Token::Dollar, - "LT" => Token::Lt, - "STAR" => Token::BinOp(BinOpToken::Star), - "FLOAT_SUFFIX" => id(), - "INT_SUFFIX" => id(), - "SHL" => Token::BinOp(BinOpToken::Shl), - "LBRACE" => Token::OpenDelim(DelimToken::Brace), - "RARROW" => Token::RArrow, - "LIT_STR" => Token::Literal(Lit::Str_(keywords::Invalid.name()), None), - "DOTDOT" => Token::DotDot, - "MOD_SEP" => Token::ModSep, - "DOTDOTDOT" => Token::DotDotDot, - "NOT" => Token::Not, - "AND" => Token::BinOp(BinOpToken::And), - "LPAREN" => Token::OpenDelim(DelimToken::Paren), - "ANDAND" => Token::AndAnd, - "AT" => Token::At, - "LBRACKET" => Token::OpenDelim(DelimToken::Bracket), - "LIT_STR_RAW" => Token::Literal(Lit::StrRaw(keywords::Invalid.name(), 0), None), - "RPAREN" => Token::CloseDelim(DelimToken::Paren), - "SLASH" => Token::BinOp(BinOpToken::Slash), - "COMMA" => Token::Comma, - "LIFETIME" => Token::Lifetime( - ast::Ident::with_empty_ctxt(keywords::Invalid.name())), - "CARET" => Token::BinOp(BinOpToken::Caret), - "TILDE" => Token::Tilde, - "IDENT" => id(), - "PLUS" => Token::BinOp(BinOpToken::Plus), - "LIT_CHAR" => Token::Literal(Lit::Char(keywords::Invalid.name()), None), - "LIT_BYTE" => Token::Literal(Lit::Byte(keywords::Invalid.name()), None), - "EQ" => Token::Eq, - "RBRACKET" => Token::CloseDelim(DelimToken::Bracket), - "COMMENT" => Token::Comment, - "DOC_COMMENT" => Token::DocComment(keywords::Invalid.name()), - "DOT" => Token::Dot, - "EQEQ" => Token::EqEq, - "NE" => Token::Ne, - "GE" => Token::Ge, - "PERCENT" => Token::BinOp(BinOpToken::Percent), - "RBRACE" => Token::CloseDelim(DelimToken::Brace), - "BINOP" => Token::BinOp(BinOpToken::Plus), - "POUND" => Token::Pound, - "OROR" => Token::OrOr, - "LIT_INTEGER" => Token::Literal(Lit::Integer(keywords::Invalid.name()), None), - "BINOPEQ" => Token::BinOpEq(BinOpToken::Plus), - "LIT_FLOAT" => Token::Literal(Lit::Float(keywords::Invalid.name()), None), - "WHITESPACE" => Token::Whitespace, - "UNDERSCORE" => Token::Underscore, - "MINUS" => Token::BinOp(BinOpToken::Minus), - "SEMI" => Token::Semi, - "COLON" => Token::Colon, - "FAT_ARROW" => Token::FatArrow, - "OR" => Token::BinOp(BinOpToken::Or), - "GT" => Token::Gt, - "LE" => Token::Le, - "LIT_BINARY" => Token::Literal(Lit::ByteStr(keywords::Invalid.name()), None), - "LIT_BINARY_RAW" => Token::Literal( - Lit::ByteStrRaw(keywords::Invalid.name(), 0), None), - "QUESTION" => Token::Question, - "SHEBANG" => Token::Shebang(keywords::Invalid.name()), - _ => continue, - }; - - res.insert(num.to_string(), tok); - } - - debug!("Token map: {:?}", res); - res -} - -fn str_to_binop(s: &str) -> token::BinOpToken { - match s { - "+" => BinOpToken::Plus, - "/" => BinOpToken::Slash, - "-" => BinOpToken::Minus, - "*" => BinOpToken::Star, - "%" => BinOpToken::Percent, - "^" => BinOpToken::Caret, - "&" => BinOpToken::And, - "|" => BinOpToken::Or, - "<<" => BinOpToken::Shl, - ">>" => BinOpToken::Shr, - _ => panic!("Bad binop str `{}`", s), - } -} - -/// Assuming a string/byte string literal, strip out the leading/trailing -/// hashes and surrounding quotes/raw/byte prefix. -fn fix(mut lit: &str) -> ast::Name { - let prefix: Vec = lit.chars().take(2).collect(); - if prefix[0] == 'r' { - if prefix[1] == 'b' { - lit = &lit[2..] - } else { - lit = &lit[1..]; - } - } else if prefix[0] == 'b' { - lit = &lit[1..]; - } - - let leading_hashes = count(lit); - - // +1/-1 to adjust for single quotes - Symbol::intern(&lit[leading_hashes + 1..lit.len() - leading_hashes - 1]) -} - -/// Assuming a char/byte literal, strip the 'b' prefix and the single quotes. -fn fixchar(mut lit: &str) -> ast::Name { - let prefix = lit.chars().next().unwrap(); - if prefix == 'b' { - lit = &lit[1..]; - } - - Symbol::intern(&lit[1..lit.len() - 1]) -} - -fn count(lit: &str) -> usize { - lit.chars().take_while(|c| *c == '#').count() -} - -fn parse_antlr_token(s: &str, tokens: &HashMap, surrogate_pairs_pos: &[usize], - has_bom: bool) - -> TokenAndSpan { - // old regex: - // \[@(?P\d+),(?P\d+):(?P\d+)='(?P.+?)',<(?P-?\d+)>,\d+:\d+] - let start = s.find("[@").unwrap(); - let comma = start + s[start..].find(",").unwrap(); - let colon = comma + s[comma..].find(":").unwrap(); - let content_start = colon + s[colon..].find("='").unwrap(); - // Use rfind instead of find, because we don't want to stop at the content - let content_end = content_start + s[content_start..].rfind("',<").unwrap(); - let toknum_end = content_end + s[content_end..].find(">,").unwrap(); - - let start = &s[comma + 1 .. colon]; - let end = &s[colon + 1 .. content_start]; - let content = &s[content_start + 2 .. content_end]; - let toknum = &s[content_end + 3 .. toknum_end]; - - let not_found = format!("didn't find token {:?} in the map", toknum); - let proto_tok = tokens.get(toknum).expect(¬_found[..]); - - let nm = Symbol::intern(content); - - debug!("What we got: content (`{}`), proto: {:?}", content, proto_tok); - - let real_tok = match *proto_tok { - Token::BinOp(..) => Token::BinOp(str_to_binop(content)), - Token::BinOpEq(..) => Token::BinOpEq(str_to_binop(&content[..content.len() - 1])), - Token::Literal(Lit::Str_(..), n) => Token::Literal(Lit::Str_(fix(content)), n), - Token::Literal(Lit::StrRaw(..), n) => Token::Literal(Lit::StrRaw(fix(content), - count(content)), n), - Token::Literal(Lit::Char(..), n) => Token::Literal(Lit::Char(fixchar(content)), n), - Token::Literal(Lit::Byte(..), n) => Token::Literal(Lit::Byte(fixchar(content)), n), - Token::DocComment(..) => Token::DocComment(nm), - Token::Literal(Lit::Integer(..), n) => Token::Literal(Lit::Integer(nm), n), - Token::Literal(Lit::Float(..), n) => Token::Literal(Lit::Float(nm), n), - Token::Literal(Lit::ByteStr(..), n) => Token::Literal(Lit::ByteStr(nm), n), - Token::Literal(Lit::ByteStrRaw(..), n) => Token::Literal(Lit::ByteStrRaw(fix(content), - count(content)), n), - Token::Ident(..) => Token::Ident(ast::Ident::with_empty_ctxt(nm)), - Token::Lifetime(..) => Token::Lifetime(ast::Ident::with_empty_ctxt(nm)), - ref t => t.clone() - }; - - let start_offset = if real_tok == Token::Eof { - 1 - } else { - 0 - }; - - let offset = if has_bom { 1 } else { 0 }; - - let mut lo = start.parse::().unwrap() - start_offset - offset; - let mut hi = end.parse::().unwrap() + 1 - offset; - - // Adjust the span: For each surrogate pair already encountered, subtract one position. - lo -= surrogate_pairs_pos.binary_search(&(lo as usize)).unwrap_or_else(|x| x) as u32; - hi -= surrogate_pairs_pos.binary_search(&(hi as usize)).unwrap_or_else(|x| x) as u32; - - let sp = syntax_pos::Span { - lo: syntax_pos::BytePos(lo), - hi: syntax_pos::BytePos(hi), - expn_id: syntax_pos::NO_EXPANSION - }; - - TokenAndSpan { - tok: real_tok, - sp: sp - } -} - -fn tok_cmp(a: &token::Token, b: &token::Token) -> bool { - match a { - &Token::Ident(id) => match b { - &Token::Ident(id2) => id == id2, - _ => false - }, - _ => a == b - } -} - -fn span_cmp(antlr_sp: codemap::Span, rust_sp: codemap::Span, cm: &codemap::CodeMap) -> bool { - antlr_sp.expn_id == rust_sp.expn_id && - antlr_sp.lo.to_usize() == cm.bytepos_to_file_charpos(rust_sp.lo).to_usize() && - antlr_sp.hi.to_usize() == cm.bytepos_to_file_charpos(rust_sp.hi).to_usize() -} - -fn main() { - fn next(r: &mut lexer::StringReader) -> TokenAndSpan { - use syntax::parse::lexer::Reader; - r.next_token() - } - - let mut args = env::args().skip(1); - let filename = args.next().unwrap(); - if filename.find("parse-fail").is_some() { - return; - } - - // Rust's lexer - let mut code = String::new(); - File::open(&Path::new(&filename)).unwrap().read_to_string(&mut code).unwrap(); - - let surrogate_pairs_pos: Vec = code.chars().enumerate() - .filter(|&(_, c)| c as usize > 0xFFFF) - .map(|(n, _)| n) - .enumerate() - .map(|(x, n)| x + n) - .collect(); - - let has_bom = code.starts_with("\u{feff}"); - - debug!("Pairs: {:?}", surrogate_pairs_pos); - - let options = config::basic_options(); - let session = session::build_session(options, &DepGraph::new(false), None, - syntax::errors::registry::Registry::new(&[]), - Rc::new(DummyCrateStore)); - let filemap = session.parse_sess.codemap() - .new_filemap("".to_string(), None, code); - let mut lexer = lexer::StringReader::new(session.diagnostic(), filemap); - let cm = session.codemap(); - - // ANTLR - let mut token_file = File::open(&Path::new(&args.next().unwrap())).unwrap(); - let mut token_list = String::new(); - token_file.read_to_string(&mut token_list).unwrap(); - let token_map = parse_token_list(&token_list[..]); - - let stdin = std::io::stdin(); - let lock = stdin.lock(); - let lines = lock.lines(); - let antlr_tokens = lines.map(|l| parse_antlr_token(l.unwrap().trim(), - &token_map, - &surrogate_pairs_pos[..], - has_bom)); - - for antlr_tok in antlr_tokens { - let rustc_tok = next(&mut lexer); - if rustc_tok.tok == Token::Eof && antlr_tok.tok == Token::Eof { - continue - } - - assert!(span_cmp(antlr_tok.sp, rustc_tok.sp, cm), "{:?} and {:?} have different spans", - rustc_tok, - antlr_tok); - - macro_rules! matches { - ( $($x:pat),+ ) => ( - match rustc_tok.tok { - $($x => match antlr_tok.tok { - $x => { - if !tok_cmp(&rustc_tok.tok, &antlr_tok.tok) { - // FIXME #15677: needs more robust escaping in - // antlr - warn!("Different names for {:?} and {:?}", rustc_tok, antlr_tok); - } - } - _ => panic!("{:?} is not {:?}", antlr_tok, rustc_tok) - },)* - ref c => assert!(c == &antlr_tok.tok, "{:?} is not {:?}", antlr_tok, rustc_tok) - } - ) - } - - matches!( - Token::Literal(Lit::Byte(..), _), - Token::Literal(Lit::Char(..), _), - Token::Literal(Lit::Integer(..), _), - Token::Literal(Lit::Float(..), _), - Token::Literal(Lit::Str_(..), _), - Token::Literal(Lit::StrRaw(..), _), - Token::Literal(Lit::ByteStr(..), _), - Token::Literal(Lit::ByteStrRaw(..), _), - Token::Ident(..), - Token::Lifetime(..), - Token::Interpolated(..), - Token::DocComment(..), - Token::Shebang(..) - ); - } -} diff --git a/src/grammar/xidcontinue.g4 b/src/grammar/xidcontinue.g4 deleted file mode 100644 index f3a1a3b40f99..000000000000 --- a/src/grammar/xidcontinue.g4 +++ /dev/null @@ -1,473 +0,0 @@ -lexer grammar Xidcontinue; - -fragment XID_Continue: - '\u0030' .. '\u0039' - | '\u0041' .. '\u005a' - | '\u005f' - | '\u0061' .. '\u007a' - | '\u00aa' - | '\u00b5' - | '\u00b7' - | '\u00ba' - | '\u00c0' .. '\u00d6' - | '\u00d8' .. '\u00f6' - | '\u00f8' .. '\u0236' - | '\u0250' .. '\u02c1' - | '\u02c6' .. '\u02d1' - | '\u02e0' .. '\u02e4' - | '\u02ee' - | '\u0300' .. '\u0357' - | '\u035d' .. '\u036f' - | '\u0386' - | '\u0388' .. '\u038a' - | '\u038c' - | '\u038e' .. '\u03a1' - | '\u03a3' .. '\u03ce' - | '\u03d0' .. '\u03f5' - | '\u03f7' .. '\u03fb' - | '\u0400' .. '\u0481' - | '\u0483' .. '\u0486' - | '\u048a' .. '\u04ce' - | '\u04d0' .. '\u04f5' - | '\u04f8' .. '\u04f9' - | '\u0500' .. '\u050f' - | '\u0531' .. '\u0556' - | '\u0559' - | '\u0561' .. '\u0587' - | '\u0591' .. '\u05a1' - | '\u05a3' .. '\u05b9' - | '\u05bb' .. '\u05bd' - | '\u05bf' - | '\u05c1' .. '\u05c2' - | '\u05c4' - | '\u05d0' .. '\u05ea' - | '\u05f0' .. '\u05f2' - | '\u0610' .. '\u0615' - | '\u0621' .. '\u063a' - | '\u0640' .. '\u0658' - | '\u0660' .. '\u0669' - | '\u066e' .. '\u06d3' - | '\u06d5' .. '\u06dc' - | '\u06df' .. '\u06e8' - | '\u06ea' .. '\u06fc' - | '\u06ff' - | '\u0710' .. '\u074a' - | '\u074d' .. '\u074f' - | '\u0780' .. '\u07b1' - | '\u0901' .. '\u0939' - | '\u093c' .. '\u094d' - | '\u0950' .. '\u0954' - | '\u0958' .. '\u0963' - | '\u0966' .. '\u096f' - | '\u0981' .. '\u0983' - | '\u0985' .. '\u098c' - | '\u098f' .. '\u0990' - | '\u0993' .. '\u09a8' - | '\u09aa' .. '\u09b0' - | '\u09b2' - | '\u09b6' .. '\u09b9' - | '\u09bc' .. '\u09c4' - | '\u09c7' .. '\u09c8' - | '\u09cb' .. '\u09cd' - | '\u09d7' - | '\u09dc' .. '\u09dd' - | '\u09df' .. '\u09e3' - | '\u09e6' .. '\u09f1' - | '\u0a01' .. '\u0a03' - | '\u0a05' .. '\u0a0a' - | '\u0a0f' .. '\u0a10' - | '\u0a13' .. '\u0a28' - | '\u0a2a' .. '\u0a30' - | '\u0a32' .. '\u0a33' - | '\u0a35' .. '\u0a36' - | '\u0a38' .. '\u0a39' - | '\u0a3c' - | '\u0a3e' .. '\u0a42' - | '\u0a47' .. '\u0a48' - | '\u0a4b' .. '\u0a4d' - | '\u0a59' .. '\u0a5c' - | '\u0a5e' - | '\u0a66' .. '\u0a74' - | '\u0a81' .. '\u0a83' - | '\u0a85' .. '\u0a8d' - | '\u0a8f' .. '\u0a91' - | '\u0a93' .. '\u0aa8' - | '\u0aaa' .. '\u0ab0' - | '\u0ab2' .. '\u0ab3' - | '\u0ab5' .. '\u0ab9' - | '\u0abc' .. '\u0ac5' - | '\u0ac7' .. '\u0ac9' - | '\u0acb' .. '\u0acd' - | '\u0ad0' - | '\u0ae0' .. '\u0ae3' - | '\u0ae6' .. '\u0aef' - | '\u0b01' .. '\u0b03' - | '\u0b05' .. '\u0b0c' - | '\u0b0f' .. '\u0b10' - | '\u0b13' .. '\u0b28' - | '\u0b2a' .. '\u0b30' - | '\u0b32' .. '\u0b33' - | '\u0b35' .. '\u0b39' - | '\u0b3c' .. '\u0b43' - | '\u0b47' .. '\u0b48' - | '\u0b4b' .. '\u0b4d' - | '\u0b56' .. '\u0b57' - | '\u0b5c' .. '\u0b5d' - | '\u0b5f' .. '\u0b61' - | '\u0b66' .. '\u0b6f' - | '\u0b71' - | '\u0b82' .. '\u0b83' - | '\u0b85' .. '\u0b8a' - | '\u0b8e' .. '\u0b90' - | '\u0b92' .. '\u0b95' - | '\u0b99' .. '\u0b9a' - | '\u0b9c' - | '\u0b9e' .. '\u0b9f' - | '\u0ba3' .. '\u0ba4' - | '\u0ba8' .. '\u0baa' - | '\u0bae' .. '\u0bb5' - | '\u0bb7' .. '\u0bb9' - | '\u0bbe' .. '\u0bc2' - | '\u0bc6' .. '\u0bc8' - | '\u0bca' .. '\u0bcd' - | '\u0bd7' - | '\u0be7' .. '\u0bef' - | '\u0c01' .. '\u0c03' - | '\u0c05' .. '\u0c0c' - | '\u0c0e' .. '\u0c10' - | '\u0c12' .. '\u0c28' - | '\u0c2a' .. '\u0c33' - | '\u0c35' .. '\u0c39' - | '\u0c3e' .. '\u0c44' - | '\u0c46' .. '\u0c48' - | '\u0c4a' .. '\u0c4d' - | '\u0c55' .. '\u0c56' - | '\u0c60' .. '\u0c61' - | '\u0c66' .. '\u0c6f' - | '\u0c82' .. '\u0c83' - | '\u0c85' .. '\u0c8c' - | '\u0c8e' .. '\u0c90' - | '\u0c92' .. '\u0ca8' - | '\u0caa' .. '\u0cb3' - | '\u0cb5' .. '\u0cb9' - | '\u0cbc' .. '\u0cc4' - | '\u0cc6' .. '\u0cc8' - | '\u0cca' .. '\u0ccd' - | '\u0cd5' .. '\u0cd6' - | '\u0cde' - | '\u0ce0' .. '\u0ce1' - | '\u0ce6' .. '\u0cef' - | '\u0d02' .. '\u0d03' - | '\u0d05' .. '\u0d0c' - | '\u0d0e' .. '\u0d10' - | '\u0d12' .. '\u0d28' - | '\u0d2a' .. '\u0d39' - | '\u0d3e' .. '\u0d43' - | '\u0d46' .. '\u0d48' - | '\u0d4a' .. '\u0d4d' - | '\u0d57' - | '\u0d60' .. '\u0d61' - | '\u0d66' .. '\u0d6f' - | '\u0d82' .. '\u0d83' - | '\u0d85' .. '\u0d96' - | '\u0d9a' .. '\u0db1' - | '\u0db3' .. '\u0dbb' - | '\u0dbd' - | '\u0dc0' .. '\u0dc6' - | '\u0dca' - | '\u0dcf' .. '\u0dd4' - | '\u0dd6' - | '\u0dd8' .. '\u0ddf' - | '\u0df2' .. '\u0df3' - | '\u0e01' .. '\u0e3a' - | '\u0e40' .. '\u0e4e' - | '\u0e50' .. '\u0e59' - | '\u0e81' .. '\u0e82' - | '\u0e84' - | '\u0e87' .. '\u0e88' - | '\u0e8a' - | '\u0e8d' - | '\u0e94' .. '\u0e97' - | '\u0e99' .. '\u0e9f' - | '\u0ea1' .. '\u0ea3' - | '\u0ea5' - | '\u0ea7' - | '\u0eaa' .. '\u0eab' - | '\u0ead' .. '\u0eb9' - | '\u0ebb' .. '\u0ebd' - | '\u0ec0' .. '\u0ec4' - | '\u0ec6' - | '\u0ec8' .. '\u0ecd' - | '\u0ed0' .. '\u0ed9' - | '\u0edc' .. '\u0edd' - | '\u0f00' - | '\u0f18' .. '\u0f19' - | '\u0f20' .. '\u0f29' - | '\u0f35' - | '\u0f37' - | '\u0f39' - | '\u0f3e' .. '\u0f47' - | '\u0f49' .. '\u0f6a' - | '\u0f71' .. '\u0f84' - | '\u0f86' .. '\u0f8b' - | '\u0f90' .. '\u0f97' - | '\u0f99' .. '\u0fbc' - | '\u0fc6' - | '\u1000' .. '\u1021' - | '\u1023' .. '\u1027' - | '\u1029' .. '\u102a' - | '\u102c' .. '\u1032' - | '\u1036' .. '\u1039' - | '\u1040' .. '\u1049' - | '\u1050' .. '\u1059' - | '\u10a0' .. '\u10c5' - | '\u10d0' .. '\u10f8' - | '\u1100' .. '\u1159' - | '\u115f' .. '\u11a2' - | '\u11a8' .. '\u11f9' - | '\u1200' .. '\u1206' - | '\u1208' .. '\u1246' - | '\u1248' - | '\u124a' .. '\u124d' - | '\u1250' .. '\u1256' - | '\u1258' - | '\u125a' .. '\u125d' - | '\u1260' .. '\u1286' - | '\u1288' - | '\u128a' .. '\u128d' - | '\u1290' .. '\u12ae' - | '\u12b0' - | '\u12b2' .. '\u12b5' - | '\u12b8' .. '\u12be' - | '\u12c0' - | '\u12c2' .. '\u12c5' - | '\u12c8' .. '\u12ce' - | '\u12d0' .. '\u12d6' - | '\u12d8' .. '\u12ee' - | '\u12f0' .. '\u130e' - | '\u1310' - | '\u1312' .. '\u1315' - | '\u1318' .. '\u131e' - | '\u1320' .. '\u1346' - | '\u1348' .. '\u135a' - | '\u1369' .. '\u1371' - | '\u13a0' .. '\u13f4' - | '\u1401' .. '\u166c' - | '\u166f' .. '\u1676' - | '\u1681' .. '\u169a' - | '\u16a0' .. '\u16ea' - | '\u16ee' .. '\u16f0' - | '\u1700' .. '\u170c' - | '\u170e' .. '\u1714' - | '\u1720' .. '\u1734' - | '\u1740' .. '\u1753' - | '\u1760' .. '\u176c' - | '\u176e' .. '\u1770' - | '\u1772' .. '\u1773' - | '\u1780' .. '\u17b3' - | '\u17b6' .. '\u17d3' - | '\u17d7' - | '\u17dc' .. '\u17dd' - | '\u17e0' .. '\u17e9' - | '\u180b' .. '\u180d' - | '\u1810' .. '\u1819' - | '\u1820' .. '\u1877' - | '\u1880' .. '\u18a9' - | '\u1900' .. '\u191c' - | '\u1920' .. '\u192b' - | '\u1930' .. '\u193b' - | '\u1946' .. '\u196d' - | '\u1970' .. '\u1974' - | '\u1d00' .. '\u1d6b' - | '\u1e00' .. '\u1e9b' - | '\u1ea0' .. '\u1ef9' - | '\u1f00' .. '\u1f15' - | '\u1f18' .. '\u1f1d' - | '\u1f20' .. '\u1f45' - | '\u1f48' .. '\u1f4d' - | '\u1f50' .. '\u1f57' - | '\u1f59' - | '\u1f5b' - | '\u1f5d' - | '\u1f5f' .. '\u1f7d' - | '\u1f80' .. '\u1fb4' - | '\u1fb6' .. '\u1fbc' - | '\u1fbe' - | '\u1fc2' .. '\u1fc4' - | '\u1fc6' .. '\u1fcc' - | '\u1fd0' .. '\u1fd3' - | '\u1fd6' .. '\u1fdb' - | '\u1fe0' .. '\u1fec' - | '\u1ff2' .. '\u1ff4' - | '\u1ff6' .. '\u1ffc' - | '\u203f' .. '\u2040' - | '\u2054' - | '\u2071' - | '\u207f' - | '\u20d0' .. '\u20dc' - | '\u20e1' - | '\u20e5' .. '\u20ea' - | '\u2102' - | '\u2107' - | '\u210a' .. '\u2113' - | '\u2115' - | '\u2118' .. '\u211d' - | '\u2124' - | '\u2126' - | '\u2128' - | '\u212a' .. '\u2131' - | '\u2133' .. '\u2139' - | '\u213d' .. '\u213f' - | '\u2145' .. '\u2149' - | '\u2160' .. '\u2183' - | '\u3005' .. '\u3007' - | '\u3021' .. '\u302f' - | '\u3031' .. '\u3035' - | '\u3038' .. '\u303c' - | '\u3041' .. '\u3096' - | '\u3099' .. '\u309a' - | '\u309d' .. '\u309f' - | '\u30a1' .. '\u30ff' - | '\u3105' .. '\u312c' - | '\u3131' .. '\u318e' - | '\u31a0' .. '\u31b7' - | '\u31f0' .. '\u31ff' - | '\u3400' .. '\u4db5' - | '\u4e00' .. '\u9fa5' - | '\ua000' .. '\ua48c' - | '\uac00' .. '\ud7a3' - | '\uf900' .. '\ufa2d' - | '\ufa30' .. '\ufa6a' - | '\ufb00' .. '\ufb06' - | '\ufb13' .. '\ufb17' - | '\ufb1d' .. '\ufb28' - | '\ufb2a' .. '\ufb36' - | '\ufb38' .. '\ufb3c' - | '\ufb3e' - | '\ufb40' .. '\ufb41' - | '\ufb43' .. '\ufb44' - | '\ufb46' .. '\ufbb1' - | '\ufbd3' .. '\ufc5d' - | '\ufc64' .. '\ufd3d' - | '\ufd50' .. '\ufd8f' - | '\ufd92' .. '\ufdc7' - | '\ufdf0' .. '\ufdf9' - | '\ufe00' .. '\ufe0f' - | '\ufe20' .. '\ufe23' - | '\ufe33' .. '\ufe34' - | '\ufe4d' .. '\ufe4f' - | '\ufe71' - | '\ufe73' - | '\ufe77' - | '\ufe79' - | '\ufe7b' - | '\ufe7d' - | '\ufe7f' .. '\ufefc' - | '\uff10' .. '\uff19' - | '\uff21' .. '\uff3a' - | '\uff3f' - | '\uff41' .. '\uff5a' - | '\uff65' .. '\uffbe' - | '\uffc2' .. '\uffc7' - | '\uffca' .. '\uffcf' - | '\uffd2' .. '\uffd7' - | '\uffda' .. '\uffdc' - | '\ud800' '\udc00' .. '\udc0a' - | '\ud800' '\udc0d' .. '\udc25' - | '\ud800' '\udc28' .. '\udc39' - | '\ud800' '\udc3c' .. '\udc3c' - | '\ud800' '\udc3f' .. '\udc4c' - | '\ud800' '\udc50' .. '\udc5c' - | '\ud800' '\udc80' .. '\udcf9' - | '\ud800' '\udf00' .. '\udf1d' - | '\ud800' '\udf30' .. '\udf49' - | '\ud800' '\udf80' .. '\udf9c' - | '\ud801' '\ue000' .. '\ue09c' - | '\ud801' '\ue0a0' .. '\ue0a8' - | '\ud802' '\ue400' .. '\ue404' - | '\ud802' '\u0808' - | '\ud802' '\ue40a' .. '\ue434' - | '\ud802' '\ue437' .. '\ue437' - | '\ud802' '\u083c' - | '\ud802' '\u083f' - | '\ud834' '\uad65' .. '\uad68' - | '\ud834' '\uad6d' .. '\uad71' - | '\ud834' '\uad7b' .. '\uad81' - | '\ud834' '\uad85' .. '\uad8a' - | '\ud834' '\uadaa' .. '\uadac' - | '\ud835' '\ub000' .. '\ub053' - | '\ud835' '\ub056' .. '\ub09b' - | '\ud835' '\ub09e' .. '\ub09e' - | '\ud835' '\ud4a2' - | '\ud835' '\ub0a5' .. '\ub0a5' - | '\ud835' '\ub0a9' .. '\ub0ab' - | '\ud835' '\ub0ae' .. '\ub0b8' - | '\ud835' '\ud4bb' - | '\ud835' '\ub0bd' .. '\ub0c2' - | '\ud835' '\ub0c5' .. '\ub104' - | '\ud835' '\ub107' .. '\ub109' - | '\ud835' '\ub10d' .. '\ub113' - | '\ud835' '\ub116' .. '\ub11b' - | '\ud835' '\ub11e' .. '\ub138' - | '\ud835' '\ub13b' .. '\ub13d' - | '\ud835' '\ub140' .. '\ub143' - | '\ud835' '\ud546' - | '\ud835' '\ub14a' .. '\ub14f' - | '\ud835' '\ub152' .. '\ub2a2' - | '\ud835' '\ub2a8' .. '\ub2bf' - | '\ud835' '\ub2c2' .. '\ub2d9' - | '\ud835' '\ub2dc' .. '\ub2f9' - | '\ud835' '\ub2fc' .. '\ub313' - | '\ud835' '\ub316' .. '\ub333' - | '\ud835' '\ub336' .. '\ub34d' - | '\ud835' '\ub350' .. '\ub36d' - | '\ud835' '\ub370' .. '\ub387' - | '\ud835' '\ub38a' .. '\ub3a7' - | '\ud835' '\ub3aa' .. '\ub3c1' - | '\ud835' '\ub3c4' .. '\ub3c8' - | '\ud835' '\ub3ce' .. '\ub3fe' - | '\ud840' '\udc00' .. '\udffe' - | '\ud841' '\ue000' .. '\ue3fe' - | '\ud842' '\ue400' .. '\ue7fe' - | '\ud843' '\ue800' .. '\uebfe' - | '\ud844' '\uec00' .. '\ueffe' - | '\ud845' '\uf000' .. '\uf3fe' - | '\ud846' '\uf400' .. '\uf7fe' - | '\ud847' '\uf800' .. '\ufbfe' - | '\ud848' '\ufc00' .. '\ufffe' - | '\ud849' '\u0000' .. '\u03fe' - | '\ud84a' '\u0400' .. '\u07fe' - | '\ud84b' '\u0800' .. '\u0bfe' - | '\ud84c' '\u0c00' .. '\u0ffe' - | '\ud84d' '\u1000' .. '\u13fe' - | '\ud84e' '\u1400' .. '\u17fe' - | '\ud84f' '\u1800' .. '\u1bfe' - | '\ud850' '\u1c00' .. '\u1ffe' - | '\ud851' '\u2000' .. '\u23fe' - | '\ud852' '\u2400' .. '\u27fe' - | '\ud853' '\u2800' .. '\u2bfe' - | '\ud854' '\u2c00' .. '\u2ffe' - | '\ud855' '\u3000' .. '\u33fe' - | '\ud856' '\u3400' .. '\u37fe' - | '\ud857' '\u3800' .. '\u3bfe' - | '\ud858' '\u3c00' .. '\u3ffe' - | '\ud859' '\u4000' .. '\u43fe' - | '\ud85a' '\u4400' .. '\u47fe' - | '\ud85b' '\u4800' .. '\u4bfe' - | '\ud85c' '\u4c00' .. '\u4ffe' - | '\ud85d' '\u5000' .. '\u53fe' - | '\ud85e' '\u5400' .. '\u57fe' - | '\ud85f' '\u5800' .. '\u5bfe' - | '\ud860' '\u5c00' .. '\u5ffe' - | '\ud861' '\u6000' .. '\u63fe' - | '\ud862' '\u6400' .. '\u67fe' - | '\ud863' '\u6800' .. '\u6bfe' - | '\ud864' '\u6c00' .. '\u6ffe' - | '\ud865' '\u7000' .. '\u73fe' - | '\ud866' '\u7400' .. '\u77fe' - | '\ud867' '\u7800' .. '\u7bfe' - | '\ud868' '\u7c00' .. '\u7ffe' - | '\ud869' '\u8000' .. '\u82d5' - | '\ud87e' '\ud400' .. '\ud61c' - | '\udb40' '\udd00' .. '\uddee' - ; diff --git a/src/grammar/xidstart.g4 b/src/grammar/xidstart.g4 deleted file mode 100644 index 53fb50f4584d..000000000000 --- a/src/grammar/xidstart.g4 +++ /dev/null @@ -1,379 +0,0 @@ -lexer grammar Xidstart; - -fragment XID_Start : - '\u0041' .. '\u005a' - | '_' - | '\u0061' .. '\u007a' - | '\u00aa' - | '\u00b5' - | '\u00ba' - | '\u00c0' .. '\u00d6' - | '\u00d8' .. '\u00f6' - | '\u00f8' .. '\u0236' - | '\u0250' .. '\u02c1' - | '\u02c6' .. '\u02d1' - | '\u02e0' .. '\u02e4' - | '\u02ee' - | '\u0386' - | '\u0388' .. '\u038a' - | '\u038c' - | '\u038e' .. '\u03a1' - | '\u03a3' .. '\u03ce' - | '\u03d0' .. '\u03f5' - | '\u03f7' .. '\u03fb' - | '\u0400' .. '\u0481' - | '\u048a' .. '\u04ce' - | '\u04d0' .. '\u04f5' - | '\u04f8' .. '\u04f9' - | '\u0500' .. '\u050f' - | '\u0531' .. '\u0556' - | '\u0559' - | '\u0561' .. '\u0587' - | '\u05d0' .. '\u05ea' - | '\u05f0' .. '\u05f2' - | '\u0621' .. '\u063a' - | '\u0640' .. '\u064a' - | '\u066e' .. '\u066f' - | '\u0671' .. '\u06d3' - | '\u06d5' - | '\u06e5' .. '\u06e6' - | '\u06ee' .. '\u06ef' - | '\u06fa' .. '\u06fc' - | '\u06ff' - | '\u0710' - | '\u0712' .. '\u072f' - | '\u074d' .. '\u074f' - | '\u0780' .. '\u07a5' - | '\u07b1' - | '\u0904' .. '\u0939' - | '\u093d' - | '\u0950' - | '\u0958' .. '\u0961' - | '\u0985' .. '\u098c' - | '\u098f' .. '\u0990' - | '\u0993' .. '\u09a8' - | '\u09aa' .. '\u09b0' - | '\u09b2' - | '\u09b6' .. '\u09b9' - | '\u09bd' - | '\u09dc' .. '\u09dd' - | '\u09df' .. '\u09e1' - | '\u09f0' .. '\u09f1' - | '\u0a05' .. '\u0a0a' - | '\u0a0f' .. '\u0a10' - | '\u0a13' .. '\u0a28' - | '\u0a2a' .. '\u0a30' - | '\u0a32' .. '\u0a33' - | '\u0a35' .. '\u0a36' - | '\u0a38' .. '\u0a39' - | '\u0a59' .. '\u0a5c' - | '\u0a5e' - | '\u0a72' .. '\u0a74' - | '\u0a85' .. '\u0a8d' - | '\u0a8f' .. '\u0a91' - | '\u0a93' .. '\u0aa8' - | '\u0aaa' .. '\u0ab0' - | '\u0ab2' .. '\u0ab3' - | '\u0ab5' .. '\u0ab9' - | '\u0abd' - | '\u0ad0' - | '\u0ae0' .. '\u0ae1' - | '\u0b05' .. '\u0b0c' - | '\u0b0f' .. '\u0b10' - | '\u0b13' .. '\u0b28' - | '\u0b2a' .. '\u0b30' - | '\u0b32' .. '\u0b33' - | '\u0b35' .. '\u0b39' - | '\u0b3d' - | '\u0b5c' .. '\u0b5d' - | '\u0b5f' .. '\u0b61' - | '\u0b71' - | '\u0b83' - | '\u0b85' .. '\u0b8a' - | '\u0b8e' .. '\u0b90' - | '\u0b92' .. '\u0b95' - | '\u0b99' .. '\u0b9a' - | '\u0b9c' - | '\u0b9e' .. '\u0b9f' - | '\u0ba3' .. '\u0ba4' - | '\u0ba8' .. '\u0baa' - | '\u0bae' .. '\u0bb5' - | '\u0bb7' .. '\u0bb9' - | '\u0c05' .. '\u0c0c' - | '\u0c0e' .. '\u0c10' - | '\u0c12' .. '\u0c28' - | '\u0c2a' .. '\u0c33' - | '\u0c35' .. '\u0c39' - | '\u0c60' .. '\u0c61' - | '\u0c85' .. '\u0c8c' - | '\u0c8e' .. '\u0c90' - | '\u0c92' .. '\u0ca8' - | '\u0caa' .. '\u0cb3' - | '\u0cb5' .. '\u0cb9' - | '\u0cbd' - | '\u0cde' - | '\u0ce0' .. '\u0ce1' - | '\u0d05' .. '\u0d0c' - | '\u0d0e' .. '\u0d10' - | '\u0d12' .. '\u0d28' - | '\u0d2a' .. '\u0d39' - | '\u0d60' .. '\u0d61' - | '\u0d85' .. '\u0d96' - | '\u0d9a' .. '\u0db1' - | '\u0db3' .. '\u0dbb' - | '\u0dbd' - | '\u0dc0' .. '\u0dc6' - | '\u0e01' .. '\u0e30' - | '\u0e32' - | '\u0e40' .. '\u0e46' - | '\u0e81' .. '\u0e82' - | '\u0e84' - | '\u0e87' .. '\u0e88' - | '\u0e8a' - | '\u0e8d' - | '\u0e94' .. '\u0e97' - | '\u0e99' .. '\u0e9f' - | '\u0ea1' .. '\u0ea3' - | '\u0ea5' - | '\u0ea7' - | '\u0eaa' .. '\u0eab' - | '\u0ead' .. '\u0eb0' - | '\u0eb2' - | '\u0ebd' - | '\u0ec0' .. '\u0ec4' - | '\u0ec6' - | '\u0edc' .. '\u0edd' - | '\u0f00' - | '\u0f40' .. '\u0f47' - | '\u0f49' .. '\u0f6a' - | '\u0f88' .. '\u0f8b' - | '\u1000' .. '\u1021' - | '\u1023' .. '\u1027' - | '\u1029' .. '\u102a' - | '\u1050' .. '\u1055' - | '\u10a0' .. '\u10c5' - | '\u10d0' .. '\u10f8' - | '\u1100' .. '\u1159' - | '\u115f' .. '\u11a2' - | '\u11a8' .. '\u11f9' - | '\u1200' .. '\u1206' - | '\u1208' .. '\u1246' - | '\u1248' - | '\u124a' .. '\u124d' - | '\u1250' .. '\u1256' - | '\u1258' - | '\u125a' .. '\u125d' - | '\u1260' .. '\u1286' - | '\u1288' - | '\u128a' .. '\u128d' - | '\u1290' .. '\u12ae' - | '\u12b0' - | '\u12b2' .. '\u12b5' - | '\u12b8' .. '\u12be' - | '\u12c0' - | '\u12c2' .. '\u12c5' - | '\u12c8' .. '\u12ce' - | '\u12d0' .. '\u12d6' - | '\u12d8' .. '\u12ee' - | '\u12f0' .. '\u130e' - | '\u1310' - | '\u1312' .. '\u1315' - | '\u1318' .. '\u131e' - | '\u1320' .. '\u1346' - | '\u1348' .. '\u135a' - | '\u13a0' .. '\u13f4' - | '\u1401' .. '\u166c' - | '\u166f' .. '\u1676' - | '\u1681' .. '\u169a' - | '\u16a0' .. '\u16ea' - | '\u16ee' .. '\u16f0' - | '\u1700' .. '\u170c' - | '\u170e' .. '\u1711' - | '\u1720' .. '\u1731' - | '\u1740' .. '\u1751' - | '\u1760' .. '\u176c' - | '\u176e' .. '\u1770' - | '\u1780' .. '\u17b3' - | '\u17d7' - | '\u17dc' - | '\u1820' .. '\u1877' - | '\u1880' .. '\u18a8' - | '\u1900' .. '\u191c' - | '\u1950' .. '\u196d' - | '\u1970' .. '\u1974' - | '\u1d00' .. '\u1d6b' - | '\u1e00' .. '\u1e9b' - | '\u1ea0' .. '\u1ef9' - | '\u1f00' .. '\u1f15' - | '\u1f18' .. '\u1f1d' - | '\u1f20' .. '\u1f45' - | '\u1f48' .. '\u1f4d' - | '\u1f50' .. '\u1f57' - | '\u1f59' - | '\u1f5b' - | '\u1f5d' - | '\u1f5f' .. '\u1f7d' - | '\u1f80' .. '\u1fb4' - | '\u1fb6' .. '\u1fbc' - | '\u1fbe' - | '\u1fc2' .. '\u1fc4' - | '\u1fc6' .. '\u1fcc' - | '\u1fd0' .. '\u1fd3' - | '\u1fd6' .. '\u1fdb' - | '\u1fe0' .. '\u1fec' - | '\u1ff2' .. '\u1ff4' - | '\u1ff6' .. '\u1ffc' - | '\u2071' - | '\u207f' - | '\u2102' - | '\u2107' - | '\u210a' .. '\u2113' - | '\u2115' - | '\u2118' .. '\u211d' - | '\u2124' - | '\u2126' - | '\u2128' - | '\u212a' .. '\u2131' - | '\u2133' .. '\u2139' - | '\u213d' .. '\u213f' - | '\u2145' .. '\u2149' - | '\u2160' .. '\u2183' - | '\u3005' .. '\u3007' - | '\u3021' .. '\u3029' - | '\u3031' .. '\u3035' - | '\u3038' .. '\u303c' - | '\u3041' .. '\u3096' - | '\u309d' .. '\u309f' - | '\u30a1' .. '\u30fa' - | '\u30fc' .. '\u30ff' - | '\u3105' .. '\u312c' - | '\u3131' .. '\u318e' - | '\u31a0' .. '\u31b7' - | '\u31f0' .. '\u31ff' - | '\u3400' .. '\u4db5' - | '\u4e00' .. '\u9fa5' - | '\ua000' .. '\ua48c' - | '\uac00' .. '\ud7a3' - | '\uf900' .. '\ufa2d' - | '\ufa30' .. '\ufa6a' - | '\ufb00' .. '\ufb06' - | '\ufb13' .. '\ufb17' - | '\ufb1d' - | '\ufb1f' .. '\ufb28' - | '\ufb2a' .. '\ufb36' - | '\ufb38' .. '\ufb3c' - | '\ufb3e' - | '\ufb40' .. '\ufb41' - | '\ufb43' .. '\ufb44' - | '\ufb46' .. '\ufbb1' - | '\ufbd3' .. '\ufc5d' - | '\ufc64' .. '\ufd3d' - | '\ufd50' .. '\ufd8f' - | '\ufd92' .. '\ufdc7' - | '\ufdf0' .. '\ufdf9' - | '\ufe71' - | '\ufe73' - | '\ufe77' - | '\ufe79' - | '\ufe7b' - | '\ufe7d' - | '\ufe7f' .. '\ufefc' - | '\uff21' .. '\uff3a' - | '\uff41' .. '\uff5a' - | '\uff66' .. '\uff9d' - | '\uffa0' .. '\uffbe' - | '\uffc2' .. '\uffc7' - | '\uffca' .. '\uffcf' - | '\uffd2' .. '\uffd7' - | '\uffda' .. '\uffdc' - | '\ud800' '\udc00' .. '\udc0a' - | '\ud800' '\udc0d' .. '\udc25' - | '\ud800' '\udc28' .. '\udc39' - | '\ud800' '\udc3c' .. '\udc3c' - | '\ud800' '\udc3f' .. '\udc4c' - | '\ud800' '\udc50' .. '\udc5c' - | '\ud800' '\udc80' .. '\udcf9' - | '\ud800' '\udf00' .. '\udf1d' - | '\ud800' '\udf30' .. '\udf49' - | '\ud800' '\udf80' .. '\udf9c' - | '\ud801' '\ue000' .. '\ue09c' - | '\ud802' '\ue400' .. '\ue404' - | '\ud802' '\u0808' - | '\ud802' '\ue40a' .. '\ue434' - | '\ud802' '\ue437' .. '\ue437' - | '\ud802' '\u083c' - | '\ud802' '\u083f' - | '\ud835' '\ub000' .. '\ub053' - | '\ud835' '\ub056' .. '\ub09b' - | '\ud835' '\ub09e' .. '\ub09e' - | '\ud835' '\ud4a2' - | '\ud835' '\ub0a5' .. '\ub0a5' - | '\ud835' '\ub0a9' .. '\ub0ab' - | '\ud835' '\ub0ae' .. '\ub0b8' - | '\ud835' '\ud4bb' - | '\ud835' '\ub0bd' .. '\ub0c2' - | '\ud835' '\ub0c5' .. '\ub104' - | '\ud835' '\ub107' .. '\ub109' - | '\ud835' '\ub10d' .. '\ub113' - | '\ud835' '\ub116' .. '\ub11b' - | '\ud835' '\ub11e' .. '\ub138' - | '\ud835' '\ub13b' .. '\ub13d' - | '\ud835' '\ub140' .. '\ub143' - | '\ud835' '\ud546' - | '\ud835' '\ub14a' .. '\ub14f' - | '\ud835' '\ub152' .. '\ub2a2' - | '\ud835' '\ub2a8' .. '\ub2bf' - | '\ud835' '\ub2c2' .. '\ub2d9' - | '\ud835' '\ub2dc' .. '\ub2f9' - | '\ud835' '\ub2fc' .. '\ub313' - | '\ud835' '\ub316' .. '\ub333' - | '\ud835' '\ub336' .. '\ub34d' - | '\ud835' '\ub350' .. '\ub36d' - | '\ud835' '\ub370' .. '\ub387' - | '\ud835' '\ub38a' .. '\ub3a7' - | '\ud835' '\ub3aa' .. '\ub3c1' - | '\ud835' '\ub3c4' .. '\ub3c8' - | '\ud840' '\udc00' .. '\udffe' - | '\ud841' '\ue000' .. '\ue3fe' - | '\ud842' '\ue400' .. '\ue7fe' - | '\ud843' '\ue800' .. '\uebfe' - | '\ud844' '\uec00' .. '\ueffe' - | '\ud845' '\uf000' .. '\uf3fe' - | '\ud846' '\uf400' .. '\uf7fe' - | '\ud847' '\uf800' .. '\ufbfe' - | '\ud848' '\ufc00' .. '\ufffe' - | '\ud849' '\u0000' .. '\u03fe' - | '\ud84a' '\u0400' .. '\u07fe' - | '\ud84b' '\u0800' .. '\u0bfe' - | '\ud84c' '\u0c00' .. '\u0ffe' - | '\ud84d' '\u1000' .. '\u13fe' - | '\ud84e' '\u1400' .. '\u17fe' - | '\ud84f' '\u1800' .. '\u1bfe' - | '\ud850' '\u1c00' .. '\u1ffe' - | '\ud851' '\u2000' .. '\u23fe' - | '\ud852' '\u2400' .. '\u27fe' - | '\ud853' '\u2800' .. '\u2bfe' - | '\ud854' '\u2c00' .. '\u2ffe' - | '\ud855' '\u3000' .. '\u33fe' - | '\ud856' '\u3400' .. '\u37fe' - | '\ud857' '\u3800' .. '\u3bfe' - | '\ud858' '\u3c00' .. '\u3ffe' - | '\ud859' '\u4000' .. '\u43fe' - | '\ud85a' '\u4400' .. '\u47fe' - | '\ud85b' '\u4800' .. '\u4bfe' - | '\ud85c' '\u4c00' .. '\u4ffe' - | '\ud85d' '\u5000' .. '\u53fe' - | '\ud85e' '\u5400' .. '\u57fe' - | '\ud85f' '\u5800' .. '\u5bfe' - | '\ud860' '\u5c00' .. '\u5ffe' - | '\ud861' '\u6000' .. '\u63fe' - | '\ud862' '\u6400' .. '\u67fe' - | '\ud863' '\u6800' .. '\u6bfe' - | '\ud864' '\u6c00' .. '\u6ffe' - | '\ud865' '\u7000' .. '\u73fe' - | '\ud866' '\u7400' .. '\u77fe' - | '\ud867' '\u7800' .. '\u7bfe' - | '\ud868' '\u7c00' .. '\u7ffe' - | '\ud869' '\u8000' .. '\u82d5' - | '\ud87e' '\ud400' .. '\ud61c' - ; diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 28f6d97756f2..1df79074d3f4 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -165,18 +165,29 @@ unsafe impl Sync for Arc {} #[unstable(feature = "coerce_unsized", issue = "27732")] impl, U: ?Sized> CoerceUnsized> for Arc {} -/// A weak version of [`Arc`][arc]. +/// `Weak` is a version of [`Arc`] that holds a non-owning reference to the +/// managed value. The value is accessed by calling [`upgrade`] on the `Weak` +/// pointer, which returns an [`Option`]`<`[`Arc`]`>`. /// -/// `Weak` pointers do not count towards determining if the inner value -/// should be dropped. +/// Since a `Weak` reference does not count towards ownership, it will not +/// prevent the inner value from being dropped, and `Weak` itself makes no +/// guarantees about the value still being present and may return [`None`] +/// when [`upgrade`]d. /// -/// The typical way to obtain a `Weak` pointer is to call -/// [`Arc::downgrade`][downgrade]. +/// A `Weak` pointer is useful for keeping a temporary reference to the value +/// within [`Arc`] without extending its lifetime. It is also used to prevent +/// circular references between [`Arc`] pointers, since mutual owning references +/// would never allow either [`Arc`] to be dropped. For example, a tree could +/// have strong [`Arc`] pointers from parent nodes to children, and `Weak` +/// pointers from children back to their parents. /// -/// See the [`Arc`][arc] documentation for more details. +/// The typical way to obtain a `Weak` pointer is to call [`Arc::downgrade`]. /// -/// [arc]: struct.Arc.html -/// [downgrade]: struct.Arc.html#method.downgrade +/// [`Arc`]: struct.Arc.html +/// [`Arc::downgrade`]: struct.Arc.html#method.downgrade +/// [`upgrade`]: struct.Weak.html#method.upgrade +/// [`Option`]: ../../std/option/enum.Option.html +/// [`None`]: ../../std/option/enum.Option.html#variant.None #[stable(feature = "arc_weak", since = "1.4.0")] pub struct Weak { ptr: Shared>, @@ -756,7 +767,18 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for Arc { // > through this reference must obviously happened before), and an // > "acquire" operation before deleting the object. // + // In particular, while the contents of an Arc are usually immutable, it's + // possible to have interior writes to something like a Mutex. Since a + // Mutex is not acquired when it is deleted, we can't rely on its + // synchronization logic to make writes in thread A visible to a destructor + // running in thread B. + // + // Also note that the Acquire fence here could probably be replaced with an + // Acquire load, which could improve performance in highly-contended + // situations. See [2]. + // // [1]: (www.boost.org/doc/libs/1_55_0/doc/html/atomic/usage_examples.html) + // [2]: (https://github.com/rust-lang/rust/pull/41714) atomic::fence(Acquire); unsafe { @@ -766,14 +788,11 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for Arc { } impl Weak { - /// Constructs a new `Weak`, without an accompanying instance of `T`. + /// Constructs a new `Weak`, allocating memory for `T` without initializing + /// it. Calling [`upgrade`] on the return value always gives [`None`]. /// - /// This allocates memory for `T`, but does not initialize it. Calling - /// [`upgrade`][upgrade] on the return value always gives - /// [`None`][option]. - /// - /// [upgrade]: struct.Weak.html#method.upgrade - /// [option]: ../../std/option/enum.Option.html + /// [`upgrade`]: struct.Weak.html#method.upgrade + /// [`None`]: ../../std/option/enum.Option.html#variant.None /// /// # Examples /// @@ -798,13 +817,13 @@ impl Weak { } impl Weak { - /// Upgrades the `Weak` pointer to an [`Arc`][arc], if possible. + /// Attempts to upgrade the `Weak` pointer to an [`Arc`], extending + /// the lifetime of the value if successful. /// - /// Returns [`None`][option] if the strong count has reached zero and the - /// inner value was destroyed. + /// Returns [`None`] if the value has since been dropped. /// - /// [arc]: struct.Arc.html - /// [option]: ../../std/option/enum.Option.html + /// [`Arc`]: struct.Arc.html + /// [`None`]: ../../std/option/enum.Option.html#variant.None /// /// # Examples /// @@ -865,10 +884,7 @@ impl Weak { #[stable(feature = "arc_weak", since = "1.4.0")] impl Clone for Weak { - /// Makes a clone of the `Weak` pointer. - /// - /// This creates another pointer to the same inner value, increasing the - /// weak reference count. + /// Makes a clone of the `Weak` pointer that points to the same value. /// /// # Examples /// @@ -900,14 +916,11 @@ impl Clone for Weak { #[stable(feature = "downgraded_weak", since = "1.10.0")] impl Default for Weak { - /// Constructs a new `Weak`, without an accompanying instance of `T`. + /// Constructs a new `Weak`, allocating memory for `T` without initializing + /// it. Calling [`upgrade`] on the return value always gives [`None`]. /// - /// This allocates memory for `T`, but does not initialize it. Calling - /// [`upgrade`][upgrade] on the return value always gives - /// [`None`][option]. - /// - /// [upgrade]: struct.Weak.html#method.upgrade - /// [option]: ../../std/option/enum.Option.html + /// [`upgrade`]: struct.Weak.html#method.upgrade + /// [`None`]: ../../std/option/enum.Option.html#variant.None /// /// # Examples /// @@ -926,8 +939,6 @@ impl Default for Weak { impl Drop for Weak { /// Drops the `Weak` pointer. /// - /// This will decrement the weak reference count. - /// /// # Examples /// /// ``` diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 43b0d72186a2..b03e3bb7a4bd 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -68,6 +68,7 @@ use core::ops::{CoerceUnsized, Deref, DerefMut}; use core::ops::{BoxPlace, Boxed, InPlace, Place, Placer}; use core::ptr::{self, Unique}; use core::convert::From; +use str::from_boxed_utf8_unchecked; /// A value that represents the heap. This is the default place that the `box` /// keyword allocates into when no place is supplied. @@ -320,8 +321,7 @@ impl Default for Box<[T]> { #[stable(feature = "default_box_extra", since = "1.17.0")] impl Default for Box { fn default() -> Box { - let default: Box<[u8]> = Default::default(); - unsafe { mem::transmute(default) } + unsafe { from_boxed_utf8_unchecked(Default::default()) } } } @@ -366,7 +366,7 @@ impl Clone for Box { let buf = RawVec::with_capacity(len); unsafe { ptr::copy_nonoverlapping(self.as_ptr(), buf.ptr(), len); - mem::transmute(buf.into_box()) // bytes to str ~magic + from_boxed_utf8_unchecked(buf.into_box()) } } } @@ -441,8 +441,16 @@ impl<'a, T: Copy> From<&'a [T]> for Box<[T]> { #[stable(feature = "box_from_slice", since = "1.17.0")] impl<'a> From<&'a str> for Box { fn from(s: &'a str) -> Box { - let boxed: Box<[u8]> = Box::from(s.as_bytes()); - unsafe { mem::transmute(boxed) } + unsafe { from_boxed_utf8_unchecked(Box::from(s.as_bytes())) } + } +} + +#[stable(feature = "boxed_str_conv", since = "1.18.0")] +impl From> for Box<[u8]> { + fn from(s: Box) -> Self { + unsafe { + mem::transmute(s) + } } } diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs index 51e6f2f8bd7a..056af13016cf 100644 --- a/src/liballoc/heap.rs +++ b/src/liballoc/heap.rs @@ -16,13 +16,13 @@ issue = "27700")] use core::{isize, usize}; -#[cfg(not(test))] use core::intrinsics::{min_align_of_val, size_of_val}; #[allow(improper_ctypes)] extern "C" { #[allocator] fn __rust_allocate(size: usize, align: usize) -> *mut u8; + fn __rust_allocate_zeroed(size: usize, align: usize) -> *mut u8; fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize); fn __rust_reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usize) -> *mut u8; fn __rust_reallocate_inplace(ptr: *mut u8, @@ -59,6 +59,20 @@ pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 { __rust_allocate(size, align) } +/// Return a pointer to `size` bytes of memory aligned to `align` and +/// initialized to zeroes. +/// +/// On failure, return a null pointer. +/// +/// Behavior is undefined if the requested size is 0 or the alignment is not a +/// power of 2. The alignment must be no larger than the largest supported page +/// size on the platform. +#[inline] +pub unsafe fn allocate_zeroed(size: usize, align: usize) -> *mut u8 { + check_size_and_alignment(size, align); + __rust_allocate_zeroed(size, align) +} + /// Resize the allocation referenced by `ptr` to `size` bytes. /// /// On failure, return a null pointer and leave the original allocation intact. @@ -143,10 +157,9 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { } } -#[cfg(not(test))] -#[lang = "box_free"] +#[cfg_attr(not(test), lang = "box_free")] #[inline] -unsafe fn box_free(ptr: *mut T) { +pub(crate) unsafe fn box_free(ptr: *mut T) { let size = size_of_val(&*ptr); let align = min_align_of_val(&*ptr); // We do not allocate for Box when T is ZST, so deallocation is also not necessary. @@ -162,6 +175,25 @@ mod tests { use boxed::Box; use heap; + #[test] + fn allocate_zeroed() { + unsafe { + let size = 1024; + let ptr = heap::allocate_zeroed(size, 1); + if ptr.is_null() { + ::oom() + } + + let end = ptr.offset(size as isize); + let mut i = ptr; + while i < end { + assert_eq!(*i, 0); + i = i.offset(1); + } + heap::deallocate(ptr, size, 1); + } + } + #[test] fn basic_reallocate_inplace_noop() { unsafe { diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 0c01eabd593f..418a084da678 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -128,6 +128,8 @@ mod boxed_test; pub mod arc; pub mod rc; pub mod raw_vec; +#[unstable(feature = "str_box_extras", issue = "41119")] +pub mod str; pub mod oom; pub use oom::oom; diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index 357a2724e002..6a53d3a9ca57 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -81,7 +81,18 @@ impl RawVec { /// # Aborts /// /// Aborts on OOM + #[inline] pub fn with_capacity(cap: usize) -> Self { + RawVec::allocate(cap, false) + } + + /// Like `with_capacity` but guarantees the buffer is zeroed. + #[inline] + pub fn with_capacity_zeroed(cap: usize) -> Self { + RawVec::allocate(cap, true) + } + + fn allocate(cap: usize, zeroed: bool) -> Self { unsafe { let elem_size = mem::size_of::(); @@ -93,7 +104,11 @@ impl RawVec { heap::EMPTY as *mut u8 } else { let align = mem::align_of::(); - let ptr = heap::allocate(alloc_size, align); + let ptr = if zeroed { + heap::allocate_zeroed(alloc_size, align) + } else { + heap::allocate(alloc_size, align) + }; if ptr.is_null() { oom() } diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 561ccaa5ef5c..38dc91458351 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -239,7 +239,7 @@ use core::ops::CoerceUnsized; use core::ptr::{self, Shared}; use core::convert::From; -use heap::deallocate; +use heap::{allocate, deallocate, box_free}; use raw_vec::RawVec; struct RcBox { @@ -248,7 +248,6 @@ struct RcBox { value: T, } - /// A single-threaded reference-counting pointer. /// /// See the [module-level documentation](./index.html) for more details. @@ -341,19 +340,6 @@ impl Rc { } } - /// Checks whether [`Rc::try_unwrap`][try_unwrap] would return - /// [`Ok`]. - /// - /// [try_unwrap]: struct.Rc.html#method.try_unwrap - /// [`Ok`]: ../../std/result/enum.Result.html#variant.Ok - #[unstable(feature = "rc_would_unwrap", - reason = "just added for niche usecase", - issue = "28356")] - #[rustc_deprecated(since = "1.15.0", reason = "too niche; use `strong_count` instead")] - pub fn would_unwrap(this: &Self) -> bool { - Rc::strong_count(&this) == 1 - } - /// Consumes the `Rc`, returning the wrapped pointer. /// /// To avoid a memory leak the pointer must be converted back to an `Rc` using @@ -438,6 +424,38 @@ impl Rc { } } +impl Rc<[T]> { + /// Constructs a new `Rc<[T]>` from a `Box<[T]>`. + #[doc(hidden)] + #[unstable(feature = "rustc_private", + reason = "for internal use in rustc", + issue = "0")] + pub fn __from_array(value: Box<[T]>) -> Rc<[T]> { + unsafe { + let ptr: *mut RcBox<[T]> = + mem::transmute([mem::align_of::>(), value.len()]); + // FIXME(custom-DST): creating this invalid &[T] is dubiously defined, + // we should have a better way of getting the size/align + // of a DST from its unsized part. + let ptr = allocate(size_of_val(&*ptr), align_of_val(&*ptr)); + let ptr: *mut RcBox<[T]> = mem::transmute([ptr as usize, value.len()]); + + // Initialize the new RcBox. + ptr::write(&mut (*ptr).strong, Cell::new(1)); + ptr::write(&mut (*ptr).weak, Cell::new(1)); + ptr::copy_nonoverlapping( + value.as_ptr(), + &mut (*ptr).value as *mut [T] as *mut T, + value.len()); + + // Free the original allocation without freeing its (moved) contents. + box_free(Box::into_raw(value)); + + Rc { ptr: Shared::new(ptr as *const _) } + } + } +} + impl Rc { /// Creates a new [`Weak`][weak] pointer to this value. /// @@ -501,11 +519,7 @@ impl Rc { /// /// [weak]: struct.Weak.html #[inline] - #[unstable(feature = "is_unique", reason = "uniqueness has unclear meaning", - issue = "28356")] - #[rustc_deprecated(since = "1.15.0", - reason = "too niche; use `strong_count` and `weak_count` instead")] - pub fn is_unique(this: &Self) -> bool { + fn is_unique(this: &Self) -> bool { Rc::weak_count(this) == 0 && Rc::strong_count(this) == 1 } @@ -922,18 +936,29 @@ impl From for Rc { } } -/// A weak version of [`Rc`][rc]. +/// `Weak` is a version of [`Rc`] that holds a non-owning reference to the +/// managed value. The value is accessed by calling [`upgrade`] on the `Weak` +/// pointer, which returns an [`Option`]`<`[`Rc`]`>`. /// -/// `Weak` pointers do not count towards determining if the inner value -/// should be dropped. +/// Since a `Weak` reference does not count towards ownership, it will not +/// prevent the inner value from being dropped, and `Weak` itself makes no +/// guarantees about the value still being present and may return [`None`] +/// when [`upgrade`]d. /// -/// The typical way to obtain a `Weak` pointer is to call -/// [`Rc::downgrade`][downgrade]. +/// A `Weak` pointer is useful for keeping a temporary reference to the value +/// within [`Rc`] without extending its lifetime. It is also used to prevent +/// circular references between [`Rc`] pointers, since mutual owning references +/// would never allow either [`Arc`] to be dropped. For example, a tree could +/// have strong [`Rc`] pointers from parent nodes to children, and `Weak` +/// pointers from children back to their parents. /// -/// See the [module-level documentation](./index.html) for more details. +/// The typical way to obtain a `Weak` pointer is to call [`Rc::downgrade`]. /// -/// [rc]: struct.Rc.html -/// [downgrade]: struct.Rc.html#method.downgrade +/// [`Rc`]: struct.Rc.html +/// [`Rc::downgrade`]: struct.Rc.html#method.downgrade +/// [`upgrade`]: struct.Weak.html#method.upgrade +/// [`Option`]: ../../std/option/enum.Option.html +/// [`None`]: ../../std/option/enum.Option.html#variant.None #[stable(feature = "rc_weak", since = "1.4.0")] pub struct Weak { ptr: Shared>, @@ -948,14 +973,11 @@ impl !marker::Sync for Weak {} impl, U: ?Sized> CoerceUnsized> for Weak {} impl Weak { - /// Constructs a new `Weak`, without an accompanying instance of `T`. + /// Constructs a new `Weak`, allocating memory for `T` without initializing + /// it. Calling [`upgrade`] on the return value always gives [`None`]. /// - /// This allocates memory for `T`, but does not initialize it. Calling - /// [`upgrade`][upgrade] on the return value always gives - /// [`None`][option]. - /// - /// [upgrade]: struct.Weak.html#method.upgrade - /// [option]: ../../std/option/enum.Option.html + /// [`upgrade`]: struct.Weak.html#method.upgrade + /// [`None`]: ../../std/option/enum.Option.html /// /// # Examples /// @@ -980,13 +1002,13 @@ impl Weak { } impl Weak { - /// Upgrades the `Weak` pointer to an [`Rc`][rc], if possible. + /// Attempts to upgrade the `Weak` pointer to an [`Rc`], extending + /// the lifetime of the value if successful. /// - /// Returns [`None`][option] if the strong count has reached zero and the - /// inner value was destroyed. + /// Returns [`None`] if the value has since been dropped. /// - /// [rc]: struct.Rc.html - /// [option]: ../../std/option/enum.Option.html + /// [`Rc`]: struct.Rc.html + /// [`None`]: ../../std/option/enum.Option.html /// /// # Examples /// @@ -1021,8 +1043,6 @@ impl Weak { impl Drop for Weak { /// Drops the `Weak` pointer. /// - /// This will decrement the weak reference count. - /// /// # Examples /// /// ``` @@ -1061,10 +1081,7 @@ impl Drop for Weak { #[stable(feature = "rc_weak", since = "1.4.0")] impl Clone for Weak { - /// Makes a clone of the `Weak` pointer. - /// - /// This creates another pointer to the same inner value, increasing the - /// weak reference count. + /// Makes a clone of the `Weak` pointer that points to the same value. /// /// # Examples /// @@ -1091,14 +1108,11 @@ impl fmt::Debug for Weak { #[stable(feature = "downgraded_weak", since = "1.10.0")] impl Default for Weak { - /// Constructs a new `Weak`, without an accompanying instance of `T`. + /// Constructs a new `Weak`, allocating memory for `T` without initializing + /// it. Calling [`upgrade`] on the return value always gives [`None`]. /// - /// This allocates memory for `T`, but does not initialize it. Calling - /// [`upgrade`][upgrade] on the return value always gives - /// [`None`][option]. - /// - /// [upgrade]: struct.Weak.html#method.upgrade - /// [option]: ../../std/option/enum.Option.html + /// [`upgrade`]: struct.Weak.html#method.upgrade + /// [`None`]: ../../std/option/enum.Option.html /// /// # Examples /// diff --git a/src/test/run-pass-fulldeps/auxiliary/logging_right_crate.rs b/src/liballoc/str.rs similarity index 50% rename from src/test/run-pass-fulldeps/auxiliary/logging_right_crate.rs rename to src/liballoc/str.rs index db26b10fc67c..c87db16a0f41 100644 --- a/src/test/run-pass-fulldeps/auxiliary/logging_right_crate.rs +++ b/src/liballoc/str.rs @@ -1,4 +1,4 @@ -// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2017 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,11 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_private)] +//! Methods for dealing with boxed strings. +use core::mem; -#[macro_use] extern crate log; +use boxed::Box; -pub fn foo() { - fn death() -> isize { panic!() } - debug!("{}", (||{ death() })()); +/// Converts a boxed slice of bytes to a boxed string slice without checking +/// that the string contains valid UTF-8. +#[unstable(feature = "str_box_extras", issue = "41119")] +pub unsafe fn from_boxed_utf8_unchecked(v: Box<[u8]>) -> Box { + mem::transmute(v) } diff --git a/src/liballoc_jemalloc/build.rs b/src/liballoc_jemalloc/build.rs index ae040a239065..f3a0eebe6984 100644 --- a/src/liballoc_jemalloc/build.rs +++ b/src/liballoc_jemalloc/build.rs @@ -129,7 +129,7 @@ fn main() { // should be good to go! cmd.arg("--with-jemalloc-prefix=je_"); cmd.arg("--disable-tls"); - } else if target.contains("dragonfly") { + } else if target.contains("dragonfly") || target.contains("musl") { cmd.arg("--with-jemalloc-prefix=je_"); } diff --git a/src/liballoc_jemalloc/lib.rs b/src/liballoc_jemalloc/lib.rs index a7a67ef76d4f..288531cb5b21 100644 --- a/src/liballoc_jemalloc/lib.rs +++ b/src/liballoc_jemalloc/lib.rs @@ -35,27 +35,33 @@ mod imp { // request it as unprefixing cause segfaults (mismatches in allocators). extern "C" { #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios", - target_os = "dragonfly", target_os = "windows"), + target_os = "dragonfly", target_os = "windows", target_env = "musl"), link_name = "je_mallocx")] fn mallocx(size: size_t, flags: c_int) -> *mut c_void; #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios", - target_os = "dragonfly", target_os = "windows"), + target_os = "dragonfly", target_os = "windows", target_env = "musl"), + link_name = "je_calloc")] + fn calloc(size: size_t, flags: c_int) -> *mut c_void; + #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios", + target_os = "dragonfly", target_os = "windows", target_env = "musl"), link_name = "je_rallocx")] fn rallocx(ptr: *mut c_void, size: size_t, flags: c_int) -> *mut c_void; #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios", - target_os = "dragonfly", target_os = "windows"), + target_os = "dragonfly", target_os = "windows", target_env = "musl"), link_name = "je_xallocx")] fn xallocx(ptr: *mut c_void, size: size_t, extra: size_t, flags: c_int) -> size_t; #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios", - target_os = "dragonfly", target_os = "windows"), + target_os = "dragonfly", target_os = "windows", target_env = "musl"), link_name = "je_sdallocx")] fn sdallocx(ptr: *mut c_void, size: size_t, flags: c_int); #[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios", - target_os = "dragonfly", target_os = "windows"), + target_os = "dragonfly", target_os = "windows", target_env = "musl"), link_name = "je_nallocx")] fn nallocx(size: size_t, flags: c_int) -> size_t; } + const MALLOCX_ZERO: c_int = 0x40; + // The minimum alignment guaranteed by the architecture. This value is used to // add fast paths for low alignment values. In practice, the alignment is a // constant at the call site and the branch will be optimized out. @@ -91,6 +97,16 @@ mod imp { unsafe { mallocx(size as size_t, flags) as *mut u8 } } + #[no_mangle] + pub extern "C" fn __rust_allocate_zeroed(size: usize, align: usize) -> *mut u8 { + if align <= MIN_ALIGN { + unsafe { calloc(size as size_t, 1) as *mut u8 } + } else { + let flags = align_to_flags(align) | MALLOCX_ZERO; + unsafe { mallocx(size as size_t, flags) as *mut u8 } + } + } + #[no_mangle] pub extern "C" fn __rust_reallocate(ptr: *mut u8, _old_size: usize, @@ -135,6 +151,11 @@ mod imp { bogus() } + #[no_mangle] + pub extern "C" fn __rust_allocate_zeroed(_size: usize, _align: usize) -> *mut u8 { + bogus() + } + #[no_mangle] pub extern "C" fn __rust_reallocate(_ptr: *mut u8, _old_size: usize, diff --git a/src/liballoc_system/lib.rs b/src/liballoc_system/lib.rs index de2b75f62b68..6d47c2ff28fb 100644 --- a/src/liballoc_system/lib.rs +++ b/src/liballoc_system/lib.rs @@ -44,6 +44,11 @@ pub extern "C" fn __rust_allocate(size: usize, align: usize) -> *mut u8 { unsafe { imp::allocate(size, align) } } +#[no_mangle] +pub extern "C" fn __rust_allocate_zeroed(size: usize, align: usize) -> *mut u8 { + unsafe { imp::allocate_zeroed(size, align) } +} + #[no_mangle] pub extern "C" fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize) { unsafe { imp::deallocate(ptr, old_size, align) } @@ -121,6 +126,18 @@ mod imp { } } + pub unsafe fn allocate_zeroed(size: usize, align: usize) -> *mut u8 { + if align <= MIN_ALIGN { + libc::calloc(size as libc::size_t, 1) as *mut u8 + } else { + let ptr = aligned_malloc(size, align); + if !ptr.is_null() { + ptr::write_bytes(ptr, 0, size); + } + ptr + } + } + pub unsafe fn reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usize) -> *mut u8 { if align <= MIN_ALIGN { libc::realloc(ptr as *mut libc::c_void, size as libc::size_t) as *mut u8 @@ -173,6 +190,8 @@ mod imp { #[repr(C)] struct Header(*mut u8); + + const HEAP_ZERO_MEMORY: DWORD = 0x00000008; const HEAP_REALLOC_IN_PLACE_ONLY: DWORD = 0x00000010; unsafe fn get_header<'a>(ptr: *mut u8) -> &'a mut Header { @@ -185,11 +204,12 @@ mod imp { aligned } - pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 { + #[inline] + unsafe fn allocate_with_flags(size: usize, align: usize, flags: DWORD) -> *mut u8 { if align <= MIN_ALIGN { - HeapAlloc(GetProcessHeap(), 0, size as SIZE_T) as *mut u8 + HeapAlloc(GetProcessHeap(), flags, size as SIZE_T) as *mut u8 } else { - let ptr = HeapAlloc(GetProcessHeap(), 0, (size + align) as SIZE_T) as *mut u8; + let ptr = HeapAlloc(GetProcessHeap(), flags, (size + align) as SIZE_T) as *mut u8; if ptr.is_null() { return ptr; } @@ -197,6 +217,14 @@ mod imp { } } + pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 { + allocate_with_flags(size, align, 0) + } + + pub unsafe fn allocate_zeroed(size: usize, align: usize) -> *mut u8 { + allocate_with_flags(size, align, HEAP_ZERO_MEMORY) + } + pub unsafe fn reallocate(ptr: *mut u8, _old_size: usize, size: usize, align: usize) -> *mut u8 { if align <= MIN_ALIGN { HeapReAlloc(GetProcessHeap(), 0, ptr as LPVOID, size as SIZE_T) as *mut u8 diff --git a/src/libcollections/Cargo.toml b/src/libcollections/Cargo.toml index 02b2171a224d..7e92404bc0d6 100644 --- a/src/libcollections/Cargo.toml +++ b/src/libcollections/Cargo.toml @@ -13,8 +13,8 @@ core = { path = "../libcore" } std_unicode = { path = "../libstd_unicode" } [[test]] -name = "collectionstest" -path = "../libcollectionstest/lib.rs" +name = "collectionstests" +path = "../libcollections/tests/lib.rs" [[bench]] name = "collectionsbenches" diff --git a/src/libcollections/binary_heap.rs b/src/libcollections/binary_heap.rs index efa96ca468e0..7d972403f65d 100644 --- a/src/libcollections/binary_heap.rs +++ b/src/libcollections/binary_heap.rs @@ -20,11 +20,12 @@ //! //! This is a larger example that implements [Dijkstra's algorithm][dijkstra] //! to solve the [shortest path problem][sssp] on a [directed graph][dir_graph]. -//! It shows how to use `BinaryHeap` with custom types. +//! It shows how to use [`BinaryHeap`] with custom types. //! //! [dijkstra]: http://en.wikipedia.org/wiki/Dijkstra%27s_algorithm //! [sssp]: http://en.wikipedia.org/wiki/Shortest_path_problem //! [dir_graph]: http://en.wikipedia.org/wiki/Directed_graph +//! [`BinaryHeap`]: struct.BinaryHeap.html //! //! ``` //! use std::cmp::Ordering; @@ -218,10 +219,14 @@ pub struct BinaryHeap { data: Vec, } -/// A container object that represents the result of the [`peek_mut`] method -/// on `BinaryHeap`. See its documentation for details. +/// Structure wrapping a mutable reference to the greatest item on a +/// `BinaryHeap`. +/// +/// This `struct` is created by the [`peek_mut`] method on [`BinaryHeap`]. See +/// its documentation for more. /// /// [`peek_mut`]: struct.BinaryHeap.html#method.peek_mut +/// [`BinaryHeap`]: struct.BinaryHeap.html #[stable(feature = "binary_heap_peek_mut", since = "1.12.0")] pub struct PeekMut<'a, T: 'a + Ord> { heap: &'a mut BinaryHeap, @@ -434,7 +439,7 @@ impl BinaryHeap { /// given `BinaryHeap`. 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 minimal. Prefer `reserve` if future + /// capacity can not be relied upon to be precisely minimal. Prefer [`reserve`] if future /// insertions are expected. /// /// # Panics @@ -452,6 +457,8 @@ impl BinaryHeap { /// assert!(heap.capacity() >= 100); /// heap.push(4); /// ``` + /// + /// [`reserve`]: #method.reserve #[stable(feature = "rust1", since = "1.0.0")] pub fn reserve_exact(&mut self, additional: usize) { self.data.reserve_exact(additional); @@ -548,82 +555,6 @@ impl BinaryHeap { self.sift_up(0, old_len); } - /// Pushes an item onto the binary heap, then pops the greatest item off the queue in - /// an optimized fashion. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// #![feature(binary_heap_extras)] - /// #![allow(deprecated)] - /// - /// use std::collections::BinaryHeap; - /// let mut heap = BinaryHeap::new(); - /// heap.push(1); - /// heap.push(5); - /// - /// assert_eq!(heap.push_pop(3), 5); - /// assert_eq!(heap.push_pop(9), 9); - /// assert_eq!(heap.len(), 2); - /// assert_eq!(heap.peek(), Some(&3)); - /// ``` - #[unstable(feature = "binary_heap_extras", - reason = "needs to be audited", - issue = "28147")] - #[rustc_deprecated(since = "1.13.0", reason = "use `peek_mut` instead")] - pub fn push_pop(&mut self, mut item: T) -> T { - match self.data.get_mut(0) { - None => return item, - Some(top) => { - if *top > item { - swap(&mut item, top); - } else { - return item; - } - } - } - - self.sift_down(0); - item - } - - /// Pops the greatest item off the binary heap, then pushes an item onto the queue in - /// an optimized fashion. The push is done regardless of whether the binary heap - /// was empty. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// #![feature(binary_heap_extras)] - /// #![allow(deprecated)] - /// - /// use std::collections::BinaryHeap; - /// let mut heap = BinaryHeap::new(); - /// - /// assert_eq!(heap.replace(1), None); - /// assert_eq!(heap.replace(3), Some(1)); - /// assert_eq!(heap.len(), 1); - /// assert_eq!(heap.peek(), Some(&3)); - /// ``` - #[unstable(feature = "binary_heap_extras", - reason = "needs to be audited", - issue = "28147")] - #[rustc_deprecated(since = "1.13.0", reason = "use `peek_mut` instead")] - pub fn replace(&mut self, mut item: T) -> Option { - if !self.is_empty() { - swap(&mut item, &mut self.data[0]); - self.sift_down(0); - Some(item) - } else { - self.push(item); - None - } - } - /// Consumes the `BinaryHeap` and returns the underlying vector /// in arbitrary order. /// @@ -971,7 +902,13 @@ impl<'a, T> Drop for Hole<'a, T> { } } -/// `BinaryHeap` iterator. +/// An iterator over the elements of a `BinaryHeap`. +/// +/// This `struct` is created by the [`iter`] method on [`BinaryHeap`]. See its +/// documentation for more. +/// +/// [`iter`]: struct.BinaryHeap.html#method.iter +/// [`BinaryHeap`]: struct.BinaryHeap.html #[stable(feature = "rust1", since = "1.0.0")] pub struct Iter<'a, T: 'a> { iter: slice::Iter<'a, T>, @@ -1027,7 +964,13 @@ impl<'a, T> ExactSizeIterator for Iter<'a, T> { #[unstable(feature = "fused", issue = "35602")] impl<'a, T> FusedIterator for Iter<'a, T> {} -/// An iterator that moves out of a `BinaryHeap`. +/// An owning iterator over the elements of a `BinaryHeap`. +/// +/// This `struct` is created by the [`into_iter`] method on [`BinaryHeap`][`BinaryHeap`] +/// (provided by the `IntoIterator` trait). See its documentation for more. +/// +/// [`into_iter`]: struct.BinaryHeap.html#method.into_iter +/// [`BinaryHeap`]: struct.BinaryHeap.html #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone)] pub struct IntoIter { @@ -1076,7 +1019,13 @@ impl ExactSizeIterator for IntoIter { #[unstable(feature = "fused", issue = "35602")] impl FusedIterator for IntoIter {} -/// An iterator that drains a `BinaryHeap`. +/// A draining iterator over the elements of a `BinaryHeap`. +/// +/// This `struct` is created by the [`drain`] method on [`BinaryHeap`]. See its +/// documentation for more. +/// +/// [`drain`]: struct.BinaryHeap.html#method.drain +/// [`BinaryHeap`]: struct.BinaryHeap.html #[stable(feature = "drain", since = "1.6.0")] #[derive(Debug)] pub struct Drain<'a, T: 'a> { diff --git a/src/libcollections/borrow.rs b/src/libcollections/borrow.rs index 65056121f05a..0de52b6696fc 100644 --- a/src/libcollections/borrow.rs +++ b/src/libcollections/borrow.rs @@ -60,6 +60,29 @@ pub trait ToOwned { /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn to_owned(&self) -> Self::Owned; + + /// Uses borrowed data to replace owned data, usually by cloning. + /// + /// This is borrow-generalized version of `Clone::clone_from`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(toowned_clone_into)] + /// let mut s: String = String::new(); + /// "hello".clone_into(&mut s); + /// + /// let mut v: Vec = Vec::new(); + /// [1, 2][..].clone_into(&mut v); + /// ``` + #[unstable(feature = "toowned_clone_into", + reason = "recently added", + issue = "41263")] + fn clone_into(&self, target: &mut Self::Owned) { + *target = self.to_owned(); + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -70,6 +93,10 @@ impl ToOwned for T fn to_owned(&self) -> T { self.clone() } + + fn clone_into(&self, target: &mut T) { + target.clone_from(self); + } } /// A clone-on-write smart pointer. @@ -141,6 +168,17 @@ impl<'a, B: ?Sized> Clone for Cow<'a, B> } } } + + fn clone_from(&mut self, source: &Cow<'a, B>) { + if let Owned(ref mut dest) = *self { + if let Owned(ref o) = *source { + o.borrow().clone_into(dest); + return; + } + } + + *self = source.clone(); + } } impl<'a, B: ?Sized> Cow<'a, B> diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs index dcacef4f0f0d..d73c0254a745 100644 --- a/src/libcollections/btree/map.rs +++ b/src/libcollections/btree/map.rs @@ -262,7 +262,13 @@ impl super::Recover for BTreeMap } } -/// An iterator over a BTreeMap's entries. +/// An iterator over the entries of a `BTreeMap`. +/// +/// This `struct` is created by the [`iter`] method on [`BTreeMap`]. See its +/// documentation for more. +/// +/// [`iter`]: struct.BTreeMap.html#method.iter +/// [`BTreeMap`]: struct.BTreeMap.html #[stable(feature = "rust1", since = "1.0.0")] pub struct Iter<'a, K: 'a, V: 'a> { range: Range<'a, K, V>, @@ -276,7 +282,13 @@ impl<'a, K: 'a + fmt::Debug, V: 'a + fmt::Debug> fmt::Debug for Iter<'a, K, V> { } } -/// A mutable iterator over a BTreeMap's entries. +/// A mutable iterator over the entries of a `BTreeMap`. +/// +/// This `struct` is created by the [`iter_mut`] method on [`BTreeMap`]. See its +/// documentation for more. +/// +/// [`iter_mut`]: struct.BTreeMap.html#method.iter_mut +/// [`BTreeMap`]: struct.BTreeMap.html #[stable(feature = "rust1", since = "1.0.0")] #[derive(Debug)] pub struct IterMut<'a, K: 'a, V: 'a> { @@ -284,7 +296,13 @@ pub struct IterMut<'a, K: 'a, V: 'a> { length: usize, } -/// An owning iterator over a BTreeMap's entries. +/// An owning iterator over the entries of a `BTreeMap`. +/// +/// This `struct` is created by the [`into_iter`] method on [`BTreeMap`][`BTreeMap`] +/// (provided by the `IntoIterator` trait). See its documentation for more. +/// +/// [`into_iter`]: struct.BTreeMap.html#method.into_iter +/// [`BTreeMap`]: struct.BTreeMap.html #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter { front: Handle, marker::Edge>, @@ -303,7 +321,13 @@ impl fmt::Debug for IntoIter { } } -/// An iterator over a BTreeMap's keys. +/// An iterator over the keys of a `BTreeMap`. +/// +/// This `struct` is created by the [`keys`] method on [`BTreeMap`]. See its +/// documentation for more. +/// +/// [`keys`]: struct.BTreeMap.html#method.keys +/// [`BTreeMap`]: struct.BTreeMap.html #[stable(feature = "rust1", since = "1.0.0")] pub struct Keys<'a, K: 'a, V: 'a> { inner: Iter<'a, K, V>, @@ -316,7 +340,13 @@ impl<'a, K: 'a + fmt::Debug, V: 'a + fmt::Debug> fmt::Debug for Keys<'a, K, V> { } } -/// An iterator over a BTreeMap's values. +/// An iterator over the values of a `BTreeMap`. +/// +/// This `struct` is created by the [`values`] method on [`BTreeMap`]. See its +/// documentation for more. +/// +/// [`values`]: struct.BTreeMap.html#method.values +/// [`BTreeMap`]: struct.BTreeMap.html #[stable(feature = "rust1", since = "1.0.0")] pub struct Values<'a, K: 'a, V: 'a> { inner: Iter<'a, K, V>, @@ -329,14 +359,26 @@ impl<'a, K: 'a + fmt::Debug, V: 'a + fmt::Debug> fmt::Debug for Values<'a, K, V> } } -/// A mutable iterator over a BTreeMap's values. +/// A mutable iterator over the values of a `BTreeMap`. +/// +/// This `struct` is created by the [`values_mut`] method on [`BTreeMap`]. See its +/// documentation for more. +/// +/// [`values_mut`]: struct.BTreeMap.html#method.values_mut +/// [`BTreeMap`]: struct.BTreeMap.html #[stable(feature = "map_values_mut", since = "1.10.0")] #[derive(Debug)] pub struct ValuesMut<'a, K: 'a, V: 'a> { inner: IterMut<'a, K, V>, } -/// An iterator over a sub-range of BTreeMap's entries. +/// An iterator over a sub-range of entries in a `BTreeMap`. +/// +/// This `struct` is created by the [`range`] method on [`BTreeMap`]. See its +/// documentation for more. +/// +/// [`range`]: struct.BTreeMap.html#method.range +/// [`BTreeMap`]: struct.BTreeMap.html #[stable(feature = "btree_range", since = "1.17.0")] pub struct Range<'a, K: 'a, V: 'a> { front: Handle, K, V, marker::Leaf>, marker::Edge>, @@ -350,7 +392,13 @@ impl<'a, K: 'a + fmt::Debug, V: 'a + fmt::Debug> fmt::Debug for Range<'a, K, V> } } -/// A mutable iterator over a sub-range of BTreeMap's entries. +/// A mutable iterator over a sub-range of entries in a `BTreeMap`. +/// +/// This `struct` is created by the [`range_mut`] method on [`BTreeMap`]. See its +/// documentation for more. +/// +/// [`range_mut`]: struct.BTreeMap.html#method.range_mut +/// [`BTreeMap`]: struct.BTreeMap.html #[stable(feature = "btree_range", since = "1.17.0")] pub struct RangeMut<'a, K: 'a, V: 'a> { front: Handle, K, V, marker::Leaf>, marker::Edge>, @@ -372,18 +420,19 @@ impl<'a, K: 'a + fmt::Debug, V: 'a + fmt::Debug> fmt::Debug for RangeMut<'a, K, } /// A view into a single entry in a map, which may either be vacant or occupied. -/// This enum is constructed from the [`entry`] method on [`BTreeMap`]. +/// +/// This `enum` is constructed from the [`entry`] method on [`BTreeMap`]. /// /// [`BTreeMap`]: struct.BTreeMap.html /// [`entry`]: struct.BTreeMap.html#method.entry #[stable(feature = "rust1", since = "1.0.0")] pub enum Entry<'a, K: 'a, V: 'a> { - /// A vacant Entry + /// A vacant entry. #[stable(feature = "rust1", since = "1.0.0")] Vacant(#[stable(feature = "rust1", since = "1.0.0")] VacantEntry<'a, K, V>), - /// An occupied Entry + /// An occupied entry. #[stable(feature = "rust1", since = "1.0.0")] Occupied(#[stable(feature = "rust1", since = "1.0.0")] OccupiedEntry<'a, K, V>), @@ -403,7 +452,8 @@ impl<'a, K: 'a + Debug + Ord, V: 'a + Debug> Debug for Entry<'a, K, V> { } } -/// A vacant Entry. It is part of the [`Entry`] enum. +/// A view into a vacant entry in a `BTreeMap`. +/// It is part of the [`Entry`] enum. /// /// [`Entry`]: enum.Entry.html #[stable(feature = "rust1", since = "1.0.0")] @@ -425,7 +475,8 @@ impl<'a, K: 'a + Debug + Ord, V: 'a> Debug for VacantEntry<'a, K, V> { } } -/// An occupied Entry. It is part of the [`Entry`] enum. +/// A view into an occupied entry in a `BTreeMap`. +/// It is part of the [`Entry`] enum. /// /// [`Entry`]: enum.Entry.html #[stable(feature = "rust1", since = "1.0.0")] @@ -1391,6 +1442,7 @@ impl<'a, K, V> Clone for Values<'a, K, V> { } } +#[stable(feature = "btree_range", since = "1.17.0")] impl<'a, K, V> Iterator for Range<'a, K, V> { type Item = (&'a K, &'a V); @@ -1466,6 +1518,7 @@ impl<'a, K, V> Range<'a, K, V> { } } +#[stable(feature = "btree_range", since = "1.17.0")] impl<'a, K, V> DoubleEndedIterator for Range<'a, K, V> { fn next_back(&mut self) -> Option<(&'a K, &'a V)> { if self.front == self.back { @@ -1511,6 +1564,7 @@ impl<'a, K, V> Range<'a, K, V> { #[unstable(feature = "fused", issue = "35602")] impl<'a, K, V> FusedIterator for Range<'a, 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> { Range { @@ -1520,6 +1574,7 @@ impl<'a, K, V> Clone for Range<'a, K, V> { } } +#[stable(feature = "btree_range", since = "1.17.0")] impl<'a, K, V> Iterator for RangeMut<'a, K, V> { type Item = (&'a K, &'a mut V); @@ -1564,6 +1619,7 @@ impl<'a, K, V> RangeMut<'a, K, V> { } } +#[stable(feature = "btree_range", since = "1.17.0")] impl<'a, K, V> DoubleEndedIterator for RangeMut<'a, K, V> { fn next_back(&mut self) -> Option<(&'a K, &'a mut V)> { if self.front == self.back { @@ -2161,13 +2217,6 @@ impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> { self.handle.reborrow().into_kv().0 } - /// Deprecated, renamed to `remove_entry` - #[unstable(feature = "map_entry_recover_keys", issue = "34285")] - #[rustc_deprecated(since = "1.12.0", reason = "renamed to `remove_entry`")] - pub fn remove_pair(self) -> (K, V) { - self.remove_entry() - } - /// Take ownership of the key and value from the map. /// /// # Examples diff --git a/src/libcollections/btree/set.rs b/src/libcollections/btree/set.rs index 9dbb61379379..d32460da9392 100644 --- a/src/libcollections/btree/set.rs +++ b/src/libcollections/btree/set.rs @@ -74,9 +74,10 @@ pub struct BTreeSet { map: BTreeMap, } -/// An iterator over a `BTreeSet`'s items. +/// An iterator over the items of a `BTreeSet`. /// -/// This structure is created by the [`iter`] method on [`BTreeSet`]. +/// This `struct` is created by the [`iter`] method on [`BTreeSet`]. +/// See its documentation for more. /// /// [`BTreeSet`]: struct.BTreeSet.html /// [`iter`]: struct.BTreeSet.html#method.iter @@ -94,21 +95,23 @@ impl<'a, T: 'a + fmt::Debug> fmt::Debug for Iter<'a, T> { } } -/// An owning iterator over a `BTreeSet`'s items. +/// An owning iterator over the items of a `BTreeSet`. /// -/// This structure is created by the `into_iter` method on [`BTreeSet`] -/// [`BTreeSet`] (provided by the `IntoIterator` trait). +/// This `struct` is created by the [`into_iter`] method on [`BTreeSet`][`BTreeSet`] +/// (provided by the `IntoIterator` trait). See its documentation for more. /// /// [`BTreeSet`]: struct.BTreeSet.html +/// [`into_iter`]: struct.BTreeSet.html#method.into_iter #[stable(feature = "rust1", since = "1.0.0")] #[derive(Debug)] pub struct IntoIter { iter: ::btree_map::IntoIter, } -/// An iterator over a sub-range of `BTreeSet`'s items. +/// An iterator over a sub-range of items in a `BTreeSet`. /// -/// This structure is created by the [`range`] method on [`BTreeSet`]. +/// This `struct` is created by the [`range`] method on [`BTreeSet`]. +/// See its documentation for more. /// /// [`BTreeSet`]: struct.BTreeSet.html /// [`range`]: struct.BTreeSet.html#method.range @@ -118,9 +121,10 @@ pub struct Range<'a, T: 'a> { iter: ::btree_map::Range<'a, T, ()>, } -/// A lazy iterator producing elements in the set difference (in-order). +/// A lazy iterator producing elements in the difference of `BTreeSet`s. /// -/// This structure is created by the [`difference`] method on [`BTreeSet`]. +/// This `struct` is created by the [`difference`] method on [`BTreeSet`]. +/// See its documentation for more. /// /// [`BTreeSet`]: struct.BTreeSet.html /// [`difference`]: struct.BTreeSet.html#method.difference @@ -134,15 +138,16 @@ pub struct Difference<'a, T: 'a> { impl<'a, T: 'a + fmt::Debug> fmt::Debug for Difference<'a, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("Difference") - .field(&self.clone()) + .field(&self.a) + .field(&self.b) .finish() } } -/// A lazy iterator producing elements in the set symmetric difference (in-order). +/// A lazy iterator producing elements in the symmetric difference of `BTreeSet`s. /// -/// This structure is created by the [`symmetric_difference`] method on -/// [`BTreeSet`]. +/// This `struct` is created by the [`symmetric_difference`] method on +/// [`BTreeSet`]. See its documentation for more. /// /// [`BTreeSet`]: struct.BTreeSet.html /// [`symmetric_difference`]: struct.BTreeSet.html#method.symmetric_difference @@ -156,14 +161,16 @@ pub struct SymmetricDifference<'a, T: 'a> { impl<'a, T: 'a + fmt::Debug> fmt::Debug for SymmetricDifference<'a, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("SymmetricDifference") - .field(&self.clone()) + .field(&self.a) + .field(&self.b) .finish() } } -/// A lazy iterator producing elements in the set intersection (in-order). +/// A lazy iterator producing elements in the intersection of `BTreeSet`s. /// -/// This structure is created by the [`intersection`] method on [`BTreeSet`]. +/// This `struct` is created by the [`intersection`] method on [`BTreeSet`]. +/// See its documentation for more. /// /// [`BTreeSet`]: struct.BTreeSet.html /// [`intersection`]: struct.BTreeSet.html#method.intersection @@ -177,14 +184,16 @@ pub struct Intersection<'a, T: 'a> { impl<'a, T: 'a + fmt::Debug> fmt::Debug for Intersection<'a, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("Intersection") - .field(&self.clone()) + .field(&self.a) + .field(&self.b) .finish() } } -/// A lazy iterator producing elements in the set union (in-order). +/// A lazy iterator producing elements in the union of `BTreeSet`s. /// -/// This structure is created by the [`union`] method on [`BTreeSet`]. +/// This `struct` is created by the [`union`] method on [`BTreeSet`]. +/// See its documentation for more. /// /// [`BTreeSet`]: struct.BTreeSet.html /// [`union`]: struct.BTreeSet.html#method.union @@ -198,7 +207,8 @@ pub struct Union<'a, T: 'a> { impl<'a, T: 'a + fmt::Debug> fmt::Debug for Union<'a, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("Union") - .field(&self.clone()) + .field(&self.a) + .field(&self.b) .finish() } } @@ -728,7 +738,7 @@ impl IntoIterator for BTreeSet { type Item = T; type IntoIter = IntoIter; - /// Gets an iterator for moving out the BtreeSet's contents. + /// Gets an iterator for moving out the `BTreeSet`'s contents. /// /// # Examples /// @@ -935,11 +945,14 @@ impl ExactSizeIterator for IntoIter { #[unstable(feature = "fused", issue = "35602")] 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> { Range { iter: self.iter.clone() } } } + +#[stable(feature = "btree_range", since = "1.17.0")] impl<'a, T> Iterator for Range<'a, T> { type Item = &'a T; @@ -947,6 +960,8 @@ impl<'a, T> Iterator for Range<'a, T> { self.iter.next().map(|(k, _)| k) } } + +#[stable(feature = "btree_range", since = "1.17.0")] impl<'a, T> DoubleEndedIterator for Range<'a, T> { fn next_back(&mut self) -> Option<&'a T> { self.iter.next_back().map(|(k, _)| k) diff --git a/src/libcollections/enum_set.rs b/src/libcollections/enum_set.rs deleted file mode 100644 index e56b94b2e1ea..000000000000 --- a/src/libcollections/enum_set.rs +++ /dev/null @@ -1,312 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! A structure for holding a set of enum variants. -//! -//! This module defines a container which uses an efficient bit mask -//! representation to hold C-like enum variants. - -#![unstable(feature = "enumset", - reason = "matches collection reform specification, \ - waiting for dust to settle", - issue = "37966")] -#![rustc_deprecated(since = "1.16.0", reason = "long since replaced")] -#![allow(deprecated)] - -use core::marker; -use core::fmt; -use core::iter::{FromIterator, FusedIterator}; -use core::ops::{Sub, BitOr, BitAnd, BitXor}; - -// FIXME(contentions): implement union family of methods? (general design may be -// wrong here) - -/// A specialized set implementation to use enum types. -/// -/// It is a logic error for an item to be modified in such a way that the -/// transformation of the item to or from a `usize`, as determined by the -/// `CLike` trait, changes while the item is in the set. This is normally only -/// possible through `Cell`, `RefCell`, global state, I/O, or unsafe code. -#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct EnumSet { - // We must maintain the invariant that no bits are set - // for which no variant exists - bits: usize, - marker: marker::PhantomData, -} - -impl Copy for EnumSet {} - -impl Clone for EnumSet { - fn clone(&self) -> EnumSet { - *self - } -} - -impl fmt::Debug for EnumSet { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - fmt.debug_set().entries(self).finish() - } -} - -/// An interface for casting C-like enum to usize and back. -/// A typically implementation is as below. -/// -/// ```{rust,ignore} -/// #[repr(usize)] -/// enum Foo { -/// A, B, C -/// } -/// -/// impl CLike for Foo { -/// fn to_usize(&self) -> usize { -/// *self as usize -/// } -/// -/// fn from_usize(v: usize) -> Foo { -/// unsafe { mem::transmute(v) } -/// } -/// } -/// ``` -pub trait CLike { - /// Converts a C-like enum to a `usize`. - fn to_usize(&self) -> usize; - /// Converts a `usize` to a C-like enum. - fn from_usize(usize) -> Self; -} - -fn bit(e: &E) -> usize { - use core::mem; - let value = e.to_usize(); - let bits = mem::size_of::() * 8; - assert!(value < bits, - "EnumSet only supports up to {} variants.", - bits - 1); - 1 << value -} - -impl EnumSet { - /// Returns an empty `EnumSet`. - pub fn new() -> EnumSet { - EnumSet { - bits: 0, - marker: marker::PhantomData, - } - } - - /// Returns the number of elements in the given `EnumSet`. - pub fn len(&self) -> usize { - self.bits.count_ones() as usize - } - - /// Returns `true` if the `EnumSet` is empty. - pub fn is_empty(&self) -> bool { - self.bits == 0 - } - - pub fn clear(&mut self) { - self.bits = 0; - } - - /// Returns `false` if the `EnumSet` contains any enum of the given `EnumSet`. - pub fn is_disjoint(&self, other: &EnumSet) -> bool { - (self.bits & other.bits) == 0 - } - - /// Returns `true` if a given `EnumSet` is included in this `EnumSet`. - pub fn is_superset(&self, other: &EnumSet) -> bool { - (self.bits & other.bits) == other.bits - } - - /// Returns `true` if this `EnumSet` is included in the given `EnumSet`. - pub fn is_subset(&self, other: &EnumSet) -> bool { - other.is_superset(self) - } - - /// Returns the union of both `EnumSets`. - pub fn union(&self, e: EnumSet) -> EnumSet { - EnumSet { - bits: self.bits | e.bits, - marker: marker::PhantomData, - } - } - - /// Returns the intersection of both `EnumSets`. - pub fn intersection(&self, e: EnumSet) -> EnumSet { - EnumSet { - bits: self.bits & e.bits, - marker: marker::PhantomData, - } - } - - /// Adds an enum to the `EnumSet`, and returns `true` if it wasn't there before - pub fn insert(&mut self, e: E) -> bool { - let result = !self.contains(&e); - self.bits |= bit(&e); - result - } - - /// Removes an enum from the EnumSet - pub fn remove(&mut self, e: &E) -> bool { - let result = self.contains(e); - self.bits &= !bit(e); - result - } - - /// Returns `true` if an `EnumSet` contains a given enum. - pub fn contains(&self, e: &E) -> bool { - (self.bits & bit(e)) != 0 - } - - /// Returns an iterator over an `EnumSet`. - pub fn iter(&self) -> Iter { - Iter::new(self.bits) - } -} - -impl Sub for EnumSet { - type Output = EnumSet; - - fn sub(self, e: EnumSet) -> EnumSet { - EnumSet { - bits: self.bits & !e.bits, - marker: marker::PhantomData, - } - } -} - -impl BitOr for EnumSet { - type Output = EnumSet; - - fn bitor(self, e: EnumSet) -> EnumSet { - EnumSet { - bits: self.bits | e.bits, - marker: marker::PhantomData, - } - } -} - -impl BitAnd for EnumSet { - type Output = EnumSet; - - fn bitand(self, e: EnumSet) -> EnumSet { - EnumSet { - bits: self.bits & e.bits, - marker: marker::PhantomData, - } - } -} - -impl BitXor for EnumSet { - type Output = EnumSet; - - fn bitxor(self, e: EnumSet) -> EnumSet { - EnumSet { - bits: self.bits ^ e.bits, - marker: marker::PhantomData, - } - } -} - -/// An iterator over an EnumSet -pub struct Iter { - index: usize, - bits: usize, - marker: marker::PhantomData, -} - -impl fmt::Debug for Iter { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_tuple("Iter") - .field(&self.clone()) - .finish() - } -} - -// FIXME(#19839) Remove in favor of `#[derive(Clone)]` -impl Clone for Iter { - fn clone(&self) -> Iter { - Iter { - index: self.index, - bits: self.bits, - marker: marker::PhantomData, - } - } -} - -impl Iter { - fn new(bits: usize) -> Iter { - Iter { - index: 0, - bits: bits, - marker: marker::PhantomData, - } - } -} - -impl Iterator for Iter { - type Item = E; - - fn next(&mut self) -> Option { - if self.bits == 0 { - return None; - } - - while (self.bits & 1) == 0 { - self.index += 1; - self.bits >>= 1; - } - let elem = CLike::from_usize(self.index); - self.index += 1; - self.bits >>= 1; - Some(elem) - } - - fn size_hint(&self) -> (usize, Option) { - let exact = self.bits.count_ones() as usize; - (exact, Some(exact)) - } -} - -#[unstable(feature = "fused", issue = "35602")] -impl FusedIterator for Iter {} - -impl FromIterator for EnumSet { - fn from_iter>(iter: I) -> EnumSet { - let mut ret = EnumSet::new(); - ret.extend(iter); - ret - } -} - -impl<'a, E> IntoIterator for &'a EnumSet - where E: CLike -{ - type Item = E; - type IntoIter = Iter; - - fn into_iter(self) -> Iter { - self.iter() - } -} - -impl Extend for EnumSet { - fn extend>(&mut self, iter: I) { - for element in iter { - self.insert(element); - } - } -} - -impl<'a, E: 'a + CLike + Copy> Extend<&'a E> for EnumSet { - fn extend>(&mut self, iter: I) { - self.extend(iter.into_iter().cloned()); - } -} diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 72e950bc91fa..842f2f44fff9 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -10,8 +10,8 @@ //! Collection types. //! -//! See [std::collections](../std/collections/index.html) for a detailed discussion of -//! collections in Rust. +//! See [`std::collections`](../std/collections/index.html) for a detailed +//! discussion of collections in Rust. #![crate_name = "collections"] #![crate_type = "rlib"] @@ -35,6 +35,7 @@ #![feature(box_patterns)] #![feature(box_syntax)] #![cfg_attr(not(test), feature(char_escape_debug))] +#![cfg_attr(not(test), feature(core_float))] #![feature(core_intrinsics)] #![feature(dropck_eyepatch)] #![feature(exact_size_is_empty)] @@ -42,8 +43,10 @@ #![feature(fused)] #![feature(generic_param_attrs)] #![feature(heap_api)] +#![feature(i128_type)] #![feature(inclusive_range)] #![feature(lang_items)] +#![feature(manually_drop)] #![feature(nonzero)] #![feature(pattern)] #![feature(placement_in)] @@ -52,15 +55,20 @@ #![feature(shared)] #![feature(slice_get_slice)] #![feature(slice_patterns)] +#![feature(slice_rsplit)] #![cfg_attr(not(test), feature(sort_unstable))] #![feature(specialization)] #![feature(staged_api)] #![feature(str_internals)] +#![feature(str_box_extras)] +#![feature(str_mut_extras)] #![feature(trusted_len)] #![feature(unicode)] #![feature(unique)] #![feature(untagged_unions)] +#![cfg_attr(not(test), feature(str_checked_slicing))] #![cfg_attr(test, feature(rand, test))] +#![feature(offset_to)] #![no_std] @@ -82,9 +90,6 @@ pub use btree_set::BTreeSet; #[doc(no_inline)] pub use linked_list::LinkedList; #[doc(no_inline)] -#[allow(deprecated)] -pub use enum_set::EnumSet; -#[doc(no_inline)] pub use vec_deque::VecDeque; #[doc(no_inline)] pub use string::String; @@ -100,7 +105,6 @@ mod macros; pub mod binary_heap; mod btree; pub mod borrow; -pub mod enum_set; pub mod fmt; pub mod linked_list; pub mod range; @@ -130,6 +134,42 @@ mod std { } /// An endpoint of a range of keys. +/// +/// # Examples +/// +/// `Bound`s are range endpoints: +/// +/// ``` +/// #![feature(collections_range)] +/// +/// use std::collections::range::RangeArgument; +/// use std::collections::Bound::*; +/// +/// assert_eq!((..100).start(), Unbounded); +/// assert_eq!((1..12).start(), Included(&1)); +/// assert_eq!((1..12).end(), Excluded(&12)); +/// ``` +/// +/// Using a tuple of `Bound`s as an argument to [`BTreeMap::range`]. +/// Note that in most cases, it's better to use range syntax (`1..5`) instead. +/// +/// ``` +/// use std::collections::BTreeMap; +/// use std::collections::Bound::{Excluded, Included, Unbounded}; +/// +/// let mut map = BTreeMap::new(); +/// map.insert(3, "a"); +/// map.insert(5, "b"); +/// map.insert(8, "c"); +/// +/// for (key, value) in map.range((Excluded(3), Included(8))) { +/// println!("{}: {}", key, value); +/// } +/// +/// assert_eq!(Some((&3, &"a")), map.range((Unbounded, Included(5))).next()); +/// ``` +/// +/// [`BTreeMap::range`]: btree_map/struct.BTreeMap.html#method.range #[stable(feature = "collections_bound", since = "1.17.0")] #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)] pub enum Bound { diff --git a/src/libcollections/linked_list.rs b/src/libcollections/linked_list.rs index f58c87b801f5..adfd91bec489 100644 --- a/src/libcollections/linked_list.rs +++ b/src/libcollections/linked_list.rs @@ -56,7 +56,13 @@ struct Node { element: T, } -/// An iterator over references to the elements of a `LinkedList`. +/// An iterator over the elements of a `LinkedList`. +/// +/// This `struct` is created by the [`iter`] method on [`LinkedList`]. See its +/// documentation for more. +/// +/// [`iter`]: struct.LinkedList.html#method.iter +/// [`LinkedList`]: struct.LinkedList.html #[stable(feature = "rust1", since = "1.0.0")] pub struct Iter<'a, T: 'a> { head: Option>>, @@ -69,7 +75,7 @@ pub struct Iter<'a, T: 'a> { impl<'a, T: 'a + fmt::Debug> fmt::Debug for Iter<'a, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("Iter") - .field(&self.clone()) + .field(&self.len) .finish() } } @@ -82,7 +88,13 @@ impl<'a, T> Clone for Iter<'a, T> { } } -/// An iterator over mutable references to the elements of a `LinkedList`. +/// A mutable iterator over the elements of a `LinkedList`. +/// +/// This `struct` is created by the [`iter_mut`] method on [`LinkedList`]. See its +/// documentation for more. +/// +/// [`iter_mut`]: struct.LinkedList.html#method.iter_mut +/// [`LinkedList`]: struct.LinkedList.html #[stable(feature = "rust1", since = "1.0.0")] pub struct IterMut<'a, T: 'a> { list: &'a mut LinkedList, @@ -95,12 +107,19 @@ pub struct IterMut<'a, T: 'a> { impl<'a, T: 'a + fmt::Debug> fmt::Debug for IterMut<'a, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("IterMut") - .field(self.clone()) + .field(&self.list) + .field(&self.len) .finish() } } -/// An iterator over the elements of a `LinkedList`. +/// An owning iterator over the elements of a `LinkedList`. +/// +/// This `struct` is created by the [`into_iter`] method on [`LinkedList`][`LinkedList`] +/// (provided by the `IntoIterator` trait). See its documentation for more. +/// +/// [`into_iter`]: struct.LinkedList.html#method.into_iter +/// [`LinkedList`]: struct.LinkedList.html #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter { @@ -111,7 +130,7 @@ pub struct IntoIter { impl fmt::Debug for IntoIter { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("IntoIter") - .field(self.clone()) + .field(&self.list) .finish() } } @@ -618,12 +637,12 @@ impl LinkedList { /// Splits the list into two at the given index. Returns everything after the given index, /// including the index. /// + /// This operation should compute in O(n) time. + /// /// # Panics /// /// Panics if `at > len`. /// - /// This operation should compute in O(n) time. - /// /// # Examples /// /// ``` @@ -697,8 +716,8 @@ impl LinkedList { /// Returns a place for insertion at the front of the list. /// - /// Using this method with placement syntax is equivalent to [`push_front`] - /// (#method.push_front), but may be more efficient. + /// Using this method with placement syntax is equivalent to + /// [`push_front`](#method.push_front), but may be more efficient. /// /// # Examples /// @@ -1110,7 +1129,7 @@ pub struct FrontPlace<'a, T: 'a> { impl<'a, T: 'a + fmt::Debug> fmt::Debug for FrontPlace<'a, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("FrontPlace") - .field(self.clone()) + .field(&self.list) .finish() } } @@ -1165,7 +1184,7 @@ pub struct BackPlace<'a, T: 'a> { impl<'a, T: 'a + fmt::Debug> fmt::Debug for BackPlace<'a, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("BackPlace") - .field(self.clone()) + .field(&self.list) .finish() } } @@ -1376,7 +1395,7 @@ mod tests { thread::spawn(move || { check_links(&n); let a: &[_] = &[&1, &2, &3]; - assert_eq!(a, &n.iter().collect::>()[..]); + assert_eq!(a, &*n.iter().collect::>()); }) .join() .ok() diff --git a/src/libcollections/range.rs b/src/libcollections/range.rs index 06d89a6a70b4..8f3209d015b1 100644 --- a/src/libcollections/range.rs +++ b/src/libcollections/range.rs @@ -17,7 +17,7 @@ use core::ops::{RangeFull, Range, RangeTo, RangeFrom, RangeInclusive, RangeToInclusive}; use Bound::{self, Excluded, Included, Unbounded}; -/// **RangeArgument** is implemented by Rust's built-in range types, produced +/// `RangeArgument` is implemented by Rust's built-in range types, produced /// by range syntax like `..`, `a..`, `..b` or `c..d`. pub trait RangeArgument { /// Start index bound. diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index f7451f574ffa..2eef132374e5 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -115,6 +115,8 @@ pub use core::slice::{Iter, IterMut}; pub use core::slice::{SplitMut, ChunksMut, Split}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::slice::{SplitN, RSplitN, SplitNMut, RSplitNMut}; +#[unstable(feature = "slice_rsplit", issue = "41020")] +pub use core::slice::{RSplit, RSplitMut}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::slice::{from_raw_parts, from_raw_parts_mut}; #[unstable(feature = "slice_get_slice", issue = "35729")] @@ -362,7 +364,7 @@ impl [T] { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn get(&self, index: I) -> Option<&I::Output> - where I: SliceIndex + where I: SliceIndex { core_slice::SliceExt::get(self, index) } @@ -385,7 +387,7 @@ impl [T] { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn get_mut(&mut self, index: I) -> Option<&mut I::Output> - where I: SliceIndex + where I: SliceIndex { core_slice::SliceExt::get_mut(self, index) } @@ -405,7 +407,7 @@ impl [T] { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub unsafe fn get_unchecked(&self, index: I) -> &I::Output - where I: SliceIndex + where I: SliceIndex { core_slice::SliceExt::get_unchecked(self, index) } @@ -427,7 +429,7 @@ impl [T] { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub unsafe fn get_unchecked_mut(&mut self, index: I) -> &mut I::Output - where I: SliceIndex + where I: SliceIndex { core_slice::SliceExt::get_unchecked_mut(self, index) } @@ -779,6 +781,72 @@ impl [T] { core_slice::SliceExt::split_mut(self, pred) } + /// Returns an iterator over subslices separated by elements that match + /// `pred`, starting at the end of the slice and working backwards. + /// The matched element is not contained in the subslices. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_rsplit)] + /// + /// let slice = [11, 22, 33, 0, 44, 55]; + /// let mut iter = slice.rsplit(|num| *num == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[44, 55]); + /// assert_eq!(iter.next().unwrap(), &[11, 22, 33]); + /// assert_eq!(iter.next(), None); + /// ``` + /// + /// As with `split()`, if the first or last element is matched, an empty + /// slice will be the first (or last) item returned by the iterator. + /// + /// ``` + /// #![feature(slice_rsplit)] + /// + /// let v = &[0, 1, 1, 2, 3, 5, 8]; + /// let mut it = v.rsplit(|n| *n % 2 == 0); + /// assert_eq!(it.next().unwrap(), &[]); + /// assert_eq!(it.next().unwrap(), &[3, 5]); + /// assert_eq!(it.next().unwrap(), &[1, 1]); + /// assert_eq!(it.next().unwrap(), &[]); + /// assert_eq!(it.next(), None); + /// ``` + #[unstable(feature = "slice_rsplit", issue = "41020")] + #[inline] + pub fn rsplit(&self, pred: F) -> RSplit + where F: FnMut(&T) -> bool + { + core_slice::SliceExt::rsplit(self, pred) + } + + /// Returns an iterator over mutable subslices separated by elements that + /// match `pred`, starting at the end of the slice and working + /// backwards. The matched element is not contained in the subslices. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_rsplit)] + /// + /// let mut v = [100, 400, 300, 200, 600, 500]; + /// + /// let mut count = 0; + /// for group in v.rsplit_mut(|num| *num % 3 == 0) { + /// count += 1; + /// group[0] = count; + /// } + /// assert_eq!(v, [3, 400, 300, 2, 600, 1]); + /// ``` + /// + #[unstable(feature = "slice_rsplit", issue = "41020")] + #[inline] + pub fn rsplit_mut(&mut self, pred: F) -> RSplitMut + where F: FnMut(&T) -> bool + { + core_slice::SliceExt::rsplit_mut(self, pred) + } + /// Returns an iterator over subslices separated by elements that match /// `pred`, limited to returning at most `n` items. The matched element is /// not contained in the subslices. @@ -1451,13 +1519,22 @@ impl ToOwned for [T] { self.to_vec() } - // HACK(japaric): with cfg(test) the inherent `[T]::to_vec`, which is required for this method - // definition, is not available. Since we don't require this method for testing purposes, I'll - // just stub it - // NB see the slice::hack module in slice.rs for more information #[cfg(test)] fn to_owned(&self) -> Vec { - panic!("not available with cfg(test)") + hack::to_vec(self) + } + + fn clone_into(&self, target: &mut Vec) { + // drop anything in target that will not be overwritten + target.truncate(self.len()); + let len = target.len(); + + // reuse the contained values' allocations/resources. + target.clone_from_slice(&self[..len]); + + // target.len <= self.len due to the truncate above, so the + // slice here is always in-bounds. + target.extend_from_slice(&self[len..]); } } @@ -1490,7 +1567,7 @@ fn insert_head(v: &mut [T], is_less: &mut F) // performance than with the 2nd method. // // All methods were benchmarked, and the 3rd showed best results. So we chose that one. - let mut tmp = NoDrop { value: ptr::read(&v[0]) }; + let mut tmp = mem::ManuallyDrop::new(ptr::read(&v[0])); // Intermediate state of the insertion process is always tracked by `hole`, which // serves two purposes: @@ -1503,13 +1580,13 @@ fn insert_head(v: &mut [T], is_less: &mut F) // fill the hole in `v` with `tmp`, thus ensuring that `v` still holds every object it // initially held exactly once. let mut hole = InsertionHole { - src: &mut tmp.value, + src: &mut *tmp, dest: &mut v[1], }; ptr::copy_nonoverlapping(&v[1], &mut v[0], 1); for i in 2..v.len() { - if !is_less(&v[i], &tmp.value) { + if !is_less(&v[i], &*tmp) { break; } ptr::copy_nonoverlapping(&v[i], &mut v[i - 1], 1); @@ -1519,12 +1596,6 @@ fn insert_head(v: &mut [T], is_less: &mut F) } } - // Holds a value, but never drops it. - #[allow(unions_with_drop_fields)] - union NoDrop { - value: T - } - // When dropped, copies from `src` into `dest`. struct InsertionHole { src: *mut T, diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index 8abc9ca7e9fe..964660183e75 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -10,9 +10,28 @@ //! Unicode string slices. //! +//! The `&str` type is one of the two main string types, the other being `String`. +//! Unlike its `String` counterpart, its contents are borrowed. +//! +//! # Basic Usage +//! +//! A basic string declaration of `&str` type: +//! +//! ``` +//! let hello_world = "Hello, World!"; +//! ``` +//! +//! Here we have declared a string literal, also known as a string slice. +//! String literals have a static lifetime, which means the string `hello_world` +//! is guaranteed to be valid for the duration of the entire program. +//! We can explicitly specify `hello_world`'s lifetime as well: +//! +//! ``` +//! let hello_world: &'static str = "Hello, world!"; +//! ``` +//! //! *[See also the `str` primitive type](../../std/primitive.str.html).* - #![stable(feature = "rust1", since = "1.0.0")] // Many of the usings in this module are only used in the test configuration. @@ -32,7 +51,7 @@ use borrow::{Borrow, ToOwned}; use string::String; use std_unicode; use vec::Vec; -use slice::SliceConcatExt; +use slice::{SliceConcatExt, SliceIndex}; use boxed::Box; #[stable(feature = "rust1", since = "1.0.0")] @@ -51,14 +70,17 @@ pub use core::str::{Matches, RMatches}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::str::{MatchIndices, RMatchIndices}; #[stable(feature = "rust1", since = "1.0.0")] -pub use core::str::{from_utf8, Chars, CharIndices, Bytes}; +pub use core::str::{from_utf8, from_utf8_mut, Chars, CharIndices, Bytes}; #[stable(feature = "rust1", since = "1.0.0")] -pub use core::str::{from_utf8_unchecked, ParseBoolError}; +pub use core::str::{from_utf8_unchecked, from_utf8_unchecked_mut, ParseBoolError}; +#[unstable(feature = "str_box_extras", issue = "41119")] +pub use alloc::str::from_boxed_utf8_unchecked; #[stable(feature = "rust1", since = "1.0.0")] pub use std_unicode::str::SplitWhitespace; #[stable(feature = "rust1", since = "1.0.0")] pub use core::str::pattern; + #[unstable(feature = "slice_concat_ext", reason = "trait should not have to exist", issue = "27747")] @@ -114,9 +136,15 @@ impl> SliceConcatExt for [S] { } } -/// External iterator for a string's UTF-16 code units. +/// An iterator of [`u16`] over the string encoded as UTF-16. /// -/// For use with the `std::iter` module. +/// [`u16`]: ../../std/primitive.u16.html +/// +/// This struct is created by the [`encode_utf16`] method on [`str`]. +/// See its documentation for more. +/// +/// [`encode_utf16`]: ../../std/primitive.str.html#method.encode_utf16 +/// [`str`]: ../../std/primitive.str.html #[derive(Clone)] #[stable(feature = "encode_utf16", since = "1.8.0")] pub struct EncodeUtf16<'a> { @@ -174,6 +202,12 @@ impl ToOwned for str { fn to_owned(&self) -> String { unsafe { String::from_utf8_unchecked(self.as_bytes().to_owned()) } } + + fn clone_into(&self, target: &mut String) { + let mut b = mem::replace(target, String::new()).into_bytes(); + self.as_bytes().clone_into(&mut b); + *target = unsafe { String::from_utf8_unchecked(b) } + } } /// Methods for string slices. @@ -269,6 +303,13 @@ impl str { core_str::StrExt::as_bytes(self) } + /// Converts a mutable string slice to a mutable byte slice. + #[unstable(feature = "str_mut_extras", issue = "41119")] + #[inline(always)] + pub unsafe fn as_bytes_mut(&mut self) -> &mut [u8] { + core_str::StrExt::as_bytes_mut(self) + } + /// Converts a string slice to a raw pointer. /// /// As string slices are a slice of bytes, the raw pointer points to a @@ -291,6 +332,118 @@ impl str { core_str::StrExt::as_ptr(self) } + /// Returns a subslice of `str`. + /// + /// This is the non-panicking alternative to indexing the `str`. Returns + /// [`None`] whenever equivalent indexing operation would panic. + /// + /// [`None`]: option/enum.Option.html#variant.None + /// + /// # Examples + /// + /// ``` + /// # #![feature(str_checked_slicing)] + /// let v = "🗻∈🌏"; + /// assert_eq!(Some("🗻"), v.get(0..4)); + /// assert!(v.get(1..).is_none()); + /// assert!(v.get(..8).is_none()); + /// assert!(v.get(..42).is_none()); + /// ``` + #[unstable(feature = "str_checked_slicing", issue = "39932")] + #[inline] + pub fn get>(&self, i: I) -> Option<&I::Output> { + core_str::StrExt::get(self, i) + } + + /// Returns a mutable subslice of `str`. + /// + /// This is the non-panicking alternative to indexing the `str`. Returns + /// [`None`] whenever equivalent indexing operation would panic. + /// + /// [`None`]: option/enum.Option.html#variant.None + /// + /// # Examples + /// + /// ``` + /// # #![feature(str_checked_slicing)] + /// let mut v = String::from("🗻∈🌏"); + /// assert_eq!(Some("🗻"), v.get_mut(0..4).map(|v| &*v)); + /// assert!(v.get_mut(1..).is_none()); + /// assert!(v.get_mut(..8).is_none()); + /// assert!(v.get_mut(..42).is_none()); + /// ``` + #[unstable(feature = "str_checked_slicing", issue = "39932")] + #[inline] + pub fn get_mut>(&mut self, i: I) -> Option<&mut I::Output> { + core_str::StrExt::get_mut(self, i) + } + + /// Returns a unchecked subslice of `str`. + /// + /// This is the unchecked alternative to indexing the `str`. + /// + /// # Safety + /// + /// Callers of this function are responsible that these preconditions are + /// satisfied: + /// + /// * The starting index must come before the ending index; + /// * Indexes must be within bounds of the original slice; + /// * Indexes must lie on UTF-8 sequence boundaries. + /// + /// Failing that, the returned string slice may reference invalid memory or + /// violate the invariants communicated by the `str` type. + /// + /// # Examples + /// + /// ``` + /// # #![feature(str_checked_slicing)] + /// let v = "🗻∈🌏"; + /// unsafe { + /// assert_eq!("🗻", v.get_unchecked(0..4)); + /// assert_eq!("∈", v.get_unchecked(4..7)); + /// assert_eq!("🌏", v.get_unchecked(7..11)); + /// } + /// ``` + #[unstable(feature = "str_checked_slicing", issue = "39932")] + #[inline] + pub unsafe fn get_unchecked>(&self, i: I) -> &I::Output { + core_str::StrExt::get_unchecked(self, i) + } + + /// Returns a mutable, unchecked subslice of `str`. + /// + /// This is the unchecked alternative to indexing the `str`. + /// + /// # Safety + /// + /// Callers of this function are responsible that these preconditions are + /// satisfied: + /// + /// * The starting index must come before the ending index; + /// * Indexes must be within bounds of the original slice; + /// * Indexes must lie on UTF-8 sequence boundaries. + /// + /// Failing that, the returned string slice may reference invalid memory or + /// violate the invariants communicated by the `str` type. + /// + /// # Examples + /// + /// ``` + /// # #![feature(str_checked_slicing)] + /// let mut v = String::from("🗻∈🌏"); + /// unsafe { + /// assert_eq!("🗻", v.get_unchecked_mut(0..4)); + /// assert_eq!("∈", v.get_unchecked_mut(4..7)); + /// assert_eq!("🌏", v.get_unchecked_mut(7..11)); + /// } + /// ``` + #[unstable(feature = "str_checked_slicing", issue = "39932")] + #[inline] + pub unsafe fn get_unchecked_mut>(&mut self, i: I) -> &mut I::Output { + core_str::StrExt::get_unchecked_mut(self, i) + } + /// Creates a string slice from another string slice, bypassing safety /// checks. /// @@ -430,7 +583,7 @@ impl str { core_str::StrExt::split_at_mut(self, mid) } - /// Returns an iterator over the `char`s of a string slice. + /// Returns an iterator over the [`char`]s of a string slice. /// /// As a string slice consists of valid UTF-8, we can iterate through a /// string slice by [`char`]. This method returns such an iterator. @@ -1517,13 +1670,13 @@ impl str { /// Parses this string slice into another type. /// - /// Because `parse()` is so general, it can cause problems with type - /// inference. As such, `parse()` is one of the few times you'll see + /// Because `parse` is so general, it can cause problems with type + /// inference. As such, `parse` is one of the few times you'll see /// the syntax affectionately known as the 'turbofish': `::<>`. This /// helps the inference algorithm understand specifically which type /// you're trying to parse into. /// - /// `parse()` can parse any type that implements the [`FromStr`] trait. + /// `parse` can parse any type that implements the [`FromStr`] trait. /// /// [`FromStr`]: str/trait.FromStr.html /// @@ -1565,6 +1718,12 @@ impl str { core_str::StrExt::parse(self) } + /// Converts a `Box` into a `Box<[u8]>` without copying or allocating. + #[unstable(feature = "str_box_extras", issue = "41119")] + pub fn into_boxed_bytes(self: Box) -> Box<[u8]> { + self.into() + } + /// Replaces all matches of a pattern with another string. /// /// `replace` creates a new [`String`], and copies the data from this string slice into it. @@ -1606,7 +1765,7 @@ impl str { /// /// `replacen` creates a new [`String`], and copies the data from this string slice into it. /// While doing so, it attempts to find matches of a pattern. If it finds any, it - /// replaces them with the replacement string slice at most `N` times. + /// replaces them with the replacement string slice at most `count` times. /// /// [`String`]: string/struct.String.html /// @@ -1752,7 +1911,9 @@ impl str { return s; } - /// Escapes each char in `s` with `char::escape_debug`. + /// Escapes each char in `s` with [`char::escape_debug`]. + /// + /// [`char::escape_debug`]: primitive.char.html#method.escape_debug #[unstable(feature = "str_escape", reason = "return type may change to be an iterator", issue = "27791")] @@ -1760,7 +1921,9 @@ impl str { self.chars().flat_map(|c| c.escape_debug()).collect() } - /// Escapes each char in `s` with `char::escape_default`. + /// 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")] @@ -1768,7 +1931,9 @@ impl str { self.chars().flat_map(|c| c.escape_default()).collect() } - /// Escapes each char in `s` with `char::escape_unicode`. + /// 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")] @@ -1776,9 +1941,10 @@ impl str { self.chars().flat_map(|c| c.escape_unicode()).collect() } - /// Converts a `Box` into a [`String`] without copying or allocating. + /// Converts a [`Box`] into a [`String`] without copying or allocating. /// /// [`String`]: string/struct.String.html + /// [`Box`]: boxed/struct.Box.html /// /// # Examples /// diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index 0ee4c8b8e95a..31ab04e9f3b7 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -56,10 +56,11 @@ #![stable(feature = "rust1", since = "1.0.0")] +use alloc::str as alloc_str; + use core::fmt; use core::hash; use core::iter::{FromIterator, FusedIterator}; -use core::mem; use core::ops::{self, Add, AddAssign, Index, IndexMut}; use core::ptr; use core::str as core_str; @@ -1316,7 +1317,7 @@ impl String { self.vec.clear() } - /// Create a draining iterator that removes the specified range in the string + /// Creates a draining iterator that removes the specified range in the string /// and yields the removed chars. /// /// Note: The element range is removed even if the iterator is not @@ -1382,6 +1383,71 @@ impl String { } } + /// Creates a splicing iterator that removes the specified range in the string, + /// replaces with the given string, and yields the removed chars. + /// The given string doesn’t need to be the same length as the range. + /// + /// Note: The element range is removed when the `Splice` is dropped, + /// even if the iterator is not consumed until the end. + /// + /// # Panics + /// + /// Panics if the starting point or end point do not lie on a [`char`] + /// boundary, or if they're out of bounds. + /// + /// [`char`]: ../../std/primitive.char.html + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(splice)] + /// let mut s = String::from("α is alpha, β is beta"); + /// let beta_offset = s.find('β').unwrap_or(s.len()); + /// + /// // Replace the range up until the β from the string + /// let t: String = s.splice(..beta_offset, "Α is capital alpha; ").collect(); + /// assert_eq!(t, "α is alpha, "); + /// assert_eq!(s, "Α is capital alpha; β is beta"); + /// ``` + #[unstable(feature = "splice", reason = "recently added", issue = "32310")] + pub fn splice<'a, 'b, R>(&'a mut self, range: R, replace_with: &'b str) -> Splice<'a, 'b> + where R: RangeArgument + { + // Memory safety + // + // The String version of Splice does not have the memory safety issues + // of the vector version. The data is just plain bytes. + // Because the range removal happens in Drop, if the Splice iterator is leaked, + // the removal will not happen. + let len = self.len(); + let start = match range.start() { + Included(&n) => n, + Excluded(&n) => n + 1, + Unbounded => 0, + }; + let end = match range.end() { + Included(&n) => n + 1, + Excluded(&n) => n, + Unbounded => len, + }; + + // Take out two simultaneous borrows. The &mut String won't be accessed + // until iteration is over, in Drop. + let self_ptr = self as *mut _; + // slicing does the appropriate bounds checks + let chars_iter = self[start..end].chars(); + + Splice { + start: start, + end: end, + iter: chars_iter, + string: self_ptr, + replace_with: replace_with + } + } + /// Converts this `String` into a `Box`. /// /// This will drop any excess capacity. @@ -1398,11 +1464,31 @@ impl String { #[stable(feature = "box_str", since = "1.4.0")] pub fn into_boxed_str(self) -> Box { let slice = self.vec.into_boxed_slice(); - unsafe { mem::transmute::, Box>(slice) } + unsafe { alloc_str::from_boxed_utf8_unchecked(slice) } } } impl FromUtf8Error { + /// Returns a slice of [`u8`]s bytes that were attempted to convert to a `String`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(from_utf8_error_as_bytes)] + /// // some invalid bytes, in a vector + /// let bytes = vec![0, 159]; + /// + /// let value = String::from_utf8(bytes); + /// + /// assert_eq!(&[0, 159], value.unwrap_err().as_bytes()); + /// ``` + #[unstable(feature = "from_utf8_error_as_bytes", reason = "recently added", issue = "40895")] + pub fn as_bytes(&self) -> &[u8] { + &self.bytes[..] + } + /// Returns the bytes that were attempted to convert to a `String`. /// /// This method is carefully constructed to avoid allocation. It will @@ -1518,6 +1604,15 @@ impl FromIterator for String { } } +#[stable(feature = "herd_cows", since = "1.19.0")] +impl<'a> FromIterator> for String { + fn from_iter>>(iter: I) -> String { + let mut buf = String::new(); + buf.extend(iter); + buf + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl Extend for String { fn extend>(&mut self, iter: I) { @@ -1555,6 +1650,15 @@ impl Extend for String { } } +#[stable(feature = "herd_cows", since = "1.19.0")] +impl<'a> Extend> for String { + fn extend>>(&mut self, iter: I) { + for s in iter { + self.push_str(&s) + } + } +} + /// A convenience impl that delegates to the impl for `&str` #[unstable(feature = "pattern", reason = "API not fully fleshed out and ready to be stabilized", @@ -1790,7 +1894,7 @@ impl ops::IndexMut> for String { impl ops::IndexMut for String { #[inline] fn index_mut(&mut self, _index: ops::RangeFull) -> &mut str { - unsafe { mem::transmute(&mut *self.vec) } + unsafe { str::from_utf8_unchecked_mut(&mut *self.vec) } } } #[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] @@ -1822,7 +1926,7 @@ impl ops::Deref for String { impl ops::DerefMut for String { #[inline] fn deref_mut(&mut self) -> &mut str { - unsafe { mem::transmute(&mut *self.vec) } + unsafe { str::from_utf8_unchecked_mut(&mut *self.vec) } } } @@ -2125,3 +2229,61 @@ impl<'a> DoubleEndedIterator for Drain<'a> { #[unstable(feature = "fused", issue = "35602")] impl<'a> FusedIterator for Drain<'a> {} + +/// A splicing iterator for `String`. +/// +/// This struct is created by the [`splice()`] method on [`String`]. See its +/// documentation for more. +/// +/// [`splice()`]: struct.String.html#method.splice +/// [`String`]: struct.String.html +#[derive(Debug)] +#[unstable(feature = "splice", reason = "recently added", issue = "32310")] +pub struct Splice<'a, 'b> { + /// Will be used as &'a mut String in the destructor + string: *mut String, + /// Start of part to remove + start: usize, + /// End of part to remove + end: usize, + /// Current remaining range to remove + iter: Chars<'a>, + replace_with: &'b str, +} + +#[unstable(feature = "splice", reason = "recently added", issue = "32310")] +unsafe impl<'a, 'b> Sync for Splice<'a, 'b> {} +#[unstable(feature = "splice", reason = "recently added", issue = "32310")] +unsafe impl<'a, 'b> Send for Splice<'a, 'b> {} + +#[unstable(feature = "splice", reason = "recently added", issue = "32310")] +impl<'a, 'b> Drop for Splice<'a, 'b> { + fn drop(&mut self) { + unsafe { + let vec = (*self.string).as_mut_vec(); + vec.splice(self.start..self.end, self.replace_with.bytes()); + } + } +} + +#[unstable(feature = "splice", reason = "recently added", issue = "32310")] +impl<'a, 'b> Iterator for Splice<'a, 'b> { + type Item = char; + + #[inline] + fn next(&mut self) -> Option { + self.iter.next() + } + + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +#[unstable(feature = "splice", reason = "recently added", issue = "32310")] +impl<'a, 'b> DoubleEndedIterator for Splice<'a, 'b> { + #[inline] + fn next_back(&mut self) -> Option { + self.iter.next_back() + } +} diff --git a/src/libcollectionstest/binary_heap.rs b/src/libcollections/tests/binary_heap.rs similarity index 88% rename from src/libcollectionstest/binary_heap.rs rename to src/libcollections/tests/binary_heap.rs index d284937a9e67..af18cddaddb0 100644 --- a/src/libcollectionstest/binary_heap.rs +++ b/src/libcollections/tests/binary_heap.rs @@ -152,36 +152,6 @@ fn test_push_unique() { assert!(*heap.peek().unwrap() == box 103); } -#[test] -#[allow(deprecated)] -fn test_push_pop() { - let mut heap = BinaryHeap::from(vec![5, 5, 2, 1, 3]); - assert_eq!(heap.len(), 5); - assert_eq!(heap.push_pop(6), 6); - assert_eq!(heap.len(), 5); - assert_eq!(heap.push_pop(0), 5); - assert_eq!(heap.len(), 5); - assert_eq!(heap.push_pop(4), 5); - assert_eq!(heap.len(), 5); - assert_eq!(heap.push_pop(1), 4); - assert_eq!(heap.len(), 5); -} - -#[test] -#[allow(deprecated)] -fn test_replace() { - let mut heap = BinaryHeap::from(vec![5, 5, 2, 1, 3]); - assert_eq!(heap.len(), 5); - assert_eq!(heap.replace(6).unwrap(), 5); - assert_eq!(heap.len(), 5); - assert_eq!(heap.replace(0).unwrap(), 6); - assert_eq!(heap.len(), 5); - assert_eq!(heap.replace(4).unwrap(), 5); - assert_eq!(heap.len(), 5); - assert_eq!(heap.replace(1).unwrap(), 4); - assert_eq!(heap.len(), 5); -} - fn check_to_vec(mut data: Vec) { let heap = BinaryHeap::from(data.clone()); let mut v = heap.clone().into_vec(); @@ -227,13 +197,6 @@ fn test_empty_peek_mut() { assert!(empty.peek_mut().is_none()); } -#[test] -#[allow(deprecated)] -fn test_empty_replace() { - let mut heap = BinaryHeap::new(); - assert!(heap.replace(5).is_none()); -} - #[test] fn test_from_iter() { let xs = vec![9, 8, 7, 6, 5, 4, 3, 2, 1]; diff --git a/src/libcollectionstest/btree/map.rs b/src/libcollections/tests/btree/map.rs similarity index 100% rename from src/libcollectionstest/btree/map.rs rename to src/libcollections/tests/btree/map.rs diff --git a/src/libcollectionstest/btree/mod.rs b/src/libcollections/tests/btree/mod.rs similarity index 100% rename from src/libcollectionstest/btree/mod.rs rename to src/libcollections/tests/btree/mod.rs diff --git a/src/libcollectionstest/btree/set.rs b/src/libcollections/tests/btree/set.rs similarity index 100% rename from src/libcollectionstest/btree/set.rs rename to src/libcollections/tests/btree/set.rs diff --git a/src/libcollectionstest/cow_str.rs b/src/libcollections/tests/cow_str.rs similarity index 94% rename from src/libcollectionstest/cow_str.rs rename to src/libcollections/tests/cow_str.rs index b29245121daa..aa87ee84b3e9 100644 --- a/src/libcollectionstest/cow_str.rs +++ b/src/libcollections/tests/cow_str.rs @@ -139,3 +139,13 @@ fn check_cow_add_assign_str() { assert_eq!("Hi, World!", owned); assert_eq!("Hello, World!", borrowed); } + +#[test] +fn check_cow_clone_from() { + let mut c1: Cow = Cow::Owned(String::with_capacity(25)); + let s: String = "hi".to_string(); + assert!(s.capacity() < 25); + let c2: Cow = Cow::Owned(s); + c1.clone_from(&c2); + assert!(c1.into_owned().capacity() >= 25); +} \ No newline at end of file diff --git a/src/libcollectionstest/fmt.rs b/src/libcollections/tests/fmt.rs similarity index 100% rename from src/libcollectionstest/fmt.rs rename to src/libcollections/tests/fmt.rs diff --git a/src/libcollectionstest/lib.rs b/src/libcollections/tests/lib.rs similarity index 97% rename from src/libcollectionstest/lib.rs rename to src/libcollections/tests/lib.rs index 618eb386c0f4..eae3bf3915f6 100644 --- a/src/libcollectionstest/lib.rs +++ b/src/libcollections/tests/lib.rs @@ -10,7 +10,6 @@ #![deny(warnings)] -#![feature(binary_heap_extras)] #![feature(binary_heap_peek_mut_pop)] #![feature(box_syntax)] #![feature(inclusive_range_syntax)] @@ -21,6 +20,7 @@ #![feature(pattern)] #![feature(placement_in_syntax)] #![feature(rand)] +#![feature(splice)] #![feature(step_by)] #![feature(str_escape)] #![feature(test)] diff --git a/src/libcollectionstest/linked_list.rs b/src/libcollections/tests/linked_list.rs similarity index 100% rename from src/libcollectionstest/linked_list.rs rename to src/libcollections/tests/linked_list.rs diff --git a/src/libcollectionstest/slice.rs b/src/libcollections/tests/slice.rs similarity index 98% rename from src/libcollectionstest/slice.rs rename to src/libcollections/tests/slice.rs index 00d4dbe9c045..c3e5304fb2b3 100644 --- a/src/libcollectionstest/slice.rs +++ b/src/libcollections/tests/slice.rs @@ -383,9 +383,11 @@ fn test_reverse() { #[test] fn test_sort() { + let mut rng = thread_rng(); + for len in (2..25).chain(500..510) { for _ in 0..100 { - let mut v: Vec<_> = thread_rng().gen_iter::().take(len).collect(); + let mut v: Vec<_> = rng.gen_iter::().take(len).collect(); let mut v1 = v.clone(); v.sort(); @@ -399,6 +401,18 @@ fn test_sort() { } } + // Sort using a completely random comparison function. + // This will reorder the elements *somehow*, but won't panic. + let mut v = [0; 500]; + for i in 0..v.len() { + v[i] = i as i32; + } + v.sort_by(|_, _| *rng.choose(&[Less, Equal, Greater]).unwrap()); + v.sort(); + for i in 0..v.len() { + assert_eq!(v[i], i as i32); + } + // Should not panic. [0i32; 0].sort(); [(); 10].sort(); diff --git a/src/libcollectionstest/str.rs b/src/libcollections/tests/str.rs similarity index 100% rename from src/libcollectionstest/str.rs rename to src/libcollections/tests/str.rs diff --git a/src/libcollectionstest/string.rs b/src/libcollections/tests/string.rs similarity index 89% rename from src/libcollectionstest/string.rs rename to src/libcollections/tests/string.rs index 2f021b9935d6..b1731b2a5dca 100644 --- a/src/libcollectionstest/string.rs +++ b/src/libcollections/tests/string.rs @@ -419,6 +419,69 @@ fn test_drain() { assert_eq!(t, ""); } +#[test] +fn test_splice() { + let mut s = "Hello, world!".to_owned(); + let t: String = s.splice(7..12, "世界").collect(); + assert_eq!(s, "Hello, 世界!"); + assert_eq!(t, "world"); +} + +#[test] +#[should_panic] +fn test_splice_char_boundary() { + let mut s = "Hello, 世界!".to_owned(); + s.splice(..8, ""); +} + +#[test] +fn test_splice_inclusive_range() { + let mut v = String::from("12345"); + let t: String = v.splice(2...3, "789").collect(); + assert_eq!(v, "127895"); + assert_eq!(t, "34"); + let t2: String = v.splice(1...2, "A").collect(); + assert_eq!(v, "1A895"); + assert_eq!(t2, "27"); +} + +#[test] +#[should_panic] +fn test_splice_out_of_bounds() { + let mut s = String::from("12345"); + s.splice(5..6, "789"); +} + +#[test] +#[should_panic] +fn test_splice_inclusive_out_of_bounds() { + let mut s = String::from("12345"); + s.splice(5...5, "789"); +} + +#[test] +fn test_splice_empty() { + let mut s = String::from("12345"); + let t: String = s.splice(1..2, "").collect(); + assert_eq!(s, "1345"); + assert_eq!(t, "2"); +} + +#[test] +fn test_splice_unbounded() { + let mut s = String::from("12345"); + let t: String = s.splice(.., "").collect(); + assert_eq!(s, ""); + assert_eq!(t, "12345"); +} + +#[test] +fn test_splice_forget() { + let mut s = String::from("12345"); + ::std::mem::forget(s.splice(2..4, "789")); + assert_eq!(s, "12345"); +} + #[test] fn test_extend_ref() { let mut a = "foo".to_string(); diff --git a/src/libcollectionstest/vec.rs b/src/libcollections/tests/vec.rs similarity index 86% rename from src/libcollectionstest/vec.rs rename to src/libcollections/tests/vec.rs index 06d70800d392..29f18274962f 100644 --- a/src/libcollectionstest/vec.rs +++ b/src/libcollections/tests/vec.rs @@ -84,6 +84,9 @@ fn test_extend() { let mut v = Vec::new(); let mut w = Vec::new(); + v.extend(w.clone()); + assert_eq!(v, &[]); + v.extend(0..3); for i in 0..3 { w.push(i) @@ -100,6 +103,25 @@ fn test_extend() { v.extend(w.clone()); // specializes to `append` assert!(v.iter().eq(w.iter().chain(w.iter()))); + + // Zero sized types + #[derive(PartialEq, Debug)] + struct Foo; + + let mut a = Vec::new(); + let b = vec![Foo, Foo]; + + a.extend(b); + assert_eq!(a, &[Foo, Foo]); + + // Double drop + let mut count_x = 0; + { + let mut x = Vec::new(); + let y = vec![DropCounter { count: &mut count_x }]; + x.extend(y); + } + assert_eq!(count_x, 1); } #[test] @@ -557,6 +579,69 @@ fn test_drain_inclusive_out_of_bounds() { v.drain(5...5); } +#[test] +fn test_splice() { + let mut v = vec![1, 2, 3, 4, 5]; + let a = [10, 11, 12]; + v.splice(2..4, a.iter().cloned()); + assert_eq!(v, &[1, 2, 10, 11, 12, 5]); + v.splice(1..3, Some(20)); + assert_eq!(v, &[1, 20, 11, 12, 5]); +} + +#[test] +fn test_splice_inclusive_range() { + let mut v = vec![1, 2, 3, 4, 5]; + let a = [10, 11, 12]; + let t1: Vec<_> = v.splice(2...3, a.iter().cloned()).collect(); + assert_eq!(v, &[1, 2, 10, 11, 12, 5]); + assert_eq!(t1, &[3, 4]); + let t2: Vec<_> = v.splice(1...2, Some(20)).collect(); + assert_eq!(v, &[1, 20, 11, 12, 5]); + assert_eq!(t2, &[2, 10]); +} + +#[test] +#[should_panic] +fn test_splice_out_of_bounds() { + let mut v = vec![1, 2, 3, 4, 5]; + let a = [10, 11, 12]; + v.splice(5..6, a.iter().cloned()); +} + +#[test] +#[should_panic] +fn test_splice_inclusive_out_of_bounds() { + let mut v = vec![1, 2, 3, 4, 5]; + let a = [10, 11, 12]; + v.splice(5...5, a.iter().cloned()); +} + +#[test] +fn test_splice_items_zero_sized() { + let mut vec = vec![(), (), ()]; + let vec2 = vec![]; + let t: Vec<_> = vec.splice(1..2, vec2.iter().cloned()).collect(); + assert_eq!(vec, &[(), ()]); + assert_eq!(t, &[()]); +} + +#[test] +fn test_splice_unbounded() { + let mut vec = vec![1, 2, 3, 4, 5]; + let t: Vec<_> = vec.splice(.., None).collect(); + assert_eq!(vec, &[]); + assert_eq!(t, &[1, 2, 3, 4, 5]); +} + +#[test] +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())); + assert_eq!(v, &[1, 2]); +} + #[test] fn test_into_boxed_slice() { let xs = vec![1, 2, 3]; @@ -680,3 +765,19 @@ fn test_placement_panic() { let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| { vec.place_back() <- mkpanic(); })); assert_eq!(vec.len(), 3); } + +#[test] +fn from_into_inner() { + let vec = vec![1, 2, 3]; + let ptr = vec.as_ptr(); + let vec = vec.into_iter().collect::>(); + assert_eq!(vec, [1, 2, 3]); + assert_eq!(vec.as_ptr(), ptr); + + let ptr = &vec[1] as *const _; + let mut it = vec.into_iter(); + it.next().unwrap(); + let vec = it.collect::>(); + assert_eq!(vec, [2, 3]); + assert!(ptr != vec.as_ptr()); +} diff --git a/src/libcollectionstest/vec_deque.rs b/src/libcollections/tests/vec_deque.rs similarity index 100% rename from src/libcollectionstest/vec_deque.rs rename to src/libcollections/tests/vec_deque.rs diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 7b408af13aa2..fc5de70e9838 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -77,6 +77,8 @@ use core::hash::{self, Hash}; use core::intrinsics::{arith_offset, assume}; use core::iter::{FromIterator, FusedIterator, TrustedLen}; use core::mem; +#[cfg(not(test))] +use core::num::Float; use core::ops::{InPlace, Index, IndexMut, Place, Placer}; use core::ops; use core::ptr; @@ -273,7 +275,9 @@ use Bound::{Excluded, Included, Unbounded}; /// removed data to be erased for security purposes. Even if you drop a `Vec`, its /// buffer may simply be reused by another `Vec`. Even if you zero a `Vec`'s memory /// first, that may not actually happen because the optimizer does not consider -/// this a side-effect that must be preserved. +/// this a side-effect that must be preserved. There is one case which we will +/// not break, however: using `unsafe` code to write to the excess capacity, +/// and then increasing the length to match, is always valid. /// /// `Vec` does not currently guarantee the order in which elements are dropped /// (the order has changed in the past, and may change again). @@ -678,8 +682,9 @@ impl Vec { self.len = len; } - /// Removes an element from anywhere in the vector and return it, replacing - /// it with the last element. + /// Removes an element from the vector and returns it. + /// + /// The removed element is replaced by the last element of the vector. /// /// This does not preserve ordering, but is O(1). /// @@ -972,6 +977,29 @@ impl Vec { } } + /// Returns a place for insertion at the back of the `Vec`. + /// + /// Using this method with placement syntax is equivalent to [`push`](#method.push), + /// but may be more efficient. + /// + /// # Examples + /// + /// ``` + /// #![feature(collection_placement)] + /// #![feature(placement_in_syntax)] + /// + /// let mut vec = vec![1, 2]; + /// vec.place_back() <- 3; + /// vec.place_back() <- 4; + /// assert_eq!(&vec, &[1, 2, 3, 4]); + /// ``` + #[unstable(feature = "collection_placement", + reason = "placement protocol is subject to change", + issue = "30172")] + pub fn place_back(&mut self) -> PlaceBack { + PlaceBack { vec: self } + } + /// Removes the last element from a vector and returns it, or [`None`] if it /// is empty. /// @@ -1015,25 +1043,29 @@ impl Vec { #[inline] #[stable(feature = "append", since = "1.4.0")] pub fn append(&mut self, other: &mut Self) { - self.reserve(other.len()); - let len = self.len(); - unsafe { - ptr::copy_nonoverlapping(other.as_ptr(), self.get_unchecked_mut(len), other.len()); - } - - self.len += other.len(); unsafe { + self.append_elements(other.as_slice() as _); other.set_len(0); } } - /// Create a draining iterator that removes the specified range in the vector + /// Appends elements to `Self` from other buffer. + #[inline] + unsafe fn append_elements(&mut self, other: *const [T]) { + let count = (*other).len(); + self.reserve(count); + let len = self.len(); + ptr::copy_nonoverlapping(other as *const T, self.get_unchecked_mut(len), count); + self.len += count; + } + + /// Creates a draining iterator that removes the specified range in the vector /// and yields the removed items. /// /// Note 1: The element range is removed even if the iterator is only /// partially consumed or not consumed at all. /// - /// Note 2: It is unspecified how many elements are removed from the vector, + /// Note 2: It is unspecified how many elements are removed from the vector /// if the `Drain` value is leaked. /// /// # Panics @@ -1117,7 +1149,8 @@ impl Vec { self.truncate(0) } - /// Returns the number of elements in the vector. + /// Returns the number of elements in the vector, also referred to + /// as its 'length'. /// /// # Examples /// @@ -1266,29 +1299,6 @@ impl Vec { pub fn extend_from_slice(&mut self, other: &[T]) { self.spec_extend(other.iter()) } - - /// Returns a place for insertion at the back of the `Vec`. - /// - /// Using this method with placement syntax is equivalent to [`push`](#method.push), - /// but may be more efficient. - /// - /// # Examples - /// - /// ``` - /// #![feature(collection_placement)] - /// #![feature(placement_in_syntax)] - /// - /// let mut vec = vec![1, 2]; - /// vec.place_back() <- 3; - /// vec.place_back() <- 4; - /// assert_eq!(&vec, &[1, 2, 3, 4]); - /// ``` - #[unstable(feature = "collection_placement", - reason = "placement protocol is subject to change", - issue = "30172")] - pub fn place_back(&mut self) -> PlaceBack { - PlaceBack { vec: self } - } } // Set the length of the vec when the `SetLenOnDrop` value goes out of scope. @@ -1345,7 +1355,7 @@ impl Vec { /// # Examples /// /// ``` - ///# #![feature(vec_remove_item)] + /// # #![feature(vec_remove_item)] /// let mut vec = vec![1, 2, 3, 1]; /// /// vec.remove_item(&1); @@ -1369,11 +1379,75 @@ impl Vec { #[doc(hidden)] #[stable(feature = "rust1", since = "1.0.0")] pub fn from_elem(elem: T, n: usize) -> Vec { - let mut v = Vec::with_capacity(n); - v.extend_with_element(n, elem); - v + ::from_elem(elem, n) } +// Specialization trait used for Vec::from_elem +trait SpecFromElem: Sized { + fn from_elem(elem: Self, n: usize) -> Vec; +} + +impl SpecFromElem for T { + default fn from_elem(elem: Self, n: usize) -> Vec { + let mut v = Vec::with_capacity(n); + v.extend_with_element(n, elem); + v + } +} + +impl SpecFromElem for u8 { + #[inline] + fn from_elem(elem: u8, n: usize) -> Vec { + if elem == 0 { + return Vec { + buf: RawVec::with_capacity_zeroed(n), + len: n, + } + } + unsafe { + let mut v = Vec::with_capacity(n); + ptr::write_bytes(v.as_mut_ptr(), elem, n); + v.set_len(n); + v + } + } +} + +macro_rules! impl_spec_from_elem { + ($t: ty, $is_zero: expr) => { + impl SpecFromElem for $t { + #[inline] + fn from_elem(elem: $t, n: usize) -> Vec<$t> { + if $is_zero(elem) { + return Vec { + buf: RawVec::with_capacity_zeroed(n), + len: n, + } + } + let mut v = Vec::with_capacity(n); + v.extend_with_element(n, elem); + v + } + } + }; +} + +impl_spec_from_elem!(i8, |x| x == 0); +impl_spec_from_elem!(i16, |x| x == 0); +impl_spec_from_elem!(i32, |x| x == 0); +impl_spec_from_elem!(i64, |x| x == 0); +impl_spec_from_elem!(i128, |x| x == 0); +impl_spec_from_elem!(isize, |x| x == 0); + +impl_spec_from_elem!(u16, |x| x == 0); +impl_spec_from_elem!(u32, |x| x == 0); +impl_spec_from_elem!(u64, |x| x == 0); +impl_spec_from_elem!(u128, |x| x == 0); +impl_spec_from_elem!(usize, |x| x == 0); + +impl_spec_from_elem!(f32, |x: f32| x == 0. && x.is_sign_positive()); +impl_spec_from_elem!(f64, |x: f64| x == 0. && x.is_sign_positive()); + //////////////////////////////////////////////////////////////////////////////// // Common trait implementations for Vec //////////////////////////////////////////////////////////////////////////////// @@ -1395,16 +1469,7 @@ impl Clone for Vec { } fn clone_from(&mut self, other: &Vec) { - // drop anything in self that will not be overwritten - self.truncate(other.len()); - let len = self.len(); - - // reuse the contained values' allocations/resources. - self.clone_from_slice(&other[..len]); - - // self.len <= other.len due to the truncate above, so the - // slice here is always in-bounds. - self.extend_from_slice(&other[len..]); + other.as_slice().clone_into(self); } } @@ -1563,7 +1628,7 @@ impl ops::DerefMut for Vec { impl FromIterator for Vec { #[inline] fn from_iter>(iter: I) -> Vec { - >::from_iter(iter.into_iter()) + >::from_iter(iter.into_iter()) } } @@ -1631,7 +1696,7 @@ impl<'a, T> IntoIterator for &'a mut Vec { impl Extend for Vec { #[inline] fn extend>(&mut self, iter: I) { - self.spec_extend(iter.into_iter()) + >::spec_extend(self, iter.into_iter()) } } @@ -1662,7 +1727,7 @@ impl SpecExtend for Vec vector } }; - vector.spec_extend(iterator); + as SpecExtend>::spec_extend(&mut vector, iterator); vector } @@ -1674,13 +1739,13 @@ impl SpecExtend for Vec impl SpecExtend for Vec where I: TrustedLen, { - fn from_iter(iterator: I) -> Self { + default fn from_iter(iterator: I) -> Self { let mut vector = Vec::new(); vector.spec_extend(iterator); vector } - fn spec_extend(&mut self, iterator: I) { + default fn spec_extend(&mut self, iterator: I) { // This is the case for a TrustedLen iterator. let (low, high) = iterator.size_hint(); if let Some(high_value) = high { @@ -1706,6 +1771,34 @@ impl SpecExtend for Vec } } +impl SpecExtend> for Vec { + fn from_iter(iterator: IntoIter) -> Self { + // A common case is passing a vector into a function which immediately + // re-collects into a vector. We can short circuit this if the IntoIter + // has not been advanced at all. + if *iterator.buf == iterator.ptr as *mut T { + unsafe { + let vec = Vec::from_raw_parts(*iterator.buf as *mut T, + iterator.len(), + iterator.cap); + mem::forget(iterator); + vec + } + } else { + let mut vector = Vec::new(); + vector.spec_extend(iterator); + vector + } + } + + fn spec_extend(&mut self, mut iterator: IntoIter) { + unsafe { + self.append_elements(iterator.as_slice() as _); + } + iterator.ptr = iterator.end; + } +} + impl<'a, T: 'a, I> SpecExtend<&'a T, I> for Vec where I: Iterator, T: Clone, @@ -1755,6 +1848,54 @@ impl Vec { } } } + + /// Creates a splicing iterator that replaces the specified range in the vector + /// with the given `replace_with` iterator and yields the removed items. + /// `replace_with` does not need to be the same length as `range`. + /// + /// Note 1: The element range is removed even if the iterator is not + /// consumed until the end. + /// + /// Note 2: It is unspecified how many elements are removed from the vector, + /// if the `Splice` value is leaked. + /// + /// Note 3: The input iterator `replace_with` is only consumed + /// when the `Splice` value is dropped. + /// + /// Note 4: This is optimal if: + /// + /// * The tail (elements in the vector after `range`) is empty, + /// * or `replace_with` yields fewer elements than `range`’s length + /// * or the lower bound of its `size_hint()` is exact. + /// + /// Otherwise, a temporary vector is allocated and the tail is moved twice. + /// + /// # Panics + /// + /// Panics if the starting point is greater than the end point or if + /// the end point is greater than the length of the vector. + /// + /// # Examples + /// + /// ``` + /// #![feature(splice)] + /// let mut v = vec![1, 2, 3]; + /// let new = [7, 8]; + /// let u: Vec<_> = v.splice(..2, new.iter().cloned()).collect(); + /// assert_eq!(v, &[7, 8, 3]); + /// assert_eq!(u, &[1, 2]); + /// ``` + #[inline] + #[unstable(feature = "splice", reason = "recently added", issue = "32310")] + pub fn splice(&mut self, range: R, replace_with: I) -> Splice + where R: RangeArgument, I: IntoIterator + { + Splice { + drain: self.drain(range), + replace_with: replace_with.into_iter(), + } + } + } #[stable(feature = "extend_ref", since = "1.2.0")] @@ -1894,6 +2035,18 @@ impl<'a, T: Clone> From<&'a [T]> for Vec { } } +#[stable(feature = "vec_from_mut", since = "1.21.0")] +impl<'a, T: Clone> From<&'a mut [T]> for Vec { + #[cfg(not(test))] + fn from(s: &'a mut [T]) -> Vec { + s.to_vec() + } + #[cfg(test)] + fn from(s: &'a mut [T]) -> Vec { + ::slice::to_vec(s) + } +} + #[stable(feature = "vec_from_cow_slice", since = "1.14.0")] impl<'a, T> From> for Vec where [T]: ToOwned> { fn from(s: Cow<'a, [T]>) -> Vec { @@ -2052,14 +2205,10 @@ impl Iterator for IntoIter { #[inline] fn size_hint(&self) -> (usize, Option) { - let diff = (self.end as usize) - (self.ptr as usize); - let size = mem::size_of::(); - let exact = diff / - (if size == 0 { - 1 - } else { - size - }); + let exact = match self.ptr.offset_to(self.end) { + Some(x) => x as usize, + None => (self.end as usize).wrapping_sub(self.ptr as usize), + }; (exact, Some(exact)) } @@ -2258,3 +2407,125 @@ impl<'a, T> InPlace for PlaceBack<'a, T> { &mut *ptr } } + + +/// A splicing iterator for `Vec`. +/// +/// This struct is created by the [`splice()`] method on [`Vec`]. See its +/// documentation for more. +/// +/// [`splice()`]: struct.Vec.html#method.splice +/// [`Vec`]: struct.Vec.html +#[derive(Debug)] +#[unstable(feature = "splice", reason = "recently added", issue = "32310")] +pub struct Splice<'a, I: Iterator + 'a> { + drain: Drain<'a, I::Item>, + replace_with: I, +} + +#[unstable(feature = "splice", reason = "recently added", issue = "32310")] +impl<'a, I: Iterator> Iterator for Splice<'a, I> { + type Item = I::Item; + + fn next(&mut self) -> Option { + self.drain.next() + } + + fn size_hint(&self) -> (usize, Option) { + self.drain.size_hint() + } +} + +#[unstable(feature = "splice", reason = "recently added", issue = "32310")] +impl<'a, I: Iterator> DoubleEndedIterator for Splice<'a, I> { + fn next_back(&mut self) -> Option { + self.drain.next_back() + } +} + +#[unstable(feature = "splice", reason = "recently added", issue = "32310")] +impl<'a, I: Iterator> ExactSizeIterator for Splice<'a, I> {} + + +#[unstable(feature = "splice", reason = "recently added", issue = "32310")] +impl<'a, I: Iterator> Drop for Splice<'a, I> { + fn drop(&mut self) { + // exhaust drain first + while let Some(_) = self.drain.next() {} + + + unsafe { + if self.drain.tail_len == 0 { + let vec = &mut *self.drain.vec.as_mut_ptr(); + vec.extend(self.replace_with.by_ref()); + return + } + + // First fill the range left by drain(). + if !self.drain.fill(&mut self.replace_with) { + return + } + + // There may be more elements. Use the lower bound as an estimate. + // FIXME: Is the upper bound a better guess? Or something else? + let (lower_bound, _upper_bound) = self.replace_with.size_hint(); + if lower_bound > 0 { + self.drain.move_tail(lower_bound); + if !self.drain.fill(&mut self.replace_with) { + return + } + } + + // Collect any remaining elements. + // This is a zero-length vector which does not allocate if `lower_bound` was exact. + let mut collected = self.replace_with.by_ref().collect::>().into_iter(); + // Now we have an exact count. + if collected.len() > 0 { + self.drain.move_tail(collected.len()); + let filled = self.drain.fill(&mut collected); + debug_assert!(filled); + debug_assert_eq!(collected.len(), 0); + } + } + // Let `Drain::drop` move the tail back if necessary and restore `vec.len`. + } +} + +/// Private helper methods for `Splice::drop` +impl<'a, T> Drain<'a, 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`.) + unsafe fn fill>(&mut self, replace_with: &mut I) -> bool { + let vec = &mut *self.vec.as_mut_ptr(); + let range_start = vec.len; + let range_end = self.tail_start; + let range_slice = slice::from_raw_parts_mut( + vec.as_mut_ptr().offset(range_start as isize), + range_end - range_start); + + for place in range_slice { + if let Some(new_item) = replace_with.next() { + ptr::write(place, new_item); + vec.len += 1; + } else { + return false + } + } + true + } + + /// Make room for inserting more elements before the tail. + unsafe fn move_tail(&mut self, extra_capacity: usize) { + let vec = &mut *self.vec.as_mut_ptr(); + let used_capacity = self.tail_start + self.tail_len; + vec.buf.reserve(used_capacity, extra_capacity); + + let new_tail_start = self.tail_start + extra_capacity; + let src = vec.as_ptr().offset(self.tail_start as isize); + let dst = vec.as_mut_ptr().offset(new_tail_start as isize); + ptr::copy(src, dst, self.tail_len); + self.tail_start = new_tail_start; + } +} diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs index cb92236ec736..079d3acf3764 100644 --- a/src/libcollections/vec_deque.rs +++ b/src/libcollections/vec_deque.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! VecDeque is a double-ended queue, which is implemented with the help of a -//! growing ring buffer. +//! A double-ended queue implemented with a growable ring buffer. //! //! This queue has `O(1)` amortized inserts and removals from both ends of the //! container. It also has `O(1)` indexing like a vector. The contained elements @@ -43,13 +42,17 @@ const MAXIMUM_ZST_CAPACITY: usize = 1 << (32 - 1); // Largest possible power of #[cfg(target_pointer_width = "64")] const MAXIMUM_ZST_CAPACITY: usize = 1 << (64 - 1); // Largest possible power of two -/// `VecDeque` is a growable ring buffer, which can be used as a double-ended -/// queue efficiently. +/// A double-ended queue implemented with a growable ring buffer. /// -/// The "default" usage of this type as a queue is to use `push_back` to add to -/// the queue, and `pop_front` to remove from the queue. `extend` and `append` +/// The "default" usage of this type as a queue is to use [`push_back`] to add to +/// the queue, and [`pop_front`] to remove from the queue. [`extend`] and [`append`] /// push onto the back in this manner, and iterating over `VecDeque` goes front /// to back. +/// +/// [`push_back`]: #method.push_back +/// [`pop_front`]: #method.pop_front +/// [`extend`]: #method.extend +/// [`append`]: #method.append #[stable(feature = "rust1", since = "1.0.0")] pub struct VecDeque { // tail and head are pointers into the buffer. Tail always points @@ -506,7 +509,7 @@ impl VecDeque { /// given `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 minimal. Prefer `reserve` if future + /// capacity can not be relied upon to be precisely minimal. Prefer [`reserve`] if future /// insertions are expected. /// /// # Panics @@ -522,6 +525,8 @@ impl VecDeque { /// buf.reserve_exact(10); /// assert!(buf.capacity() >= 11); /// ``` + /// + /// [`reserve`]: #method.reserve #[stable(feature = "rust1", since = "1.0.0")] pub fn reserve_exact(&mut self, additional: usize) { self.reserve(additional); @@ -635,7 +640,7 @@ impl VecDeque { } } - /// Shortens a `VecDeque`, dropping excess elements from the back. + /// Shortens the `VecDeque`, dropping excess elements from the back. /// /// If `len` is greater than the `VecDeque`'s current length, this has no /// effect. @@ -941,7 +946,7 @@ impl VecDeque { a.contains(x) || b.contains(x) } - /// Provides a reference to the front element, or `None` if the sequence is + /// Provides a reference to the front element, or `None` if the `VecDeque` is /// empty. /// /// # Examples @@ -966,7 +971,7 @@ impl VecDeque { } /// Provides a mutable reference to the front element, or `None` if the - /// sequence is empty. + /// `VecDeque` is empty. /// /// # Examples /// @@ -993,7 +998,7 @@ impl VecDeque { } } - /// Provides a reference to the back element, or `None` if the sequence is + /// Provides a reference to the back element, or `None` if the `VecDeque` is /// empty. /// /// # Examples @@ -1018,7 +1023,7 @@ impl VecDeque { } /// Provides a mutable reference to the back element, or `None` if the - /// sequence is empty. + /// `VecDeque` is empty. /// /// # Examples /// @@ -1046,7 +1051,7 @@ impl VecDeque { } } - /// Removes the first element and returns it, or `None` if the sequence is + /// Removes the first element and returns it, or `None` if the `VecDeque` is /// empty. /// /// # Examples @@ -1073,7 +1078,7 @@ impl VecDeque { } } - /// Inserts an element first in the sequence. + /// Prepends an element to the `VecDeque`. /// /// # Examples /// @@ -1096,7 +1101,7 @@ impl VecDeque { } } - /// Appends an element to the back of a buffer + /// Appends an element to the back of the `VecDeque`. /// /// # Examples /// @@ -1117,7 +1122,7 @@ impl VecDeque { unsafe { self.buffer_write(head, value) } } - /// Removes the last element from a buffer and returns it, or `None` if + /// Removes the last element from the `VecDeque` and returns it, or `None` if /// it is empty. /// /// # Examples @@ -1847,7 +1852,7 @@ fn wrap_index(index: usize, size: usize) -> usize { index & (size - 1) } -/// Returns the two slices that cover the VecDeque's valid range +/// Returns the two slices that cover the `VecDeque`'s valid range trait RingSlices: Sized { fn slice(self, from: usize, to: usize) -> Self; fn split_at(self, i: usize) -> (Self, Self); @@ -1890,7 +1895,13 @@ fn count(tail: usize, head: usize, size: usize) -> usize { (head.wrapping_sub(tail)) & (size - 1) } -/// `VecDeque` iterator. +/// An iterator over the elements of a `VecDeque`. +/// +/// This `struct` is created by the [`iter`] method on [`VecDeque`]. See its +/// documentation for more. +/// +/// [`iter`]: struct.VecDeque.html#method.iter +/// [`VecDeque`]: struct.VecDeque.html #[stable(feature = "rust1", since = "1.0.0")] pub struct Iter<'a, T: 'a> { ring: &'a [T], @@ -1902,7 +1913,9 @@ pub struct Iter<'a, T: 'a> { impl<'a, T: 'a + fmt::Debug> fmt::Debug for Iter<'a, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("Iter") - .field(&self.clone()) + .field(&self.ring) + .field(&self.tail) + .field(&self.head) .finish() } } @@ -1971,7 +1984,13 @@ impl<'a, T> ExactSizeIterator for Iter<'a, T> { impl<'a, T> FusedIterator for Iter<'a, T> {} -/// `VecDeque` mutable iterator. +/// A mutable iterator over the elements of a `VecDeque`. +/// +/// This `struct` is created by the [`iter_mut`] method on [`VecDeque`]. See its +/// documentation for more. +/// +/// [`iter_mut`]: struct.VecDeque.html#method.iter_mut +/// [`VecDeque`]: struct.VecDeque.html #[stable(feature = "rust1", since = "1.0.0")] pub struct IterMut<'a, T: 'a> { ring: &'a mut [T], @@ -1983,7 +2002,9 @@ pub struct IterMut<'a, T: 'a> { impl<'a, T: 'a + fmt::Debug> fmt::Debug for IterMut<'a, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("IterMut") - .field(&self.clone()) + .field(&self.ring) + .field(&self.tail) + .field(&self.head) .finish() } } @@ -2047,7 +2068,13 @@ impl<'a, T> ExactSizeIterator for IterMut<'a, T> { #[unstable(feature = "fused", issue = "35602")] impl<'a, T> FusedIterator for IterMut<'a, T> {} -/// A by-value VecDeque iterator +/// An owning iterator over the elements of a `VecDeque`. +/// +/// This `struct` is created by the [`into_iter`] method on [`VecDeque`][`VecDeque`] +/// (provided by the `IntoIterator` trait). See its documentation for more. +/// +/// [`into_iter`]: struct.VecDeque.html#method.into_iter +/// [`VecDeque`]: struct.VecDeque.html #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter { @@ -2058,7 +2085,7 @@ pub struct IntoIter { impl fmt::Debug for IntoIter { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("IntoIter") - .field(&self.clone()) + .field(&self.inner) .finish() } } @@ -2097,7 +2124,13 @@ impl ExactSizeIterator for IntoIter { #[unstable(feature = "fused", issue = "35602")] impl FusedIterator for IntoIter {} -/// A draining VecDeque iterator +/// A draining iterator over the elements of a `VecDeque`. +/// +/// This `struct` is created by the [`drain`] method on [`VecDeque`]. See its +/// documentation for more. +/// +/// [`drain`]: struct.VecDeque.html#method.drain +/// [`VecDeque`]: struct.VecDeque.html #[stable(feature = "drain", since = "1.6.0")] pub struct Drain<'a, T: 'a> { after_tail: usize, @@ -2110,7 +2143,9 @@ pub struct Drain<'a, T: 'a> { impl<'a, T: 'a + fmt::Debug> fmt::Debug for Drain<'a, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("Drain") - .field(&self.clone()) + .field(&self.after_tail) + .field(&self.after_head) + .field(&self.iter) .finish() } } @@ -2243,7 +2278,7 @@ macro_rules! __impl_slice_eq1 { __impl_slice_eq1! { $Lhs, $Rhs, Sized } }; ($Lhs: ty, $Rhs: ty, $Bound: ident) => { - #[stable(feature = "vec-deque-partial-eq-slice", since = "1.16.0")] + #[stable(feature = "vec-deque-partial-eq-slice", since = "1.17.0")] impl<'a, 'b, A: $Bound, B> PartialEq<$Rhs> for $Lhs where A: PartialEq { fn eq(&self, other: &$Rhs) -> bool { if self.len() != other.len() { diff --git a/src/libcompiler_builtins/build.rs b/src/libcompiler_builtins/build.rs index bcd3a92dd430..8fe79057bd81 100644 --- a/src/libcompiler_builtins/build.rs +++ b/src/libcompiler_builtins/build.rs @@ -293,6 +293,12 @@ fn main() { } if target.contains("arm") && !target.contains("ios") { + // (At least) udivsi3.S is broken for Thumb 1 which our gcc uses by + // default, we don't want Thumb 2 since it isn't supported on some + // devices, so disable thumb entirely. + // Upstream bug: https://bugs.llvm.org/show_bug.cgi?id=32492 + cfg.define("__ARM_ARCH_ISA_THUMB", Some("0")); + sources.extend(&["arm/aeabi_cdcmp.S", "arm/aeabi_cdcmpeq_check_nan.c", "arm/aeabi_cfcmp.S", diff --git a/src/libcompiler_builtins/lib.rs b/src/libcompiler_builtins/lib.rs index 58aba11e4394..09b3d6395070 100644 --- a/src/libcompiler_builtins/lib.rs +++ b/src/libcompiler_builtins/lib.rs @@ -180,7 +180,7 @@ pub mod reimpls { sr = sr.wrapping_add(1); // 1 <= sr <= u64::bits() - 1 - q = n.wrapping_shl(64u32.wrapping_sub(sr)); + q = n.wrapping_shl(128u32.wrapping_sub(sr)); r = n.wrapping_shr(sr); } else { if d.high() == 0 { diff --git a/src/libcore/Cargo.toml b/src/libcore/Cargo.toml index e847c7fa3a0e..5af63aa970f2 100644 --- a/src/libcore/Cargo.toml +++ b/src/libcore/Cargo.toml @@ -10,8 +10,8 @@ test = false bench = false [[test]] -name = "coretest" -path = "../libcoretest/lib.rs" +name = "coretests" +path = "../libcore/tests/lib.rs" [[bench]] name = "corebenches" diff --git a/src/libcore/benches/num/flt2dec/mod.rs b/src/libcore/benches/num/flt2dec/mod.rs index 1de2bf4921f5..7f3b98a1c761 100644 --- a/src/libcore/benches/num/flt2dec/mod.rs +++ b/src/libcore/benches/num/flt2dec/mod.rs @@ -13,6 +13,10 @@ mod strategy { mod grisu; } +use std::f64; +use std::io::Write; +use std::vec::Vec; +use test::Bencher; use core::num::flt2dec::{decode, DecodableFloat, FullDecoded, Decoded}; use core::num::flt2dec::MAX_SIG_DIGITS; @@ -22,3 +26,23 @@ pub fn decode_finite(v: T) -> Decoded { full_decoded => panic!("expected finite, got {:?} instead", full_decoded) } } + +#[bench] +fn bench_small_shortest(b: &mut Bencher) { + let mut buf = Vec::with_capacity(20); + + b.iter(|| { + buf.clear(); + write!(&mut buf, "{}", 3.1415926f64).unwrap() + }); +} + +#[bench] +fn bench_big_shortest(b: &mut Bencher) { + let mut buf = Vec::with_capacity(300); + + b.iter(|| { + buf.clear(); + write!(&mut buf, "{}", f64::MAX).unwrap() + }); +} diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 0186d9727828..f62057b3a52d 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -310,26 +310,6 @@ impl Cell { } } - /// Returns a reference to the underlying `UnsafeCell`. - /// - /// # Examples - /// - /// ``` - /// #![feature(as_unsafe_cell)] - /// - /// use std::cell::Cell; - /// - /// let c = Cell::new(5); - /// - /// let uc = c.as_unsafe_cell(); - /// ``` - #[inline] - #[unstable(feature = "as_unsafe_cell", issue = "27708")] - #[rustc_deprecated(since = "1.12.0", reason = "renamed to as_ptr")] - pub fn as_unsafe_cell(&self) -> &UnsafeCell { - &self.value - } - /// Returns a raw pointer to the underlying data in this cell. /// /// # Examples @@ -480,20 +460,6 @@ pub struct RefCell { value: UnsafeCell, } -/// An enumeration of values returned from the `state` method on a `RefCell`. -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -#[unstable(feature = "borrow_state", issue = "27733")] -#[rustc_deprecated(since = "1.15.0", reason = "use `try_borrow` instead")] -#[allow(deprecated)] -pub enum BorrowState { - /// The cell is currently being read, there is at least one active `borrow`. - Reading, - /// The cell is currently being written to, there is an active `borrow_mut`. - Writing, - /// There are no outstanding borrows on this cell. - Unused, -} - /// An error returned by [`RefCell::try_borrow`](struct.RefCell.html#method.try_borrow). #[stable(feature = "try_borrow", since = "1.13.0")] pub struct BorrowError { @@ -582,38 +548,6 @@ impl RefCell { } impl RefCell { - /// Query the current state of this `RefCell` - /// - /// The returned value can be dispatched on to determine if a call to - /// `borrow` or `borrow_mut` would succeed. - /// - /// # Examples - /// - /// ``` - /// #![feature(borrow_state)] - /// - /// use std::cell::{BorrowState, RefCell}; - /// - /// let c = RefCell::new(5); - /// - /// match c.borrow_state() { - /// BorrowState::Writing => println!("Cannot be borrowed"), - /// BorrowState::Reading => println!("Cannot be borrowed mutably"), - /// BorrowState::Unused => println!("Can be borrowed (mutably as well)"), - /// } - /// ``` - #[unstable(feature = "borrow_state", issue = "27733")] - #[rustc_deprecated(since = "1.15.0", reason = "use `try_borrow` instead")] - #[allow(deprecated)] - #[inline] - pub fn borrow_state(&self) -> BorrowState { - match self.borrow.get() { - WRITING => BorrowState::Writing, - UNUSED => BorrowState::Unused, - _ => BorrowState::Reading, - } - } - /// Immutably borrows the wrapped value. /// /// The borrow lasts until the returned `Ref` exits scope. Multiple @@ -769,29 +703,6 @@ impl RefCell { } } - /// Returns a reference to the underlying `UnsafeCell`. - /// - /// This can be used to circumvent `RefCell`'s safety checks. - /// - /// This function is `unsafe` because `UnsafeCell`'s field is public. - /// - /// # Examples - /// - /// ``` - /// #![feature(as_unsafe_cell)] - /// - /// use std::cell::RefCell; - /// - /// let c = RefCell::new(5); - /// let c = unsafe { c.as_unsafe_cell() }; - /// ``` - #[inline] - #[unstable(feature = "as_unsafe_cell", issue = "27708")] - #[rustc_deprecated(since = "1.12.0", reason = "renamed to as_ptr")] - pub unsafe fn as_unsafe_cell(&self) -> &UnsafeCell { - &self.value - } - /// Returns a raw pointer to the underlying data in this cell. /// /// # Examples @@ -814,6 +725,15 @@ impl RefCell { /// This call borrows `RefCell` mutably (at compile-time) so there is no /// need for dynamic checks. /// + /// However be cautious: this method expects `self` to be mutable, which is + /// generally not the case when using a `RefCell`. Take a look at the + /// [`borrow_mut`] method instead if `self` isn't mutable. + /// + /// Also, please be aware that this method is only for special circumstances and is usually + /// not you want. In case of doubt, use [`borrow_mut`] instead. + /// + /// [`borrow_mut`]: #method.borrow_mut + /// /// # Examples /// /// ``` diff --git a/src/libcore/char.rs b/src/libcore/char.rs index 19e69ca296d8..98268e3813fa 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -19,6 +19,7 @@ use char_private::is_printable; use convert::TryFrom; use fmt::{self, Write}; use slice; +use str::from_utf8_unchecked_mut; use iter::FusedIterator; use mem::transmute; @@ -187,7 +188,7 @@ impl From for u32 { /// with the character encoding that IANA calls ISO-8859-1. /// This encoding is compatible with ASCII. /// -/// Note that this is different from ISO/IEC 8859-1 a.k.a. ISO 8859-1 (with one less hypen), +/// Note that this is different from ISO/IEC 8859-1 a.k.a. ISO 8859-1 (with one less hyphen), /// which leaves some "blanks", byte values that are not assigned to any character. /// ISO-8859-1 (the IANA one) assigns them to the C0 and C1 control codes. /// @@ -448,7 +449,7 @@ impl CharExt for char { code, dst.len()) }; - transmute(slice::from_raw_parts_mut(dst.as_mut_ptr(), len)) + from_utf8_unchecked_mut(dst.get_unchecked_mut(..len)) } } diff --git a/src/libcore/char_private.rs b/src/libcore/char_private.rs index ddc473592a26..2c0f449b2760 100644 --- a/src/libcore/char_private.rs +++ b/src/libcore/char_private.rs @@ -11,38 +11,49 @@ // NOTE: The following code was generated by "src/etc/char_private.py", // do not edit directly! -use slice::SliceExt; - -fn check(x: u16, singletons: &[u16], normal: &[u16]) -> bool { - for &s in singletons { - if x == s { - return false; - } else if x < s { - break; - } - } - for w in normal.chunks(2) { - let start = w[0]; - let len = w[1]; - let difference = (x as i32) - (start as i32); - if 0 <= difference { - if difference < len as i32 { - return false; +fn check(x: u16, singletonuppers: &[(u8, u8)], singletonlowers: &[u8], + normal: &[u8]) -> bool { + let xupper = (x >> 8) as u8; + let mut lowerstart = 0; + for &(upper, lowercount) in singletonuppers { + let lowerend = lowerstart + lowercount as usize; + if xupper == upper { + for &lower in &singletonlowers[lowerstart..lowerend] { + if lower == x as u8 { + return false; + } } - } else { + } else if xupper < upper { break; } + lowerstart = lowerend; } - true + + let mut x = x as i32; + let mut normal = normal.iter().cloned(); + let mut current = true; + while let Some(v) = normal.next() { + let len = if v & 0x80 != 0 { + ((v & 0x7f) as i32) << 8 | normal.next().unwrap() as i32 + } else { + v as i32 + }; + x -= len; + if x < 0 { + break; + } + current = !current; + } + current } pub fn is_printable(x: char) -> bool { let x = x as u32; let lower = x as u16; if x < 0x10000 { - check(lower, SINGLETONS0, NORMAL0) + check(lower, SINGLETONS0U, SINGLETONS0L, NORMAL0) } else if x < 0x20000 { - check(lower, SINGLETONS1, NORMAL1) + check(lower, SINGLETONS1U, SINGLETONS1L, NORMAL1) } else { if 0x2a6d7 <= x && x < 0x2a700 { return false; @@ -66,761 +77,446 @@ pub fn is_printable(x: char) -> bool { } } -const SINGLETONS0: &'static [u16] = &[ - 0xad, - 0x378, - 0x379, - 0x38b, - 0x38d, - 0x3a2, - 0x530, - 0x557, - 0x558, - 0x560, - 0x588, - 0x58b, - 0x58c, - 0x590, - 0x61c, - 0x61d, - 0x6dd, - 0x70e, - 0x70f, - 0x74b, - 0x74c, - 0x82e, - 0x82f, - 0x83f, - 0x85c, - 0x85d, - 0x8b5, - 0x8e2, - 0x984, - 0x98d, - 0x98e, - 0x991, - 0x992, - 0x9a9, - 0x9b1, - 0x9ba, - 0x9bb, - 0x9c5, - 0x9c6, - 0x9c9, - 0x9ca, - 0x9de, - 0x9e4, - 0x9e5, - 0xa04, - 0xa11, - 0xa12, - 0xa29, - 0xa31, - 0xa34, - 0xa37, - 0xa3a, - 0xa3b, - 0xa3d, - 0xa49, - 0xa4a, - 0xa5d, - 0xa84, - 0xa8e, - 0xa92, - 0xaa9, - 0xab1, - 0xab4, - 0xaba, - 0xabb, - 0xac6, - 0xaca, - 0xace, - 0xacf, - 0xae4, - 0xae5, - 0xb04, - 0xb0d, - 0xb0e, - 0xb11, - 0xb12, - 0xb29, - 0xb31, - 0xb34, - 0xb3a, - 0xb3b, - 0xb45, - 0xb46, - 0xb49, - 0xb4a, - 0xb5e, - 0xb64, - 0xb65, - 0xb84, - 0xb91, - 0xb9b, - 0xb9d, - 0xbc9, - 0xbce, - 0xbcf, - 0xc04, - 0xc0d, - 0xc11, - 0xc29, - 0xc45, - 0xc49, - 0xc57, - 0xc64, - 0xc65, - 0xc84, - 0xc8d, - 0xc91, - 0xca9, - 0xcb4, - 0xcba, - 0xcbb, - 0xcc5, - 0xcc9, - 0xcdf, - 0xce4, - 0xce5, - 0xcf0, - 0xd04, - 0xd0d, - 0xd11, - 0xd3b, - 0xd3c, - 0xd45, - 0xd49, - 0xd64, - 0xd65, - 0xd80, - 0xd81, - 0xd84, - 0xdb2, - 0xdbc, - 0xdbe, - 0xdbf, - 0xdd5, - 0xdd7, - 0xdf0, - 0xdf1, - 0xe83, - 0xe85, - 0xe86, - 0xe89, - 0xe8b, - 0xe8c, - 0xe98, - 0xea0, - 0xea4, - 0xea6, - 0xea8, - 0xea9, - 0xeac, - 0xeba, - 0xebe, - 0xebf, - 0xec5, - 0xec7, - 0xece, - 0xecf, - 0xeda, - 0xedb, - 0xf48, - 0xf98, - 0xfbd, - 0xfcd, - 0x10c6, - 0x10ce, - 0x10cf, - 0x1249, - 0x124e, - 0x124f, - 0x1257, - 0x1259, - 0x125e, - 0x125f, - 0x1289, - 0x128e, - 0x128f, - 0x12b1, - 0x12b6, - 0x12b7, - 0x12bf, - 0x12c1, - 0x12c6, - 0x12c7, - 0x12d7, - 0x1311, - 0x1316, - 0x1317, - 0x135b, - 0x135c, - 0x13f6, - 0x13f7, - 0x13fe, - 0x13ff, - 0x1680, - 0x170d, - 0x176d, - 0x1771, - 0x17de, - 0x17df, - 0x180e, - 0x180f, - 0x191f, - 0x196e, - 0x196f, - 0x1a1c, - 0x1a1d, - 0x1a5f, - 0x1a7d, - 0x1a7e, - 0x1aae, - 0x1aaf, - 0x1cf7, - 0x1f16, - 0x1f17, - 0x1f1e, - 0x1f1f, - 0x1f46, - 0x1f47, - 0x1f4e, - 0x1f4f, - 0x1f58, - 0x1f5a, - 0x1f5c, - 0x1f5e, - 0x1f7e, - 0x1f7f, - 0x1fb5, - 0x1fc5, - 0x1fd4, - 0x1fd5, - 0x1fdc, - 0x1ff0, - 0x1ff1, - 0x1ff5, - 0x2072, - 0x2073, - 0x208f, - 0x23ff, - 0x2b74, - 0x2b75, - 0x2b96, - 0x2b97, - 0x2bc9, - 0x2c2f, - 0x2c5f, - 0x2d26, - 0x2d2e, - 0x2d2f, - 0x2da7, - 0x2daf, - 0x2db7, - 0x2dbf, - 0x2dc7, - 0x2dcf, - 0x2dd7, - 0x2ddf, - 0x2e9a, - 0x3040, - 0x3097, - 0x3098, - 0x318f, - 0x321f, - 0x32ff, - 0xa7af, - 0xa8fe, - 0xa8ff, - 0xa9ce, - 0xa9ff, - 0xaa4e, - 0xaa4f, - 0xaa5a, - 0xaa5b, - 0xab07, - 0xab08, - 0xab0f, - 0xab10, - 0xab27, - 0xab2f, - 0xabee, - 0xabef, - 0xfa6e, - 0xfa6f, - 0xfb37, - 0xfb3d, - 0xfb3f, - 0xfb42, - 0xfb45, - 0xfd90, - 0xfd91, - 0xfdfe, - 0xfdff, - 0xfe53, - 0xfe67, - 0xfe75, - 0xffc8, - 0xffc9, - 0xffd0, - 0xffd1, - 0xffd8, - 0xffd9, - 0xffe7, - 0xfffe, - 0xffff, +const SINGLETONS0U: &'static [(u8, u8)] = &[ + (0x00, 1), + (0x03, 5), + (0x05, 8), + (0x06, 3), + (0x07, 4), + (0x08, 7), + (0x09, 16), + (0x0a, 27), + (0x0b, 24), + (0x0c, 22), + (0x0d, 20), + (0x0e, 22), + (0x0f, 4), + (0x10, 3), + (0x12, 18), + (0x13, 9), + (0x16, 1), + (0x17, 5), + (0x18, 2), + (0x19, 3), + (0x1a, 7), + (0x1c, 1), + (0x1f, 22), + (0x20, 3), + (0x23, 1), + (0x2b, 5), + (0x2c, 2), + (0x2d, 11), + (0x2e, 1), + (0x30, 3), + (0x31, 1), + (0x32, 2), + (0xa7, 1), + (0xa8, 2), + (0xa9, 2), + (0xaa, 4), + (0xab, 8), + (0xfa, 2), + (0xfb, 5), + (0xfd, 4), + (0xfe, 3), + (0xff, 9), ]; -const SINGLETONS1: &'static [u16] = &[ - 0xc, - 0x27, - 0x3b, - 0x3e, - 0x4e, - 0x4f, - 0x18f, - 0x39e, - 0x49e, - 0x49f, - 0x806, - 0x807, - 0x809, - 0x836, - 0x83d, - 0x83e, - 0x856, - 0x8f3, - 0x9d0, - 0x9d1, - 0xa04, - 0xa14, - 0xa18, - 0xb56, - 0xb57, - 0x10bd, - 0x1135, - 0x11ce, - 0x11cf, - 0x11e0, - 0x1212, - 0x1287, - 0x1289, - 0x128e, - 0x129e, - 0x1304, - 0x130d, - 0x130e, - 0x1311, - 0x1312, - 0x1329, - 0x1331, - 0x1334, - 0x133a, - 0x133b, - 0x1345, - 0x1346, - 0x1349, - 0x134a, - 0x134e, - 0x134f, - 0x1364, - 0x1365, - 0x145a, - 0x145c, - 0x15b6, - 0x15b7, - 0x1c09, - 0x1c37, - 0x1c90, - 0x1c91, - 0x1ca8, - 0x246f, - 0x6a5f, - 0x6aee, - 0x6aef, - 0x6b5a, - 0x6b62, - 0xbc9a, - 0xbc9b, - 0xd127, - 0xd128, - 0xd455, - 0xd49d, - 0xd4a0, - 0xd4a1, - 0xd4a3, - 0xd4a4, - 0xd4a7, - 0xd4a8, - 0xd4ad, - 0xd4ba, - 0xd4bc, - 0xd4c4, - 0xd506, - 0xd50b, - 0xd50c, - 0xd515, - 0xd51d, - 0xd53a, - 0xd53f, - 0xd545, - 0xd551, - 0xd6a6, - 0xd6a7, - 0xd7cc, - 0xd7cd, - 0xdaa0, - 0xe007, - 0xe019, - 0xe01a, - 0xe022, - 0xe025, - 0xe8c5, - 0xe8c6, - 0xee04, - 0xee20, - 0xee23, - 0xee25, - 0xee26, - 0xee28, - 0xee33, - 0xee38, - 0xee3a, - 0xee48, - 0xee4a, - 0xee4c, - 0xee50, - 0xee53, - 0xee55, - 0xee56, - 0xee58, - 0xee5a, - 0xee5c, - 0xee5e, - 0xee60, - 0xee63, - 0xee65, - 0xee66, - 0xee6b, - 0xee73, - 0xee78, - 0xee7d, - 0xee7f, - 0xee8a, - 0xeea4, - 0xeeaa, - 0xf0af, - 0xf0b0, - 0xf0c0, - 0xf0d0, - 0xf12f, - 0xf91f, - 0xf931, - 0xf932, - 0xf93f, +const SINGLETONS0L: &'static [u8] = &[ + 0xad, 0x78, 0x79, 0x8b, 0x8d, 0xa2, 0x30, 0x57, + 0x58, 0x60, 0x88, 0x8b, 0x8c, 0x90, 0x1c, 0x1d, + 0xdd, 0x0e, 0x0f, 0x4b, 0x4c, 0x2e, 0x2f, 0x3f, + 0x5c, 0x5d, 0xb5, 0xe2, 0x84, 0x8d, 0x8e, 0x91, + 0x92, 0xa9, 0xb1, 0xba, 0xbb, 0xc5, 0xc6, 0xc9, + 0xca, 0xde, 0xe4, 0xe5, 0x04, 0x11, 0x12, 0x29, + 0x31, 0x34, 0x37, 0x3a, 0x3b, 0x3d, 0x49, 0x4a, + 0x5d, 0x84, 0x8e, 0x92, 0xa9, 0xb1, 0xb4, 0xba, + 0xbb, 0xc6, 0xca, 0xce, 0xcf, 0xe4, 0xe5, 0x04, + 0x0d, 0x0e, 0x11, 0x12, 0x29, 0x31, 0x34, 0x3a, + 0x3b, 0x45, 0x46, 0x49, 0x4a, 0x5e, 0x64, 0x65, + 0x84, 0x91, 0x9b, 0x9d, 0xc9, 0xce, 0xcf, 0x04, + 0x0d, 0x11, 0x29, 0x45, 0x49, 0x57, 0x64, 0x65, + 0x84, 0x8d, 0x91, 0xa9, 0xb4, 0xba, 0xbb, 0xc5, + 0xc9, 0xdf, 0xe4, 0xe5, 0xf0, 0x04, 0x0d, 0x11, + 0x3b, 0x3c, 0x45, 0x49, 0x64, 0x65, 0x80, 0x81, + 0x84, 0xb2, 0xbc, 0xbe, 0xbf, 0xd5, 0xd7, 0xf0, + 0xf1, 0x83, 0x85, 0x86, 0x89, 0x8b, 0x8c, 0x98, + 0xa0, 0xa4, 0xa6, 0xa8, 0xa9, 0xac, 0xba, 0xbe, + 0xbf, 0xc5, 0xc7, 0xce, 0xcf, 0xda, 0xdb, 0x48, + 0x98, 0xbd, 0xcd, 0xc6, 0xce, 0xcf, 0x49, 0x4e, + 0x4f, 0x57, 0x59, 0x5e, 0x5f, 0x89, 0x8e, 0x8f, + 0xb1, 0xb6, 0xb7, 0xbf, 0xc1, 0xc6, 0xc7, 0xd7, + 0x11, 0x16, 0x17, 0x5b, 0x5c, 0xf6, 0xf7, 0xfe, + 0xff, 0x80, 0x0d, 0x6d, 0x71, 0xde, 0xdf, 0x0e, + 0x0f, 0x1f, 0x6e, 0x6f, 0x1c, 0x1d, 0x5f, 0x7d, + 0x7e, 0xae, 0xaf, 0xf7, 0x16, 0x17, 0x1e, 0x1f, + 0x46, 0x47, 0x4e, 0x4f, 0x58, 0x5a, 0x5c, 0x5e, + 0x7e, 0x7f, 0xb5, 0xc5, 0xd4, 0xd5, 0xdc, 0xf0, + 0xf1, 0xf5, 0x72, 0x73, 0x8f, 0xff, 0x74, 0x75, + 0x96, 0x97, 0xc9, 0x2f, 0x5f, 0x26, 0x2e, 0x2f, + 0xa7, 0xaf, 0xb7, 0xbf, 0xc7, 0xcf, 0xd7, 0xdf, + 0x9a, 0x40, 0x97, 0x98, 0x8f, 0x1f, 0xff, 0xaf, + 0xfe, 0xff, 0xce, 0xff, 0x4e, 0x4f, 0x5a, 0x5b, + 0x07, 0x08, 0x0f, 0x10, 0x27, 0x2f, 0xee, 0xef, + 0x6e, 0x6f, 0x37, 0x3d, 0x3f, 0x42, 0x45, 0x90, + 0x91, 0xfe, 0xff, 0x53, 0x67, 0x75, 0xc8, 0xc9, + 0xd0, 0xd1, 0xd8, 0xd9, 0xe7, 0xfe, 0xff, ]; -const NORMAL0: &'static [u16] = &[ - 0x0, 0x20, - 0x7f, 0x22, - 0x380, 0x4, - 0x5c8, 0x8, - 0x5eb, 0x5, - 0x5f5, 0x11, - 0x7b2, 0xe, - 0x7fb, 0x5, - 0x85f, 0x41, - 0x8be, 0x16, - 0x9b3, 0x3, - 0x9cf, 0x8, - 0x9d8, 0x4, - 0x9fc, 0x5, - 0xa0b, 0x4, - 0xa43, 0x4, - 0xa4e, 0x3, - 0xa52, 0x7, - 0xa5f, 0x7, - 0xa76, 0xb, - 0xad1, 0xf, - 0xaf2, 0x7, - 0xafa, 0x7, - 0xb4e, 0x8, - 0xb58, 0x4, - 0xb78, 0xa, - 0xb8b, 0x3, - 0xb96, 0x3, - 0xba0, 0x3, - 0xba5, 0x3, - 0xbab, 0x3, - 0xbba, 0x4, - 0xbc3, 0x3, - 0xbd1, 0x6, - 0xbd8, 0xe, - 0xbfb, 0x5, - 0xc3a, 0x3, - 0xc4e, 0x7, - 0xc5b, 0x5, - 0xc70, 0x8, - 0xcce, 0x7, - 0xcd7, 0x7, - 0xcf3, 0xe, - 0xd50, 0x4, - 0xd97, 0x3, - 0xdc7, 0x3, - 0xdcb, 0x4, - 0xde0, 0x6, - 0xdf5, 0xc, - 0xe3b, 0x4, - 0xe5c, 0x25, - 0xe8e, 0x6, - 0xee0, 0x20, - 0xf6d, 0x4, - 0xfdb, 0x25, - 0x10c8, 0x5, - 0x137d, 0x3, - 0x139a, 0x6, - 0x169d, 0x3, - 0x16f9, 0x7, - 0x1715, 0xb, - 0x1737, 0x9, - 0x1754, 0xc, - 0x1774, 0xc, - 0x17ea, 0x6, - 0x17fa, 0x6, - 0x181a, 0x6, - 0x1878, 0x8, - 0x18ab, 0x5, - 0x18f6, 0xa, - 0x192c, 0x4, - 0x193c, 0x4, - 0x1941, 0x3, - 0x1975, 0xb, - 0x19ac, 0x4, - 0x19ca, 0x6, - 0x19db, 0x3, - 0x1a8a, 0x6, - 0x1a9a, 0x6, - 0x1abf, 0x41, - 0x1b4c, 0x4, - 0x1b7d, 0x3, - 0x1bf4, 0x8, - 0x1c38, 0x3, - 0x1c4a, 0x3, - 0x1c89, 0x37, - 0x1cc8, 0x8, - 0x1cfa, 0x6, - 0x1df6, 0x5, - 0x1fff, 0x11, - 0x2028, 0x8, - 0x205f, 0x11, - 0x209d, 0x3, - 0x20bf, 0x11, - 0x20f1, 0xf, - 0x218c, 0x4, - 0x2427, 0x19, - 0x244b, 0x15, - 0x2bba, 0x3, - 0x2bd2, 0x1a, - 0x2bf0, 0x10, - 0x2cf4, 0x5, - 0x2d28, 0x5, - 0x2d68, 0x7, - 0x2d71, 0xe, - 0x2d97, 0x9, - 0x2e45, 0x3b, - 0x2ef4, 0xc, - 0x2fd6, 0x1a, - 0x2ffc, 0x5, - 0x3100, 0x5, - 0x312e, 0x3, - 0x31bb, 0x5, - 0x31e4, 0xc, - 0x4db6, 0xa, - 0x9fd6, 0x2a, - 0xa48d, 0x3, - 0xa4c7, 0x9, - 0xa62c, 0x14, - 0xa6f8, 0x8, - 0xa7b8, 0x3f, - 0xa82c, 0x4, - 0xa83a, 0x6, - 0xa878, 0x8, - 0xa8c6, 0x8, - 0xa8da, 0x6, - 0xa954, 0xb, - 0xa97d, 0x3, - 0xa9da, 0x4, - 0xaa37, 0x9, - 0xaac3, 0x18, - 0xaaf7, 0xa, - 0xab17, 0x9, - 0xab66, 0xa, - 0xabfa, 0x6, - 0xd7a4, 0xc, - 0xd7c7, 0x4, - 0xd7fc, 0x2104, - 0xfada, 0x26, - 0xfb07, 0xc, - 0xfb18, 0x5, - 0xfbc2, 0x11, - 0xfd40, 0x10, - 0xfdc8, 0x28, - 0xfe1a, 0x6, - 0xfe6c, 0x4, - 0xfefd, 0x4, - 0xffbf, 0x3, - 0xffdd, 0x3, - 0xffef, 0xd, +const SINGLETONS1U: &'static [(u8, u8)] = &[ + (0x00, 6), + (0x01, 1), + (0x03, 1), + (0x04, 2), + (0x08, 8), + (0x09, 2), + (0x0a, 3), + (0x0b, 2), + (0x10, 1), + (0x11, 4), + (0x12, 5), + (0x13, 18), + (0x14, 2), + (0x15, 2), + (0x1c, 5), + (0x24, 1), + (0x6a, 3), + (0x6b, 2), + (0xbc, 2), + (0xd1, 2), + (0xd4, 12), + (0xd5, 9), + (0xd6, 2), + (0xd7, 2), + (0xda, 1), + (0xe0, 5), + (0xe8, 2), + (0xee, 32), + (0xf0, 4), + (0xf1, 1), + (0xf9, 4), ]; -const NORMAL1: &'static [u16] = &[ +const SINGLETONS1L: &'static [u8] = &[ + 0x0c, 0x27, 0x3b, 0x3e, 0x4e, 0x4f, 0x8f, 0x9e, + 0x9e, 0x9f, 0x06, 0x07, 0x09, 0x36, 0x3d, 0x3e, + 0x56, 0xf3, 0xd0, 0xd1, 0x04, 0x14, 0x18, 0x56, + 0x57, 0xbd, 0x35, 0xce, 0xcf, 0xe0, 0x12, 0x87, + 0x89, 0x8e, 0x9e, 0x04, 0x0d, 0x0e, 0x11, 0x12, + 0x29, 0x31, 0x34, 0x3a, 0x3b, 0x45, 0x46, 0x49, + 0x4a, 0x4e, 0x4f, 0x64, 0x65, 0x5a, 0x5c, 0xb6, + 0xb7, 0x09, 0x37, 0x90, 0x91, 0xa8, 0x6f, 0x5f, + 0xee, 0xef, 0x5a, 0x62, 0x9a, 0x9b, 0x27, 0x28, + 0x55, 0x9d, 0xa0, 0xa1, 0xa3, 0xa4, 0xa7, 0xa8, + 0xad, 0xba, 0xbc, 0xc4, 0x06, 0x0b, 0x0c, 0x15, + 0x1d, 0x3a, 0x3f, 0x45, 0x51, 0xa6, 0xa7, 0xcc, + 0xcd, 0xa0, 0x07, 0x19, 0x1a, 0x22, 0x25, 0xc5, + 0xc6, 0x04, 0x20, 0x23, 0x25, 0x26, 0x28, 0x33, + 0x38, 0x3a, 0x48, 0x4a, 0x4c, 0x50, 0x53, 0x55, + 0x56, 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x63, 0x65, + 0x66, 0x6b, 0x73, 0x78, 0x7d, 0x7f, 0x8a, 0xa4, + 0xaa, 0xaf, 0xb0, 0xc0, 0xd0, 0x2f, 0x1f, 0x31, + 0x32, 0x3f, +]; +const NORMAL0: &'static [u8] = &[ + 0x00, 0x20, + 0x5f, 0x22, + 0x82, 0xdf, 0x04, + 0x82, 0x44, 0x08, + 0x1b, 0x05, + 0x05, 0x11, + 0x81, 0xac, 0x0e, + 0x3b, 0x05, + 0x5f, 0x41, + 0x1e, 0x16, + 0x80, 0xdf, 0x03, + 0x19, 0x08, + 0x01, 0x04, + 0x20, 0x05, + 0x0a, 0x04, + 0x34, 0x04, + 0x07, 0x03, + 0x01, 0x07, + 0x06, 0x07, + 0x10, 0x0b, + 0x50, 0x0f, + 0x12, 0x07, + 0x01, 0x07, + 0x4d, 0x08, + 0x02, 0x04, + 0x1c, 0x0a, + 0x09, 0x03, + 0x08, 0x03, + 0x07, 0x03, + 0x02, 0x03, + 0x03, 0x03, + 0x0c, 0x04, + 0x05, 0x03, + 0x0b, 0x06, + 0x01, 0x0e, + 0x15, 0x05, + 0x3a, 0x03, + 0x11, 0x07, + 0x06, 0x05, + 0x10, 0x08, + 0x56, 0x07, + 0x02, 0x07, + 0x15, 0x0e, + 0x4f, 0x04, + 0x43, 0x03, + 0x2d, 0x03, + 0x01, 0x04, + 0x11, 0x06, + 0x0f, 0x0c, + 0x3a, 0x04, + 0x1d, 0x25, + 0x0d, 0x06, + 0x4c, 0x20, + 0x6d, 0x04, + 0x6a, 0x25, + 0x80, 0xc8, 0x05, + 0x82, 0xb0, 0x03, + 0x1a, 0x06, + 0x82, 0xfd, 0x03, + 0x59, 0x07, + 0x15, 0x0b, + 0x17, 0x09, + 0x14, 0x0c, + 0x14, 0x0c, + 0x6a, 0x06, + 0x0a, 0x06, + 0x1a, 0x06, + 0x58, 0x08, + 0x2b, 0x05, + 0x46, 0x0a, + 0x2c, 0x04, + 0x0c, 0x04, + 0x01, 0x03, + 0x31, 0x0b, + 0x2c, 0x04, + 0x1a, 0x06, + 0x0b, 0x03, + 0x80, 0xac, 0x06, + 0x0a, 0x06, + 0x1f, 0x41, + 0x4c, 0x04, + 0x2d, 0x03, + 0x74, 0x08, + 0x3c, 0x03, + 0x0f, 0x03, + 0x3c, 0x37, + 0x08, 0x08, + 0x2a, 0x06, + 0x80, 0xf6, 0x05, + 0x82, 0x04, 0x11, + 0x18, 0x08, + 0x2f, 0x11, + 0x2d, 0x03, + 0x1f, 0x11, + 0x21, 0x0f, + 0x80, 0x8c, 0x04, + 0x82, 0x97, 0x19, + 0x0b, 0x15, + 0x87, 0x5a, 0x03, + 0x15, 0x1a, + 0x04, 0x10, + 0x80, 0xf4, 0x05, + 0x2f, 0x05, + 0x3b, 0x07, + 0x02, 0x0e, + 0x18, 0x09, + 0x80, 0xa5, 0x3b, + 0x74, 0x0c, + 0x80, 0xd6, 0x1a, + 0x0c, 0x05, + 0x80, 0xff, 0x05, + 0x29, 0x03, + 0x80, 0x8a, 0x05, + 0x24, 0x0c, + 0x9b, 0xc6, 0x0a, + 0xd2, 0x16, 0x2a, + 0x84, 0x8d, 0x03, + 0x37, 0x09, + 0x81, 0x5c, 0x14, + 0x80, 0xb8, 0x08, + 0x80, 0xb8, 0x3f, + 0x35, 0x04, + 0x0a, 0x06, + 0x38, 0x08, + 0x46, 0x08, + 0x0c, 0x06, + 0x74, 0x0b, + 0x1e, 0x03, + 0x5a, 0x04, + 0x59, 0x09, + 0x80, 0x83, 0x18, + 0x1c, 0x0a, + 0x16, 0x09, + 0x46, 0x0a, + 0x80, 0x8a, 0x06, + 0xab, 0xa4, 0x0c, + 0x17, 0x04, + 0x31, 0xa1, 0x04, + 0x81, 0xda, 0x26, + 0x07, 0x0c, + 0x05, 0x05, + 0x80, 0xa5, 0x11, + 0x81, 0x6d, 0x10, + 0x78, 0x28, + 0x2a, 0x06, + 0x4c, 0x04, + 0x80, 0x8d, 0x04, + 0x80, 0xbe, 0x03, + 0x1b, 0x03, + 0x0f, 0x0d, +]; +const NORMAL1: &'static [u8] = &[ 0x5e, 0x22, - 0xfb, 0x5, - 0x103, 0x4, - 0x134, 0x3, - 0x19c, 0x4, - 0x1a1, 0x2f, - 0x1fe, 0x82, - 0x29d, 0x3, - 0x2d1, 0xf, - 0x2fc, 0x4, - 0x324, 0xc, - 0x34b, 0x5, - 0x37b, 0x5, - 0x3c4, 0x4, - 0x3d6, 0x2a, - 0x4aa, 0x6, - 0x4d4, 0x4, - 0x4fc, 0x4, - 0x528, 0x8, - 0x564, 0xb, - 0x570, 0x90, - 0x737, 0x9, - 0x756, 0xa, - 0x768, 0x98, - 0x839, 0x3, - 0x89f, 0x8, - 0x8b0, 0x30, - 0x8f6, 0x5, - 0x91c, 0x3, - 0x93a, 0x5, - 0x940, 0x40, - 0x9b8, 0x4, - 0xa07, 0x5, - 0xa34, 0x4, - 0xa3b, 0x4, - 0xa48, 0x8, - 0xa59, 0x7, - 0xaa0, 0x20, - 0xae7, 0x4, - 0xaf7, 0x9, - 0xb36, 0x3, - 0xb73, 0x5, - 0xb92, 0x7, - 0xb9d, 0xc, - 0xbb0, 0x50, - 0xc49, 0x37, - 0xcb3, 0xd, - 0xcf3, 0x7, - 0xd00, 0x160, - 0xe7f, 0x181, - 0x104e, 0x4, - 0x1070, 0xf, - 0x10c2, 0xe, - 0x10e9, 0x7, - 0x10fa, 0x6, - 0x1144, 0xc, - 0x1177, 0x9, - 0x11f5, 0xb, - 0x123f, 0x41, - 0x12aa, 0x6, - 0x12eb, 0x5, - 0x12fa, 0x6, - 0x1351, 0x6, - 0x1358, 0x5, - 0x136d, 0x3, - 0x1375, 0x8b, - 0x145e, 0x22, - 0x14c8, 0x8, - 0x14da, 0xa6, - 0x15de, 0x22, - 0x1645, 0xb, - 0x165a, 0x6, - 0x166d, 0x13, - 0x16b8, 0x8, - 0x16ca, 0x36, - 0x171a, 0x3, - 0x172c, 0x4, - 0x1740, 0x160, - 0x18f3, 0xc, - 0x1900, 0x1c0, - 0x1af9, 0x107, - 0x1c46, 0xa, - 0x1c6d, 0x3, - 0x1cb7, 0x349, - 0x239a, 0x66, - 0x2475, 0xb, - 0x2544, 0xabc, - 0x342f, 0xfd1, - 0x4647, 0x21b9, - 0x6a39, 0x7, - 0x6a6a, 0x4, - 0x6a70, 0x60, - 0x6af6, 0xa, - 0x6b46, 0xa, - 0x6b78, 0x5, - 0x6b90, 0x370, - 0x6f45, 0xb, - 0x6f7f, 0x10, - 0x6fa0, 0x40, - 0x6fe1, 0x1f, - 0x87ed, 0x13, - 0x8af3, 0x250d, - 0xb002, 0xbfe, - 0xbc6b, 0x5, - 0xbc7d, 0x3, - 0xbc89, 0x7, - 0xbca0, 0x1360, - 0xd0f6, 0xa, - 0xd173, 0x8, - 0xd1e9, 0x17, - 0xd246, 0xba, - 0xd357, 0x9, - 0xd372, 0x8e, - 0xd547, 0x3, - 0xda8c, 0xf, - 0xdab0, 0x550, - 0xe02b, 0x7d5, - 0xe8d7, 0x29, - 0xe94b, 0x5, - 0xe95a, 0x4, - 0xe960, 0x4a0, - 0xee3c, 0x6, - 0xee43, 0x4, - 0xee9c, 0x5, - 0xeebc, 0x34, - 0xeef2, 0x10e, - 0xf02c, 0x4, - 0xf094, 0xc, - 0xf0f6, 0xa, - 0xf10d, 0x3, - 0xf16c, 0x4, - 0xf1ad, 0x39, - 0xf203, 0xd, - 0xf23c, 0x4, - 0xf249, 0x7, - 0xf252, 0xae, - 0xf6d3, 0xd, - 0xf6ed, 0x3, - 0xf6f7, 0x9, - 0xf774, 0xc, - 0xf7d5, 0x2b, - 0xf80c, 0x4, - 0xf848, 0x8, - 0xf85a, 0x6, - 0xf888, 0x8, - 0xf8ae, 0x62, - 0xf928, 0x8, - 0xf94c, 0x4, - 0xf95f, 0x21, - 0xf992, 0x2e, - 0xf9c1, 0x63f, + 0x7b, 0x05, + 0x03, 0x04, + 0x2d, 0x03, + 0x65, 0x04, + 0x01, 0x2f, + 0x2e, 0x80, 0x82, + 0x1d, 0x03, + 0x31, 0x0f, + 0x1c, 0x04, + 0x24, 0x0c, + 0x1b, 0x05, + 0x2b, 0x05, + 0x44, 0x04, + 0x0e, 0x2a, + 0x80, 0xaa, 0x06, + 0x24, 0x04, + 0x24, 0x04, + 0x28, 0x08, + 0x34, 0x0b, + 0x01, 0x80, 0x90, + 0x81, 0x37, 0x09, + 0x16, 0x0a, + 0x08, 0x80, 0x98, + 0x39, 0x03, + 0x63, 0x08, + 0x09, 0x30, + 0x16, 0x05, + 0x21, 0x03, + 0x1b, 0x05, + 0x01, 0x40, + 0x38, 0x04, + 0x4b, 0x05, + 0x28, 0x04, + 0x03, 0x04, + 0x09, 0x08, + 0x09, 0x07, + 0x40, 0x20, + 0x27, 0x04, + 0x0c, 0x09, + 0x36, 0x03, + 0x3a, 0x05, + 0x1a, 0x07, + 0x04, 0x0c, + 0x07, 0x50, + 0x49, 0x37, + 0x33, 0x0d, + 0x33, 0x07, + 0x06, 0x81, 0x60, + 0x1f, 0x81, 0x81, + 0x4e, 0x04, + 0x1e, 0x0f, + 0x43, 0x0e, + 0x19, 0x07, + 0x0a, 0x06, + 0x44, 0x0c, + 0x27, 0x09, + 0x75, 0x0b, + 0x3f, 0x41, + 0x2a, 0x06, + 0x3b, 0x05, + 0x0a, 0x06, + 0x51, 0x06, + 0x01, 0x05, + 0x10, 0x03, + 0x05, 0x80, 0x8b, + 0x5e, 0x22, + 0x48, 0x08, + 0x0a, 0x80, 0xa6, + 0x5e, 0x22, + 0x45, 0x0b, + 0x0a, 0x06, + 0x0d, 0x13, + 0x38, 0x08, + 0x0a, 0x36, + 0x1a, 0x03, + 0x0f, 0x04, + 0x10, 0x81, 0x60, + 0x53, 0x0c, + 0x01, 0x81, 0xc0, + 0x39, 0x81, 0x07, + 0x46, 0x0a, + 0x1d, 0x03, + 0x47, 0x83, 0x49, + 0x83, 0x9a, 0x66, + 0x75, 0x0b, + 0x80, 0xc4, 0x8a, 0xbc, + 0x84, 0x2f, 0x8f, 0xd1, + 0x82, 0x47, 0xa1, 0xb9, + 0x82, 0x39, 0x07, + 0x2a, 0x04, + 0x02, 0x60, + 0x26, 0x0a, + 0x46, 0x0a, + 0x28, 0x05, + 0x13, 0x83, 0x70, + 0x45, 0x0b, + 0x2f, 0x10, + 0x11, 0x40, + 0x01, 0x1f, + 0x97, 0xed, 0x13, + 0x82, 0xf3, 0xa5, 0x0d, + 0x02, 0x8b, 0xfe, + 0x6b, 0x05, + 0x0d, 0x03, + 0x09, 0x07, + 0x10, 0x93, 0x60, + 0x80, 0xf6, 0x0a, + 0x73, 0x08, + 0x6e, 0x17, + 0x46, 0x80, 0xba, + 0x57, 0x09, + 0x12, 0x80, 0x8e, + 0x81, 0x47, 0x03, + 0x85, 0x42, 0x0f, + 0x15, 0x85, 0x50, + 0x2b, 0x87, 0xd5, + 0x80, 0xd7, 0x29, + 0x4b, 0x05, + 0x0a, 0x04, + 0x02, 0x84, 0xa0, + 0x3c, 0x06, + 0x01, 0x04, + 0x55, 0x05, + 0x1b, 0x34, + 0x02, 0x81, 0x0e, + 0x2c, 0x04, + 0x64, 0x0c, + 0x56, 0x0a, + 0x0d, 0x03, + 0x5c, 0x04, + 0x3d, 0x39, + 0x1d, 0x0d, + 0x2c, 0x04, + 0x09, 0x07, + 0x02, 0x80, 0xae, + 0x83, 0xd3, 0x0d, + 0x0d, 0x03, + 0x07, 0x09, + 0x74, 0x0c, + 0x55, 0x2b, + 0x0c, 0x04, + 0x38, 0x08, + 0x0a, 0x06, + 0x28, 0x08, + 0x1e, 0x62, + 0x18, 0x08, + 0x1c, 0x04, + 0x0f, 0x21, + 0x12, 0x2e, + 0x01, 0x86, 0x3f, ]; diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index 7db35359a1f7..d4544dadaeb0 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -102,6 +102,7 @@ use self::Ordering::*; /// ``` #[lang = "eq"] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_on_unimplemented = "can't compare `{Self}` with `{Rhs}`"] pub trait PartialEq { /// This method tests for `self` and `other` values to be equal, and is used /// by `==`. @@ -322,6 +323,50 @@ impl Ordering { } } +/// A helper struct for reverse ordering. +/// +/// This struct is a helper to be used with functions like `Vec::sort_by_key` and +/// can be used to reverse order a part of a key. +/// +/// Example usage: +/// +/// ``` +/// #![feature(reverse_cmp_key)] +/// use std::cmp::Reverse; +/// +/// let mut v = vec![1, 2, 3, 4, 5, 6]; +/// v.sort_by_key(|&num| (num > 3, Reverse(num))); +/// assert_eq!(v, vec![3, 2, 1, 6, 5, 4]); +/// ``` +#[derive(PartialEq, Eq, Debug)] +#[unstable(feature = "reverse_cmp_key", issue = "40893")] +pub struct Reverse(pub T); + +#[unstable(feature = "reverse_cmp_key", issue = "40893")] +impl PartialOrd for Reverse { + #[inline] + fn partial_cmp(&self, other: &Reverse) -> Option { + other.0.partial_cmp(&self.0) + } + + #[inline] + fn lt(&self, other: &Self) -> bool { other.0 < self.0 } + #[inline] + fn le(&self, other: &Self) -> bool { other.0 <= self.0 } + #[inline] + fn ge(&self, other: &Self) -> bool { other.0 >= self.0 } + #[inline] + fn gt(&self, other: &Self) -> bool { other.0 > self.0 } +} + +#[unstable(feature = "reverse_cmp_key", issue = "40893")] +impl Ord for Reverse { + #[inline] + fn cmp(&self, other: &Reverse) -> Ordering { + other.0.cmp(&self.0) + } +} + /// Trait for types that form a [total order](https://en.wikipedia.org/wiki/Total_order). /// /// An order is a total order if it is (for all `a`, `b` and `c`): @@ -506,6 +551,7 @@ impl PartialOrd for Ordering { /// ``` #[lang = "ord"] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_on_unimplemented = "can't compare `{Self}` with `{Rhs}`"] pub trait PartialOrd: PartialEq { /// This method returns an ordering between `self` and `other` values if one exists. /// diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs index 0b0f831f093b..21c75ad33951 100644 --- a/src/libcore/convert.rs +++ b/src/libcore/convert.rs @@ -17,8 +17,8 @@ //! Like many traits, these are often used as bounds for generic functions, to //! support arguments of multiple types. //! -//! - Impl the `As*` traits for reference-to-reference conversions -//! - Impl the [`Into`] trait when you want to consume the value in the conversion +//! - Implement the `As*` traits for reference-to-reference conversions +//! - Implement the [`Into`] trait when you want to consume the value in the conversion //! - The [`From`] trait is the most flexible, useful for value _and_ reference conversions //! - The [`TryFrom`] and [`TryInto`] traits behave like [`From`] and [`Into`], but allow for the //! conversion to fail @@ -26,16 +26,16 @@ //! As a library author, you should prefer implementing [`From`][`From`] or //! [`TryFrom`][`TryFrom`] rather than [`Into`][`Into`] or [`TryInto`][`TryInto`], //! as [`From`] and [`TryFrom`] provide greater flexibility and offer -//! equivalent [`Into`] or [`TryInto`] implementations for free, thanks to a blanket implementation -//! in the standard library. +//! equivalent [`Into`] or [`TryInto`] implementations for free, thanks to a +//! blanket implementation in the standard library. //! -//! # Generic impl +//! # Generic Implementations //! //! - [`AsRef`] and [`AsMut`] auto-dereference if the inner type is a reference //! - [`From`]` for T` implies [`Into`]` for U` //! - [`TryFrom`]` for T` implies [`TryInto`]` for U` -//! - [`From`] and [`Into`] are reflexive, which means that all types can `into()` -//! themselves and `from()` themselves +//! - [`From`] and [`Into`] are reflexive, which means that all types can +//! `into` themselves and `from` themselves //! //! See each trait for usage examples. //! @@ -50,20 +50,42 @@ use str::FromStr; -/// A cheap, reference-to-reference conversion. +/// A cheap reference-to-reference conversion. Used to convert a value to a +/// reference value within generic code. /// -/// `AsRef` is very similar to, but different than, [`Borrow`]. See -/// [the book][book] for more. +/// `AsRef` is very similar to, but serves a slightly different purpose than, +/// [`Borrow`]. +/// +/// `AsRef` is to be used when wishing to convert to a reference of another +/// type. +/// `Borrow` is more related to the notion of taking the reference. It is +/// useful when wishing to abstract over the type of reference +/// (`&T`, `&mut T`) or allow both the referenced and owned type to be treated +/// in the same manner. +/// +/// The key difference between the two traits is the intention: +/// +/// - Use `AsRef` when goal is to simply convert into a reference +/// - Use `Borrow` when goal is related to writing code that is agnostic to the +/// type of borrow and if is reference or value +/// +/// See [the book][book] for a more detailed comparison. /// /// [book]: ../../book/borrow-and-asref.html /// [`Borrow`]: ../../std/borrow/trait.Borrow.html /// -/// **Note: this trait must not fail**. If the conversion can fail, use a dedicated method which -/// returns an [`Option`] or a [`Result`]. +/// **Note: this trait must not fail**. If the conversion can fail, use a +/// dedicated method which returns an [`Option`] or a [`Result`]. /// /// [`Option`]: ../../std/option/enum.Option.html /// [`Result`]: ../../std/result/enum.Result.html /// +/// # Generic Implementations +/// +/// - `AsRef` auto-dereferences if the inner type is a reference or a mutable +/// reference (e.g.: `foo.as_ref()` will work the same if `foo` has type +/// `&mut Foo` or `&&mut Foo`) +/// /// # Examples /// /// Both [`String`] and `&str` implement `AsRef`: @@ -82,11 +104,6 @@ use str::FromStr; /// is_hello(s); /// ``` /// -/// # Generic Impls -/// -/// - `AsRef` auto-dereferences if the inner type is a reference or a mutable -/// reference (e.g.: `foo.as_ref()` will work the same if `foo` has type `&mut Foo` or `&&mut Foo`) -/// #[stable(feature = "rust1", since = "1.0.0")] pub trait AsRef { /// Performs the conversion. @@ -96,12 +113,21 @@ pub trait AsRef { /// A cheap, mutable reference-to-mutable reference conversion. /// -/// **Note: this trait must not fail**. If the conversion can fail, use a dedicated method which -/// returns an [`Option`] or a [`Result`]. +/// This trait is similar to `AsRef` but used for converting between mutable +/// references. +/// +/// **Note: this trait must not fail**. If the conversion can fail, use a +/// dedicated method which returns an [`Option`] or a [`Result`]. /// /// [`Option`]: ../../std/option/enum.Option.html /// [`Result`]: ../../std/result/enum.Result.html /// +/// # Generic Implementations +/// +/// - `AsMut` auto-dereferences if the inner type is a reference or a mutable +/// reference (e.g.: `foo.as_ref()` will work the same if `foo` has type +/// `&mut Foo` or `&&mut Foo`) +/// /// # Examples /// /// [`Box`] implements `AsMut`: @@ -118,10 +144,6 @@ pub trait AsRef { /// assert_eq!(*boxed_num, 1); /// ``` /// -/// # Generic Impls -/// -/// - `AsMut` auto-dereferences if the inner type is a reference or a mutable -/// reference (e.g.: `foo.as_ref()` will work the same if `foo` has type `&mut Foo` or `&&mut Foo`) /// #[stable(feature = "rust1", since = "1.0.0")] pub trait AsMut { @@ -130,14 +152,22 @@ pub trait AsMut { fn as_mut(&mut self) -> &mut T; } -/// A conversion that consumes `self`, which may or may not be expensive. +/// A conversion that consumes `self`, which may or may not be expensive. The +/// reciprocal of [`From`][From]. /// -/// **Note: this trait must not fail**. If the conversion can fail, use [`TryInto`] or a dedicated -/// method which returns an [`Option`] or a [`Result`]. +/// **Note: this trait must not fail**. If the conversion can fail, use +/// [`TryInto`] or a dedicated method which returns an [`Option`] or a +/// [`Result`]. /// -/// Library authors should not directly implement this trait, but should prefer implementing -/// the [`From`][From] trait, which offers greater flexibility and provides an equivalent `Into` -/// implementation for free, thanks to a blanket implementation in the standard library. +/// Library authors should not directly implement this trait, but should prefer +/// implementing the [`From`][From] trait, which offers greater flexibility and +/// provides an equivalent `Into` implementation for free, thanks to a blanket +/// implementation in the standard library. +/// +/// # Generic Implementations +/// +/// - [`From`][From]` for U` implies `Into for T` +/// - [`into`] is reflexive, which means that `Into for T` is implemented /// /// # Examples /// @@ -153,11 +183,6 @@ pub trait AsMut { /// is_hello(s); /// ``` /// -/// # Generic Impls -/// -/// - [`From`][From]` for U` implies `Into for T` -/// - [`into`] is reflexive, which means that `Into for T` is implemented -/// /// [`TryInto`]: trait.TryInto.html /// [`Option`]: ../../std/option/enum.Option.html /// [`Result`]: ../../std/result/enum.Result.html @@ -171,10 +196,31 @@ pub trait Into: Sized { fn into(self) -> T; } -/// Construct `Self` via a conversion. +/// Simple and safe type conversions in to `Self`. It is the reciprocal of +/// `Into`. /// -/// **Note: this trait must not fail**. If the conversion can fail, use [`TryFrom`] or a dedicated -/// method which returns an [`Option`] or a [`Result`]. +/// This trait is useful when performing error handling as described by +/// [the book][book] and is closely related to the `?` operator. +/// +/// When constructing a function that is capable of failing the return type +/// will generally be of the form `Result`. +/// +/// The `From` trait allows for simplification of error handling by providing a +/// means of returning a single error type that encapsulates numerous possible +/// erroneous situations. +/// +/// This trait is not limited to error handling, rather the general case for +/// this trait would be in any type conversions to have an explicit definition +/// of how they are performed. +/// +/// **Note: this trait must not fail**. If the conversion can fail, use +/// [`TryFrom`] or a dedicated method which returns an [`Option`] or a +/// [`Result`]. +/// +/// # Generic Implementations +/// +/// - `From for U` implies [`Into`]` for T` +/// - [`from`] is reflexive, which means that `From for T` is implemented /// /// # Examples /// @@ -186,10 +232,38 @@ pub trait Into: Sized { /// /// assert_eq!(string, other_string); /// ``` -/// # Generic impls /// -/// - `From for U` implies [`Into`]` for T` -/// - [`from`] is reflexive, which means that `From for T` is implemented +/// An example usage for error handling: +/// +/// ``` +/// use std::io::{self, Read}; +/// use std::num; +/// +/// enum CliError { +/// IoError(io::Error), +/// ParseError(num::ParseIntError), +/// } +/// +/// impl From for CliError { +/// fn from(error: io::Error) -> Self { +/// CliError::IoError(error) +/// } +/// } +/// +/// impl From for CliError { +/// fn from(error: num::ParseIntError) -> Self { +/// CliError::ParseError(error) +/// } +/// } +/// +/// fn open_and_parse_file(file_name: &str) -> Result { +/// let mut file = std::fs::File::open("test")?; +/// let mut contents = String::new(); +/// file.read_to_string(&mut contents)?; +/// let num: i32 = contents.trim().parse()?; +/// Ok(num) +/// } +/// ``` /// /// [`TryFrom`]: trait.TryFrom.html /// [`Option`]: ../../std/option/enum.Option.html @@ -197,18 +271,21 @@ pub trait Into: Sized { /// [`String`]: ../../std/string/struct.String.html /// [`Into`]: trait.Into.html /// [`from`]: trait.From.html#tymethod.from +/// [book]: ../../book/error-handling.html #[stable(feature = "rust1", since = "1.0.0")] pub trait From: Sized { /// Performs the conversion. #[stable(feature = "rust1", since = "1.0.0")] - fn from(T) -> Self; + fn from(_: T) -> Self; } -/// An attempted conversion that consumes `self`, which may or may not be expensive. +/// An attempted conversion that consumes `self`, which may or may not be +/// expensive. /// -/// Library authors should not directly implement this trait, but should prefer implementing -/// the [`TryFrom`] trait, which offers greater flexibility and provides an equivalent `TryInto` -/// implementation for free, thanks to a blanket implementation in the standard library. +/// Library authors should not directly implement this trait, but should prefer +/// implementing the [`TryFrom`] trait, which offers greater flexibility and +/// provides an equivalent `TryInto` implementation for free, thanks to a +/// blanket implementation in the standard library. /// /// [`TryFrom`]: trait.TryFrom.html #[unstable(feature = "try_from", issue = "33417")] @@ -236,7 +313,8 @@ pub trait TryFrom: Sized { // As lifts over & #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T: ?Sized, U: ?Sized> AsRef for &'a T where T: AsRef { +impl<'a, T: ?Sized, U: ?Sized> AsRef for &'a T where T: AsRef +{ fn as_ref(&self) -> &U { >::as_ref(*self) } @@ -244,7 +322,8 @@ impl<'a, T: ?Sized, U: ?Sized> AsRef for &'a T where T: AsRef { // As lifts over &mut #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T: ?Sized, U: ?Sized> AsRef for &'a mut T where T: AsRef { +impl<'a, T: ?Sized, U: ?Sized> AsRef for &'a mut T where T: AsRef +{ fn as_ref(&self) -> &U { >::as_ref(*self) } @@ -260,7 +339,8 @@ impl<'a, T: ?Sized, U: ?Sized> AsRef for &'a mut T where T: AsRef { // AsMut lifts over &mut #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T: ?Sized, U: ?Sized> AsMut for &'a mut T where T: AsMut { +impl<'a, T: ?Sized, U: ?Sized> AsMut for &'a mut T where T: AsMut +{ fn as_mut(&mut self) -> &mut U { (*self).as_mut() } @@ -276,7 +356,8 @@ impl<'a, T: ?Sized, U: ?Sized> AsMut for &'a mut T where T: AsMut { // From implies Into #[stable(feature = "rust1", since = "1.0.0")] -impl Into for T where U: From { +impl Into for T where U: From +{ fn into(self) -> U { U::from(self) } @@ -291,7 +372,8 @@ impl From for T { // TryFrom implies TryInto #[unstable(feature = "try_from", issue = "33417")] -impl TryInto for T where U: TryFrom { +impl TryInto for T where U: TryFrom +{ type Error = U::Error; fn try_into(self) -> Result { @@ -327,7 +409,8 @@ impl AsRef for str { // FromStr implies TryFrom<&str> #[unstable(feature = "try_from", issue = "33417")] -impl<'a, T> TryFrom<&'a str> for T where T: FromStr { +impl<'a, T> TryFrom<&'a str> for T where T: FromStr +{ type Error = ::Err; fn try_from(s: &'a str) -> Result { diff --git a/src/libcore/fmt/float.rs b/src/libcore/fmt/float.rs index 50248fabfcd4..87def375b202 100644 --- a/src/libcore/fmt/float.rs +++ b/src/libcore/fmt/float.rs @@ -9,8 +9,43 @@ // except according to those terms. use fmt::{Formatter, Result, LowerExp, UpperExp, Display, Debug}; +use mem; use num::flt2dec; +// Don't inline this so callers don't use the stack space this function +// requires unless they have to. +#[inline(never)] +fn float_to_decimal_common_exact(fmt: &mut Formatter, num: &T, + sign: flt2dec::Sign, precision: usize) -> Result + where T: flt2dec::DecodableFloat +{ + unsafe { + let mut buf: [u8; 1024] = mem::uninitialized(); // enough for f32 and f64 + let mut parts: [flt2dec::Part; 5] = mem::uninitialized(); + let formatted = flt2dec::to_exact_fixed_str(flt2dec::strategy::grisu::format_exact, + *num, sign, precision, + false, &mut buf, &mut parts); + fmt.pad_formatted_parts(&formatted) + } +} + +// Don't inline this so callers that call both this and the above won't wind +// up using the combined stack space of both functions in some cases. +#[inline(never)] +fn float_to_decimal_common_shortest(fmt: &mut Formatter, + num: &T, sign: flt2dec::Sign) -> Result + where T: flt2dec::DecodableFloat +{ + unsafe { + // enough for f32 and f64 + let mut buf: [u8; flt2dec::MAX_SIG_DIGITS] = mem::uninitialized(); + let mut parts: [flt2dec::Part; 5] = mem::uninitialized(); + let formatted = flt2dec::to_shortest_str(flt2dec::strategy::grisu::format_shortest, + *num, sign, 0, false, &mut buf, &mut parts); + fmt.pad_formatted_parts(&formatted) + } +} + // Common code of floating point Debug and Display. fn float_to_decimal_common(fmt: &mut Formatter, num: &T, negative_zero: bool) -> Result where T: flt2dec::DecodableFloat @@ -23,16 +58,48 @@ fn float_to_decimal_common(fmt: &mut Formatter, num: &T, negative_zero: bool) (true, true) => flt2dec::Sign::MinusPlusRaw, }; - let mut buf = [0; 1024]; // enough for f32 and f64 - let mut parts = [flt2dec::Part::Zero(0); 16]; - let formatted = if let Some(precision) = fmt.precision { - flt2dec::to_exact_fixed_str(flt2dec::strategy::grisu::format_exact, *num, sign, - precision, false, &mut buf, &mut parts) + if let Some(precision) = fmt.precision { + float_to_decimal_common_exact(fmt, num, sign, precision) } else { - flt2dec::to_shortest_str(flt2dec::strategy::grisu::format_shortest, *num, sign, - 0, false, &mut buf, &mut parts) - }; - fmt.pad_formatted_parts(&formatted) + float_to_decimal_common_shortest(fmt, num, sign) + } +} + +// Don't inline this so callers don't use the stack space this function +// requires unless they have to. +#[inline(never)] +fn float_to_exponential_common_exact(fmt: &mut Formatter, num: &T, + sign: flt2dec::Sign, precision: usize, + upper: bool) -> Result + where T: flt2dec::DecodableFloat +{ + unsafe { + let mut buf: [u8; 1024] = mem::uninitialized(); // enough for f32 and f64 + let mut parts: [flt2dec::Part; 7] = mem::uninitialized(); + let formatted = flt2dec::to_exact_exp_str(flt2dec::strategy::grisu::format_exact, + *num, sign, precision, + upper, &mut buf, &mut parts); + fmt.pad_formatted_parts(&formatted) + } +} + +// Don't inline this so callers that call both this and the above won't wind +// up using the combined stack space of both functions in some cases. +#[inline(never)] +fn float_to_exponential_common_shortest(fmt: &mut Formatter, + num: &T, sign: flt2dec::Sign, + upper: bool) -> Result + where T: flt2dec::DecodableFloat +{ + unsafe { + // enough for f32 and f64 + let mut buf: [u8; flt2dec::MAX_SIG_DIGITS] = mem::uninitialized(); + let mut parts: [flt2dec::Part; 7] = mem::uninitialized(); + let formatted = flt2dec::to_shortest_exp_str(flt2dec::strategy::grisu::format_shortest, + *num, sign, (0, 0), upper, + &mut buf, &mut parts); + fmt.pad_formatted_parts(&formatted) + } } // Common code of floating point LowerExp and UpperExp. @@ -45,17 +112,12 @@ fn float_to_exponential_common(fmt: &mut Formatter, num: &T, upper: bool) -> true => flt2dec::Sign::MinusPlus, }; - let mut buf = [0; 1024]; // enough for f32 and f64 - let mut parts = [flt2dec::Part::Zero(0); 16]; - let formatted = if let Some(precision) = fmt.precision { + if let Some(precision) = fmt.precision { // 1 integral digit + `precision` fractional digits = `precision + 1` total digits - flt2dec::to_exact_exp_str(flt2dec::strategy::grisu::format_exact, *num, sign, - precision + 1, upper, &mut buf, &mut parts) + float_to_exponential_common_exact(fmt, num, sign, precision + 1, upper) } else { - flt2dec::to_shortest_exp_str(flt2dec::strategy::grisu::format_shortest, *num, sign, - (0, 0), upper, &mut buf, &mut parts) - }; - fmt.pad_formatted_parts(&formatted) + float_to_exponential_common_shortest(fmt, num, sign, upper) + } } macro_rules! floating { diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 0bfab92fa5d5..8c3d3ce7d886 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -49,8 +49,31 @@ pub mod rt { pub mod v1; } -#[stable(feature = "rust1", since = "1.0.0")] /// The type returned by formatter methods. +/// +/// # Examples +/// +/// ``` +/// use std::fmt; +/// +/// #[derive(Debug)] +/// struct Triangle { +/// a: f32, +/// b: f32, +/// c: f32 +/// } +/// +/// impl fmt::Display for Triangle { +/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +/// write!(f, "({}, {}, {})", self.a, self.b, self.c) +/// } +/// } +/// +/// let pythagorean_triple = Triangle { a: 3.0, b: 4.0, c: 5.0 }; +/// +/// println!("{}", pythagorean_triple); +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] pub type Result = result::Result<(), Error>; /// The error type which is returned from formatting a message into a stream. diff --git a/src/libcore/fmt/num.rs b/src/libcore/fmt/num.rs index a324a4aed257..4ca303dee43f 100644 --- a/src/libcore/fmt/num.rs +++ b/src/libcore/fmt/num.rs @@ -15,7 +15,6 @@ // FIXME: #6220 Implement floating point formatting use fmt; -use num::Zero; use ops::{Div, Rem, Sub}; use str; use slice; @@ -23,8 +22,9 @@ use ptr; use mem; #[doc(hidden)] -trait Int: Zero + PartialEq + PartialOrd + Div + Rem + +trait Int: PartialEq + PartialOrd + Div + Rem + Sub + Copy { + fn zero() -> Self; fn from_u8(u: u8) -> Self; fn to_u8(&self) -> u8; fn to_u16(&self) -> u16; @@ -35,6 +35,7 @@ trait Int: Zero + PartialEq + PartialOrd + Div + Rem + macro_rules! doit { ($($t:ident)*) => ($(impl Int for $t { + fn zero() -> $t { 0 } fn from_u8(u: u8) -> $t { u as $t } fn to_u8(&self) -> u8 { *self as u8 } fn to_u16(&self) -> u16 { *self as u16 } diff --git a/src/libcore/hash/mod.rs b/src/libcore/hash/mod.rs index 756d472eca8d..f68361e85227 100644 --- a/src/libcore/hash/mod.rs +++ b/src/libcore/hash/mod.rs @@ -107,29 +107,25 @@ mod sip; /// A hashable type. /// -/// The `H` type parameter is an abstract hash state that is used by the `Hash` -/// to compute the hash. +/// Types implementing `Hash` are able to be [`hash`]ed with an instance of +/// [`Hasher`]. /// -/// If you are also implementing [`Eq`], there is an additional property that -/// is important: +/// ## Implementing `Hash` /// -/// ```text -/// k1 == k2 -> hash(k1) == hash(k2) +/// You can derive `Hash` with `#[derive(Hash)]` if all fields implement `Hash`. +/// The resulting hash will be the combination of the values from calling +/// [`hash`] on each field. +/// +/// ``` +/// #[derive(Hash)] +/// struct Rustacean { +/// name: String, +/// country: String, +/// } /// ``` /// -/// In other words, if two keys are equal, their hashes should also be equal. -/// [`HashMap`] and [`HashSet`] both rely on this behavior. -/// -/// ## Derivable -/// -/// This trait can be used with `#[derive]` if all fields implement `Hash`. -/// When `derive`d, the resulting hash will be the combination of the values -/// from calling [`.hash`] on each field. -/// -/// ## How can I implement `Hash`? -/// -/// If you need more control over how a value is hashed, you need to implement -/// the `Hash` trait: +/// If you need more control over how a value is hashed, you can of course +/// implement the `Hash` trait yourself: /// /// ``` /// use std::hash::{Hash, Hasher}; @@ -148,17 +144,60 @@ mod sip; /// } /// ``` /// +/// ## `Hash` and `Eq` +/// +/// When implementing both `Hash` and [`Eq`], it is important that the following +/// property holds: +/// +/// ```text +/// k1 == k2 -> hash(k1) == hash(k2) +/// ``` +/// +/// In other words, if two keys are equal, their hashes must also be equal. +/// [`HashMap`] and [`HashSet`] both rely on this behavior. +/// +/// Thankfully, you won't need to worry about upholding this property when +/// deriving both [`Eq`] and `Hash` with `#[derive(PartialEq, Eq, Hash)]`. +/// /// [`Eq`]: ../../std/cmp/trait.Eq.html +/// [`Hasher`]: trait.Hasher.html /// [`HashMap`]: ../../std/collections/struct.HashMap.html /// [`HashSet`]: ../../std/collections/struct.HashSet.html -/// [`.hash`]: #tymethod.hash +/// [`hash`]: #tymethod.hash #[stable(feature = "rust1", since = "1.0.0")] pub trait Hash { - /// Feeds this value into the state given, updating the hasher as necessary. + /// Feeds this value into the given [`Hasher`]. + /// + /// # Examples + /// + /// ``` + /// use std::collections::hash_map::DefaultHasher; + /// use std::hash::{Hash, Hasher}; + /// + /// let mut hasher = DefaultHasher::new(); + /// 7920.hash(&mut hasher); + /// println!("Hash is {:x}!", hasher.finish()); + /// ``` + /// + /// [`Hasher`]: trait.Hasher.html #[stable(feature = "rust1", since = "1.0.0")] fn hash(&self, state: &mut H); - /// Feeds a slice of this type into the state provided. + /// Feeds a slice of this type into the given [`Hasher`]. + /// + /// # Examples + /// + /// ``` + /// use std::collections::hash_map::DefaultHasher; + /// use std::hash::{Hash, Hasher}; + /// + /// let mut hasher = DefaultHasher::new(); + /// let numbers = [6, 28, 496, 8128]; + /// Hash::hash_slice(&numbers, &mut hasher); + /// println!("Hash is {:x}!", hasher.finish()); + /// ``` + /// + /// [`Hasher`]: trait.Hasher.html #[stable(feature = "hash_slice", since = "1.3.0")] fn hash_slice(data: &[Self], state: &mut H) where Self: Sized @@ -169,18 +208,73 @@ pub trait Hash { } } -/// A trait which represents the ability to hash an arbitrary stream of bytes. +/// A trait for hashing an arbitrary stream of bytes. +/// +/// Instances of `Hasher` usually represent state that is changed while hashing +/// data. +/// +/// `Hasher` provides a fairly basic interface for retrieving the generated hash +/// (with [`finish`]), and writing integers as well as slices of bytes into an +/// instance (with [`write`] and [`write_u8`] etc.). Most of the time, `Hasher` +/// instances are used in conjunction with the [`Hash`] trait. +/// +/// # Examples +/// +/// ``` +/// use std::collections::hash_map::DefaultHasher; +/// use std::hash::Hasher; +/// +/// let mut hasher = DefaultHasher::new(); +/// +/// hasher.write_u32(1989); +/// hasher.write_u8(11); +/// hasher.write_u8(9); +/// hasher.write(b"Huh?"); +/// +/// println!("Hash is {:x}!", hasher.finish()); +/// ``` +/// +/// [`Hash`]: trait.Hash.html +/// [`finish`]: #tymethod.finish +/// [`write`]: #tymethod.write +/// [`write_u8`]: #method.write_u8 #[stable(feature = "rust1", since = "1.0.0")] pub trait Hasher { /// Completes a round of hashing, producing the output hash generated. + /// + /// # Examples + /// + /// ``` + /// use std::collections::hash_map::DefaultHasher; + /// use std::hash::Hasher; + /// + /// let mut hasher = DefaultHasher::new(); + /// hasher.write(b"Cool!"); + /// + /// println!("Hash is {:x}!", hasher.finish()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn finish(&self) -> u64; /// Writes some data into this `Hasher`. + /// + /// # Examples + /// + /// ``` + /// use std::collections::hash_map::DefaultHasher; + /// use std::hash::Hasher; + /// + /// let mut hasher = DefaultHasher::new(); + /// let data = [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]; + /// + /// hasher.write(&data); + /// + /// println!("Hash is {:x}!", hasher.finish()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn write(&mut self, bytes: &[u8]); - /// Write a single `u8` into this hasher. + /// Writes a single `u8` into this hasher. #[inline] #[stable(feature = "hasher_write", since = "1.3.0")] fn write_u8(&mut self, i: u8) { @@ -258,12 +352,35 @@ pub trait Hasher { } } -/// A `BuildHasher` is typically used as a factory for instances of `Hasher` -/// which a `HashMap` can then use to hash keys independently. +/// A trait for creating instances of [`Hasher`]. /// -/// Note that for each instance of `BuildHasher`, the created hashers should be -/// identical. That is, if the same stream of bytes is fed into each hasher, the -/// same output will also be generated. +/// A `BuildHasher` is typically used (e.g. by [`HashMap`]) to create +/// [`Hasher`]s for each key such that they are hashed independently of one +/// another, since [`Hasher`]s contain state. +/// +/// For each instance of `BuildHasher`, the [`Hasher`]s created by +/// [`build_hasher`] should be identical. That is, if the same stream of bytes +/// is fed into each hasher, the same output will also be generated. +/// +/// # Examples +/// +/// ``` +/// use std::collections::hash_map::RandomState; +/// use std::hash::{BuildHasher, Hasher}; +/// +/// let s = RandomState::new(); +/// let mut hasher_1 = s.build_hasher(); +/// let mut hasher_2 = s.build_hasher(); +/// +/// hasher_1.write_u32(8128); +/// hasher_2.write_u32(8128); +/// +/// assert_eq!(hasher_1.finish(), hasher_2.finish()); +/// ``` +/// +/// [`build_hasher`]: #tymethod.build_hasher +/// [`Hasher`]: trait.Hasher.html +/// [`HashMap`]: ../../std/collections/struct.HashMap.html #[stable(since = "1.7.0", feature = "build_hasher")] pub trait BuildHasher { /// Type of the hasher that will be created. @@ -272,6 +389,9 @@ pub trait BuildHasher { /// Creates a new hasher. /// + /// Each call to `build_hasher` on the same instance should produce identical + /// [`Hasher`]s. + /// /// # Examples /// /// ``` @@ -281,15 +401,23 @@ pub trait BuildHasher { /// let s = RandomState::new(); /// let new_s = s.build_hasher(); /// ``` + /// + /// [`Hasher`]: trait.Hasher.html #[stable(since = "1.7.0", feature = "build_hasher")] fn build_hasher(&self) -> Self::Hasher; } -/// The `BuildHasherDefault` structure is used in scenarios where one has a -/// type that implements [`Hasher`] and [`Default`], but needs that type to -/// implement [`BuildHasher`]. +/// Used to create a default [`BuildHasher`] instance for types that implement +/// [`Hasher`] and [`Default`]. /// -/// This structure is zero-sized and does not need construction. +/// `BuildHasherDefault` can be used when a type `H` implements [`Hasher`] and +/// [`Default`], and you need a corresponding [`BuildHasher`] instance, but none is +/// defined. +/// +/// Any `BuildHasherDefault` is [zero-sized]. It can be created with +/// [`default`][method.Default]. When using `BuildHasherDefault` with [`HashMap`] or +/// [`HashSet`], this doesn't need to be done, since they implement appropriate +/// [`Default`] instances themselves. /// /// # Examples /// @@ -322,8 +450,11 @@ pub trait BuildHasher { /// /// [`BuildHasher`]: trait.BuildHasher.html /// [`Default`]: ../default/trait.Default.html +/// [method.default]: #method.default /// [`Hasher`]: trait.Hasher.html /// [`HashMap`]: ../../std/collections/struct.HashMap.html +/// [`HashSet`]: ../../std/collections/struct.HashSet.html +/// [zero-sized]: https://doc.rust-lang.org/nomicon/exotic-sizes.html#zero-sized-types-zsts #[stable(since = "1.7.0", feature = "build_hasher")] pub struct BuildHasherDefault(marker::PhantomData); diff --git a/src/libcore/hash/sip.rs b/src/libcore/hash/sip.rs index 5f5d07b66823..db12496b6f32 100644 --- a/src/libcore/hash/sip.rs +++ b/src/libcore/hash/sip.rs @@ -403,8 +403,8 @@ impl Default for Hasher { #[doc(hidden)] trait Sip { - fn c_rounds(&mut State); - fn d_rounds(&mut State); + fn c_rounds(_: &mut State); + fn d_rounds(_: &mut State); } #[derive(Debug, Clone, Default)] diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 1ae8b6bb4511..9f1870e56d38 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -46,7 +46,6 @@ issue = "0")] #![allow(missing_docs)] -#[cfg(not(stage0))] #[stable(feature = "drop_in_place", since = "1.8.0")] #[rustc_deprecated(reason = "no longer an intrinsic - use `ptr::drop_in_place` directly", since = "1.18.0")] @@ -61,16 +60,18 @@ extern "rust-intrinsic" { /// `std::sync::atomic` types via the `compare_exchange` method by passing /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html) /// as both the `success` and `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange). + /// [`AtomicBool::compare_exchange`][compare_exchange]. + /// + /// [compare_exchange]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange pub fn atomic_cxchg(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the /// `std::sync::atomic` types via the `compare_exchange` method by passing /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) /// as both the `success` and `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange). + /// [`AtomicBool::compare_exchange`][compare_exchange]. + /// + /// [compare_exchange]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange pub fn atomic_cxchg_acq(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -79,8 +80,9 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange). + /// [`AtomicBool::compare_exchange`][compare_exchange]. + /// + /// [compare_exchange]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange pub fn atomic_cxchg_rel(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -89,16 +91,18 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange). + /// [`AtomicBool::compare_exchange`][compare_exchange]. + /// + /// [compare_exchange]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange pub fn atomic_cxchg_acqrel(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the /// `std::sync::atomic` types via the `compare_exchange` method by passing /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) /// as both the `success` and `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange). + /// [`AtomicBool::compare_exchange`][compare_exchange]. + /// + /// [compare_exchange]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange pub fn atomic_cxchg_relaxed(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -107,8 +111,9 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange). + /// [`AtomicBool::compare_exchange`][compare_exchange]. + /// + /// [compare_exchange]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange pub fn atomic_cxchg_failrelaxed(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -117,8 +122,9 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange). + /// [`AtomicBool::compare_exchange`][compare_exchange]. + /// + /// [compare_exchange]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange pub fn atomic_cxchg_failacq(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -127,8 +133,9 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange). + /// [`AtomicBool::compare_exchange`][compare_exchange]. + /// + /// [compare_exchange]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange pub fn atomic_cxchg_acq_failrelaxed(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -137,8 +144,9 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange). + /// [`AtomicBool::compare_exchange`][compare_exchange]. + /// + /// [compare_exchange]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange pub fn atomic_cxchg_acqrel_failrelaxed(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. @@ -146,16 +154,18 @@ extern "rust-intrinsic" { /// `std::sync::atomic` types via the `compare_exchange_weak` method by passing /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html) /// as both the `success` and `failure` parameters. For example, - /// [`AtomicBool::compare_exchange_weak`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak). + /// [`AtomicBool::compare_exchange_weak`][cew]. + /// + /// [cew]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak pub fn atomic_cxchgweak(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the /// `std::sync::atomic` types via the `compare_exchange_weak` method by passing /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) /// as both the `success` and `failure` parameters. For example, - /// [`AtomicBool::compare_exchange_weak`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak). + /// [`AtomicBool::compare_exchange_weak`][cew]. + /// + /// [cew]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak pub fn atomic_cxchgweak_acq(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -164,8 +174,9 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange_weak`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak). + /// [`AtomicBool::compare_exchange_weak`][cew]. + /// + /// [cew]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak pub fn atomic_cxchgweak_rel(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -174,16 +185,18 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange_weak`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak). + /// [`AtomicBool::compare_exchange_weak`][cew]. + /// + /// [cew]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak pub fn atomic_cxchgweak_acqrel(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the /// `std::sync::atomic` types via the `compare_exchange_weak` method by passing /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) /// as both the `success` and `failure` parameters. For example, - /// [`AtomicBool::compare_exchange_weak`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak). + /// [`AtomicBool::compare_exchange_weak`][cew]. + /// + /// [cew]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak pub fn atomic_cxchgweak_relaxed(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -192,8 +205,9 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange_weak`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak). + /// [`AtomicBool::compare_exchange_weak`][cew]. + /// + /// [cew]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak pub fn atomic_cxchgweak_failrelaxed(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -202,8 +216,9 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange_weak`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak). + /// [`AtomicBool::compare_exchange_weak`][cew]. + /// + /// [cew]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak pub fn atomic_cxchgweak_failacq(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -212,8 +227,9 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange_weak`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak). + /// [`AtomicBool::compare_exchange_weak`][cew]. + /// + /// [cew]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak pub fn atomic_cxchgweak_acq_failrelaxed(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. /// The stabilized version of this intrinsic is available on the @@ -222,8 +238,9 @@ extern "rust-intrinsic" { /// as the `success` and /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html) /// as the `failure` parameters. For example, - /// [`AtomicBool::compare_exchange_weak`] - /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak). + /// [`AtomicBool::compare_exchange_weak`][cew]. + /// + /// [cew]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak pub fn atomic_cxchgweak_acqrel_failrelaxed(dst: *mut T, old: T, src: T) -> (T, bool); /// Loads the current value of the pointer. @@ -627,27 +644,6 @@ extern "rust-intrinsic" { pub fn size_of_val(_: &T) -> usize; pub fn min_align_of_val(_: &T) -> usize; - #[cfg(stage0)] - /// Executes the destructor (if any) of the pointed-to value. - /// - /// This has two use cases: - /// - /// * It is *required* to use `drop_in_place` to drop unsized types like - /// trait objects, because they can't be read out onto the stack and - /// dropped normally. - /// - /// * It is friendlier to the optimizer to do this over `ptr::read` when - /// dropping manually allocated memory (e.g. when writing Box/Rc/Vec), - /// as the compiler doesn't need to prove that it's sound to elide the - /// copy. - /// - /// # Undefined Behavior - /// - /// This has all the same safety problems as `ptr::read` with respect to - /// invalid pointers, types, and double drops. - #[stable(feature = "drop_in_place", since = "1.8.0")] - pub fn drop_in_place(to_drop: *mut T); - /// Gets a static string slice containing the name of a type. pub fn type_name() -> &'static str; @@ -673,9 +669,6 @@ extern "rust-intrinsic" { /// initialize memory previous set to the result of `uninit`. pub fn uninit() -> T; - /// Moves a value out of scope without running drop glue. - pub fn forget(_: T) -> (); - /// Reinterprets the bits of a value of one type as another type. /// /// Both types must have the same size. Neither the original, nor the result, @@ -1246,24 +1239,22 @@ extern "rust-intrinsic" { /// Performs an unchecked left shift, resulting in undefined behavior when /// y < 0 or y >= N, where N is the width of T in bits. - #[cfg(not(stage0))] pub fn unchecked_shl(x: T, y: T) -> T; /// Performs an unchecked right shift, resulting in undefined behavior when /// y < 0 or y >= N, where N is the width of T in bits. - #[cfg(not(stage0))] pub fn unchecked_shr(x: T, y: T) -> T; - /// Returns (a + b) mod 2^N, where N is the width of T in bits. + /// Returns (a + b) mod 2N, where N is the width of T in bits. /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `wrapping_add` method. For example, /// [`std::u32::wrapping_add`](../../std/primitive.u32.html#method.wrapping_add) pub fn overflowing_add(a: T, b: T) -> T; - /// Returns (a - b) mod 2^N, where N is the width of T in bits. + /// Returns (a - b) mod 2N, where N is the width of T in bits. /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `wrapping_sub` method. For example, /// [`std::u32::wrapping_sub`](../../std/primitive.u32.html#method.wrapping_sub) pub fn overflowing_sub(a: T, b: T) -> T; - /// Returns (a * b) mod 2^N, where N is the width of T in bits. + /// Returns (a * b) mod 2N, where N is the width of T in bits. /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `wrapping_mul` method. For example, /// [`std::u32::wrapping_mul`](../../std/primitive.u32.html#method.wrapping_mul) diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index 618edf48abd0..b3f4d75c4da6 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -629,8 +629,9 @@ pub trait Iterator { /// /// Note that the underlying iterator is still advanced when [`peek`] is /// called for the first time: In order to retrieve the next element, - /// [`next`] is called on the underlying iterator, hence any side effects of - /// the [`next`] method will occur. + /// [`next`] is called on the underlying iterator, hence any side effects (i.e. + /// anything other than fetching the next value) of the [`next`] method + /// will occur. /// /// [`peek`]: struct.Peekable.html#method.peek /// [`next`]: ../../std/iter/trait.Iterator.html#tymethod.next @@ -1532,14 +1533,18 @@ pub trait Iterator { /// Stopping at the first `true`: /// /// ``` - /// let a = [1, 2, 3]; + /// let a = [1, 2, 3, 4]; /// /// let mut iter = a.iter(); /// - /// assert_eq!(iter.position(|&x| x == 2), Some(1)); + /// assert_eq!(iter.position(|&x| x >= 2), Some(1)); /// /// // we can still use `iter`, as there are more elements. /// assert_eq!(iter.next(), Some(&3)); + /// + /// // The returned index depends on iterator state + /// assert_eq!(iter.position(|&x| x == 4), Some(0)); + /// /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -2160,16 +2165,16 @@ pub trait Iterator { } } -/// Select an element from an iterator based on the given projection +/// Select an element from an iterator based on the given "projection" /// and "comparison" function. /// /// This is an idiosyncratic helper to try to factor out the /// commonalities of {max,min}{,_by}. In particular, this avoids /// having to implement optimizations several times. #[inline] -fn select_fold1(mut it: I, - mut f_proj: FProj, - mut f_cmp: FCmp) -> Option<(B, I::Item)> +fn select_fold1(mut it: I, + mut f_proj: FProj, + mut f_cmp: FCmp) -> Option<(B, I::Item)> where I: Iterator, FProj: FnMut(&I::Item) -> B, FCmp: FnMut(&B, &I::Item, &B, &I::Item) -> bool @@ -2182,7 +2187,7 @@ fn select_fold1(mut it: I, for x in it { let x_p = f_proj(&x); - if f_cmp(&sel_p, &sel, &x_p, &x) { + if f_cmp(&sel_p, &sel, &x_p, &x) { sel = x; sel_p = x_p; } diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index 04394e0a3a87..273f9d0e6f6d 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -358,12 +358,24 @@ impl Iterator for Rev where I: DoubleEndedIterator { fn next(&mut self) -> Option<::Item> { self.iter.next_back() } #[inline] fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } + + fn find

(&mut self, predicate: P) -> Option + where P: FnMut(&Self::Item) -> bool + { + self.iter.rfind(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() } + + fn rfind

(&mut self, predicate: P) -> Option + where P: FnMut(&Self::Item) -> bool + { + self.iter.find(predicate) + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs index 687c477f19e4..bd831d638c0c 100644 --- a/src/libcore/iter/range.rs +++ b/src/libcore/iter/range.rs @@ -86,12 +86,12 @@ macro_rules! step_impl_unsigned { #[inline] fn replace_one(&mut self) -> Self { - mem::replace(self, 0) + mem::replace(self, 1) } #[inline] fn replace_zero(&mut self) -> Self { - mem::replace(self, 1) + mem::replace(self, 0) } #[inline] @@ -157,12 +157,12 @@ macro_rules! step_impl_signed { #[inline] fn replace_one(&mut self) -> Self { - mem::replace(self, 0) + mem::replace(self, 1) } #[inline] fn replace_zero(&mut self) -> Self { - mem::replace(self, 1) + mem::replace(self, 0) } #[inline] @@ -206,12 +206,12 @@ macro_rules! step_impl_no_between { #[inline] fn replace_one(&mut self) -> Self { - mem::replace(self, 0) + mem::replace(self, 1) } #[inline] fn replace_zero(&mut self) -> Self { - mem::replace(self, 1) + mem::replace(self, 0) } #[inline] diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs index 34f14ef53f89..798dda199281 100644 --- a/src/libcore/iter/traits.rs +++ b/src/libcore/iter/traits.rs @@ -467,7 +467,7 @@ pub trait DoubleEndedIterator: Iterator { Self: Sized, P: FnMut(&Self::Item) -> bool { - for x in self.by_ref().rev() { + while let Some(x) = self.next_back() { if predicate(&x) { return Some(x) } } None diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index af6134274931..80c2221ce641 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -70,6 +70,7 @@ #![feature(allow_internal_unstable)] #![feature(asm)] #![feature(associated_type_defaults)] +#![feature(associated_consts)] #![feature(cfg_target_feature)] #![feature(cfg_target_has_atomic)] #![feature(concat_idents)] diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index 021079f85f6b..bf4e414d4168 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -150,7 +150,7 @@ macro_rules! assert_eq { /// assert_ne!(a, b, "we are testing that the values are not equal"); /// ``` #[macro_export] -#[stable(feature = "assert_ne", since = "1.12.0")] +#[stable(feature = "assert_ne", since = "1.13.0")] macro_rules! assert_ne { ($left:expr, $right:expr) => ({ match (&$left, &$right) { @@ -268,7 +268,7 @@ macro_rules! debug_assert_eq { /// debug_assert_ne!(a, b); /// ``` #[macro_export] -#[stable(feature = "assert_ne", since = "1.12.0")] +#[stable(feature = "assert_ne", since = "1.13.0")] macro_rules! debug_assert_ne { ($($arg:tt)*) => (if cfg!(debug_assertions) { assert_ne!($($arg)*); }) } @@ -337,27 +337,20 @@ macro_rules! try { /// Write formatted data into a buffer /// -/// This macro accepts a 'writer' (any value with a `write_fmt` method), a format string, and a -/// list of arguments to format. +/// This macro accepts a format string, a list of arguments, and a 'writer'. Arguments will be +/// formatted according to the specified format string and the result will be passed to the writer. +/// The writer may be any value with a `write_fmt` method; generally this comes from an +/// implementation of either the [`std::fmt::Write`] or the [`std::io::Write`] trait. The macro +/// returns whatever the 'write_fmt' method returns; commonly a [`std::fmt::Result`], or an +/// [`io::Result`]. /// -/// The `write_fmt` method usually comes from an implementation of [`std::fmt::Write`][fmt_write] -/// or [`std::io::Write`][io_write] traits. The term 'writer' refers to an implementation of one of -/// these two traits. +/// See [`std::fmt`] for more information on the format string syntax. /// -/// Passed arguments will be formatted according to the specified format string and the resulting -/// string will be passed to the writer. -/// -/// See [`std::fmt`][fmt] for more information on format syntax. -/// -/// `write!` returns whatever the 'write_fmt' method returns. -/// -/// Common return values include: [`fmt::Result`][fmt_result], [`io::Result`][io_result] -/// -/// [fmt]: ../std/fmt/index.html -/// [fmt_write]: ../std/fmt/trait.Write.html -/// [io_write]: ../std/io/trait.Write.html -/// [fmt_result]: ../std/fmt/type.Result.html -/// [io_result]: ../std/io/type.Result.html +/// [`std::fmt`]: ../std/fmt/index.html +/// [`std::fmt::Write`]: ../std/fmt/trait.Write.html +/// [`std::io::Write`]: ../std/io/trait.Write.html +/// [`std::fmt::Result`]: ../std/fmt/type.Result.html +/// [`io::Result`]: ../std/io/type.Result.html /// /// # Examples /// @@ -386,7 +379,7 @@ macro_rules! try { /// assert_eq!(v, b"s = \"abc 123\""); /// ``` #[macro_export] -#[stable(feature = "core", since = "1.6.0")] +#[stable(feature = "rust1", since = "1.0.0")] macro_rules! write { ($dst:expr, $($arg:tt)*) => ($dst.write_fmt(format_args!($($arg)*))) } @@ -396,27 +389,12 @@ macro_rules! write { /// On all platforms, the newline is the LINE FEED character (`\n`/`U+000A`) alone /// (no additional CARRIAGE RETURN (`\r`/`U+000D`). /// -/// This macro accepts a 'writer' (any value with a `write_fmt` method), a format string, and a -/// list of arguments to format. +/// For more information, see [`write!`]. For information on the format string syntax, see +/// [`std::fmt`]. /// -/// The `write_fmt` method usually comes from an implementation of [`std::fmt::Write`][fmt_write] -/// or [`std::io::Write`][io_write] traits. The term 'writer' refers to an implementation of one of -/// these two traits. +/// [`write!`]: macro.write.html +/// [`std::fmt`]: ../std/fmt/index.html /// -/// Passed arguments will be formatted according to the specified format string and the resulting -/// string will be passed to the writer, along with the appended newline. -/// -/// See [`std::fmt`][fmt] for more information on format syntax. -/// -/// `write!` returns whatever the 'write_fmt' method returns. -/// -/// Common return values include: [`fmt::Result`][fmt_result], [`io::Result`][io_result] -/// -/// [fmt]: ../std/fmt/index.html -/// [fmt_write]: ../std/fmt/trait.Write.html -/// [io_write]: ../std/io/trait.Write.html -/// [fmt_result]: ../std/fmt/type.Result.html -/// [io_result]: ../std/io/type.Result.html /// /// # Examples /// @@ -501,7 +479,7 @@ macro_rules! writeln { /// } /// ``` #[macro_export] -#[stable(feature = "core", since = "1.6.0")] +#[stable(feature = "rust1", since = "1.0.0")] macro_rules! unreachable { () => ({ panic!("internal error: entered unreachable code") @@ -562,7 +540,7 @@ macro_rules! unreachable { /// } /// ``` #[macro_export] -#[stable(feature = "core", since = "1.6.0")] +#[stable(feature = "rust1", since = "1.0.0")] macro_rules! unimplemented { () => (panic!("not yet implemented")) } diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 393c01b0105c..3f32db122351 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -16,6 +16,7 @@ #![stable(feature = "rust1", since = "1.0.0")] +use cell::UnsafeCell; use cmp; use hash::Hash; use hash::Hasher; @@ -553,3 +554,19 @@ mod impls { #[stable(feature = "rust1", since = "1.0.0")] unsafe impl<'a, T: Send + ?Sized> Send for &'a mut T {} } + +/// Compiler-internal trait used to determine whether a type contains +/// any `UnsafeCell` internally, but not through an indirection. +/// This affects, for example, whether a `static` of that type is +/// placed in read-only static memory or writable static memory. +#[lang = "freeze"] +unsafe trait Freeze {} + +unsafe impl Freeze for .. {} + +impl !Freeze for UnsafeCell {} +unsafe impl Freeze for PhantomData {} +unsafe impl Freeze for *const T {} +unsafe impl Freeze for *mut T {} +unsafe impl<'a, T: ?Sized> Freeze for &'a T {} +unsafe impl<'a, T: ?Sized> Freeze for &'a mut T {} diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index f5cf3724d071..b397aba6b92d 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -40,7 +40,7 @@ pub use intrinsics::transmute; /// `forget` is not marked as `unsafe`, because Rust's safety guarantees /// do not include a guarantee that destructors will always run. For example, /// a program can create a reference cycle using [`Rc`][rc], or call -/// [`process:exit`][exit] to exit without running destructors. Thus, allowing +/// [`process::exit`][exit] to exit without running destructors. Thus, allowing /// `mem::forget` from safe code does not fundamentally change Rust's safety /// guarantees. /// @@ -171,7 +171,7 @@ pub use intrinsics::transmute; #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn forget(t: T) { - unsafe { intrinsics::forget(t) } + ManuallyDrop::new(t); } /// Returns the size of a type in bytes. @@ -736,3 +736,121 @@ pub fn discriminant(v: &T) -> Discriminant { } } + +/// A wrapper to inhibit compiler from automatically calling `T`’s destructor. +/// +/// This wrapper is 0-cost. +/// +/// # Examples +/// +/// This wrapper helps with explicitly documenting the drop order dependencies between fields of +/// the type: +/// +/// ```rust +/// # #![feature(manually_drop)] +/// use std::mem::ManuallyDrop; +/// struct Peach; +/// struct Banana; +/// struct Melon; +/// struct FruitBox { +/// // Immediately clear there’s something non-trivial going on with these fields. +/// peach: ManuallyDrop, +/// melon: Melon, // Field that’s independent of the other two. +/// banana: ManuallyDrop, +/// } +/// +/// impl Drop for FruitBox { +/// fn drop(&mut self) { +/// unsafe { +/// // Explicit ordering in which field destructors are run specified in the intuitive +/// // location – the destructor of the structure containing the fields. +/// // Moreover, one can now reorder fields within the struct however much they want. +/// ManuallyDrop::drop(&mut self.peach); +/// ManuallyDrop::drop(&mut self.banana); +/// } +/// // After destructor for `FruitBox` runs (this function), the destructor for Melon gets +/// // invoked in the usual manner, as it is not wrapped in `ManuallyDrop`. +/// } +/// } +/// ``` +#[unstable(feature = "manually_drop", issue = "40673")] +#[allow(unions_with_drop_fields)] +pub union ManuallyDrop{ value: T } + +impl ManuallyDrop { + /// Wrap a value to be manually dropped. + /// + /// # Examples + /// + /// ```rust + /// # #![feature(manually_drop)] + /// use std::mem::ManuallyDrop; + /// ManuallyDrop::new(Box::new(())); + /// ``` + #[unstable(feature = "manually_drop", issue = "40673")] + #[inline] + pub fn new(value: T) -> ManuallyDrop { + ManuallyDrop { value: value } + } + + /// Extract the value from the ManuallyDrop container. + /// + /// # Examples + /// + /// ```rust + /// # #![feature(manually_drop)] + /// use std::mem::ManuallyDrop; + /// let x = ManuallyDrop::new(Box::new(())); + /// let _: Box<()> = ManuallyDrop::into_inner(x); + /// ``` + #[unstable(feature = "manually_drop", issue = "40673")] + #[inline] + pub fn into_inner(slot: ManuallyDrop) -> T { + unsafe { + slot.value + } + } + + /// Manually drops the contained value. + /// + /// # Unsafety + /// + /// This function runs the destructor of the contained value and thus the wrapped value + /// now represents uninitialized data. It is up to the user of this method to ensure the + /// uninitialized data is not actually used. + #[unstable(feature = "manually_drop", issue = "40673")] + #[inline] + pub unsafe fn drop(slot: &mut ManuallyDrop) { + ptr::drop_in_place(&mut slot.value) + } +} + +#[unstable(feature = "manually_drop", issue = "40673")] +impl ::ops::Deref for ManuallyDrop { + type Target = T; + #[inline] + fn deref(&self) -> &Self::Target { + unsafe { + &self.value + } + } +} + +#[unstable(feature = "manually_drop", issue = "40673")] +impl ::ops::DerefMut for ManuallyDrop { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { + &mut self.value + } + } +} + +#[unstable(feature = "manually_drop", issue = "40673")] +impl ::fmt::Debug for ManuallyDrop { + fn fmt(&self, fmt: &mut ::fmt::Formatter) -> ::fmt::Result { + unsafe { + fmt.debug_tuple("ManuallyDrop").field(&self.value).finish() + } + } +} diff --git a/src/libcore/num/bignum.rs b/src/libcore/num/bignum.rs index 8904322ca48f..b5553fb29475 100644 --- a/src/libcore/num/bignum.rs +++ b/src/libcore/num/bignum.rs @@ -19,7 +19,7 @@ //! inputs, but we don't do so to avoid the code bloat. Each bignum is still //! tracked for the actual usages, so it normally doesn't matter. -// This module is only for dec2flt and flt2dec, and only public because of libcoretest. +// This module is only for dec2flt and flt2dec, and only public because of coretests. // It is not intended to ever be stabilized. #![doc(hidden)] #![unstable(feature = "core_private_bignum", diff --git a/src/libcore/num/dec2flt/algorithm.rs b/src/libcore/num/dec2flt/algorithm.rs index 604bc7c10dea..42bc46c0c683 100644 --- a/src/libcore/num/dec2flt/algorithm.rs +++ b/src/libcore/num/dec2flt/algorithm.rs @@ -106,17 +106,17 @@ mod fpu_precision { /// a bignum. pub fn fast_path(integral: &[u8], fractional: &[u8], e: i64) -> Option { let num_digits = integral.len() + fractional.len(); - // log_10(f64::max_sig) ~ 15.95. We compare the exact value to max_sig near the end, + // log_10(f64::MAX_SIG) ~ 15.95. We compare the exact value to MAX_SIG near the end, // this is just a quick, cheap rejection (and also frees the rest of the code from // worrying about underflow). if num_digits > 16 { return None; } - if e.abs() >= T::ceil_log5_of_max_sig() as i64 { + if e.abs() >= T::CEIL_LOG5_OF_MAX_SIG as i64 { return None; } let f = num::from_str_unchecked(integral.iter().chain(fractional.iter())); - if f > T::max_sig() { + if f > T::MAX_SIG { return None; } @@ -141,7 +141,7 @@ pub fn fast_path(integral: &[u8], fractional: &[u8], e: i64) -> Opt /// /// It rounds ``f`` to a float with 64 bit significand and multiplies it by the best approximation /// of `10^e` (in the same floating point format). This is often enough to get the correct result. -/// However, when the result is close to halfway between two adjecent (ordinary) floats, the +/// However, when the result is close to halfway between two adjacent (ordinary) floats, the /// compound rounding error from multiplying two approximation means the result may be off by a /// few bits. When this happens, the iterative Algorithm R fixes things up. /// @@ -154,14 +154,14 @@ pub fn fast_path(integral: &[u8], fractional: &[u8], e: i64) -> Opt /// > the best possible approximation that uses p bits of significand.) pub fn bellerophon(f: &Big, e: i16) -> T { let slop; - if f <= &Big::from_u64(T::max_sig()) { + if f <= &Big::from_u64(T::MAX_SIG) { // The cases abs(e) < log5(2^N) are in fast_path() slop = if e >= 0 { 0 } else { 3 }; } else { slop = if e >= 0 { 1 } else { 4 }; } let z = rawfp::big_to_fp(f).mul(&power_of_ten(e)).normalize(); - let exp_p_n = 1 << (P - T::sig_bits() as u32); + let exp_p_n = 1 << (P - T::SIG_BITS as u32); let lowbits: i64 = (z.f % exp_p_n) as i64; // Is the slop large enough to make a difference when // rounding to n bits? @@ -210,14 +210,14 @@ fn algorithm_r(f: &Big, e: i16, z0: T) -> T { if d2 < y { let mut d2_double = d2; d2_double.mul_pow2(1); - if m == T::min_sig() && d_negative && d2_double > y { + if m == T::MIN_SIG && d_negative && d2_double > y { z = prev_float(z); } else { return z; } } else if d2 == y { if m % 2 == 0 { - if m == T::min_sig() && d_negative { + if m == T::MIN_SIG && d_negative { z = prev_float(z); } else { return z; @@ -303,12 +303,12 @@ pub fn algorithm_m(f: &Big, e: i16) -> T { quick_start::(&mut u, &mut v, &mut k); let mut rem = Big::from_small(0); let mut x = Big::from_small(0); - let min_sig = Big::from_u64(T::min_sig()); - let max_sig = Big::from_u64(T::max_sig()); + let min_sig = Big::from_u64(T::MIN_SIG); + let max_sig = Big::from_u64(T::MAX_SIG); loop { u.div_rem(&v, &mut x, &mut rem); - if k == T::min_exp_int() { - // We have to stop at the minimum exponent, if we wait until `k < T::min_exp_int()`, + if k == T::MIN_EXP_INT { + // We have to stop at the minimum exponent, if we wait until `k < T::MIN_EXP_INT`, // then we'd be off by a factor of two. Unfortunately this means we have to special- // case normal numbers with the minimum exponent. // FIXME find a more elegant formulation, but run the `tiny-pow10` test to make sure @@ -318,8 +318,8 @@ pub fn algorithm_m(f: &Big, e: i16) -> T { } return underflow(x, v, rem); } - if k > T::max_exp_int() { - return T::infinity2(); + if k > T::MAX_EXP_INT { + return T::INFINITY; } if x < min_sig { u.mul_pow2(1); @@ -345,18 +345,18 @@ fn quick_start(u: &mut Big, v: &mut Big, k: &mut i16) { // The target ratio is one where u/v is in an in-range significand. Thus our termination // condition is log2(u / v) being the significand bits, plus/minus one. // FIXME Looking at the second bit could improve the estimate and avoid some more divisions. - let target_ratio = T::sig_bits() as i16; + let target_ratio = T::SIG_BITS as i16; let log2_u = u.bit_length() as i16; let log2_v = v.bit_length() as i16; let mut u_shift: i16 = 0; let mut v_shift: i16 = 0; assert!(*k == 0); loop { - if *k == T::min_exp_int() { + if *k == T::MIN_EXP_INT { // Underflow or subnormal. Leave it to the main function. break; } - if *k == T::max_exp_int() { + if *k == T::MAX_EXP_INT { // Overflow. Leave it to the main function. break; } @@ -376,7 +376,7 @@ fn quick_start(u: &mut Big, v: &mut Big, k: &mut i16) { } fn underflow(x: Big, v: Big, rem: Big) -> T { - if x < Big::from_u64(T::min_sig()) { + if x < Big::from_u64(T::MIN_SIG) { let q = num::to_u64(&x); let z = rawfp::encode_subnormal(q); return round_by_remainder(v, rem, q, z); @@ -392,12 +392,12 @@ fn underflow(x: Big, v: Big, rem: Big) -> T { // // Therefore, when the rounded-off bits are != 0.5 ULP, they decide the rounding // on their own. When they are equal and the remainder is non-zero, the value still - // needs to be rounded up. Only when the rounded off bits are 1/2 and the remainer + // needs to be rounded up. Only when the rounded off bits are 1/2 and the remainder // is zero, we have a half-to-even situation. let bits = x.bit_length(); - let lsb = bits - T::sig_bits() as usize; + let lsb = bits - T::SIG_BITS as usize; let q = num::get_bits(&x, lsb, bits); - let k = T::min_exp_int() + lsb as i16; + let k = T::MIN_EXP_INT + lsb as i16; let z = rawfp::encode_normal(Unpacked::new(q, k)); let q_even = q % 2 == 0; match num::compare_with_half_ulp(&x, lsb) { diff --git a/src/libcore/num/dec2flt/mod.rs b/src/libcore/num/dec2flt/mod.rs index eee3e9250fe8..f353770a736e 100644 --- a/src/libcore/num/dec2flt/mod.rs +++ b/src/libcore/num/dec2flt/mod.rs @@ -214,11 +214,11 @@ fn dec2flt(s: &str) -> Result { let (sign, s) = extract_sign(s); let flt = match parse_decimal(s) { ParseResult::Valid(decimal) => convert(decimal)?, - ParseResult::ShortcutToInf => T::infinity2(), - ParseResult::ShortcutToZero => T::zero2(), + ParseResult::ShortcutToInf => T::INFINITY, + ParseResult::ShortcutToZero => T::ZERO, ParseResult::Invalid => match s { - "inf" => T::infinity2(), - "NaN" => T::nan2(), + "inf" => T::INFINITY, + "NaN" => T::NAN, _ => { return Err(pfe_invalid()); } } }; @@ -254,7 +254,7 @@ fn convert(mut decimal: Decimal) -> Result { // FIXME These bounds are rather conservative. A more careful analysis of the failure modes // of Bellerophon could allow using it in more cases for a massive speed up. let exponent_in_range = table::MIN_E <= e && e <= table::MAX_E; - let value_in_range = upper_bound <= T::max_normal_digits() as u64; + let value_in_range = upper_bound <= T::MAX_NORMAL_DIGITS as u64; if exponent_in_range && value_in_range { Ok(algorithm::bellerophon(&f, e)) } else { @@ -315,17 +315,17 @@ fn bound_intermediate_digits(decimal: &Decimal, e: i64) -> u64 { fn trivial_cases(decimal: &Decimal) -> Option { // There were zeros but they were stripped by simplify() if decimal.integral.is_empty() && decimal.fractional.is_empty() { - return Some(T::zero2()); + return Some(T::ZERO); } // This is a crude approximation of ceil(log10(the real value)). We don't need to worry too // much about overflow here because the input length is tiny (at least compared to 2^64) and // the parser already handles exponents whose absolute value is greater than 10^18 // (which is still 10^19 short of 2^64). let max_place = decimal.exp + decimal.integral.len() as i64; - if max_place > T::inf_cutoff() { - return Some(T::infinity2()); - } else if max_place < T::zero_cutoff() { - return Some(T::zero2()); + if max_place > T::INF_CUTOFF { + return Some(T::INFINITY); + } else if max_place < T::ZERO_CUTOFF { + return Some(T::ZERO); } None } diff --git a/src/libcore/num/dec2flt/rawfp.rs b/src/libcore/num/dec2flt/rawfp.rs index e3b58b6cc7ce..2a60292d0232 100644 --- a/src/libcore/num/dec2flt/rawfp.rs +++ b/src/libcore/num/dec2flt/rawfp.rs @@ -10,12 +10,12 @@ //! Bit fiddling on positive IEEE 754 floats. Negative numbers aren't and needn't be handled. //! Normal floating point numbers have a canonical representation as (frac, exp) such that the -//! value is 2^exp * (1 + sum(frac[N-i] / 2^i)) where N is the number of bits. Subnormals are -//! slightly different and weird, but the same principle applies. +//! value is 2exp * (1 + sum(frac[N-i] / 2i)) where N is the number of bits. +//! Subnormals are slightly different and weird, but the same principle applies. //! -//! Here, however, we represent them as (sig, k) with f positive, such that the value is f * 2^e. -//! Besides making the "hidden bit" explicit, this changes the exponent by the so-called -//! mantissa shift. +//! Here, however, we represent them as (sig, k) with f positive, such that the value is f * +//! 2e. Besides making the "hidden bit" explicit, this changes the exponent by the +//! so-called mantissa shift. //! //! Put another way, normally floats are written as (1) but here they are written as (2): //! @@ -56,30 +56,15 @@ impl Unpacked { /// /// Should **never ever** be implemented for other types or be used outside the dec2flt module. /// Inherits from `Float` because there is some overlap, but all the reused methods are trivial. -/// The "methods" (pseudo-constants) with default implementation should not be overriden. pub trait RawFloat : Float + Copy + Debug + LowerExp + Mul + Div + Neg { - // suffix of "2" because Float::infinity is deprecated - #[allow(deprecated)] - fn infinity2() -> Self { - Float::infinity() - } + const INFINITY: Self; + const NAN: Self; + const ZERO: Self; - // suffix of "2" because Float::nan is deprecated - #[allow(deprecated)] - fn nan2() -> Self { - Float::nan() - } - - // suffix of "2" because Float::zero is deprecated - fn zero2() -> Self; - - // suffix of "2" because Float::integer_decode is deprecated - #[allow(deprecated)] - fn integer_decode2(self) -> (u64, i16, i8) { - Float::integer_decode(self) - } + /// Returns the mantissa, exponent and sign as integers. + fn integer_decode(self) -> (u64, i16, i8); /// Get the raw binary representation of the float. fn transmute(self) -> u64; @@ -94,92 +79,97 @@ pub trait RawFloat : Float + Copy + Debug + LowerExp /// represented, the other code in this module makes sure to never let that happen. fn from_int(x: u64) -> Self; - /// Get the value 10^e from a pre-computed table. Panics for e >= ceil_log5_of_max_sig(). + /// Get the value 10e from a pre-computed table. + /// Panics for `e >= CEIL_LOG5_OF_MAX_SIG`. fn short_fast_pow10(e: usize) -> Self; - // FIXME Everything that follows should be associated constants, but taking the value of an - // associated constant from a type parameter does not work (yet?) - // A possible workaround is having a `FloatInfo` struct for all the constants, but so far - // the methods aren't painful enough to rewrite. - /// What the name says. It's easier to hard code than juggling intrinsics and /// hoping LLVM constant folds it. - fn ceil_log5_of_max_sig() -> i16; + const CEIL_LOG5_OF_MAX_SIG: i16; // A conservative bound on the decimal digits of inputs that can't produce overflow or zero or /// subnormals. Probably the decimal exponent of the maximum normal value, hence the name. - fn max_normal_digits() -> usize; + const MAX_NORMAL_DIGITS: usize; /// When the most significant decimal digit has a place value greater than this, the number /// is certainly rounded to infinity. - fn inf_cutoff() -> i64; + const INF_CUTOFF: i64; /// When the most significant decimal digit has a place value less than this, the number /// is certainly rounded to zero. - fn zero_cutoff() -> i64; + const ZERO_CUTOFF: i64; /// The number of bits in the exponent. - fn exp_bits() -> u8; + const EXP_BITS: u8; /// The number of bits in the singificand, *including* the hidden bit. - fn sig_bits() -> u8; + const SIG_BITS: u8; /// The number of bits in the singificand, *excluding* the hidden bit. - fn explicit_sig_bits() -> u8 { - Self::sig_bits() - 1 - } + const EXPLICIT_SIG_BITS: u8; /// The maximum legal exponent in fractional representation. - fn max_exp() -> i16 { - (1 << (Self::exp_bits() - 1)) - 1 - } + const MAX_EXP: i16; /// The minimum legal exponent in fractional representation, excluding subnormals. - fn min_exp() -> i16 { - -Self::max_exp() + 1 - } + const MIN_EXP: i16; /// `MAX_EXP` for integral representation, i.e., with the shift applied. - fn max_exp_int() -> i16 { - Self::max_exp() - (Self::sig_bits() as i16 - 1) - } + const MAX_EXP_INT: i16; /// `MAX_EXP` encoded (i.e., with offset bias) - fn max_encoded_exp() -> i16 { - (1 << Self::exp_bits()) - 1 - } + const MAX_ENCODED_EXP: i16; /// `MIN_EXP` for integral representation, i.e., with the shift applied. - fn min_exp_int() -> i16 { - Self::min_exp() - (Self::sig_bits() as i16 - 1) - } + const MIN_EXP_INT: i16; /// The maximum normalized singificand in integral representation. - fn max_sig() -> u64 { - (1 << Self::sig_bits()) - 1 - } + const MAX_SIG: u64; /// The minimal normalized significand in integral representation. - fn min_sig() -> u64 { - 1 << (Self::sig_bits() - 1) + const MIN_SIG: u64; +} + +// Mostly a workaround for #34344. +macro_rules! other_constants { + ($type: ident) => { + const EXPLICIT_SIG_BITS: u8 = Self::SIG_BITS - 1; + const MAX_EXP: i16 = (1 << (Self::EXP_BITS - 1)) - 1; + const MIN_EXP: i16 = -Self::MAX_EXP + 1; + const MAX_EXP_INT: i16 = Self::MAX_EXP - (Self::SIG_BITS as i16 - 1); + const MAX_ENCODED_EXP: i16 = (1 << Self::EXP_BITS) - 1; + const MIN_EXP_INT: i16 = Self::MIN_EXP - (Self::SIG_BITS as i16 - 1); + const MAX_SIG: u64 = (1 << Self::SIG_BITS) - 1; + const MIN_SIG: u64 = 1 << (Self::SIG_BITS - 1); + + const INFINITY: Self = $crate::$type::INFINITY; + const NAN: Self = $crate::$type::NAN; + const ZERO: Self = 0.0; } } impl RawFloat for f32 { - fn zero2() -> Self { - 0.0 - } + const SIG_BITS: u8 = 24; + const EXP_BITS: u8 = 8; + const CEIL_LOG5_OF_MAX_SIG: i16 = 11; + const MAX_NORMAL_DIGITS: usize = 35; + const INF_CUTOFF: i64 = 40; + const ZERO_CUTOFF: i64 = -48; + other_constants!(f32); - fn sig_bits() -> u8 { - 24 - } - - fn exp_bits() -> u8 { - 8 - } - - fn ceil_log5_of_max_sig() -> i16 { - 11 + /// Returns the mantissa, exponent and sign as integers. + fn integer_decode(self) -> (u64, i16, i8) { + let bits: u32 = unsafe { transmute(self) }; + let sign: i8 = if bits >> 31 == 0 { 1 } else { -1 }; + let mut exponent: i16 = ((bits >> 23) & 0xff) as i16; + let mantissa = if exponent == 0 { + (bits & 0x7fffff) << 1 + } else { + (bits & 0x7fffff) | 0x800000 + }; + // Exponent bias + mantissa shift + exponent -= 127 + 23; + (mantissa as u64, exponent, sign) } fn transmute(self) -> u64 { @@ -193,7 +183,7 @@ impl RawFloat for f32 { } fn unpack(self) -> Unpacked { - let (sig, exp, _sig) = self.integer_decode2(); + let (sig, exp, _sig) = self.integer_decode(); Unpacked::new(sig, exp) } @@ -206,36 +196,31 @@ impl RawFloat for f32 { fn short_fast_pow10(e: usize) -> Self { table::F32_SHORT_POWERS[e] } - - fn max_normal_digits() -> usize { - 35 - } - - fn inf_cutoff() -> i64 { - 40 - } - - fn zero_cutoff() -> i64 { - -48 - } } impl RawFloat for f64 { - fn zero2() -> Self { - 0.0 - } + const SIG_BITS: u8 = 53; + const EXP_BITS: u8 = 11; + const CEIL_LOG5_OF_MAX_SIG: i16 = 23; + const MAX_NORMAL_DIGITS: usize = 305; + const INF_CUTOFF: i64 = 310; + const ZERO_CUTOFF: i64 = -326; + other_constants!(f64); - fn sig_bits() -> u8 { - 53 - } - - fn exp_bits() -> u8 { - 11 - } - - fn ceil_log5_of_max_sig() -> i16 { - 23 + /// Returns the mantissa, exponent and sign as integers. + fn integer_decode(self) -> (u64, i16, i8) { + let bits: u64 = unsafe { transmute(self) }; + let sign: i8 = if bits >> 63 == 0 { 1 } else { -1 }; + let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16; + let mantissa = if exponent == 0 { + (bits & 0xfffffffffffff) << 1 + } else { + (bits & 0xfffffffffffff) | 0x10000000000000 + }; + // Exponent bias + mantissa shift + exponent -= 1023 + 52; + (mantissa, exponent, sign) } fn transmute(self) -> u64 { @@ -248,7 +233,7 @@ impl RawFloat for f64 { } fn unpack(self) -> Unpacked { - let (sig, exp, _sig) = self.integer_decode2(); + let (sig, exp, _sig) = self.integer_decode(); Unpacked::new(sig, exp) } @@ -261,38 +246,27 @@ impl RawFloat for f64 { fn short_fast_pow10(e: usize) -> Self { table::F64_SHORT_POWERS[e] } - - fn max_normal_digits() -> usize { - 305 - } - - fn inf_cutoff() -> i64 { - 310 - } - - fn zero_cutoff() -> i64 { - -326 - } - } -/// Convert an Fp to the closest f64. Only handles number that fit into a normalized f64. +/// Convert 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(); // x.f is 64 bit, so x.e has a mantissa shift of 63 let e = x.e + 63; - if e > T::max_exp() { + if e > T::MAX_EXP { panic!("fp_to_float: exponent {} too large", e) - } else if e > T::min_exp() { + } else if e > T::MIN_EXP { encode_normal(round_normal::(x)) } else { panic!("fp_to_float: exponent {} too small", e) } } -/// Round the 64-bit significand to 53 bit with half-to-even. Does not handle exponent overflow. +/// Round the 64-bit significand to T::SIG_BITS bits with half-to-even. +/// Does not handle exponent overflow. pub fn round_normal(x: Fp) -> Unpacked { - let excess = 64 - T::sig_bits() as i16; + let excess = 64 - T::SIG_BITS as i16; let half: u64 = 1 << (excess - 1); let (q, rem) = (x.f >> excess, x.f & ((1 << excess) - 1)); assert_eq!(q << excess | rem, x.f); @@ -302,8 +276,8 @@ pub fn round_normal(x: Fp) -> Unpacked { Unpacked::new(q, k) } else if rem == half && (q % 2) == 0 { Unpacked::new(q, k) - } else if q == T::max_sig() { - Unpacked::new(T::min_sig(), k + 1) + } else if q == T::MAX_SIG { + Unpacked::new(T::MIN_SIG, k + 1) } else { Unpacked::new(q + 1, k) } @@ -312,22 +286,22 @@ pub fn round_normal(x: Fp) -> Unpacked { /// Inverse of `RawFloat::unpack()` for normalized numbers. /// Panics if the significand or exponent are not valid for normalized numbers. pub fn encode_normal(x: Unpacked) -> T { - debug_assert!(T::min_sig() <= x.sig && x.sig <= T::max_sig(), + debug_assert!(T::MIN_SIG <= x.sig && x.sig <= T::MAX_SIG, "encode_normal: significand not normalized"); // Remove the hidden bit - let sig_enc = x.sig & !(1 << T::explicit_sig_bits()); + let sig_enc = x.sig & !(1 << T::EXPLICIT_SIG_BITS); // Adjust the exponent for exponent bias and mantissa shift - let k_enc = x.k + T::max_exp() + T::explicit_sig_bits() as i16; - debug_assert!(k_enc != 0 && k_enc < T::max_encoded_exp(), + let k_enc = x.k + T::MAX_EXP + T::EXPLICIT_SIG_BITS as i16; + debug_assert!(k_enc != 0 && k_enc < T::MAX_ENCODED_EXP, "encode_normal: exponent out of range"); // Leave sign bit at 0 ("+"), our numbers are all positive - let bits = (k_enc as u64) << T::explicit_sig_bits() | sig_enc; + let bits = (k_enc as u64) << T::EXPLICIT_SIG_BITS | sig_enc; T::from_bits(bits) } -/// Construct the subnormal. A mantissa of 0 is allowed and constructs zero. +/// Construct a subnormal. A mantissa of 0 is allowed and constructs zero. pub fn encode_subnormal(significand: u64) -> T { - assert!(significand < T::min_sig(), "encode_subnormal: not actually subnormal"); + assert!(significand < T::MIN_SIG, "encode_subnormal: not actually subnormal"); // Encoded exponent is 0, the sign bit is 0, so we just have to reinterpret the bits. T::from_bits(significand) } @@ -363,8 +337,8 @@ pub fn prev_float(x: T) -> T { Zero => panic!("prev_float: argument is zero"), Normal => { let Unpacked { sig, k } = x.unpack(); - if sig == T::min_sig() { - encode_normal(Unpacked::new(T::max_sig(), k - 1)) + if sig == T::MIN_SIG { + encode_normal(Unpacked::new(T::MAX_SIG, k - 1)) } else { encode_normal(Unpacked::new(sig - 1, k)) } @@ -379,7 +353,7 @@ pub fn prev_float(x: T) -> T { pub fn next_float(x: T) -> T { match x.classify() { Nan => panic!("next_float: argument is NaN"), - Infinite => T::infinity2(), + Infinite => T::INFINITY, // This seems too good to be true, but it works. // 0.0 is encoded as the all-zero word. Subnormals are 0x000m...m where m is the mantissa. // In particular, the smallest subnormal is 0x0...01 and the largest is 0x000F...F. diff --git a/src/libcore/num/diy_float.rs b/src/libcore/num/diy_float.rs index 11eea753f93f..6635d95155f4 100644 --- a/src/libcore/num/diy_float.rs +++ b/src/libcore/num/diy_float.rs @@ -10,7 +10,7 @@ //! Extended precision "soft float", for internal use only. -// This module is only for dec2flt and flt2dec, and only public because of libcoretest. +// This module is only for dec2flt and flt2dec, and only public because of coretests. // It is not intended to ever be stabilized. #![doc(hidden)] #![unstable(feature = "core_private_diy_float", diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 4527d46a27d8..91ca213e96e0 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -143,36 +143,6 @@ pub mod consts { reason = "stable interface is via `impl f{32,64}` in later crates", issue = "32110")] impl Float for f32 { - #[inline] - fn nan() -> f32 { - NAN - } - - #[inline] - fn infinity() -> f32 { - INFINITY - } - - #[inline] - fn neg_infinity() -> f32 { - NEG_INFINITY - } - - #[inline] - fn zero() -> f32 { - 0.0 - } - - #[inline] - fn neg_zero() -> f32 { - -0.0 - } - - #[inline] - fn one() -> f32 { - 1.0 - } - /// Returns `true` if the number is NaN. #[inline] fn is_nan(self) -> bool { @@ -214,21 +184,6 @@ impl Float for f32 { } } - /// Returns the mantissa, exponent and sign as integers. - fn integer_decode(self) -> (u64, i16, i8) { - let bits: u32 = unsafe { mem::transmute(self) }; - let sign: i8 = if bits >> 31 == 0 { 1 } else { -1 }; - let mut exponent: i16 = ((bits >> 23) & 0xff) as i16; - let mantissa = if exponent == 0 { - (bits & 0x7fffff) << 1 - } else { - (bits & 0x7fffff) | 0x800000 - }; - // Exponent bias + mantissa shift - exponent -= 127 + 23; - (mantissa as u64, exponent, sign) - } - /// Computes the absolute value of `self`. Returns `Float::nan()` if the /// number is `Float::nan()`. #[inline] diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index 991a85683494..7d6d6cef0497 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -143,36 +143,6 @@ pub mod consts { reason = "stable interface is via `impl f{32,64}` in later crates", issue = "32110")] impl Float for f64 { - #[inline] - fn nan() -> f64 { - NAN - } - - #[inline] - fn infinity() -> f64 { - INFINITY - } - - #[inline] - fn neg_infinity() -> f64 { - NEG_INFINITY - } - - #[inline] - fn zero() -> f64 { - 0.0 - } - - #[inline] - fn neg_zero() -> f64 { - -0.0 - } - - #[inline] - fn one() -> f64 { - 1.0 - } - /// Returns `true` if the number is NaN. #[inline] fn is_nan(self) -> bool { @@ -214,21 +184,6 @@ impl Float for f64 { } } - /// Returns the mantissa, exponent and sign as integers. - fn integer_decode(self) -> (u64, i16, i8) { - let bits: u64 = unsafe { mem::transmute(self) }; - let sign: i8 = if bits >> 63 == 0 { 1 } else { -1 }; - let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16; - let mantissa = if exponent == 0 { - (bits & 0xfffffffffffff) << 1 - } else { - (bits & 0xfffffffffffff) | 0x10000000000000 - }; - // Exponent bias + mantissa shift - exponent -= 1023 + 52; - (mantissa, exponent, sign) - } - /// Computes the absolute value of `self`. Returns `Float::nan()` if the /// number is `Float::nan()`. #[inline] diff --git a/src/libcore/num/flt2dec/decoder.rs b/src/libcore/num/flt2dec/decoder.rs index 72529d3da01d..b779eefce575 100644 --- a/src/libcore/num/flt2dec/decoder.rs +++ b/src/libcore/num/flt2dec/decoder.rs @@ -67,7 +67,7 @@ impl DecodableFloat for f64 { /// Returns a sign (true when negative) and `FullDecoded` value /// from given floating point number. pub fn decode(v: T) -> (/*negative?*/ bool, FullDecoded) { - let (mant, exp, sign) = v.integer_decode2(); + let (mant, exp, sign) = v.integer_decode(); let even = (mant & 1) == 0; let decoded = match v.classify() { FpCategory::Nan => FullDecoded::Nan, @@ -81,7 +81,7 @@ pub fn decode(v: T) -> (/*negative?*/ bool, FullDecoded) { exp: exp, inclusive: even }) } FpCategory::Normal => { - let minnorm = ::min_pos_norm_value().integer_decode2(); + let minnorm = ::min_pos_norm_value().integer_decode(); if mant == minnorm.0 { // neighbors: (maxmant, exp - 1) -- (minnormmant, exp) -- (minnormmant + 1, exp) // where maxmant = minnormmant * 2 - 1 diff --git a/src/libcore/num/flt2dec/mod.rs b/src/libcore/num/flt2dec/mod.rs index f6c03a59f81e..5123e42df61c 100644 --- a/src/libcore/num/flt2dec/mod.rs +++ b/src/libcore/num/flt2dec/mod.rs @@ -118,7 +118,7 @@ provide a large enough buffer and `Part` array, and to assemble the final string from resulting `Part`s itself. All algorithms and formatting functions are accompanied by extensive tests -in `coretest::num::flt2dec` module. It also shows how to use individual +in `coretests::num::flt2dec` module. It also shows how to use individual functions. */ diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index df343c9d45f2..18e2c1d5c73f 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -90,84 +90,12 @@ impl fmt::UpperHex for Wrapping { mod wrapping; -// All these modules are technically private and only exposed for libcoretest: +// All these modules are technically private and only exposed for coretests: pub mod flt2dec; pub mod dec2flt; pub mod bignum; pub mod diy_float; -/// Types that have a "zero" value. -/// -/// This trait is intended for use in conjunction with `Add`, as an identity: -/// `x + T::zero() == x`. -#[unstable(feature = "zero_one", - reason = "unsure of placement, wants to use associated constants", - issue = "27739")] -#[rustc_deprecated(since = "1.11.0", reason = "no longer used for \ - Iterator::sum")] -pub trait Zero: Sized { - /// The "zero" (usually, additive identity) for this type. - fn zero() -> Self; -} - -/// Types that have a "one" value. -/// -/// This trait is intended for use in conjunction with `Mul`, as an identity: -/// `x * T::one() == x`. -#[unstable(feature = "zero_one", - reason = "unsure of placement, wants to use associated constants", - issue = "27739")] -#[rustc_deprecated(since = "1.11.0", reason = "no longer used for \ - Iterator::product")] -pub trait One: Sized { - /// The "one" (usually, multiplicative identity) for this type. - fn one() -> Self; -} - -macro_rules! zero_one_impl { - ($($t:ty)*) => ($( - #[unstable(feature = "zero_one", - reason = "unsure of placement, wants to use associated constants", - issue = "27739")] - #[allow(deprecated)] - impl Zero for $t { - #[inline] - fn zero() -> Self { 0 } - } - #[unstable(feature = "zero_one", - reason = "unsure of placement, wants to use associated constants", - issue = "27739")] - #[allow(deprecated)] - impl One for $t { - #[inline] - fn one() -> Self { 1 } - } - )*) -} -zero_one_impl! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize } - -macro_rules! zero_one_impl_float { - ($($t:ty)*) => ($( - #[unstable(feature = "zero_one", - reason = "unsure of placement, wants to use associated constants", - issue = "27739")] - #[allow(deprecated)] - impl Zero for $t { - #[inline] - fn zero() -> Self { 0.0 } - } - #[unstable(feature = "zero_one", - reason = "unsure of placement, wants to use associated constants", - issue = "27739")] - #[allow(deprecated)] - impl One for $t { - #[inline] - fn one() -> Self { 1.0 } - } - )*) -} -zero_one_impl_float! { f32 f64 } - macro_rules! checked_op { ($U:ty, $op:path, $x:expr, $y:expr) => {{ let (result, overflowed) = unsafe { $op($x as $U, $y as $U) }; @@ -850,21 +778,12 @@ macro_rules! int_impl { /// ``` #[stable(feature = "num_wrapping", since = "1.2.0")] #[inline(always)] - #[cfg(not(stage0))] pub fn wrapping_shl(self, rhs: u32) -> Self { unsafe { intrinsics::unchecked_shl(self, (rhs & ($BITS - 1)) as $SelfT) } } - /// Stage 0 - #[stable(feature = "num_wrapping", since = "1.2.0")] - #[inline(always)] - #[cfg(stage0)] - pub fn wrapping_shl(self, rhs: u32) -> Self { - self.overflowing_shl(rhs).0 - } - /// Panic-free bitwise shift-right; yields `self >> mask(rhs)`, /// where `mask` removes any high-order bits of `rhs` that /// would cause the shift to exceed the bitwidth of the type. @@ -886,21 +805,12 @@ macro_rules! int_impl { /// ``` #[stable(feature = "num_wrapping", since = "1.2.0")] #[inline(always)] - #[cfg(not(stage0))] pub fn wrapping_shr(self, rhs: u32) -> Self { unsafe { intrinsics::unchecked_shr(self, (rhs & ($BITS - 1)) as $SelfT) } } - /// Stage 0 - #[stable(feature = "num_wrapping", since = "1.2.0")] - #[inline(always)] - #[cfg(stage0)] - pub fn wrapping_shr(self, rhs: u32) -> Self { - self.overflowing_shr(rhs).0 - } - /// Wrapping (modular) absolute value. Computes `self.abs()`, /// wrapping around at the boundary of the type. /// @@ -1111,19 +1021,10 @@ macro_rules! int_impl { /// ``` #[inline] #[stable(feature = "wrapping", since = "1.7.0")] - #[cfg(not(stage0))] pub fn overflowing_shl(self, rhs: u32) -> (Self, bool) { (self.wrapping_shl(rhs), (rhs > ($BITS - 1))) } - /// Stage 0 - #[inline] - #[stable(feature = "wrapping", since = "1.7.0")] - #[cfg(stage0)] - pub fn overflowing_shl(self, rhs: u32) -> (Self, bool) { - (self << (rhs & ($BITS - 1)), (rhs > ($BITS - 1))) - } - /// Shifts self right by `rhs` bits. /// /// Returns a tuple of the shifted version of self along with a boolean @@ -1142,19 +1043,10 @@ macro_rules! int_impl { /// ``` #[inline] #[stable(feature = "wrapping", since = "1.7.0")] - #[cfg(not(stage0))] pub fn overflowing_shr(self, rhs: u32) -> (Self, bool) { (self.wrapping_shr(rhs), (rhs > ($BITS - 1))) } - /// Stage 0 - #[inline] - #[stable(feature = "wrapping", since = "1.7.0")] - #[cfg(stage0)] - pub fn overflowing_shr(self, rhs: u32) -> (Self, bool) { - (self >> (rhs & ($BITS - 1)), (rhs > ($BITS - 1))) - } - /// Computes the absolute value of `self`. /// /// Returns a tuple of the absolute version of self along with a @@ -2018,21 +1910,12 @@ macro_rules! uint_impl { /// ``` #[stable(feature = "num_wrapping", since = "1.2.0")] #[inline(always)] - #[cfg(not(stage0))] pub fn wrapping_shl(self, rhs: u32) -> Self { unsafe { intrinsics::unchecked_shl(self, (rhs & ($BITS - 1)) as $SelfT) } } - /// Stage 0 - #[stable(feature = "num_wrapping", since = "1.2.0")] - #[inline(always)] - #[cfg(stage0)] - pub fn wrapping_shl(self, rhs: u32) -> Self { - self.overflowing_shl(rhs).0 - } - /// Panic-free bitwise shift-right; yields `self >> mask(rhs)`, /// where `mask` removes any high-order bits of `rhs` that /// would cause the shift to exceed the bitwidth of the type. @@ -2054,21 +1937,12 @@ macro_rules! uint_impl { /// ``` #[stable(feature = "num_wrapping", since = "1.2.0")] #[inline(always)] - #[cfg(not(stage0))] pub fn wrapping_shr(self, rhs: u32) -> Self { unsafe { intrinsics::unchecked_shr(self, (rhs & ($BITS - 1)) as $SelfT) } } - /// Stage 0 - #[stable(feature = "num_wrapping", since = "1.2.0")] - #[inline(always)] - #[cfg(stage0)] - pub fn wrapping_shr(self, rhs: u32) -> Self { - self.overflowing_shr(rhs).0 - } - /// Calculates `self` + `rhs` /// /// Returns a tuple of the addition along with a boolean indicating @@ -2232,19 +2106,10 @@ macro_rules! uint_impl { /// ``` #[inline] #[stable(feature = "wrapping", since = "1.7.0")] - #[cfg(not(stage0))] pub fn overflowing_shl(self, rhs: u32) -> (Self, bool) { (self.wrapping_shl(rhs), (rhs > ($BITS - 1))) } - /// Stage 0 - #[inline] - #[stable(feature = "wrapping", since = "1.7.0")] - #[cfg(stage0)] - pub fn overflowing_shl(self, rhs: u32) -> (Self, bool) { - (self << (rhs & ($BITS - 1)), (rhs > ($BITS - 1))) - } - /// Shifts self right by `rhs` bits. /// /// Returns a tuple of the shifted version of self along with a boolean @@ -2263,20 +2128,11 @@ macro_rules! uint_impl { /// ``` #[inline] #[stable(feature = "wrapping", since = "1.7.0")] - #[cfg(not(stage0))] pub fn overflowing_shr(self, rhs: u32) -> (Self, bool) { (self.wrapping_shr(rhs), (rhs > ($BITS - 1))) } - /// Stage 0 - #[inline] - #[stable(feature = "wrapping", since = "1.7.0")] - #[cfg(stage0)] - pub fn overflowing_shr(self, rhs: u32) -> (Self, bool) { - (self >> (rhs & ($BITS - 1)), (rhs > ($BITS - 1))) - } - /// Raises self to the power of `exp`, using exponentiation by squaring. /// /// # Examples @@ -2525,49 +2381,6 @@ pub enum FpCategory { reason = "stable interface is via `impl f{32,64}` in later crates", issue = "32110")] pub trait Float: Sized { - /// Returns the NaN value. - #[unstable(feature = "float_extras", reason = "needs removal", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - fn nan() -> Self; - /// Returns the infinite value. - #[unstable(feature = "float_extras", reason = "needs removal", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - fn infinity() -> Self; - /// Returns the negative infinite value. - #[unstable(feature = "float_extras", reason = "needs removal", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - fn neg_infinity() -> Self; - /// Returns -0.0. - #[unstable(feature = "float_extras", reason = "needs removal", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - fn neg_zero() -> Self; - /// Returns 0.0. - #[unstable(feature = "float_extras", reason = "needs removal", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - fn zero() -> Self; - /// Returns 1.0. - #[unstable(feature = "float_extras", reason = "needs removal", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - fn one() -> Self; - /// Returns `true` if this value is NaN and false otherwise. #[stable(feature = "core", since = "1.6.0")] fn is_nan(self) -> bool; @@ -2585,14 +2398,6 @@ pub trait Float: Sized { #[stable(feature = "core", since = "1.6.0")] fn classify(self) -> FpCategory; - /// Returns the mantissa, exponent and sign as integers, respectively. - #[unstable(feature = "float_extras", reason = "signature is undecided", - issue = "27752")] - #[rustc_deprecated(since = "1.11.0", - reason = "never really came to fruition and easily \ - implementable outside the standard library")] - fn integer_decode(self) -> (u64, i16, i8); - /// Computes the absolute value of `self`. Returns `Float::nan()` if the /// number is `Float::nan()`. #[stable(feature = "core", since = "1.6.0")] diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 686cc21eba1a..391b606f613f 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -196,7 +196,7 @@ pub trait Drop { fn drop(&mut self); } -/// The `Add` trait is used to specify the functionality of `+`. +/// The addition operator `+`. /// /// # Examples /// @@ -242,6 +242,7 @@ pub trait Drop { /// [std::time::SystemTime]: ../../std/time/struct.SystemTime.html #[lang = "add"] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_on_unimplemented = "no implementation for `{Self} + {RHS}`"] pub trait Add { /// The resulting type after applying the `+` operator #[stable(feature = "rust1", since = "1.0.0")] @@ -269,7 +270,7 @@ macro_rules! add_impl { add_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } -/// The `Sub` trait is used to specify the functionality of `-`. +/// The subtraction operator `-`. /// /// # Examples /// @@ -315,6 +316,7 @@ add_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// [std::time::SystemTime]: ../../std/time/struct.SystemTime.html #[lang = "sub"] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_on_unimplemented = "no implementation for `{Self} - {RHS}`"] pub trait Sub { /// The resulting type after applying the `-` operator #[stable(feature = "rust1", since = "1.0.0")] @@ -342,7 +344,7 @@ macro_rules! sub_impl { sub_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } -/// The `Mul` trait is used to specify the functionality of `*`. +/// The multiplication operator `*`. /// /// # Examples /// @@ -437,6 +439,7 @@ sub_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// ``` #[lang = "mul"] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_on_unimplemented = "no implementation for `{Self} * {RHS}`"] pub trait Mul { /// The resulting type after applying the `*` operator #[stable(feature = "rust1", since = "1.0.0")] @@ -464,7 +467,7 @@ macro_rules! mul_impl { mul_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } -/// The `Div` trait is used to specify the functionality of `/`. +/// The division operator `/`. /// /// # Examples /// @@ -565,6 +568,7 @@ mul_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// ``` #[lang = "div"] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_on_unimplemented = "no implementation for `{Self} / {RHS}`"] pub trait Div { /// The resulting type after applying the `/` operator #[stable(feature = "rust1", since = "1.0.0")] @@ -609,7 +613,7 @@ macro_rules! div_impl_float { div_impl_float! { f32 f64 } -/// The `Rem` trait is used to specify the functionality of `%`. +/// The remainder operator `%`. /// /// # Examples /// @@ -644,6 +648,7 @@ div_impl_float! { f32 f64 } /// ``` #[lang = "rem"] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_on_unimplemented = "no implementation for `{Self} % {RHS}`"] pub trait Rem { /// The resulting type after applying the `%` operator #[stable(feature = "rust1", since = "1.0.0")] @@ -689,7 +694,7 @@ macro_rules! rem_impl_float { rem_impl_float! { f32 f64 } -/// The `Neg` trait is used to specify the functionality of unary `-`. +/// The unary negation operator `-`. /// /// # Examples /// @@ -768,7 +773,7 @@ macro_rules! neg_impl_unsigned { // neg_impl_unsigned! { usize u8 u16 u32 u64 } neg_impl_numeric! { isize i8 i16 i32 i64 i128 f32 f64 } -/// The `Not` trait is used to specify the functionality of unary `!`. +/// The unary logical negation operator `!`. /// /// # Examples /// @@ -826,7 +831,7 @@ macro_rules! not_impl { not_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } -/// The `BitAnd` trait is used to specify the functionality of `&`. +/// The bitwise AND operator `&`. /// /// # Examples /// @@ -883,6 +888,7 @@ not_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// ``` #[lang = "bitand"] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_on_unimplemented = "no implementation for `{Self} & {RHS}`"] pub trait BitAnd { /// The resulting type after applying the `&` operator #[stable(feature = "rust1", since = "1.0.0")] @@ -909,7 +915,7 @@ macro_rules! bitand_impl { bitand_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } -/// The `BitOr` trait is used to specify the functionality of `|`. +/// The bitwise OR operator `|`. /// /// # Examples /// @@ -966,6 +972,7 @@ bitand_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// ``` #[lang = "bitor"] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_on_unimplemented = "no implementation for `{Self} | {RHS}`"] pub trait BitOr { /// The resulting type after applying the `|` operator #[stable(feature = "rust1", since = "1.0.0")] @@ -992,7 +999,7 @@ macro_rules! bitor_impl { bitor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } -/// The `BitXor` trait is used to specify the functionality of `^`. +/// The bitwise XOR operator `^`. /// /// # Examples /// @@ -1052,6 +1059,7 @@ bitor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// ``` #[lang = "bitxor"] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_on_unimplemented = "no implementation for `{Self} ^ {RHS}`"] pub trait BitXor { /// The resulting type after applying the `^` operator #[stable(feature = "rust1", since = "1.0.0")] @@ -1078,7 +1086,7 @@ macro_rules! bitxor_impl { bitxor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } -/// The `Shl` trait is used to specify the functionality of `<<`. +/// The left shift operator `<<`. /// /// # Examples /// @@ -1134,6 +1142,7 @@ bitxor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// ``` #[lang = "shl"] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_on_unimplemented = "no implementation for `{Self} << {RHS}`"] pub trait Shl { /// The resulting type after applying the `<<` operator #[stable(feature = "rust1", since = "1.0.0")] @@ -1181,7 +1190,7 @@ macro_rules! shl_impl_all { shl_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 isize i128 } -/// The `Shr` trait is used to specify the functionality of `>>`. +/// The right shift operator `>>`. /// /// # Examples /// @@ -1237,6 +1246,7 @@ shl_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 isize i128 } /// ``` #[lang = "shr"] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_on_unimplemented = "no implementation for `{Self} >> {RHS}`"] pub trait Shr { /// The resulting type after applying the `>>` operator #[stable(feature = "rust1", since = "1.0.0")] @@ -1284,7 +1294,7 @@ macro_rules! shr_impl_all { shr_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize } -/// The `AddAssign` trait is used to specify the functionality of `+=`. +/// The addition assignment operator `+=`. /// /// # Examples /// @@ -1321,6 +1331,7 @@ shr_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize } /// ``` #[lang = "add_assign"] #[stable(feature = "op_assign_traits", since = "1.8.0")] +#[rustc_on_unimplemented = "no implementation for `{Self} += {Rhs}`"] pub trait AddAssign { /// The method for the `+=` operator #[stable(feature = "op_assign_traits", since = "1.8.0")] @@ -1340,7 +1351,7 @@ macro_rules! add_assign_impl { add_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } -/// The `SubAssign` trait is used to specify the functionality of `-=`. +/// The subtraction assignment operator `-=`. /// /// # Examples /// @@ -1377,6 +1388,7 @@ add_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// ``` #[lang = "sub_assign"] #[stable(feature = "op_assign_traits", since = "1.8.0")] +#[rustc_on_unimplemented = "no implementation for `{Self} -= {Rhs}`"] pub trait SubAssign { /// The method for the `-=` operator #[stable(feature = "op_assign_traits", since = "1.8.0")] @@ -1396,7 +1408,7 @@ macro_rules! sub_assign_impl { sub_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } -/// The `MulAssign` trait is used to specify the functionality of `*=`. +/// The multiplication assignment operator `*=`. /// /// # Examples /// @@ -1422,6 +1434,7 @@ sub_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// ``` #[lang = "mul_assign"] #[stable(feature = "op_assign_traits", since = "1.8.0")] +#[rustc_on_unimplemented = "no implementation for `{Self} *= {Rhs}`"] pub trait MulAssign { /// The method for the `*=` operator #[stable(feature = "op_assign_traits", since = "1.8.0")] @@ -1441,7 +1454,7 @@ macro_rules! mul_assign_impl { mul_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } -/// The `DivAssign` trait is used to specify the functionality of `/=`. +/// The division assignment operator `/=`. /// /// # Examples /// @@ -1467,6 +1480,7 @@ mul_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// ``` #[lang = "div_assign"] #[stable(feature = "op_assign_traits", since = "1.8.0")] +#[rustc_on_unimplemented = "no implementation for `{Self} /= {Rhs}`"] pub trait DivAssign { /// The method for the `/=` operator #[stable(feature = "op_assign_traits", since = "1.8.0")] @@ -1485,7 +1499,7 @@ macro_rules! div_assign_impl { div_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } -/// The `RemAssign` trait is used to specify the functionality of `%=`. +/// The remainder assignment operator `%=`. /// /// # Examples /// @@ -1511,6 +1525,7 @@ div_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// ``` #[lang = "rem_assign"] #[stable(feature = "op_assign_traits", since = "1.8.0")] +#[rustc_on_unimplemented = "no implementation for `{Self} %= {Rhs}`"] pub trait RemAssign { /// The method for the `%=` operator #[stable(feature = "op_assign_traits", since = "1.8.0")] @@ -1529,7 +1544,7 @@ macro_rules! rem_assign_impl { rem_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } -/// The `BitAndAssign` trait is used to specify the functionality of `&=`. +/// The bitwise AND assignment operator `&=`. /// /// # Examples /// @@ -1597,6 +1612,7 @@ rem_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// ``` #[lang = "bitand_assign"] #[stable(feature = "op_assign_traits", since = "1.8.0")] +#[rustc_on_unimplemented = "no implementation for `{Self} &= {Rhs}`"] pub trait BitAndAssign { /// The method for the `&=` operator #[stable(feature = "op_assign_traits", since = "1.8.0")] @@ -1615,7 +1631,7 @@ macro_rules! bitand_assign_impl { bitand_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } -/// The `BitOrAssign` trait is used to specify the functionality of `|=`. +/// The bitwise OR assignment operator `|=`. /// /// # Examples /// @@ -1641,6 +1657,7 @@ bitand_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// ``` #[lang = "bitor_assign"] #[stable(feature = "op_assign_traits", since = "1.8.0")] +#[rustc_on_unimplemented = "no implementation for `{Self} |= {Rhs}`"] pub trait BitOrAssign { /// The method for the `|=` operator #[stable(feature = "op_assign_traits", since = "1.8.0")] @@ -1659,7 +1676,7 @@ macro_rules! bitor_assign_impl { bitor_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } -/// The `BitXorAssign` trait is used to specify the functionality of `^=`. +/// The bitwise XOR assignment operator `^=`. /// /// # Examples /// @@ -1685,6 +1702,7 @@ bitor_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// ``` #[lang = "bitxor_assign"] #[stable(feature = "op_assign_traits", since = "1.8.0")] +#[rustc_on_unimplemented = "no implementation for `{Self} ^= {Rhs}`"] pub trait BitXorAssign { /// The method for the `^=` operator #[stable(feature = "op_assign_traits", since = "1.8.0")] @@ -1703,7 +1721,7 @@ macro_rules! bitxor_assign_impl { bitxor_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } -/// The `ShlAssign` trait is used to specify the functionality of `<<=`. +/// The left shift assignment operator `<<=`. /// /// # Examples /// @@ -1729,6 +1747,7 @@ bitxor_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// ``` #[lang = "shl_assign"] #[stable(feature = "op_assign_traits", since = "1.8.0")] +#[rustc_on_unimplemented = "no implementation for `{Self} <<= {Rhs}`"] pub trait ShlAssign { /// The method for the `<<=` operator #[stable(feature = "op_assign_traits", since = "1.8.0")] @@ -1768,7 +1787,7 @@ macro_rules! shl_assign_impl_all { shl_assign_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize } -/// The `ShrAssign` trait is used to specify the functionality of `>>=`. +/// The right shift assignment operator `>>=`. /// /// # Examples /// @@ -1794,6 +1813,7 @@ shl_assign_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize } /// ``` #[lang = "shr_assign"] #[stable(feature = "op_assign_traits", since = "1.8.0")] +#[rustc_on_unimplemented = "no implementation for `{Self} >>= {Rhs}`"] pub trait ShrAssign { /// The method for the `>>=` operator #[stable(feature = "op_assign_traits", since = "1.8.0")] @@ -2858,10 +2878,10 @@ pub trait Carrier { type Error; /// Create a `Carrier` from a success value. - fn from_success(Self::Success) -> Self; + fn from_success(_: Self::Success) -> Self; /// Create a `Carrier` from an error value. - fn from_error(Self::Error) -> Self; + fn from_error(_: Self::Error) -> Self; /// Translate this `Carrier` to another implementation of `Carrier` with the /// same associated types. diff --git a/src/libcore/option.rs b/src/libcore/option.rs index d997f3592fd7..515f49d6f0bd 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -66,14 +66,14 @@ //! not ([`None`]). //! //! ``` -//! let optional: Option> = None; -//! check_optional(&optional); +//! let optional = None; +//! check_optional(optional); //! -//! let optional: Option> = Some(Box::new(9000)); -//! check_optional(&optional); +//! let optional = Some(Box::new(9000)); +//! check_optional(optional); //! -//! fn check_optional(optional: &Option>) { -//! match *optional { +//! fn check_optional(optional: Option>) { +//! match optional { //! Some(ref p) => println!("has value {}", p), //! None => println!("has no value"), //! } @@ -894,9 +894,15 @@ impl ExactSizeIterator for Item {} impl FusedIterator for Item {} unsafe impl TrustedLen for Item {} -/// An iterator over a reference of the contained item in an [`Option`]. +/// An iterator over a reference to the [`Some`] variant of an [`Option`]. +/// +/// The iterator yields one value if the [`Option`] is a [`Some`], otherwise none. +/// +/// This `struct` is created by the [`Option::iter`] function. /// /// [`Option`]: enum.Option.html +/// [`Some`]: enum.Option.html#variant.Some +/// [`Option::iter`]: enum.Option.html#method.iter #[stable(feature = "rust1", since = "1.0.0")] #[derive(Debug)] pub struct Iter<'a, A: 'a> { inner: Item<&'a A> } @@ -933,9 +939,15 @@ impl<'a, A> Clone for Iter<'a, A> { } } -/// An iterator over a mutable reference of the contained item in an [`Option`]. +/// An iterator over a mutable reference to the [`Some`] variant of an [`Option`]. +/// +/// The iterator yields one value if the [`Option`] is a [`Some`], otherwise none. +/// +/// This `struct` is created by the [`Option::iter_mut`] function. /// /// [`Option`]: enum.Option.html +/// [`Some`]: enum.Option.html#variant.Some +/// [`Option::iter_mut`]: enum.Option.html#method.iter_mut #[stable(feature = "rust1", since = "1.0.0")] #[derive(Debug)] pub struct IterMut<'a, A: 'a> { inner: Item<&'a mut A> } @@ -964,9 +976,15 @@ impl<'a, A> FusedIterator for IterMut<'a, A> {} #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl<'a, A> TrustedLen for IterMut<'a, A> {} -/// An iterator over the item contained inside an [`Option`]. +/// An iterator over the value in [`Some`] variant of an [`Option`]. +/// +/// The iterator yields one value if the [`Option`] is a [`Some`], otherwise none. +/// +/// This `struct` is created by the [`Option::into_iter`] function. /// /// [`Option`]: enum.Option.html +/// [`Some`]: enum.Option.html#variant.Some +/// [`Option::into_iter`]: enum.Option.html#method.into_iter #[derive(Clone, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter { inner: Item } diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index d2830a6d00ce..115326bb9169 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -37,11 +37,6 @@ pub use intrinsics::copy; #[stable(feature = "rust1", since = "1.0.0")] pub use intrinsics::write_bytes; -#[cfg(stage0)] -#[stable(feature = "drop_in_place", since = "1.8.0")] -pub use intrinsics::drop_in_place; - -#[cfg(not(stage0))] /// Executes the destructor (if any) of the pointed-to value. /// /// This has two use cases: @@ -500,6 +495,44 @@ impl *const T { intrinsics::arith_offset(self, count) } } + + /// Calculates the distance between two pointers. The returned value is in + /// units of T: the distance in bytes is divided by `mem::size_of::()`. + /// + /// If the address different between the two pointers ia not a multiple of + /// `mem::size_of::()` then the result of the division is rounded towards + /// zero. + /// + /// This function returns `None` if `T` is a zero-sized typed. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(offset_to)] + /// + /// fn main() { + /// let a = [0; 5]; + /// let ptr1: *const i32 = &a[1]; + /// let ptr2: *const i32 = &a[3]; + /// assert_eq!(ptr1.offset_to(ptr2), Some(2)); + /// assert_eq!(ptr2.offset_to(ptr1), Some(-2)); + /// assert_eq!(unsafe { ptr1.offset(2) }, ptr2); + /// assert_eq!(unsafe { ptr2.offset(-2) }, ptr1); + /// } + /// ``` + #[unstable(feature = "offset_to", issue = "41079")] + #[inline] + pub fn offset_to(self, other: *const T) -> Option where T: Sized { + let size = mem::size_of::(); + if size == 0 { + None + } else { + let diff = (other as isize).wrapping_sub(self as isize); + Some(diff / size as isize) + } + } } #[lang = "mut_ptr"] @@ -653,6 +686,44 @@ impl *mut T { Some(&mut *self) } } + + /// Calculates the distance between two pointers. The returned value is in + /// units of T: the distance in bytes is divided by `mem::size_of::()`. + /// + /// If the address different between the two pointers ia not a multiple of + /// `mem::size_of::()` then the result of the division is rounded towards + /// zero. + /// + /// This function returns `None` if `T` is a zero-sized typed. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(offset_to)] + /// + /// fn main() { + /// let mut a = [0; 5]; + /// let ptr1: *mut i32 = &mut a[1]; + /// let ptr2: *mut i32 = &mut a[3]; + /// assert_eq!(ptr1.offset_to(ptr2), Some(2)); + /// assert_eq!(ptr2.offset_to(ptr1), Some(-2)); + /// assert_eq!(unsafe { ptr1.offset(2) }, ptr2); + /// assert_eq!(unsafe { ptr2.offset(-2) }, ptr1); + /// } + /// ``` + #[unstable(feature = "offset_to", issue = "41079")] + #[inline] + pub fn offset_to(self, other: *const T) -> Option where T: Sized { + let size = mem::size_of::(); + if size == 0 { + None + } else { + let diff = (other as isize).wrapping_sub(self as isize); + Some(diff / size as isize) + } + } } // Equality for pointers diff --git a/src/libcore/result.rs b/src/libcore/result.rs index 6ec8a37dfa43..c46b0c1324de 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -838,10 +838,10 @@ impl Result { /// /// assert_eq!(1909, good_year); /// assert_eq!(0, bad_year); + /// ``` /// /// [`parse`]: ../../std/primitive.str.html#method.parse /// [`FromStr`]: ../../std/str/trait.FromStr.html - /// ``` #[inline] #[stable(feature = "result_unwrap_or_default", since = "1.16.0")] pub fn unwrap_or_default(self) -> T { diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index af492b3c6397..9e3bd9115468 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -81,6 +81,10 @@ pub trait SliceExt { fn split

(&self, pred: P) -> Split where P: FnMut(&Self::Item) -> bool; + #[unstable(feature = "slice_rsplit", issue = "41020")] + fn rsplit

(&self, pred: P) -> RSplit + where P: FnMut(&Self::Item) -> bool; + #[stable(feature = "core", since = "1.6.0")] fn splitn

(&self, n: usize, pred: P) -> SplitN where P: FnMut(&Self::Item) -> bool; @@ -97,8 +101,7 @@ pub trait SliceExt { #[stable(feature = "core", since = "1.6.0")] fn get(&self, index: I) -> Option<&I::Output> - where I: SliceIndex; - + where I: SliceIndex; #[stable(feature = "core", since = "1.6.0")] fn first(&self) -> Option<&Self::Item>; @@ -113,8 +116,7 @@ pub trait SliceExt { #[stable(feature = "core", since = "1.6.0")] unsafe fn get_unchecked(&self, index: I) -> &I::Output - where I: SliceIndex; - + where I: SliceIndex; #[stable(feature = "core", since = "1.6.0")] fn as_ptr(&self) -> *const Self::Item; @@ -141,8 +143,7 @@ pub trait SliceExt { #[stable(feature = "core", since = "1.6.0")] fn get_mut(&mut self, index: I) -> Option<&mut I::Output> - where I: SliceIndex; - + where I: SliceIndex; #[stable(feature = "core", since = "1.6.0")] fn iter_mut(&mut self) -> IterMut; @@ -162,6 +163,10 @@ pub trait SliceExt { fn split_mut

(&mut self, pred: P) -> SplitMut where P: FnMut(&Self::Item) -> bool; + #[unstable(feature = "slice_rsplit", issue = "41020")] + fn rsplit_mut

(&mut self, pred: P) -> RSplitMut + where P: FnMut(&Self::Item) -> bool; + #[stable(feature = "core", since = "1.6.0")] fn splitn_mut

(&mut self, n: usize, pred: P) -> SplitNMut where P: FnMut(&Self::Item) -> bool; @@ -184,8 +189,7 @@ pub trait SliceExt { #[stable(feature = "core", since = "1.6.0")] unsafe fn get_unchecked_mut(&mut self, index: I) -> &mut I::Output - where I: SliceIndex; - + where I: SliceIndex; #[stable(feature = "core", since = "1.6.0")] fn as_mut_ptr(&mut self) -> *mut Self::Item; @@ -297,6 +301,13 @@ impl SliceExt for [T] { } } + #[inline] + fn rsplit

(&self, pred: P) -> RSplit + where P: FnMut(&T) -> bool + { + RSplit { inner: self.split(pred) } + } + #[inline] fn splitn

(&self, n: usize, pred: P) -> SplitN where P: FnMut(&T) -> bool @@ -304,8 +315,7 @@ impl SliceExt for [T] { SplitN { inner: GenericSplitN { iter: self.split(pred), - count: n, - invert: false + count: n } } } @@ -316,9 +326,8 @@ impl SliceExt for [T] { { RSplitN { inner: GenericSplitN { - iter: self.split(pred), - count: n, - invert: true + iter: self.rsplit(pred), + count: n } } } @@ -337,7 +346,7 @@ impl SliceExt for [T] { #[inline] fn get(&self, index: I) -> Option<&I::Output> - where I: SliceIndex + where I: SliceIndex<[T]> { index.get(self) } @@ -365,7 +374,7 @@ impl SliceExt for [T] { #[inline] unsafe fn get_unchecked(&self, index: I) -> &I::Output - where I: SliceIndex + where I: SliceIndex<[T]> { index.get_unchecked(self) } @@ -406,7 +415,7 @@ impl SliceExt for [T] { #[inline] fn get_mut(&mut self, index: I) -> Option<&mut I::Output> - where I: SliceIndex + where I: SliceIndex<[T]> { index.get_mut(self) } @@ -479,6 +488,13 @@ impl SliceExt for [T] { SplitMut { v: self, pred: pred, finished: false } } + #[inline] + fn rsplit_mut

(&mut self, pred: P) -> RSplitMut + where P: FnMut(&T) -> bool + { + RSplitMut { inner: self.split_mut(pred) } + } + #[inline] fn splitn_mut

(&mut self, n: usize, pred: P) -> SplitNMut where P: FnMut(&T) -> bool @@ -486,8 +502,7 @@ impl SliceExt for [T] { SplitNMut { inner: GenericSplitN { iter: self.split_mut(pred), - count: n, - invert: false + count: n } } } @@ -498,9 +513,8 @@ impl SliceExt for [T] { { RSplitNMut { inner: GenericSplitN { - iter: self.split_mut(pred), - count: n, - invert: true + iter: self.rsplit_mut(pred), + count: n } } } @@ -538,7 +552,7 @@ impl SliceExt for [T] { #[inline] unsafe fn get_unchecked_mut(&mut self, index: I) -> &mut I::Output - where I: SliceIndex + where I: SliceIndex<[T]> { index.get_unchecked_mut(self) } @@ -631,7 +645,7 @@ impl SliceExt for [T] { #[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 + where I: SliceIndex<[T]> { type Output = I::Output; @@ -644,7 +658,7 @@ 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 + where I: SliceIndex<[T]> { #[inline] fn index_mut(&mut self, index: I) -> &mut I::Output { @@ -667,37 +681,37 @@ fn slice_index_order_fail(index: usize, end: usize) -> ! { /// A helper trait used for indexing operations. #[unstable(feature = "slice_get_slice", issue = "35729")] #[rustc_on_unimplemented = "slice indices are of type `usize` or ranges of `usize`"] -pub trait SliceIndex { +pub trait SliceIndex { /// The output type returned by methods. type Output: ?Sized; /// Returns a shared reference to the output at this location, if in /// bounds. - fn get(self, slice: &[T]) -> Option<&Self::Output>; + fn get(self, slice: &T) -> Option<&Self::Output>; /// Returns a mutable reference to the output at this location, if in /// bounds. - fn get_mut(self, slice: &mut [T]) -> Option<&mut Self::Output>; + fn get_mut(self, slice: &mut T) -> Option<&mut Self::Output>; /// Returns a shared reference to the output at this location, without /// performing any bounds checking. - unsafe fn get_unchecked(self, slice: &[T]) -> &Self::Output; + unsafe fn get_unchecked(self, slice: &T) -> &Self::Output; /// Returns a mutable reference to the output at this location, without /// performing any bounds checking. - unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut Self::Output; + unsafe fn get_unchecked_mut(self, slice: &mut T) -> &mut Self::Output; /// Returns a shared reference to the output at this location, panicking /// if out of bounds. - fn index(self, slice: &[T]) -> &Self::Output; + fn index(self, slice: &T) -> &Self::Output; /// Returns a mutable reference to the output at this location, panicking /// if out of bounds. - fn index_mut(self, slice: &mut [T]) -> &mut Self::Output; + fn index_mut(self, slice: &mut T) -> &mut Self::Output; } #[stable(feature = "slice-get-slice-impls", since = "1.15.0")] -impl SliceIndex for usize { +impl SliceIndex<[T]> for usize { type Output = T; #[inline] @@ -746,7 +760,7 @@ impl SliceIndex for usize { } #[stable(feature = "slice-get-slice-impls", since = "1.15.0")] -impl SliceIndex for ops::Range { +impl SliceIndex<[T]> for ops::Range { type Output = [T]; #[inline] @@ -807,7 +821,7 @@ impl SliceIndex for ops::Range { } #[stable(feature = "slice-get-slice-impls", since = "1.15.0")] -impl SliceIndex for ops::RangeTo { +impl SliceIndex<[T]> for ops::RangeTo { type Output = [T]; #[inline] @@ -842,7 +856,7 @@ impl SliceIndex for ops::RangeTo { } #[stable(feature = "slice-get-slice-impls", since = "1.15.0")] -impl SliceIndex for ops::RangeFrom { +impl SliceIndex<[T]> for ops::RangeFrom { type Output = [T]; #[inline] @@ -877,7 +891,7 @@ impl SliceIndex for ops::RangeFrom { } #[stable(feature = "slice-get-slice-impls", since = "1.15.0")] -impl SliceIndex for ops::RangeFull { +impl SliceIndex<[T]> for ops::RangeFull { type Output = [T]; #[inline] @@ -913,7 +927,7 @@ impl SliceIndex for ops::RangeFull { #[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] -impl SliceIndex for ops::RangeInclusive { +impl SliceIndex<[T]> for ops::RangeInclusive { type Output = [T]; #[inline] @@ -976,7 +990,7 @@ impl SliceIndex for ops::RangeInclusive { } #[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] -impl SliceIndex for ops::RangeToInclusive { +impl SliceIndex<[T]> for ops::RangeToInclusive { type Output = [T]; #[inline] @@ -1176,6 +1190,19 @@ macro_rules! iterator { } } } + + fn rfind(&mut self, mut predicate: F) -> Option + where F: FnMut(&Self::Item) -> bool, + { + self.rsearch_while(None, move |elt| { + if predicate(&elt) { + SearchWhile::Done(Some(elt)) + } else { + SearchWhile::Continue + } + }) + } + } // search_while is a generalization of the internal iteration methods. @@ -1502,9 +1529,10 @@ unsafe impl<'a, T> TrustedLen for IterMut<'a, T> {} // Return the arithmetic difference if `T` is zero size. #[inline(always)] fn ptrdistance(start: *const T, end: *const T) -> usize { - let diff = (end as usize).wrapping_sub(start as usize); - let size = mem::size_of::(); - diff / (if size == 0 { 1 } else { size }) + match start.offset_to(end) { + Some(x) => x as usize, + None => (end as usize).wrapping_sub(start as usize), + } } // Extension methods for raw pointers, used by the iterators @@ -1739,6 +1767,123 @@ impl<'a, T, P> DoubleEndedIterator for SplitMut<'a, T, P> where #[unstable(feature = "fused", issue = "35602")] impl<'a, T, P> FusedIterator for SplitMut<'a, T, P> where P: FnMut(&T) -> bool {} +/// An iterator over subslices separated by elements that match a predicate +/// function, starting from the end of the slice. +/// +/// This struct is created by the [`rsplit`] method on [slices]. +/// +/// [`rsplit`]: ../../std/primitive.slice.html#method.rsplit +/// [slices]: ../../std/primitive.slice.html +#[unstable(feature = "slice_rsplit", issue = "41020")] +#[derive(Clone)] // Is this correct, or does it incorrectly require `T: Clone`? +pub struct RSplit<'a, T:'a, P> where P: FnMut(&T) -> bool { + inner: Split<'a, T, P> +} + +#[unstable(feature = "slice_rsplit", issue = "41020")] +impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for RSplit<'a, T, P> where P: FnMut(&T) -> bool { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("RSplit") + .field("v", &self.inner.v) + .field("finished", &self.inner.finished) + .finish() + } +} + +#[unstable(feature = "slice_rsplit", issue = "41020")] +impl<'a, T, P> Iterator for RSplit<'a, T, P> where P: FnMut(&T) -> bool { + type Item = &'a [T]; + + #[inline] + fn next(&mut self) -> Option<&'a [T]> { + self.inner.next_back() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } +} + +#[unstable(feature = "slice_rsplit", issue = "41020")] +impl<'a, T, P> DoubleEndedIterator for RSplit<'a, T, P> where P: FnMut(&T) -> bool { + #[inline] + fn next_back(&mut self) -> Option<&'a [T]> { + self.inner.next() + } +} + +#[unstable(feature = "slice_rsplit", issue = "41020")] +impl<'a, T, P> SplitIter for RSplit<'a, T, P> where P: FnMut(&T) -> bool { + #[inline] + fn finish(&mut self) -> Option<&'a [T]> { + self.inner.finish() + } +} + +//#[unstable(feature = "fused", issue = "35602")] +#[unstable(feature = "slice_rsplit", issue = "41020")] +impl<'a, T, P> FusedIterator for RSplit<'a, T, P> where P: FnMut(&T) -> bool {} + +/// An iterator over the subslices of the vector which are separated +/// by elements that match `pred`, starting from the end of the slice. +/// +/// This struct is created by the [`rsplit_mut`] method on [slices]. +/// +/// [`rsplit_mut`]: ../../std/primitive.slice.html#method.rsplit_mut +/// [slices]: ../../std/primitive.slice.html +#[unstable(feature = "slice_rsplit", issue = "41020")] +pub struct RSplitMut<'a, T:'a, P> where P: FnMut(&T) -> bool { + inner: SplitMut<'a, T, P> +} + +#[unstable(feature = "slice_rsplit", issue = "41020")] +impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for RSplitMut<'a, T, P> where P: FnMut(&T) -> bool { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("RSplitMut") + .field("v", &self.inner.v) + .field("finished", &self.inner.finished) + .finish() + } +} + +#[unstable(feature = "slice_rsplit", issue = "41020")] +impl<'a, T, P> SplitIter for RSplitMut<'a, T, P> where P: FnMut(&T) -> bool { + #[inline] + fn finish(&mut self) -> Option<&'a mut [T]> { + self.inner.finish() + } +} + +#[unstable(feature = "slice_rsplit", issue = "41020")] +impl<'a, T, P> Iterator for RSplitMut<'a, T, P> where P: FnMut(&T) -> bool { + type Item = &'a mut [T]; + + #[inline] + fn next(&mut self) -> Option<&'a mut [T]> { + self.inner.next_back() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } +} + +#[unstable(feature = "slice_rsplit", issue = "41020")] +impl<'a, T, P> DoubleEndedIterator for RSplitMut<'a, T, P> where + P: FnMut(&T) -> bool, +{ + #[inline] + fn next_back(&mut self) -> Option<&'a mut [T]> { + self.inner.next() + } +} + +//#[unstable(feature = "fused", issue = "35602")] +#[unstable(feature = "slice_rsplit", issue = "41020")] +impl<'a, T, P> FusedIterator for RSplitMut<'a, T, P> where P: FnMut(&T) -> bool {} + /// An private iterator over subslices separated by elements that /// match a predicate function, splitting at most a fixed number of /// times. @@ -1746,7 +1891,6 @@ impl<'a, T, P> FusedIterator for SplitMut<'a, T, P> where P: FnMut(&T) -> bool { struct GenericSplitN { iter: I, count: usize, - invert: bool } impl> Iterator for GenericSplitN { @@ -1757,10 +1901,7 @@ impl> Iterator for GenericSplitN { match self.count { 0 => None, 1 => { self.count -= 1; self.iter.finish() } - _ => { - self.count -= 1; - if self.invert {self.iter.next_back()} else {self.iter.next()} - } + _ => { self.count -= 1; self.iter.next() } } } @@ -1802,7 +1943,7 @@ impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for SplitN<'a, T, P> where P: FnMut(& /// [slices]: ../../std/primitive.slice.html #[stable(feature = "rust1", since = "1.0.0")] pub struct RSplitN<'a, T: 'a, P> where P: FnMut(&T) -> bool { - inner: GenericSplitN> + inner: GenericSplitN> } #[stable(feature = "core_impl_debug", since = "1.9.0")] @@ -1845,7 +1986,7 @@ impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for SplitNMut<'a, T, P> where P: FnMu /// [slices]: ../../std/primitive.slice.html #[stable(feature = "rust1", since = "1.0.0")] pub struct RSplitNMut<'a, T: 'a, P> where P: FnMut(&T) -> bool { - inner: GenericSplitN> + inner: GenericSplitN> } #[stable(feature = "core_impl_debug", since = "1.9.0")] @@ -2213,7 +2354,10 @@ impl<'a, T> FusedIterator for ChunksMut<'a, T> {} /// valid for `len` elements, nor whether the lifetime inferred is a suitable /// lifetime for the returned slice. /// -/// `p` must be non-null, even for zero-length slices. +/// `p` must be non-null, even for zero-length slices, because non-zero bits +/// are required to distinguish between a zero-length slice within `Some()` +/// from `None`. `p` can be a bogus non-dereferencable pointer, such as `0x1`, +/// for zero-length slices, though. /// /// # Caveat /// @@ -2246,7 +2390,8 @@ pub unsafe fn from_raw_parts<'a, T>(p: *const T, len: usize) -> &'a [T] { /// /// This function is unsafe for the same reasons as `from_raw_parts`, as well /// as not being able to provide a non-aliasing guarantee of the returned -/// mutable slice. +/// mutable slice. `p` must be non-null even for zero-length slices as with +/// `from_raw_parts`. #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn from_raw_parts_mut<'a, T>(p: *mut T, len: usize) -> &'a mut [T] { diff --git a/src/libcore/slice/sort.rs b/src/libcore/slice/sort.rs index d13d537d9930..6f9f2915dfe1 100644 --- a/src/libcore/slice/sort.rs +++ b/src/libcore/slice/sort.rs @@ -20,12 +20,6 @@ use cmp; use mem; use ptr; -/// Holds a value, but never drops it. -#[allow(unions_with_drop_fields)] -union NoDrop { - value: T -} - /// When dropped, copies from `src` into `dest`. struct CopyOnDrop { src: *mut T, @@ -49,15 +43,15 @@ fn shift_head(v: &mut [T], is_less: &mut F) // Read the first element into a stack-allocated variable. If a following comparison // operation panics, `hole` will get dropped and automatically write the element back // into the slice. - let mut tmp = NoDrop { value: ptr::read(v.get_unchecked(0)) }; + let mut tmp = mem::ManuallyDrop::new(ptr::read(v.get_unchecked(0))); let mut hole = CopyOnDrop { - src: &mut tmp.value, + src: &mut *tmp, dest: v.get_unchecked_mut(1), }; ptr::copy_nonoverlapping(v.get_unchecked(1), v.get_unchecked_mut(0), 1); for i in 2..len { - if !is_less(v.get_unchecked(i), &tmp.value) { + if !is_less(v.get_unchecked(i), &*tmp) { break; } @@ -81,15 +75,15 @@ fn shift_tail(v: &mut [T], is_less: &mut F) // Read the last element into a stack-allocated variable. If a following comparison // operation panics, `hole` will get dropped and automatically write the element back // into the slice. - let mut tmp = NoDrop { value: ptr::read(v.get_unchecked(len - 1)) }; + let mut tmp = mem::ManuallyDrop::new(ptr::read(v.get_unchecked(len - 1))); let mut hole = CopyOnDrop { - src: &mut tmp.value, + src: &mut *tmp, dest: v.get_unchecked_mut(len - 2), }; ptr::copy_nonoverlapping(v.get_unchecked(len - 2), v.get_unchecked_mut(len - 1), 1); for i in (0..len-2).rev() { - if !is_less(&tmp.value, v.get_unchecked(i)) { + if !is_less(&*tmp, v.get_unchecked(i)) { break; } @@ -152,8 +146,8 @@ fn partial_insertion_sort(v: &mut [T], is_less: &mut F) -> bool fn insertion_sort(v: &mut [T], is_less: &mut F) where F: FnMut(&T, &T) -> bool { - for i in 2..v.len()+1 { - shift_tail(&mut v[..i], is_less); + for i in 1..v.len() { + shift_tail(&mut v[..i+1], is_less); } } @@ -403,12 +397,12 @@ fn partition(v: &mut [T], pivot: usize, is_less: &mut F) -> (usize, bool) // Read the pivot into a stack-allocated variable for efficiency. If a following comparison // operation panics, the pivot will be automatically written back into the slice. - let mut tmp = NoDrop { value: unsafe { ptr::read(pivot) } }; + let mut tmp = mem::ManuallyDrop::new(unsafe { ptr::read(pivot) }); let _pivot_guard = CopyOnDrop { - src: unsafe { &mut tmp.value }, + src: &mut *tmp, dest: pivot, }; - let pivot = unsafe { &tmp.value }; + let pivot = &*tmp; // Find the first pair of out-of-order elements. let mut l = 0; @@ -452,12 +446,12 @@ fn partition_equal(v: &mut [T], pivot: usize, is_less: &mut F) -> usize // Read the pivot into a stack-allocated variable for efficiency. If a following comparison // operation panics, the pivot will be automatically written back into the slice. - let mut tmp = NoDrop { value: unsafe { ptr::read(pivot) } }; + let mut tmp = mem::ManuallyDrop::new(unsafe { ptr::read(pivot) }); let _pivot_guard = CopyOnDrop { - src: unsafe { &mut tmp.value }, + src: &mut *tmp, dest: pivot, }; - let pivot = unsafe { &tmp.value }; + let pivot = &*tmp; // Now partition the slice. let mut l = 0; @@ -498,32 +492,42 @@ fn partition_equal(v: &mut [T], pivot: usize, is_less: &mut F) -> usize #[cold] fn break_patterns(v: &mut [T]) { let len = v.len(); - if len >= 8 { - // A random number will be taken modulo this one. The modulus is a power of two so that we - // can simply take bitwise "and", thus avoiding costly CPU operations. - let modulus = (len / 4).next_power_of_two(); - debug_assert!(modulus >= 1 && modulus <= len / 2); + // Pseudorandom number generator from the "Xorshift RNGs" paper by George Marsaglia. + let mut random = len as u32; + let mut gen_u32 = || { + random ^= random << 13; + random ^= random >> 17; + random ^= random << 5; + random + }; + let mut gen_usize = || { + if mem::size_of::() <= 4 { + gen_u32() as usize + } else { + (((gen_u32() as u64) << 32) | (gen_u32() as u64)) as usize + } + }; - // Pseudorandom number generation from the "Xorshift RNGs" paper by George Marsaglia. - let mut random = len; - random ^= random << 13; - random ^= random >> 17; - random ^= random << 5; - random &= modulus - 1; - debug_assert!(random < len / 2); + // Take random numbers modulo this number. + // The number fits into `usize` because `len` is not greater than `isize::MAX`. + let modulus = len.next_power_of_two(); - // The first index. - let a = len / 4 * 2; - debug_assert!(a >= 1 && a < len - 2); + // Some pivot candidates will be in the nearby of this index. Let's randomize them. + let pos = len / 4 * 2; - // The second index. - let b = len / 4 + random; - debug_assert!(b >= 1 && b < len - 2); - - // Swap neighbourhoods of `a` and `b`. for i in 0..3 { - v.swap(a - 1 + i, b - 1 + i); + // Generate a random number modulo `len`. However, in order to avoid costly operations + // we first take it modulo a power of two, and then decrease by `len` until it fits + // into the range `[0, len - 1]`. + let mut other = gen_usize() & (modulus - 1); + + // `other` is guaranteed to be less than `2 * len`. + if other >= len { + other -= len; + } + + v.swap(pos - 1 + i, other); } } } diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index dfb6936da6bd..6b6274309048 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -21,8 +21,8 @@ use char; use convert::TryFrom; use fmt; use iter::{Map, Cloned, FusedIterator}; +use slice::{self, SliceIndex}; use mem; -use slice; pub mod pattern; @@ -35,6 +35,39 @@ pub mod pattern; /// [`from_str`]: #tymethod.from_str /// [`str`]: ../../std/primitive.str.html /// [`parse`]: ../../std/primitive.str.html#method.parse +/// +/// # Examples +/// +/// Basic implementation of `FromStr` on an example `Point` type: +/// +/// ``` +/// use std::str::FromStr; +/// use std::num::ParseIntError; +/// +/// #[derive(Debug, PartialEq)] +/// struct Point { +/// x: i32, +/// y: i32 +/// } +/// +/// impl FromStr for Point { +/// type Err = ParseIntError; +/// +/// fn from_str(s: &str) -> Result { +/// let coords: Vec<&str> = s.trim_matches(|p| p == '(' || p == ')' ) +/// .split(",") +/// .collect(); +/// +/// let x_fromstr = coords[0].parse::()?; +/// let y_fromstr = coords[1].parse::()?; +/// +/// Ok(Point { x: x_fromstr, y: y_fromstr }) +/// } +/// } +/// +/// let p = Point::from_str("(1,2)"); +/// assert_eq!(p.unwrap(), Point{ x: 1, y: 2} ) +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub trait FromStr: Sized { /// The associated error which can be returned from parsing. @@ -101,7 +134,9 @@ impl FromStr for bool { } } -/// An error returned when parsing a `bool` from a string fails. +/// An error returned when parsing a `bool` using [`from_str`] fails +/// +/// [`from_str`]: ../../std/primitive.bool.html#method.from_str #[derive(Debug, Clone, PartialEq, Eq)] #[stable(feature = "rust1", since = "1.0.0")] pub struct ParseBoolError { _priv: () } @@ -117,11 +152,16 @@ impl fmt::Display for ParseBoolError { Section: Creating a string */ -/// Errors which can occur when attempting to interpret a sequence of `u8` +/// Errors which can occur when attempting to interpret a sequence of [`u8`] /// as a string. /// -/// As such, the `from_utf8` family of functions and methods for both `String`s -/// and `&str`s make use of this error, for example. +/// [`u8`]: ../../std/primitive.u8.html +/// +/// As such, the `from_utf8` family of functions and methods for both [`String`]s +/// and [`&str`]s make use of this error, for example. +/// +/// [`String`]: ../../std/string/struct.String.html#method.from_utf8 +/// [`&str`]: ../../std/str/fn.from_utf8.html #[derive(Copy, Eq, PartialEq, Clone, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Utf8Error { @@ -175,11 +215,15 @@ impl Utf8Error { /// Converts a slice of bytes to a string slice. /// -/// A string slice (`&str`) is made of bytes (`u8`), and a byte slice (`&[u8]`) -/// is made of bytes, so this function converts between the two. Not all byte -/// slices are valid string slices, however: `&str` requires that it is valid -/// UTF-8. `from_utf8()` checks to ensure that the bytes are valid UTF-8, and -/// then does the conversion. +/// A string slice ([`&str`]) is made of bytes ([`u8`]), and a byte slice +/// ([`&[u8]`][byteslice]) is made of bytes, so this function converts between +/// the two. Not all byte slices are valid string slices, however: [`&str`] requires +/// that it is valid UTF-8. `from_utf8()` checks to ensure that the bytes are valid +/// UTF-8, and then does the conversion. +/// +/// [`&str`]: ../../std/primitive.str.html +/// [`u8`]: ../../std/primitive.u8.html +/// [byteslice]: ../../std/primitive.slice.html /// /// If you are sure that the byte slice is valid UTF-8, and you don't want to /// incur the overhead of the validity check, there is an unsafe version of @@ -193,9 +237,12 @@ impl Utf8Error { /// /// [string]: ../../std/string/struct.String.html#method.from_utf8 /// -/// Because you can stack-allocate a `[u8; N]`, and you can take a `&[u8]` of -/// it, this function is one way to have a stack-allocated string. There is -/// an example of this in the examples section below. +/// Because you can stack-allocate a `[u8; N]`, and you can take a +/// [`&[u8]`][byteslice] of it, this function is one way to have a +/// stack-allocated string. There is an example of this in the +/// examples section below. +/// +/// [byteslice]: ../../std/primitive.slice.html /// /// # Errors /// @@ -253,6 +300,13 @@ pub fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> { Ok(unsafe { from_utf8_unchecked(v) }) } +/// Converts a mutable slice of bytes to a mutable string slice. +#[unstable(feature = "str_mut_extras", issue = "41119")] +pub fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> { + run_utf8_validation(v)?; + Ok(unsafe { from_utf8_unchecked_mut(v) }) +} + /// Forms a str from a pointer and a length. /// /// The `len` argument is the number of bytes in the string. @@ -265,7 +319,10 @@ pub fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> { /// /// The data must be valid UTF-8 /// -/// `p` must be non-null, even for zero-length str. +/// `p` must be non-null, even for zero-length strs, because non-zero bits +/// are required to distinguish between a zero-length str within `Some()` +/// from `None`. `p` can be a bogus non-dereferencable pointer, such as `0x1`, +/// for zero-length strs, though. /// /// # Caveat /// @@ -278,7 +335,7 @@ pub fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> { /// str is returned. /// unsafe fn from_raw_parts_mut<'a>(p: *mut u8, len: usize) -> &'a mut str { - mem::transmute::<&mut [u8], &mut str>(slice::from_raw_parts_mut(p, len)) + from_utf8_unchecked_mut(slice::from_raw_parts_mut(p, len)) } /// Converts a slice of bytes to a string slice without checking @@ -292,7 +349,9 @@ unsafe fn from_raw_parts_mut<'a>(p: *mut u8, len: usize) -> &'a mut str { /// /// This function is unsafe because it does not check that the bytes passed to /// it are valid UTF-8. If this constraint is violated, undefined behavior -/// results, as the rest of Rust assumes that `&str`s are valid UTF-8. +/// results, as the rest of Rust assumes that [`&str`]s are valid UTF-8. +/// +/// [`&str`]: ../../std/primitive.str.html /// /// # Examples /// @@ -316,6 +375,18 @@ pub unsafe fn from_utf8_unchecked(v: &[u8]) -> &str { mem::transmute(v) } +/// Converts a slice of bytes to a string slice without checking +/// that the string contains valid UTF-8; mutable version. +/// +/// See the immutable version, [`from_utf8_unchecked()`][fromutf8], for more information. +/// +/// [fromutf8]: fn.from_utf8_unchecked.html +#[inline(always)] +#[unstable(feature = "str_mut_extras", issue = "41119")] +pub unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str { + mem::transmute(v) +} + #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for Utf8Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -332,11 +403,15 @@ impl fmt::Display for Utf8Error { Section: Iterators */ -/// Iterator for the char (representing *Unicode Scalar Values*) of a string. +/// An iterator over the [`char`]s of a string slice. /// -/// Created with the method [`chars`]. +/// [`char`]: ../../std/primitive.char.html +/// +/// This struct is created by the [`chars`] method on [`str`]. +/// See its documentation for more. /// /// [`chars`]: ../../std/primitive.str.html#method.chars +/// [`str`]: ../../std/primitive.str.html #[derive(Clone, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Chars<'a> { @@ -516,7 +591,15 @@ impl<'a> Chars<'a> { } } -/// Iterator for a string's characters and their byte offsets. +/// An iterator over the [`char`]s of a string slice, and their positions. +/// +/// [`char`]: ../../std/primitive.char.html +/// +/// This struct is created by the [`char_indices`] method on [`str`]. +/// See its documentation for more. +/// +/// [`char_indices`]: ../../std/primitive.str.html#method.char_indices +/// [`str`]: ../../std/primitive.str.html #[derive(Clone, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct CharIndices<'a> { @@ -588,12 +671,13 @@ impl<'a> CharIndices<'a> { } } -/// External iterator for a string's bytes. -/// Use with the `std::iter` module. +/// An iterator over the bytes of a string slice. /// -/// Created with the method [`bytes`]. +/// This struct is created by the [`bytes`] method on [`str`]. +/// See its documentation for more. /// /// [`bytes`]: ../../std/primitive.str.html#method.bytes +/// [`str`]: ../../std/primitive.str.html #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone, Debug)] pub struct Bytes<'a>(Cloned>); @@ -1124,9 +1208,13 @@ generate_pattern_iterators! { delegate double ended; } -/// Created with the method [`lines`]. +/// An iterator over the lines of a string, as string slices. +/// +/// This struct is created with the [`lines`] method on [`str`]. +/// See its documentation for more. /// /// [`lines`]: ../../std/primitive.str.html#method.lines +/// [`str`]: ../../std/primitive.str.html #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone, Debug)] pub struct Lines<'a>(Map, LinesAnyMap>); @@ -1408,6 +1496,7 @@ Section: Trait implementations mod traits { use cmp::Ordering; use ops; + use slice::{self, SliceIndex}; use str::eq_slice; /// Implements ordering of strings. @@ -1490,14 +1579,7 @@ mod traits { type Output = str; #[inline] fn index(&self, index: ops::Range) -> &str { - // is_char_boundary checks that the index is in [0, .len()] - if index.start <= index.end && - self.is_char_boundary(index.start) && - self.is_char_boundary(index.end) { - unsafe { self.slice_unchecked(index.start, index.end) } - } else { - super::slice_error_fail(self, index.start, index.end) - } + index.index(self) } } @@ -1519,14 +1601,7 @@ mod traits { impl ops::IndexMut> for str { #[inline] fn index_mut(&mut self, index: ops::Range) -> &mut str { - // is_char_boundary checks that the index is in [0, .len()] - if index.start <= index.end && - self.is_char_boundary(index.start) && - self.is_char_boundary(index.end) { - unsafe { self.slice_mut_unchecked(index.start, index.end) } - } else { - super::slice_error_fail(self, index.start, index.end) - } + index.index_mut(self) } } @@ -1694,8 +1769,276 @@ mod traits { self.index_mut(0...index.end) } } + + #[unstable(feature = "str_checked_slicing", issue = "39932")] + impl SliceIndex for ops::RangeFull { + type Output = str; + #[inline] + fn get(self, slice: &str) -> Option<&Self::Output> { + Some(slice) + } + #[inline] + fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { + Some(slice) + } + #[inline] + unsafe fn get_unchecked(self, slice: &str) -> &Self::Output { + slice + } + #[inline] + unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output { + slice + } + #[inline] + fn index(self, slice: &str) -> &Self::Output { + slice + } + #[inline] + fn index_mut(self, slice: &mut str) -> &mut Self::Output { + slice + } + } + + #[unstable(feature = "str_checked_slicing", issue = "39932")] + impl SliceIndex for ops::Range { + type Output = str; + #[inline] + fn get(self, slice: &str) -> Option<&Self::Output> { + if self.start <= self.end && + slice.is_char_boundary(self.start) && + slice.is_char_boundary(self.end) { + Some(unsafe { self.get_unchecked(slice) }) + } else { + None + } + } + #[inline] + fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { + if self.start <= self.end && + slice.is_char_boundary(self.start) && + slice.is_char_boundary(self.end) { + Some(unsafe { self.get_unchecked_mut(slice) }) + } else { + None + } + } + #[inline] + unsafe fn get_unchecked(self, slice: &str) -> &Self::Output { + let ptr = slice.as_ptr().offset(self.start as isize); + let len = self.end - self.start; + super::from_utf8_unchecked(slice::from_raw_parts(ptr, len)) + } + #[inline] + unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output { + let ptr = slice.as_ptr().offset(self.start as isize); + let len = self.end - self.start; + super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr as *mut u8, len)) + } + #[inline] + fn index(self, slice: &str) -> &Self::Output { + let (start, end) = (self.start, self.end); + self.get(slice).unwrap_or_else(|| super::slice_error_fail(slice, start, end)) + } + #[inline] + fn index_mut(self, slice: &mut str) -> &mut Self::Output { + // is_char_boundary checks that the index is in [0, .len()] + // canot reuse `get` as above, because of NLL trouble + if self.start <= self.end && + slice.is_char_boundary(self.start) && + slice.is_char_boundary(self.end) { + unsafe { self.get_unchecked_mut(slice) } + } else { + super::slice_error_fail(slice, self.start, self.end) + } + } + } + + #[unstable(feature = "str_checked_slicing", issue = "39932")] + impl SliceIndex for ops::RangeTo { + type Output = str; + #[inline] + fn get(self, slice: &str) -> Option<&Self::Output> { + if slice.is_char_boundary(self.end) { + Some(unsafe { self.get_unchecked(slice) }) + } else { + None + } + } + #[inline] + fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { + if slice.is_char_boundary(self.end) { + Some(unsafe { self.get_unchecked_mut(slice) }) + } else { + None + } + } + #[inline] + unsafe fn get_unchecked(self, slice: &str) -> &Self::Output { + let ptr = slice.as_ptr(); + super::from_utf8_unchecked(slice::from_raw_parts(ptr, self.end)) + } + #[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)) + } + #[inline] + fn index(self, slice: &str) -> &Self::Output { + let end = self.end; + self.get(slice).unwrap_or_else(|| super::slice_error_fail(slice, 0, end)) + } + #[inline] + fn index_mut(self, slice: &mut str) -> &mut Self::Output { + if slice.is_char_boundary(self.end) { + unsafe { self.get_unchecked_mut(slice) } + } else { + super::slice_error_fail(slice, 0, self.end) + } + } + } + + #[unstable(feature = "str_checked_slicing", issue = "39932")] + impl SliceIndex for ops::RangeFrom { + type Output = str; + #[inline] + fn get(self, slice: &str) -> Option<&Self::Output> { + if slice.is_char_boundary(self.start) { + Some(unsafe { self.get_unchecked(slice) }) + } else { + None + } + } + #[inline] + fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { + if slice.is_char_boundary(self.start) { + Some(unsafe { self.get_unchecked_mut(slice) }) + } else { + None + } + } + #[inline] + unsafe fn get_unchecked(self, slice: &str) -> &Self::Output { + let ptr = slice.as_ptr().offset(self.start as isize); + let len = slice.len() - self.start; + super::from_utf8_unchecked(slice::from_raw_parts(ptr, len)) + } + #[inline] + unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output { + let ptr = slice.as_ptr().offset(self.start as isize); + let len = slice.len() - self.start; + super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr as *mut u8, len)) + } + #[inline] + fn index(self, slice: &str) -> &Self::Output { + let (start, end) = (self.start, slice.len()); + self.get(slice).unwrap_or_else(|| super::slice_error_fail(slice, start, end)) + } + #[inline] + fn index_mut(self, slice: &mut str) -> &mut Self::Output { + if slice.is_char_boundary(self.start) { + unsafe { self.get_unchecked_mut(slice) } + } else { + super::slice_error_fail(slice, self.start, slice.len()) + } + } + } + + #[unstable(feature = "str_checked_slicing", issue = "39932")] + impl SliceIndex for ops::RangeInclusive { + type Output = str; + #[inline] + fn get(self, slice: &str) -> Option<&Self::Output> { + match self { + ops::RangeInclusive::Empty { .. } => 0..0, + ops::RangeInclusive::NonEmpty { start, end } => start..end+1, + }.get(slice) + } + #[inline] + fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { + match self { + ops::RangeInclusive::Empty { .. } => 0..0, + ops::RangeInclusive::NonEmpty { start, end } => start..end+1, + }.get_mut(slice) + } + #[inline] + unsafe fn get_unchecked(self, slice: &str) -> &Self::Output { + match self { + ops::RangeInclusive::Empty { .. } => 0..0, + ops::RangeInclusive::NonEmpty { start, end } => start..end+1, + }.get_unchecked(slice) + } + #[inline] + unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output { + match self { + ops::RangeInclusive::Empty { .. } => 0..0, + ops::RangeInclusive::NonEmpty { start, end } => start..end+1, + }.get_unchecked_mut(slice) + } + #[inline] + fn index(self, slice: &str) -> &Self::Output { + match self { + ops::RangeInclusive::Empty { .. } => 0..0, + ops::RangeInclusive::NonEmpty { start, end } => start..end+1, + }.index(slice) + } + #[inline] + fn index_mut(self, slice: &mut str) -> &mut Self::Output { + match self { + ops::RangeInclusive::Empty { .. } => 0..0, + ops::RangeInclusive::NonEmpty { start, end } => start..end+1, + }.index_mut(slice) + } + } + + + + #[unstable(feature = "str_checked_slicing", issue = "39932")] + impl SliceIndex for ops::RangeToInclusive { + type Output = str; + #[inline] + fn get(self, slice: &str) -> Option<&Self::Output> { + if slice.is_char_boundary(self.end + 1) { + Some(unsafe { self.get_unchecked(slice) }) + } else { + None + } + } + #[inline] + fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { + if slice.is_char_boundary(self.end + 1) { + Some(unsafe { self.get_unchecked_mut(slice) }) + } else { + None + } + } + #[inline] + unsafe fn get_unchecked(self, slice: &str) -> &Self::Output { + let ptr = slice.as_ptr(); + super::from_utf8_unchecked(slice::from_raw_parts(ptr, self.end + 1)) + } + #[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 + 1)) + } + #[inline] + fn index(self, slice: &str) -> &Self::Output { + let end = self.end + 1; + self.get(slice).unwrap_or_else(|| super::slice_error_fail(slice, 0, end)) + } + #[inline] + fn index_mut(self, slice: &mut str) -> &mut Self::Output { + if slice.is_char_boundary(self.end) { + unsafe { self.get_unchecked_mut(slice) } + } else { + super::slice_error_fail(slice, 0, self.end + 1) + } + } + } + } + /// Methods for string slices #[allow(missing_docs)] #[doc(hidden)] @@ -1745,6 +2088,14 @@ pub trait StrExt { #[rustc_deprecated(since = "1.6.0", reason = "use lines() instead now")] #[allow(deprecated)] fn lines_any(&self) -> LinesAny; + #[unstable(feature = "str_checked_slicing", issue = "39932")] + fn get>(&self, i: I) -> Option<&I::Output>; + #[unstable(feature = "str_checked_slicing", issue = "39932")] + fn get_mut>(&mut self, i: I) -> Option<&mut I::Output>; + #[unstable(feature = "str_checked_slicing", issue = "39932")] + unsafe fn get_unchecked>(&self, i: I) -> &I::Output; + #[unstable(feature = "str_checked_slicing", issue = "39932")] + unsafe fn get_unchecked_mut>(&mut self, i: I) -> &mut I::Output; #[stable(feature = "core", since = "1.6.0")] unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str; #[stable(feature = "core", since = "1.6.0")] @@ -1766,6 +2117,8 @@ pub trait StrExt { fn is_char_boundary(&self, index: usize) -> bool; #[stable(feature = "core", since = "1.6.0")] fn as_bytes(&self) -> &[u8]; + #[unstable(feature = "str_mut_extras", issue = "0")] + unsafe fn as_bytes_mut(&mut self) -> &mut [u8]; #[stable(feature = "core", since = "1.6.0")] fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option; #[stable(feature = "core", since = "1.6.0")] @@ -1934,18 +2287,34 @@ impl StrExt for str { LinesAny(self.lines()) } + #[inline] + fn get>(&self, i: I) -> Option<&I::Output> { + i.get(self) + } + + #[inline] + fn get_mut>(&mut self, i: I) -> Option<&mut I::Output> { + i.get_mut(self) + } + + #[inline] + unsafe fn get_unchecked>(&self, i: I) -> &I::Output { + i.get_unchecked(self) + } + + #[inline] + unsafe fn get_unchecked_mut>(&mut self, i: I) -> &mut I::Output { + i.get_unchecked_mut(self) + } + #[inline] unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str { - let ptr = self.as_ptr().offset(begin as isize); - let len = end - begin; - from_utf8_unchecked(slice::from_raw_parts(ptr, len)) + (begin..end).get_unchecked(self) } #[inline] unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut str { - let ptr = self.as_ptr().offset(begin as isize); - let len = end - begin; - mem::transmute(slice::from_raw_parts_mut(ptr as *mut u8, len)) + (begin..end).get_unchecked_mut(self) } #[inline] @@ -2027,6 +2396,11 @@ impl StrExt for str { unsafe { mem::transmute(self) } } + #[inline] + unsafe fn as_bytes_mut(&mut self) -> &mut [u8] { + mem::transmute(self) + } + fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option { pat.into_searcher(self).next_match().map(|(i, _)| i) } diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index 743e3c41170a..c13fd5583543 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -15,27 +15,37 @@ //! types. //! //! This module defines atomic versions of a select number of primitive -//! types, including `AtomicBool`, `AtomicIsize`, and `AtomicUsize`. +//! types, including [`AtomicBool`], [`AtomicIsize`], and [`AtomicUsize`]. //! Atomic types present operations that, when used correctly, synchronize //! updates between threads. //! -//! Each method takes an `Ordering` which represents the strength of +//! [`AtomicBool`]: struct.AtomicBool.html +//! [`AtomicIsize`]: struct.AtomicIsize.html +//! [`AtomicUsize`]: struct.AtomicUsize.html +//! +//! Each method takes an [`Ordering`] which represents the strength of //! the memory barrier for that operation. These orderings are the //! same as [LLVM atomic orderings][1]. For more information see the [nomicon][2]. //! +//! [`Ordering`]: enum.Ordering.html +//! //! [1]: http://llvm.org/docs/LangRef.html#memory-model-for-concurrent-operations //! [2]: ../../../nomicon/atomics.html //! -//! Atomic variables are safe to share between threads (they implement `Sync`) +//! Atomic variables are safe to share between threads (they implement [`Sync`]) //! but they do not themselves provide the mechanism for sharing and follow the //! [threading model](../../../std/thread/index.html#the-threading-model) of rust. -//! The most common way to share an atomic variable is to put it into an `Arc` (an +//! The most common way to share an atomic variable is to put it into an [`Arc`][arc] (an //! atomically-reference-counted shared pointer). //! +//! [`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 +//! the provided static initializers like [`ATOMIC_BOOL_INIT`]. Atomic statics //! are often used for lazy global initialization. //! +//! [`ATOMIC_BOOL_INIT`]: constant.ATOMIC_BOOL_INIT.html //! //! # Examples //! @@ -84,6 +94,29 @@ use intrinsics; use cell::UnsafeCell; use fmt; +/// Save power or switch hyperthreads in a busy-wait spin-loop. +/// +/// This function is deliberately more primitive than +/// `std::thread::yield_now` 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 = "hint_core_should_pause", issue = "41196")] +pub fn hint_core_should_pause() +{ + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + unsafe { + asm!("pause" ::: "memory" : "volatile"); + } + + #[cfg(target_arch = "aarch64")] + unsafe { + asm!("yield" ::: "memory" : "volatile"); + } +} + /// A boolean type which can be safely shared between threads. /// /// This type has the same in-memory representation as a `bool`. @@ -143,27 +176,38 @@ unsafe impl Sync for AtomicPtr {} /// Rust's memory orderings are [the same as /// LLVM's](http://llvm.org/docs/LangRef.html#memory-model-for-concurrent-operations). /// -/// For more information see the [nomicon][1]. -/// [1]: ../../../nomicon/atomics.html +/// For more information see the [nomicon]. +/// +/// [nomicon]: ../../../nomicon/atomics.html #[stable(feature = "rust1", since = "1.0.0")] #[derive(Copy, Clone, Debug)] pub enum Ordering { - /// No ordering constraints, only atomic operations. Corresponds to LLVM's - /// `Monotonic` ordering. + /// No ordering constraints, only atomic operations. + /// + /// Corresponds to LLVM's [`Monotonic`] ordering. + /// + /// [`Monotonic`]: http://llvm.org/docs/Atomics.html#monotonic #[stable(feature = "rust1", since = "1.0.0")] Relaxed, /// When coupled with a store, all previous writes become visible - /// to the other threads that perform a load with `Acquire` ordering + /// to the other threads that perform a load with [`Acquire`] ordering /// on the same value. + /// + /// [`Acquire`]: http://llvm.org/docs/Atomics.html#acquire #[stable(feature = "rust1", since = "1.0.0")] Release, /// When coupled with a load, all subsequent loads will see data - /// written before a store with `Release` ordering on the same value + /// written before a store with [`Release`] ordering on the same value /// in other threads. + /// + /// [`Release`]: http://llvm.org/docs/Atomics.html#release #[stable(feature = "rust1", since = "1.0.0")] Acquire, - /// When coupled with a load, uses `Acquire` ordering, and with a store - /// `Release` ordering. + /// When coupled with a load, uses [`Acquire`] ordering, and with a store + /// [`Release`] ordering. + /// + /// [`Acquire`]: http://llvm.org/docs/Atomics.html#acquire + /// [`Release`]: http://llvm.org/docs/Atomics.html#release #[stable(feature = "rust1", since = "1.0.0")] AcqRel, /// Like `AcqRel` with the additional guarantee that all threads see all @@ -176,7 +220,9 @@ pub enum Ordering { __Nonexhaustive, } -/// An `AtomicBool` initialized to `false`. +/// An [`AtomicBool`] initialized to `false`. +/// +/// [`AtomicBool`]: struct.AtomicBool.html #[cfg(target_has_atomic = "8")] #[stable(feature = "rust1", since = "1.0.0")] pub const ATOMIC_BOOL_INIT: AtomicBool = AtomicBool::new(false); @@ -250,7 +296,7 @@ impl AtomicBool { /// /// [`Ordering`]: enum.Ordering.html /// [`Release`]: enum.Ordering.html#variant.Release - /// [`AcqRel`]: enum.Ordering.html#variant.Release + /// [`AcqRel`]: enum.Ordering.html#variant.AcqRel /// /// # Examples /// @@ -287,7 +333,10 @@ impl AtomicBool { /// /// # Panics /// - /// Panics if `order` is `Acquire` or `AcqRel`. + /// Panics if `order` is [`Acquire`] or [`AcqRel`]. + /// + /// [`Acquire`]: enum.Ordering.html#variant.Acquire + /// [`AcqRel`]: enum.Ordering.html#variant.AcqRel #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn store(&self, val: bool, order: Ordering) { @@ -296,7 +345,7 @@ impl AtomicBool { } } - /// Stores a value into the bool, returning the old value. + /// Stores a value into the bool, returning the previous value. /// /// `swap` takes an [`Ordering`] argument which describes the memory ordering /// of this operation. @@ -404,7 +453,7 @@ impl AtomicBool { /// Stores a value into the `bool` if the current value is the same as the `current` value. /// - /// Unlike `compare_exchange`, this function is allowed to spuriously fail even when the + /// Unlike [`compare_exchange`], this function is allowed to spuriously fail even when the /// comparison succeeds, which can result in more efficient code on some platforms. The /// return value is a result indicating whether the new value was written and containing the /// previous value. @@ -415,6 +464,7 @@ impl AtomicBool { /// failure ordering can't be [`Release`] or [`AcqRel`] and must be equivalent or /// weaker than the success ordering. /// + /// [`compare_exchange`]: #method.compare_exchange /// [`Ordering`]: enum.Ordering.html /// [`Release`]: enum.Ordering.html#variant.Release /// [`AcqRel`]: enum.Ordering.html#variant.Release @@ -512,17 +562,16 @@ impl AtomicBool { // We can't use atomic_nand here because it can result in a bool with // an invalid value. This happens because the atomic operation is done // with an 8-bit integer internally, which would set the upper 7 bits. - // So we just use a compare-exchange loop instead, which is what the - // intrinsic actually expands to anyways on many platforms. - let mut old = self.load(Relaxed); - loop { - let new = !(old && val); - match self.compare_exchange_weak(old, new, order, Relaxed) { - Ok(_) => break, - Err(x) => old = x, - } + // So we just use fetch_xor or swap instead. + if val { + // !(x & true) == !x + // We must invert the bool. + self.fetch_xor(true, order) + } else { + // !(x & false) == true + // We must set the bool to true. + self.swap(true, order) } - old } /// Logical "or" with a boolean value. @@ -694,7 +743,10 @@ impl AtomicPtr { /// /// # Panics /// - /// Panics if `order` is `Acquire` or `AcqRel`. + /// Panics if `order` is [`Acquire`] or [`AcqRel`]. + /// + /// [`Acquire`]: enum.Ordering.html#variant.Acquire + /// [`AcqRel`]: enum.Ordering.html#variant.AcqRel #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn store(&self, ptr: *mut T, order: Ordering) { @@ -703,7 +755,7 @@ impl AtomicPtr { } } - /// Stores a value into the pointer, returning the old value. + /// Stores a value into the pointer, returning the previous value. /// /// `swap` takes an [`Ordering`] argument which describes the memory ordering /// of this operation. @@ -1008,14 +1060,17 @@ macro_rules! atomic_int { /// /// # Panics /// - /// Panics if `order` is `Acquire` or `AcqRel`. + /// Panics if `order` is [`Acquire`] or [`AcqRel`]. + /// + /// [`Acquire`]: enum.Ordering.html#variant.Acquire + /// [`AcqRel`]: enum.Ordering.html#variant.AcqRel #[inline] #[$stable] pub fn store(&self, val: $int_type, order: Ordering) { unsafe { atomic_store(self.v.get(), val, order); } } - /// Stores a value into the atomic integer, returning the old value. + /// Stores a value into the atomic integer, returning the previous value. /// /// `swap` takes an [`Ordering`] argument which describes the memory ordering of this /// operation. @@ -1169,7 +1224,9 @@ macro_rules! atomic_int { } } - /// Add to the current value, returning the previous value. + /// Adds to the current value, returning the previous value. + /// + /// This operation wraps around on overflow. /// /// # Examples /// @@ -1186,7 +1243,9 @@ macro_rules! atomic_int { unsafe { atomic_add(self.v.get(), val, order) } } - /// Subtract from the current value, returning the previous value. + /// Subtracts from the current value, returning the previous value. + /// + /// This operation wraps around on overflow. /// /// # Examples /// @@ -1203,7 +1262,12 @@ macro_rules! atomic_int { unsafe { atomic_sub(self.v.get(), val, order) } } - /// Bitwise and with the current value, returning the previous value. + /// Bitwise "and" with the current value. + /// + /// Performs a bitwise "and" operation on the current value and the argument `val`, and + /// sets the new value to the result. + /// + /// Returns the previous value. /// /// # Examples /// @@ -1219,7 +1283,12 @@ macro_rules! atomic_int { unsafe { atomic_and(self.v.get(), val, order) } } - /// Bitwise or with the current value, returning the previous value. + /// Bitwise "or" with the current value. + /// + /// Performs a bitwise "or" operation on the current value and the argument `val`, and + /// sets the new value to the result. + /// + /// Returns the previous value. /// /// # Examples /// @@ -1235,7 +1304,12 @@ macro_rules! atomic_int { unsafe { atomic_or(self.v.get(), val, order) } } - /// Bitwise xor with the current value, returning the previous value. + /// Bitwise "xor" with the current value. + /// + /// Performs a bitwise "xor" operation on the current value and the argument `val`, and + /// sets the new value to the result. + /// + /// Returns the previous value. /// /// # Examples /// @@ -1383,7 +1457,7 @@ unsafe fn atomic_swap(dst: *mut T, val: T, order: Ordering) -> T { } } -/// Returns the old value (like __sync_fetch_and_add). +/// Returns the previous value (like __sync_fetch_and_add). #[inline] unsafe fn atomic_add(dst: *mut T, val: T, order: Ordering) -> T { match order { @@ -1396,7 +1470,7 @@ unsafe fn atomic_add(dst: *mut T, val: T, order: Ordering) -> T { } } -/// Returns the old value (like __sync_fetch_and_sub). +/// Returns the previous value (like __sync_fetch_and_sub). #[inline] unsafe fn atomic_sub(dst: *mut T, val: T, order: Ordering) -> T { match order { @@ -1499,12 +1573,30 @@ unsafe fn atomic_xor(dst: *mut T, val: T, order: Ordering) -> T { /// An atomic fence. /// -/// A fence 'A' which has [`Release`] ordering semantics, synchronizes with a -/// fence 'B' with (at least) [`Acquire`] semantics, if and only if there exists -/// atomic operations X and Y, both operating on some atomic object 'M' such +/// Depending on the specified order, a fence prevents the compiler and CPU from +/// reordering certain types of memory operations around it. +/// That creates synchronizes-with relationships between it and atomic operations +/// or fences in other threads. +/// +/// A fence 'A' which has (at least) [`Release`] ordering semantics, synchronizes +/// with a fence 'B' with (at least) [`Acquire`] semantics, if and only if there +/// exist operations X and Y, both operating on some atomic object 'M' such /// that A is sequenced before X, Y is synchronized before B and Y observes /// the change to M. This provides a happens-before dependence between A and B. /// +/// ```text +/// Thread 1 Thread 2 +/// +/// fence(Release); A -------------- +/// x.store(3, Relaxed); X --------- | +/// | | +/// | | +/// -------------> Y if x.load(Relaxed) == 3 { +/// |-------> B fence(Acquire); +/// ... +/// } +/// ``` +/// /// Atomic operations with [`Release`] or [`Acquire`] semantics can also synchronize /// with a fence. /// @@ -1518,6 +1610,37 @@ unsafe fn atomic_xor(dst: *mut T, val: T, order: Ordering) -> T { /// /// Panics if `order` is [`Relaxed`]. /// +/// # Examples +/// +/// ``` +/// use std::sync::atomic::AtomicBool; +/// use std::sync::atomic::fence; +/// use std::sync::atomic::Ordering; +/// +/// // A mutual exclusion primitive based on spinlock. +/// pub struct Mutex { +/// flag: AtomicBool, +/// } +/// +/// impl Mutex { +/// pub fn new() -> Mutex { +/// Mutex { +/// flag: AtomicBool::new(false), +/// } +/// } +/// +/// pub fn lock(&self) { +/// while !self.flag.compare_and_swap(false, true, Ordering::Relaxed) {} +/// // This fence syncronizes-with store in `unlock`. +/// fence(Ordering::Acquire); +/// } +/// +/// pub fn unlock(&self) { +/// self.flag.store(false, Ordering::Release); +/// } +/// } +/// ``` +/// /// [`Ordering`]: enum.Ordering.html /// [`Acquire`]: enum.Ordering.html#variant.Acquire /// [`SeqCst`]: enum.Ordering.html#variant.SeqCst @@ -1540,6 +1663,47 @@ pub fn fence(order: Ordering) { } +/// A compiler memory fence. +/// +/// `compiler_fence` does not emit any machine code, but prevents the compiler from re-ordering +/// memory operations across this point. Which reorderings are disallowed is dictated by the given +/// [`Ordering`]. Note that `compiler_fence` does *not* introduce inter-thread memory +/// synchronization; for that, a [`fence`] is needed. +/// +/// The re-ordering prevented by the different ordering semantics are: +/// +/// - with [`SeqCst`], no re-ordering of reads and writes across this point is allowed. +/// - with [`Release`], preceding reads and writes cannot be moved past subsequent writes. +/// - with [`Acquire`], subsequent reads and writes cannot be moved ahead of preceding reads. +/// - with [`AcqRel`], both of the above rules are enforced. +/// +/// # Panics +/// +/// Panics if `order` is [`Relaxed`]. +/// +/// [`fence`]: fn.fence.html +/// [`Ordering`]: enum.Ordering.html +/// [`Acquire`]: enum.Ordering.html#variant.Acquire +/// [`SeqCst`]: enum.Ordering.html#variant.SeqCst +/// [`Release`]: enum.Ordering.html#variant.Release +/// [`AcqRel`]: enum.Ordering.html#variant.AcqRel +/// [`Relaxed`]: enum.Ordering.html#variant.Relaxed +#[inline] +#[unstable(feature = "compiler_fences", issue = "41091")] +pub fn compiler_fence(order: Ordering) { + unsafe { + match order { + Acquire => intrinsics::atomic_singlethreadfence_acq(), + Release => intrinsics::atomic_singlethreadfence_rel(), + AcqRel => intrinsics::atomic_singlethreadfence_acqrel(), + SeqCst => intrinsics::atomic_singlethreadfence(), + Relaxed => panic!("there is no such thing as a relaxed compiler fence"), + __Nonexhaustive => panic!("invalid memory ordering"), + } + } +} + + #[cfg(target_has_atomic = "8")] #[stable(feature = "atomic_debug", since = "1.3.0")] impl fmt::Debug for AtomicBool { diff --git a/src/libcoretest/any.rs b/src/libcore/tests/any.rs similarity index 100% rename from src/libcoretest/any.rs rename to src/libcore/tests/any.rs diff --git a/src/libcoretest/array.rs b/src/libcore/tests/array.rs similarity index 100% rename from src/libcoretest/array.rs rename to src/libcore/tests/array.rs diff --git a/src/libcoretest/atomic.rs b/src/libcore/tests/atomic.rs similarity index 82% rename from src/libcoretest/atomic.rs rename to src/libcore/tests/atomic.rs index b6bb5fddf4a4..9babe24a9856 100644 --- a/src/libcoretest/atomic.rs +++ b/src/libcore/tests/atomic.rs @@ -24,10 +24,23 @@ fn bool_() { #[test] fn bool_and() { let a = AtomicBool::new(true); - assert_eq!(a.fetch_and(false, SeqCst),true); + assert_eq!(a.fetch_and(false, SeqCst), true); assert_eq!(a.load(SeqCst),false); } +#[test] +fn bool_nand() { + let a = AtomicBool::new(false); + assert_eq!(a.fetch_nand(false, SeqCst), false); + assert_eq!(a.load(SeqCst), true); + assert_eq!(a.fetch_nand(false, SeqCst), true); + assert_eq!(a.load(SeqCst), true); + assert_eq!(a.fetch_nand(true, SeqCst), true); + assert_eq!(a.load(SeqCst), false); + assert_eq!(a.fetch_nand(true, SeqCst), false); + assert_eq!(a.load(SeqCst), true); +} + #[test] fn uint_and() { let x = AtomicUsize::new(0xf731); diff --git a/src/libcoretest/cell.rs b/src/libcore/tests/cell.rs similarity index 100% rename from src/libcoretest/cell.rs rename to src/libcore/tests/cell.rs diff --git a/src/libcoretest/char.rs b/src/libcore/tests/char.rs similarity index 100% rename from src/libcoretest/char.rs rename to src/libcore/tests/char.rs diff --git a/src/libcoretest/clone.rs b/src/libcore/tests/clone.rs similarity index 100% rename from src/libcoretest/clone.rs rename to src/libcore/tests/clone.rs diff --git a/src/libcoretest/cmp.rs b/src/libcore/tests/cmp.rs similarity index 100% rename from src/libcoretest/cmp.rs rename to src/libcore/tests/cmp.rs diff --git a/src/libcoretest/fmt/builders.rs b/src/libcore/tests/fmt/builders.rs similarity index 100% rename from src/libcoretest/fmt/builders.rs rename to src/libcore/tests/fmt/builders.rs diff --git a/src/libcoretest/fmt/float.rs b/src/libcore/tests/fmt/float.rs similarity index 100% rename from src/libcoretest/fmt/float.rs rename to src/libcore/tests/fmt/float.rs diff --git a/src/libcoretest/fmt/mod.rs b/src/libcore/tests/fmt/mod.rs similarity index 100% rename from src/libcoretest/fmt/mod.rs rename to src/libcore/tests/fmt/mod.rs diff --git a/src/libcoretest/fmt/num.rs b/src/libcore/tests/fmt/num.rs similarity index 100% rename from src/libcoretest/fmt/num.rs rename to src/libcore/tests/fmt/num.rs diff --git a/src/libcoretest/hash/mod.rs b/src/libcore/tests/hash/mod.rs similarity index 100% rename from src/libcoretest/hash/mod.rs rename to src/libcore/tests/hash/mod.rs diff --git a/src/libcoretest/hash/sip.rs b/src/libcore/tests/hash/sip.rs similarity index 100% rename from src/libcoretest/hash/sip.rs rename to src/libcore/tests/hash/sip.rs diff --git a/src/libcoretest/intrinsics.rs b/src/libcore/tests/intrinsics.rs similarity index 100% rename from src/libcoretest/intrinsics.rs rename to src/libcore/tests/intrinsics.rs diff --git a/src/libcoretest/iter.rs b/src/libcore/tests/iter.rs similarity index 97% rename from src/libcoretest/iter.rs rename to src/libcore/tests/iter.rs index 08442f9bcbff..001fa304cd08 100644 --- a/src/libcoretest/iter.rs +++ b/src/libcore/tests/iter.rs @@ -1082,3 +1082,41 @@ fn test_chain_fold() { assert_eq!(&[2, 3, 1, 2, 0], &result[..]); } +#[test] +fn test_step_replace_unsigned() { + let mut x = 4u32; + let y = x.replace_zero(); + assert_eq!(x, 0); + assert_eq!(y, 4); + + x = 5; + let y = x.replace_one(); + assert_eq!(x, 1); + assert_eq!(y, 5); +} + +#[test] +fn test_step_replace_signed() { + let mut x = 4i32; + let y = x.replace_zero(); + assert_eq!(x, 0); + assert_eq!(y, 4); + + x = 5; + let y = x.replace_one(); + assert_eq!(x, 1); + assert_eq!(y, 5); +} + +#[test] +fn test_step_replace_no_between() { + let mut x = 4u128; + let y = x.replace_zero(); + assert_eq!(x, 0); + assert_eq!(y, 4); + + x = 5; + let y = x.replace_one(); + assert_eq!(x, 1); + assert_eq!(y, 5); +} \ No newline at end of file diff --git a/src/libcoretest/lib.rs b/src/libcore/tests/lib.rs similarity index 95% rename from src/libcoretest/lib.rs rename to src/libcore/tests/lib.rs index d92c378160d2..f0c46a6f194d 100644 --- a/src/libcoretest/lib.rs +++ b/src/libcore/tests/lib.rs @@ -20,6 +20,8 @@ #![feature(fixed_size_array)] #![feature(flt2dec)] #![feature(fmt_internals)] +#![feature(i128_type)] +#![feature(iter_rfind)] #![feature(libc)] #![feature(nonzero)] #![feature(rand)] @@ -29,6 +31,7 @@ #![feature(sort_internals)] #![feature(sort_unstable)] #![feature(step_by)] +#![feature(step_trait)] #![feature(test)] #![feature(try_from)] #![feature(unicode)] diff --git a/src/libcoretest/mem.rs b/src/libcore/tests/mem.rs similarity index 100% rename from src/libcoretest/mem.rs rename to src/libcore/tests/mem.rs diff --git a/src/libcoretest/nonzero.rs b/src/libcore/tests/nonzero.rs similarity index 100% rename from src/libcoretest/nonzero.rs rename to src/libcore/tests/nonzero.rs diff --git a/src/libcoretest/num/bignum.rs b/src/libcore/tests/num/bignum.rs similarity index 100% rename from src/libcoretest/num/bignum.rs rename to src/libcore/tests/num/bignum.rs diff --git a/src/libcoretest/num/dec2flt/mod.rs b/src/libcore/tests/num/dec2flt/mod.rs similarity index 100% rename from src/libcoretest/num/dec2flt/mod.rs rename to src/libcore/tests/num/dec2flt/mod.rs diff --git a/src/libcoretest/num/dec2flt/parse.rs b/src/libcore/tests/num/dec2flt/parse.rs similarity index 100% rename from src/libcoretest/num/dec2flt/parse.rs rename to src/libcore/tests/num/dec2flt/parse.rs diff --git a/src/libcoretest/num/dec2flt/rawfp.rs b/src/libcore/tests/num/dec2flt/rawfp.rs similarity index 72% rename from src/libcoretest/num/dec2flt/rawfp.rs rename to src/libcore/tests/num/dec2flt/rawfp.rs index 1a3533317dae..2b0afc402027 100644 --- a/src/libcoretest/num/dec2flt/rawfp.rs +++ b/src/libcore/tests/num/dec2flt/rawfp.rs @@ -8,23 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use std::f32; use std::f64; -use std::mem; use core::num::diy_float::Fp; use core::num::dec2flt::rawfp::{fp_to_float, prev_float, next_float, round_normal}; +use core::num::dec2flt::rawfp::RawFloat; fn integer_decode(f: f64) -> (u64, i16, i8) { - let bits: u64 = unsafe { mem::transmute(f) }; - let sign: i8 = if bits >> 63 == 0 { 1 } else { -1 }; - let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16; - let mantissa = if exponent == 0 { - (bits & 0xfffffffffffff) << 1 - } else { - (bits & 0xfffffffffffff) | 0x10000000000000 - }; - // Exponent bias + mantissa shift - exponent -= 1023 + 52; - (mantissa, exponent, sign) + RawFloat::integer_decode(f) } #[test] @@ -152,3 +143,35 @@ fn next_float_monotonic() { } assert!(x > 0.5); } + +#[test] +fn test_f32_integer_decode() { + assert_eq!(3.14159265359f32.integer_decode(), (13176795, -22, 1)); + assert_eq!((-8573.5918555f32).integer_decode(), (8779358, -10, -1)); + assert_eq!(2f32.powf(100.0).integer_decode(), (8388608, 77, 1)); + assert_eq!(0f32.integer_decode(), (0, -150, 1)); + assert_eq!((-0f32).integer_decode(), (0, -150, -1)); + assert_eq!(f32::INFINITY.integer_decode(), (8388608, 105, 1)); + assert_eq!(f32::NEG_INFINITY.integer_decode(), (8388608, 105, -1)); + + // Ignore the "sign" (quiet / signalling flag) of NAN. + // It can vary between runtime operations and LLVM folding. + let (nan_m, nan_e, _nan_s) = f32::NAN.integer_decode(); + assert_eq!((nan_m, nan_e), (12582912, 105)); +} + +#[test] +fn test_f64_integer_decode() { + assert_eq!(3.14159265359f64.integer_decode(), (7074237752028906, -51, 1)); + assert_eq!((-8573.5918555f64).integer_decode(), (4713381968463931, -39, -1)); + assert_eq!(2f64.powf(100.0).integer_decode(), (4503599627370496, 48, 1)); + assert_eq!(0f64.integer_decode(), (0, -1075, 1)); + assert_eq!((-0f64).integer_decode(), (0, -1075, -1)); + assert_eq!(f64::INFINITY.integer_decode(), (4503599627370496, 972, 1)); + assert_eq!(f64::NEG_INFINITY.integer_decode(), (4503599627370496, 972, -1)); + + // Ignore the "sign" (quiet / signalling flag) of NAN. + // It can vary between runtime operations and LLVM folding. + let (nan_m, nan_e, _nan_s) = f64::NAN.integer_decode(); + assert_eq!((nan_m, nan_e), (6755399441055744, 972)); +} diff --git a/src/libcoretest/num/flt2dec/estimator.rs b/src/libcore/tests/num/flt2dec/estimator.rs similarity index 100% rename from src/libcoretest/num/flt2dec/estimator.rs rename to src/libcore/tests/num/flt2dec/estimator.rs diff --git a/src/libcoretest/num/flt2dec/mod.rs b/src/libcore/tests/num/flt2dec/mod.rs similarity index 100% rename from src/libcoretest/num/flt2dec/mod.rs rename to src/libcore/tests/num/flt2dec/mod.rs diff --git a/src/libcoretest/num/flt2dec/strategy/dragon.rs b/src/libcore/tests/num/flt2dec/strategy/dragon.rs similarity index 100% rename from src/libcoretest/num/flt2dec/strategy/dragon.rs rename to src/libcore/tests/num/flt2dec/strategy/dragon.rs diff --git a/src/libcoretest/num/flt2dec/strategy/grisu.rs b/src/libcore/tests/num/flt2dec/strategy/grisu.rs similarity index 100% rename from src/libcoretest/num/flt2dec/strategy/grisu.rs rename to src/libcore/tests/num/flt2dec/strategy/grisu.rs diff --git a/src/libcoretest/num/i16.rs b/src/libcore/tests/num/i16.rs similarity index 100% rename from src/libcoretest/num/i16.rs rename to src/libcore/tests/num/i16.rs diff --git a/src/libcoretest/num/i32.rs b/src/libcore/tests/num/i32.rs similarity index 100% rename from src/libcoretest/num/i32.rs rename to src/libcore/tests/num/i32.rs diff --git a/src/libcoretest/num/i64.rs b/src/libcore/tests/num/i64.rs similarity index 100% rename from src/libcoretest/num/i64.rs rename to src/libcore/tests/num/i64.rs diff --git a/src/libcoretest/num/i8.rs b/src/libcore/tests/num/i8.rs similarity index 100% rename from src/libcoretest/num/i8.rs rename to src/libcore/tests/num/i8.rs diff --git a/src/libcoretest/num/int_macros.rs b/src/libcore/tests/num/int_macros.rs similarity index 100% rename from src/libcoretest/num/int_macros.rs rename to src/libcore/tests/num/int_macros.rs diff --git a/src/libcoretest/num/mod.rs b/src/libcore/tests/num/mod.rs similarity index 100% rename from src/libcoretest/num/mod.rs rename to src/libcore/tests/num/mod.rs diff --git a/src/libcoretest/num/u16.rs b/src/libcore/tests/num/u16.rs similarity index 100% rename from src/libcoretest/num/u16.rs rename to src/libcore/tests/num/u16.rs diff --git a/src/libcoretest/num/u32.rs b/src/libcore/tests/num/u32.rs similarity index 100% rename from src/libcoretest/num/u32.rs rename to src/libcore/tests/num/u32.rs diff --git a/src/libcoretest/num/u64.rs b/src/libcore/tests/num/u64.rs similarity index 100% rename from src/libcoretest/num/u64.rs rename to src/libcore/tests/num/u64.rs diff --git a/src/libcoretest/num/u8.rs b/src/libcore/tests/num/u8.rs similarity index 100% rename from src/libcoretest/num/u8.rs rename to src/libcore/tests/num/u8.rs diff --git a/src/libcoretest/num/uint_macros.rs b/src/libcore/tests/num/uint_macros.rs similarity index 100% rename from src/libcoretest/num/uint_macros.rs rename to src/libcore/tests/num/uint_macros.rs diff --git a/src/libcoretest/ops.rs b/src/libcore/tests/ops.rs similarity index 100% rename from src/libcoretest/ops.rs rename to src/libcore/tests/ops.rs diff --git a/src/libcoretest/option.rs b/src/libcore/tests/option.rs similarity index 100% rename from src/libcoretest/option.rs rename to src/libcore/tests/option.rs diff --git a/src/libcoretest/ptr.rs b/src/libcore/tests/ptr.rs similarity index 100% rename from src/libcoretest/ptr.rs rename to src/libcore/tests/ptr.rs diff --git a/src/libcoretest/result.rs b/src/libcore/tests/result.rs similarity index 100% rename from src/libcoretest/result.rs rename to src/libcore/tests/result.rs diff --git a/src/libcoretest/slice.rs b/src/libcore/tests/slice.rs similarity index 91% rename from src/libcoretest/slice.rs rename to src/libcore/tests/slice.rs index 89bd3be08519..15047204e50d 100644 --- a/src/libcoretest/slice.rs +++ b/src/libcore/tests/slice.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use core::cmp::Ordering::{Equal, Greater, Less}; use core::slice::heapsort; use core::result::Result::{Ok, Err}; use rand::{Rng, XorShiftRng}; @@ -224,6 +225,19 @@ fn get_unchecked_mut_range() { } } +#[test] +fn test_find_rfind() { + let v = [0, 1, 2, 3, 4, 5]; + let mut iter = v.iter(); + let mut i = v.len(); + while let Some(&elt) = iter.rfind(|_| true) { + i -= 1; + assert_eq!(elt, v[i]); + } + assert_eq!(i, 0); + assert_eq!(v.iter().rfind(|&&x| x <= 3), Some(&3)); +} + #[test] fn sort_unstable() { let mut v = [0; 600]; @@ -268,6 +282,17 @@ fn sort_unstable() { } } + // Sort using a completely random comparison function. + // This will reorder the elements *somehow*, but won't panic. + for i in 0..v.len() { + v[i] = i as i32; + } + v.sort_unstable_by(|_, _| *rng.choose(&[Less, Equal, Greater]).unwrap()); + v.sort_unstable(); + for i in 0..v.len() { + assert_eq!(v[i], i as i32); + } + // Should not panic. [0i32; 0].sort_unstable(); [(); 10].sort_unstable(); diff --git a/src/libcoretest/str.rs b/src/libcore/tests/str.rs similarity index 90% rename from src/libcoretest/str.rs rename to src/libcore/tests/str.rs index b7d9ba4463d9..08daafccc540 100644 --- a/src/libcoretest/str.rs +++ b/src/libcore/tests/str.rs @@ -8,4 +8,4 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// All `str` tests live in libcollectiontest::str +// All `str` tests live in collectionstests::str diff --git a/src/libcoretest/tuple.rs b/src/libcore/tests/tuple.rs similarity index 100% rename from src/libcoretest/tuple.rs rename to src/libcore/tests/tuple.rs diff --git a/src/libgraphviz/lib.rs b/src/libgraphviz/lib.rs index 8e587ad211de..1b2c7775185f 100644 --- a/src/libgraphviz/lib.rs +++ b/src/libgraphviz/lib.rs @@ -554,7 +554,7 @@ impl<'a> LabelText<'a> { pub fn to_dot_string(&self) -> String { match self { &LabelStr(ref s) => format!("\"{}\"", s.escape_default()), - &EscStr(ref s) => format!("\"{}\"", LabelText::escape_str(&s[..])), + &EscStr(ref s) => format!("\"{}\"", LabelText::escape_str(&s)), &HtmlStr(ref s) => format!("<{}>", s), } } @@ -587,7 +587,7 @@ impl<'a> LabelText<'a> { let mut prefix = self.pre_escaped_content().into_owned(); let suffix = suffix.pre_escaped_content(); prefix.push_str(r"\n\n"); - prefix.push_str(&suffix[..]); + prefix.push_str(&suffix); EscStr(prefix.into_cow()) } } @@ -878,7 +878,7 @@ mod tests { type Node = Node; type Edge = &'a Edge; fn graph_id(&'a self) -> Id<'a> { - Id::new(&self.name[..]).unwrap() + Id::new(self.name).unwrap() } fn node_id(&'a self, n: &Node) -> Id<'a> { id_name(n) diff --git a/src/liblibc b/src/liblibc index 64d954c6a76e..c34a802d1eb0 160000 --- a/src/liblibc +++ b/src/liblibc @@ -1 +1 @@ -Subproject commit 64d954c6a76e896fbf7ed5c17e77c40e388abe84 +Subproject commit c34a802d1eb037b44c5252078c7270b5472e0f65 diff --git a/src/liblog/Cargo.toml b/src/liblog/Cargo.toml deleted file mode 100644 index 31a862478d03..000000000000 --- a/src/liblog/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "log" -version = "0.0.0" - -[lib] -name = "log" -path = "lib.rs" -crate-type = ["dylib", "rlib"] diff --git a/src/liblog/directive.rs b/src/liblog/directive.rs deleted file mode 100644 index eb50d6e6135e..000000000000 --- a/src/liblog/directive.rs +++ /dev/null @@ -1,193 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::ascii::AsciiExt; -use std::cmp; - -#[derive(Debug, Clone)] -pub struct LogDirective { - pub name: Option, - pub level: u32, -} - -pub const LOG_LEVEL_NAMES: [&'static str; 5] = ["ERROR", "WARN", "INFO", "DEBUG", "TRACE"]; - -/// Parse an individual log level that is either a number or a symbolic log level -fn parse_log_level(level: &str) -> Option { - level.parse::() - .ok() - .or_else(|| { - let pos = LOG_LEVEL_NAMES.iter().position(|&name| name.eq_ignore_ascii_case(level)); - pos.map(|p| p as u32 + 1) - }) - .map(|p| cmp::min(p, ::MAX_LOG_LEVEL)) -} - -/// Parse a logging specification string (e.g: "crate1,crate2::mod3,crate3::x=1/foo") -/// and return a vector with log directives. -/// -/// Valid log levels are 0-255, with the most likely ones being 1-4 (defined in -/// std::). Also supports string log levels of error, warn, info, and debug -pub fn parse_logging_spec(spec: &str) -> (Vec, Option) { - let mut dirs = Vec::new(); - - let mut parts = spec.split('/'); - let mods = parts.next(); - let filter = parts.next(); - if parts.next().is_some() { - println!("warning: invalid logging spec '{}', ignoring it (too many '/'s)", - spec); - return (dirs, None); - } - if let Some(m) = mods { - for s in m.split(',') { - if s.is_empty() { - continue; - } - let mut parts = s.split('='); - let (log_level, name) = - match (parts.next(), parts.next().map(|s| s.trim()), parts.next()) { - (Some(part0), None, None) => { - // if the single argument is a log-level string or number, - // treat that as a global fallback - match parse_log_level(part0) { - Some(num) => (num, None), - None => (::MAX_LOG_LEVEL, Some(part0)), - } - } - (Some(part0), Some(""), None) => (::MAX_LOG_LEVEL, Some(part0)), - (Some(part0), Some(part1), None) => { - match parse_log_level(part1) { - Some(num) => (num, Some(part0)), - _ => { - println!("warning: invalid logging spec '{}', ignoring it", part1); - continue; - } - } - } - _ => { - println!("warning: invalid logging spec '{}', ignoring it", s); - continue; - } - }; - dirs.push(LogDirective { - name: name.map(str::to_owned), - level: log_level, - }); - } - } - - (dirs, filter.map(str::to_owned)) -} - -#[cfg(test)] -mod tests { - use super::parse_logging_spec; - - #[test] - fn parse_logging_spec_valid() { - let (dirs, filter) = parse_logging_spec("crate1::mod1=1,crate1::mod2,crate2=4"); - assert_eq!(dirs.len(), 3); - assert_eq!(dirs[0].name, Some("crate1::mod1".to_owned())); - assert_eq!(dirs[0].level, 1); - - assert_eq!(dirs[1].name, Some("crate1::mod2".to_owned())); - assert_eq!(dirs[1].level, ::MAX_LOG_LEVEL); - - assert_eq!(dirs[2].name, Some("crate2".to_owned())); - assert_eq!(dirs[2].level, 4); - assert!(filter.is_none()); - } - - #[test] - fn parse_logging_spec_invalid_crate() { - // test parse_logging_spec with multiple = in specification - let (dirs, filter) = parse_logging_spec("crate1::mod1=1=2,crate2=4"); - assert_eq!(dirs.len(), 1); - assert_eq!(dirs[0].name, Some("crate2".to_owned())); - assert_eq!(dirs[0].level, 4); - assert!(filter.is_none()); - } - - #[test] - fn parse_logging_spec_invalid_log_level() { - // test parse_logging_spec with 'noNumber' as log level - let (dirs, filter) = parse_logging_spec("crate1::mod1=noNumber,crate2=4"); - assert_eq!(dirs.len(), 1); - assert_eq!(dirs[0].name, Some("crate2".to_owned())); - assert_eq!(dirs[0].level, 4); - assert!(filter.is_none()); - } - - #[test] - fn parse_logging_spec_string_log_level() { - // test parse_logging_spec with 'warn' as log level - let (dirs, filter) = parse_logging_spec("crate1::mod1=wrong,crate2=warn"); - assert_eq!(dirs.len(), 1); - assert_eq!(dirs[0].name, Some("crate2".to_owned())); - assert_eq!(dirs[0].level, ::WARN); - assert!(filter.is_none()); - } - - #[test] - fn parse_logging_spec_empty_log_level() { - // test parse_logging_spec with '' as log level - let (dirs, filter) = parse_logging_spec("crate1::mod1=wrong,crate2="); - assert_eq!(dirs.len(), 1); - assert_eq!(dirs[0].name, Some("crate2".to_owned())); - assert_eq!(dirs[0].level, ::MAX_LOG_LEVEL); - assert!(filter.is_none()); - } - - #[test] - fn parse_logging_spec_global() { - // test parse_logging_spec with no crate - let (dirs, filter) = parse_logging_spec("warn,crate2=4"); - assert_eq!(dirs.len(), 2); - assert_eq!(dirs[0].name, None); - assert_eq!(dirs[0].level, 2); - assert_eq!(dirs[1].name, Some("crate2".to_owned())); - assert_eq!(dirs[1].level, 4); - assert!(filter.is_none()); - } - - #[test] - fn parse_logging_spec_valid_filter() { - let (dirs, filter) = parse_logging_spec("crate1::mod1=1,crate1::mod2,crate2=4/abc"); - assert_eq!(dirs.len(), 3); - assert_eq!(dirs[0].name, Some("crate1::mod1".to_owned())); - assert_eq!(dirs[0].level, 1); - - assert_eq!(dirs[1].name, Some("crate1::mod2".to_owned())); - assert_eq!(dirs[1].level, ::MAX_LOG_LEVEL); - - assert_eq!(dirs[2].name, Some("crate2".to_owned())); - assert_eq!(dirs[2].level, 4); - assert!(filter.is_some() && filter.unwrap().to_owned() == "abc"); - } - - #[test] - fn parse_logging_spec_invalid_crate_filter() { - let (dirs, filter) = parse_logging_spec("crate1::mod1=1=2,crate2=4/a.c"); - assert_eq!(dirs.len(), 1); - assert_eq!(dirs[0].name, Some("crate2".to_owned())); - assert_eq!(dirs[0].level, 4); - assert!(filter.is_some() && filter.unwrap().to_owned() == "a.c"); - } - - #[test] - fn parse_logging_spec_empty_with_filter() { - let (dirs, filter) = parse_logging_spec("crate1/a*c"); - assert_eq!(dirs.len(), 1); - assert_eq!(dirs[0].name, Some("crate1".to_owned())); - assert_eq!(dirs[0].level, ::MAX_LOG_LEVEL); - assert!(filter.is_some() && filter.unwrap().to_owned() == "a*c"); - } -} diff --git a/src/liblog/lib.rs b/src/liblog/lib.rs deleted file mode 100644 index 057df647c725..000000000000 --- a/src/liblog/lib.rs +++ /dev/null @@ -1,506 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Utilities for program-wide and customizable logging -//! -//! # Examples -//! -//! ``` -//! # #![feature(rustc_private)] -//! #[macro_use] extern crate log; -//! -//! fn main() { -//! debug!("this is a debug {:?}", "message"); -//! error!("this is printed by default"); -//! -//! if log_enabled!(log::INFO) { -//! let x = 3 * 4; // expensive computation -//! info!("the answer was: {:?}", x); -//! } -//! } -//! ``` -//! -//! Assumes the binary is `main`: -//! -//! ```{.bash} -//! $ RUST_LOG=error ./main -//! ERROR:main: this is printed by default -//! ``` -//! -//! ```{.bash} -//! $ RUST_LOG=info ./main -//! ERROR:main: this is printed by default -//! INFO:main: the answer was: 12 -//! ``` -//! -//! ```{.bash} -//! $ RUST_LOG=debug ./main -//! DEBUG:main: this is a debug message -//! ERROR:main: this is printed by default -//! INFO:main: the answer was: 12 -//! ``` -//! -//! You can also set the log level on a per module basis: -//! -//! ```{.bash} -//! $ RUST_LOG=main=info ./main -//! ERROR:main: this is printed by default -//! INFO:main: the answer was: 12 -//! ``` -//! -//! And enable all logging: -//! -//! ```{.bash} -//! $ RUST_LOG=main ./main -//! DEBUG:main: this is a debug message -//! ERROR:main: this is printed by default -//! INFO:main: the answer was: 12 -//! ``` -//! -//! # Logging Macros -//! -//! There are five macros that the logging subsystem uses: -//! -//! * `log!(level, ...)` - the generic logging macro, takes a level as a u32 and any -//! related `format!` arguments -//! * `debug!(...)` - a macro hard-wired to the log level of `DEBUG` -//! * `info!(...)` - a macro hard-wired to the log level of `INFO` -//! * `warn!(...)` - a macro hard-wired to the log level of `WARN` -//! * `error!(...)` - a macro hard-wired to the log level of `ERROR` -//! -//! All of these macros use the same style of syntax as the `format!` syntax -//! extension. Details about the syntax can be found in the documentation of -//! `std::fmt` along with the Rust tutorial/manual. -//! -//! If you want to check at runtime if a given logging level is enabled (e.g. if the -//! information you would want to log is expensive to produce), you can use the -//! following macro: -//! -//! * `log_enabled!(level)` - returns true if logging of the given level is enabled -//! -//! # Enabling logging -//! -//! Log levels are controlled on a per-module basis, and by default all logging is -//! disabled except for `error!` (a log level of 1). Logging is controlled via the -//! `RUST_LOG` environment variable. The value of this environment variable is a -//! comma-separated list of logging directives. A logging directive is of the form: -//! -//! ```text -//! path::to::module=log_level -//! ``` -//! -//! The path to the module is rooted in the name of the crate it was compiled for, -//! so if your program is contained in a file `hello.rs`, for example, to turn on -//! logging for this file you would use a value of `RUST_LOG=hello`. -//! Furthermore, this path is a prefix-search, so all modules nested in the -//! specified module will also have logging enabled. -//! -//! The actual `log_level` is optional to specify. If omitted, all logging will be -//! enabled. If specified, the it must be either a numeric in the range of 1-255, or -//! it must be one of the strings `debug`, `error`, `info`, or `warn`. If a numeric -//! is specified, then all logging less than or equal to that numeral is enabled. -//! For example, if logging level 3 is active, error, warn, and info logs will be -//! printed, but debug will be omitted. -//! -//! As the log level for a module is optional, the module to enable logging for is -//! also optional. If only a `log_level` is provided, then the global log level for -//! all modules is set to this value. -//! -//! Some examples of valid values of `RUST_LOG` are: -//! -//! * `hello` turns on all logging for the 'hello' module -//! * `info` turns on all info logging -//! * `hello=debug` turns on debug logging for 'hello' -//! * `hello=3` turns on info logging for 'hello' -//! * `hello,std::option` turns on hello, and std's option logging -//! * `error,hello=warn` turn on global error logging and also warn for hello -//! -//! # Filtering results -//! -//! A RUST_LOG directive may include a string filter. The syntax is to append -//! `/` followed by a string. Each message is checked against the string and is -//! only logged if it contains the string. Note that the matching is done after -//! formatting the log string but before adding any logging meta-data. There is -//! a single filter for all modules. -//! -//! Some examples: -//! -//! * `hello/foo` turns on all logging for the 'hello' module where the log message -//! includes 'foo'. -//! * `info/f.o` turns on all info logging where the log message includes 'foo', -//! 'f1o', 'fao', etc. -//! * `hello=debug/foo*foo` turns on debug logging for 'hello' where the log -//! message includes 'foofoo' or 'fofoo' or 'fooooooofoo', etc. -//! * `error,hello=warn/[0-9] scopes` turn on global error logging and also warn for -//! hello. In both cases the log message must include a single digit number -//! followed by 'scopes' -//! -//! # Performance and Side Effects -//! -//! Each of these macros will expand to code similar to: -//! -//! ```rust,ignore -//! if log_level <= my_module_log_level() { -//! ::log::log(log_level, format!(...)); -//! } -//! ``` -//! -//! What this means is that each of these macros are very cheap at runtime if -//! they're turned off (just a load and an integer comparison). This also means that -//! if logging is disabled, none of the components of the log will be executed. - -#![crate_name = "log"] -#![unstable(feature = "rustc_private", - reason = "use the crates.io `log` library instead", - issue = "27812")] -#![crate_type = "rlib"] -#![crate_type = "dylib"] -#![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/", - html_playground_url = "https://play.rust-lang.org/", - test(attr(deny(warnings))))] -#![deny(missing_docs)] -#![deny(warnings)] - -#![feature(staged_api)] - -use std::cell::RefCell; -use std::fmt; -use std::io::{self, Stderr}; -use std::io::prelude::*; -use std::mem; -use std::env; -use std::slice; -use std::sync::{Mutex, ONCE_INIT, Once}; - -use directive::LOG_LEVEL_NAMES; - -#[macro_use] -pub mod macros; - -mod directive; - -/// Maximum logging level of a module that can be specified. Common logging -/// levels are found in the DEBUG/INFO/WARN/ERROR constants. -pub const MAX_LOG_LEVEL: u32 = 255; - -/// The default logging level of a crate if no other is specified. -const DEFAULT_LOG_LEVEL: u32 = 1; - -static mut LOCK: *mut Mutex<(Vec, Option)> = 0 as *mut _; - -/// An unsafe constant that is the maximum logging level of any module -/// specified. This is the first line of defense to determining whether a -/// logging statement should be run. -static mut LOG_LEVEL: u32 = MAX_LOG_LEVEL; - -/// Debug log level -pub const DEBUG: u32 = 4; -/// Info log level -pub const INFO: u32 = 3; -/// Warn log level -pub const WARN: u32 = 2; -/// Error log level -pub const ERROR: u32 = 1; - -thread_local! { - static LOCAL_LOGGER: RefCell>> = { - RefCell::new(None) - } -} - -/// A trait used to represent an interface to a thread-local logger. Each thread -/// can have its own custom logger which can respond to logging messages -/// however it likes. -pub trait Logger { - /// Logs a single message described by the `record`. - fn log(&mut self, record: &LogRecord); -} - -struct DefaultLogger { - handle: Stderr, -} - -/// Wraps the log level with fmt implementations. -#[derive(Copy, Clone, PartialEq, PartialOrd, Debug)] -pub struct LogLevel(pub u32); - -impl fmt::Display for LogLevel { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - let LogLevel(level) = *self; - match LOG_LEVEL_NAMES.get(level as usize - 1) { - Some(ref name) => fmt::Display::fmt(name, fmt), - None => fmt::Display::fmt(&level, fmt), - } - } -} - -impl Logger for DefaultLogger { - fn log(&mut self, record: &LogRecord) { - match writeln!(&mut self.handle, - "{}:{}: {}", - record.level, - record.module_path, - record.args) { - Err(e) => panic!("failed to log: {:?}", e), - Ok(()) => {} - } - } -} - -impl Drop for DefaultLogger { - fn drop(&mut self) { - // FIXME(#12628): is panicking the right thing to do? - match self.handle.flush() { - Err(e) => panic!("failed to flush a logger: {:?}", e), - Ok(()) => {} - } - } -} - -/// This function is called directly by the compiler when using the logging -/// macros. This function does not take into account whether the log level -/// specified is active or not, it will always log something if this method is -/// called. -/// -/// It is not recommended to call this function directly, rather it should be -/// invoked through the logging family of macros. -#[doc(hidden)] -pub fn log(level: u32, loc: &'static LogLocation, args: fmt::Arguments) { - // Test the literal string from args against the current filter, if there - // is one. - unsafe { - let filter = (*LOCK).lock().unwrap(); - if let Some(ref filter) = filter.1 { - if !args.to_string().contains(filter) { - return; - } - } - } - - // Completely remove the local logger from TLS in case anyone attempts to - // frob the slot while we're doing the logging. This will destroy any logger - // set during logging. - let logger = LOCAL_LOGGER.with(|s| s.borrow_mut().take()); - let mut logger = logger.unwrap_or_else(|| Box::new(DefaultLogger { handle: io::stderr() })); - logger.log(&LogRecord { - level: LogLevel(level), - args: args, - file: loc.file, - module_path: loc.module_path, - line: loc.line, - }); - set_logger(logger); -} - -/// Getter for the global log level. This is a function so that it can be called -/// safely -#[doc(hidden)] -#[inline(always)] -pub fn log_level() -> u32 { - unsafe { LOG_LEVEL } -} - -/// Replaces the thread-local logger with the specified logger, returning the old -/// logger. -pub fn set_logger(logger: Box) -> Option> { - LOCAL_LOGGER.with(|slot| mem::replace(&mut *slot.borrow_mut(), Some(logger))) -} - -/// A LogRecord is created by the logging macros, and passed as the only -/// argument to Loggers. -#[derive(Debug)] -pub struct LogRecord<'a> { - /// The module path of where the LogRecord originated. - pub module_path: &'a str, - - /// The LogLevel of this record. - pub level: LogLevel, - - /// The arguments from the log line. - pub args: fmt::Arguments<'a>, - - /// The file of where the LogRecord originated. - pub file: &'a str, - - /// The line number of where the LogRecord originated. - pub line: u32, -} - -#[doc(hidden)] -#[derive(Copy, Clone)] -pub struct LogLocation { - pub module_path: &'static str, - pub file: &'static str, - pub line: u32, -} - -/// Tests whether a given module's name is enabled for a particular level of -/// logging. This is the second layer of defense about determining whether a -/// module's log statement should be emitted or not. -#[doc(hidden)] -pub fn mod_enabled(level: u32, module: &str) -> bool { - static INIT: Once = ONCE_INIT; - INIT.call_once(init); - - // It's possible for many threads are in this function, only one of them - // will perform the global initialization, but all of them will need to check - // again to whether they should really be here or not. Hence, despite this - // check being expanded manually in the logging macro, this function checks - // the log level again. - if level > unsafe { LOG_LEVEL } { - return false; - } - - // This assertion should never get tripped unless we're in an at_exit - // handler after logging has been torn down and a logging attempt was made. - - unsafe { - let directives = (*LOCK).lock().unwrap(); - enabled(level, module, directives.0.iter()) - } -} - -fn enabled(level: u32, module: &str, iter: slice::Iter) -> bool { - // Search for the longest match, the vector is assumed to be pre-sorted. - for directive in iter.rev() { - match directive.name { - Some(ref name) if !module.starts_with(&name[..]) => {} - Some(..) | None => return level <= directive.level, - } - } - level <= DEFAULT_LOG_LEVEL -} - -/// Initialize logging for the current process. -/// -/// This is not threadsafe at all, so initialization is performed through a -/// `Once` primitive (and this function is called from that primitive). -fn init() { - let (mut directives, filter) = match env::var("RUST_LOG") { - Ok(spec) => directive::parse_logging_spec(&spec[..]), - Err(..) => (Vec::new(), None), - }; - - // Sort the provided directives by length of their name, this allows a - // little more efficient lookup at runtime. - directives.sort_by(|a, b| { - let alen = a.name.as_ref().map(|a| a.len()).unwrap_or(0); - let blen = b.name.as_ref().map(|b| b.len()).unwrap_or(0); - alen.cmp(&blen) - }); - - let max_level = { - let max = directives.iter().max_by_key(|d| d.level); - max.map(|d| d.level).unwrap_or(DEFAULT_LOG_LEVEL) - }; - - unsafe { - LOG_LEVEL = max_level; - - assert!(LOCK.is_null()); - LOCK = Box::into_raw(Box::new(Mutex::new((directives, filter)))); - } -} - -#[cfg(test)] -mod tests { - use super::enabled; - use directive::LogDirective; - - #[test] - fn match_full_path() { - let dirs = [LogDirective { - name: Some("crate2".to_string()), - level: 3, - }, - LogDirective { - name: Some("crate1::mod1".to_string()), - level: 2, - }]; - assert!(enabled(2, "crate1::mod1", dirs.iter())); - assert!(!enabled(3, "crate1::mod1", dirs.iter())); - assert!(enabled(3, "crate2", dirs.iter())); - assert!(!enabled(4, "crate2", dirs.iter())); - } - - #[test] - fn no_match() { - let dirs = [LogDirective { - name: Some("crate2".to_string()), - level: 3, - }, - LogDirective { - name: Some("crate1::mod1".to_string()), - level: 2, - }]; - assert!(!enabled(2, "crate3", dirs.iter())); - } - - #[test] - fn match_beginning() { - let dirs = [LogDirective { - name: Some("crate2".to_string()), - level: 3, - }, - LogDirective { - name: Some("crate1::mod1".to_string()), - level: 2, - }]; - assert!(enabled(3, "crate2::mod1", dirs.iter())); - } - - #[test] - fn match_beginning_longest_match() { - let dirs = [LogDirective { - name: Some("crate2".to_string()), - level: 3, - }, - LogDirective { - name: Some("crate2::mod".to_string()), - level: 4, - }, - LogDirective { - name: Some("crate1::mod1".to_string()), - level: 2, - }]; - assert!(enabled(4, "crate2::mod1", dirs.iter())); - assert!(!enabled(4, "crate2", dirs.iter())); - } - - #[test] - fn match_default() { - let dirs = [LogDirective { - name: None, - level: 3, - }, - LogDirective { - name: Some("crate1::mod1".to_string()), - level: 2, - }]; - assert!(enabled(2, "crate1::mod1", dirs.iter())); - assert!(enabled(3, "crate2::mod2", dirs.iter())); - } - - #[test] - fn zero_level() { - let dirs = [LogDirective { - name: None, - level: 3, - }, - LogDirective { - name: Some("crate1::mod1".to_string()), - level: 0, - }]; - assert!(!enabled(1, "crate1::mod1", dirs.iter())); - assert!(enabled(3, "crate2::mod2", dirs.iter())); - } -} diff --git a/src/liblog/macros.rs b/src/liblog/macros.rs deleted file mode 100644 index 803a2df9ccc8..000000000000 --- a/src/liblog/macros.rs +++ /dev/null @@ -1,205 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Logging macros - -/// The standard logging macro -/// -/// This macro will generically log over a provided level (of type u32) with a -/// format!-based argument list. See documentation in `std::fmt` for details on -/// how to use the syntax. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rustc_private)] -/// #[macro_use] extern crate log; -/// -/// fn main() { -/// log!(log::WARN, "this is a warning {}", "message"); -/// log!(log::DEBUG, "this is a debug message"); -/// log!(6, "this is a custom logging level: {level}", level=6); -/// } -/// ``` -/// -/// Assumes the binary is `main`: -/// -/// ```{.bash} -/// $ RUST_LOG=warn ./main -/// WARN:main: this is a warning message -/// ``` -/// -/// ```{.bash} -/// $ RUST_LOG=debug ./main -/// DEBUG:main: this is a debug message -/// WARN:main: this is a warning message -/// ``` -/// -/// ```{.bash} -/// $ RUST_LOG=6 ./main -/// DEBUG:main: this is a debug message -/// WARN:main: this is a warning message -/// 6:main: this is a custom logging level: 6 -/// ``` -#[macro_export] -macro_rules! log { - ($lvl:expr, $($arg:tt)+) => ({ - static LOC: ::log::LogLocation = ::log::LogLocation { - line: line!(), - file: file!(), - module_path: module_path!(), - }; - let lvl = $lvl; - if log_enabled!(lvl) { - ::log::log(lvl, &LOC, format_args!($($arg)+)) - } - }) -} - -/// A convenience macro for logging at the error log level. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rustc_private)] -/// #[macro_use] extern crate log; -/// -/// fn main() { -/// let error = 3; -/// error!("the build has failed with error code: {}", error); -/// } -/// ``` -/// -/// Assumes the binary is `main`: -/// -/// ```{.bash} -/// $ RUST_LOG=error ./main -/// ERROR:main: the build has failed with error code: 3 -/// ``` -/// -#[macro_export] -macro_rules! error { - ($($arg:tt)*) => (log!(::log::ERROR, $($arg)*)) -} - -/// A convenience macro for logging at the warning log level. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rustc_private)] -/// #[macro_use] extern crate log; -/// -/// fn main() { -/// let code = 3; -/// warn!("you may like to know that a process exited with: {}", code); -/// } -/// ``` -/// -/// Assumes the binary is `main`: -/// -/// ```{.bash} -/// $ RUST_LOG=warn ./main -/// WARN:main: you may like to know that a process exited with: 3 -/// ``` -#[macro_export] -macro_rules! warn { - ($($arg:tt)*) => (log!(::log::WARN, $($arg)*)) -} - -/// A convenience macro for logging at the info log level. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rustc_private)] -/// #[macro_use] extern crate log; -/// -/// fn main() { -/// let ret = 3; -/// info!("this function is about to return: {}", ret); -/// } -/// ``` -/// -/// Assumes the binary is `main`: -/// -/// ```{.bash} -/// $ RUST_LOG=info ./main -/// INFO:main: this function is about to return: 3 -/// ``` -#[macro_export] -macro_rules! info { - ($($arg:tt)*) => (log!(::log::INFO, $($arg)*)) -} - -/// A convenience macro for logging at the debug log level. This macro will -/// be omitted at compile time in an optimized build unless `-C debug-assertions` -/// is passed to the compiler. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rustc_private)] -/// #[macro_use] extern crate log; -/// -/// fn main() { -/// debug!("x = {x}, y = {y}", x=10, y=20); -/// } -/// ``` -/// -/// Assumes the binary is `main`: -/// -/// ```{.bash} -/// $ RUST_LOG=debug ./main -/// DEBUG:main: x = 10, y = 20 -/// ``` -#[macro_export] -macro_rules! debug { - ($($arg:tt)*) => (if cfg!(debug_assertions) { log!(::log::DEBUG, $($arg)*) }) -} - -/// A macro to test whether a log level is enabled for the current module. -/// -/// # Examples -/// -/// ``` -/// # #![feature(rustc_private)] -/// #[macro_use] extern crate log; -/// -/// struct Point { x: i32, y: i32 } -/// fn some_expensive_computation() -> Point { Point { x: 1, y: 2 } } -/// -/// fn main() { -/// if log_enabled!(log::DEBUG) { -/// let x = some_expensive_computation(); -/// debug!("x.x = {}, x.y = {}", x.x, x.y); -/// } -/// } -/// ``` -/// -/// Assumes the binary is `main`: -/// -/// ```{.bash} -/// $ RUST_LOG=error ./main -/// ``` -/// -/// ```{.bash} -/// $ RUST_LOG=debug ./main -/// DEBUG:main: x.x = 1, x.y = 2 -/// ``` -#[macro_export] -macro_rules! log_enabled { - ($lvl:expr) => ({ - let lvl = $lvl; - (lvl != ::log::DEBUG || cfg!(debug_assertions)) && - lvl <= ::log::log_level() && - ::log::mod_enabled(lvl, module_path!()) - }) -} diff --git a/src/librand/distributions/gamma.rs b/src/librand/distributions/gamma.rs index e024b62adfb1..9a42b82beff6 100644 --- a/src/librand/distributions/gamma.rs +++ b/src/librand/distributions/gamma.rs @@ -103,12 +103,14 @@ impl Gamma { assert!(shape > 0.0, "Gamma::new called with shape <= 0"); assert!(scale > 0.0, "Gamma::new called with scale <= 0"); - let repr = match shape { - 1.0 => One(Exp::new(1.0 / scale)), - 0.0...1.0 => Small(GammaSmallShape::new_raw(shape, scale)), - _ => Large(GammaLargeShape::new_raw(shape, scale)), + let repr = if shape == 1.0 { + One(Exp::new(1.0 / scale)) + } else if 0.0 <= shape && shape < 1.0 { + Small(GammaSmallShape::new_raw(shape, scale)) + } else { + Large(GammaLargeShape::new_raw(shape, scale)) }; - Gamma { repr: repr } + Gamma { repr } } } diff --git a/src/librand/distributions/mod.rs b/src/librand/distributions/mod.rs index eb9476efb7b4..67b9449981e0 100644 --- a/src/librand/distributions/mod.rs +++ b/src/librand/distributions/mod.rs @@ -53,7 +53,7 @@ pub trait Sample { // trait called `Sample` and the other should be `DependentSample`. pub trait IndependentSample: Sample { /// Generate a random value. - fn ind_sample(&self, &mut R) -> Support; + fn ind_sample(&self, _: &mut R) -> Support; } /// A wrapper for generating types that implement `Rand` via the diff --git a/src/librand/lib.rs b/src/librand/lib.rs index f2b43a20f944..ca05db15ffeb 100644 --- a/src/librand/lib.rs +++ b/src/librand/lib.rs @@ -329,7 +329,7 @@ impl<'a, R: fmt::Debug> fmt::Debug for AsciiGenerator<'a, R> { /// the same stream of randomness multiple times. pub trait SeedableRng: Rng { /// Reseed an RNG with the given seed. - fn reseed(&mut self, Seed); + fn reseed(&mut self, _: Seed); /// Create a new RNG with the given seed. fn from_seed(seed: Seed) -> Self; diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml index 5d53c60ad7fd..fa217acd9f9b 100644 --- a/src/librustc/Cargo.toml +++ b/src/librustc/Cargo.toml @@ -12,7 +12,7 @@ crate-type = ["dylib"] arena = { path = "../libarena" } fmt_macros = { path = "../libfmt_macros" } graphviz = { path = "../libgraphviz" } -log = { path = "../liblog" } +log = "0.3" rustc_back = { path = "../librustc_back" } rustc_bitflags = { path = "../librustc_bitflags" } rustc_const_math = { path = "../librustc_const_math" } diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs index 189a7344c313..a8ad49c6582d 100644 --- a/src/librustc/cfg/construct.rs +++ b/src/librustc/cfg/construct.rs @@ -15,9 +15,11 @@ use syntax::ast; use syntax::ptr::P; use hir::{self, PatKind}; +use hir::def_id::DefId; struct CFGBuilder<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, + owner_def_id: DefId, tables: &'a ty::TypeckTables<'tcx>, graph: CFGGraph, fn_exit: CFGIndex, @@ -52,10 +54,11 @@ pub fn construct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Find the tables for this body. let owner_def_id = tcx.hir.local_def_id(tcx.hir.body_owner(body.id())); - let tables = tcx.item_tables(owner_def_id); + let tables = tcx.typeck_tables_of(owner_def_id); let mut cfg_builder = CFGBuilder { tcx: tcx, + owner_def_id, tables: tables, graph: graph, fn_exit: fn_exit, @@ -74,11 +77,11 @@ pub fn construct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { fn block(&mut self, blk: &hir::Block, pred: CFGIndex) -> CFGIndex { - if let Some(break_to_expr_id) = blk.break_to_expr_id { + if blk.targeted_by_break { let expr_exit = self.add_ast_node(blk.id, &[]); self.breakable_block_scopes.push(BlockScope { - block_expr_id: break_to_expr_id, + block_expr_id: blk.id, break_index: expr_exit, }); @@ -195,7 +198,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { // [..expr..] // let cond_exit = self.expr(&cond, pred); // 1 - let then_exit = self.block(&then, cond_exit); // 2 + let then_exit = self.expr(&then, cond_exit); // 2 self.add_ast_node(expr.id, &[cond_exit, then_exit]) // 3,4 } @@ -215,7 +218,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { // [..expr..] // let cond_exit = self.expr(&cond, pred); // 1 - let then_exit = self.block(&then, cond_exit); // 2 + let then_exit = self.expr(&then, cond_exit); // 2 let else_exit = self.expr(&otherwise, cond_exit); // 3 self.add_ast_node(expr.id, &[then_exit, else_exit]) // 4, 5 } @@ -583,11 +586,12 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { scope_id: ast::NodeId, to_index: CFGIndex) { let mut data = CFGEdgeData { exiting_scopes: vec![] }; - let mut scope = self.tcx.region_maps.node_extent(from_expr.id); - let target_scope = self.tcx.region_maps.node_extent(scope_id); + let mut scope = self.tcx.node_extent(from_expr.id); + let target_scope = self.tcx.node_extent(scope_id); + let region_maps = self.tcx.region_maps(self.owner_def_id); while scope != target_scope { - data.exiting_scopes.push(scope.node_id(&self.tcx.region_maps)); - scope = self.tcx.region_maps.encl_scope(scope); + data.exiting_scopes.push(scope.node_id()); + scope = region_maps.encl_scope(scope); } self.graph.add_edge(from_index, to_index, data); } diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 399af258e925..37b8a56d9166 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use hir::def_id::CrateNum; use std::fmt::Debug; use std::sync::Arc; @@ -55,35 +56,15 @@ pub enum DepNode { WorkProduct(Arc), // Represents different phases in the compiler. - CollectLanguageItems, - CheckStaticRecursion, - ResolveLifetimes, - RegionResolveCrate, - CheckLoops, - PluginRegistrar, - StabilityIndex, - CollectItem(D), - CollectItemSig(D), + RegionMaps(D), Coherence, - EffectCheck, - Liveness, Resolve, - EntryPoint, - CheckEntryFn, CoherenceCheckTrait(D), CoherenceCheckImpl(D), CoherenceOverlapCheck(D), CoherenceOverlapCheckSpecial(D), - CoherenceOverlapInherentCheck(D), - CoherenceOrphanCheck(D), Variance, - WfCheck(D), - TypeckItemType(D), - UnusedTraitCheck, - CheckConst(D), - Privacy, - IntrinsicCheck(D), - MatchCheck(D), + PrivacyAccessLevels(CrateNum), // Represents the MIR for a fn; also used as the task node for // things read/modify that MIR. @@ -95,14 +76,11 @@ pub enum DepNode { BorrowCheck(D), RvalueCheck(D), Reachability, - DeadCheck, - StabilityCheck(D), + MirKeys, LateLintCheck, - TransCrate, TransCrateItem(D), TransInlinedItem(D), TransWriteMetadata, - LinkBinary, // Nodes representing bits of computed IR in the tcx. Each shared // table in the tcx (or elsewhere) maps to one of these @@ -111,15 +89,18 @@ pub enum DepNode { // predicates for an item wind up in `ItemSignature`). AssociatedItems(D), ItemSignature(D), + IsForeignItem(D), TypeParamPredicates((D, D)), SizedConstraint(D), + DtorckConstraint(D), AdtDestructor(D), AssociatedItemDefIds(D), InherentImpls(D), TypeckBodiesKrate, TypeckTables(D), UsedTraitImports(D), - MonomorphicConstEval(D), + ConstEval(D), + SymbolName(D), // The set of impls for a given trait. Ultimately, it would be // nice to get more fine-grained here (e.g., to include a @@ -168,6 +149,11 @@ pub enum DepNode { // For proj. cache, we just keep a list of all def-ids, since it is // not a hotspot. ProjectionCache { def_ids: Vec }, + + DescribeDef(D), + DefSpan(D), + Stability(D), + Deprecation(D), } impl DepNode { @@ -188,14 +174,13 @@ impl DepNode { } check! { - CollectItem, BorrowCheck, Hir, HirBody, TransCrateItem, - TypeckItemType, AssociatedItems, ItemSignature, + IsForeignItem, AssociatedItemDefIds, InherentImpls, TypeckTables, @@ -215,28 +200,14 @@ impl DepNode { BorrowCheckKrate => Some(BorrowCheckKrate), MirKrate => Some(MirKrate), TypeckBodiesKrate => Some(TypeckBodiesKrate), - CollectLanguageItems => Some(CollectLanguageItems), - CheckStaticRecursion => Some(CheckStaticRecursion), - ResolveLifetimes => Some(ResolveLifetimes), - RegionResolveCrate => Some(RegionResolveCrate), - CheckLoops => Some(CheckLoops), - PluginRegistrar => Some(PluginRegistrar), - StabilityIndex => Some(StabilityIndex), Coherence => Some(Coherence), - EffectCheck => Some(EffectCheck), - Liveness => Some(Liveness), Resolve => Some(Resolve), - EntryPoint => Some(EntryPoint), - CheckEntryFn => Some(CheckEntryFn), Variance => Some(Variance), - UnusedTraitCheck => Some(UnusedTraitCheck), - Privacy => Some(Privacy), + PrivacyAccessLevels(k) => Some(PrivacyAccessLevels(k)), Reachability => Some(Reachability), - DeadCheck => Some(DeadCheck), + MirKeys => Some(MirKeys), LateLintCheck => Some(LateLintCheck), - TransCrate => Some(TransCrate), TransWriteMetadata => Some(TransWriteMetadata), - LinkBinary => Some(LinkBinary), // work product names do not need to be mapped, because // they are always absolute. @@ -245,41 +216,35 @@ impl DepNode { Hir(ref d) => op(d).map(Hir), HirBody(ref d) => op(d).map(HirBody), MetaData(ref d) => op(d).map(MetaData), - CollectItem(ref d) => op(d).map(CollectItem), - CollectItemSig(ref d) => op(d).map(CollectItemSig), CoherenceCheckTrait(ref d) => op(d).map(CoherenceCheckTrait), CoherenceCheckImpl(ref d) => op(d).map(CoherenceCheckImpl), CoherenceOverlapCheck(ref d) => op(d).map(CoherenceOverlapCheck), CoherenceOverlapCheckSpecial(ref d) => op(d).map(CoherenceOverlapCheckSpecial), - CoherenceOverlapInherentCheck(ref d) => op(d).map(CoherenceOverlapInherentCheck), - CoherenceOrphanCheck(ref d) => op(d).map(CoherenceOrphanCheck), - WfCheck(ref d) => op(d).map(WfCheck), - TypeckItemType(ref d) => op(d).map(TypeckItemType), - CheckConst(ref d) => op(d).map(CheckConst), - IntrinsicCheck(ref d) => op(d).map(IntrinsicCheck), - MatchCheck(ref d) => op(d).map(MatchCheck), Mir(ref d) => op(d).map(Mir), MirShim(ref def_ids) => { let def_ids: Option> = def_ids.iter().map(op).collect(); def_ids.map(MirShim) } BorrowCheck(ref d) => op(d).map(BorrowCheck), + RegionMaps(ref d) => op(d).map(RegionMaps), RvalueCheck(ref d) => op(d).map(RvalueCheck), - StabilityCheck(ref d) => op(d).map(StabilityCheck), TransCrateItem(ref d) => op(d).map(TransCrateItem), TransInlinedItem(ref d) => op(d).map(TransInlinedItem), AssociatedItems(ref d) => op(d).map(AssociatedItems), ItemSignature(ref d) => op(d).map(ItemSignature), + IsForeignItem(ref d) => op(d).map(IsForeignItem), TypeParamPredicates((ref item, ref param)) => { Some(TypeParamPredicates((try_opt!(op(item)), try_opt!(op(param))))) } SizedConstraint(ref d) => op(d).map(SizedConstraint), + DtorckConstraint(ref d) => op(d).map(DtorckConstraint), AdtDestructor(ref d) => op(d).map(AdtDestructor), AssociatedItemDefIds(ref d) => op(d).map(AssociatedItemDefIds), InherentImpls(ref d) => op(d).map(InherentImpls), TypeckTables(ref d) => op(d).map(TypeckTables), UsedTraitImports(ref d) => op(d).map(UsedTraitImports), - MonomorphicConstEval(ref d) => op(d).map(MonomorphicConstEval), + ConstEval(ref d) => op(d).map(ConstEval), + SymbolName(ref d) => op(d).map(SymbolName), TraitImpls(ref d) => op(d).map(TraitImpls), TraitItems(ref d) => op(d).map(TraitItems), ReprHints(ref d) => op(d).map(ReprHints), @@ -295,6 +260,10 @@ impl DepNode { let def_ids: Option> = def_ids.iter().map(op).collect(); def_ids.map(|d| ProjectionCache { def_ids: d }) } + DescribeDef(ref d) => op(d).map(DescribeDef), + DefSpan(ref d) => op(d).map(DefSpan), + Stability(ref d) => op(d).map(Stability), + Deprecation(ref d) => op(d).map(Deprecation), } } } diff --git a/src/librustc/dep_graph/dep_tracking_map.rs b/src/librustc/dep_graph/dep_tracking_map.rs index 0f3108df9a82..b6a2360211ca 100644 --- a/src/librustc/dep_graph/dep_tracking_map.rs +++ b/src/librustc/dep_graph/dep_tracking_map.rs @@ -81,21 +81,6 @@ impl DepTrackingMap { pub fn keys(&self) -> Vec { self.map.keys().cloned().collect() } - - /// Append `elem` to the vector stored for `k`, creating a new vector if needed. - /// This is considered a write to `k`. - /// - /// NOTE: Caution is required when using this method. You should - /// be sure that nobody is **reading from the vector** while you - /// are writing to it. Eventually, it'd be nice to remove this. - pub fn push(&mut self, k: M::Key, elem: E) - where M: DepTrackingMapConfig> - { - self.write(&k); - self.map.entry(k) - .or_insert(Vec::new()) - .push(elem); - } } impl MemoizationMap for RefCell> { diff --git a/src/librustc/dep_graph/edges.rs b/src/librustc/dep_graph/edges.rs index 8657a3e5a587..5dbabcc92304 100644 --- a/src/librustc/dep_graph/edges.rs +++ b/src/librustc/dep_graph/edges.rs @@ -101,11 +101,15 @@ impl DepGraphEdges { } /// Indicates that the current task `C` reads `v` by adding an - /// edge from `v` to `C`. If there is no current task, panics. If - /// you want to suppress this edge, use `ignore`. + /// edge from `v` to `C`. If there is no current task, has no + /// effect. Note that *reading* from tracked state is harmless if + /// you are not in a task; what is bad is *writing* to tracked + /// state (and leaking data that you read into a tracked task). pub fn read(&mut self, v: DepNode) { - let source = self.make_node(v); - self.add_edge_from_current_node(|current| (source, current)) + if self.current_node().is_some() { + let source = self.make_node(v); + self.add_edge_from_current_node(|current| (source, current)) + } } /// Indicates that the current task `C` writes `v` by adding an diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs index a9f0a44e4208..6cb86a30400a 100644 --- a/src/librustc/dep_graph/mod.rs +++ b/src/librustc/dep_graph/mod.rs @@ -28,6 +28,5 @@ pub use self::graph::WorkProduct; pub use self::query::DepGraphQuery; pub use self::safe::AssertDepGraphSafe; pub use self::safe::DepGraphSafe; -pub use self::visit::visit_all_bodies_in_krate; pub use self::visit::visit_all_item_likes_in_krate; pub use self::raii::DepTask; diff --git a/src/librustc/dep_graph/safe.rs b/src/librustc/dep_graph/safe.rs index f85f0338ed99..59dce6f6bb09 100644 --- a/src/librustc/dep_graph/safe.rs +++ b/src/librustc/dep_graph/safe.rs @@ -50,6 +50,12 @@ impl DepGraphSafe for (A, B) { } +/// Shared ref to dep-graph-safe stuff should still be dep-graph-safe. +impl<'a, A> DepGraphSafe for &'a A + where A: DepGraphSafe, +{ +} + /// No data here! :) impl DepGraphSafe for () { } diff --git a/src/librustc/dep_graph/shadow.rs b/src/librustc/dep_graph/shadow.rs index 5d4190a8ae1a..bedb6ff2771f 100644 --- a/src/librustc/dep_graph/shadow.rs +++ b/src/librustc/dep_graph/shadow.rs @@ -80,7 +80,13 @@ impl ShadowGraph { let mut stack = self.stack.borrow_mut(); match *message { - DepMessage::Read(ref n) => self.check_edge(Some(Some(n)), top(&stack)), + // It is ok to READ shared state outside of a + // task. That can't do any harm (at least, the only + // way it can do harm is by leaking that data into a + // query or task, which would be a problem + // anyway). What would be bad is WRITING to that + // state. + DepMessage::Read(_) => { } DepMessage::Write(ref n) => self.check_edge(top(&stack), Some(Some(n))), DepMessage::PushTask(ref n) => stack.push(Some(n.clone())), DepMessage::PushIgnore => stack.push(None), @@ -116,7 +122,7 @@ impl ShadowGraph { (None, None) => unreachable!(), // nothing on top of the stack - (None, Some(n)) | (Some(n), None) => bug!("read/write of {:?} but no current task", n), + (None, Some(n)) | (Some(n), None) => bug!("write of {:?} but no current task", n), // this corresponds to an Ignore being top of the stack (Some(None), _) | (_, Some(None)) => (), diff --git a/src/librustc/dep_graph/visit.rs b/src/librustc/dep_graph/visit.rs index 93f6e3a83a0c..bf3748659fe0 100644 --- a/src/librustc/dep_graph/visit.rs +++ b/src/librustc/dep_graph/visit.rs @@ -75,15 +75,3 @@ pub fn visit_all_item_likes_in_krate<'a, 'tcx, V, F>(tcx: TyCtxt<'a, 'tcx, 'tcx> krate.visit_all_item_likes(&mut tracking_visitor) } -pub fn visit_all_bodies_in_krate<'a, 'tcx, C>(tcx: TyCtxt<'a, 'tcx, 'tcx>, callback: C) - where C: Fn(/* body_owner */ - DefId, - /* body id */ - hir::BodyId) -{ - let krate = tcx.hir.krate(); - for &body_id in &krate.body_ids { - let body_owner_def_id = tcx.hir.body_owner_def_id(body_id); - callback(body_owner_def_id, body_id); - } -} diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 85b4ddcdd719..8ef42826faca 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -327,6 +327,25 @@ struct ListNode { This works because `Box` is a pointer, so its size is well-known. "##, +E0080: r##" +This error indicates that the compiler was unable to sensibly evaluate an +constant expression that had to be evaluated. Attempting to divide by 0 +or causing integer overflow are two ways to induce this error. For example: + +```compile_fail,E0080 +enum Enum { + X = (1 << 500), + Y = (1 / 0) +} +``` + +Ensure that the expressions given can be evaluated as the desired integer type. +See the FFI section of the Reference for more information about using a custom +integer type: + +https://doc.rust-lang.org/reference.html#ffi-attributes +"##, + E0106: r##" This error indicates that a lifetime is missing from a type. If it is an error inside a function signature, the problem may be with failing to adhere to the @@ -1030,18 +1049,19 @@ which expected that trait. This error typically occurs when working with `Fn`-based types. Erroneous code example: ```compile_fail,E0281 -fn foo(x: F) { } +fn foo(x: F) { } fn main() { - // type mismatch: the type ... implements the trait `core::ops::Fn<(_,)>`, - // but the trait `core::ops::Fn<()>` is required (expected (), found tuple + // type mismatch: ... implements the trait `core::ops::Fn<(String,)>`, + // but the trait `core::ops::Fn<(usize,)>` is required // [E0281] - foo(|y| { }); + foo(|y: String| { }); } ``` -The issue in this case is that `foo` is defined as accepting a `Fn` with no -arguments, but the closure we attempted to pass to it requires one argument. +The issue in this case is that `foo` is defined as accepting a `Fn` with one +argument of type `String`, but the closure we attempted to pass to it requires +one arguments of type `usize`. "##, E0282: r##" @@ -1336,7 +1356,7 @@ trait SecondTrait : FirstTrait { E0398: r##" In Rust 1.3, the default object lifetime bounds are expected to change, as -described in RFC #1156 [1]. You are getting a warning because the compiler +described in [RFC 1156]. You are getting a warning because the compiler thinks it is possible that this change will cause a compilation error in your code. It is possible, though unlikely, that this is a false alarm. @@ -1365,7 +1385,7 @@ fn foo<'a>(arg: &Box) { ... } This explicitly states that you expect the trait object `SomeTrait` to contain references (with a maximum lifetime of `'a`). -[1]: https://github.com/rust-lang/rfcs/pull/1156 +[RFC 1156]: https://github.com/rust-lang/rfcs/blob/master/text/1156-adjust-default-object-bounds.md "##, E0452: r##" @@ -1771,6 +1791,7 @@ This pattern is incorrect because, because the type of `foo` is a function **item** (`typeof(foo)`), which is zero-sized, and the target type (`fn()`) is a function pointer, which is not zero-sized. This pattern should be rewritten. There are a few possible ways to do this: + - change the original fn declaration to match the expected signature, and do the cast in the fn body (the prefered option) - cast the fn item fo a fn pointer before calling transmute, as shown here: @@ -1787,11 +1808,27 @@ makes a difference in practice.) [rfc401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md "##, +E0593: r##" +You tried to supply an `Fn`-based type with an incorrect number of arguments +than what was expected. Erroneous code example: + +```compile_fail,E0593 +fn foo(x: F) { } + +fn main() { + // [E0593] closure takes 1 argument but 0 arguments are required + foo(|y| { }); +} +``` +"##, + } register_diagnostics! { // E0006 // merged with E0005 +// E0101, // replaced with E0282 +// E0102, // replaced with E0282 // E0134, // E0135, E0278, // requirement is not satisfied @@ -1807,6 +1844,7 @@ register_diagnostics! { E0314, // closure outlives stack frame E0315, // cannot invoke closure outside of its lifetime E0316, // nested quantification of lifetimes + E0320, // recursive overflow during dropck E0473, // dereference of reference outside its lifetime E0474, // captured variable `..` does not outlive the enclosing closure E0475, // index of slice outside its lifetime @@ -1825,5 +1863,6 @@ register_diagnostics! { E0489, // type/lifetime parameter not in scope here E0490, // a value of type `..` is borrowed for too long E0495, // cannot infer an appropriate lifetime due to conflicting requirements - E0566 // conflicting representation hints + E0566, // conflicting representation hints + E0587, // conflicting packed and align representation hints } diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs index 54ae94721409..bf292ccb8d86 100644 --- a/src/librustc/hir/check_attr.rs +++ b/src/librustc/hir/check_attr.rs @@ -57,6 +57,9 @@ impl<'a> CheckAttrVisitor<'a> { }; let mut conflicting_reprs = 0; + let mut found_packed = false; + let mut found_align = false; + for word in words { let name = match word.name() { @@ -84,6 +87,7 @@ impl<'a> CheckAttrVisitor<'a> { ("attribute should be applied to struct or union", "a struct or union") } else { + found_packed = true; continue } } @@ -96,6 +100,15 @@ impl<'a> CheckAttrVisitor<'a> { continue } } + "align" => { + found_align = true; + if target != Target::Struct { + ("attribute should be applied to struct", + "a struct") + } else { + continue + } + } "i8" | "u8" | "i16" | "u16" | "i32" | "u32" | "i64" | "u64" | "isize" | "usize" => { @@ -117,6 +130,10 @@ impl<'a> CheckAttrVisitor<'a> { span_warn!(self.sess, attr.span, E0566, "conflicting representation hints"); } + if found_align && found_packed { + struct_span_err!(self.sess, attr.span, E0587, + "conflicting packed and align representation hints").emit(); + } } fn check_attribute(&self, attr: &ast::Attribute, target: Target) { diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs index 7bab4a8d725d..771031db0c04 100644 --- a/src/librustc/hir/def.rs +++ b/src/librustc/hir/def.rs @@ -57,6 +57,8 @@ pub enum Def { // Macro namespace Macro(DefId, MacroKind), + GlobalAsm(DefId), + // Both namespaces Err, } @@ -144,7 +146,8 @@ impl Def { Def::Variant(id) | Def::VariantCtor(id, ..) | Def::Enum(id) | Def::TyAlias(id) | Def::AssociatedTy(id) | Def::TyParam(id) | Def::Struct(id) | Def::StructCtor(id, ..) | Def::Union(id) | Def::Trait(id) | Def::Method(id) | Def::Const(id) | - Def::AssociatedConst(id) | Def::Local(id) | Def::Upvar(id, ..) | Def::Macro(id, ..) => { + Def::AssociatedConst(id) | Def::Local(id) | Def::Upvar(id, ..) | Def::Macro(id, ..) | + Def::GlobalAsm(id) => { id } @@ -185,6 +188,7 @@ impl Def { Def::Label(..) => "label", Def::SelfTy(..) => "self type", Def::Macro(..) => "macro", + Def::GlobalAsm(..) => "global asm", Def::Err => "unresolved item", } } diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index f59b8b757f5c..3e610dd3c0d8 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -39,7 +39,7 @@ use syntax::codemap::Spanned; use syntax_pos::Span; use hir::*; use hir::def::Def; -use hir::map::Map; +use hir::map::{self, Map}; use super::itemlikevisit::DeepVisitor; use std::cmp; @@ -140,6 +140,23 @@ impl<'this, 'tcx> NestedVisitorMap<'this, 'tcx> { /// to monitor future changes to `Visitor` in case a new method with a /// new default implementation gets introduced.) pub trait Visitor<'v> : Sized { + /// Invokes the suitable visitor method for the given `Node` + /// extracted from the hir map. + fn visit_hir_map_node(&mut self, node: map::Node<'v>) { + match node { + map::NodeItem(a) => self.visit_item(a), + map::NodeForeignItem(a) => self.visit_foreign_item(a), + map::NodeTraitItem(a) => self.visit_trait_item(a), + map::NodeImplItem(a) => self.visit_impl_item(a), + map::NodeExpr(a) => self.visit_expr(a), + map::NodeStmt(a) => self.visit_stmt(a), + map::NodeTy(a) => self.visit_ty(a), + map::NodePat(a) => self.visit_pat(a), + map::NodeBlock(a) => self.visit_block(a), + _ => bug!("Visitor::visit_hir_map_node() not yet impl for node `{:?}`", node) + } + } + /////////////////////////////////////////////////////////////////////////// // Nested items. @@ -474,6 +491,9 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { visitor.visit_id(item.id); walk_list!(visitor, visit_foreign_item, &foreign_module.items); } + ItemGlobalAsm(_) => { + visitor.visit_id(item.id); + } ItemTy(ref typ, ref type_parameters) => { visitor.visit_id(item.id); visitor.visit_ty(typ); @@ -578,7 +598,7 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) { TyTypeof(expression) => { visitor.visit_nested_body(expression) } - TyInfer => {} + TyInfer | TyErr => {} } } @@ -960,7 +980,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { } ExprIf(ref head_expression, ref if_block, ref optional_else) => { visitor.visit_expr(head_expression); - visitor.visit_block(if_block); + visitor.visit_expr(if_block); walk_list!(visitor, visit_expr, optional_else); } ExprWhile(ref subexpression, ref block, ref opt_sp_name) => { diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 2ac1a036f99e..8f4dce5a7830 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -57,6 +57,7 @@ use std::mem; use syntax::attr; use syntax::ast::*; use syntax::errors; +use syntax::ext::hygiene::{Mark, SyntaxContext}; use syntax::ptr::P; use syntax::codemap::{self, respan, Spanned}; use syntax::std_inject; @@ -392,7 +393,8 @@ impl<'a> LoweringContext<'a> { } fn allow_internal_unstable(&self, reason: &'static str, mut span: Span) -> Span { - span.expn_id = self.sess.codemap().record_expansion(codemap::ExpnInfo { + let mark = Mark::fresh(); + mark.set_expn_info(codemap::ExpnInfo { call_site: span, callee: codemap::NameAndSpan { format: codemap::CompilerDesugaring(Symbol::intern(reason)), @@ -400,6 +402,7 @@ impl<'a> LoweringContext<'a> { allow_internal_unstable: true, }, }); + span.ctxt = SyntaxContext::empty().apply_mark(mark); span } @@ -552,6 +555,7 @@ impl<'a> LoweringContext<'a> { fn lower_ty(&mut self, t: &Ty) -> P { let kind = match t.node { TyKind::Infer => hir::TyInfer, + TyKind::Err => hir::TyErr, TyKind::Slice(ref ty) => hir::TySlice(self.lower_ty(ty)), TyKind::Ptr(ref mt) => hir::TyPtr(self.lower_mt(mt)), TyKind::Rptr(ref region, ref mt) => { @@ -642,6 +646,13 @@ impl<'a> LoweringContext<'a> { } } + fn lower_global_asm(&mut self, ga: &GlobalAsm) -> P { + P(hir::GlobalAsm { + asm: ga.asm, + ctxt: ga.ctxt, + }) + } + fn lower_variant(&mut self, v: &Variant) -> hir::Variant { Spanned { node: hir::Variant_ { @@ -907,6 +918,13 @@ impl<'a> LoweringContext<'a> { FunctionRetTy::Default(span) => hir::DefaultReturn(span), }, variadic: decl.variadic, + has_implicit_self: decl.inputs.get(0).map_or(false, |arg| { + match arg.ty.node { + TyKind::ImplicitSelf => true, + TyKind::Rptr(_, ref mt) => mt.ty.node == TyKind::ImplicitSelf, + _ => false + } + }) }) } @@ -1146,7 +1164,7 @@ impl<'a> LoweringContext<'a> { bounds.iter().map(|bound| self.lower_ty_param_bound(bound)).collect() } - fn lower_block(&mut self, b: &Block, break_to: Option) -> P { + fn lower_block(&mut self, b: &Block, targeted_by_break: bool) -> P { let mut expr = None; let mut stmts = vec![]; @@ -1169,7 +1187,7 @@ impl<'a> LoweringContext<'a> { expr: expr, rules: self.lower_block_check_mode(&b.rules), span: b.span, - break_to_expr_id: break_to, + targeted_by_break: targeted_by_break, }) } @@ -1264,7 +1282,7 @@ impl<'a> LoweringContext<'a> { } ItemKind::Fn(ref decl, unsafety, constness, abi, ref generics, ref body) => { self.with_new_scopes(|this| { - let body = this.lower_block(body, None); + let body = this.lower_block(body, false); let body = this.expr_block(body, ThinVec::new()); let body_id = this.record_body(body, Some(decl)); hir::ItemFn(this.lower_fn_decl(decl), @@ -1277,6 +1295,7 @@ impl<'a> LoweringContext<'a> { } ItemKind::Mod(ref m) => hir::ItemMod(self.lower_mod(m)), ItemKind::ForeignMod(ref nm) => hir::ItemForeignMod(self.lower_foreign_mod(nm)), + ItemKind::GlobalAsm(ref ga) => hir::ItemGlobalAsm(self.lower_global_asm(ga)), ItemKind::Ty(ref t, ref generics) => { hir::ItemTy(self.lower_ty(t), self.lower_generics(generics)) } @@ -1307,7 +1326,13 @@ impl<'a> LoweringContext<'a> { hir::ItemDefaultImpl(self.lower_unsafety(unsafety), trait_ref) } - ItemKind::Impl(unsafety, polarity, ref generics, ref ifce, ref ty, ref impl_items) => { + ItemKind::Impl(unsafety, + polarity, + defaultness, + ref generics, + ref ifce, + ref ty, + ref impl_items) => { let new_impl_items = impl_items.iter() .map(|item| self.lower_impl_item_ref(item)) .collect(); @@ -1321,6 +1346,7 @@ impl<'a> LoweringContext<'a> { hir::ItemImpl(self.lower_unsafety(unsafety), self.lower_impl_polarity(polarity), + self.lower_defaultness(defaultness, true /* [1] */), self.lower_generics(generics), ifce, self.lower_ty(ty), @@ -1336,6 +1362,9 @@ impl<'a> LoweringContext<'a> { } ItemKind::MacroDef(..) | ItemKind::Mac(..) => panic!("Shouldn't still be around"), } + + // [1] `defaultness.has_value()` is never called for an `impl`, always `true` in order to + // not cause an assertion failure inside the `lower_defaultness` function } fn lower_trait_item(&mut self, i: &TraitItem) -> hir::TraitItem { @@ -1358,7 +1387,7 @@ impl<'a> LoweringContext<'a> { hir::TraitMethod::Required(names)) } TraitItemKind::Method(ref sig, Some(ref body)) => { - let body = this.lower_block(body, None); + let body = this.lower_block(body, false); let expr = this.expr_block(body, ThinVec::new()); let body_id = this.record_body(expr, Some(&sig.decl)); hir::TraitItemKind::Method(this.lower_method_sig(sig), @@ -1414,7 +1443,7 @@ impl<'a> LoweringContext<'a> { hir::ImplItemKind::Const(this.lower_ty(ty), body_id) } ImplItemKind::Method(ref sig, ref body) => { - let body = this.lower_block(body, None); + let body = this.lower_block(body, false); let expr = this.expr_block(body, ThinVec::new()); let body_id = this.record_body(expr, Some(&sig.decl)); hir::ImplItemKind::Method(this.lower_method_sig(sig), body_id) @@ -1838,7 +1867,7 @@ impl<'a> LoweringContext<'a> { id: id, rules: hir::DefaultBlock, span: span, - break_to_expr_id: None, + targeted_by_break: false, }); P(self.expr_block(blk, ThinVec::new())) } @@ -1846,24 +1875,27 @@ impl<'a> LoweringContext<'a> { } }); - hir::ExprIf(P(self.lower_expr(cond)), self.lower_block(blk, None), else_opt) + let then_blk = self.lower_block(blk, false); + let then_expr = self.expr_block(then_blk, ThinVec::new()); + + hir::ExprIf(P(self.lower_expr(cond)), P(then_expr), else_opt) } ExprKind::While(ref cond, ref body, opt_ident) => { self.with_loop_scope(e.id, |this| hir::ExprWhile( this.with_loop_condition_scope(|this| P(this.lower_expr(cond))), - this.lower_block(body, None), + this.lower_block(body, false), this.lower_opt_sp_ident(opt_ident))) } ExprKind::Loop(ref body, opt_ident) => { self.with_loop_scope(e.id, |this| - hir::ExprLoop(this.lower_block(body, None), + hir::ExprLoop(this.lower_block(body, false), this.lower_opt_sp_ident(opt_ident), hir::LoopSource::Loop)) } ExprKind::Catch(ref body) => { - self.with_catch_scope(e.id, |this| - hir::ExprBlock(this.lower_block(body, Some(e.id)))) + self.with_catch_scope(body.id, |this| + hir::ExprBlock(this.lower_block(body, true))) } ExprKind::Match(ref expr, ref arms) => { hir::ExprMatch(P(self.lower_expr(expr)), @@ -1881,7 +1913,7 @@ impl<'a> LoweringContext<'a> { }) }) } - ExprKind::Block(ref blk) => hir::ExprBlock(self.lower_block(blk, None)), + ExprKind::Block(ref blk) => hir::ExprBlock(self.lower_block(blk, false)), ExprKind::Assign(ref el, ref er) => { hir::ExprAssign(P(self.lower_expr(el)), P(self.lower_expr(er))) } @@ -1900,57 +1932,45 @@ impl<'a> LoweringContext<'a> { hir::ExprIndex(P(self.lower_expr(el)), P(self.lower_expr(er))) } ExprKind::Range(ref e1, ref e2, lims) => { - fn make_struct(this: &mut LoweringContext, - ast_expr: &Expr, - path: &[&str], - fields: &[(&str, &P)]) -> hir::Expr { - let struct_path = &iter::once(&"ops").chain(path).map(|s| *s) - .collect::>(); - let unstable_span = this.allow_internal_unstable("...", ast_expr.span); - - if fields.len() == 0 { - this.expr_std_path(unstable_span, struct_path, - ast_expr.attrs.clone()) - } else { - let fields = fields.into_iter().map(|&(s, e)| { - let expr = P(this.lower_expr(&e)); - let unstable_span = this.allow_internal_unstable("...", e.span); - this.field(Symbol::intern(s), expr, unstable_span) - }).collect(); - let attrs = ast_expr.attrs.clone(); - - this.expr_std_struct(unstable_span, struct_path, fields, None, attrs) - } - } - use syntax::ast::RangeLimits::*; - return match (e1, e2, lims) { - (&None, &None, HalfOpen) => - make_struct(self, e, &["RangeFull"], &[]), + let (path, variant) = match (e1, e2, lims) { + (&None, &None, HalfOpen) => ("RangeFull", None), + (&Some(..), &None, HalfOpen) => ("RangeFrom", None), + (&None, &Some(..), HalfOpen) => ("RangeTo", None), + (&Some(..), &Some(..), HalfOpen) => ("Range", None), + (&None, &Some(..), Closed) => ("RangeToInclusive", None), + (&Some(..), &Some(..), Closed) => ("RangeInclusive", Some("NonEmpty")), + (_, &None, Closed) => + panic!(self.diagnostic().span_fatal( + e.span, "inclusive range with no end")), + }; - (&Some(ref e1), &None, HalfOpen) => - make_struct(self, e, &["RangeFrom"], - &[("start", e1)]), + let fields = + e1.iter().map(|e| ("start", e)).chain(e2.iter().map(|e| ("end", e))) + .map(|(s, e)| { + let expr = P(self.lower_expr(&e)); + let unstable_span = self.allow_internal_unstable("...", e.span); + self.field(Symbol::intern(s), expr, unstable_span) + }).collect::>(); - (&None, &Some(ref e2), HalfOpen) => - make_struct(self, e, &["RangeTo"], - &[("end", e2)]), + let is_unit = fields.is_empty(); + let unstable_span = self.allow_internal_unstable("...", e.span); + let struct_path = + iter::once("ops").chain(iter::once(path)).chain(variant) + .collect::>(); + let struct_path = self.std_path(unstable_span, &struct_path, is_unit); + let struct_path = hir::QPath::Resolved(None, P(struct_path)); - (&Some(ref e1), &Some(ref e2), HalfOpen) => - make_struct(self, e, &["Range"], - &[("start", e1), ("end", e2)]), - - (&None, &Some(ref e2), Closed) => - make_struct(self, e, &["RangeToInclusive"], - &[("end", e2)]), - - (&Some(ref e1), &Some(ref e2), Closed) => - make_struct(self, e, &["RangeInclusive", "NonEmpty"], - &[("start", e1), ("end", e2)]), - - _ => panic!(self.diagnostic() - .span_fatal(e.span, "inclusive range with no end")), + return hir::Expr { + id: self.lower_node_id(e.id), + node: if is_unit { + hir::ExprPath(struct_path) + } else { + hir::ExprStruct(struct_path, fields, None) + }, + span: unstable_span, + attrs: e.attrs.clone(), }; } ExprKind::Path(ref qself, ref path) => { @@ -1998,7 +2018,7 @@ impl<'a> LoweringContext<'a> { volatile: asm.volatile, alignstack: asm.alignstack, dialect: asm.dialect, - expn_id: asm.expn_id, + ctxt: asm.ctxt, }; let outputs = asm.outputs.iter().map(|out| self.lower_expr(&out.expr)).collect(); @@ -2031,7 +2051,6 @@ impl<'a> LoweringContext<'a> { // // match { // => , - // [_ if => ,] // _ => [ | ()] // } @@ -2039,99 +2058,22 @@ impl<'a> LoweringContext<'a> { // ` => ` { - let body = self.lower_block(body, None); + let body = self.lower_block(body, false); let body_expr = P(self.expr_block(body, ThinVec::new())); let pat = self.lower_pat(pat); arms.push(self.arm(hir_vec![pat], body_expr)); } - // `[_ if => ,]` - // `_ => [ | ()]` + // _ => [|()] { - let mut current: Option<&Expr> = else_opt.as_ref().map(|p| &**p); - let mut else_exprs: Vec> = vec![current]; - - // First, we traverse the AST and recursively collect all - // `else` branches into else_exprs, e.g.: - // - // if let Some(_) = x { - // ... - // } else if ... { // Expr1 - // ... - // } else if ... { // Expr2 - // ... - // } else { // Expr3 - // ... - // } - // - // ... results in else_exprs = [Some(&Expr1), - // Some(&Expr2), - // Some(&Expr3)] - // - // Because there also the case there is no `else`, these - // entries can also be `None`, as in: - // - // if let Some(_) = x { - // ... - // } else if ... { // Expr1 - // ... - // } else if ... { // Expr2 - // ... - // } - // - // ... results in else_exprs = [Some(&Expr1), - // Some(&Expr2), - // None] - // - // The last entry in this list is always translated into - // the final "unguard" wildcard arm of the `match`. In the - // case of a `None`, it becomes `_ => ()`. - loop { - if let Some(e) = current { - // There is an else branch at this level - if let ExprKind::If(_, _, ref else_opt) = e.node { - // The else branch is again an if-expr - current = else_opt.as_ref().map(|p| &**p); - else_exprs.push(current); - } else { - // The last item in the list is not an if-expr, - // stop here - break - } - } else { - // We have no more else branch - break - } - } - - // Now translate the list of nested else-branches into the - // arms of the match statement. - for else_expr in else_exprs { - if let Some(else_expr) = else_expr { - let (guard, body) = if let ExprKind::If(ref cond, - ref then, - _) = else_expr.node { - let then = self.lower_block(then, None); - (Some(cond), - self.expr_block(then, ThinVec::new())) - } else { - (None, - self.lower_expr(else_expr)) - }; - - arms.push(hir::Arm { - attrs: hir_vec![], - pats: hir_vec![self.pat_wild(e.span)], - guard: guard.map(|e| P(self.lower_expr(e))), - body: P(body), - }); - } else { - // There was no else-branch, push a noop - let pat_under = self.pat_wild(e.span); - let unit = self.expr_tuple(e.span, hir_vec![]); - arms.push(self.arm(hir_vec![pat_under], unit)); - } - } + let wildcard_arm: Option<&Expr> = else_opt.as_ref().map(|p| &**p); + let wildcard_pattern = self.pat_wild(e.span); + let body = if let Some(else_expr) = wildcard_arm { + P(self.lower_expr(else_expr)) + } else { + self.expr_tuple(e.span, hir_vec![]) + }; + arms.push(self.arm(hir_vec![wildcard_pattern], body)); } let contains_else_clause = else_opt.is_some(); @@ -2161,7 +2103,7 @@ impl<'a> LoweringContext<'a> { // Note that the block AND the condition are evaluated in the loop scope. // This is done to allow `break` from inside the condition of the loop. let (body, break_expr, sub_expr) = self.with_loop_scope(e.id, |this| ( - this.lower_block(body, None), + this.lower_block(body, false), this.expr_break(e.span, ThinVec::new()), this.with_loop_condition_scope(|this| P(this.lower_expr(sub_expr))), )); @@ -2222,7 +2164,7 @@ impl<'a> LoweringContext<'a> { // `::std::option::Option::Some() => ` let pat_arm = { let body_block = self.with_loop_scope(e.id, - |this| this.lower_block(body, None)); + |this| this.lower_block(body, false)); let body_expr = P(self.expr_block(body_block, ThinVec::new())); let pat = self.lower_pat(pat); let some_pat = self.pat_some(e.span, pat); @@ -2613,17 +2555,6 @@ impl<'a> LoweringContext<'a> { P(self.expr(sp, hir::ExprTup(exprs), ThinVec::new())) } - fn expr_std_struct(&mut self, - span: Span, - components: &[&str], - fields: hir::HirVec, - e: Option>, - attrs: ThinVec) -> hir::Expr { - let path = self.std_path(span, components, false); - let qpath = hir::QPath::Resolved(None, P(path)); - self.expr(span, hir::ExprStruct(qpath, fields, e), attrs) - } - fn expr(&mut self, span: Span, node: hir::Expr_, attrs: ThinVec) -> hir::Expr { hir::Expr { id: self.next_id(), @@ -2665,7 +2596,7 @@ impl<'a> LoweringContext<'a> { id: self.next_id(), rules: hir::DefaultBlock, span: span, - break_to_expr_id: None, + targeted_by_break: false, } } @@ -2707,7 +2638,7 @@ impl<'a> LoweringContext<'a> { fn pat_ident_binding_mode(&mut self, span: Span, name: Name, bm: hir::BindingMode) -> P { let id = self.next_id(); - let parent_def = self.parent_def; + let parent_def = self.parent_def.unwrap(); let def_id = { let defs = self.resolver.definitions(); let def_path_data = DefPathData::Binding(name.as_str()); @@ -2773,7 +2704,7 @@ impl<'a> LoweringContext<'a> { id: id, stmts: stmts, expr: Some(expr), - break_to_expr_id: None, + targeted_by_break: false, }); self.expr_block(block, attrs) } diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index cae358a303e0..7ff5152c71a2 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -40,11 +40,9 @@ impl<'a> DefCollector<'a> { } } - pub fn collect_root(&mut self) { - let root = self.create_def_with_parent(None, - CRATE_NODE_ID, - DefPathData::CrateRoot, - ITEM_LIKE_SPACE); + pub fn collect_root(&mut self, crate_name: &str, crate_disambiguator: &str) { + let root = self.definitions.create_root_def(crate_name, + crate_disambiguator); assert_eq!(root, CRATE_DEF_INDEX); self.parent_def = Some(root); } @@ -54,20 +52,11 @@ impl<'a> DefCollector<'a> { data: DefPathData, address_space: DefIndexAddressSpace) -> DefIndex { - let parent_def = self.parent_def; + let parent_def = self.parent_def.unwrap(); debug!("create_def(node_id={:?}, data={:?}, parent_def={:?})", node_id, data, parent_def); self.definitions.create_def_with_parent(parent_def, node_id, data, address_space) } - fn create_def_with_parent(&mut self, - parent: Option, - node_id: NodeId, - data: DefPathData, - address_space: DefIndexAddressSpace) - -> DefIndex { - self.definitions.create_def_with_parent(parent, node_id, data, address_space) - } - pub fn with_parent(&mut self, parent_def: DefIndex, f: F) { let parent = self.parent_def; self.parent_def = Some(parent_def); @@ -92,7 +81,7 @@ impl<'a> DefCollector<'a> { fn visit_macro_invoc(&mut self, id: NodeId, const_expr: bool) { if let Some(ref mut visit) = self.visit_macro_invoc { visit(MacroInvocationData { - mark: Mark::from_placeholder_id(id), + mark: id.placeholder_to_mark(), const_expr: const_expr, def_index: self.parent_def.unwrap(), }) @@ -120,6 +109,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { DefPathData::ValueNs(i.ident.name.as_str()), ItemKind::MacroDef(..) => DefPathData::MacroDef(i.ident.name.as_str()), ItemKind::Mac(..) => return self.visit_macro_invoc(i.id, false), + ItemKind::GlobalAsm(..) => DefPathData::Misc, ItemKind::Use(ref view_path) => { match view_path.node { ViewPathGlob(..) => {} diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs index 809d5db3071d..6118df2ddfc8 100644 --- a/src/librustc/hir/map/definitions.rs +++ b/src/librustc/hir/map/definitions.rs @@ -21,7 +21,7 @@ use rustc_data_structures::indexed_vec::IndexVec; use rustc_data_structures::stable_hasher::StableHasher; use serialize::{Encodable, Decodable, Encoder, Decoder}; use std::fmt::Write; -use std::hash::{Hash, Hasher}; +use std::hash::Hash; use syntax::ast; use syntax::symbol::{Symbol, InternedString}; use ty::TyCtxt; @@ -34,6 +34,7 @@ use util::nodemap::NodeMap; pub struct DefPathTable { index_to_key: [Vec; 2], key_to_index: FxHashMap, + def_path_hashes: [Vec; 2], } // Unfortunately we have to provide a manual impl of Clone because of the @@ -44,6 +45,8 @@ impl Clone for DefPathTable { index_to_key: [self.index_to_key[0].clone(), self.index_to_key[1].clone()], key_to_index: self.key_to_index.clone(), + def_path_hashes: [self.def_path_hashes[0].clone(), + self.def_path_hashes[1].clone()], } } } @@ -52,6 +55,7 @@ impl DefPathTable { fn allocate(&mut self, key: DefKey, + def_path_hash: u64, address_space: DefIndexAddressSpace) -> DefIndex { let index = { @@ -62,6 +66,9 @@ impl DefPathTable { index }; self.key_to_index.insert(key, index); + self.def_path_hashes[address_space.index()].push(def_path_hash); + debug_assert!(self.def_path_hashes[address_space.index()].len() == + self.index_to_key[address_space.index()].len()); index } @@ -71,6 +78,12 @@ impl DefPathTable { [index.as_array_index()].clone() } + #[inline(always)] + pub fn def_path_hash(&self, index: DefIndex) -> u64 { + self.def_path_hashes[index.address_space().index()] + [index.as_array_index()] + } + #[inline(always)] pub fn def_index_for_def_key(&self, key: &DefKey) -> Option { self.key_to_index.get(key).cloned() @@ -116,17 +129,28 @@ impl DefPathTable { impl Encodable for DefPathTable { fn encode(&self, s: &mut S) -> Result<(), S::Error> { + // Index to key self.index_to_key[DefIndexAddressSpace::Low.index()].encode(s)?; - self.index_to_key[DefIndexAddressSpace::High.index()].encode(s) + self.index_to_key[DefIndexAddressSpace::High.index()].encode(s)?; + + // DefPath hashes + self.def_path_hashes[DefIndexAddressSpace::Low.index()].encode(s)?; + self.def_path_hashes[DefIndexAddressSpace::High.index()].encode(s)?; + + Ok(()) } } impl Decodable for DefPathTable { fn decode(d: &mut D) -> Result { let index_to_key_lo: Vec = Decodable::decode(d)?; - let index_to_key_high: Vec = Decodable::decode(d)?; + let index_to_key_hi: Vec = Decodable::decode(d)?; - let index_to_key = [index_to_key_lo, index_to_key_high]; + let def_path_hashes_lo: Vec = Decodable::decode(d)?; + let def_path_hashes_hi: Vec = Decodable::decode(d)?; + + let index_to_key = [index_to_key_lo, index_to_key_hi]; + let def_path_hashes = [def_path_hashes_lo, def_path_hashes_hi]; let mut key_to_index = FxHashMap(); @@ -141,6 +165,7 @@ impl Decodable for DefPathTable { Ok(DefPathTable { index_to_key: index_to_key, key_to_index: key_to_index, + def_path_hashes: def_path_hashes, }) } } @@ -184,6 +209,29 @@ pub struct DefKey { pub disambiguated_data: DisambiguatedDefPathData, } +impl DefKey { + fn compute_stable_hash(&self, parent_hash: u64) -> u64 { + let mut hasher = StableHasher::new(); + + // We hash a 0u8 here to disambiguate between regular DefPath hashes, + // and the special "root_parent" below. + 0u8.hash(&mut hasher); + parent_hash.hash(&mut hasher); + self.disambiguated_data.hash(&mut hasher); + hasher.finish() + } + + fn root_parent_stable_hash(crate_name: &str, crate_disambiguator: &str) -> u64 { + let mut hasher = StableHasher::new(); + // Disambiguate this from a regular DefPath hash, + // see compute_stable_hash() above. + 1u8.hash(&mut hasher); + crate_name.hash(&mut hasher); + crate_disambiguator.hash(&mut hasher); + hasher.finish() + } +} + /// 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 @@ -271,19 +319,6 @@ impl DefPath { s } - - pub fn deterministic_hash(&self, tcx: TyCtxt) -> u64 { - debug!("deterministic_hash({:?})", self); - let mut state = StableHasher::new(); - self.deterministic_hash_to(tcx, &mut state); - state.finish() - } - - pub fn deterministic_hash_to(&self, tcx: TyCtxt, state: &mut H) { - tcx.original_crate_name(self.krate).as_str().hash(state); - tcx.crate_disambiguator(self.krate).as_str().hash(state); - self.data.hash(state); - } } #[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] @@ -338,6 +373,7 @@ impl Definitions { table: DefPathTable { index_to_key: [vec![], vec![]], key_to_index: FxHashMap(), + def_path_hashes: [vec![], vec![]], }, node_to_def_index: NodeMap(), def_index_to_node: [vec![], vec![]], @@ -359,6 +395,11 @@ impl Definitions { self.table.def_key(index) } + #[inline(always)] + pub fn def_path_hash(&self, index: DefIndex) -> u64 { + self.table.def_path_hash(index) + } + pub fn def_index_for_def_key(&self, key: DefKey) -> Option { self.table.def_index_for_def_key(&key) } @@ -394,12 +435,42 @@ impl Definitions { } } + pub fn node_to_hir_id(&self, node_id: ast::NodeId) -> hir::HirId { + self.node_to_hir_id[node_id] + } + + /// Add a definition with a parent definition. + pub fn create_root_def(&mut self, + crate_name: &str, + crate_disambiguator: &str) + -> DefIndex { + let key = DefKey { + parent: None, + disambiguated_data: DisambiguatedDefPathData { + data: DefPathData::CrateRoot, + disambiguator: 0 + } + }; + + let parent_hash = DefKey::root_parent_stable_hash(crate_name, + crate_disambiguator); + let def_path_hash = key.compute_stable_hash(parent_hash); + + // Create the definition. + let address_space = super::ITEM_LIKE_SPACE; + let index = self.table.allocate(key, def_path_hash, address_space); + assert!(self.def_index_to_node[address_space.index()].is_empty()); + self.def_index_to_node[address_space.index()].push(ast::CRATE_NODE_ID); + self.node_to_def_index.insert(ast::CRATE_NODE_ID, index); + + index + } + /// Add a definition with a parent definition. pub fn create_def_with_parent(&mut self, - parent: Option, + parent: DefIndex, node_id: ast::NodeId, data: DefPathData, - // is_owner: bool) address_space: DefIndexAddressSpace) -> DefIndex { debug!("create_def_with_parent(parent={:?}, node_id={:?}, data={:?})", @@ -411,12 +482,13 @@ impl Definitions { data, self.table.def_key(self.node_to_def_index[&node_id])); - assert_eq!(parent.is_some(), data != DefPathData::CrateRoot); + // The root node must be created with create_root_def() + assert!(data != DefPathData::CrateRoot); // Find a unique DefKey. This basically means incrementing the disambiguator // until we get no match. let mut key = DefKey { - parent: parent, + parent: Some(parent), disambiguated_data: DisambiguatedDefPathData { data: data, disambiguator: 0 @@ -427,10 +499,13 @@ impl Definitions { key.disambiguated_data.disambiguator += 1; } + let parent_hash = self.table.def_path_hash(parent); + let def_path_hash = key.compute_stable_hash(parent_hash); + debug!("create_def_with_parent: after disambiguation, key = {:?}", key); // Create the definition. - let index = self.table.allocate(key, address_space); + let index = self.table.allocate(key, def_path_hash, address_space); assert_eq!(index.as_array_index(), self.def_index_to_node[address_space.index()].len()); self.def_index_to_node[address_space.index()].push(node_id); diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 583b3b848f30..abc967dec905 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -442,6 +442,27 @@ impl<'hir> Map<'hir> { self.local_def_id(self.body_owner(id)) } + /// Given a body owner's id, returns the `BodyId` associated with it. + pub fn body_owned_by(&self, id: NodeId) -> BodyId { + if let Some(entry) = self.find_entry(id) { + if let Some(body_id) = entry.associated_body() { + // For item-like things and closures, the associated + // body has its own distinct id, and that is returned + // by `associated_body`. + body_id + } else { + // For some expressions, the expression is its own body. + if let EntryExpr(_, expr) = entry { + BodyId { node_id: expr.id } + } else { + span_bug!(self.span(id), "id `{}` has no associated body: {:?}", id, entry); + } + } + } else { + bug!("no entry for id `{}`", id) + } + } + pub fn ty_param_owner(&self, id: NodeId) -> NodeId { match self.get(id) { NodeItem(&Item { node: ItemTrait(..), .. }) => id, @@ -948,7 +969,7 @@ pub fn map_crate<'hir>(forest: &'hir mut Forest, intravisit::walk_crate(&mut collector, &forest.krate); let map = collector.map; - if log_enabled!(::log::DEBUG) { + if log_enabled!(::log::LogLevel::Debug) { // This only makes sense for ordered stores; note the // enumerate to count the number of entries. let (entries_less_1, _) = map.iter().filter(|&x| { @@ -1056,6 +1077,7 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String { ItemFn(..) => "fn", ItemMod(..) => "mod", ItemForeignMod(..) => "foreign mod", + ItemGlobalAsm(..) => "global asm", ItemTy(..) => "ty", ItemEnum(..) => "enum", ItemStruct(..) => "struct", diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 1c79a02d3da0..cb7f530b9952 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -33,11 +33,12 @@ use hir::def::Def; use hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX}; use util::nodemap::{NodeMap, FxHashSet}; -use syntax_pos::{Span, ExpnId, DUMMY_SP}; +use syntax_pos::{Span, DUMMY_SP}; use syntax::codemap::{self, Spanned}; use syntax::abi::Abi; use syntax::ast::{Ident, Name, NodeId, DUMMY_NODE_ID, AsmDialect}; use syntax::ast::{Attribute, Lit, StrStyle, FloatTy, IntTy, UintTy, MetaItem}; +use syntax::ext::hygiene::SyntaxContext; use syntax::ptr::P; use syntax::symbol::{Symbol, keywords}; use syntax::tokenstream::TokenStream; @@ -159,6 +160,10 @@ impl Lifetime { pub fn is_elided(&self) -> bool { self.name == keywords::Invalid.name() } + + pub fn is_static(&self) -> bool { + self.name == keywords::StaticLifetime.name() + } } /// A lifetime definition, eg `'a: 'b+'c+'d` @@ -544,9 +549,11 @@ pub struct Block { /// Distinguishes between `unsafe { ... }` and `{ ... }` pub rules: BlockCheckMode, pub span: Span, - /// The id of the expression that `break` breaks to if the block can be broken out of. - /// Currently only `Some(_)` for `catch {}` blocks - pub break_to_expr_id: Option, + /// If true, then there may exist `break 'a` values that aim to + /// break out of this block early. As of this writing, this is not + /// currently permitted in Rust itself, but it is generated as + /// part of `catch` statements. + pub targeted_by_break: bool, } #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)] @@ -988,8 +995,8 @@ pub enum Expr_ { ExprType(P, P), /// An `if` block, with an optional else block /// - /// `if expr { block } else { expr }` - ExprIf(P, P, Option>), + /// `if expr { expr } else { expr }` + ExprIf(P, P, Option>), /// A while loop, with an optional label /// /// `'label: while expr { block }` @@ -1344,6 +1351,8 @@ pub enum Ty_ { /// TyInfer means the type should be inferred instead of it having been /// specified. This can appear anywhere in a type. TyInfer, + /// Placeholder for a type that has failed to be defined. + TyErr, } #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] @@ -1363,7 +1372,7 @@ pub struct InlineAsm { pub volatile: bool, pub alignstack: bool, pub dialect: AsmDialect, - pub expn_id: ExpnId, + pub ctxt: SyntaxContext, } /// represents an argument in a function header @@ -1379,6 +1388,9 @@ pub struct FnDecl { pub inputs: HirVec>, pub output: FunctionRetTy, pub variadic: bool, + /// True if this function has an `self`, `&self` or `&mut self` receiver + /// (but not a `self: Xxx` one). + pub has_implicit_self: bool, } #[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] @@ -1483,6 +1495,12 @@ pub struct ForeignMod { pub items: HirVec, } +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub struct GlobalAsm { + pub asm: Symbol, + pub ctxt: SyntaxContext, +} + #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct EnumDef { pub variants: HirVec, @@ -1674,6 +1692,8 @@ pub enum Item_ { ItemMod(Mod), /// An external module ItemForeignMod(ForeignMod), + /// Module-level inline assembly (from global_asm!) + ItemGlobalAsm(P), /// A type alias, e.g. `type Foo = Bar` ItemTy(P, Generics), /// An enum definition, e.g. `enum Foo {C, D}` @@ -1692,6 +1712,7 @@ pub enum Item_ { /// An implementation, eg `impl Trait for Foo { .. }` ItemImpl(Unsafety, ImplPolarity, + Defaultness, Generics, Option, // (optional) trait this impl implements P, // self @@ -1708,6 +1729,7 @@ impl Item_ { ItemFn(..) => "function", ItemMod(..) => "module", ItemForeignMod(..) => "foreign module", + ItemGlobalAsm(..) => "global asm", ItemTy(..) => "type alias", ItemEnum(..) => "enum", ItemStruct(..) => "struct", diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 3411de9bb5df..a78d5ce1c16d 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -450,6 +450,9 @@ impl<'a> State<'a> { hir::TyInfer => { word(&mut self.s, "_")?; } + hir::TyErr => { + word(&mut self.s, "?")?; + } } self.end() } @@ -630,6 +633,11 @@ impl<'a> State<'a> { self.print_foreign_mod(nmod, &item.attrs)?; self.bclose(item.span)?; } + hir::ItemGlobalAsm(ref ga) => { + self.head(&visibility_qualified(&item.vis, "global asm"))?; + word(&mut self.s, &ga.asm.as_str())?; + self.end()? + } hir::ItemTy(ref ty, ref params) => { self.ibox(indent_unit)?; self.ibox(0)?; @@ -670,12 +678,14 @@ impl<'a> State<'a> { } hir::ItemImpl(unsafety, polarity, + defaultness, ref generics, ref opt_trait, ref ty, ref impl_items) => { self.head("")?; self.print_visibility(&item.vis)?; + self.print_defaultness(defaultness)?; self.print_unsafety(unsafety)?; self.word_nbsp("impl")?; @@ -812,6 +822,14 @@ impl<'a> State<'a> { } } + pub fn print_defaultness(&mut self, defaultness: hir::Defaultness) -> io::Result<()> { + match defaultness { + hir::Defaultness::Default { .. } => self.word_nbsp("default")?, + hir::Defaultness::Final => (), + } + Ok(()) + } + pub fn print_struct(&mut self, struct_def: &hir::VariantData, generics: &hir::Generics, @@ -923,11 +941,7 @@ impl<'a> State<'a> { self.hardbreak_if_not_bol()?; self.maybe_print_comment(ii.span.lo)?; self.print_outer_attributes(&ii.attrs)?; - - match ii.defaultness { - hir::Defaultness::Default { .. } => self.word_nbsp("default")?, - hir::Defaultness::Final => (), - } + self.print_defaultness(ii.defaultness)?; match ii.node { hir::ImplItemKind::Const(ref ty, expr) => { @@ -1036,7 +1050,7 @@ impl<'a> State<'a> { word(&mut self.s, " else if ")?; self.print_expr(&i)?; space(&mut self.s)?; - self.print_block(&then)?; + self.print_expr(&then)?; self.print_else(e.as_ref().map(|e| &**e)) } // "final else" @@ -1058,13 +1072,13 @@ impl<'a> State<'a> { pub fn print_if(&mut self, test: &hir::Expr, - blk: &hir::Block, + blk: &hir::Expr, elseopt: Option<&hir::Expr>) -> io::Result<()> { self.head("if")?; self.print_expr(test)?; space(&mut self.s)?; - self.print_block(blk)?; + self.print_expr(blk)?; self.print_else(elseopt) } diff --git a/src/librustc/ich/caching_codemap_view.rs b/src/librustc/ich/caching_codemap_view.rs index a71251eedf5d..1278d9f5171b 100644 --- a/src/librustc/ich/caching_codemap_view.rs +++ b/src/librustc/ich/caching_codemap_view.rs @@ -47,10 +47,6 @@ impl<'tcx> CachingCodemapView<'tcx> { } } - pub fn codemap(&self) -> &'tcx CodeMap { - self.codemap - } - pub fn byte_pos_to_line_and_col(&mut self, pos: BytePos) -> Option<(Rc, usize, BytePos)> { diff --git a/src/librustc/ich/def_path_hash.rs b/src/librustc/ich/def_path_hash.rs deleted file mode 100644 index 03051dc00342..000000000000 --- a/src/librustc/ich/def_path_hash.rs +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use hir::def_id::DefId; -use ty::TyCtxt; -use util::nodemap::DefIdMap; - -pub struct DefPathHashes<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, - data: DefIdMap, -} - -impl<'a, 'tcx> DefPathHashes<'a, 'tcx> { - pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self { - DefPathHashes { - tcx: tcx, - data: DefIdMap() - } - } - - pub fn hash(&mut self, def_id: DefId) -> u64 { - let tcx = self.tcx; - *self.data.entry(def_id) - .or_insert_with(|| { - let def_path = tcx.def_path(def_id); - def_path.deterministic_hash(tcx) - }) - } -} diff --git a/src/librustc/ich/fingerprint.rs b/src/librustc/ich/fingerprint.rs index d296d8293fb0..e760f7efc93d 100644 --- a/src/librustc/ich/fingerprint.rs +++ b/src/librustc/ich/fingerprint.rs @@ -55,7 +55,7 @@ impl Fingerprint { impl Encodable for Fingerprint { #[inline] fn encode(&self, s: &mut S) -> Result<(), S::Error> { - for &byte in &self.0[..] { + for &byte in &self.0 { s.emit_u8(byte)?; } Ok(()) @@ -66,7 +66,7 @@ impl Decodable for Fingerprint { #[inline] fn decode(d: &mut D) -> Result { let mut result = Fingerprint([0u8; FINGERPRINT_LENGTH]); - for byte in &mut result.0[..] { + for byte in &mut result.0 { *byte = d.read_u8()?; } Ok(result) diff --git a/src/librustc/ich/hcx.rs b/src/librustc/ich/hcx.rs new file mode 100644 index 000000000000..3a6367c353c1 --- /dev/null +++ b/src/librustc/ich/hcx.rs @@ -0,0 +1,350 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use hir; +use hir::def_id::DefId; +use ich::{self, CachingCodemapView}; +use session::config::DebugInfoLevel::NoDebugInfo; +use ty; +use util::nodemap::NodeMap; + +use std::hash as std_hash; +use std::collections::{HashMap, HashSet}; + +use syntax::ast; +use syntax::attr; +use syntax::ext::hygiene::SyntaxContext; +use syntax::symbol::Symbol; +use syntax_pos::Span; + +use rustc_data_structures::stable_hasher::{HashStable, StableHasher, + StableHasherResult}; +use rustc_data_structures::accumulate_vec::AccumulateVec; + +/// This is the context state available during incr. comp. hashing. It contains +/// enough information to transform DefIds and HirIds into stable DefPaths (i.e. +/// a reference to the TyCtxt) and it holds a few caches for speeding up various +/// things (e.g. each DefId/DefPath is only hashed once). +pub struct StableHashingContext<'a, 'tcx: 'a> { + tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, + codemap: CachingCodemapView<'tcx>, + hash_spans: bool, + hash_bodies: bool, + overflow_checks_enabled: bool, + node_id_hashing_mode: NodeIdHashingMode, + // A sorted array of symbol keys for fast lookup. + ignored_attr_names: Vec, +} + +#[derive(PartialEq, Eq, Clone, Copy)] +pub enum NodeIdHashingMode { + Ignore, + HashDefPath, + HashTraitsInScope, +} + +impl<'a, 'tcx: 'a> StableHashingContext<'a, 'tcx> { + + pub fn new(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>) -> Self { + let hash_spans_initial = tcx.sess.opts.debuginfo != NoDebugInfo; + let check_overflow_initial = tcx.sess.overflow_checks(); + + let mut ignored_attr_names: Vec<_> = ich::IGNORED_ATTRIBUTES + .iter() + .map(|&s| Symbol::intern(s)) + .collect(); + + ignored_attr_names.sort(); + + StableHashingContext { + tcx: tcx, + codemap: CachingCodemapView::new(tcx), + hash_spans: hash_spans_initial, + hash_bodies: true, + overflow_checks_enabled: check_overflow_initial, + node_id_hashing_mode: NodeIdHashingMode::HashDefPath, + ignored_attr_names: ignored_attr_names, + } + } + + #[inline] + pub fn while_hashing_hir_bodies(&mut self, + hash_bodies: bool, + f: F) { + let prev_hash_bodies = self.hash_bodies; + self.hash_bodies = hash_bodies; + f(self); + self.hash_bodies = prev_hash_bodies; + } + + #[inline] + pub fn while_hashing_spans(&mut self, + hash_spans: bool, + f: F) { + let prev_hash_spans = self.hash_spans; + self.hash_spans = hash_spans; + f(self); + self.hash_spans = prev_hash_spans; + } + + #[inline] + pub fn with_node_id_hashing_mode(&mut self, + mode: NodeIdHashingMode, + f: F) { + let prev = self.node_id_hashing_mode; + self.node_id_hashing_mode = mode; + f(self); + self.node_id_hashing_mode = prev; + } + + #[inline] + pub fn tcx(&self) -> ty::TyCtxt<'a, 'tcx, 'tcx> { + self.tcx + } + + #[inline] + pub fn def_path_hash(&mut self, def_id: DefId) -> u64 { + self.tcx.def_path_hash(def_id) + } + + #[inline] + pub fn hash_spans(&self) -> bool { + self.hash_spans + } + + #[inline] + pub fn hash_bodies(&self) -> bool { + self.hash_bodies + } + + #[inline] + pub fn codemap(&mut self) -> &mut CachingCodemapView<'tcx> { + &mut self.codemap + } + + #[inline] + pub fn is_ignored_attr(&self, name: Symbol) -> bool { + self.ignored_attr_names.binary_search(&name).is_ok() + } + + pub fn hash_hir_item_like(&mut self, + item_attrs: &[ast::Attribute], + f: F) { + let prev_overflow_checks = self.overflow_checks_enabled; + if attr::contains_name(item_attrs, "rustc_inherit_overflow_checks") { + self.overflow_checks_enabled = true; + } + let prev_hash_node_ids = self.node_id_hashing_mode; + self.node_id_hashing_mode = NodeIdHashingMode::Ignore; + + f(self); + + self.node_id_hashing_mode = prev_hash_node_ids; + self.overflow_checks_enabled = prev_overflow_checks; + } + + #[inline] + pub fn binop_can_panic_at_runtime(&self, binop: hir::BinOp_) -> bool + { + match binop { + hir::BiAdd | + hir::BiSub | + hir::BiMul => self.overflow_checks_enabled, + + hir::BiDiv | + hir::BiRem => true, + + hir::BiAnd | + hir::BiOr | + hir::BiBitXor | + hir::BiBitAnd | + hir::BiBitOr | + hir::BiShl | + hir::BiShr | + hir::BiEq | + hir::BiLt | + hir::BiLe | + hir::BiNe | + hir::BiGe | + hir::BiGt => false + } + } + + #[inline] + pub fn unop_can_panic_at_runtime(&self, unop: hir::UnOp) -> bool + { + match unop { + hir::UnDeref | + hir::UnNot => false, + hir::UnNeg => self.overflow_checks_enabled, + } + } +} + + +impl<'a, 'tcx> HashStable> for ast::NodeId { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + match hcx.node_id_hashing_mode { + NodeIdHashingMode::Ignore => { + // Most NodeIds in the HIR can be ignored, but if there is a + // corresponding entry in the `trait_map` we need to hash that. + // Make sure we don't ignore too much by checking that there is + // no entry in a debug_assert!(). + debug_assert!(hcx.tcx.trait_map.get(self).is_none()); + } + NodeIdHashingMode::HashDefPath => { + hcx.tcx.hir.definitions().node_to_hir_id(*self).hash_stable(hcx, hasher); + } + NodeIdHashingMode::HashTraitsInScope => { + if let Some(traits) = hcx.tcx.trait_map.get(self) { + // The ordering of the candidates is not fixed. So we hash + // the def-ids and then sort them and hash the collection. + let mut candidates: AccumulateVec<[_; 8]> = + traits.iter() + .map(|&hir::TraitCandidate { def_id, import_id: _ }| { + hcx.def_path_hash(def_id) + }) + .collect(); + if traits.len() > 1 { + candidates.sort(); + } + candidates.hash_stable(hcx, hasher); + } + } + } + } +} + +impl<'a, 'tcx> HashStable> for Span { + + // Hash a span in a stable way. We can't directly hash the span's BytePos + // fields (that would be similar to hashing pointers, since those are just + // offsets into the CodeMap). Instead, we hash the (file name, line, column) + // triple, which stays the same even if the containing FileMap has moved + // within the CodeMap. + // Also note that we are hashing byte offsets for the column, not unicode + // codepoint offsets. For the purpose of the hash that's sufficient. + // Also, hashing filenames is expensive so we avoid doing it twice when the + // span starts and ends in the same file, which is almost always the case. + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + use syntax_pos::Pos; + + if !hcx.hash_spans { + return + } + + // If this is not an empty or invalid span, we want to hash the last + // position that belongs to it, as opposed to hashing the first + // position past it. + let span_hi = if self.hi > self.lo { + // We might end up in the middle of a multibyte character here, + // but that's OK, since we are not trying to decode anything at + // this position. + self.hi - ::syntax_pos::BytePos(1) + } else { + self.hi + }; + + { + let loc1 = hcx.codemap().byte_pos_to_line_and_col(self.lo); + let loc1 = loc1.as_ref() + .map(|&(ref fm, line, col)| (&fm.name[..], line, col.to_usize())) + .unwrap_or(("???", 0, 0)); + + let loc2 = hcx.codemap().byte_pos_to_line_and_col(span_hi); + let loc2 = loc2.as_ref() + .map(|&(ref fm, line, col)| (&fm.name[..], line, col.to_usize())) + .unwrap_or(("???", 0, 0)); + + if loc1.0 == loc2.0 { + std_hash::Hash::hash(&0u8, hasher); + + std_hash::Hash::hash(loc1.0, hasher); + std_hash::Hash::hash(&loc1.1, hasher); + std_hash::Hash::hash(&loc1.2, hasher); + + // Do not hash the file name twice + std_hash::Hash::hash(&loc2.1, hasher); + std_hash::Hash::hash(&loc2.2, hasher); + } else { + std_hash::Hash::hash(&1u8, hasher); + + std_hash::Hash::hash(loc1.0, hasher); + std_hash::Hash::hash(&loc1.1, hasher); + std_hash::Hash::hash(&loc1.2, hasher); + + std_hash::Hash::hash(loc2.0, hasher); + std_hash::Hash::hash(&loc2.1, hasher); + std_hash::Hash::hash(&loc2.2, hasher); + } + } + + if self.ctxt == SyntaxContext::empty() { + 0u8.hash_stable(hcx, hasher); + } else { + 1u8.hash_stable(hcx, hasher); + self.source_callsite().hash_stable(hcx, hasher); + } + } +} + +pub fn hash_stable_hashmap<'a, 'tcx, K, V, R, SK, F, W>(hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher, + map: &HashMap, + extract_stable_key: F) + where K: Eq + std_hash::Hash, + V: HashStable>, + R: std_hash::BuildHasher, + SK: HashStable> + Ord + Clone, + F: Fn(&mut StableHashingContext<'a, 'tcx>, &K) -> SK, + W: StableHasherResult, +{ + let mut keys: Vec<_> = map.keys() + .map(|k| (extract_stable_key(hcx, k), k)) + .collect(); + keys.sort_unstable_by_key(|&(ref stable_key, _)| stable_key.clone()); + keys.len().hash_stable(hcx, hasher); + for (stable_key, key) in keys { + stable_key.hash_stable(hcx, hasher); + map[key].hash_stable(hcx, hasher); + } +} + +pub fn hash_stable_hashset<'a, 'tcx, K, R, SK, F, W>(hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher, + set: &HashSet, + extract_stable_key: F) + where K: Eq + std_hash::Hash, + R: std_hash::BuildHasher, + SK: HashStable> + Ord + Clone, + F: Fn(&mut StableHashingContext<'a, 'tcx>, &K) -> SK, + W: StableHasherResult, +{ + let mut keys: Vec<_> = set.iter() + .map(|k| extract_stable_key(hcx, k)) + .collect(); + keys.sort_unstable(); + keys.hash_stable(hcx, hasher); +} + +pub fn hash_stable_nodemap<'a, 'tcx, V, W>(hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher, + map: &NodeMap) + where V: HashStable>, + W: StableHasherResult, +{ + hash_stable_hashmap(hcx, hasher, map, |hcx, node_id| { + hcx.tcx.hir.definitions().node_to_hir_id(*node_id).local_id + }); +} diff --git a/src/librustc/ich/impls_const_math.rs b/src/librustc/ich/impls_const_math.rs new file mode 100644 index 000000000000..6d11f2a87a41 --- /dev/null +++ b/src/librustc/ich/impls_const_math.rs @@ -0,0 +1,71 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! This module contains `HashStable` implementations for various data types +//! from `rustc_const_math` in no particular order. + +impl_stable_hash_for!(enum ::rustc_const_math::ConstFloat { + F32(val), + F64(val) +}); + +impl_stable_hash_for!(enum ::rustc_const_math::ConstInt { + I8(val), + I16(val), + I32(val), + I64(val), + I128(val), + Isize(val), + U8(val), + U16(val), + U32(val), + U64(val), + U128(val), + Usize(val) +}); + +impl_stable_hash_for!(enum ::rustc_const_math::ConstIsize { + Is16(i16), + Is32(i32), + Is64(i64) +}); + +impl_stable_hash_for!(enum ::rustc_const_math::ConstUsize { + Us16(i16), + Us32(i32), + Us64(i64) +}); + +impl_stable_hash_for!(enum ::rustc_const_math::ConstMathErr { + NotInRange, + CmpBetweenUnequalTypes, + UnequalTypes(op), + Overflow(op), + ShiftNegative, + DivisionByZero, + RemainderByZero, + UnsignedNegation, + ULitOutOfRange(int_ty), + LitOutOfRange(int_ty) +}); + +impl_stable_hash_for!(enum ::rustc_const_math::Op { + Add, + Sub, + Mul, + Div, + Rem, + Shr, + Shl, + Neg, + BitAnd, + BitOr, + BitXor +}); diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs new file mode 100644 index 000000000000..3aeee1c1b981 --- /dev/null +++ b/src/librustc/ich/impls_hir.rs @@ -0,0 +1,1122 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! This module contains `HashStable` implementations for various HIR data +//! types in no particular order. + +use hir; +use hir::def_id::DefId; +use ich::{StableHashingContext, NodeIdHashingMode}; +use std::mem; + +use syntax::ast; + +use rustc_data_structures::stable_hasher::{HashStable, StableHasher, + StableHasherResult}; + +impl<'a, 'tcx> HashStable> for DefId { + #[inline] + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + hcx.def_path_hash(*self).hash_stable(hcx, hasher); + } +} + + +impl<'a, 'tcx> HashStable> for hir::HirId { + #[inline] + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let hir::HirId { + owner, + local_id, + } = *self; + + hcx.def_path_hash(DefId::local(owner)).hash_stable(hcx, hasher); + local_id.hash_stable(hcx, hasher); + } +} + +impl_stable_hash_for!(tuple_struct hir::ItemLocalId { index }); + +// The following implementations of HashStable for ItemId, TraitItemId, and +// ImplItemId deserve special attention. Normally we do not hash NodeIds within +// the HIR, since they just signify a HIR nodes own path. But ItemId et al +// are used when another item in the HIR is *referenced* and we certainly +// want to pick up on a reference changing its target, so we hash the NodeIds +// in "DefPath Mode". + +impl<'a, 'tcx> HashStable> for hir::ItemId { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let hir::ItemId { + id + } = *self; + + hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { + id.hash_stable(hcx, hasher); + }) + } +} + +impl<'a, 'tcx> HashStable> for hir::TraitItemId { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let hir::TraitItemId { + node_id + } = * self; + + hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { + node_id.hash_stable(hcx, hasher); + }) + } +} + +impl<'a, 'tcx> HashStable> for hir::ImplItemId { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let hir::ImplItemId { + node_id + } = * self; + + hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { + node_id.hash_stable(hcx, hasher); + }) + } +} + +impl_stable_hash_for!(struct hir::Lifetime { + id, + span, + name +}); + +impl_stable_hash_for!(struct hir::LifetimeDef { + lifetime, + bounds, + pure_wrt_drop +}); + +impl_stable_hash_for!(struct hir::Path { + span, + def, + segments +}); + +impl_stable_hash_for!(struct hir::PathSegment { + name, + parameters +}); + +impl_stable_hash_for!(enum hir::PathParameters { + AngleBracketedParameters(data), + ParenthesizedParameters(data) +}); + +impl_stable_hash_for!(struct hir::AngleBracketedParameterData { + lifetimes, + types, + infer_types, + bindings +}); + +impl_stable_hash_for!(struct hir::ParenthesizedParameterData { + span, + inputs, + output +}); + +impl_stable_hash_for!(enum hir::TyParamBound { + TraitTyParamBound(poly_trait_ref, trait_bound_modifier), + RegionTyParamBound(lifetime) +}); + +impl_stable_hash_for!(enum hir::TraitBoundModifier { + None, + Maybe +}); + +impl_stable_hash_for!(struct hir::TyParam { + name, + id, + bounds, + default, + span, + pure_wrt_drop +}); + +impl_stable_hash_for!(struct hir::Generics { + lifetimes, + ty_params, + where_clause, + span +}); + +impl_stable_hash_for!(struct hir::WhereClause { + id, + predicates +}); + +impl_stable_hash_for!(enum hir::WherePredicate { + BoundPredicate(pred), + RegionPredicate(pred), + EqPredicate(pred) +}); + +impl_stable_hash_for!(struct hir::WhereBoundPredicate { + span, + bound_lifetimes, + bounded_ty, + bounds +}); + +impl_stable_hash_for!(struct hir::WhereRegionPredicate { + span, + lifetime, + bounds +}); + +impl_stable_hash_for!(struct hir::WhereEqPredicate { + id, + span, + lhs_ty, + rhs_ty +}); + +impl_stable_hash_for!(struct hir::MutTy { + ty, + mutbl +}); + +impl_stable_hash_for!(struct hir::MethodSig { + unsafety, + constness, + abi, + decl, + generics +}); + +impl_stable_hash_for!(struct hir::TypeBinding { + id, + name, + ty, + span +}); + +impl<'a, 'tcx> HashStable> for hir::Ty { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let node_id_hashing_mode = match self.node { + hir::TySlice(..) | + hir::TyArray(..) | + hir::TyPtr(..) | + hir::TyRptr(..) | + hir::TyBareFn(..) | + hir::TyNever | + hir::TyTup(..) | + hir::TyTraitObject(..) | + hir::TyImplTrait(..) | + hir::TyTypeof(..) | + hir::TyErr | + hir::TyInfer => { + NodeIdHashingMode::Ignore + } + hir::TyPath(..) => { + NodeIdHashingMode::HashTraitsInScope + } + }; + + hcx.while_hashing_hir_bodies(true, |hcx| { + let hir::Ty { + id, + ref node, + ref span, + } = *self; + + hcx.with_node_id_hashing_mode(node_id_hashing_mode, |hcx| { + id.hash_stable(hcx, hasher); + }); + node.hash_stable(hcx, hasher); + span.hash_stable(hcx, hasher); + }) + } +} + +impl_stable_hash_for!(enum hir::PrimTy { + TyInt(int_ty), + TyUint(uint_ty), + TyFloat(float_ty), + TyStr, + TyBool, + TyChar +}); + +impl_stable_hash_for!(struct hir::BareFnTy { + unsafety, + abi, + lifetimes, + decl +}); + +impl_stable_hash_for!(enum hir::Ty_ { + TySlice(t), + TyArray(t, body_id), + TyPtr(t), + TyRptr(lifetime, t), + TyBareFn(t), + TyNever, + TyTup(ts), + TyPath(qpath), + TyTraitObject(trait_refs, lifetime), + TyImplTrait(bounds), + TyTypeof(body_id), + TyErr, + TyInfer +}); + +impl_stable_hash_for!(struct hir::FnDecl { + inputs, + output, + variadic, + has_implicit_self +}); + +impl_stable_hash_for!(enum hir::FunctionRetTy { + DefaultReturn(span), + Return(t) +}); + +impl<'a, 'tcx> HashStable> for hir::TraitRef { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let hir::TraitRef { + ref path, + ref_id, + } = *self; + + path.hash_stable(hcx, hasher); + hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashTraitsInScope, |hcx| { + ref_id.hash_stable(hcx, hasher); + }); + } +} + + +impl_stable_hash_for!(struct hir::PolyTraitRef { + bound_lifetimes, + trait_ref, + span +}); + +impl_stable_hash_for!(enum hir::QPath { + Resolved(t, path), + TypeRelative(t, path_segment) +}); + +impl_stable_hash_for!(struct hir::MacroDef { + name, + attrs, + id, + span, + body +}); + + +impl<'a, 'tcx> HashStable> for hir::Block { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let hir::Block { + ref stmts, + ref expr, + id, + rules, + span, + targeted_by_break, + } = *self; + + let non_item_stmts = || stmts.iter().filter(|stmt| { + match stmt.node { + hir::StmtDecl(ref decl, _) => { + match decl.node { + // If this is a declaration of a nested item, we don't + // want to leave any trace of it in the hash value, not + // even that it exists. Otherwise changing the position + // of nested items would invalidate the containing item + // even though that does not constitute a semantic + // change. + hir::DeclItem(_) => false, + hir::DeclLocal(_) => true + } + } + hir::StmtExpr(..) | + hir::StmtSemi(..) => true + } + }); + + let count = non_item_stmts().count(); + + count.hash_stable(hcx, hasher); + + for stmt in non_item_stmts() { + stmt.hash_stable(hcx, hasher); + } + + expr.hash_stable(hcx, hasher); + id.hash_stable(hcx, hasher); + rules.hash_stable(hcx, hasher); + span.hash_stable(hcx, hasher); + targeted_by_break.hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable> for hir::Pat { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let node_id_hashing_mode = match self.node { + hir::PatKind::Wild | + hir::PatKind::Binding(..) | + hir::PatKind::Tuple(..) | + hir::PatKind::Box(..) | + hir::PatKind::Ref(..) | + hir::PatKind::Lit(..) | + hir::PatKind::Range(..) | + hir::PatKind::Slice(..) => { + NodeIdHashingMode::Ignore + } + hir::PatKind::Path(..) | + hir::PatKind::Struct(..) | + hir::PatKind::TupleStruct(..) => { + NodeIdHashingMode::HashTraitsInScope + } + }; + + let hir::Pat { + id, + ref node, + ref span + } = *self; + + hcx.with_node_id_hashing_mode(node_id_hashing_mode, |hcx| { + id.hash_stable(hcx, hasher); + }); + node.hash_stable(hcx, hasher); + span.hash_stable(hcx, hasher); + } +} + +impl_stable_hash_for_spanned!(hir::FieldPat); +impl_stable_hash_for!(struct hir::FieldPat { + name, + pat, + is_shorthand +}); + +impl_stable_hash_for!(enum hir::BindingMode { + BindByRef(mutability), + BindByValue(mutability) +}); + +impl_stable_hash_for!(enum hir::RangeEnd { + Included, + Excluded +}); + +impl_stable_hash_for!(enum hir::PatKind { + Wild, + Binding(binding_mode, var, name, sub), + Struct(path, field_pats, dotdot), + TupleStruct(path, field_pats, dotdot), + Path(path), + Tuple(field_pats, dotdot), + Box(sub), + Ref(sub, mutability), + Lit(expr), + Range(start, end, end_kind), + Slice(one, two, three) +}); + +impl_stable_hash_for!(enum hir::BinOp_ { + BiAdd, + BiSub, + BiMul, + BiDiv, + BiRem, + BiAnd, + BiOr, + BiBitXor, + BiBitAnd, + BiBitOr, + BiShl, + BiShr, + BiEq, + BiLt, + BiLe, + BiNe, + BiGe, + BiGt +}); + +impl_stable_hash_for_spanned!(hir::BinOp_); + +impl_stable_hash_for!(enum hir::UnOp { + UnDeref, + UnNot, + UnNeg +}); + +impl_stable_hash_for_spanned!(hir::Stmt_); + +impl_stable_hash_for!(struct hir::Local { + pat, + ty, + init, + id, + span, + attrs +}); + +impl_stable_hash_for_spanned!(hir::Decl_); +impl_stable_hash_for!(enum hir::Decl_ { + DeclLocal(local), + DeclItem(item_id) +}); + +impl_stable_hash_for!(struct hir::Arm { + attrs, + pats, + guard, + body +}); + +impl_stable_hash_for!(struct hir::Field { + name, + expr, + span, + is_shorthand +}); + +impl_stable_hash_for_spanned!(ast::Name); + + +impl_stable_hash_for!(enum hir::BlockCheckMode { + DefaultBlock, + UnsafeBlock(src), + PushUnsafeBlock(src), + PopUnsafeBlock(src) +}); + +impl_stable_hash_for!(enum hir::UnsafeSource { + CompilerGenerated, + UserProvided +}); + +impl<'a, 'tcx> HashStable> for hir::Expr { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + hcx.while_hashing_hir_bodies(true, |hcx| { + let hir::Expr { + id, + ref span, + ref node, + ref attrs + } = *self; + + let (spans_always_on, node_id_hashing_mode) = match *node { + hir::ExprBox(..) | + hir::ExprArray(..) | + hir::ExprCall(..) | + hir::ExprLit(..) | + hir::ExprCast(..) | + hir::ExprType(..) | + hir::ExprIf(..) | + hir::ExprWhile(..) | + hir::ExprLoop(..) | + hir::ExprMatch(..) | + hir::ExprClosure(..) | + hir::ExprBlock(..) | + hir::ExprAssign(..) | + hir::ExprTupField(..) | + hir::ExprAddrOf(..) | + hir::ExprBreak(..) | + hir::ExprAgain(..) | + hir::ExprRet(..) | + hir::ExprInlineAsm(..) | + hir::ExprRepeat(..) | + hir::ExprTup(..) => { + // For these we only hash the span when debuginfo is on. + (false, NodeIdHashingMode::Ignore) + } + // For the following, spans might be significant because of + // panic messages indicating the source location. + hir::ExprBinary(op, ..) => { + (hcx.binop_can_panic_at_runtime(op.node), NodeIdHashingMode::Ignore) + } + hir::ExprUnary(op, _) => { + (hcx.unop_can_panic_at_runtime(op), NodeIdHashingMode::Ignore) + } + hir::ExprAssignOp(op, ..) => { + (hcx.binop_can_panic_at_runtime(op.node), NodeIdHashingMode::Ignore) + } + hir::ExprIndex(..) => { + (true, NodeIdHashingMode::Ignore) + } + // For these we don't care about the span, but want to hash the + // trait in scope + hir::ExprMethodCall(..) | + hir::ExprPath(..) | + hir::ExprStruct(..) | + hir::ExprField(..) => { + (false, NodeIdHashingMode::HashTraitsInScope) + } + }; + + hcx.with_node_id_hashing_mode(node_id_hashing_mode, |hcx| { + id.hash_stable(hcx, hasher); + }); + + if spans_always_on { + hcx.while_hashing_spans(true, |hcx| { + span.hash_stable(hcx, hasher); + node.hash_stable(hcx, hasher); + attrs.hash_stable(hcx, hasher); + }); + } else { + span.hash_stable(hcx, hasher); + node.hash_stable(hcx, hasher); + attrs.hash_stable(hcx, hasher); + } + }) + } +} + +impl_stable_hash_for!(enum hir::Expr_ { + ExprBox(sub), + ExprArray(subs), + ExprCall(callee, args), + ExprMethodCall(name, ts, args), + ExprTup(fields), + ExprBinary(op, lhs, rhs), + ExprUnary(op, operand), + ExprLit(value), + ExprCast(expr, t), + ExprType(expr, t), + ExprIf(cond, then, els), + ExprWhile(cond, body, label), + ExprLoop(body, label, loop_src), + ExprMatch(matchee, arms, match_src), + ExprClosure(capture_clause, decl, body_id, span), + ExprBlock(blk), + ExprAssign(lhs, rhs), + ExprAssignOp(op, lhs, rhs), + ExprField(owner, field_name), + ExprTupField(owner, idx), + ExprIndex(lhs, rhs), + ExprPath(path), + ExprAddrOf(mutability, sub), + ExprBreak(destination, sub), + ExprAgain(destination), + ExprRet(val), + ExprInlineAsm(asm, inputs, outputs), + ExprStruct(path, fields, base), + ExprRepeat(val, times) +}); + +impl_stable_hash_for!(enum hir::LoopSource { + Loop, + WhileLet, + ForLoop +}); + +impl<'a, 'tcx> HashStable> for hir::MatchSource { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + use hir::MatchSource; + + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + MatchSource::Normal | + MatchSource::WhileLetDesugar | + MatchSource::ForLoopDesugar | + MatchSource::TryDesugar => { + // No fields to hash. + } + MatchSource::IfLetDesugar { contains_else_clause } => { + contains_else_clause.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(enum hir::CaptureClause { + CaptureByValue, + CaptureByRef +}); + +impl_stable_hash_for_spanned!(usize); + +impl_stable_hash_for!(struct hir::Destination { + ident, + target_id +}); + +impl_stable_hash_for_spanned!(ast::Ident); + +impl_stable_hash_for!(enum hir::LoopIdResult { + Ok(node_id), + Err(loop_id_error) +}); + +impl_stable_hash_for!(enum hir::LoopIdError { + OutsideLoopScope, + UnlabeledCfInWhileCondition, + UnresolvedLabel +}); + +impl_stable_hash_for!(enum hir::ScopeTarget { + Block(node_id), + Loop(loop_id_result) +}); + +impl<'a, 'tcx> HashStable> for ast::Ident { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let ast::Ident { + ref name, + ctxt: _ // Ignore this + } = *self; + + name.hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable> for hir::TraitItem { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let hir::TraitItem { + id, + name, + ref attrs, + ref node, + span + } = *self; + + hcx.hash_hir_item_like(attrs, |hcx| { + id.hash_stable(hcx, hasher); + name.hash_stable(hcx, hasher); + attrs.hash_stable(hcx, hasher); + node.hash_stable(hcx, hasher); + span.hash_stable(hcx, hasher); + }); + } +} + +impl_stable_hash_for!(enum hir::TraitMethod { + Required(name), + Provided(body) +}); + +impl_stable_hash_for!(enum hir::TraitItemKind { + Const(t, body), + Method(sig, method), + Type(bounds, rhs) +}); + +impl<'a, 'tcx> HashStable> for hir::ImplItem { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let hir::ImplItem { + id, + name, + ref vis, + defaultness, + ref attrs, + ref node, + span + } = *self; + + hcx.hash_hir_item_like(attrs, |hcx| { + id.hash_stable(hcx, hasher); + name.hash_stable(hcx, hasher); + vis.hash_stable(hcx, hasher); + defaultness.hash_stable(hcx, hasher); + attrs.hash_stable(hcx, hasher); + node.hash_stable(hcx, hasher); + span.hash_stable(hcx, hasher); + }); + } +} + +impl_stable_hash_for!(enum hir::ImplItemKind { + Const(t, body), + Method(sig, body), + Type(t) +}); + +impl<'a, 'tcx> HashStable> for hir::Visibility { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + hir::Visibility::Public | + hir::Visibility::Crate | + hir::Visibility::Inherited => { + // No fields to hash. + } + hir::Visibility::Restricted { ref path, id } => { + hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashTraitsInScope, |hcx| { + id.hash_stable(hcx, hasher); + }); + path.hash_stable(hcx, hasher); + } + } + } +} + +impl<'a, 'tcx> HashStable> for hir::Defaultness { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + hir::Defaultness::Final => { + // No fields to hash. + } + hir::Defaultness::Default { has_value } => { + has_value.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(enum hir::ImplPolarity { + Positive, + Negative +}); + +impl<'a, 'tcx> HashStable> for hir::Mod { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let hir::Mod { + inner, + // We are not hashing the IDs of the items contained in the module. + // This is harmless and matches the current behavior but it's not + // actually correct. See issue #40876. + item_ids: _, + } = *self; + + inner.hash_stable(hcx, hasher); + } +} + +impl_stable_hash_for!(struct hir::ForeignMod { + abi, + items +}); + +impl_stable_hash_for!(struct hir::EnumDef { + variants +}); + +impl_stable_hash_for!(struct hir::Variant_ { + name, + attrs, + data, + disr_expr +}); + +impl_stable_hash_for_spanned!(hir::Variant_); + +impl_stable_hash_for!(enum hir::UseKind { + Single, + Glob, + ListStem +}); + +impl_stable_hash_for!(struct hir::StructField { + span, + name, + vis, + id, + ty, + attrs +}); + +impl_stable_hash_for!(enum hir::VariantData { + Struct(fields, id), + Tuple(fields, id), + Unit(id) +}); + +impl<'a, 'tcx> HashStable> for hir::Item { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let node_id_hashing_mode = match self.node { + hir::ItemExternCrate(..) | + hir::ItemStatic(..) | + hir::ItemConst(..) | + hir::ItemFn(..) | + hir::ItemMod(..) | + hir::ItemForeignMod(..) | + hir::ItemGlobalAsm(..) | + hir::ItemTy(..) | + hir::ItemEnum(..) | + hir::ItemStruct(..) | + hir::ItemUnion(..) | + hir::ItemTrait(..) | + hir::ItemDefaultImpl(..) | + hir::ItemImpl(..) => { + NodeIdHashingMode::Ignore + } + hir::ItemUse(..) => { + NodeIdHashingMode::HashTraitsInScope + } + }; + + let hir::Item { + name, + ref attrs, + id, + ref node, + ref vis, + span + } = *self; + + hcx.hash_hir_item_like(attrs, |hcx| { + hcx.with_node_id_hashing_mode(node_id_hashing_mode, |hcx| { + id.hash_stable(hcx, hasher); + }); + name.hash_stable(hcx, hasher); + attrs.hash_stable(hcx, hasher); + node.hash_stable(hcx, hasher); + vis.hash_stable(hcx, hasher); + span.hash_stable(hcx, hasher); + }); + } +} + +impl_stable_hash_for!(enum hir::Item_ { + ItemExternCrate(name), + ItemUse(path, use_kind), + ItemStatic(ty, mutability, body_id), + ItemConst(ty, body_id), + ItemFn(fn_decl, unsafety, constness, abi, generics, body_id), + ItemMod(module), + ItemForeignMod(foreign_mod), + ItemGlobalAsm(global_asm), + ItemTy(ty, generics), + ItemEnum(enum_def, generics), + ItemStruct(variant_data, generics), + ItemUnion(variant_data, generics), + ItemTrait(unsafety, generics, bounds, item_refs), + ItemDefaultImpl(unsafety, trait_ref), + ItemImpl(unsafety, impl_polarity, impl_defaultness, generics, trait_ref, ty, impl_item_refs) +}); + +impl_stable_hash_for!(struct hir::TraitItemRef { + id, + name, + kind, + span, + defaultness +}); + +impl_stable_hash_for!(struct hir::ImplItemRef { + id, + name, + kind, + span, + vis, + defaultness +}); + +impl<'a, 'tcx> HashStable> for hir::AssociatedItemKind { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + hir::AssociatedItemKind::Const | + hir::AssociatedItemKind::Type => { + // No fields to hash. + } + hir::AssociatedItemKind::Method { has_self } => { + has_self.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(struct hir::ForeignItem { + name, + attrs, + node, + id, + span, + vis +}); + +impl_stable_hash_for!(enum hir::ForeignItem_ { + ForeignItemFn(fn_decl, arg_names, generics), + ForeignItemStatic(ty, is_mutbl) +}); + +impl_stable_hash_for!(enum hir::Stmt_ { + StmtDecl(decl, id), + StmtExpr(expr, id), + StmtSemi(expr, id) +}); + +impl_stable_hash_for!(struct hir::Arg { + pat, + id +}); + +impl_stable_hash_for!(struct hir::Body { + arguments, + value +}); + +impl<'a, 'tcx> HashStable> for hir::BodyId { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + if hcx.hash_bodies() { + hcx.tcx().hir.body(*self).hash_stable(hcx, hasher); + } + } +} + +impl_stable_hash_for!(struct hir::InlineAsmOutput { + constraint, + is_rw, + is_indirect +}); + +impl<'a, 'tcx> HashStable> for hir::GlobalAsm { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let hir::GlobalAsm { + asm, + ctxt: _ + } = *self; + + asm.hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable> for hir::InlineAsm { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let hir::InlineAsm { + asm, + asm_str_style, + ref outputs, + ref inputs, + ref clobbers, + volatile, + alignstack, + dialect, + ctxt: _, // This is used for error reporting + } = *self; + + asm.hash_stable(hcx, hasher); + asm_str_style.hash_stable(hcx, hasher); + outputs.hash_stable(hcx, hasher); + inputs.hash_stable(hcx, hasher); + clobbers.hash_stable(hcx, hasher); + volatile.hash_stable(hcx, hasher); + alignstack.hash_stable(hcx, hasher); + dialect.hash_stable(hcx, hasher); + } +} + +impl_stable_hash_for!(enum hir::def::CtorKind { + Fn, + Const, + Fictive +}); + +impl_stable_hash_for!(enum hir::def::Def { + Mod(def_id), + Struct(def_id), + Union(def_id), + Enum(def_id), + Variant(def_id), + Trait(def_id), + TyAlias(def_id), + AssociatedTy(def_id), + PrimTy(prim_ty), + TyParam(def_id), + SelfTy(trait_def_id, impl_def_id), + Fn(def_id), + Const(def_id), + Static(def_id, is_mutbl), + StructCtor(def_id, ctor_kind), + VariantCtor(def_id, ctor_kind), + Method(def_id), + AssociatedConst(def_id), + Local(def_id), + Upvar(def_id, index, expr_id), + Label(node_id), + Macro(def_id, macro_kind), + GlobalAsm(def_id), + Err +}); + +impl_stable_hash_for!(enum hir::Mutability { + MutMutable, + MutImmutable +}); + + +impl_stable_hash_for!(enum hir::Unsafety { + Unsafe, + Normal +}); + + +impl_stable_hash_for!(enum hir::Constness { + Const, + NotConst +}); + +impl<'a, 'tcx> HashStable> for hir::def_id::DefIndex { + + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + DefId::local(*self).hash_stable(hcx, hasher); + } +} + +impl_stable_hash_for!(struct hir::def::Export { + name, + def, + span +}); diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs new file mode 100644 index 000000000000..3ff8ffb35054 --- /dev/null +++ b/src/librustc/ich/impls_mir.rs @@ -0,0 +1,408 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! This module contains `HashStable` implementations for various MIR data +//! types in no particular order. + +use ich::StableHashingContext; +use mir; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher, + StableHasherResult}; +use std::mem; + + +impl_stable_hash_for!(struct mir::SourceInfo { span, scope }); +impl_stable_hash_for!(enum mir::Mutability { Mut, Not }); +impl_stable_hash_for!(enum mir::BorrowKind { Shared, Unique, Mut }); +impl_stable_hash_for!(enum mir::LocalKind { Var, Temp, Arg, ReturnPointer }); +impl_stable_hash_for!(struct mir::LocalDecl<'tcx> { mutability, ty, name, source_info, +is_user_variable}); +impl_stable_hash_for!(struct mir::UpvarDecl { debug_name, by_ref }); +impl_stable_hash_for!(struct mir::BasicBlockData<'tcx> { statements, terminator, is_cleanup }); +impl_stable_hash_for!(struct mir::Terminator<'tcx> { source_info, kind }); + +impl<'a, 'tcx> HashStable> for mir::Local { + #[inline] + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + use rustc_data_structures::indexed_vec::Idx; + self.index().hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable> for mir::BasicBlock { + #[inline] + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + use rustc_data_structures::indexed_vec::Idx; + self.index().hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable> for mir::Field { + #[inline] + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + use rustc_data_structures::indexed_vec::Idx; + self.index().hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable> for mir::VisibilityScope { + #[inline] + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + use rustc_data_structures::indexed_vec::Idx; + self.index().hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable> for mir::Promoted { + #[inline] + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + use rustc_data_structures::indexed_vec::Idx; + self.index().hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable> for mir::TerminatorKind<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + + match *self { + mir::TerminatorKind::Goto { ref target } => { + target.hash_stable(hcx, hasher); + } + mir::TerminatorKind::SwitchInt { ref discr, + switch_ty, + ref values, + ref targets } => { + discr.hash_stable(hcx, hasher); + switch_ty.hash_stable(hcx, hasher); + values.hash_stable(hcx, hasher); + targets.hash_stable(hcx, hasher); + } + mir::TerminatorKind::Resume | + mir::TerminatorKind::Return | + mir::TerminatorKind::Unreachable => {} + mir::TerminatorKind::Drop { ref location, target, unwind } => { + location.hash_stable(hcx, hasher); + target.hash_stable(hcx, hasher); + unwind.hash_stable(hcx, hasher); + } + mir::TerminatorKind::DropAndReplace { ref location, + ref value, + target, + unwind, } => { + location.hash_stable(hcx, hasher); + value.hash_stable(hcx, hasher); + target.hash_stable(hcx, hasher); + unwind.hash_stable(hcx, hasher); + } + mir::TerminatorKind::Call { ref func, + ref args, + ref destination, + cleanup } => { + func.hash_stable(hcx, hasher); + args.hash_stable(hcx, hasher); + destination.hash_stable(hcx, hasher); + cleanup.hash_stable(hcx, hasher); + } + mir::TerminatorKind::Assert { ref cond, + expected, + ref msg, + target, + cleanup } => { + cond.hash_stable(hcx, hasher); + expected.hash_stable(hcx, hasher); + msg.hash_stable(hcx, hasher); + target.hash_stable(hcx, hasher); + cleanup.hash_stable(hcx, hasher); + } + } + } +} + +impl<'a, 'tcx> HashStable> for mir::AssertMessage<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + + match *self { + mir::AssertMessage::BoundsCheck { ref len, ref index } => { + len.hash_stable(hcx, hasher); + index.hash_stable(hcx, hasher); + } + mir::AssertMessage::Math(ref const_math_err) => { + const_math_err.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(struct mir::Statement<'tcx> { source_info, kind }); + +impl<'a, 'tcx> HashStable> for mir::StatementKind<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + + match *self { + mir::StatementKind::Assign(ref lvalue, ref rvalue) => { + lvalue.hash_stable(hcx, hasher); + rvalue.hash_stable(hcx, hasher); + } + mir::StatementKind::SetDiscriminant { ref lvalue, variant_index } => { + lvalue.hash_stable(hcx, hasher); + variant_index.hash_stable(hcx, hasher); + } + mir::StatementKind::StorageLive(ref lvalue) | + mir::StatementKind::StorageDead(ref lvalue) => { + lvalue.hash_stable(hcx, hasher); + } + mir::StatementKind::Nop => {} + mir::StatementKind::InlineAsm { ref asm, ref outputs, ref inputs } => { + asm.hash_stable(hcx, hasher); + outputs.hash_stable(hcx, hasher); + inputs.hash_stable(hcx, hasher); + } + } + } +} + +impl<'a, 'tcx> HashStable> for mir::Lvalue<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + mir::Lvalue::Local(ref local) => { + local.hash_stable(hcx, hasher); + } + mir::Lvalue::Static(ref statik) => { + statik.hash_stable(hcx, hasher); + } + mir::Lvalue::Projection(ref lvalue_projection) => { + lvalue_projection.hash_stable(hcx, hasher); + } + } + } +} + +impl<'a, 'tcx, B, V> HashStable> for mir::Projection<'tcx, B, V> + where B: HashStable>, + V: HashStable> +{ + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let mir::Projection { + ref base, + ref elem, + } = *self; + + base.hash_stable(hcx, hasher); + elem.hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx, V> HashStable> for mir::ProjectionElem<'tcx, V> + where V: HashStable> +{ + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + mir::ProjectionElem::Deref => {} + mir::ProjectionElem::Field(field, ty) => { + field.hash_stable(hcx, hasher); + ty.hash_stable(hcx, hasher); + } + mir::ProjectionElem::Index(ref value) => { + value.hash_stable(hcx, hasher); + } + mir::ProjectionElem::ConstantIndex { offset, min_length, from_end } => { + offset.hash_stable(hcx, hasher); + min_length.hash_stable(hcx, hasher); + from_end.hash_stable(hcx, hasher); + } + mir::ProjectionElem::Subslice { from, to } => { + from.hash_stable(hcx, hasher); + to.hash_stable(hcx, hasher); + } + mir::ProjectionElem::Downcast(adt_def, variant) => { + adt_def.hash_stable(hcx, hasher); + variant.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(struct mir::VisibilityScopeData { span, parent_scope }); + +impl<'a, 'tcx> HashStable> for mir::Operand<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + + match *self { + mir::Operand::Consume(ref lvalue) => { + lvalue.hash_stable(hcx, hasher); + } + mir::Operand::Constant(ref constant) => { + constant.hash_stable(hcx, hasher); + } + } + } +} + +impl<'a, 'tcx> HashStable> for mir::Rvalue<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + + match *self { + mir::Rvalue::Use(ref operand) => { + operand.hash_stable(hcx, hasher); + } + mir::Rvalue::Repeat(ref operand, ref val) => { + operand.hash_stable(hcx, hasher); + val.hash_stable(hcx, hasher); + } + mir::Rvalue::Ref(region, borrow_kind, ref lvalue) => { + region.hash_stable(hcx, hasher); + borrow_kind.hash_stable(hcx, hasher); + lvalue.hash_stable(hcx, hasher); + } + mir::Rvalue::Len(ref lvalue) => { + lvalue.hash_stable(hcx, hasher); + } + mir::Rvalue::Cast(cast_kind, ref operand, ty) => { + cast_kind.hash_stable(hcx, hasher); + operand.hash_stable(hcx, hasher); + ty.hash_stable(hcx, hasher); + } + mir::Rvalue::BinaryOp(op, ref operand1, ref operand2) | + mir::Rvalue::CheckedBinaryOp(op, ref operand1, ref operand2) => { + op.hash_stable(hcx, hasher); + operand1.hash_stable(hcx, hasher); + operand2.hash_stable(hcx, hasher); + } + mir::Rvalue::UnaryOp(op, ref operand) => { + op.hash_stable(hcx, hasher); + operand.hash_stable(hcx, hasher); + } + mir::Rvalue::Discriminant(ref lvalue) => { + lvalue.hash_stable(hcx, hasher); + } + mir::Rvalue::Box(ty) => { + ty.hash_stable(hcx, hasher); + } + mir::Rvalue::Aggregate(ref kind, ref operands) => { + kind.hash_stable(hcx, hasher); + operands.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(enum mir::CastKind { + Misc, + ReifyFnPointer, + ClosureFnPointer, + UnsafeFnPointer, + Unsize +}); + +impl<'a, 'tcx> HashStable> for mir::AggregateKind<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + mir::AggregateKind::Tuple => {} + mir::AggregateKind::Array(t) => { + t.hash_stable(hcx, hasher); + } + mir::AggregateKind::Adt(adt_def, idx, substs, active_field) => { + adt_def.hash_stable(hcx, hasher); + idx.hash_stable(hcx, hasher); + substs.hash_stable(hcx, hasher); + active_field.hash_stable(hcx, hasher); + } + mir::AggregateKind::Closure(def_id, ref substs) => { + def_id.hash_stable(hcx, hasher); + substs.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(enum mir::BinOp { + Add, + Sub, + Mul, + Div, + Rem, + BitXor, + BitAnd, + BitOr, + Shl, + Shr, + Eq, + Lt, + Le, + Ne, + Ge, + Gt +}); + +impl_stable_hash_for!(enum mir::UnOp { + Not, + Neg +}); + + +impl_stable_hash_for!(struct mir::Constant<'tcx> { span, ty, literal }); + +impl<'a, 'tcx> HashStable> for mir::Literal<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + mir::Literal::Item { def_id, substs } => { + def_id.hash_stable(hcx, hasher); + substs.hash_stable(hcx, hasher); + } + mir::Literal::Value { ref value } => { + value.hash_stable(hcx, hasher); + } + mir::Literal::Promoted { index } => { + index.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(struct mir::Location { block, statement_index }); diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs new file mode 100644 index 000000000000..26734500001f --- /dev/null +++ b/src/librustc/ich/impls_syntax.rs @@ -0,0 +1,301 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! This module contains `HashStable` implementations for various data types +//! from libsyntax in no particular order. + +use ich::StableHashingContext; + +use std::hash as std_hash; +use std::mem; + +use syntax::ast; +use syntax::parse::token; +use syntax::tokenstream; +use syntax_pos::Span; + +use rustc_data_structures::stable_hasher::{HashStable, StableHasher, + StableHasherResult}; +use rustc_data_structures::accumulate_vec::AccumulateVec; + +impl<'a, 'tcx> HashStable> for ::syntax::symbol::InternedString { + #[inline] + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let s: &str = &**self; + s.hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable> for ast::Name { + #[inline] + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + self.as_str().hash_stable(hcx, hasher); + } +} + +impl_stable_hash_for!(enum ::syntax::ast::AsmDialect { + Att, + Intel +}); + +impl_stable_hash_for!(enum ::syntax::ext::base::MacroKind { + Bang, + Attr, + Derive +}); + + +impl_stable_hash_for!(enum ::syntax::abi::Abi { + Cdecl, + Stdcall, + Fastcall, + Vectorcall, + Aapcs, + Win64, + SysV64, + PtxKernel, + Msp430Interrupt, + X86Interrupt, + Rust, + C, + System, + RustIntrinsic, + RustCall, + PlatformIntrinsic, + Unadjusted +}); + +impl_stable_hash_for!(struct ::syntax::attr::Deprecation { since, note }); +impl_stable_hash_for!(struct ::syntax::attr::Stability { level, feature, rustc_depr }); + +impl<'a, 'tcx> HashStable> for ::syntax::attr::StabilityLevel { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + ::syntax::attr::StabilityLevel::Unstable { ref reason, ref issue } => { + reason.hash_stable(hcx, hasher); + issue.hash_stable(hcx, hasher); + } + ::syntax::attr::StabilityLevel::Stable { ref since } => { + since.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(struct ::syntax::attr::RustcDeprecation { since, reason }); + + +impl_stable_hash_for!(enum ::syntax::attr::IntType { + SignedInt(int_ty), + UnsignedInt(uint_ty) +}); + +impl_stable_hash_for!(enum ::syntax::ast::LitIntType { + Signed(int_ty), + Unsigned(int_ty), + Unsuffixed +}); + +impl_stable_hash_for_spanned!(::syntax::ast::LitKind); +impl_stable_hash_for!(enum ::syntax::ast::LitKind { + Str(value, style), + ByteStr(value), + Byte(value), + Char(value), + Int(value, lit_int_type), + Float(value, float_ty), + FloatUnsuffixed(value), + Bool(value) +}); + +impl_stable_hash_for!(enum ::syntax::ast::IntTy { Is, I8, I16, I32, I64, I128 }); +impl_stable_hash_for!(enum ::syntax::ast::UintTy { Us, U8, U16, U32, U64, U128 }); +impl_stable_hash_for!(enum ::syntax::ast::FloatTy { F32, F64 }); +impl_stable_hash_for!(enum ::syntax::ast::Unsafety { Unsafe, Normal }); +impl_stable_hash_for!(enum ::syntax::ast::Constness { Const, NotConst }); +impl_stable_hash_for!(enum ::syntax::ast::Defaultness { Default, Final }); +impl_stable_hash_for!(struct ::syntax::ast::Lifetime { id, span, name }); +impl_stable_hash_for!(enum ::syntax::ast::StrStyle { Cooked, Raw(pounds) }); +impl_stable_hash_for!(enum ::syntax::ast::AttrStyle { Outer, Inner }); + +impl<'a, 'tcx> HashStable> for [ast::Attribute] { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + // Some attributes are always ignored during hashing. + let filtered: AccumulateVec<[&ast::Attribute; 8]> = self + .iter() + .filter(|attr| { + !attr.is_sugared_doc && + attr.name().map(|name| !hcx.is_ignored_attr(name)).unwrap_or(true) + }) + .collect(); + + filtered.len().hash_stable(hcx, hasher); + for attr in filtered { + attr.hash_stable(hcx, hasher); + } + } +} + +impl<'a, 'tcx> HashStable> for ast::Attribute { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + // Make sure that these have been filtered out. + debug_assert!(self.name().map(|name| !hcx.is_ignored_attr(name)).unwrap_or(true)); + debug_assert!(!self.is_sugared_doc); + + let ast::Attribute { + id: _, + style, + ref path, + ref tokens, + is_sugared_doc: _, + span, + } = *self; + + style.hash_stable(hcx, hasher); + path.segments.len().hash_stable(hcx, hasher); + for segment in &path.segments { + segment.identifier.name.hash_stable(hcx, hasher); + } + for tt in tokens.trees() { + tt.hash_stable(hcx, hasher); + } + span.hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable> for tokenstream::TokenTree { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + tokenstream::TokenTree::Token(span, ref token) => { + span.hash_stable(hcx, hasher); + hash_token(token, hcx, hasher, span); + } + tokenstream::TokenTree::Delimited(span, ref delimited) => { + span.hash_stable(hcx, hasher); + std_hash::Hash::hash(&delimited.delim, hasher); + for sub_tt in delimited.stream().trees() { + sub_tt.hash_stable(hcx, hasher); + } + } + } + } +} + +impl<'a, 'tcx> HashStable> for tokenstream::TokenStream { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + for sub_tt in self.trees() { + sub_tt.hash_stable(hcx, hasher); + } + } +} + +fn hash_token<'a, 'tcx, W: StableHasherResult>(token: &token::Token, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher, + error_reporting_span: Span) { + mem::discriminant(token).hash_stable(hcx, hasher); + match *token { + token::Token::Eq | + token::Token::Lt | + token::Token::Le | + token::Token::EqEq | + token::Token::Ne | + token::Token::Ge | + token::Token::Gt | + token::Token::AndAnd | + token::Token::OrOr | + token::Token::Not | + token::Token::Tilde | + token::Token::At | + token::Token::Dot | + token::Token::DotDot | + token::Token::DotDotDot | + token::Token::Comma | + token::Token::Semi | + token::Token::Colon | + token::Token::ModSep | + token::Token::RArrow | + token::Token::LArrow | + token::Token::FatArrow | + token::Token::Pound | + token::Token::Dollar | + token::Token::Question | + token::Token::Underscore | + token::Token::Whitespace | + token::Token::Comment | + token::Token::Eof => {} + + token::Token::BinOp(bin_op_token) | + token::Token::BinOpEq(bin_op_token) => { + std_hash::Hash::hash(&bin_op_token, hasher); + } + + token::Token::OpenDelim(delim_token) | + token::Token::CloseDelim(delim_token) => { + std_hash::Hash::hash(&delim_token, hasher); + } + token::Token::Literal(ref lit, ref opt_name) => { + mem::discriminant(lit).hash_stable(hcx, hasher); + match *lit { + token::Lit::Byte(val) | + token::Lit::Char(val) | + token::Lit::Integer(val) | + token::Lit::Float(val) | + token::Lit::Str_(val) | + token::Lit::ByteStr(val) => val.hash_stable(hcx, hasher), + token::Lit::StrRaw(val, n) | + token::Lit::ByteStrRaw(val, n) => { + val.hash_stable(hcx, hasher); + n.hash_stable(hcx, hasher); + } + }; + opt_name.hash_stable(hcx, hasher); + } + + token::Token::Ident(ident) | + token::Token::Lifetime(ident) | + token::Token::SubstNt(ident) => ident.name.hash_stable(hcx, hasher), + + token::Token::Interpolated(ref non_terminal) => { + // FIXME(mw): This could be implemented properly. It's just a + // lot of work, since we would need to hash the AST + // in a stable way, in addition to the HIR. + // Since this is hardly used anywhere, just emit a + // warning for now. + if hcx.tcx().sess.opts.debugging_opts.incremental.is_some() { + let msg = format!("Quasi-quoting might make incremental \ + compilation very inefficient: {:?}", + non_terminal); + hcx.tcx().sess.span_warn(error_reporting_span, &msg[..]); + } + + std_hash::Hash::hash(non_terminal, hasher); + } + + token::Token::DocComment(val) | + token::Token::Shebang(val) => val.hash_stable(hcx, hasher), + } +} diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs new file mode 100644 index 000000000000..52bdb5d02406 --- /dev/null +++ b/src/librustc/ich/impls_ty.rs @@ -0,0 +1,670 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! This module contains `HashStable` implementations for various data types +//! from rustc::ty in no particular order. + +use ich::{self, StableHashingContext, NodeIdHashingMode}; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher, + StableHasherResult}; +use std::hash as std_hash; +use std::mem; +use syntax_pos::symbol::InternedString; +use ty; + +impl_stable_hash_for!(struct ty::ItemSubsts<'tcx> { substs }); + +impl<'a, 'tcx, T> HashStable> for &'tcx ty::Slice + where T: HashStable> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + (&self[..]).hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable> for ty::subst::Kind<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + self.as_type().hash_stable(hcx, hasher); + self.as_region().hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable> for ty::RegionKind<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + ty::ReErased | + ty::ReStatic | + ty::ReEmpty => { + // No variant fields to hash for these ... + } + ty::ReLateBound(db, ty::BrAnon(i)) => { + db.depth.hash_stable(hcx, hasher); + i.hash_stable(hcx, hasher); + } + ty::ReEarlyBound(ty::EarlyBoundRegion { index, name }) => { + index.hash_stable(hcx, hasher); + name.hash_stable(hcx, hasher); + } + ty::ReScope(code_extent) => { + code_extent.hash_stable(hcx, hasher); + } + ty::ReFree(ref free_region) => { + free_region.hash_stable(hcx, hasher); + } + ty::ReLateBound(..) | + ty::ReVar(..) | + ty::ReSkolemized(..) => { + bug!("TypeIdHasher: unexpected region {:?}", *self) + } + } + } +} + +impl<'a, 'tcx> HashStable> for ty::adjustment::AutoBorrow<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + ty::adjustment::AutoBorrow::Ref(ref region, mutability) => { + region.hash_stable(hcx, hasher); + mutability.hash_stable(hcx, hasher); + } + ty::adjustment::AutoBorrow::RawPtr(mutability) => { + mutability.hash_stable(hcx, hasher); + } + } + } +} + +impl<'a, 'tcx> HashStable> for ty::adjustment::Adjust<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + ty::adjustment::Adjust::NeverToAny | + ty::adjustment::Adjust::ReifyFnPointer | + ty::adjustment::Adjust::UnsafeFnPointer | + ty::adjustment::Adjust::ClosureFnPointer | + ty::adjustment::Adjust::MutToConstPointer => {} + ty::adjustment::Adjust::DerefRef { autoderefs, ref autoref, unsize } => { + autoderefs.hash_stable(hcx, hasher); + autoref.hash_stable(hcx, hasher); + unsize.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(struct ty::adjustment::Adjustment<'tcx> { kind, target }); +impl_stable_hash_for!(struct ty::MethodCall { expr_id, autoderef }); +impl_stable_hash_for!(struct ty::MethodCallee<'tcx> { def_id, ty, substs }); +impl_stable_hash_for!(struct ty::UpvarId { var_id, closure_expr_id }); +impl_stable_hash_for!(struct ty::UpvarBorrow<'tcx> { kind, region }); + +impl_stable_hash_for!(enum ty::BorrowKind { + ImmBorrow, + UniqueImmBorrow, + MutBorrow +}); + +impl<'a, 'tcx> HashStable> for ty::UpvarCapture<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + ty::UpvarCapture::ByValue => {} + ty::UpvarCapture::ByRef(ref up_var_borrow) => { + up_var_borrow.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(struct ty::FnSig<'tcx> { + inputs_and_output, + variadic, + unsafety, + abi +}); + +impl<'a, 'tcx, T> HashStable> for ty::Binder + where T: HashStable> + ty::fold::TypeFoldable<'tcx> +{ + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + hcx.tcx().anonymize_late_bound_regions(self).0.hash_stable(hcx, hasher); + } +} + +impl_stable_hash_for!(enum ty::ClosureKind { Fn, FnMut, FnOnce }); + +impl_stable_hash_for!(enum ty::Visibility { + Public, + Restricted(def_id), + Invisible +}); + +impl_stable_hash_for!(struct ty::TraitRef<'tcx> { def_id, substs }); +impl_stable_hash_for!(struct ty::TraitPredicate<'tcx> { trait_ref }); +impl_stable_hash_for!(tuple_struct ty::EquatePredicate<'tcx> { t1, t2 }); +impl_stable_hash_for!(struct ty::SubtypePredicate<'tcx> { a_is_expected, a, b }); + +impl<'a, 'tcx, A, B> HashStable> for ty::OutlivesPredicate + where A: HashStable>, + B: HashStable>, +{ + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let ty::OutlivesPredicate(ref a, ref b) = *self; + a.hash_stable(hcx, hasher); + b.hash_stable(hcx, hasher); + } +} + +impl_stable_hash_for!(struct ty::ProjectionPredicate<'tcx> { projection_ty, ty }); +impl_stable_hash_for!(struct ty::ProjectionTy<'tcx> { trait_ref, item_name }); + + +impl<'a, 'tcx> HashStable> for ty::Predicate<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + ty::Predicate::Trait(ref pred) => { + pred.hash_stable(hcx, hasher); + } + ty::Predicate::Equate(ref pred) => { + pred.hash_stable(hcx, hasher); + } + ty::Predicate::Subtype(ref pred) => { + pred.hash_stable(hcx, hasher); + } + ty::Predicate::RegionOutlives(ref pred) => { + pred.hash_stable(hcx, hasher); + } + ty::Predicate::TypeOutlives(ref pred) => { + pred.hash_stable(hcx, hasher); + } + ty::Predicate::Projection(ref pred) => { + pred.hash_stable(hcx, hasher); + } + ty::Predicate::WellFormed(ty) => { + ty.hash_stable(hcx, hasher); + } + ty::Predicate::ObjectSafe(def_id) => { + def_id.hash_stable(hcx, hasher); + } + ty::Predicate::ClosureKind(def_id, closure_kind) => { + def_id.hash_stable(hcx, hasher); + closure_kind.hash_stable(hcx, hasher); + } + } + } +} + +impl<'a, 'tcx> HashStable> for ty::AdtFlags { + fn hash_stable(&self, + _: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + std_hash::Hash::hash(self, hasher); + } +} + +impl_stable_hash_for!(struct ty::VariantDef { + did, + name, + discr, + fields, + ctor_kind +}); + +impl_stable_hash_for!(enum ty::VariantDiscr { + Explicit(def_id), + Relative(distance) +}); + +impl_stable_hash_for!(struct ty::FieldDef { + did, + name, + vis +}); + +impl<'a, 'tcx> HashStable> +for ::middle::const_val::ConstVal<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + use middle::const_val::ConstVal; + + mem::discriminant(self).hash_stable(hcx, hasher); + + match *self { + ConstVal::Float(ref value) => { + value.hash_stable(hcx, hasher); + } + ConstVal::Integral(ref value) => { + value.hash_stable(hcx, hasher); + } + ConstVal::Str(ref value) => { + value.hash_stable(hcx, hasher); + } + ConstVal::ByteStr(ref value) => { + value.hash_stable(hcx, hasher); + } + ConstVal::Bool(value) => { + value.hash_stable(hcx, hasher); + } + ConstVal::Char(value) => { + value.hash_stable(hcx, hasher); + } + ConstVal::Variant(def_id) => { + def_id.hash_stable(hcx, hasher); + } + ConstVal::Function(def_id, substs) => { + def_id.hash_stable(hcx, hasher); + substs.hash_stable(hcx, hasher); + } + ConstVal::Struct(ref name_value_map) => { + let mut values: Vec<(InternedString, &ConstVal)> = + name_value_map.iter() + .map(|(name, val)| (name.as_str(), val)) + .collect(); + + values.sort_unstable_by_key(|&(ref name, _)| name.clone()); + values.hash_stable(hcx, hasher); + } + ConstVal::Tuple(ref value) => { + value.hash_stable(hcx, hasher); + } + ConstVal::Array(ref value) => { + value.hash_stable(hcx, hasher); + } + ConstVal::Repeat(ref value, times) => { + value.hash_stable(hcx, hasher); + times.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(struct ty::ClosureSubsts<'tcx> { substs }); + +impl_stable_hash_for!(struct ty::GenericPredicates<'tcx> { + parent, + predicates +}); + +impl_stable_hash_for!(enum ty::Variance { + Covariant, + Invariant, + Contravariant, + Bivariant +}); + +impl_stable_hash_for!(enum ty::adjustment::CustomCoerceUnsized { + Struct(index) +}); + +impl<'a, 'tcx> HashStable> for ty::Generics { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let ty::Generics { + parent, + parent_regions, + parent_types, + ref regions, + ref types, + + // Reverse map to each `TypeParameterDef`'s `index` field, from + // `def_id.index` (`def_id.krate` is the same as the item's). + type_param_to_index: _, // Don't hash this + has_self, + } = *self; + + parent.hash_stable(hcx, hasher); + parent_regions.hash_stable(hcx, hasher); + parent_types.hash_stable(hcx, hasher); + regions.hash_stable(hcx, hasher); + types.hash_stable(hcx, hasher); + has_self.hash_stable(hcx, hasher); + } +} + +impl<'a, 'tcx> HashStable> for ty::RegionParameterDef { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let ty::RegionParameterDef { + name, + def_id, + index, + issue_32330: _, + pure_wrt_drop + } = *self; + + name.hash_stable(hcx, hasher); + def_id.hash_stable(hcx, hasher); + index.hash_stable(hcx, hasher); + pure_wrt_drop.hash_stable(hcx, hasher); + } +} + +impl_stable_hash_for!(struct ty::TypeParameterDef { + name, + def_id, + index, + has_default, + object_lifetime_default, + pure_wrt_drop +}); + + +impl<'a, 'tcx, T> HashStable> +for ::middle::resolve_lifetime::Set1 + where T: HashStable> +{ + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + use middle::resolve_lifetime::Set1; + + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + Set1::Empty | + Set1::Many => { + // Nothing to do. + } + Set1::One(ref value) => { + value.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(enum ::middle::resolve_lifetime::Region { + Static, + EarlyBound(index, decl), + LateBound(db_index, decl), + LateBoundAnon(db_index, anon_index), + Free(call_site_scope_data, decl) +}); + +impl_stable_hash_for!(struct ::middle::region::CallSiteScopeData { + fn_id, + body_id +}); + +impl_stable_hash_for!(struct ty::DebruijnIndex { + depth +}); + +impl_stable_hash_for!(enum ty::cast::CastKind { + CoercionCast, + PtrPtrCast, + PtrAddrCast, + AddrPtrCast, + NumericCast, + EnumCast, + PrimIntCast, + U8CharCast, + ArrayPtrCast, + FnPtrPtrCast, + FnPtrAddrCast +}); + +impl<'a, 'tcx> HashStable> for ::middle::region::CodeExtentData +{ + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + use middle::region::CodeExtentData; + + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + CodeExtentData::Misc(node_id) | + CodeExtentData::DestructionScope(node_id) => { + node_id.hash_stable(hcx, hasher); + } + CodeExtentData::CallSiteScope { fn_id, body_id } | + CodeExtentData::ParameterScope { fn_id, body_id } => { + fn_id.hash_stable(hcx, hasher); + body_id.hash_stable(hcx, hasher); + } + CodeExtentData::Remainder(block_remainder) => { + block_remainder.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(struct ::middle::region::BlockRemainder { + block, + first_statement_index +}); + +impl_stable_hash_for!(struct ty::adjustment::CoerceUnsizedInfo { + custom_kind +}); + +impl_stable_hash_for!(struct ty::FreeRegion<'tcx> { + scope, + bound_region +}); + +impl_stable_hash_for!(enum ty::BoundRegion { + BrAnon(index), + BrNamed(def_id, name), + BrFresh(index), + BrEnv +}); + +impl<'a, 'tcx> HashStable> for ty::TypeVariants<'tcx> +{ + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + use ty::TypeVariants::*; + + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + TyBool | + TyChar | + TyStr | + TyNever => { + // Nothing more to hash. + } + TyInt(int_ty) => { + int_ty.hash_stable(hcx, hasher); + } + TyUint(uint_ty) => { + uint_ty.hash_stable(hcx, hasher); + } + TyFloat(float_ty) => { + float_ty.hash_stable(hcx, hasher); + } + TyAdt(adt_def, substs) => { + adt_def.hash_stable(hcx, hasher); + substs.hash_stable(hcx, hasher); + } + TyArray(inner_ty, len) => { + inner_ty.hash_stable(hcx, hasher); + len.hash_stable(hcx, hasher); + } + TySlice(inner_ty) => { + inner_ty.hash_stable(hcx, hasher); + } + TyRawPtr(pointee_ty) => { + pointee_ty.hash_stable(hcx, hasher); + } + TyRef(region, pointee_ty) => { + region.hash_stable(hcx, hasher); + pointee_ty.hash_stable(hcx, hasher); + } + TyFnDef(def_id, substs, ref sig) => { + def_id.hash_stable(hcx, hasher); + substs.hash_stable(hcx, hasher); + sig.hash_stable(hcx, hasher); + } + TyFnPtr(ref sig) => { + sig.hash_stable(hcx, hasher); + } + TyDynamic(ref existential_predicates, region) => { + existential_predicates.hash_stable(hcx, hasher); + region.hash_stable(hcx, hasher); + } + TyClosure(def_id, closure_substs) => { + def_id.hash_stable(hcx, hasher); + closure_substs.hash_stable(hcx, hasher); + } + TyTuple(inner_tys, from_diverging_type_var) => { + inner_tys.hash_stable(hcx, hasher); + from_diverging_type_var.hash_stable(hcx, hasher); + } + TyProjection(ref projection_ty) => { + projection_ty.hash_stable(hcx, hasher); + } + TyAnon(def_id, substs) => { + def_id.hash_stable(hcx, hasher); + substs.hash_stable(hcx, hasher); + } + TyParam(param_ty) => { + param_ty.hash_stable(hcx, hasher); + } + + TyError | + TyInfer(..) => { + bug!("ty::TypeVariants::hash_stable() - Unexpected variant.") + } + } + } +} + +impl_stable_hash_for!(struct ty::ParamTy { + idx, + name +}); + +impl_stable_hash_for!(struct ty::TypeAndMut<'tcx> { + ty, + mutbl +}); + +impl<'a, 'tcx> HashStable> for ty::ExistentialPredicate<'tcx> +{ + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + ty::ExistentialPredicate::Trait(ref trait_ref) => { + trait_ref.hash_stable(hcx, hasher); + } + ty::ExistentialPredicate::Projection(ref projection) => { + projection.hash_stable(hcx, hasher); + } + ty::ExistentialPredicate::AutoTrait(def_id) => { + def_id.hash_stable(hcx, hasher); + } + } + } +} + +impl_stable_hash_for!(struct ty::ExistentialTraitRef<'tcx> { + def_id, + substs +}); + +impl_stable_hash_for!(struct ty::ExistentialProjection<'tcx> { + trait_ref, + item_name, + ty +}); + + +impl<'a, 'tcx> HashStable> for ty::TypeckTables<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let ty::TypeckTables { + ref type_relative_path_defs, + ref node_types, + ref item_substs, + ref adjustments, + ref method_map, + ref upvar_capture_map, + ref closure_tys, + ref closure_kinds, + ref liberated_fn_sigs, + ref fru_field_types, + + ref cast_kinds, + + // FIXME(#41184): This is still ignored at the moment. + lints: _, + ref used_trait_imports, + tainted_by_errors, + ref free_region_map, + } = *self; + + hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { + ich::hash_stable_nodemap(hcx, hasher, type_relative_path_defs); + ich::hash_stable_nodemap(hcx, hasher, node_types); + ich::hash_stable_nodemap(hcx, hasher, item_substs); + ich::hash_stable_nodemap(hcx, hasher, adjustments); + + ich::hash_stable_hashmap(hcx, hasher, method_map, |hcx, method_call| { + let ty::MethodCall { + expr_id, + autoderef + } = *method_call; + + let def_id = hcx.tcx().hir.local_def_id(expr_id); + (hcx.def_path_hash(def_id), autoderef) + }); + + ich::hash_stable_hashmap(hcx, hasher, upvar_capture_map, |hcx, up_var_id| { + let ty::UpvarId { + var_id, + closure_expr_id + } = *up_var_id; + + let var_def_id = hcx.tcx().hir.local_def_id(var_id); + let closure_def_id = hcx.tcx().hir.local_def_id(closure_expr_id); + (hcx.def_path_hash(var_def_id), hcx.def_path_hash(closure_def_id)) + }); + + ich::hash_stable_nodemap(hcx, hasher, closure_tys); + ich::hash_stable_nodemap(hcx, hasher, closure_kinds); + ich::hash_stable_nodemap(hcx, hasher, liberated_fn_sigs); + ich::hash_stable_nodemap(hcx, hasher, fru_field_types); + ich::hash_stable_nodemap(hcx, hasher, cast_kinds); + + ich::hash_stable_hashset(hcx, hasher, used_trait_imports, |hcx, def_id| { + hcx.def_path_hash(*def_id) + }); + + tainted_by_errors.hash_stable(hcx, hasher); + free_region_map.hash_stable(hcx, hasher); + }) + } +} diff --git a/src/librustc/ich/mod.rs b/src/librustc/ich/mod.rs index 209953f3c686..d70ed051ac41 100644 --- a/src/librustc/ich/mod.rs +++ b/src/librustc/ich/mod.rs @@ -8,13 +8,21 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -pub use self::fingerprint::Fingerprint; -pub use self::def_path_hash::DefPathHashes; -pub use self::caching_codemap_view::CachingCodemapView; +//! ICH - Incremental Compilation Hash +pub use self::fingerprint::Fingerprint; +pub use self::caching_codemap_view::CachingCodemapView; +pub use self::hcx::{StableHashingContext, NodeIdHashingMode, hash_stable_hashmap, + hash_stable_hashset, hash_stable_nodemap}; mod fingerprint; -mod def_path_hash; mod caching_codemap_view; +mod hcx; + +mod impls_const_math; +mod impls_hir; +mod impls_mir; +mod impls_ty; +mod impls_syntax; pub const ATTR_DIRTY: &'static str = "rustc_dirty"; pub const ATTR_CLEAN: &'static str = "rustc_clean"; @@ -22,6 +30,20 @@ pub const ATTR_DIRTY_METADATA: &'static str = "rustc_metadata_dirty"; pub const ATTR_CLEAN_METADATA: &'static str = "rustc_metadata_clean"; pub const ATTR_IF_THIS_CHANGED: &'static str = "rustc_if_this_changed"; pub const ATTR_THEN_THIS_WOULD_NEED: &'static str = "rustc_then_this_would_need"; +pub const ATTR_PARTITION_REUSED: &'static str = "rustc_partition_reused"; +pub const ATTR_PARTITION_TRANSLATED: &'static str = "rustc_partition_translated"; + + +pub const DEP_GRAPH_ASSERT_ATTRS: &'static [&'static str] = &[ + ATTR_IF_THIS_CHANGED, + ATTR_THEN_THIS_WOULD_NEED, + ATTR_DIRTY, + ATTR_CLEAN, + ATTR_DIRTY_METADATA, + ATTR_CLEAN_METADATA, + ATTR_PARTITION_REUSED, + ATTR_PARTITION_TRANSLATED, +]; pub const IGNORED_ATTRIBUTES: &'static [&'static str] = &[ "cfg", @@ -30,5 +52,7 @@ pub const IGNORED_ATTRIBUTES: &'static [&'static str] = &[ ATTR_DIRTY, ATTR_CLEAN, ATTR_DIRTY_METADATA, - ATTR_CLEAN_METADATA + ATTR_CLEAN_METADATA, + ATTR_PARTITION_REUSED, + ATTR_PARTITION_TRANSLATED, ]; diff --git a/src/librustc/infer/bivariate.rs b/src/librustc/infer/bivariate.rs deleted file mode 100644 index 4acb8b807d59..000000000000 --- a/src/librustc/infer/bivariate.rs +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Applies the "bivariance relationship" to two types and/or regions. -//! If (A,B) are bivariant then either A <: B or B <: A. It occurs -//! when type/lifetime parameters are unconstrained. Usually this is -//! an error, but we permit it in the specific case where a type -//! parameter is constrained in a where-clause via an associated type. -//! -//! There are several ways one could implement bivariance. You could -//! just do nothing at all, for example, or you could fully verify -//! that one of the two subtyping relationships hold. We choose to -//! thread a middle line: we relate types up to regions, but ignore -//! all region relationships. -//! -//! At one point, handling bivariance in this fashion was necessary -//! for inference, but I'm actually not sure if that is true anymore. -//! In particular, it might be enough to say (A,B) are bivariant for -//! all (A,B). - -use super::combine::CombineFields; -use super::type_variable::{BiTo}; - -use ty::{self, Ty, TyCtxt}; -use ty::TyVar; -use ty::relate::{Relate, RelateResult, TypeRelation}; - -pub struct Bivariate<'combine, 'infcx: 'combine, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> { - fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, - a_is_expected: bool, -} - -impl<'combine, 'infcx, 'gcx, 'tcx> Bivariate<'combine, 'infcx, 'gcx, 'tcx> { - pub fn new(fields: &'combine mut CombineFields<'infcx, 'gcx, 'tcx>, a_is_expected: bool) - -> Bivariate<'combine, 'infcx, 'gcx, 'tcx> - { - Bivariate { fields: fields, a_is_expected: a_is_expected } - } -} - -impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> - for Bivariate<'combine, 'infcx, 'gcx, 'tcx> -{ - fn tag(&self) -> &'static str { "Bivariate" } - - fn tcx(&self) -> TyCtxt<'infcx, 'gcx, 'tcx> { self.fields.tcx() } - - fn a_is_expected(&self) -> bool { self.a_is_expected } - - fn relate_with_variance>(&mut self, - variance: ty::Variance, - a: &T, - b: &T) - -> RelateResult<'tcx, T> - { - match variance { - // If we have Foo and Foo is invariant w/r/t A, - // and we want to assert that - // - // Foo <: Foo || - // Foo <: Foo - // - // then still A must equal B. - ty::Invariant => self.relate(a, b), - - ty::Covariant => self.relate(a, b), - ty::Bivariant => self.relate(a, b), - ty::Contravariant => self.relate(a, b), - } - } - - fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { - debug!("{}.tys({:?}, {:?})", self.tag(), - a, b); - if a == b { return Ok(a); } - - let infcx = self.fields.infcx; - let a = infcx.type_variables.borrow_mut().replace_if_possible(a); - let b = infcx.type_variables.borrow_mut().replace_if_possible(b); - match (&a.sty, &b.sty) { - (&ty::TyInfer(TyVar(a_id)), &ty::TyInfer(TyVar(b_id))) => { - infcx.type_variables.borrow_mut().relate_vars(a_id, BiTo, b_id); - Ok(a) - } - - (&ty::TyInfer(TyVar(a_id)), _) => { - self.fields.instantiate(b, BiTo, a_id, self.a_is_expected)?; - Ok(a) - } - - (_, &ty::TyInfer(TyVar(b_id))) => { - self.fields.instantiate(a, BiTo, b_id, self.a_is_expected)?; - Ok(a) - } - - _ => { - self.fields.infcx.super_combine_tys(self, a, b) - } - } - } - - fn regions(&mut self, a: &'tcx ty::Region, _: &'tcx ty::Region) - -> RelateResult<'tcx, &'tcx ty::Region> { - Ok(a) - } - - fn binders(&mut self, a: &ty::Binder, b: &ty::Binder) - -> RelateResult<'tcx, ty::Binder> - where T: Relate<'tcx> - { - let a1 = self.tcx().erase_late_bound_regions(a); - let b1 = self.tcx().erase_late_bound_regions(b); - let c = self.relate(&a1, &b1)?; - Ok(ty::Binder(c)) - } -} diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs index 5d33d6e6d2e7..1bac512e2097 100644 --- a/src/librustc/infer/combine.rs +++ b/src/librustc/infer/combine.rs @@ -32,14 +32,12 @@ // is also useful to track which value is the "expected" value in // terms of error reporting. -use super::bivariate::Bivariate; use super::equate::Equate; use super::glb::Glb; use super::lub::Lub; use super::sub::Sub; use super::InferCtxt; use super::{MiscVariable, TypeTrace}; -use super::type_variable::{RelationDir, BiTo, EqTo, SubtypeOf, SupertypeOf}; use ty::{IntType, UintType}; use ty::{self, Ty, TyCtxt}; @@ -49,7 +47,6 @@ use ty::relate::{RelateResult, TypeRelation}; use traits::PredicateObligations; use syntax::ast; -use syntax::util::small_vector::SmallVector; use syntax_pos::Span; #[derive(Clone)] @@ -60,6 +57,11 @@ pub struct CombineFields<'infcx, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> { pub obligations: PredicateObligations<'tcx>, } +#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +pub enum RelationDir { + SubtypeOf, SupertypeOf, EqTo +} + impl<'infcx, 'gcx, 'tcx> InferCtxt<'infcx, 'gcx, 'tcx> { pub fn super_combine_tys(&self, relation: &mut R, @@ -159,10 +161,6 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> { Equate::new(self, a_is_expected) } - pub fn bivariate<'a>(&'a mut self, a_is_expected: bool) -> Bivariate<'a, 'infcx, 'gcx, 'tcx> { - Bivariate::new(self, a_is_expected) - } - pub fn sub<'a>(&'a mut self, a_is_expected: bool) -> Sub<'a, 'infcx, 'gcx, 'tcx> { Sub::new(self, a_is_expected) } @@ -175,6 +173,15 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> { Glb::new(self, a_is_expected) } + /// Here dir is either EqTo, SubtypeOf, or SupertypeOf. The + /// idea is that we should ensure that the type `a_ty` is equal + /// to, a subtype of, or a supertype of (respectively) the type + /// to which `b_vid` is bound. + /// + /// Since `b_vid` has not yet been instantiated with a type, we + /// will first instantiate `b_vid` with a *generalized* version + /// of `a_ty`. Generalization introduces other inference + /// variables wherever subtyping could occur. pub fn instantiate(&mut self, a_ty: Ty<'tcx>, dir: RelationDir, @@ -182,101 +189,66 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> { a_is_expected: bool) -> RelateResult<'tcx, ()> { - // We use SmallVector here instead of Vec because this code is hot and - // it's rare that the stack length exceeds 1. - let mut stack = SmallVector::new(); - stack.push((a_ty, dir, b_vid)); - loop { - // For each turn of the loop, we extract a tuple - // - // (a_ty, dir, b_vid) - // - // to relate. Here dir is either SubtypeOf or - // SupertypeOf. The idea is that we should ensure that - // the type `a_ty` is a subtype or supertype (respectively) of the - // type to which `b_vid` is bound. - // - // If `b_vid` has not yet been instantiated with a type - // (which is always true on the first iteration, but not - // necessarily true on later iterations), we will first - // instantiate `b_vid` with a *generalized* version of - // `a_ty`. Generalization introduces other inference - // variables wherever subtyping could occur (at time of - // this writing, this means replacing free regions with - // region variables). - let (a_ty, dir, b_vid) = match stack.pop() { - None => break, - Some(e) => e, - }; - // Get the actual variable that b_vid has been inferred to - let (b_vid, b_ty) = { - let mut variables = self.infcx.type_variables.borrow_mut(); - let b_vid = variables.root_var(b_vid); - (b_vid, variables.probe_root(b_vid)) - }; + use self::RelationDir::*; - debug!("instantiate(a_ty={:?} dir={:?} b_vid={:?})", - a_ty, - dir, - b_vid); + // Get the actual variable that b_vid has been inferred to + debug_assert!(self.infcx.type_variables.borrow_mut().probe(b_vid).is_none()); - // Check whether `vid` has been instantiated yet. If not, - // make a generalized form of `ty` and instantiate with - // that. - let b_ty = match b_ty { - Some(t) => t, // ...already instantiated. - None => { // ...not yet instantiated: - // Generalize type if necessary. - let generalized_ty = match dir { - EqTo => self.generalize(a_ty, b_vid, false), - BiTo | SupertypeOf | SubtypeOf => self.generalize(a_ty, b_vid, true), - }?; - debug!("instantiate(a_ty={:?}, dir={:?}, \ - b_vid={:?}, generalized_ty={:?})", - a_ty, dir, b_vid, - generalized_ty); - self.infcx.type_variables - .borrow_mut() - .instantiate_and_push( - b_vid, generalized_ty, &mut stack); - generalized_ty - } - }; + debug!("instantiate(a_ty={:?} dir={:?} b_vid={:?})", a_ty, dir, b_vid); - // The original triple was `(a_ty, dir, b_vid)` -- now we have - // resolved `b_vid` to `b_ty`, so apply `(a_ty, dir, b_ty)`: - // - // FIXME(#16847): This code is non-ideal because all these subtype - // relations wind up attributed to the same spans. We need - // to associate causes/spans with each of the relations in - // the stack to get this right. - match dir { - BiTo => self.bivariate(a_is_expected).relate(&a_ty, &b_ty), - EqTo => self.equate(a_is_expected).relate(&a_ty, &b_ty), - SubtypeOf => self.sub(a_is_expected).relate(&a_ty, &b_ty), - SupertypeOf => self.sub(a_is_expected).relate_with_variance( - ty::Contravariant, &a_ty, &b_ty), - }?; - } + // Generalize type of `a_ty` appropriately depending on the + // direction. As an example, assume: + // + // - `a_ty == &'x ?1`, where `'x` is some free region and `?1` is an + // inference variable, + // - and `dir` == `SubtypeOf`. + // + // Then the generalized form `b_ty` would be `&'?2 ?3`, where + // `'?2` and `?3` are fresh region/type inference + // variables. (Down below, we will relate `a_ty <: b_ty`, + // adding constraints like `'x: '?2` and `?1 <: ?3`.) + let b_ty = self.generalize(a_ty, b_vid, dir == EqTo)?; + debug!("instantiate(a_ty={:?}, dir={:?}, b_vid={:?}, generalized b_ty={:?})", + a_ty, dir, b_vid, b_ty); + self.infcx.type_variables.borrow_mut().instantiate(b_vid, b_ty); + + // Finally, relate `b_ty` to `a_ty`, as described in previous comment. + // + // FIXME(#16847): This code is non-ideal because all these subtype + // relations wind up attributed to the same spans. We need + // to associate causes/spans with each of the relations in + // the stack to get this right. + match dir { + EqTo => self.equate(a_is_expected).relate(&a_ty, &b_ty), + SubtypeOf => self.sub(a_is_expected).relate(&a_ty, &b_ty), + SupertypeOf => self.sub(a_is_expected).relate_with_variance( + ty::Contravariant, &a_ty, &b_ty), + }?; Ok(()) } - /// Attempts to generalize `ty` for the type variable `for_vid`. This checks for cycle -- that - /// is, whether the type `ty` references `for_vid`. If `make_region_vars` is true, it will also - /// replace all regions with fresh variables. Returns `TyError` in the case of a cycle, `Ok` + /// Attempts to generalize `ty` for the type variable `for_vid`. + /// This checks for cycle -- that is, whether the type `ty` + /// references `for_vid`. If `is_eq_relation` is false, it will + /// also replace all regions/unbound-type-variables with fresh + /// variables. Returns `TyError` in the case of a cycle, `Ok` /// otherwise. + /// + /// Preconditions: + /// + /// - `for_vid` is a "root vid" fn generalize(&self, ty: Ty<'tcx>, for_vid: ty::TyVid, - make_region_vars: bool) + is_eq_relation: bool) -> RelateResult<'tcx, Ty<'tcx>> { let mut generalize = Generalizer { infcx: self.infcx, span: self.trace.cause.span, - for_vid: for_vid, - make_region_vars: make_region_vars, + for_vid_sub_root: self.infcx.type_variables.borrow_mut().sub_root_var(for_vid), + is_eq_relation: is_eq_relation, cycle_detected: false }; let u = ty.fold_with(&mut generalize); @@ -291,8 +263,8 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> { struct Generalizer<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> { infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>, span: Span, - for_vid: ty::TyVid, - make_region_vars: bool, + for_vid_sub_root: ty::TyVid, + is_eq_relation: bool, cycle_detected: bool, } @@ -303,17 +275,17 @@ impl<'cx, 'gcx, 'tcx> ty::fold::TypeFolder<'gcx, 'tcx> for Generalizer<'cx, 'gcx fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { // Check to see whether the type we are genealizing references - // `vid`. At the same time, also update any type variables to - // the values that they are bound to. This is needed to truly - // check for cycles, but also just makes things readable. - // - // (In particular, you could have something like `$0 = Box<$1>` - // where `$1` has already been instantiated with `Box<$0>`) + // any other type variable related to `vid` via + // subtyping. This is basically our "occurs check", preventing + // us from creating infinitely sized types. match t.sty { ty::TyInfer(ty::TyVar(vid)) => { let mut variables = self.infcx.type_variables.borrow_mut(); let vid = variables.root_var(vid); - if vid == self.for_vid { + let sub_vid = variables.sub_root_var(vid); + if sub_vid == self.for_vid_sub_root { + // If sub-roots are equal, then `for_vid` and + // `vid` are related via subtyping. self.cycle_detected = true; self.tcx().types.err } else { @@ -322,7 +294,18 @@ impl<'cx, 'gcx, 'tcx> ty::fold::TypeFolder<'gcx, 'tcx> for Generalizer<'cx, 'gcx drop(variables); self.fold_ty(u) } - None => t, + None => { + if !self.is_eq_relation { + let origin = variables.origin(vid); + let new_var_id = variables.new_var(false, origin, None); + let u = self.tcx().mk_var(new_var_id); + debug!("generalize: replacing original vid={:?} with new={:?}", + vid, u); + u + } else { + t + } + } } } } @@ -332,7 +315,7 @@ impl<'cx, 'gcx, 'tcx> ty::fold::TypeFolder<'gcx, 'tcx> for Generalizer<'cx, 'gcx } } - fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region { + fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { match *r { // Never make variables for regions bound within the type itself, // nor for erased regions. @@ -359,7 +342,7 @@ impl<'cx, 'gcx, 'tcx> ty::fold::TypeFolder<'gcx, 'tcx> for Generalizer<'cx, 'gcx ty::ReScope(..) | ty::ReVar(..) | ty::ReFree(..) => { - if !self.make_region_vars { + if self.is_eq_relation { return r; } } diff --git a/src/librustc/infer/equate.rs b/src/librustc/infer/equate.rs index bf247acec5a2..f0b179fa2e42 100644 --- a/src/librustc/infer/equate.rs +++ b/src/librustc/infer/equate.rs @@ -8,9 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use super::combine::CombineFields; +use super::combine::{CombineFields, RelationDir}; use super::{Subtype}; -use super::type_variable::{EqTo}; use ty::{self, Ty, TyCtxt}; use ty::TyVar; @@ -58,17 +57,17 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> let b = infcx.type_variables.borrow_mut().replace_if_possible(b); match (&a.sty, &b.sty) { (&ty::TyInfer(TyVar(a_id)), &ty::TyInfer(TyVar(b_id))) => { - infcx.type_variables.borrow_mut().relate_vars(a_id, EqTo, b_id); + infcx.type_variables.borrow_mut().equate(a_id, b_id); Ok(a) } (&ty::TyInfer(TyVar(a_id)), _) => { - self.fields.instantiate(b, EqTo, a_id, self.a_is_expected)?; + self.fields.instantiate(b, RelationDir::EqTo, a_id, self.a_is_expected)?; Ok(a) } (_, &ty::TyInfer(TyVar(b_id))) => { - self.fields.instantiate(a, EqTo, b_id, self.a_is_expected)?; + self.fields.instantiate(a, RelationDir::EqTo, b_id, self.a_is_expected)?; Ok(a) } @@ -79,8 +78,8 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> } } - fn regions(&mut self, a: &'tcx ty::Region, b: &'tcx ty::Region) - -> RelateResult<'tcx, &'tcx ty::Region> { + fn regions(&mut self, a: ty::Region<'tcx>, b: ty::Region<'tcx>) + -> RelateResult<'tcx, ty::Region<'tcx>> { debug!("{}.regions({:?}, {:?})", self.tag(), a, diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 21139c8dde2a..8f2bdd4e85c7 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -69,8 +69,9 @@ use traits::{ObligationCause, ObligationCauseCode}; use ty::{self, TyCtxt, TypeFoldable}; use ty::{Region, Issue32330}; use ty::error::TypeError; +use syntax::ast::DUMMY_NODE_ID; use syntax_pos::{Pos, Span}; -use errors::DiagnosticBuilder; +use errors::{DiagnosticBuilder, DiagnosticStyledString}; mod note; @@ -78,7 +79,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn note_and_explain_region(self, err: &mut DiagnosticBuilder, prefix: &str, - region: &'tcx ty::Region, + region: ty::Region<'tcx>, suffix: &str) { fn item_scope_tag(item: &hir::Item) -> &'static str { match item.node { @@ -123,14 +124,14 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { format!("{}unknown scope: {:?}{}. Please report a bug.", prefix, scope, suffix) }; - let span = match scope.span(&self.region_maps, &self.hir) { + let span = match scope.span(&self.hir) { Some(s) => s, None => { err.note(&unknown_scope()); return; } }; - let tag = match self.hir.find(scope.node_id(&self.region_maps)) { + let tag = match self.hir.find(scope.node_id()) { Some(hir_map::NodeBlock(_)) => "block", Some(hir_map::NodeExpr(expr)) => match expr.node { hir::ExprCall(..) => "call", @@ -150,7 +151,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { return; } }; - let scope_decorated_tag = match self.region_maps.code_extent_data(scope) { + let scope_decorated_tag = match *scope { region::CodeExtentData::Misc(_) => tag, region::CodeExtentData::CallSiteScope { .. } => { "scope of call-site for function" @@ -183,7 +184,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } }; - let node = fr.scope.node_id(&self.region_maps); + let node = fr.scope.map(|s| s.node_id()) + .unwrap_or(DUMMY_NODE_ID); let unknown; let tag = match self.hir.find(node) { Some(hir_map::NodeBlock(_)) | @@ -365,6 +367,262 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } + /// Given that `other_ty` is the same as a type argument for `name` in `sub`, populate `value` + /// highlighting `name` and every type argument that isn't at `pos` (which is `other_ty`), and + /// populate `other_value` with `other_ty`. + /// + /// ```text + /// Foo> + /// ^^^^--------^ this is highlighted + /// | | + /// | this type argument is exactly the same as the other type, not highlighted + /// this is highlighted + /// Bar + /// -------- this type is the same as a type argument in the other type, not highlighted + /// ``` + fn highlight_outer(&self, + mut value: &mut DiagnosticStyledString, + mut other_value: &mut DiagnosticStyledString, + name: String, + sub: &ty::subst::Substs<'tcx>, + pos: usize, + other_ty: &ty::Ty<'tcx>) { + // `value` and `other_value` hold two incomplete type representation for display. + // `name` is the path of both types being compared. `sub` + value.push_highlighted(name); + let len = sub.len(); + if len > 0 { + value.push_highlighted("<"); + } + + // Output the lifetimes fot the first type + let lifetimes = sub.regions().map(|lifetime| { + let s = format!("{}", lifetime); + if s.is_empty() { + "'_".to_string() + } else { + s + } + }).collect::>().join(", "); + if !lifetimes.is_empty() { + if sub.regions().count() < len { + value.push_normal(lifetimes + &", "); + } else { + value.push_normal(lifetimes); + } + } + + // Highlight all the type arguments that aren't at `pos` and compare the type argument at + // `pos` and `other_ty`. + for (i, type_arg) in sub.types().enumerate() { + if i == pos { + let values = self.cmp(type_arg, other_ty); + value.0.extend((values.0).0); + other_value.0.extend((values.1).0); + } else { + value.push_highlighted(format!("{}", type_arg)); + } + + if len > 0 && i != len - 1 { + value.push_normal(", "); + } + //self.push_comma(&mut value, &mut other_value, len, i); + } + if len > 0 { + value.push_highlighted(">"); + } + } + + /// If `other_ty` is the same as a type argument present in `sub`, highlight `path` in `t1_out`, + /// as that is the difference to the other type. + /// + /// For the following code: + /// + /// ```norun + /// let x: Foo> = foo::>(); + /// ``` + /// + /// The type error output will behave in the following way: + /// + /// ```text + /// Foo> + /// ^^^^--------^ this is highlighted + /// | | + /// | this type argument is exactly the same as the other type, not highlighted + /// this is highlighted + /// Bar + /// -------- this type is the same as a type argument in the other type, not highlighted + /// ``` + fn cmp_type_arg(&self, + mut t1_out: &mut DiagnosticStyledString, + mut t2_out: &mut DiagnosticStyledString, + path: String, + sub: &ty::subst::Substs<'tcx>, + other_path: String, + other_ty: &ty::Ty<'tcx>) -> Option<()> { + for (i, ta) in sub.types().enumerate() { + if &ta == other_ty { + self.highlight_outer(&mut t1_out, &mut t2_out, path, sub, i, &other_ty); + return Some(()); + } + if let &ty::TyAdt(def, _) = &ta.sty { + let path_ = self.tcx.item_path_str(def.did.clone()); + if path_ == other_path { + self.highlight_outer(&mut t1_out, &mut t2_out, path, sub, i, &other_ty); + return Some(()); + } + } + } + None + } + + /// Add a `,` to the type representation only if it is appropriate. + fn push_comma(&self, + value: &mut DiagnosticStyledString, + other_value: &mut DiagnosticStyledString, + len: usize, + pos: usize) { + if len > 0 && pos != len - 1 { + value.push_normal(", "); + other_value.push_normal(", "); + } + } + + /// Compare two given types, eliding parts that are the same between them and highlighting + /// relevant differences, and return two representation of those types for highlighted printing. + fn cmp(&self, t1: ty::Ty<'tcx>, t2: ty::Ty<'tcx>) + -> (DiagnosticStyledString, DiagnosticStyledString) + { + match (&t1.sty, &t2.sty) { + (&ty::TyAdt(def1, sub1), &ty::TyAdt(def2, sub2)) => { + let mut values = (DiagnosticStyledString::new(), DiagnosticStyledString::new()); + let path1 = self.tcx.item_path_str(def1.did.clone()); + let path2 = self.tcx.item_path_str(def2.did.clone()); + if def1.did == def2.did { + // Easy case. Replace same types with `_` to shorten the output and highlight + // the differing ones. + // let x: Foo = y::>(); + // Foo + // Foo + // --- ^ type argument elided + // | + // highlighted in output + values.0.push_normal(path1); + values.1.push_normal(path2); + + // Only draw `<...>` if there're lifetime/type arguments. + let len = sub1.len(); + if len > 0 { + values.0.push_normal("<"); + values.1.push_normal("<"); + } + + fn lifetime_display(lifetime: Region) -> String { + let s = format!("{}", lifetime); + if s.is_empty() { + "'_".to_string() + } else { + s + } + } + // At one point we'd like to elide all lifetimes here, they are irrelevant for + // all diagnostics that use this output + // + // Foo<'x, '_, Bar> + // Foo<'y, '_, Qux> + // ^^ ^^ --- type arguments are not elided + // | | + // | elided as they were the same + // not elided, they were different, but irrelevant + let lifetimes = sub1.regions().zip(sub2.regions()); + for (i, lifetimes) in lifetimes.enumerate() { + let l1 = lifetime_display(lifetimes.0); + let l2 = lifetime_display(lifetimes.1); + if l1 == l2 { + values.0.push_normal("'_"); + values.1.push_normal("'_"); + } else { + values.0.push_highlighted(l1); + values.1.push_highlighted(l2); + } + self.push_comma(&mut values.0, &mut values.1, len, i); + } + + // We're comparing two types with the same path, so we compare the type + // arguments for both. If they are the same, do not highlight and elide from the + // output. + // Foo<_, Bar> + // Foo<_, Qux> + // ^ elided type as this type argument was the same in both sides + let type_arguments = sub1.types().zip(sub2.types()); + let regions_len = sub1.regions().collect::>().len(); + for (i, (ta1, ta2)) in type_arguments.enumerate() { + let i = i + regions_len; + if ta1 == ta2 { + values.0.push_normal("_"); + values.1.push_normal("_"); + } else { + let (x1, x2) = self.cmp(ta1, ta2); + (values.0).0.extend(x1.0); + (values.1).0.extend(x2.0); + } + self.push_comma(&mut values.0, &mut values.1, len, i); + } + + // Close the type argument bracket. + // Only draw `<...>` if there're lifetime/type arguments. + if len > 0 { + values.0.push_normal(">"); + values.1.push_normal(">"); + } + values + } else { + // Check for case: + // let x: Foo = foo::>(); + // Foo + // ------- this type argument is exactly the same as the other type + // Bar + if self.cmp_type_arg(&mut values.0, + &mut values.1, + path1.clone(), + sub1, + path2.clone(), + &t2).is_some() { + return values; + } + // Check for case: + // let x: Bar = y:>>(); + // Bar + // Foo> + // ------- this type argument is exactly the same as the other type + if self.cmp_type_arg(&mut values.1, + &mut values.0, + path2, + sub2, + path1, + &t1).is_some() { + return values; + } + + // We couldn't find anything in common, highlight everything. + // let x: Bar = y::>(); + (DiagnosticStyledString::highlighted(format!("{}", t1)), + DiagnosticStyledString::highlighted(format!("{}", t2))) + } + } + _ => { + if t1 == t2 { + // The two types are the same, elide and don't highlight. + (DiagnosticStyledString::normal("_"), DiagnosticStyledString::normal("_")) + } else { + // We couldn't find anything in common, highlight everything. + (DiagnosticStyledString::highlighted(format!("{}", t1)), + DiagnosticStyledString::highlighted(format!("{}", t2))) + } + } + } + } + pub fn note_type_err(&self, diag: &mut DiagnosticBuilder<'tcx>, cause: &ObligationCause<'tcx>, @@ -397,14 +655,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { if let Some((expected, found)) = expected_found { match (terr, is_simple_error, expected == found) { - (&TypeError::Sorts(ref values), false, true) => { + (&TypeError::Sorts(ref values), false, true) => { diag.note_expected_found_extra( - &"type", &expected, &found, + &"type", expected, found, &format!(" ({})", values.expected.sort_string(self.tcx)), &format!(" ({})", values.found.sort_string(self.tcx))); } (_, false, _) => { - diag.note_expected_found(&"type", &expected, &found); + diag.note_expected_found(&"type", expected, found); } _ => (), } @@ -426,30 +684,26 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { { debug!("note_issue_32330: terr={:?}", terr); match *terr { - TypeError::RegionsInsufficientlyPolymorphic(_, &Region::ReVar(vid)) | - TypeError::RegionsOverlyPolymorphic(_, &Region::ReVar(vid)) => { - match self.region_vars.var_origin(vid) { - RegionVariableOrigin::EarlyBoundRegion(_, _, Some(Issue32330 { - fn_def_id, - region_name - })) => { - diag.note( - &format!("lifetime parameter `{0}` declared on fn `{1}` \ - appears only in the return type, \ - but here is required to be higher-ranked, \ - which means that `{0}` must appear in both \ - argument and return types", - region_name, - self.tcx.item_path_str(fn_def_id))); - diag.note( - &format!("this error is the result of a recent bug fix; \ - for more information, see issue #33685 \ - ")); - } - _ => { } - } + TypeError::RegionsInsufficientlyPolymorphic(_, _, Some(box Issue32330 { + fn_def_id, region_name + })) | + TypeError::RegionsOverlyPolymorphic(_, _, Some(box Issue32330 { + fn_def_id, region_name + })) => { + diag.note( + &format!("lifetime parameter `{0}` declared on fn `{1}` \ + appears only in the return type, \ + but here is required to be higher-ranked, \ + which means that `{0}` must appear in both \ + argument and return types", + region_name, + self.tcx.item_path_str(fn_def_id))); + diag.note( + &format!("this error is the result of a recent bug fix; \ + for more information, see issue #33685 \ + ")); } - _ => { } + _ => {} } } @@ -476,32 +730,46 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { diag } - /// Returns a string of the form "expected `{}`, found `{}`". - fn values_str(&self, values: &ValuePairs<'tcx>) -> Option<(String, String)> { + fn values_str(&self, values: &ValuePairs<'tcx>) + -> Option<(DiagnosticStyledString, DiagnosticStyledString)> + { match *values { - infer::Types(ref exp_found) => self.expected_found_str(exp_found), + infer::Types(ref exp_found) => self.expected_found_str_ty(exp_found), infer::TraitRefs(ref exp_found) => self.expected_found_str(exp_found), infer::PolyTraitRefs(ref exp_found) => self.expected_found_str(exp_found), } } + fn expected_found_str_ty(&self, + exp_found: &ty::error::ExpectedFound>) + -> Option<(DiagnosticStyledString, DiagnosticStyledString)> { + let exp_found = self.resolve_type_vars_if_possible(exp_found); + if exp_found.references_error() { + return None; + } + + Some(self.cmp(exp_found.expected, exp_found.found)) + } + + /// Returns a string of the form "expected `{}`, found `{}`". fn expected_found_str>( &self, exp_found: &ty::error::ExpectedFound) - -> Option<(String, String)> + -> Option<(DiagnosticStyledString, DiagnosticStyledString)> { let exp_found = self.resolve_type_vars_if_possible(exp_found); if exp_found.references_error() { return None; } - Some((format!("{}", exp_found.expected), format!("{}", exp_found.found))) + Some((DiagnosticStyledString::highlighted(format!("{}", exp_found.expected)), + DiagnosticStyledString::highlighted(format!("{}", exp_found.found)))) } fn report_generic_bound_failure(&self, origin: SubregionOrigin<'tcx>, bound_kind: GenericKind<'tcx>, - sub: &'tcx Region) + sub: Region<'tcx>) { // FIXME: it would be better to report the first error message // with the span of the parameter itself, rather than the span @@ -580,9 +848,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { fn report_sub_sup_conflict(&self, var_origin: RegionVariableOrigin, sub_origin: SubregionOrigin<'tcx>, - sub_region: &'tcx Region, + sub_region: Region<'tcx>, sup_origin: SubregionOrigin<'tcx>, - sup_region: &'tcx Region) { + sup_region: Region<'tcx>) { let mut err = self.report_inference_failure(var_origin); self.tcx.note_and_explain_region(&mut err, diff --git a/src/librustc/infer/error_reporting/note.rs b/src/librustc/infer/error_reporting/note.rs index 8f8b2603dad8..49952d81cbb0 100644 --- a/src/librustc/infer/error_reporting/note.rs +++ b/src/librustc/infer/error_reporting/note.rs @@ -20,6 +20,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { match *origin { infer::Subtype(ref trace) => { if let Some((expected, found)) = self.values_str(&trace.values) { + let expected = expected.content(); + let found = found.content(); // FIXME: do we want a "the" here? err.span_note(trace.cause.span, &format!("...so that {} (expected {}, found {})", @@ -144,8 +146,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub(super) fn report_concrete_failure(&self, origin: SubregionOrigin<'tcx>, - sub: &'tcx Region, - sup: &'tcx Region) + sub: Region<'tcx>, + sup: Region<'tcx>) -> DiagnosticBuilder<'tcx> { match origin { infer::Subtype(trace) => { diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs index 697a1ecadc45..ad67ef9a127d 100644 --- a/src/librustc/infer/freshen.rs +++ b/src/librustc/infer/freshen.rs @@ -83,7 +83,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> { self.infcx.tcx } - fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region { + fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { match *r { ty::ReEarlyBound(..) | ty::ReLateBound(..) => { @@ -99,7 +99,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> { ty::ReEmpty | ty::ReErased => { // replace all free regions with 'erased - self.tcx().mk_region(ty::ReErased) + self.tcx().types.re_erased } } } diff --git a/src/librustc/infer/fudge.rs b/src/librustc/infer/fudge.rs index 806b94486615..a8bc33f772d5 100644 --- a/src/librustc/infer/fudge.rs +++ b/src/librustc/infer/fudge.rs @@ -8,7 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use ty::{self, TyCtxt}; +use infer::type_variable::TypeVariableMap; +use ty::{self, Ty, TyCtxt}; use ty::fold::{TypeFoldable, TypeFolder}; use super::InferCtxt; @@ -54,57 +55,52 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { /// the actual types (`?T`, `Option(&self, origin: &RegionVariableOrigin, f: F) -> Result where F: FnOnce() -> Result, T: TypeFoldable<'tcx>, { - let (region_vars, value) = self.probe(|snapshot| { - let vars_at_start = self.type_variables.borrow().num_vars(); + debug!("fudge_regions_if_ok(origin={:?})", origin); + let (type_variables, region_vars, value) = self.probe(|snapshot| { match f() { Ok(value) => { let value = self.resolve_type_vars_if_possible(&value); // At this point, `value` could in principle refer - // to regions that have been created during the - // snapshot (we assert below that `f()` does not - // create any new type variables, so there - // shouldn't be any of those). Once we exit - // `probe()`, those are going to be popped, so we - // will have to eliminate any references to them. + // to types/regions that have been created during + // the snapshot. Once we exit `probe()`, those are + // going to be popped, so we will have to + // eliminate any references to them. - assert_eq!(self.type_variables.borrow().num_vars(), vars_at_start, - "type variables were created during fudge_regions_if_ok"); + let type_variables = + self.type_variables.borrow_mut().types_created_since_snapshot( + &snapshot.type_snapshot); let region_vars = self.region_vars.vars_created_since_snapshot( &snapshot.region_vars_snapshot); - Ok((region_vars, value)) + Ok((type_variables, region_vars, value)) } Err(e) => Err(e), } })?; // At this point, we need to replace any of the now-popped - // region variables that appear in `value` with a fresh region - // variable. We can't do this during the probe because they - // would just get popped then too. =) + // type/region variables that appear in `value` with a fresh + // variable of the appropriate kind. We can't do this during + // the probe because they would just get popped then too. =) // Micro-optimization: if no variables have been created, then // `value` can't refer to any of them. =) So we can just return it. - if region_vars.is_empty() { + if type_variables.is_empty() && region_vars.is_empty() { return Ok(value); } let mut fudger = RegionFudger { infcx: self, + type_variables: &type_variables, region_vars: ®ion_vars, origin: origin }; @@ -115,6 +111,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub struct RegionFudger<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, + type_variables: &'a TypeVariableMap, region_vars: &'a Vec, origin: &'a RegionVariableOrigin, } @@ -124,7 +121,33 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionFudger<'a, 'gcx, 'tcx> { self.infcx.tcx } - fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region { + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + match ty.sty { + ty::TyInfer(ty::InferTy::TyVar(vid)) => { + match self.type_variables.get(&vid) { + None => { + // This variable was created before the + // "fudging". Since we refresh all type + // variables to their binding anyhow, we know + // that it is unbound, so we can just return + // it. + debug_assert!(self.infcx.type_variables.borrow_mut().probe(vid).is_none()); + ty + } + + Some(&origin) => { + // This variable was created during the + // fudging. Recreate it with a fresh variable + // here. + self.infcx.next_ty_var(origin) + } + } + } + _ => ty.super_fold_with(self), + } + } + + fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { match *r { ty::ReVar(v) if self.region_vars.contains(&v) => { self.infcx.next_region_var(self.origin.clone()) diff --git a/src/librustc/infer/glb.rs b/src/librustc/infer/glb.rs index 8ccadc6b2af0..d7afeba7dc96 100644 --- a/src/librustc/infer/glb.rs +++ b/src/librustc/infer/glb.rs @@ -49,7 +49,8 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> match variance { ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b), ty::Covariant => self.relate(a, b), - ty::Bivariant => self.fields.bivariate(self.a_is_expected).relate(a, b), + // FIXME(#41044) -- not correct, need test + ty::Bivariant => Ok(a.clone()), ty::Contravariant => self.fields.lub(self.a_is_expected).relate(a, b), } } @@ -58,8 +59,8 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> lattice::super_lattice_tys(self, a, b) } - fn regions(&mut self, a: &'tcx ty::Region, b: &'tcx ty::Region) - -> RelateResult<'tcx, &'tcx ty::Region> { + fn regions(&mut self, a: ty::Region<'tcx>, b: ty::Region<'tcx>) + -> RelateResult<'tcx, ty::Region<'tcx>> { debug!("{}.regions({:?}, {:?})", self.tag(), a, diff --git a/src/librustc/infer/higher_ranked/mod.rs b/src/librustc/infer/higher_ranked/mod.rs index e919f025409c..09f909ef399d 100644 --- a/src/librustc/infer/higher_ranked/mod.rs +++ b/src/librustc/infer/higher_ranked/mod.rs @@ -15,6 +15,7 @@ use super::{CombinedSnapshot, InferCtxt, LateBoundRegion, HigherRankedType, + RegionVariableOrigin, SubregionOrigin, SkolemizationMap}; use super::combine::CombineFields; @@ -268,9 +269,9 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { snapshot: &CombinedSnapshot, debruijn: ty::DebruijnIndex, new_vars: &[ty::RegionVid], - a_map: &FxHashMap, - r0: &'tcx ty::Region) - -> &'tcx ty::Region { + a_map: &FxHashMap>, + r0: ty::Region<'tcx>) + -> ty::Region<'tcx> { // Regions that pre-dated the LUB computation stay as they are. if !is_var_in_set(new_vars, r0) { assert!(!r0.is_bound()); @@ -283,7 +284,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { // Variables created during LUB computation which are // *related* to regions that pre-date the LUB computation // stay as they are. - if !tainted.iter().all(|r| is_var_in_set(new_vars, *r)) { + if !tainted.iter().all(|&r| is_var_in_set(new_vars, r)) { debug!("generalize_region(r0={:?}): \ non-new-variables found in {:?}", r0, tainted); @@ -364,11 +365,11 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { snapshot: &CombinedSnapshot, debruijn: ty::DebruijnIndex, new_vars: &[ty::RegionVid], - a_map: &FxHashMap, + a_map: &FxHashMap>, a_vars: &[ty::RegionVid], b_vars: &[ty::RegionVid], - r0: &'tcx ty::Region) - -> &'tcx ty::Region { + r0: ty::Region<'tcx>) + -> ty::Region<'tcx> { if !is_var_in_set(new_vars, r0) { assert!(!r0.is_bound()); return r0; @@ -433,8 +434,8 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { fn rev_lookup<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, span: Span, - a_map: &FxHashMap, - r: &'tcx ty::Region) -> &'tcx ty::Region + a_map: &FxHashMap>, + r: ty::Region<'tcx>) -> ty::Region<'tcx> { for (a_br, a_r) in a_map { if *a_r == r { @@ -449,14 +450,14 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { fn fresh_bound_variable<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, debruijn: ty::DebruijnIndex) - -> &'tcx ty::Region { + -> ty::Region<'tcx> { infcx.region_vars.new_bound(debruijn) } } } fn var_ids<'a, 'gcx, 'tcx>(fields: &CombineFields<'a, 'gcx, 'tcx>, - map: &FxHashMap) + map: &FxHashMap>) -> Vec { map.iter() .map(|(_, &r)| match *r { @@ -471,7 +472,7 @@ fn var_ids<'a, 'gcx, 'tcx>(fields: &CombineFields<'a, 'gcx, 'tcx>, .collect() } -fn is_var_in_set(new_vars: &[ty::RegionVid], r: &ty::Region) -> bool { +fn is_var_in_set(new_vars: &[ty::RegionVid], r: ty::Region) -> bool { match *r { ty::ReVar(ref v) => new_vars.iter().any(|x| x == v), _ => false @@ -483,7 +484,7 @@ fn fold_regions_in<'a, 'gcx, 'tcx, T, F>(tcx: TyCtxt<'a, 'gcx, 'tcx>, mut fldr: F) -> T where T: TypeFoldable<'tcx>, - F: FnMut(&'tcx ty::Region, ty::DebruijnIndex) -> &'tcx ty::Region, + F: FnMut(ty::Region<'tcx>, ty::DebruijnIndex) -> ty::Region<'tcx>, { tcx.fold_regions(unbound_value, &mut false, |region, current_depth| { // we should only be encountering "escaping" late-bound regions here, @@ -501,9 +502,9 @@ fn fold_regions_in<'a, 'gcx, 'tcx, T, F>(tcx: TyCtxt<'a, 'gcx, 'tcx>, impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { fn tainted_regions(&self, snapshot: &CombinedSnapshot, - r: &'tcx ty::Region, + r: ty::Region<'tcx>, directions: TaintDirections) - -> FxHashSet<&'tcx ty::Region> { + -> FxHashSet> { self.region_vars.tainted(&snapshot.region_vars_snapshot, r, directions) } @@ -656,14 +657,27 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { skol_br, tainted_region); + let issue_32330 = if let &ty::ReVar(vid) = tainted_region { + match self.region_vars.var_origin(vid) { + RegionVariableOrigin::EarlyBoundRegion(_, _, issue_32330) => { + issue_32330.map(Box::new) + } + _ => None + } + } else { + None + }; + if overly_polymorphic { debug!("Overly polymorphic!"); return Err(TypeError::RegionsOverlyPolymorphic(skol_br, - tainted_region)); + tainted_region, + issue_32330)); } else { debug!("Not as polymorphic!"); return Err(TypeError::RegionsInsufficientlyPolymorphic(skol_br, - tainted_region)); + tainted_region, + issue_32330)); } } } @@ -717,7 +731,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // region back to the `ty::BoundRegion` that it originally // represented. Because `leak_check` passed, we know that // these taint sets are mutually disjoint. - let inv_skol_map: FxHashMap<&'tcx ty::Region, ty::BoundRegion> = + let inv_skol_map: FxHashMap, ty::BoundRegion> = skol_map .iter() .flat_map(|(&skol_br, &skol)| { diff --git a/src/librustc/infer/lattice.rs b/src/librustc/infer/lattice.rs index f7b26a918b3a..d4d090f0153d 100644 --- a/src/librustc/infer/lattice.rs +++ b/src/librustc/infer/lattice.rs @@ -44,6 +44,10 @@ pub trait LatticeDir<'f, 'gcx: 'f+'tcx, 'tcx: 'f> : TypeRelation<'f, 'gcx, 'tcx> // Relates the type `v` to `a` and `b` such that `v` represents // the LUB/GLB of `a` and `b` as appropriate. + // + // Subtle hack: ordering *may* be significant here. This method + // relates `v` to `a` first, which may help us to avoid unecessary + // type variable obligations. See caller for details. fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()>; } @@ -74,7 +78,29 @@ pub fn super_lattice_tys<'a, 'gcx, 'tcx, L>(this: &mut L, Ok(v) } - (&ty::TyInfer(TyVar(..)), _) | + // If one side is known to be a variable and one is not, + // create a variable (`v`) to represent the LUB. Make sure to + // relate `v` to the non-type-variable first (by passing it + // first to `relate_bound`). Otherwise, we would produce a + // subtype obligation that must then be processed. + // + // Example: if the LHS is a type variable, and RHS is + // `Box`, then we current compare `v` to the RHS first, + // which will instantiate `v` with `Box`. Then when `v` + // is compared to the LHS, we instantiate LHS with `Box`. + // But if we did in reverse order, we would create a `v <: + // LHS` (or vice versa) constraint and then instantiate + // `v`. This would require further processing to achieve same + // end-result; in partiular, this screws up some of the logic + // in coercion, which expects LUB to figure out that the LHS + // is (e.g.) `Box`. A more obvious solution might be to + // iterate on the subtype obligations that are returned, but I + // think this suffices. -nmatsakis + (&ty::TyInfer(TyVar(..)), _) => { + let v = infcx.next_ty_var(TypeVariableOrigin::LatticeVariable(this.cause().span)); + this.relate_bound(v, b, a)?; + Ok(v) + } (_, &ty::TyInfer(TyVar(..))) => { let v = infcx.next_ty_var(TypeVariableOrigin::LatticeVariable(this.cause().span)); this.relate_bound(v, a, b)?; diff --git a/src/librustc/infer/lub.rs b/src/librustc/infer/lub.rs index 89571dea10c3..04b470b29fc5 100644 --- a/src/librustc/infer/lub.rs +++ b/src/librustc/infer/lub.rs @@ -49,7 +49,8 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> match variance { ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b), ty::Covariant => self.relate(a, b), - ty::Bivariant => self.fields.bivariate(self.a_is_expected).relate(a, b), + // FIXME(#41044) -- not correct, need test + ty::Bivariant => Ok(a.clone()), ty::Contravariant => self.fields.glb(self.a_is_expected).relate(a, b), } } @@ -58,8 +59,8 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> lattice::super_lattice_tys(self, a, b) } - fn regions(&mut self, a: &'tcx ty::Region, b: &'tcx ty::Region) - -> RelateResult<'tcx, &'tcx ty::Region> { + fn regions(&mut self, a: ty::Region<'tcx>, b: ty::Region<'tcx>) + -> RelateResult<'tcx, ty::Region<'tcx>> { debug!("{}.regions({:?}, {:?})", self.tag(), a, diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index b07ef4dfd448..e91af21c6db2 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -20,7 +20,8 @@ pub use self::region_inference::{GenericKind, VerifyBound}; use hir::def_id::DefId; use hir; -use middle::free_region::FreeRegionMap; +use middle::free_region::{FreeRegionMap, RegionRelations}; +use middle::region::RegionMaps; use middle::mem_categorization as mc; use middle::mem_categorization::McResult; use middle::lang_items; @@ -48,7 +49,6 @@ use self::region_inference::{RegionVarBindings, RegionSnapshot}; use self::type_variable::TypeVariableOrigin; use self::unify_key::ToType; -mod bivariate; mod combine; mod equate; pub mod error_reporting; @@ -200,15 +200,13 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { // `tained_by_errors`) to avoid reporting certain kinds of errors. err_count_on_creation: usize, - // This flag is used for debugging, and is set to true if there are - // any obligations set during the current snapshot. In that case, the - // snapshot can't be rolled back. - pub obligations_in_snapshot: Cell, + // This flag is true while there is an active snapshot. + in_snapshot: Cell, } /// A map returned by `skolemize_late_bound_regions()` indicating the skolemized /// region that each late-bound region was replaced with. -pub type SkolemizationMap<'tcx> = FxHashMap; +pub type SkolemizationMap<'tcx> = FxHashMap>; /// See `error_reporting` module for more details #[derive(Clone, Debug)] @@ -453,7 +451,7 @@ impl<'a, 'tcx> InferEnv<'a, 'tcx> for hir::BodyId { Option>, Option>) { let item_id = tcx.hir.body_owner(self); - (Some(tcx.item_tables(tcx.hir.local_def_id(item_id))), + (Some(tcx.typeck_tables_of(tcx.hir.local_def_id(item_id))), None, Some(ty::ParameterEnvironment::for_item(tcx, item_id))) } @@ -508,7 +506,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> { projection_mode: Reveal::UserFacing, tainted_by_errors_flag: Cell::new(false), err_count_on_creation: self.sess.err_count(), - obligations_in_snapshot: Cell::new(false), + in_snapshot: Cell::new(false), } } } @@ -546,13 +544,13 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> { projection_mode: projection_mode, tainted_by_errors_flag: Cell::new(false), err_count_on_creation: tcx.sess.err_count(), - obligations_in_snapshot: Cell::new(false), + in_snapshot: Cell::new(false), })) } } impl ExpectedFound { - fn new(a_is_expected: bool, a: T, b: T) -> Self { + pub fn new(a_is_expected: bool, a: T, b: T) -> Self { if a_is_expected { ExpectedFound {expected: a, found: b} } else { @@ -574,7 +572,7 @@ pub struct CombinedSnapshot { int_snapshot: unify::Snapshot, float_snapshot: unify::Snapshot, region_vars_snapshot: RegionSnapshot, - obligations_in_snapshot: bool, + was_in_snapshot: bool, } /// Helper trait for shortening the lifetimes inside a @@ -735,6 +733,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.projection_mode } + pub fn is_in_snapshot(&self) -> bool { + self.in_snapshot.get() + } + pub fn freshen>(&self, t: T) -> T { t.fold_with(&mut self.freshener()) } @@ -862,38 +864,37 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { result.map(move |t| InferOk { value: t, obligations: fields.obligations }) } - // Clear the "obligations in snapshot" flag, invoke the closure, + // Clear the "currently in a snapshot" flag, invoke the closure, // then restore the flag to its original value. This flag is a // debugging measure designed to detect cases where we start a - // snapshot, create type variables, register obligations involving - // those type variables in the fulfillment cx, and then have to - // unroll the snapshot, leaving "dangling type variables" behind. - // In such cases, the flag will be set by the fulfillment cx, and - // an assertion will fail when rolling the snapshot back. Very - // useful, much better than grovelling through megabytes of - // RUST_LOG output. + // snapshot, create type variables, and register obligations + // which may involve those type variables in the fulfillment cx, + // potentially leaving "dangling type variables" behind. + // In such cases, an assertion will fail when attempting to + // register obligations, within a snapshot. Very useful, much + // better than grovelling through megabytes of RUST_LOG output. // - // HOWEVER, in some cases the flag is wrong. In particular, we + // HOWEVER, in some cases the flag is unhelpful. In particular, we // sometimes create a "mini-fulfilment-cx" in which we enroll // obligations. As long as this fulfillment cx is fully drained // before we return, this is not a problem, as there won't be any // escaping obligations in the main cx. In those cases, you can // use this function. - pub fn save_and_restore_obligations_in_snapshot_flag(&self, func: F) -> R + pub fn save_and_restore_in_snapshot_flag(&self, func: F) -> R where F: FnOnce(&Self) -> R { - let flag = self.obligations_in_snapshot.get(); - self.obligations_in_snapshot.set(false); + let flag = self.in_snapshot.get(); + self.in_snapshot.set(false); let result = func(self); - self.obligations_in_snapshot.set(flag); + self.in_snapshot.set(flag); result } fn start_snapshot(&self) -> CombinedSnapshot { debug!("start_snapshot()"); - let obligations_in_snapshot = self.obligations_in_snapshot.get(); - self.obligations_in_snapshot.set(false); + let in_snapshot = self.in_snapshot.get(); + self.in_snapshot.set(true); CombinedSnapshot { projection_cache_snapshot: self.projection_cache.borrow_mut().snapshot(), @@ -901,7 +902,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { int_snapshot: self.int_unification_table.borrow_mut().snapshot(), float_snapshot: self.float_unification_table.borrow_mut().snapshot(), region_vars_snapshot: self.region_vars.start_snapshot(), - obligations_in_snapshot: obligations_in_snapshot, + was_in_snapshot: in_snapshot, } } @@ -912,10 +913,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { int_snapshot, float_snapshot, region_vars_snapshot, - obligations_in_snapshot } = snapshot; + was_in_snapshot } = snapshot; - assert!(!self.obligations_in_snapshot.get()); - self.obligations_in_snapshot.set(obligations_in_snapshot); + self.in_snapshot.set(was_in_snapshot); self.projection_cache .borrow_mut() @@ -940,9 +940,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { int_snapshot, float_snapshot, region_vars_snapshot, - obligations_in_snapshot } = snapshot; + was_in_snapshot } = snapshot; - self.obligations_in_snapshot.set(obligations_in_snapshot); + self.in_snapshot.set(was_in_snapshot); self.projection_cache .borrow_mut() @@ -1009,7 +1009,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } pub fn add_given(&self, - sub: ty::FreeRegion, + sub: ty::FreeRegion<'tcx>, sup: ty::RegionVid) { self.region_vars.add_given(sub, sup); @@ -1037,9 +1037,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.probe(|_| { let origin = &ObligationCause::dummy(); let trace = TypeTrace::types(origin, true, a, b); - self.sub(true, trace, &a, &b).map(|InferOk { obligations, .. }| { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); + self.sub(true, trace, &a, &b).map(|InferOk { obligations: _, .. }| { + // Ignore obligations, since we are unrolling + // everything anyway. }) }) } @@ -1108,8 +1108,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub fn sub_regions(&self, origin: SubregionOrigin<'tcx>, - a: &'tcx ty::Region, - b: &'tcx ty::Region) { + a: ty::Region<'tcx>, + b: ty::Region<'tcx>) { debug!("sub_regions({:?} <: {:?})", a, b); self.region_vars.make_subregion(origin, a, b); } @@ -1130,6 +1130,43 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { }) } + pub fn subtype_predicate(&self, + cause: &ObligationCause<'tcx>, + predicate: &ty::PolySubtypePredicate<'tcx>) + -> Option> + { + // Subtle: it's ok to skip the binder here and resolve because + // `shallow_resolve` just ignores anything that is not a type + // variable, and because type variable's can't (at present, at + // least) capture any of the things bound by this binder. + // + // Really, there is no *particular* reason to do this + // `shallow_resolve` here except as a + // micro-optimization. Naturally I could not + // resist. -nmatsakis + let two_unbound_type_vars = { + let a = self.shallow_resolve(predicate.skip_binder().a); + let b = self.shallow_resolve(predicate.skip_binder().b); + a.is_ty_var() && b.is_ty_var() + }; + + if two_unbound_type_vars { + // Two unbound type variables? Can't make progress. + return None; + } + + Some(self.commit_if_ok(|snapshot| { + let (ty::SubtypePredicate { a_is_expected, a, b}, skol_map) = + self.skolemize_late_bound_regions(predicate, snapshot); + + let cause_span = cause.span; + let ok = self.sub_types(a_is_expected, cause, a, b)?; + self.leak_check(false, cause_span, &skol_map, snapshot)?; + self.pop_skolemized(skol_map, snapshot); + Ok(ok.unit()) + })) + } + pub fn region_outlives_predicate(&self, cause: &traits::ObligationCause<'tcx>, predicate: &ty::PolyRegionOutlivesPredicate<'tcx>) @@ -1174,7 +1211,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } pub fn next_region_var(&self, origin: RegionVariableOrigin) - -> &'tcx ty::Region { + -> ty::Region<'tcx> { self.tcx.mk_region(ty::ReVar(self.region_vars.new_region_var(origin))) } @@ -1183,7 +1220,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub fn region_var_for_def(&self, span: Span, def: &ty::RegionParameterDef) - -> &'tcx ty::Region { + -> ty::Region<'tcx> { self.next_region_var(EarlyBoundRegion(span, def.name, def.issue_32330)) } @@ -1201,7 +1238,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { substs: &[Kind<'tcx>]) -> Ty<'tcx> { let default = if def.has_default { - let default = self.tcx.item_type(def.def_id); + let default = self.tcx.type_of(def.def_id); Some(type_variable::Default { ty: default.subst_spanned(self.tcx, substs, Some(span)), origin_span: span, @@ -1234,7 +1271,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { }) } - pub fn fresh_bound_region(&self, debruijn: ty::DebruijnIndex) -> &'tcx ty::Region { + pub fn fresh_bound_region(&self, debruijn: ty::DebruijnIndex) -> ty::Region<'tcx> { self.region_vars.new_bound(debruijn) } @@ -1286,9 +1323,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } pub fn resolve_regions_and_report_errors(&self, - free_regions: &FreeRegionMap, - subject_node_id: ast::NodeId) { - let errors = self.region_vars.resolve_regions(free_regions, subject_node_id); + region_context: DefId, + region_map: &RegionMaps<'tcx>, + free_regions: &FreeRegionMap<'tcx>) { + let region_rels = RegionRelations::new(self.tcx, + region_context, + region_map, + free_regions); + let errors = self.region_vars.resolve_regions(®ion_rels); if !self.is_tainted_by_errors() { // As a heuristic, just skip reporting region errors // altogether if other errors have been reported while @@ -1495,7 +1537,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { span: Span, lbrct: LateBoundRegionConversionTime, value: &ty::Binder) - -> (T, FxHashMap) + -> (T, FxHashMap>) where T : TypeFoldable<'tcx> { self.tcx.replace_late_bound_regions( @@ -1541,7 +1583,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub fn verify_generic_bound(&self, origin: SubregionOrigin<'tcx>, kind: GenericKind<'tcx>, - a: &'tcx ty::Region, + a: ty::Region<'tcx>, bound: VerifyBound<'tcx>) { debug!("verify_generic_bound({:?}, {:?} <: {:?})", kind, @@ -1561,9 +1603,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // generic so we don't have to do anything quite this // terrible. let trace = TypeTrace::dummy(self.tcx); - self.equate(true, trace, a, b).map(|InferOk { obligations, .. }| { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); + self.equate(true, trace, a, b).map(|InferOk { obligations: _, .. }| { + // We can intentionally ignore obligations here, since + // this is part of a simple test for general + // "equatability". However, it's not entirely clear + // that we *ought* to be, perhaps a better thing would + // be to use a mini-fulfillment context or something + // like that. }) }) } diff --git a/src/librustc/infer/region_inference/graphviz.rs b/src/librustc/infer/region_inference/graphviz.rs index a67049f72852..c48b8f610a2b 100644 --- a/src/librustc/infer/region_inference/graphviz.rs +++ b/src/librustc/infer/region_inference/graphviz.rs @@ -18,7 +18,9 @@ /// For clarity, rename the graphviz crate locally to dot. use graphviz as dot; -use ty::{self, TyCtxt}; +use hir::def_id::DefIndex; +use ty; +use middle::free_region::RegionRelations; use middle::region::CodeExtent; use super::Constraint; use infer::SubregionOrigin; @@ -32,7 +34,6 @@ use std::fs::File; use std::io; use std::io::prelude::*; use std::sync::atomic::{AtomicBool, Ordering}; -use syntax::ast; fn print_help_message() { println!("\ @@ -55,18 +56,18 @@ graphs will be printed. \n\ pub fn maybe_print_constraints_for<'a, 'gcx, 'tcx>( region_vars: &RegionVarBindings<'a, 'gcx, 'tcx>, - subject_node: ast::NodeId) + region_rels: &RegionRelations<'a, 'gcx, 'tcx>) { - let tcx = region_vars.tcx; + let context = region_rels.context; if !region_vars.tcx.sess.opts.debugging_opts.print_region_graph { return; } let requested_node = env::var("RUST_REGION_GRAPH_NODE") - .ok().and_then(|s| s.parse().map(ast::NodeId::new).ok()); + .ok().and_then(|s| s.parse().map(DefIndex::new).ok()); - if requested_node.is_some() && requested_node != Some(subject_node) { + if requested_node.is_some() && requested_node != Some(context.index) { return; } @@ -98,7 +99,7 @@ pub fn maybe_print_constraints_for<'a, 'gcx, 'tcx>( let mut new_str = String::new(); for c in output_template.chars() { if c == '%' { - new_str.push_str(&subject_node.to_string()); + new_str.push_str(&context.index.as_usize().to_string()); } else { new_str.push(c); } @@ -110,7 +111,7 @@ pub fn maybe_print_constraints_for<'a, 'gcx, 'tcx>( }; let constraints = &*region_vars.constraints.borrow(); - match dump_region_constraints_to(tcx, constraints, &output_path) { + match dump_region_constraints_to(region_rels, constraints, &output_path) { Ok(()) => {} Err(e) => { let msg = format!("io error dumping region constraints: {}", e); @@ -120,28 +121,28 @@ pub fn maybe_print_constraints_for<'a, 'gcx, 'tcx>( } struct ConstraintGraph<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { - tcx: TyCtxt<'a, 'gcx, 'tcx>, graph_name: String, + region_rels: &'a RegionRelations<'a, 'gcx, 'tcx>, map: &'a FxHashMap, SubregionOrigin<'tcx>>, - node_ids: FxHashMap, + node_ids: FxHashMap, usize>, } #[derive(Clone, Hash, PartialEq, Eq, Debug, Copy)] -enum Node { +enum Node<'tcx> { RegionVid(ty::RegionVid), - Region(ty::Region), + Region(ty::RegionKind<'tcx>), } // type Edge = Constraint; #[derive(Clone, PartialEq, Eq, Debug, Copy)] enum Edge<'tcx> { Constraint(Constraint<'tcx>), - EnclScope(CodeExtent, CodeExtent), + EnclScope(CodeExtent<'tcx>, CodeExtent<'tcx>), } impl<'a, 'gcx, 'tcx> ConstraintGraph<'a, 'gcx, 'tcx> { - fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>, - name: String, + fn new(name: String, + region_rels: &'a RegionRelations<'a, 'gcx, 'tcx>, map: &'a ConstraintMap<'tcx>) -> ConstraintGraph<'a, 'gcx, 'tcx> { let mut i = 0; @@ -159,23 +160,23 @@ impl<'a, 'gcx, 'tcx> ConstraintGraph<'a, 'gcx, 'tcx> { add_node(n2); } - tcx.region_maps.each_encl_scope(|sub, sup| { - add_node(Node::Region(ty::ReScope(*sub))); - add_node(Node::Region(ty::ReScope(*sup))); + region_rels.region_maps.each_encl_scope(|sub, sup| { + add_node(Node::Region(ty::ReScope(sub))); + add_node(Node::Region(ty::ReScope(sup))); }); } ConstraintGraph { - tcx: tcx, + map, + node_ids, + region_rels, graph_name: name, - map: map, - node_ids: node_ids, } } } impl<'a, 'gcx, 'tcx> dot::Labeller<'a> for ConstraintGraph<'a, 'gcx, 'tcx> { - type Node = Node; + type Node = Node<'tcx>; type Edge = Edge<'tcx>; fn graph_id(&self) -> dot::Id { dot::Id::new(&*self.graph_name).unwrap() @@ -208,7 +209,7 @@ impl<'a, 'gcx, 'tcx> dot::Labeller<'a> for ConstraintGraph<'a, 'gcx, 'tcx> { } } -fn constraint_to_nodes(c: &Constraint) -> (Node, Node) { +fn constraint_to_nodes<'tcx>(c: &Constraint<'tcx>) -> (Node<'tcx>, Node<'tcx>) { match *c { Constraint::ConstrainVarSubVar(rv_1, rv_2) => (Node::RegionVid(rv_1), Node::RegionVid(rv_2)), @@ -221,7 +222,7 @@ fn constraint_to_nodes(c: &Constraint) -> (Node, Node) { } } -fn edge_to_nodes(e: &Edge) -> (Node, Node) { +fn edge_to_nodes<'tcx>(e: &Edge<'tcx>) -> (Node<'tcx>, Node<'tcx>) { match *e { Edge::Constraint(ref c) => constraint_to_nodes(c), Edge::EnclScope(sub, sup) => { @@ -232,9 +233,9 @@ fn edge_to_nodes(e: &Edge) -> (Node, Node) { } impl<'a, 'gcx, 'tcx> dot::GraphWalk<'a> for ConstraintGraph<'a, 'gcx, 'tcx> { - type Node = Node; + type Node = Node<'tcx>; type Edge = Edge<'tcx>; - fn nodes(&self) -> dot::Nodes { + fn nodes(&self) -> dot::Nodes> { let mut set = FxHashSet(); for node in self.node_ids.keys() { set.insert(*node); @@ -245,16 +246,16 @@ impl<'a, 'gcx, 'tcx> dot::GraphWalk<'a> for ConstraintGraph<'a, 'gcx, 'tcx> { fn edges(&self) -> dot::Edges> { debug!("constraint graph has {} edges", self.map.len()); let mut v: Vec<_> = self.map.keys().map(|e| Edge::Constraint(*e)).collect(); - self.tcx.region_maps.each_encl_scope(|sub, sup| v.push(Edge::EnclScope(*sub, *sup))); + self.region_rels.region_maps.each_encl_scope(|sub, sup| v.push(Edge::EnclScope(sub, sup))); debug!("region graph has {} edges", v.len()); Cow::Owned(v) } - fn source(&self, edge: &Edge<'tcx>) -> Node { + fn source(&self, edge: &Edge<'tcx>) -> Node<'tcx> { let (n1, _) = edge_to_nodes(edge); debug!("edge {:?} has source {:?}", edge, n1); n1 } - fn target(&self, edge: &Edge<'tcx>) -> Node { + fn target(&self, edge: &Edge<'tcx>) -> Node<'tcx> { let (_, n2) = edge_to_nodes(edge); debug!("edge {:?} has target {:?}", edge, n2); n2 @@ -263,14 +264,14 @@ impl<'a, 'gcx, 'tcx> dot::GraphWalk<'a> for ConstraintGraph<'a, 'gcx, 'tcx> { pub type ConstraintMap<'tcx> = FxHashMap, SubregionOrigin<'tcx>>; -fn dump_region_constraints_to<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, +fn dump_region_constraints_to<'a, 'gcx, 'tcx>(region_rels: &RegionRelations<'a, 'gcx, 'tcx>, map: &ConstraintMap<'tcx>, path: &str) -> io::Result<()> { debug!("dump_region_constraints map (len: {}) path: {}", map.len(), path); - let g = ConstraintGraph::new(tcx, format!("region_constraints"), map); + let g = ConstraintGraph::new(format!("region_constraints"), region_rels, map); debug!("dump_region_constraints calling render"); let mut v = Vec::new(); dot::render(&g, &mut v).unwrap(); diff --git a/src/librustc/infer/region_inference/mod.rs b/src/librustc/infer/region_inference/mod.rs index 0bb9e2c7fa15..39554d1fa3a3 100644 --- a/src/librustc/infer/region_inference/mod.rs +++ b/src/librustc/infer/region_inference/mod.rs @@ -22,7 +22,7 @@ use super::unify_key; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::graph::{self, Direction, NodeIndex, OUTGOING}; use rustc_data_structures::unify::{self, UnificationTable}; -use middle::free_region::FreeRegionMap; +use middle::free_region::RegionRelations; use ty::{self, Ty, TyCtxt}; use ty::{Region, RegionVid}; use ty::{ReEmpty, ReStatic, ReFree, ReEarlyBound, ReErased}; @@ -33,7 +33,6 @@ use std::cmp::Ordering::{self, Less, Greater, Equal}; use std::fmt; use std::mem; use std::u32; -use syntax::ast; mod graphviz; @@ -44,17 +43,17 @@ pub enum Constraint<'tcx> { ConstrainVarSubVar(RegionVid, RegionVid), // Concrete region is subregion of region variable - ConstrainRegSubVar(&'tcx Region, RegionVid), + ConstrainRegSubVar(Region<'tcx>, RegionVid), // Region variable is subregion of concrete region. This does not // directly affect inference, but instead is checked after // inference is complete. - ConstrainVarSubReg(RegionVid, &'tcx Region), + ConstrainVarSubReg(RegionVid, Region<'tcx>), // A constraint where neither side is a variable. This does not // directly affect inference, but instead is checked after // inference is complete. - ConstrainRegSubReg(&'tcx Region, &'tcx Region), + ConstrainRegSubReg(Region<'tcx>, Region<'tcx>), } // VerifyGenericBound(T, _, R, RS): The parameter type `T` (or @@ -66,7 +65,7 @@ pub enum Constraint<'tcx> { pub struct Verify<'tcx> { kind: GenericKind<'tcx>, origin: SubregionOrigin<'tcx>, - region: &'tcx Region, + region: Region<'tcx>, bound: VerifyBound<'tcx>, } @@ -86,14 +85,14 @@ pub enum VerifyBound<'tcx> { // Put another way, the subject value is known to outlive all // regions in {R}, so if any of those outlives 'min, then the // bound is met. - AnyRegion(Vec<&'tcx Region>), + AnyRegion(Vec>), // B = forall {R} --> all 'r in {R} must outlive 'min // // Put another way, the subject value is known to outlive some // region in {R}, so if all of those outlives 'min, then the bound // is met. - AllRegions(Vec<&'tcx Region>), + AllRegions(Vec>), // B = exists {B} --> 'min must meet some bound b in {B} AnyBound(Vec>), @@ -104,8 +103,8 @@ pub enum VerifyBound<'tcx> { #[derive(Copy, Clone, PartialEq, Eq, Hash)] pub struct TwoRegions<'tcx> { - a: &'tcx Region, - b: &'tcx Region, + a: Region<'tcx>, + b: Region<'tcx>, } #[derive(Copy, Clone, PartialEq)] @@ -128,7 +127,7 @@ pub enum UndoLogEntry<'tcx> { AddVerify(usize), /// We added the given `given` - AddGiven(ty::FreeRegion, ty::RegionVid), + AddGiven(ty::FreeRegion<'tcx>, ty::RegionVid), /// We added a GLB/LUB "combinaton variable" AddCombination(CombineMapType, TwoRegions<'tcx>), @@ -153,13 +152,13 @@ pub enum RegionResolutionError<'tcx> { /// `ConcreteFailure(o, a, b)`: /// /// `o` requires that `a <= b`, but this does not hold - ConcreteFailure(SubregionOrigin<'tcx>, &'tcx Region, &'tcx Region), + ConcreteFailure(SubregionOrigin<'tcx>, Region<'tcx>, Region<'tcx>), /// `GenericBoundFailure(p, s, a) /// /// The parameter/associated-type `p` must be known to outlive the lifetime /// `a` (but none of the known bounds are sufficient). - GenericBoundFailure(SubregionOrigin<'tcx>, GenericKind<'tcx>, &'tcx Region), + GenericBoundFailure(SubregionOrigin<'tcx>, GenericKind<'tcx>, Region<'tcx>), /// `SubSupConflict(v, sub_origin, sub_r, sup_origin, sup_r)`: /// @@ -168,14 +167,14 @@ pub enum RegionResolutionError<'tcx> { /// `sub_r <= sup_r` does not hold. SubSupConflict(RegionVariableOrigin, SubregionOrigin<'tcx>, - &'tcx Region, + Region<'tcx>, SubregionOrigin<'tcx>, - &'tcx Region), + Region<'tcx>), } #[derive(Clone, Debug)] pub enum ProcessedErrorOrigin<'tcx> { - ConcreteFailure(SubregionOrigin<'tcx>, &'tcx Region, &'tcx Region), + ConcreteFailure(SubregionOrigin<'tcx>, Region<'tcx>, Region<'tcx>), VariableFailure(RegionVariableOrigin), } @@ -214,7 +213,7 @@ pub struct RegionVarBindings<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { // record the fact that `'a <= 'b` is implied by the fn signature, // and then ignore the constraint when solving equations. This is // a bit of a hack but seems to work. - givens: RefCell>, + givens: RefCell, ty::RegionVid)>>, lubs: RefCell>, glbs: RefCell>, @@ -271,12 +270,12 @@ impl TaintDirections { struct TaintSet<'tcx> { directions: TaintDirections, - regions: FxHashSet<&'tcx ty::Region> + regions: FxHashSet> } impl<'a, 'gcx, 'tcx> TaintSet<'tcx> { fn new(directions: TaintDirections, - initial_region: &'tcx ty::Region) + initial_region: ty::Region<'tcx>) -> Self { let mut regions = FxHashSet(); regions.insert(initial_region); @@ -328,7 +327,7 @@ impl<'a, 'gcx, 'tcx> TaintSet<'tcx> { } } - fn into_set(self) -> FxHashSet<&'tcx ty::Region> { + fn into_set(self) -> FxHashSet> { self.regions } @@ -337,8 +336,8 @@ impl<'a, 'gcx, 'tcx> TaintSet<'tcx> { } fn add_edge(&mut self, - source: &'tcx ty::Region, - target: &'tcx ty::Region) { + source: ty::Region<'tcx>, + target: ty::Region<'tcx>) { if self.directions.incoming { if self.regions.contains(&target) { self.regions.insert(source); @@ -499,7 +498,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { /// it's just there to make it explicit which snapshot bounds the /// skolemized region that results. It should always be the top-most snapshot. pub fn push_skolemized(&self, br: ty::BoundRegion, snapshot: &RegionSnapshot) - -> &'tcx Region { + -> Region<'tcx> { assert!(self.in_snapshot()); assert!(self.undo_log.borrow()[snapshot.length] == OpenSnapshot); @@ -513,7 +512,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { /// completes to remove all trace of the skolemized regions /// created in that time. pub fn pop_skolemized(&self, - skols: &FxHashSet<&'tcx ty::Region>, + skols: &FxHashSet>, snapshot: &RegionSnapshot) { debug!("pop_skolemized_regions(skols={:?})", skols); @@ -567,7 +566,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { self.skolemization_count.set(snapshot.skolemization_count); return; - fn kill_constraint<'tcx>(skols: &FxHashSet<&'tcx ty::Region>, + fn kill_constraint<'tcx>(skols: &FxHashSet>, undo_entry: &UndoLogEntry<'tcx>) -> bool { match undo_entry { @@ -596,7 +595,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { } - pub fn new_bound(&self, debruijn: ty::DebruijnIndex) -> &'tcx Region { + pub fn new_bound(&self, debruijn: ty::DebruijnIndex) -> Region<'tcx> { // Creates a fresh bound variable for use in GLB computations. // See discussion of GLB computation in the large comment at // the top of this file for more details. @@ -662,7 +661,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { } } - pub fn add_given(&self, sub: ty::FreeRegion, sup: ty::RegionVid) { + pub fn add_given(&self, sub: ty::FreeRegion<'tcx>, sup: ty::RegionVid) { // cannot add givens once regions are resolved assert!(self.values_are_none()); @@ -676,8 +675,8 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { pub fn make_eqregion(&self, origin: SubregionOrigin<'tcx>, - sub: &'tcx Region, - sup: &'tcx Region) { + sub: Region<'tcx>, + sup: Region<'tcx>) { if sub != sup { // Eventually, it would be nice to add direct support for // equating regions. @@ -692,8 +691,8 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { pub fn make_subregion(&self, origin: SubregionOrigin<'tcx>, - sub: &'tcx Region, - sup: &'tcx Region) { + sub: Region<'tcx>, + sup: Region<'tcx>) { // cannot add constraints once regions are resolved assert!(self.values_are_none()); @@ -734,7 +733,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { pub fn verify_generic_bound(&self, origin: SubregionOrigin<'tcx>, kind: GenericKind<'tcx>, - sub: &'tcx Region, + sub: Region<'tcx>, bound: VerifyBound<'tcx>) { self.add_verify(Verify { kind: kind, @@ -746,9 +745,9 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { pub fn lub_regions(&self, origin: SubregionOrigin<'tcx>, - a: &'tcx Region, - b: &'tcx Region) - -> &'tcx Region { + a: Region<'tcx>, + b: Region<'tcx>) + -> Region<'tcx> { // cannot add constraints once regions are resolved assert!(self.values_are_none()); @@ -772,9 +771,9 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { pub fn glb_regions(&self, origin: SubregionOrigin<'tcx>, - a: &'tcx Region, - b: &'tcx Region) - -> &'tcx Region { + a: Region<'tcx>, + b: Region<'tcx>) + -> Region<'tcx> { // cannot add constraints once regions are resolved assert!(self.values_are_none()); @@ -796,7 +795,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { } } - pub fn resolve_var(&self, rid: RegionVid) -> &'tcx ty::Region { + pub fn resolve_var(&self, rid: RegionVid) -> ty::Region<'tcx> { match *self.values.borrow() { None => { span_bug!((*self.var_origins.borrow())[rid.index as usize].span(), @@ -811,7 +810,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { } } - pub fn opportunistic_resolve_var(&self, rid: RegionVid) -> &'tcx ty::Region { + pub fn opportunistic_resolve_var(&self, rid: RegionVid) -> ty::Region<'tcx> { let vid = self.unification_table.borrow_mut().find_value(rid).min_vid; self.tcx.mk_region(ty::ReVar(vid)) } @@ -825,12 +824,12 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { pub fn combine_vars(&self, t: CombineMapType, - a: &'tcx Region, - b: &'tcx Region, + a: Region<'tcx>, + b: Region<'tcx>, origin: SubregionOrigin<'tcx>, mut relate: F) - -> &'tcx Region - where F: FnMut(&RegionVarBindings<'a, 'gcx, 'tcx>, &'tcx Region, &'tcx Region) + -> Region<'tcx> + where F: FnMut(&RegionVarBindings<'a, 'gcx, 'tcx>, Region<'tcx>, Region<'tcx>) { let vars = TwoRegions { a: a, b: b }; if let Some(&c) = self.combine_map(t).borrow().get(&vars) { @@ -869,9 +868,9 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { /// related to other regions. pub fn tainted(&self, mark: &RegionSnapshot, - r0: &'tcx Region, + r0: Region<'tcx>, directions: TaintDirections) - -> FxHashSet<&'tcx ty::Region> { + -> FxHashSet> { debug!("tainted(mark={:?}, r0={:?}, directions={:?})", mark, r0, directions); @@ -892,21 +891,20 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { /// constraints, assuming such values can be found; if they cannot, /// errors are reported. pub fn resolve_regions(&self, - free_regions: &FreeRegionMap, - subject_node: ast::NodeId) + region_rels: &RegionRelations<'a, 'gcx, 'tcx>) -> Vec> { debug!("RegionVarBindings: resolve_regions()"); let mut errors = vec![]; - let v = self.infer_variable_values(free_regions, &mut errors, subject_node); + let v = self.infer_variable_values(region_rels, &mut errors); *self.values.borrow_mut() = Some(v); errors } fn lub_concrete_regions(&self, - free_regions: &FreeRegionMap, - a: &'tcx Region, - b: &'tcx Region) - -> &'tcx Region { + region_rels: &RegionRelations<'a, 'gcx, 'tcx>, + a: Region<'tcx>, + b: Region<'tcx>) + -> Region<'tcx> { match (a, b) { (&ReLateBound(..), _) | (_, &ReLateBound(..)) | @@ -938,30 +936,31 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { // A "free" region can be interpreted as "some region // at least as big as the block fr.scope_id". So, we can // reasonably compare free regions and scopes: - let r_id = self.tcx.region_maps.nearest_common_ancestor(fr.scope, s_id); - - if r_id == fr.scope { - // if the free region's scope `fr.scope_id` is bigger than - // the scope region `s_id`, then the LUB is the free - // region itself: - self.tcx.mk_region(ReFree(fr)) - } else { - // otherwise, we don't know what the free region is, - // so we must conservatively say the LUB is static: - self.tcx.mk_region(ReStatic) + if let Some(fr_scope) = fr.scope { + let r_id = region_rels.region_maps.nearest_common_ancestor(fr_scope, s_id); + if r_id == fr_scope { + // if the free region's scope `fr.scope_id` is bigger than + // the scope region `s_id`, then the LUB is the free + // region itself: + return self.tcx.mk_region(ReFree(fr)); + } } + + // otherwise, we don't know what the free region is, + // so we must conservatively say the LUB is static: + self.tcx.types.re_static } (&ReScope(a_id), &ReScope(b_id)) => { // The region corresponding to an outer block is a // subtype of the region corresponding to an inner // block. - self.tcx.mk_region(ReScope( - self.tcx.region_maps.nearest_common_ancestor(a_id, b_id))) + let lub = region_rels.region_maps.nearest_common_ancestor(a_id, b_id); + self.tcx.mk_region(ReScope(lub)) } - (&ReFree(a_fr), &ReFree(b_fr)) => { - self.tcx.mk_region(free_regions.lub_free_regions(a_fr, b_fr)) + (&ReFree(_), &ReFree(_)) => { + region_rels.lub_free_regions(a, b) } // For these types, we cannot define any additional @@ -971,7 +970,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { if a == b { a } else { - self.tcx.mk_region(ReStatic) + self.tcx.types.re_static } } } @@ -982,12 +981,12 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { #[derive(Copy, Clone, Debug)] pub enum VarValue<'tcx> { - Value(&'tcx Region), + Value(Region<'tcx>), ErrorValue, } struct RegionAndOrigin<'tcx> { - region: &'tcx Region, + region: Region<'tcx>, origin: SubregionOrigin<'tcx>, } @@ -995,36 +994,35 @@ type RegionGraph<'tcx> = graph::Graph<(), Constraint<'tcx>>; impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { fn infer_variable_values(&self, - free_regions: &FreeRegionMap, - errors: &mut Vec>, - subject: ast::NodeId) + region_rels: &RegionRelations<'a, 'gcx, 'tcx>, + errors: &mut Vec>) -> Vec> { let mut var_data = self.construct_var_data(); // Dorky hack to cause `dump_constraints` to only get called // if debug mode is enabled: - debug!("----() End constraint listing (subject={}) {:?}---", - subject, - self.dump_constraints(subject)); - graphviz::maybe_print_constraints_for(self, subject); + debug!("----() End constraint listing (context={:?}) {:?}---", + region_rels.context, + self.dump_constraints(region_rels)); + graphviz::maybe_print_constraints_for(self, region_rels); let graph = self.construct_graph(); self.expand_givens(&graph); - self.expansion(free_regions, &mut var_data); - self.collect_errors(free_regions, &mut var_data, errors); - self.collect_var_errors(free_regions, &var_data, &graph, errors); + self.expansion(region_rels, &mut var_data); + self.collect_errors(region_rels, &mut var_data, errors); + self.collect_var_errors(region_rels, &var_data, &graph, errors); var_data } fn construct_var_data(&self) -> Vec> { (0..self.num_vars() as usize) - .map(|_| Value(self.tcx.mk_region(ty::ReEmpty))) + .map(|_| Value(self.tcx.types.re_empty)) .collect() } - fn dump_constraints(&self, subject: ast::NodeId) { - debug!("----() Start constraint listing (subject={}) ()----", - subject); + fn dump_constraints(&self, free_regions: &RegionRelations<'a, 'gcx, 'tcx>) { + debug!("----() Start constraint listing (context={:?}) ()----", + free_regions.context); for (idx, (constraint, _)) in self.constraints.borrow().iter().enumerate() { debug!("Constraint {} => {:?}", idx, constraint); } @@ -1055,21 +1053,23 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { } } - fn expansion(&self, free_regions: &FreeRegionMap, var_values: &mut [VarValue<'tcx>]) { + fn expansion(&self, + region_rels: &RegionRelations<'a, 'gcx, 'tcx>, + var_values: &mut [VarValue<'tcx>]) { self.iterate_until_fixed_point("Expansion", |constraint, origin| { debug!("expansion: constraint={:?} origin={:?}", constraint, origin); match *constraint { ConstrainRegSubVar(a_region, b_vid) => { let b_data = &mut var_values[b_vid.index as usize]; - self.expand_node(free_regions, a_region, b_vid, b_data) + self.expand_node(region_rels, a_region, b_vid, b_data) } ConstrainVarSubVar(a_vid, b_vid) => { match var_values[a_vid.index as usize] { ErrorValue => false, Value(a_region) => { let b_node = &mut var_values[b_vid.index as usize]; - self.expand_node(free_regions, a_region, b_vid, b_node) + self.expand_node(region_rels, a_region, b_vid, b_node) } } } @@ -1084,8 +1084,8 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { } fn expand_node(&self, - free_regions: &FreeRegionMap, - a_region: &'tcx Region, + region_rels: &RegionRelations<'a, 'gcx, 'tcx>, + a_region: Region<'tcx>, b_vid: RegionVid, b_data: &mut VarValue<'tcx>) -> bool { @@ -1107,7 +1107,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { match *b_data { Value(cur_region) => { - let lub = self.lub_concrete_regions(free_regions, a_region, cur_region); + let lub = self.lub_concrete_regions(region_rels, a_region, cur_region); if lub == cur_region { return false; } @@ -1131,7 +1131,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { /// cases where the region cannot grow larger than a fixed point) /// and check that they are satisfied. fn collect_errors(&self, - free_regions: &FreeRegionMap, + region_rels: &RegionRelations<'a, 'gcx, 'tcx>, var_data: &mut Vec>, errors: &mut Vec>) { let constraints = self.constraints.borrow(); @@ -1145,7 +1145,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { } ConstrainRegSubReg(sub, sup) => { - if free_regions.is_subregion_of(self.tcx, sub, sup) { + if region_rels.is_subregion_of(sub, sup) { continue; } @@ -1173,7 +1173,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { // Do not report these errors immediately: // instead, set the variable value to error and // collect them later. - if !free_regions.is_subregion_of(self.tcx, a_region, b_region) { + if !region_rels.is_subregion_of(a_region, b_region) { debug!("collect_errors: region error at {:?}: \ cannot verify that {:?}={:?} <= {:?}", origin, @@ -1189,7 +1189,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { for verify in self.verifys.borrow().iter() { debug!("collect_errors: verify={:?}", verify); let sub = normalize(self.tcx, var_data, verify.region); - if verify.bound.is_met(self.tcx, free_regions, var_data, sub) { + if verify.bound.is_met(region_rels, var_data, sub) { continue; } @@ -1208,7 +1208,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { /// Go over the variables that were declared to be error variables /// and create a `RegionResolutionError` for each of them. fn collect_var_errors(&self, - free_regions: &FreeRegionMap, + region_rels: &RegionRelations<'a, 'gcx, 'tcx>, var_data: &[VarValue<'tcx>], graph: &RegionGraph<'tcx>, errors: &mut Vec>) { @@ -1257,7 +1257,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { this portion of the code and think hard about it. =) */ let node_vid = RegionVid { index: idx as u32 }; - self.collect_error_for_expanding_node(free_regions, + self.collect_error_for_expanding_node(region_rels, graph, &mut dup_vec, node_vid, @@ -1310,7 +1310,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { } fn collect_error_for_expanding_node(&self, - free_regions: &FreeRegionMap, + region_rels: &RegionRelations<'a, 'gcx, 'tcx>, graph: &RegionGraph<'tcx>, dup_vec: &mut [u32], node_idx: RegionVid, @@ -1346,7 +1346,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { for lower_bound in &lower_bounds { for upper_bound in &upper_bounds { - if !free_regions.is_subregion_of(self.tcx, lower_bound.region, upper_bound.region) { + if !region_rels.is_subregion_of(lower_bound.region, upper_bound.region) { let origin = (*self.var_origins.borrow())[node_idx.index as usize].clone(); debug!("region inference error at {:?} for {:?}: SubSupConflict sub: {:?} \ sup: {:?}", @@ -1479,8 +1479,8 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { fn normalize<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, values: &Vec>, - r: &'tcx ty::Region) - -> &'tcx ty::Region { + r: ty::Region<'tcx>) + -> ty::Region<'tcx> { match *r { ty::ReVar(rid) => lookup(tcx, values, rid), _ => r, @@ -1490,10 +1490,10 @@ fn normalize<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, fn lookup<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, values: &Vec>, rid: ty::RegionVid) - -> &'tcx ty::Region { + -> ty::Region<'tcx> { match values[rid.index as usize] { Value(r) => r, - ErrorValue => tcx.mk_region(ReStatic), // Previously reported error. + ErrorValue => tcx.types.re_static, // Previously reported error. } } @@ -1538,7 +1538,7 @@ impl<'a, 'gcx, 'tcx> GenericKind<'tcx> { } impl<'a, 'gcx, 'tcx> VerifyBound<'tcx> { - fn for_each_region(&self, f: &mut FnMut(&'tcx ty::Region)) { + fn for_each_region(&self, f: &mut FnMut(ty::Region<'tcx>)) { match self { &VerifyBound::AnyRegion(ref rs) | &VerifyBound::AllRegions(ref rs) => for &r in rs { @@ -1590,29 +1590,30 @@ impl<'a, 'gcx, 'tcx> VerifyBound<'tcx> { } } - fn is_met(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, - free_regions: &FreeRegionMap, + fn is_met(&self, + region_rels: &RegionRelations<'a, 'gcx, 'tcx>, var_values: &Vec>, - min: &'tcx ty::Region) + min: ty::Region<'tcx>) -> bool { + let tcx = region_rels.tcx; match self { &VerifyBound::AnyRegion(ref rs) => rs.iter() .map(|&r| normalize(tcx, var_values, r)) - .any(|r| free_regions.is_subregion_of(tcx, min, r)), + .any(|r| region_rels.is_subregion_of(min, r)), &VerifyBound::AllRegions(ref rs) => rs.iter() .map(|&r| normalize(tcx, var_values, r)) - .all(|r| free_regions.is_subregion_of(tcx, min, r)), + .all(|r| region_rels.is_subregion_of(min, r)), &VerifyBound::AnyBound(ref bs) => bs.iter() - .any(|b| b.is_met(tcx, free_regions, var_values, min)), + .any(|b| b.is_met(region_rels, var_values, min)), &VerifyBound::AllBounds(ref bs) => bs.iter() - .all(|b| b.is_met(tcx, free_regions, var_values, min)), + .all(|b| b.is_met(region_rels, var_values, min)), } } } diff --git a/src/librustc/infer/resolve.rs b/src/librustc/infer/resolve.rs index 357a03a2ffd7..2e8b843d07b3 100644 --- a/src/librustc/infer/resolve.rs +++ b/src/librustc/infer/resolve.rs @@ -72,7 +72,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for OpportunisticTypeAndRegionResolv } } - fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region { + fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { match *r { ty::ReVar(rid) => self.infcx.region_vars.opportunistic_resolve_var(rid), _ => r, @@ -138,7 +138,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for FullTypeResolver<'a, 'gcx, 'tcx> } } - fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region { + fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { match *r { ty::ReVar(rid) => self.infcx.region_vars.resolve_var(rid), _ => r, diff --git a/src/librustc/infer/sub.rs b/src/librustc/infer/sub.rs index dae30ea97c80..487195fdfae9 100644 --- a/src/librustc/infer/sub.rs +++ b/src/librustc/infer/sub.rs @@ -9,11 +9,12 @@ // except according to those terms. use super::SubregionOrigin; -use super::combine::CombineFields; -use super::type_variable::{SubtypeOf, SupertypeOf}; +use super::combine::{CombineFields, RelationDir}; +use traits::Obligation; use ty::{self, Ty, TyCtxt}; use ty::TyVar; +use ty::fold::TypeFoldable; use ty::relate::{Cause, Relate, RelateResult, TypeRelation}; use std::mem; @@ -65,7 +66,7 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> match variance { ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b), ty::Covariant => self.relate(a, b), - ty::Bivariant => self.fields.bivariate(self.a_is_expected).relate(a, b), + ty::Bivariant => Ok(a.clone()), ty::Contravariant => self.with_expected_switched(|this| { this.relate(b, a) }), } } @@ -79,19 +80,38 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> let a = infcx.type_variables.borrow_mut().replace_if_possible(a); let b = infcx.type_variables.borrow_mut().replace_if_possible(b); match (&a.sty, &b.sty) { - (&ty::TyInfer(TyVar(a_id)), &ty::TyInfer(TyVar(b_id))) => { - infcx.type_variables - .borrow_mut() - .relate_vars(a_id, SubtypeOf, b_id); + (&ty::TyInfer(TyVar(a_vid)), &ty::TyInfer(TyVar(b_vid))) => { + // Shouldn't have any LBR here, so we can safely put + // this under a binder below without fear of accidental + // capture. + assert!(!a.has_escaping_regions()); + assert!(!b.has_escaping_regions()); + + // can't make progress on `A <: B` if both A and B are + // type variables, so record an obligation. We also + // have to record in the `type_variables` tracker that + // the two variables are equal modulo subtyping, which + // is important to the occurs check later on. + infcx.type_variables.borrow_mut().sub(a_vid, b_vid); + self.fields.obligations.push( + Obligation::new( + self.fields.trace.cause.clone(), + ty::Predicate::Subtype( + ty::Binder(ty::SubtypePredicate { + a_is_expected: self.a_is_expected, + a, + b, + })))); + Ok(a) } (&ty::TyInfer(TyVar(a_id)), _) => { self.fields - .instantiate(b, SupertypeOf, a_id, !self.a_is_expected)?; + .instantiate(b, RelationDir::SupertypeOf, a_id, !self.a_is_expected)?; Ok(a) } (_, &ty::TyInfer(TyVar(b_id))) => { - self.fields.instantiate(a, SubtypeOf, b_id, self.a_is_expected)?; + self.fields.instantiate(a, RelationDir::SubtypeOf, b_id, self.a_is_expected)?; Ok(a) } @@ -107,8 +127,8 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> } } - fn regions(&mut self, a: &'tcx ty::Region, b: &'tcx ty::Region) - -> RelateResult<'tcx, &'tcx ty::Region> { + fn regions(&mut self, a: ty::Region<'tcx>, b: ty::Region<'tcx>) + -> RelateResult<'tcx, ty::Region<'tcx>> { debug!("{}.regions({:?}, {:?}) self.cause={:?}", self.tag(), a, b, self.fields.cause); diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs index 9c8419d9546d..4ae2a8026409 100644 --- a/src/librustc/infer/type_variable.rs +++ b/src/librustc/infer/type_variable.rs @@ -8,11 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -pub use self::RelationDir::*; use self::TypeVariableValue::*; -use self::UndoEntry::*; use hir::def_id::{DefId}; -use syntax::util::small_vector::SmallVector; use syntax::ast; use syntax_pos::Span; use ty::{self, Ty}; @@ -21,15 +18,39 @@ use std::cmp::min; use std::marker::PhantomData; use std::mem; use std::u32; +use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::snapshot_vec as sv; use rustc_data_structures::unify as ut; pub struct TypeVariableTable<'tcx> { values: sv::SnapshotVec>, + + /// Two variables are unified in `eq_relations` when we have a + /// constraint `?X == ?Y`. eq_relations: ut::UnificationTable, + + /// Two variables are unified in `eq_relations` when we have a + /// constraint `?X <: ?Y` *or* a constraint `?Y <: ?X`. This second + /// table exists only to help with the occurs check. In particular, + /// we want to report constraints like these as an occurs check + /// violation: + /// + /// ?1 <: ?3 + /// Box <: ?1 + /// + /// This works because `?1` and `?3` are unified in the + /// `sub_relations` relation (not in `eq_relations`). Then when we + /// process the `Box <: ?1` constraint, we do an occurs check + /// on `Box` and find a potential cycle. + /// + /// This is reasonable because, in Rust, subtypes have the same + /// "skeleton" and hence there is no possible type such that + /// (e.g.) `Box <: ?3` for any `?3`. + sub_relations: ut::UnificationTable, } /// Reasons to create a type inference variable +#[derive(Copy, Clone, Debug)] pub enum TypeVariableOrigin { MiscVariable(Span), NormalizeProjectionType(Span), @@ -41,9 +62,13 @@ pub enum TypeVariableOrigin { AdjustmentType(Span), DivergingStmt(Span), DivergingBlockExpr(Span), + DivergingFn(Span), LatticeVariable(Span), + Generalized(ty::TyVid), } +pub type TypeVariableMap = FxHashMap; + struct TypeVariableData<'tcx> { value: TypeVariableValue<'tcx>, origin: TypeVariableOrigin, @@ -53,7 +78,6 @@ struct TypeVariableData<'tcx> { enum TypeVariableValue<'tcx> { Known(Ty<'tcx>), Bounded { - relations: Vec, default: Option> } } @@ -72,47 +96,25 @@ pub struct Default<'tcx> { pub struct Snapshot { snapshot: sv::Snapshot, eq_snapshot: ut::Snapshot, + sub_snapshot: ut::Snapshot, } -enum UndoEntry<'tcx> { - // The type of the var was specified. - SpecifyVar(ty::TyVid, Vec, Option>), - Relate(ty::TyVid, ty::TyVid), - RelateRange(ty::TyVid, usize), +struct Instantiate<'tcx> { + vid: ty::TyVid, + default: Option>, } struct Delegate<'tcx>(PhantomData<&'tcx ()>); -type Relation = (RelationDir, ty::TyVid); - -#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] -pub enum RelationDir { - SubtypeOf, SupertypeOf, EqTo, BiTo -} - -impl RelationDir { - fn opposite(self) -> RelationDir { - match self { - SubtypeOf => SupertypeOf, - SupertypeOf => SubtypeOf, - EqTo => EqTo, - BiTo => BiTo, - } - } -} - impl<'tcx> TypeVariableTable<'tcx> { pub fn new() -> TypeVariableTable<'tcx> { TypeVariableTable { values: sv::SnapshotVec::new(), eq_relations: ut::UnificationTable::new(), + sub_relations: ut::UnificationTable::new(), } } - fn relations<'a>(&'a mut self, a: ty::TyVid) -> &'a mut Vec { - relations(self.values.get_mut(a.index as usize)) - } - pub fn default(&self, vid: ty::TyVid) -> Option> { match &self.values.get(vid.index as usize).value { &Known(_) => None, @@ -128,82 +130,62 @@ impl<'tcx> TypeVariableTable<'tcx> { &self.values.get(vid.index as usize).origin } - /// Records that `a <: b`, `a :> b`, or `a == b`, depending on `dir`. + /// Records that `a == b`, depending on `dir`. /// /// Precondition: neither `a` nor `b` are known. - pub fn relate_vars(&mut self, a: ty::TyVid, dir: RelationDir, b: ty::TyVid) { - let a = self.root_var(a); - let b = self.root_var(b); - if a != b { - if dir == EqTo { - // a and b must be equal which we mark in the unification table - let root = self.eq_relations.union(a, b); - // In addition to being equal, all relations from the variable which is no longer - // the root must be added to the root so they are not forgotten as the other - // variable should no longer be referenced (other than to get the root) - let other = if a == root { b } else { a }; - let count = { - let (relations, root_relations) = if other.index < root.index { - let (pre, post) = self.values.split_at_mut(root.index as usize); - (relations(&mut pre[other.index as usize]), relations(&mut post[0])) - } else { - let (pre, post) = self.values.split_at_mut(other.index as usize); - (relations(&mut post[0]), relations(&mut pre[root.index as usize])) - }; - root_relations.extend_from_slice(relations); - relations.len() - }; - self.values.record(RelateRange(root, count)); - } else { - self.relations(a).push((dir, b)); - self.relations(b).push((dir.opposite(), a)); - self.values.record(Relate(a, b)); - } - } + pub fn equate(&mut self, a: ty::TyVid, b: ty::TyVid) { + debug_assert!(self.probe(a).is_none()); + debug_assert!(self.probe(b).is_none()); + self.eq_relations.union(a, b); + self.sub_relations.union(a, b); } - /// Instantiates `vid` with the type `ty` and then pushes an entry onto `stack` for each of the - /// relations of `vid` to other variables. The relations will have the form `(ty, dir, vid1)` - /// where `vid1` is some other variable id. + /// Records that `a <: b`, depending on `dir`. /// - /// Precondition: `vid` must be a root in the unification table - pub fn instantiate_and_push( - &mut self, - vid: ty::TyVid, - ty: Ty<'tcx>, - stack: &mut SmallVector<(Ty<'tcx>, RelationDir, ty::TyVid)>) - { - debug_assert!(self.root_var(vid) == vid); + /// Precondition: neither `a` nor `b` are known. + pub fn sub(&mut self, a: ty::TyVid, b: ty::TyVid) { + debug_assert!(self.probe(a).is_none()); + debug_assert!(self.probe(b).is_none()); + self.sub_relations.union(a, b); + } + + /// Instantiates `vid` with the type `ty`. + /// + /// Precondition: `vid` must not have been previously instantiated. + pub fn instantiate(&mut self, vid: ty::TyVid, ty: Ty<'tcx>) { + let vid = self.root_var(vid); + debug_assert!(self.probe_root(vid).is_none()); + let old_value = { - let value_ptr = &mut self.values.get_mut(vid.index as usize).value; - mem::replace(value_ptr, Known(ty)) + let vid_data = &mut self.values[vid.index as usize]; + mem::replace(&mut vid_data.value, TypeVariableValue::Known(ty)) }; - let (relations, default) = match old_value { - Bounded { relations, default } => (relations, default), - Known(_) => bug!("Asked to instantiate variable that is \ - already instantiated") - }; - - for &(dir, vid) in &relations { - stack.push((ty, dir, vid)); + match old_value { + TypeVariableValue::Bounded { default } => { + self.values.record(Instantiate { vid: vid, default: default }); + } + TypeVariableValue::Known(old_ty) => { + bug!("instantiating type variable `{:?}` twice: new-value = {:?}, old-value={:?}", + vid, ty, old_ty) + } } - - self.values.record(SpecifyVar(vid, relations, default)); } pub fn new_var(&mut self, diverging: bool, origin: TypeVariableOrigin, default: Option>,) -> ty::TyVid { + debug!("new_var(diverging={:?}, origin={:?})", diverging, origin); self.eq_relations.new_key(()); + self.sub_relations.new_key(()); let index = self.values.push(TypeVariableData { - value: Bounded { relations: vec![], default: default }, + value: Bounded { default: default }, origin: origin, diverging: diverging }); let v = ty::TyVid { index: index as u32 }; - debug!("new_var() -> {:?}", v); + debug!("new_var: diverging={:?} index={:?}", diverging, v); v } @@ -211,15 +193,41 @@ impl<'tcx> TypeVariableTable<'tcx> { self.values.len() } + /// Returns the "root" variable of `vid` in the `eq_relations` + /// equivalence table. All type variables that have been equated + /// will yield the same root variable (per the union-find + /// algorithm), so `root_var(a) == root_var(b)` implies that `a == + /// b` (transitively). pub fn root_var(&mut self, vid: ty::TyVid) -> ty::TyVid { self.eq_relations.find(vid) } + /// Returns the "root" variable of `vid` in the `sub_relations` + /// equivalence table. All type variables that have been are + /// related via equality or subtyping will yield the same root + /// variable (per the union-find algorithm), so `sub_root_var(a) + /// == sub_root_var(b)` implies that: + /// + /// exists X. (a <: X || X <: a) && (b <: X || X <: b) + pub fn sub_root_var(&mut self, vid: ty::TyVid) -> ty::TyVid { + self.sub_relations.find(vid) + } + + /// True if `a` and `b` have same "sub-root" (i.e., exists some + /// type X such that `forall i in {a, b}. (i <: X || X <: i)`. + pub fn sub_unified(&mut self, a: ty::TyVid, b: ty::TyVid) -> bool { + self.sub_root_var(a) == self.sub_root_var(b) + } + pub fn probe(&mut self, vid: ty::TyVid) -> Option> { let vid = self.root_var(vid); self.probe_root(vid) } + pub fn origin(&self, vid: ty::TyVid) -> TypeVariableOrigin { + self.values.get(vid.index as usize).origin.clone() + } + /// Retrieves the type of `vid` given that it is currently a root in the unification table pub fn probe_root(&mut self, vid: ty::TyVid) -> Option> { debug_assert!(self.root_var(vid) == vid); @@ -245,6 +253,7 @@ impl<'tcx> TypeVariableTable<'tcx> { Snapshot { snapshot: self.values.start_snapshot(), eq_snapshot: self.eq_relations.snapshot(), + sub_snapshot: self.sub_relations.snapshot(), } } @@ -260,13 +269,37 @@ impl<'tcx> TypeVariableTable<'tcx> { } }); - self.values.rollback_to(s.snapshot); - self.eq_relations.rollback_to(s.eq_snapshot); + let Snapshot { snapshot, eq_snapshot, sub_snapshot } = s; + self.values.rollback_to(snapshot); + self.eq_relations.rollback_to(eq_snapshot); + self.sub_relations.rollback_to(sub_snapshot); } pub fn commit(&mut self, s: Snapshot) { - self.values.commit(s.snapshot); - self.eq_relations.commit(s.eq_snapshot); + let Snapshot { snapshot, eq_snapshot, sub_snapshot } = s; + self.values.commit(snapshot); + self.eq_relations.commit(eq_snapshot); + self.sub_relations.commit(sub_snapshot); + } + + /// Returns a map `{V1 -> V2}`, where the keys `{V1}` are + /// ty-variables created during the snapshot, and the values + /// `{V2}` are the root variables that they were unified with, + /// along with their origin. + pub fn types_created_since_snapshot(&mut self, s: &Snapshot) -> TypeVariableMap { + let actions_since_snapshot = self.values.actions_since_snapshot(&s.snapshot); + + actions_since_snapshot + .iter() + .filter_map(|action| match action { + &sv::UndoLog::NewElem(index) => Some(ty::TyVid { index: index as u32 }), + _ => None, + }) + .map(|vid| { + let origin = self.values.get(vid.index as usize).origin.clone(); + (vid, origin) + }) + .collect() } pub fn types_escaping_snapshot(&mut self, s: &Snapshot) -> Vec> { @@ -295,7 +328,7 @@ impl<'tcx> TypeVariableTable<'tcx> { debug!("NewElem({}) new_elem_threshold={}", index, new_elem_threshold); } - sv::UndoLog::Other(SpecifyVar(vid, ..)) => { + sv::UndoLog::Other(Instantiate { vid, .. }) => { if vid.index < new_elem_threshold { // quick check to see if this variable was // created since the snapshot started or not. @@ -331,35 +364,12 @@ impl<'tcx> TypeVariableTable<'tcx> { impl<'tcx> sv::SnapshotVecDelegate for Delegate<'tcx> { type Value = TypeVariableData<'tcx>; - type Undo = UndoEntry<'tcx>; + type Undo = Instantiate<'tcx>; - fn reverse(values: &mut Vec>, action: UndoEntry<'tcx>) { - match action { - SpecifyVar(vid, relations, default) => { - values[vid.index as usize].value = Bounded { - relations: relations, - default: default - }; - } - - Relate(a, b) => { - relations(&mut (*values)[a.index as usize]).pop(); - relations(&mut (*values)[b.index as usize]).pop(); - } - - RelateRange(i, n) => { - let relations = relations(&mut (*values)[i.index as usize]); - for _ in 0..n { - relations.pop(); - } - } - } - } -} - -fn relations<'a>(v: &'a mut TypeVariableData) -> &'a mut Vec { - match v.value { - Known(_) => bug!("var_sub_var: variable is known"), - Bounded { ref mut relations, .. } => relations + fn reverse(values: &mut Vec>, action: Instantiate<'tcx>) { + let Instantiate { vid, default } = action; + values[vid.index as usize].value = Bounded { + default: default + }; } } diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index c1c945d4e606..d3954326e7b7 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -29,12 +29,11 @@ #![feature(conservative_impl_trait)] #![feature(const_fn)] #![feature(core_intrinsics)] -#![cfg_attr(stage0,feature(field_init_shorthand))] #![feature(i128_type)] #![feature(libc)] #![feature(loop_break_value)] +#![feature(never_type)] #![feature(nonzero)] -#![cfg_attr(stage0, feature(pub_restricted))] #![feature(quote)] #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] @@ -42,6 +41,11 @@ #![feature(specialization)] #![feature(staged_api)] #![feature(unboxed_closures)] +#![feature(discriminant_value)] +#![feature(sort_unstable)] +#![feature(trace_macros)] + +#![recursion_limit="128"] extern crate arena; extern crate core; diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 843f3a53f33e..6947e7c3f408 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -40,13 +40,13 @@ use std::cmp; use std::default::Default as StdDefault; use std::mem; use std::fmt; -use std::ops::Deref; use syntax::attr; use syntax::ast; use syntax::symbol::Symbol; use syntax_pos::{MultiSpan, Span}; use errors::{self, Diagnostic, DiagnosticBuilder}; use hir; +use hir::def_id::LOCAL_CRATE; use hir::intravisit as hir_visit; use syntax::visit as ast_visit; @@ -484,7 +484,7 @@ pub fn raw_struct_lint<'a, S>(sess: &'a Session, Allow => bug!("earlier conditional return should handle Allow case") }; let hyphen_case_lint_name = name.replace("_", "-"); - if lint_flag_val.as_str().deref() == name { + if lint_flag_val.as_str() == name { err.note(&format!("requested on the command line with `{} {}`", flag, hyphen_case_lint_name)); } else { @@ -495,7 +495,7 @@ pub fn raw_struct_lint<'a, S>(sess: &'a Session, }, Node(lint_attr_name, src) => { def = Some(src); - if lint_attr_name.as_str().deref() != name { + if lint_attr_name.as_str() != name { let level_str = level.as_str(); err.note(&format!("#[{}({})] implied by #[{}({})]", level_str, name, level_str, lint_attr_name)); @@ -1231,10 +1231,11 @@ fn check_lint_name_cmdline(sess: &Session, lint_cx: &LintStore, /// Perform lint checking on a crate. /// /// Consumes the `lint_store` field of the `Session`. -pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - access_levels: &AccessLevels) { +pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let _task = tcx.dep_graph.in_task(DepNode::LateLintCheck); + let access_levels = &tcx.privacy_access_levels(LOCAL_CRATE); + let krate = tcx.hir.krate(); // We want to own the lint store, so move it out of the session. diff --git a/src/librustc/macros.rs b/src/librustc/macros.rs index 76dca1bb5b64..c18e585f7955 100644 --- a/src/librustc/macros.rs +++ b/src/librustc/macros.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-tidy-linelength + macro_rules! enum_from_u32 { ($(#[$attr:meta])* pub enum $name:ident { $($variant:ident = $e:expr,)* @@ -59,3 +61,80 @@ macro_rules! span_bug { $crate::session::span_bug_fmt(file!(), line!(), $span, format_args!($($message)*)) }) } + +#[macro_export] +macro_rules! __impl_stable_hash_field { + (DECL IGNORED) => (_); + (DECL $name:ident) => (ref $name); + (USE IGNORED $ctx:expr, $hasher:expr) => ({}); + (USE $name:ident, $ctx:expr, $hasher:expr) => ($name.hash_stable($ctx, $hasher)); +} + +#[macro_export] +macro_rules! impl_stable_hash_for { + (enum $enum_name:path { $( $variant:ident $( ( $($arg:ident),* ) )* ),* }) => { + impl<'a, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a, 'tcx>> for $enum_name { + #[inline] + fn hash_stable(&self, + __ctx: &mut $crate::ich::StableHashingContext<'a, 'tcx>, + __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) { + use $enum_name::*; + ::std::mem::discriminant(self).hash_stable(__ctx, __hasher); + + match *self { + $( + $variant $( ( $( __impl_stable_hash_field!(DECL $arg) ),* ) )* => { + $($( __impl_stable_hash_field!(USE $arg, __ctx, __hasher) );*)* + } + )* + } + } + } + }; + (struct $struct_name:path { $($field:ident),* }) => { + impl<'a, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a, 'tcx>> for $struct_name { + #[inline] + fn hash_stable(&self, + __ctx: &mut $crate::ich::StableHashingContext<'a, 'tcx>, + __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) { + let $struct_name { + $(ref $field),* + } = *self; + + $( $field.hash_stable(__ctx, __hasher));* + } + } + }; + (tuple_struct $struct_name:path { $($field:ident),* }) => { + impl<'a, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a, 'tcx>> for $struct_name { + #[inline] + fn hash_stable(&self, + __ctx: &mut $crate::ich::StableHashingContext<'a, 'tcx>, + __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) { + let $struct_name ( + $(ref $field),* + ) = *self; + + $( $field.hash_stable(__ctx, __hasher));* + } + } + }; +} + +#[macro_export] +macro_rules! impl_stable_hash_for_spanned { + ($T:path) => ( + + impl<'a, 'tcx> HashStable> for ::syntax::codemap::Spanned<$T> + { + #[inline] + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + self.node.hash_stable(hcx, hasher); + self.span.hash_stable(hcx, hasher); + } + } + ); +} + diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs index d81f89827d93..74026abe64db 100644 --- a/src/librustc/middle/const_val.rs +++ b/src/librustc/middle/const_val.rs @@ -8,17 +8,28 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use syntax::symbol::InternedString; -use syntax::ast; -use std::rc::Rc; -use hir::def_id::DefId; -use ty::subst::Substs; -use rustc_const_math::*; - use self::ConstVal::*; pub use rustc_const_math::ConstInt; +use hir; +use hir::def::Def; +use hir::def_id::DefId; +use ty::TyCtxt; +use ty::subst::Substs; +use util::common::ErrorReported; +use rustc_const_math::*; + +use graphviz::IntoCow; +use errors::DiagnosticBuilder; +use syntax::symbol::InternedString; +use syntax::ast; +use syntax_pos::Span; + +use std::borrow::Cow; use std::collections::BTreeMap; +use std::rc::Rc; + +pub type EvalResult<'tcx> = Result, ConstEvalErr<'tcx>>; #[derive(Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq)] pub enum ConstVal<'tcx> { @@ -27,12 +38,13 @@ pub enum ConstVal<'tcx> { Str(InternedString), ByteStr(Rc>), Bool(bool), + Char(char), + Variant(DefId), Function(DefId, &'tcx Substs<'tcx>), Struct(BTreeMap>), Tuple(Vec>), Array(Vec>), Repeat(Box>, u64), - Char(char), } impl<'tcx> ConstVal<'tcx> { @@ -43,12 +55,13 @@ impl<'tcx> ConstVal<'tcx> { Str(_) => "string literal", ByteStr(_) => "byte string literal", Bool(_) => "boolean", + Char(..) => "char", + Variant(_) => "enum variant", Struct(_) => "struct", Tuple(_) => "tuple", Function(..) => "function definition", Array(..) => "array", Repeat(..) => "repeat", - Char(..) => "char", } } @@ -61,3 +74,180 @@ impl<'tcx> ConstVal<'tcx> { } } } + +#[derive(Clone, Debug)] +pub struct ConstEvalErr<'tcx> { + pub span: Span, + pub kind: ErrKind<'tcx>, +} + +#[derive(Clone, Debug)] +pub enum ErrKind<'tcx> { + CannotCast, + MissingStructField, + NegateOn(ConstVal<'tcx>), + NotOn(ConstVal<'tcx>), + + NonConstPath, + UnimplementedConstVal(&'static str), + ExpectedConstTuple, + ExpectedConstStruct, + IndexedNonVec, + IndexNotUsize, + IndexOutOfBounds { len: u64, index: u64 }, + + MiscBinaryOp, + MiscCatchAll, + + IndexOpFeatureGated, + Math(ConstMathErr), + + ErroneousReferencedConstant(Box>), + + TypeckError +} + +impl<'tcx> From for ErrKind<'tcx> { + fn from(err: ConstMathErr) -> ErrKind<'tcx> { + match err { + ConstMathErr::UnsignedNegation => ErrKind::TypeckError, + _ => ErrKind::Math(err) + } + } +} + +#[derive(Clone, Debug)] +pub enum ConstEvalErrDescription<'a> { + Simple(Cow<'a, str>), +} + +impl<'a> ConstEvalErrDescription<'a> { + /// Return a one-line description of the error, for lints and such + pub fn into_oneline(self) -> Cow<'a, str> { + match self { + ConstEvalErrDescription::Simple(simple) => simple, + } + } +} + +impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> { + pub fn description(&self) -> ConstEvalErrDescription { + use self::ErrKind::*; + use self::ConstEvalErrDescription::*; + + macro_rules! simple { + ($msg:expr) => ({ Simple($msg.into_cow()) }); + ($fmt:expr, $($arg:tt)+) => ({ + Simple(format!($fmt, $($arg)+).into_cow()) + }) + } + + match self.kind { + CannotCast => simple!("can't cast this type"), + NegateOn(ref const_val) => simple!("negate on {}", const_val.description()), + NotOn(ref const_val) => simple!("not on {}", const_val.description()), + + MissingStructField => simple!("nonexistent struct field"), + NonConstPath => simple!("non-constant path in constant expression"), + UnimplementedConstVal(what) => + simple!("unimplemented constant expression: {}", what), + ExpectedConstTuple => simple!("expected constant tuple"), + ExpectedConstStruct => simple!("expected constant struct"), + IndexedNonVec => simple!("indexing is only supported for arrays"), + IndexNotUsize => simple!("indices must be of type `usize`"), + IndexOutOfBounds { len, index } => { + simple!("index out of bounds: the len is {} but the index is {}", + len, index) + } + + MiscBinaryOp => simple!("bad operands for binary"), + MiscCatchAll => simple!("unsupported constant expr"), + IndexOpFeatureGated => simple!("the index operation on const values is unstable"), + Math(ref err) => Simple(err.description().into_cow()), + + ErroneousReferencedConstant(_) => simple!("could not evaluate referenced constant"), + + TypeckError => simple!("type-checking failed"), + } + } + + pub fn struct_error(&self, + tcx: TyCtxt<'a, 'gcx, 'tcx>, + primary_span: Span, + primary_kind: &str) + -> DiagnosticBuilder<'gcx> + { + let mut err = self; + while let &ConstEvalErr { + kind: ErrKind::ErroneousReferencedConstant(box ref i_err), .. + } = err { + err = i_err; + } + + let mut diag = struct_span_err!(tcx.sess, err.span, E0080, "constant evaluation error"); + err.note(tcx, primary_span, primary_kind, &mut diag); + diag + } + + pub fn note(&self, + _tcx: TyCtxt<'a, 'gcx, 'tcx>, + primary_span: Span, + primary_kind: &str, + diag: &mut DiagnosticBuilder) + { + match self.description() { + ConstEvalErrDescription::Simple(message) => { + diag.span_label(self.span, &message); + } + } + + if !primary_span.contains(self.span) { + diag.span_note(primary_span, + &format!("for {} here", primary_kind)); + } + } + + pub fn report(&self, + tcx: TyCtxt<'a, 'gcx, 'tcx>, + primary_span: Span, + primary_kind: &str) + { + if let ErrKind::TypeckError = self.kind { + return; + } + self.struct_error(tcx, primary_span, primary_kind).emit(); + } +} + +/// Returns the value of the length-valued expression +pub fn eval_length(tcx: TyCtxt, + count: hir::BodyId, + reason: &str) + -> Result +{ + let count_expr = &tcx.hir.body(count).value; + let count_def_id = tcx.hir.body_owner_def_id(count); + let substs = Substs::empty(); + match tcx.at(count_expr.span).const_eval((count_def_id, substs)) { + Ok(Integral(Usize(count))) => { + let val = count.as_u64(tcx.sess.target.uint_type); + assert_eq!(val as usize as u64, val); + Ok(val as usize) + }, + Ok(_) | + Err(ConstEvalErr { kind: ErrKind::TypeckError, .. }) => Err(ErrorReported), + Err(err) => { + let mut diag = err.struct_error(tcx, count_expr.span, reason); + + if let hir::ExprPath(hir::QPath::Resolved(None, ref path)) = count_expr.node { + if let Def::Local(..) = path.def { + diag.note(&format!("`{}` is a variable", + tcx.hir.node_to_pretty_string(count_expr.id))); + } + } + + diag.emit(); + Err(ErrorReported) + } + } +} diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 225d6fc9bb2b..303c5059e7cf 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -22,11 +22,12 @@ // are *mostly* used as a part of that interface, but these should // probably get a better home if someone can find one. -use hir::def::{self, Def}; +use hir::def; use hir::def_id::{CrateNum, DefId, DefIndex}; use hir::map as hir_map; use hir::map::definitions::{Definitions, DefKey, DisambiguatedDefPathData}; use hir::svh::Svh; +use ich; use middle::lang_items; use ty::{self, TyCtxt}; use session::Session; @@ -34,11 +35,9 @@ use session::search_paths::PathKind; use util::nodemap::{NodeSet, DefIdMap}; use std::any::Any; -use std::collections::BTreeMap; use std::path::PathBuf; use std::rc::Rc; use syntax::ast; -use syntax::attr; use syntax::ext::base::SyntaxExtension; use syntax::symbol::Symbol; use syntax_pos::Span; @@ -52,7 +51,6 @@ pub use self::NativeLibraryKind::*; #[derive(Clone, Debug)] pub struct LinkMeta { - pub crate_name: Symbol, pub crate_hash: Svh, } @@ -161,28 +159,37 @@ pub struct ExternCrate { pub path_len: usize, } +pub struct EncodedMetadata { + pub raw_data: Vec, + pub hashes: Vec, +} + +/// The hash for some metadata that (when saving) will be exported +/// from this crate, or which (when importing) was exported by an +/// upstream crate. +#[derive(Debug, RustcEncodable, RustcDecodable, Copy, Clone)] +pub struct EncodedMetadataHash { + pub def_index: DefIndex, + pub hash: ich::Fingerprint, +} + /// A store of Rust crates, through with their metadata /// can be accessed. pub trait CrateStore { fn crate_data_as_rc_any(&self, krate: CrateNum) -> Rc; // item info - fn describe_def(&self, def: DefId) -> Option; - fn def_span(&self, sess: &Session, def: DefId) -> Span; - fn stability(&self, def: DefId) -> Option; - fn deprecation(&self, def: DefId) -> Option; fn visibility(&self, def: DefId) -> ty::Visibility; - fn visible_parent_map<'a>(&'a self) -> ::std::cell::RefMut<'a, DefIdMap>; + fn visible_parent_map<'a>(&'a self) -> ::std::cell::Ref<'a, DefIdMap>; fn item_generics_cloned(&self, def: DefId) -> ty::Generics; - fn item_attrs(&self, def_id: DefId) -> Vec; + fn item_attrs(&self, def_id: DefId) -> Rc<[ast::Attribute]>; fn fn_arg_names(&self, did: DefId) -> Vec; - fn inherent_implementations_for_type(&self, def_id: DefId) -> Vec; // trait info fn implementations_of_trait(&self, filter: Option) -> Vec; // impl info - fn impl_polarity(&self, def: DefId) -> hir::ImplPolarity; + fn impl_defaultness(&self, def: DefId) -> hir::Defaultness; fn impl_parent(&self, impl_def_id: DefId) -> Option; // trait/impl-item info @@ -231,17 +238,14 @@ pub trait CrateStore { -> Option; fn def_key(&self, def: DefId) -> DefKey; fn def_path(&self, def: DefId) -> hir_map::DefPath; + fn def_path_hash(&self, def: DefId) -> u64; fn struct_field_names(&self, def: DefId) -> Vec; fn item_children(&self, did: DefId) -> Vec; fn load_macro(&self, did: DefId, sess: &Session) -> LoadedMacro; // misc. metadata - fn maybe_get_item_body<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) - -> Option<&'tcx hir::Body>; - fn item_body_nested_bodies(&self, def: DefId) -> BTreeMap; - fn const_is_rvalue_promotable_to_static(&self, def: DefId) -> bool; - - fn is_item_mir_available(&self, def: DefId) -> bool; + fn item_body<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) + -> &'tcx hir::Body; // This is basically a 1-based range of ints, which is a little // silly - I may fix that. @@ -255,10 +259,11 @@ pub trait CrateStore { fn used_crates(&self, prefer: LinkagePreference) -> Vec<(CrateNum, LibSource)>; fn used_crate_source(&self, cnum: CrateNum) -> CrateSource; fn extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option; - fn encode_metadata<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - reexports: &def::ExportMap, + fn encode_metadata<'a, 'tcx>(&self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, link_meta: &LinkMeta, - reachable: &NodeSet) -> Vec; + reachable: &NodeSet) + -> EncodedMetadata; fn metadata_encoding_version(&self) -> &[u8]; } @@ -298,25 +303,20 @@ impl CrateStore for DummyCrateStore { fn crate_data_as_rc_any(&self, krate: CrateNum) -> Rc { bug!("crate_data_as_rc_any") } // item info - fn describe_def(&self, def: DefId) -> Option { bug!("describe_def") } - fn def_span(&self, sess: &Session, def: DefId) -> Span { bug!("def_span") } - fn stability(&self, def: DefId) -> Option { bug!("stability") } - fn deprecation(&self, def: DefId) -> Option { bug!("deprecation") } fn visibility(&self, def: DefId) -> ty::Visibility { bug!("visibility") } - fn visible_parent_map<'a>(&'a self) -> ::std::cell::RefMut<'a, DefIdMap> { + fn visible_parent_map<'a>(&'a self) -> ::std::cell::Ref<'a, DefIdMap> { bug!("visible_parent_map") } fn item_generics_cloned(&self, def: DefId) -> ty::Generics { bug!("item_generics_cloned") } - fn item_attrs(&self, def_id: DefId) -> Vec { bug!("item_attrs") } + fn item_attrs(&self, def_id: DefId) -> Rc<[ast::Attribute]> { bug!("item_attrs") } fn fn_arg_names(&self, did: DefId) -> Vec { bug!("fn_arg_names") } - fn inherent_implementations_for_type(&self, def_id: DefId) -> Vec { vec![] } // trait info fn implementations_of_trait(&self, filter: Option) -> Vec { vec![] } // impl info - fn impl_polarity(&self, def: DefId) -> hir::ImplPolarity { bug!("impl_polarity") } + fn impl_defaultness(&self, def: DefId) -> hir::Defaultness { bug!("impl_defaultness") } fn impl_parent(&self, def: DefId) -> Option { bug!("impl_parent") } // trait/impl-item info @@ -379,24 +379,17 @@ impl CrateStore for DummyCrateStore { fn def_path(&self, def: DefId) -> hir_map::DefPath { bug!("relative_def_path") } + fn def_path_hash(&self, def: DefId) -> u64 { + bug!("wa") + } fn struct_field_names(&self, def: DefId) -> Vec { bug!("struct_field_names") } fn item_children(&self, did: DefId) -> Vec { bug!("item_children") } fn load_macro(&self, did: DefId, sess: &Session) -> LoadedMacro { bug!("load_macro") } // misc. metadata - fn maybe_get_item_body<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) - -> Option<&'tcx hir::Body> { - bug!("maybe_get_item_body") - } - fn item_body_nested_bodies(&self, def: DefId) -> BTreeMap { - bug!("item_body_nested_bodies") - } - fn const_is_rvalue_promotable_to_static(&self, def: DefId) -> bool { - bug!("const_is_rvalue_promotable_to_static") - } - - fn is_item_mir_available(&self, def: DefId) -> bool { - bug!("is_item_mir_available") + fn item_body<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) + -> &'tcx hir::Body { + bug!("item_body") } // This is basically a 1-based range of ints, which is a little @@ -412,10 +405,13 @@ impl CrateStore for DummyCrateStore { { vec![] } fn used_crate_source(&self, cnum: CrateNum) -> CrateSource { bug!("used_crate_source") } fn extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option { None } - fn encode_metadata<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - reexports: &def::ExportMap, - link_meta: &LinkMeta, - reachable: &NodeSet) -> Vec { vec![] } + fn encode_metadata<'a, 'tcx>(&self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + link_meta: &LinkMeta, + reachable: &NodeSet) + -> EncodedMetadata { + bug!("encode_metadata") + } fn metadata_encoding_version(&self) -> &[u8] { bug!("metadata_encoding_version") } } diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index cc6d6e88dee4..84ead6506c85 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -12,7 +12,6 @@ // closely. The idea is that all reachable symbols are live, codes called // from live codes are live, and everything else is dead. -use dep_graph::DepNode; use hir::map as hir_map; use hir::{self, PatKind}; use hir::intravisit::{self, Visitor, NestedVisitorMap}; @@ -21,7 +20,7 @@ use hir::itemlikevisit::ItemLikeVisitor; use middle::privacy; use ty::{self, TyCtxt}; use hir::def::Def; -use hir::def_id::{DefId}; +use hir::def_id::{DefId, LOCAL_CRATE}; use lint; use util::nodemap::FxHashSet; @@ -160,8 +159,8 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { match item.node { hir::ItemStruct(..) | hir::ItemUnion(..) => { let def_id = self.tcx.hir.local_def_id(item.id); - let def = self.tcx.lookup_adt_def(def_id); - self.struct_has_extern_repr = def.repr.c; + let def = self.tcx.adt_def(def_id); + self.struct_has_extern_repr = def.repr.c(); intravisit::walk_item(self, &item); } @@ -284,6 +283,12 @@ fn has_allow_dead_code_or_lang_attr(attrs: &[ast::Attribute]) -> bool { return true; } + // #[used] also keeps the item alive forcefully, + // e.g. for placing it in a specific section. + if attr::contains_name(attrs, "used") { + return true; + } + let dead_code = lint::builtin::DEAD_CODE.name_lower(); for attr in lint::gather_attrs(attrs) { match attr { @@ -433,7 +438,7 @@ impl<'a, 'tcx> DeadVisitor<'a, 'tcx> { } fn should_warn_about_field(&mut self, field: &hir::StructField) -> bool { - let field_type = self.tcx.item_type(self.tcx.hir.local_def_id(field.id)); + let field_type = self.tcx.type_of(self.tcx.hir.local_def_id(field.id)); let is_marker_field = match field_type.ty_to_def_id() { Some(def_id) => self.tcx.lang_items.items().iter().any(|item| *item == Some(def_id)), _ => false @@ -476,14 +481,13 @@ impl<'a, 'tcx> DeadVisitor<'a, 'tcx> { // This is done to handle the case where, for example, the static // method of a private type is used, but the type itself is never // called directly. - if let Some(impl_list) = - self.tcx.maps.inherent_impls.borrow().get(&self.tcx.hir.local_def_id(id)) { - for &impl_did in impl_list.iter() { - for &item_did in &self.tcx.associated_item_def_ids(impl_did)[..] { - if let Some(item_node_id) = self.tcx.hir.as_local_node_id(item_did) { - if self.live_symbols.contains(&item_node_id) { - return true; - } + let def_id = self.tcx.hir.local_def_id(id); + let inherent_impls = self.tcx.inherent_impls(def_id); + for &impl_did in inherent_impls.iter() { + for &item_did in &self.tcx.associated_item_def_ids(impl_did)[..] { + if let Some(item_node_id) = self.tcx.hir.as_local_node_id(item_did) { + if self.live_symbols.contains(&item_node_id) { + return true; } } } @@ -592,9 +596,8 @@ impl<'a, 'tcx> Visitor<'tcx> for DeadVisitor<'a, 'tcx> { } } -pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - access_levels: &privacy::AccessLevels) { - let _task = tcx.dep_graph.in_task(DepNode::DeadCheck); +pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { + let access_levels = &tcx.privacy_access_levels(LOCAL_CRATE); let krate = tcx.hir.krate(); let live_symbols = find_live(tcx, access_levels, krate); let mut visitor = DeadVisitor { tcx: tcx, live_symbols: live_symbols }; diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs index 5af8e7e52d88..d2b8ed8c2970 100644 --- a/src/librustc/middle/effect.rs +++ b/src/librustc/middle/effect.rs @@ -12,7 +12,6 @@ //! `unsafe`. use self::RootUnsafeContext::*; -use dep_graph::DepNode; use ty::{self, Ty, TyCtxt}; use ty::MethodCall; use lint; @@ -241,8 +240,6 @@ impl<'a, 'tcx> Visitor<'tcx> for EffectCheckVisitor<'a, 'tcx> { } pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - let _task = tcx.dep_graph.in_task(DepNode::EffectCheck); - let mut visitor = EffectCheckVisitor { tcx: tcx, tables: &ty::TypeckTables::empty(), diff --git a/src/librustc/middle/entry.rs b/src/librustc/middle/entry.rs index ff7adfb327ad..8da7560387f8 100644 --- a/src/librustc/middle/entry.rs +++ b/src/librustc/middle/entry.rs @@ -9,7 +9,6 @@ // except according to those terms. -use dep_graph::DepNode; use hir::map as hir_map; use hir::def_id::{CRATE_DEF_INDEX}; use session::{config, Session}; @@ -57,8 +56,6 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for EntryContext<'a, 'tcx> { } pub fn find_entry_point(session: &Session, hir_map: &hir_map::Map) { - let _task = hir_map.dep_graph.in_task(DepNode::EntryPoint); - let any_exe = session.crate_types.borrow().iter().any(|ty| { *ty == config::CrateTypeExecutable }); diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index a44679b0b3e0..41f9311dd809 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -23,6 +23,7 @@ use hir::def::Def; use hir::def_id::{DefId}; use infer::InferCtxt; use middle::mem_categorization as mc; +use middle::region::RegionMaps; use ty::{self, TyCtxt, adjustment}; use hir::{self, PatKind}; @@ -75,7 +76,7 @@ pub trait Delegate<'tcx> { borrow_id: ast::NodeId, borrow_span: Span, cmt: mc::cmt<'tcx>, - loan_region: &'tcx ty::Region, + loan_region: ty::Region<'tcx>, bk: ty::BorrowKind, loan_cause: LoanCause); @@ -270,24 +271,31 @@ enum PassArgs { impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { pub fn new(delegate: &'a mut (Delegate<'tcx>+'a), + region_maps: &'a RegionMaps<'tcx>, infcx: &'a InferCtxt<'a, 'gcx, 'tcx>) -> Self { - ExprUseVisitor::with_options(delegate, infcx, mc::MemCategorizationOptions::default()) + ExprUseVisitor::with_options(delegate, + infcx, + region_maps, + mc::MemCategorizationOptions::default()) } pub fn with_options(delegate: &'a mut (Delegate<'tcx>+'a), infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, + region_maps: &'a RegionMaps<'tcx>, options: mc::MemCategorizationOptions) -> Self { ExprUseVisitor { - mc: mc::MemCategorizationContext::with_options(infcx, options), + mc: mc::MemCategorizationContext::with_options(infcx, region_maps, options), delegate: delegate } } pub fn consume_body(&mut self, body: &hir::Body) { + debug!("consume_body(body={:?})", body); + for arg in &body.arguments { let arg_ty = return_if_err!(self.mc.infcx.node_ty(arg.pat.id)); @@ -345,7 +353,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { fn borrow_expr(&mut self, expr: &hir::Expr, - r: &'tcx ty::Region, + r: ty::Region<'tcx>, bk: ty::BorrowKind, cause: LoanCause) { debug!("borrow_expr(expr={:?}, r={:?}, bk={:?})", @@ -414,9 +422,9 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { self.consume_exprs(exprs); } - hir::ExprIf(ref cond_expr, ref then_blk, ref opt_else_expr) => { + hir::ExprIf(ref cond_expr, ref then_expr, ref opt_else_expr) => { self.consume_expr(&cond_expr); - self.walk_block(&then_blk); + self.walk_expr(&then_expr); if let Some(ref else_expr) = *opt_else_expr { self.consume_expr(&else_expr); } @@ -424,7 +432,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { hir::ExprMatch(ref discr, ref arms, _) => { let discr_cmt = return_if_err!(self.mc.cat_expr(&discr)); - let r = self.tcx().mk_region(ty::ReEmpty); + let r = self.tcx().types.re_empty; self.borrow_expr(&discr, r, ty::ImmBorrow, MatchDiscriminant); // treatment of the discriminant is handled while walking the arms. @@ -996,7 +1004,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { Def::Variant(variant_did) | Def::VariantCtor(variant_did, ..) => { let enum_did = tcx.parent_def_id(variant_did).unwrap(); - let downcast_cmt = if tcx.lookup_adt_def(enum_did).is_univariant() { + let downcast_cmt = if tcx.adt_def(enum_did).is_univariant() { cmt_pat } else { let cmt_pat_ty = cmt_pat.ty; diff --git a/src/librustc/middle/free_region.rs b/src/librustc/middle/free_region.rs index cdb081ab4009..2dc7aac04aed 100644 --- a/src/librustc/middle/free_region.rs +++ b/src/librustc/middle/free_region.rs @@ -15,18 +15,119 @@ //! `TransitiveRelation` type and use that to decide when one free //! region outlives another and so forth. -use ty::{self, TyCtxt, FreeRegion, Region}; +use hir::def_id::DefId; +use middle::region::RegionMaps; +use ty::{self, Lift, TyCtxt, Region}; use ty::wf::ImpliedBound; use rustc_data_structures::transitive_relation::TransitiveRelation; -#[derive(Clone, RustcEncodable, RustcDecodable)] -pub struct FreeRegionMap { - // Stores the relation `a < b`, where `a` and `b` are regions. - relation: TransitiveRelation +/// Combines a `RegionMaps` (which governs relationships between +/// scopes) and a `FreeRegionMap` (which governs relationships between +/// free regions) to yield a complete relation between concrete +/// regions. +/// +/// This stuff is a bit convoluted and should be refactored, but as we +/// move to NLL it'll all go away anyhow. +pub struct RegionRelations<'a, 'gcx: 'tcx, 'tcx: 'a> { + pub tcx: TyCtxt<'a, 'gcx, 'tcx>, + + /// context used to fetch the region maps + pub context: DefId, + + /// region maps for the given context + pub region_maps: &'a RegionMaps<'tcx>, + + /// free-region relationships + pub free_regions: &'a FreeRegionMap<'tcx>, } -impl FreeRegionMap { - pub fn new() -> FreeRegionMap { +impl<'a, 'gcx, 'tcx> RegionRelations<'a, 'gcx, 'tcx> { + pub fn new( + tcx: TyCtxt<'a, 'gcx, 'tcx>, + context: DefId, + region_maps: &'a RegionMaps<'tcx>, + free_regions: &'a FreeRegionMap<'tcx>, + ) -> Self { + Self { + tcx, + context, + region_maps, + free_regions, + } + } + + /// Determines whether one region is a subregion of another. This is intended to run *after + /// inference* and sadly the logic is somewhat duplicated with the code in infer.rs. + pub fn is_subregion_of(&self, + sub_region: ty::Region<'tcx>, + super_region: ty::Region<'tcx>) + -> bool { + let result = sub_region == super_region || { + match (sub_region, super_region) { + (&ty::ReEmpty, _) | + (_, &ty::ReStatic) => + true, + + (&ty::ReScope(sub_scope), &ty::ReScope(super_scope)) => + self.region_maps.is_subscope_of(sub_scope, super_scope), + + (&ty::ReScope(sub_scope), &ty::ReFree(fr)) => { + // 1. It is safe to unwrap `fr.scope` because we + // should only ever wind up comparing against + // `ReScope` in the context of a method or + // body, where `fr.scope` should be `Some`. + self.region_maps.is_subscope_of(sub_scope, fr.scope.unwrap() /*1*/) || + self.is_static(super_region) + } + + (&ty::ReFree(_), &ty::ReFree(_)) => + self.free_regions.relation.contains(&sub_region, &super_region) || + self.is_static(super_region), + + (&ty::ReStatic, &ty::ReFree(_)) => + self.is_static(super_region), + + _ => + false, + } + }; + debug!("is_subregion_of(sub_region={:?}, super_region={:?}) = {:?}", + sub_region, super_region, result); + result + } + + /// Determines whether this free-region is required to be 'static + fn is_static(&self, super_region: ty::Region<'tcx>) -> bool { + debug!("is_static(super_region={:?})", super_region); + match *super_region { + ty::ReStatic => true, + ty::ReFree(_) => { + let re_static = self.tcx.mk_region(ty::ReStatic); + self.free_regions.relation.contains(&re_static, &super_region) + } + _ => bug!("only free regions should be given to `is_static`") + } + } + + pub fn lub_free_regions(&self, + r_a: Region<'tcx>, + r_b: Region<'tcx>) + -> Region<'tcx> { + self.free_regions.lub_free_regions(self.tcx, r_a, r_b) + } +} + +#[derive(Clone, RustcEncodable, RustcDecodable)] +pub struct FreeRegionMap<'tcx> { + // Stores the relation `a < b`, where `a` and `b` are regions. + // + // Invariant: only free regions like `'x` or `'static` are stored + // in this relation, not scopes. + relation: TransitiveRelation> +} + +impl<'tcx> FreeRegionMap<'tcx> { + pub fn new() -> Self { FreeRegionMap { relation: TransitiveRelation::new() } } @@ -34,15 +135,16 @@ impl FreeRegionMap { self.relation.is_empty() } - pub fn relate_free_regions_from_implied_bounds<'tcx>(&mut self, - implied_bounds: &[ImpliedBound<'tcx>]) + pub fn relate_free_regions_from_implied_bounds(&mut self, + implied_bounds: &[ImpliedBound<'tcx>]) { debug!("relate_free_regions_from_implied_bounds()"); for implied_bound in implied_bounds { debug!("implied bound: {:?}", implied_bound); match *implied_bound { - ImpliedBound::RegionSubRegion(&ty::ReFree(free_a), &ty::ReFree(free_b)) => { - self.relate_free_regions(free_a, free_b); + ImpliedBound::RegionSubRegion(a @ &ty::ReFree(_), b @ &ty::ReFree(_)) | + ImpliedBound::RegionSubRegion(a @ &ty::ReStatic, b @ &ty::ReFree(_)) => { + self.relate_regions(a, b); } ImpliedBound::RegionSubRegion(..) | ImpliedBound::RegionSubParam(..) | @@ -53,13 +155,14 @@ impl FreeRegionMap { } pub fn relate_free_regions_from_predicates(&mut self, - predicates: &[ty::Predicate]) { + predicates: &[ty::Predicate<'tcx>]) { debug!("relate_free_regions_from_predicates(predicates={:?})", predicates); for predicate in predicates { match *predicate { ty::Predicate::Projection(..) | ty::Predicate::Trait(..) | ty::Predicate::Equate(..) | + ty::Predicate::Subtype(..) | ty::Predicate::WellFormed(..) | ty::Predicate::ObjectSafe(..) | ty::Predicate::ClosureKind(..) | @@ -68,12 +171,15 @@ impl FreeRegionMap { } ty::Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(r_a, r_b))) => { match (r_a, r_b) { + // `'static: 'x` is not notable (&ty::ReStatic, &ty::ReFree(_)) => {}, - (&ty::ReFree(fr_a), &ty::ReStatic) => self.relate_to_static(fr_a), - (&ty::ReFree(fr_a), &ty::ReFree(fr_b)) => { + + (&ty::ReFree(_), &ty::ReStatic) | + (&ty::ReFree(_), &ty::ReFree(_)) => { // Record that `'a:'b`. Or, put another way, `'b <= 'a`. - self.relate_free_regions(fr_b, fr_a); + self.relate_regions(r_b, r_a); } + _ => { // All named regions are instantiated with free regions. bug!("record_region_bounds: non free region: {:?} / {:?}", @@ -86,97 +192,38 @@ impl FreeRegionMap { } } - fn relate_to_static(&mut self, sup: FreeRegion) { - self.relation.add(ty::ReStatic, ty::ReFree(sup)); + fn relate_regions(&mut self, sub: Region<'tcx>, sup: Region<'tcx>) { + assert!(match *sub { ty::ReFree(_) | ty::ReStatic => true, _ => false }); + assert!(match *sup { ty::ReFree(_) | ty::ReStatic => true, _ => false }); + self.relation.add(sub, sup) } - fn relate_free_regions(&mut self, sub: FreeRegion, sup: FreeRegion) { - self.relation.add(ty::ReFree(sub), ty::ReFree(sup)) - } - - /// Determines whether two free regions have a subregion relationship - /// by walking the graph encoded in `map`. Note that - /// it is possible that `sub != sup` and `sub <= sup` and `sup <= sub` - /// (that is, the user can give two different names to the same lifetime). - pub fn sub_free_region(&self, sub: FreeRegion, sup: FreeRegion) -> bool { - let result = sub == sup || { - let sub = ty::ReFree(sub); - let sup = ty::ReFree(sup); - self.relation.contains(&sub, &sup) || self.relation.contains(&ty::ReStatic, &sup) - }; - debug!("sub_free_region(sub={:?}, sup={:?}) = {:?}", sub, sup, result); - result - } - - pub fn lub_free_regions(&self, fr_a: FreeRegion, fr_b: FreeRegion) -> Region { - let r_a = ty::ReFree(fr_a); - let r_b = ty::ReFree(fr_b); - let result = if fr_a == fr_b { r_a } else { + pub fn lub_free_regions<'a, 'gcx>(&self, + tcx: TyCtxt<'a, 'gcx, 'tcx>, + r_a: Region<'tcx>, + r_b: Region<'tcx>) + -> Region<'tcx> { + assert!(match *r_a { ty::ReFree(_) => true, _ => false }); + assert!(match *r_b { ty::ReFree(_) => true, _ => false }); + let result = if r_a == r_b { r_a } else { match self.relation.postdom_upper_bound(&r_a, &r_b) { - None => ty::ReStatic, + None => tcx.mk_region(ty::ReStatic), Some(r) => *r, } }; - debug!("lub_free_regions(fr_a={:?}, fr_b={:?}) = {:?}", fr_a, fr_b, result); + debug!("lub_free_regions(r_a={:?}, r_b={:?}) = {:?}", r_a, r_b, result); result } +} - /// Determines whether one region is a subregion of another. This is intended to run *after - /// inference* and sadly the logic is somewhat duplicated with the code in infer.rs. - pub fn is_subregion_of(&self, - tcx: TyCtxt, - sub_region: &ty::Region, - super_region: &ty::Region) - -> bool { - let result = sub_region == super_region || { - match (sub_region, super_region) { - (&ty::ReEmpty, _) | - (_, &ty::ReStatic) => - true, +impl_stable_hash_for!(struct FreeRegionMap<'tcx> { + relation +}); - (&ty::ReScope(sub_scope), &ty::ReScope(super_scope)) => - tcx.region_maps.is_subscope_of(sub_scope, super_scope), - - (&ty::ReScope(sub_scope), &ty::ReFree(fr)) => - tcx.region_maps.is_subscope_of(sub_scope, fr.scope) || - self.is_static(fr), - - (&ty::ReFree(sub_fr), &ty::ReFree(super_fr)) => - self.sub_free_region(sub_fr, super_fr), - - (&ty::ReStatic, &ty::ReFree(sup_fr)) => - self.is_static(sup_fr), - - _ => - false, - } - }; - debug!("is_subregion_of(sub_region={:?}, super_region={:?}) = {:?}", - sub_region, super_region, result); - result - } - - /// Determines whether this free-region is required to be 'static - pub fn is_static(&self, super_region: ty::FreeRegion) -> bool { - debug!("is_static(super_region={:?})", super_region); - self.relation.contains(&ty::ReStatic, &ty::ReFree(super_region)) +impl<'a, 'tcx> Lift<'tcx> for FreeRegionMap<'a> { + type Lifted = FreeRegionMap<'tcx>; + fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option> { + self.relation.maybe_map(|&fr| fr.lift_to_tcx(tcx)) + .map(|relation| FreeRegionMap { relation }) } } - -#[cfg(test)] -fn free_region(index: u32) -> FreeRegion { - use middle::region::DUMMY_CODE_EXTENT; - FreeRegion { scope: DUMMY_CODE_EXTENT, - bound_region: ty::BoundRegion::BrAnon(index) } -} - -#[test] -fn lub() { - // a very VERY basic test, but see the tests in - // TransitiveRelation, which are much more thorough. - let frs: Vec<_> = (0..3).map(|i| free_region(i)).collect(); - let mut map = FreeRegionMap::new(); - map.relate_free_regions(frs[0], frs[2]); - map.relate_free_regions(frs[1], frs[2]); - assert_eq!(map.lub_free_regions(frs[0], frs[1]), ty::ReFree(frs[2])); -} diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs index c9722adc9510..435dd05358d4 100644 --- a/src/librustc/middle/intrinsicck.rs +++ b/src/librustc/middle/intrinsicck.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use dep_graph::DepNode; use hir::def::Def; use hir::def_id::DefId; use infer::InferCtxt; @@ -25,7 +24,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let mut visitor = ItemVisitor { tcx: tcx }; - tcx.visit_all_item_likes_in_krate(DepNode::IntrinsicCheck, &mut visitor.as_deep_visitor()); + tcx.hir.krate().visit_all_item_likes(&mut visitor.as_deep_visitor()); } struct ItemVisitor<'a, 'tcx: 'a> { @@ -46,7 +45,7 @@ fn unpack_option_like<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, _ => return ty }; - if def.variants.len() == 2 && !def.repr.c && def.repr.int.is_none() { + if def.variants.len() == 2 && !def.repr.c() && def.repr.int.is_none() { let data_idx; if def.variants[0].fields.is_empty() { @@ -67,7 +66,7 @@ fn unpack_option_like<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl<'a, 'gcx, 'tcx> ExprVisitor<'a, 'gcx, 'tcx> { fn def_id_is_transmute(&self, def_id: DefId) -> bool { - let intrinsic = match self.infcx.tcx.item_type(def_id).sty { + let intrinsic = match self.infcx.tcx.type_of(def_id).sty { ty::TyFnDef(.., bfty) => bfty.abi() == RustIntrinsic, _ => return false }; @@ -89,7 +88,7 @@ impl<'a, 'gcx, 'tcx> ExprVisitor<'a, 'gcx, 'tcx> { let from = unpack_option_like(self.infcx.tcx.global_tcx(), from); match (&from.sty, sk_to) { (&ty::TyFnDef(..), SizeSkeleton::Known(size_to)) - if size_to == Pointer.size(&self.infcx.tcx.data_layout) => { + if size_to == Pointer.size(self.infcx) => { struct_span_err!(self.infcx.tcx.sess, span, E0591, "`{}` is zero-sized and can't be transmuted to `{}`", from, to) diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 81a415a2f530..3b506d748ef7 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -21,7 +21,6 @@ pub use self::LangItem::*; -use dep_graph::DepNode; use hir::map as hir_map; use session::Session; use hir::def_id::DefId; @@ -224,9 +223,10 @@ impl<'a, 'tcx> LanguageItemCollector<'a, 'tcx> { pub fn extract(attrs: &[ast::Attribute]) -> Option { for attribute in attrs { - match attribute.value_str() { - Some(value) if attribute.check_name("lang") => return Some(value), - _ => {} + if attribute.check_name("lang") { + if let Some(value) = attribute.value_str() { + return Some(value) + } } } @@ -236,7 +236,6 @@ pub fn extract(attrs: &[ast::Attribute]) -> Option { pub fn collect_language_items(session: &Session, map: &hir_map::Map) -> LanguageItems { - let _task = map.dep_graph.in_task(DepNode::CollectLanguageItems); let krate: &hir::Crate = map.krate(); let mut collector = LanguageItemCollector::new(session, map); collector.collect(krate); @@ -276,6 +275,7 @@ language_item_table! { UnsizeTraitLangItem, "unsize", unsize_trait; CopyTraitLangItem, "copy", copy_trait; SyncTraitLangItem, "sync", sync_trait; + FreezeTraitLangItem, "freeze", freeze_trait; DropTraitLangItem, "drop", drop_trait; diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 769dc8aeb54d..1ea87cc0a456 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -109,7 +109,6 @@ use self::LoopKind::*; use self::LiveNodeKind::*; use self::VarKind::*; -use dep_graph::DepNode; use hir::def::*; use ty::{self, TyCtxt, ParameterEnvironment}; use traits::{self, Reveal}; @@ -196,7 +195,6 @@ impl<'a, 'tcx> Visitor<'tcx> for IrMaps<'a, 'tcx> { } pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - let _task = tcx.dep_graph.in_task(DepNode::Liveness); tcx.hir.krate().visit_all_item_likes(&mut IrMaps::new(tcx).as_deep_visitor()); tcx.sess.abort_if_errors(); } @@ -821,8 +819,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { fn propagate_through_block(&mut self, blk: &hir::Block, succ: LiveNode) -> LiveNode { - if let Some(break_to_expr_id) = blk.break_to_expr_id { - self.breakable_block_ln.insert(break_to_expr_id, succ); + if blk.targeted_by_break { + self.breakable_block_ln.insert(blk.id, succ); } let succ = self.propagate_through_opt_expr(blk.expr.as_ref().map(|e| &**e), succ); blk.stmts.iter().rev().fold(succ, |succ, stmt| { @@ -951,7 +949,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // ( succ ) // let else_ln = self.propagate_through_opt_expr(els.as_ref().map(|e| &**e), succ); - let then_ln = self.propagate_through_block(&then, succ); + let then_ln = self.propagate_through_expr(&then, succ); let ln = self.live_node(expr.id, expr.span); self.init_from_succ(ln, else_ln); self.merge_from_succ(ln, then_ln, false); @@ -1428,7 +1426,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { entry_ln: LiveNode, body: &hir::Body) { - let fn_ty = self.ir.tcx.item_type(self.ir.tcx.hir.local_def_id(id)); + let fn_ty = self.ir.tcx.type_of(self.ir.tcx.hir.local_def_id(id)); let fn_sig = match fn_ty.sty { ty::TyClosure(closure_def_id, substs) => { self.ir.tcx.closure_type(closure_def_id) @@ -1443,7 +1441,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // and must outlive the *call-site* of the function. let fn_ret = self.ir.tcx.liberate_late_bound_regions( - self.ir.tcx.region_maps.call_site_extent(id, body.value.id), + Some(self.ir.tcx.call_site_extent(id, body.value.id)), &fn_ret); if !fn_ret.is_never() && self.live_on_entry(entry_ln, self.s.no_ret_var).is_some() { diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 0cf53826dd42..11a364f92c31 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -70,6 +70,7 @@ pub use self::Note::*; use self::Aliasability::*; +use middle::region::RegionMaps; use hir::def_id::DefId; use hir::map as hir_map; use infer::InferCtxt; @@ -89,7 +90,7 @@ use std::rc::Rc; #[derive(Clone, PartialEq)] pub enum Categorization<'tcx> { // temporary val, argument is its scope - Rvalue(&'tcx ty::Region, &'tcx ty::Region), + Rvalue(ty::Region<'tcx>, ty::Region<'tcx>), StaticItem, Upvar(Upvar), // upvar referenced by closure env Local(ast::NodeId), // local variable @@ -114,13 +115,13 @@ pub enum PointerKind<'tcx> { Unique, /// `&T` - BorrowedPtr(ty::BorrowKind, &'tcx ty::Region), + BorrowedPtr(ty::BorrowKind, ty::Region<'tcx>), /// `*T` UnsafePtr(hir::Mutability), /// Implicit deref of the `&T` that results from an overloaded index `[]`. - Implicit(ty::BorrowKind, &'tcx ty::Region), + Implicit(ty::BorrowKind, ty::Region<'tcx>), } // We use the term "interior" to mean "something reachable from the @@ -194,76 +195,79 @@ pub struct cmt_<'tcx> { pub type cmt<'tcx> = Rc>; +pub enum ImmutabilityBlame<'tcx> { + ImmLocal(ast::NodeId), + ClosureEnv(ast::NodeId), + LocalDeref(ast::NodeId), + AdtFieldDeref(&'tcx ty::AdtDef, &'tcx ty::FieldDef) +} + impl<'tcx> cmt_<'tcx> { - pub fn get_def(&self) -> Option { - match self.cat { - Categorization::Deref(ref cmt, ..) | - Categorization::Interior(ref cmt, _) | - Categorization::Downcast(ref cmt, _) => { - if let Categorization::Local(nid) = cmt.cat { - Some(nid) - } else { - None - } + fn resolve_field(&self, field_name: FieldName) -> Option<(&'tcx ty::AdtDef, &'tcx ty::FieldDef)> + { + let adt_def = match self.ty.sty { + ty::TyAdt(def, _) => def, + ty::TyTuple(..) => return None, + // closures get `Categorization::Upvar` rather than `Categorization::Interior` + _ => bug!("interior cmt {:?} is not an ADT", self) + }; + let variant_def = match self.cat { + Categorization::Downcast(_, variant_did) => { + adt_def.variant_with_id(variant_did) } - _ => None - } + _ => { + assert!(adt_def.is_univariant()); + &adt_def.variants[0] + } + }; + let field_def = match field_name { + NamedField(name) => variant_def.field_named(name), + PositionalField(idx) => &variant_def.fields[idx] + }; + Some((adt_def, field_def)) } - pub fn get_field(&self, name: ast::Name) -> Option { + pub fn immutability_blame(&self) -> Option> { match self.cat { - Categorization::Deref(ref cmt, ..) | - Categorization::Interior(ref cmt, _) | - Categorization::Downcast(ref cmt, _) => { - if let Categorization::Local(_) = cmt.cat { - if let ty::TyAdt(def, _) = self.ty.sty { - if def.is_struct() { - return def.struct_variant().find_field_named(name).map(|x| x.did); + Categorization::Deref(ref base_cmt, _, BorrowedPtr(ty::ImmBorrow, _)) | + Categorization::Deref(ref base_cmt, _, Implicit(ty::ImmBorrow, _)) => { + // try to figure out where the immutable reference came from + match base_cmt.cat { + Categorization::Local(node_id) => + Some(ImmutabilityBlame::LocalDeref(node_id)), + Categorization::Interior(ref base_cmt, InteriorField(field_name)) => { + base_cmt.resolve_field(field_name).map(|(adt_def, field_def)| { + ImmutabilityBlame::AdtFieldDeref(adt_def, field_def) + }) + } + Categorization::Upvar(Upvar { id, .. }) => { + if let NoteClosureEnv(..) = self.note { + Some(ImmutabilityBlame::ClosureEnv(id.closure_expr_id)) + } else { + None } } - None - } else { - cmt.get_field(name) + _ => None } } - _ => None - } - } - - pub fn get_field_name(&self) -> Option { - match self.cat { - Categorization::Interior(_, ref ik) => { - if let InteriorKind::InteriorField(FieldName::NamedField(name)) = *ik { - Some(name) - } else { - None - } + Categorization::Local(node_id) => { + Some(ImmutabilityBlame::ImmLocal(node_id)) } - Categorization::Deref(ref cmt, ..) | - Categorization::Downcast(ref cmt, _) => { - cmt.get_field_name() + Categorization::Rvalue(..) | + Categorization::Upvar(..) | + Categorization::Deref(.., UnsafePtr(..)) => { + // This should not be reachable up to inference limitations. + None } - _ => None, - } - } - - pub fn get_arg_if_immutable(&self, map: &hir_map::Map) -> Option { - match self.cat { - Categorization::Deref(ref cmt, ..) | - Categorization::Interior(ref cmt, _) | - Categorization::Downcast(ref cmt, _) => { - if let Categorization::Local(nid) = cmt.cat { - if let ty::TyAdt(_, _) = self.ty.sty { - if let ty::TyRef(_, ty::TypeAndMut{mutbl: MutImmutable, ..}) = cmt.ty.sty { - return Some(nid); - } - } - None - } else { - cmt.get_arg_if_immutable(map) - } + Categorization::Interior(ref base_cmt, _) | + Categorization::Downcast(ref base_cmt, _) | + Categorization::Deref(ref base_cmt, _, _) => { + base_cmt.immutability_blame() + } + Categorization::StaticItem => { + // Do we want to do something here? + None } - _ => None } } } @@ -283,9 +287,10 @@ impl ast_node for hir::Pat { fn span(&self) -> Span { self.span } } -#[derive(Copy, Clone)] +#[derive(Clone)] pub struct MemCategorizationContext<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { pub infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, + pub region_maps: &'a RegionMaps<'tcx>, options: MemCategorizationOptions, } @@ -399,16 +404,22 @@ impl MutabilityCategory { } impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { - pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>) + /// Context should be the `DefId` we use to fetch region-maps. + pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, + region_maps: &'a RegionMaps<'tcx>) -> MemCategorizationContext<'a, 'gcx, 'tcx> { - MemCategorizationContext::with_options(infcx, MemCategorizationOptions::default()) + MemCategorizationContext::with_options(infcx, + region_maps, + MemCategorizationOptions::default()) } pub fn with_options(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, + region_maps: &'a RegionMaps<'tcx>, options: MemCategorizationOptions) -> MemCategorizationContext<'a, 'gcx, 'tcx> { MemCategorizationContext { infcx: infcx, + region_maps: region_maps, options: options, } } @@ -448,7 +459,10 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // So peel off one-level, turning the &T into T. match base_ty.builtin_deref(false, ty::NoPreference) { Some(t) => t.ty, - None => { return Err(()); } + None => { + debug!("By-ref binding of non-derefable type {:?}", base_ty); + return Err(()); + } } } _ => base_ty, @@ -780,7 +794,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { }; match fn_expr.node { - hir::ExprClosure(.., body_id, _) => body_id.node_id, + hir::ExprClosure(.., body_id, _) => body_id, _ => bug!() } }; @@ -790,7 +804,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // The environment of a closure is guaranteed to // outlive any bindings introduced in the body of the // closure itself. - scope: self.tcx().region_maps.item_extent(fn_body_id), + scope: Some(self.tcx().item_extent(fn_body_id.node_id)), bound_region: ty::BrEnv })); @@ -836,10 +850,10 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { /// Returns the lifetime of a temporary created by expr with id `id`. /// This could be `'static` if `id` is part of a constant expression. - pub fn temporary_scope(&self, id: ast::NodeId) -> (&'tcx ty::Region, &'tcx ty::Region) + pub fn temporary_scope(&self, id: ast::NodeId) -> (ty::Region<'tcx>, ty::Region<'tcx>) { let (scope, old_scope) = - self.tcx().region_maps.old_and_new_temporary_scope(id); + self.region_maps.old_and_new_temporary_scope(self.tcx(), id); (self.tcx().mk_region(match scope { Some(scope) => ty::ReScope(scope), None => ty::ReStatic @@ -868,8 +882,8 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // we can promote to a constant, otherwise equal to enclosing temp // lifetime. let (re, old_re) = if promotable { - (self.tcx().mk_region(ty::ReStatic), - self.tcx().mk_region(ty::ReStatic)) + (self.tcx().types.re_static, + self.tcx().types.re_static) } else { self.temporary_scope(id) }; @@ -881,8 +895,8 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { pub fn cat_rvalue(&self, cmt_id: ast::NodeId, span: Span, - temp_scope: &'tcx ty::Region, - old_temp_scope: &'tcx ty::Region, + temp_scope: ty::Region<'tcx>, + old_temp_scope: ty::Region<'tcx>, expr_ty: Ty<'tcx>) -> cmt<'tcx> { let ret = Rc::new(cmt_ { id:cmt_id, @@ -1036,6 +1050,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { match base_cmt.ty.builtin_index() { Some(ty) => (ty, ElementKind::VecElement), None => { + debug!("Explicit index of non-indexable type {:?}", base_cmt); return Err(()); } } @@ -1151,12 +1166,15 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { PatKind::TupleStruct(hir::QPath::Resolved(_, ref path), ..) | PatKind::Struct(hir::QPath::Resolved(_, ref path), ..) => { match path.def { - Def::Err => return Err(()), + Def::Err => { + debug!("access to unresolvable pattern {:?}", pat); + return Err(()) + } Def::Variant(variant_did) | Def::VariantCtor(variant_did, ..) => { // univariant enums do not need downcasts let enum_did = self.tcx().parent_def_id(variant_did).unwrap(); - if !self.tcx().lookup_adt_def(enum_did).is_univariant() { + if !self.tcx().adt_def(enum_did).is_univariant() { self.cat_downcast(pat, cmt.clone(), cmt.ty, variant_did) } else { cmt @@ -1174,7 +1192,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { let expected_len = match def { Def::VariantCtor(def_id, CtorKind::Fn) => { let enum_def = self.tcx().parent_def_id(def_id).unwrap(); - self.tcx().lookup_adt_def(enum_def).variant_with_id(def_id).fields.len() + self.tcx().adt_def(enum_def).variant_with_id(def_id).fields.len() } Def::StructCtor(_, CtorKind::Fn) => { match self.pat_ty(&pat)?.sty { @@ -1282,9 +1300,6 @@ pub enum Aliasability { #[derive(Copy, Clone, Debug)] pub enum AliasableReason { AliasableBorrowed, - AliasableClosure(ast::NodeId), // Aliasable due to capture Fn closure env - AliasableOther, - UnaliasableImmutable, // Created as needed upon seeing ImmutableUnique AliasableStatic, AliasableStaticMut, } @@ -1324,23 +1339,13 @@ impl<'tcx> cmt_<'tcx> { Categorization::Deref(ref b, _, Implicit(ty::MutBorrow, _)) | Categorization::Deref(ref b, _, BorrowedPtr(ty::UniqueImmBorrow, _)) | Categorization::Deref(ref b, _, Implicit(ty::UniqueImmBorrow, _)) | + Categorization::Deref(ref b, _, Unique) | Categorization::Downcast(ref b, _) | Categorization::Interior(ref b, _) => { // Aliasability depends on base cmt b.freely_aliasable() } - Categorization::Deref(ref b, _, Unique) => { - let sub = b.freely_aliasable(); - if b.mutbl.is_mutable() { - // Aliasability depends on base cmt alone - sub - } else { - // Do not allow mutation through an immutable box. - ImmutableUnique(Box::new(sub)) - } - } - Categorization::Rvalue(..) | Categorization::Local(..) | Categorization::Upvar(..) | @@ -1356,13 +1361,9 @@ impl<'tcx> cmt_<'tcx> { } } - Categorization::Deref(ref base, _, BorrowedPtr(ty::ImmBorrow, _)) | - Categorization::Deref(ref base, _, Implicit(ty::ImmBorrow, _)) => { - match base.cat { - Categorization::Upvar(Upvar{ id, .. }) => - FreelyAliasable(AliasableClosure(id.closure_expr_id)), - _ => FreelyAliasable(AliasableBorrowed) - } + Categorization::Deref(_, _, BorrowedPtr(ty::ImmBorrow, _)) | + Categorization::Deref(_, _, Implicit(ty::ImmBorrow, _)) => { + FreelyAliasable(AliasableBorrowed) } } } diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 4ec43e368a60..939d7364d9e0 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -15,11 +15,12 @@ // makes all other generics or inline functions that it references // reachable as well. -use dep_graph::DepNode; use hir::map as hir_map; use hir::def::Def; -use hir::def_id::DefId; +use hir::def_id::{DefId, CrateNum}; +use std::rc::Rc; use ty::{self, TyCtxt}; +use ty::maps::Providers; use middle::privacy; use session::config; use util::nodemap::{NodeSet, FxHashSet}; @@ -28,6 +29,7 @@ use syntax::abi::Abi; use syntax::ast; use syntax::attr; use hir; +use hir::def_id::LOCAL_CRATE; use hir::intravisit::{Visitor, NestedVisitorMap}; use hir::itemlikevisit::ItemLikeVisitor; use hir::intravisit; @@ -47,7 +49,7 @@ fn item_might_be_inlined(item: &hir::Item) -> bool { } match item.node { - hir::ItemImpl(_, _, ref generics, ..) | + hir::ItemImpl(_, _, _, ref generics, ..) | hir::ItemFn(.., ref generics, _) => { generics_require_inlining(generics) } @@ -183,7 +185,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { // does too. let impl_node_id = self.tcx.hir.as_local_node_id(impl_did).unwrap(); match self.tcx.hir.expect_item(impl_node_id).node { - hir::ItemImpl(_, _, ref generics, ..) => { + hir::ItemImpl(_, _, _, ref generics, ..) => { generics_require_inlining(generics) } _ => false @@ -265,7 +267,8 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { hir::ItemMod(..) | hir::ItemForeignMod(..) | hir::ItemImpl(..) | hir::ItemTrait(..) | hir::ItemStruct(..) | hir::ItemEnum(..) | - hir::ItemUnion(..) | hir::ItemDefaultImpl(..) => {} + hir::ItemUnion(..) | hir::ItemDefaultImpl(..) | + hir::ItemGlobalAsm(..) => {} } } hir_map::NodeTraitItem(trait_method) => { @@ -359,10 +362,14 @@ impl<'a, 'tcx: 'a> ItemLikeVisitor<'tcx> for CollectPrivateImplItemsVisitor<'a, } } -pub fn find_reachable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - access_levels: &privacy::AccessLevels) - -> NodeSet { - let _task = tcx.dep_graph.in_task(DepNode::Reachability); +pub fn find_reachable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Rc { + tcx.reachable_set(LOCAL_CRATE) +} + +fn reachable_set<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum) -> Rc { + debug_assert!(crate_num == LOCAL_CRATE); + + let access_levels = &tcx.privacy_access_levels(LOCAL_CRATE); let any_library = tcx.sess.crate_types.borrow().iter().any(|ty| { *ty == config::CrateTypeRlib || *ty == config::CrateTypeDylib || @@ -404,5 +411,12 @@ pub fn find_reachable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, reachable_context.propagate(); // Return the set of reachable symbols. - reachable_context.reachable_symbols + Rc::new(reachable_context.reachable_symbols) +} + +pub fn provide(providers: &mut Providers) { + *providers = Providers { + reachable_set, + ..*providers + }; } diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index a19f15a9329f..d1d5e9d6cb18 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -16,50 +16,27 @@ //! Most of the documentation on regions can be found in //! `middle/infer/region_inference/README.md` -use dep_graph::DepNode; use hir::map as hir_map; -use session::Session; use util::nodemap::{FxHashMap, NodeMap, NodeSet}; use ty; -use std::cell::RefCell; -use std::collections::hash_map::Entry; -use std::fmt; use std::mem; +use std::rc::Rc; +use serialize; use syntax::codemap; use syntax::ast::{self, NodeId}; use syntax_pos::Span; +use ty::TyCtxt; +use ty::maps::Providers; -use hir; +use hir; use hir::def_id::DefId; use hir::intravisit::{self, Visitor, FnKind, NestedVisitorMap}; use hir::{Block, Item, FnDecl, Arm, Pat, PatKind, Stmt, Expr, Local}; -#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, RustcEncodable, - RustcDecodable, Copy)] -pub struct CodeExtent(u32); +pub type CodeExtent<'tcx> = &'tcx CodeExtentData; -impl fmt::Debug for CodeExtent { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "CodeExtent({:?}", self.0)?; - - ty::tls::with_opt(|opt_tcx| { - if let Some(tcx) = opt_tcx { - if let Some(data) = tcx.region_maps.code_extents.borrow().get(self.0 as usize) { - write!(f, "/{:?}", data)?; - } - } - Ok(()) - })?; - - write!(f, ")") - } -} - -/// The root of everything. I should be using NonZero or profiling -/// instead of this (probably). -pub const ROOT_CODE_EXTENT : CodeExtent = CodeExtent(0); -/// A placeholder used in trans to stand for real code extents -pub const DUMMY_CODE_EXTENT : CodeExtent = CodeExtent(1); +impl<'tcx> serialize::UseSpecializedEncodable for CodeExtent<'tcx> {} +impl<'tcx> serialize::UseSpecializedDecodable for CodeExtent<'tcx> {} /// CodeExtent represents a statically-describable extent that can be /// used to bound the lifetime/region for values. @@ -122,7 +99,7 @@ pub const DUMMY_CODE_EXTENT : CodeExtent = CodeExtent(1); /// placate the same deriving in `ty::FreeRegion`, but we may want to /// actually attach a more meaningful ordering to scopes than the one /// generated via deriving here. -#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Debug, Copy)] +#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Debug, Copy, RustcEncodable, RustcDecodable)] pub enum CodeExtentData { Misc(ast::NodeId), @@ -149,8 +126,8 @@ pub struct CallSiteScopeData { } impl CallSiteScopeData { - pub fn to_code_extent(&self, region_maps: &RegionMaps) -> CodeExtent { - region_maps.lookup_code_extent( + pub fn to_code_extent<'a, 'tcx, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> CodeExtent<'tcx> { + tcx.intern_code_extent( match *self { CallSiteScopeData { fn_id, body_id } => CodeExtentData::CallSiteScope { fn_id: fn_id, body_id: body_id }, @@ -199,28 +176,14 @@ impl CodeExtentData { CodeExtentData::ParameterScope { fn_id: _, body_id } => body_id, } } -} - -impl CodeExtent { - #[inline] - fn into_option(self) -> Option { - if self == ROOT_CODE_EXTENT { - None - } else { - Some(self) - } - } - pub fn node_id(&self, region_maps: &RegionMaps) -> ast::NodeId { - region_maps.code_extent_data(*self).node_id() - } /// Returns the span of this CodeExtent. Note that in general the /// returned span may not correspond to the span of any node id in /// the AST. - pub fn span(&self, region_maps: &RegionMaps, hir_map: &hir_map::Map) -> Option { - match hir_map.find(self.node_id(region_maps)) { + pub fn span(&self, hir_map: &hir_map::Map) -> Option { + match hir_map.find(self.node_id()) { Some(hir_map::NodeBlock(ref blk)) => { - match region_maps.code_extent_data(*self) { + match *self { CodeExtentData::CallSiteScope { .. } | CodeExtentData::ParameterScope { .. } | CodeExtentData::Misc(_) | @@ -236,7 +199,7 @@ impl CodeExtent { // (This is the special case aluded to in the // doc-comment for this method) let stmt_span = blk.stmts[r.first_statement_index as usize].span; - Some(Span { lo: stmt_span.hi, hi: blk.span.hi, expn_id: stmt_span.expn_id }) + Some(Span { lo: stmt_span.hi, hi: blk.span.hi, ctxt: stmt_span.ctxt }) } } } @@ -249,20 +212,21 @@ impl CodeExtent { } /// The region maps encode information about region relationships. -pub struct RegionMaps { - code_extents: RefCell>, - code_extent_interner: RefCell>, +pub struct RegionMaps<'tcx> { /// `scope_map` maps from a scope id to the enclosing scope id; /// this is usually corresponding to the lexical nesting, though /// in the case of closures the parent scope is the innermost /// conditional expression or repeating block. (Note that the /// enclosing scope id for the block associated with a closure is /// the closure itself.) - scope_map: RefCell>, + scope_map: FxHashMap, CodeExtent<'tcx>>, /// `var_map` maps from a variable or binding id to the block in /// which that variable is declared. - var_map: RefCell>, + var_map: NodeMap>, + + /// maps from a node-id to the associated destruction scope (if any) + destruction_scopes: NodeMap>, /// `rvalue_scopes` includes entries for those expressions whose cleanup scope is /// larger than the default. The map goes from the expression id @@ -270,14 +234,14 @@ pub struct RegionMaps { /// table, the appropriate cleanup scope is the innermost /// enclosing statement, conditional expression, or repeating /// block (see `terminating_scopes`). - rvalue_scopes: RefCell>, + rvalue_scopes: NodeMap>, /// Records the value of rvalue scopes before they were shrunk by /// #36082, for error reporting. /// /// FIXME: this should be temporary. Remove this by 1.18.0 or /// so. - shrunk_rvalue_scopes: RefCell>, + shrunk_rvalue_scopes: NodeMap>, /// Encodes the hierarchy of fn bodies. Every fn body (including /// closures) forms its own distinct region hierarchy, rooted in @@ -289,11 +253,11 @@ pub struct RegionMaps { /// closure defined by that fn. See the "Modeling closures" /// section of the README in infer::region_inference for /// more details. - fn_tree: RefCell>, + fn_tree: NodeMap, } #[derive(Debug, Copy, Clone)] -pub struct Context { +pub struct Context<'tcx> { /// the root of the current region tree. This is typically the id /// of the innermost fn body. Each fn forms its own disjoint tree /// in the region hierarchy. These fn bodies are themselves @@ -303,21 +267,21 @@ pub struct Context { root_id: Option, /// the scope that contains any new variables declared - var_parent: CodeExtent, + var_parent: Option>, /// region parent of expressions etc - parent: CodeExtent + parent: Option>, } -struct RegionResolutionVisitor<'hir: 'a, 'a> { - sess: &'a Session, +struct RegionResolutionVisitor<'a, 'tcx: 'a> { + tcx: TyCtxt<'a, 'tcx, 'tcx>, // Generated maps: - region_maps: &'a RegionMaps, + region_maps: &'a mut RegionMaps<'tcx>, - cx: Context, + cx: Context<'tcx>, - map: &'a hir_map::Map<'hir>, + map: &'a hir_map::Map<'tcx>, /// `terminating_scopes` is a set containing the ids of each /// statement, or conditional/repeating expression. These scopes @@ -339,155 +303,117 @@ struct RegionResolutionVisitor<'hir: 'a, 'a> { /// arbitrary amounts of stack space. Terminating scopes end /// up being contained in a DestructionScope that contains the /// destructor's execution. - terminating_scopes: NodeSet + terminating_scopes: NodeSet, } -impl RegionMaps { - /// create a bogus code extent for the regions in astencode types. Nobody - /// really cares about the contents of these. - pub fn bogus_code_extent(&self, e: CodeExtentData) -> CodeExtent { - self.intern_code_extent(e, DUMMY_CODE_EXTENT) - } - pub fn lookup_code_extent(&self, e: CodeExtentData) -> CodeExtent { - match self.code_extent_interner.borrow().get(&e) { - Some(&d) => d, - None => bug!("unknown code extent {:?}", e) +impl<'tcx> RegionMaps<'tcx> { + pub fn new() -> Self { + RegionMaps { + scope_map: FxHashMap(), + destruction_scopes: FxHashMap(), + var_map: NodeMap(), + rvalue_scopes: NodeMap(), + shrunk_rvalue_scopes: NodeMap(), + fn_tree: NodeMap(), } } - pub fn node_extent(&self, n: ast::NodeId) -> CodeExtent { - self.lookup_code_extent(CodeExtentData::Misc(n)) - } - // Returns the code extent for an item - the destruction scope. - pub fn item_extent(&self, n: ast::NodeId) -> CodeExtent { - self.lookup_code_extent(CodeExtentData::DestructionScope(n)) - } - pub fn call_site_extent(&self, fn_id: ast::NodeId, body_id: ast::NodeId) -> CodeExtent { - assert!(fn_id != body_id); - self.lookup_code_extent(CodeExtentData::CallSiteScope { fn_id: fn_id, body_id: body_id }) - } - pub fn opt_destruction_extent(&self, n: ast::NodeId) -> Option { - self.code_extent_interner.borrow().get(&CodeExtentData::DestructionScope(n)).cloned() - } - pub fn intern_code_extent(&self, - e: CodeExtentData, - parent: CodeExtent) -> CodeExtent { - match self.code_extent_interner.borrow_mut().entry(e) { - Entry::Occupied(o) => { - // this can happen when the bogus code extents from tydecode - // have (bogus) NodeId-s that overlap items created during - // inlining. - // We probably shouldn't be creating bogus code extents - // though. - let idx = *o.get(); - if parent == DUMMY_CODE_EXTENT { - info!("CodeExtent({}) = {:?} [parent={}] BOGUS!", - idx.0, e, parent.0); - } else { - assert_eq!(self.scope_map.borrow()[idx.0 as usize], - DUMMY_CODE_EXTENT); - info!("CodeExtent({}) = {:?} [parent={}] RECLAIMED!", - idx.0, e, parent.0); - self.scope_map.borrow_mut()[idx.0 as usize] = parent; - } - idx - } - Entry::Vacant(v) => { - if self.code_extents.borrow().len() > 0xffffffffusize { - bug!() // should pass a sess, - // but this isn't the only place - } - let idx = CodeExtent(self.code_extents.borrow().len() as u32); - debug!("CodeExtent({}) = {:?} [parent={}]", idx.0, e, parent.0); - self.code_extents.borrow_mut().push(e); - self.scope_map.borrow_mut().push(parent); - *v.insert(idx) - } + + pub fn record_code_extent(&mut self, + child: CodeExtent<'tcx>, + parent: Option>) { + debug!("{:?}.parent = {:?}", child, parent); + + if let Some(p) = parent { + let prev = self.scope_map.insert(child, p); + assert!(prev.is_none()); + } + + // record the destruction scopes for later so we can query them + if let &CodeExtentData::DestructionScope(n) = child { + self.destruction_scopes.insert(n, child); } } - pub fn intern_node(&self, - n: ast::NodeId, - parent: CodeExtent) -> CodeExtent { - self.intern_code_extent(CodeExtentData::Misc(n), parent) - } - pub fn code_extent_data(&self, e: CodeExtent) -> CodeExtentData { - self.code_extents.borrow()[e.0 as usize] - } - pub fn each_encl_scope(&self, mut e:E) where E: FnMut(&CodeExtent, &CodeExtent) { - for child_id in 1..self.code_extents.borrow().len() { - let child = CodeExtent(child_id as u32); - if let Some(parent) = self.opt_encl_scope(child) { - e(&child, &parent) - } - } - } - pub fn each_var_scope(&self, mut e:E) where E: FnMut(&ast::NodeId, &CodeExtent) { - for (child, parent) in self.var_map.borrow().iter() { + + pub fn each_encl_scope(&self, mut e:E) where E: FnMut(CodeExtent<'tcx>, CodeExtent<'tcx>) { + for (&child, &parent) in &self.scope_map { e(child, parent) } } + pub fn each_var_scope(&self, mut e:E) where E: FnMut(&ast::NodeId, CodeExtent<'tcx>) { + for (child, parent) in self.var_map.iter() { + e(child, parent) + } + } + + pub fn opt_destruction_extent(&self, n: ast::NodeId) -> Option> { + self.destruction_scopes.get(&n).cloned() + } + /// Records that `sub_fn` is defined within `sup_fn`. These ids /// should be the id of the block that is the fn body, which is /// also the root of the region hierarchy for that fn. - fn record_fn_parent(&self, sub_fn: ast::NodeId, sup_fn: ast::NodeId) { + fn record_fn_parent(&mut self, sub_fn: ast::NodeId, sup_fn: ast::NodeId) { debug!("record_fn_parent(sub_fn={:?}, sup_fn={:?})", sub_fn, sup_fn); assert!(sub_fn != sup_fn); - let previous = self.fn_tree.borrow_mut().insert(sub_fn, sup_fn); + let previous = self.fn_tree.insert(sub_fn, sup_fn); assert!(previous.is_none()); } fn fn_is_enclosed_by(&self, mut sub_fn: ast::NodeId, sup_fn: ast::NodeId) -> bool { - let fn_tree = self.fn_tree.borrow(); loop { if sub_fn == sup_fn { return true; } - match fn_tree.get(&sub_fn) { + match self.fn_tree.get(&sub_fn) { Some(&s) => { sub_fn = s; } None => { return false; } } } } - fn record_var_scope(&self, var: ast::NodeId, lifetime: CodeExtent) { + fn record_var_scope(&mut self, var: ast::NodeId, lifetime: CodeExtent<'tcx>) { debug!("record_var_scope(sub={:?}, sup={:?})", var, lifetime); - assert!(var != lifetime.node_id(self)); - self.var_map.borrow_mut().insert(var, lifetime); + assert!(var != lifetime.node_id()); + self.var_map.insert(var, lifetime); } - fn record_rvalue_scope(&self, var: ast::NodeId, lifetime: CodeExtent) { + fn record_rvalue_scope(&mut self, var: ast::NodeId, lifetime: CodeExtent<'tcx>) { debug!("record_rvalue_scope(sub={:?}, sup={:?})", var, lifetime); - assert!(var != lifetime.node_id(self)); - self.rvalue_scopes.borrow_mut().insert(var, lifetime); + assert!(var != lifetime.node_id()); + self.rvalue_scopes.insert(var, lifetime); } - fn record_shrunk_rvalue_scope(&self, var: ast::NodeId, lifetime: CodeExtent) { + fn record_shrunk_rvalue_scope(&mut self, var: ast::NodeId, lifetime: CodeExtent<'tcx>) { debug!("record_rvalue_scope(sub={:?}, sup={:?})", var, lifetime); - assert!(var != lifetime.node_id(self)); - self.shrunk_rvalue_scopes.borrow_mut().insert(var, lifetime); + assert!(var != lifetime.node_id()); + self.shrunk_rvalue_scopes.insert(var, lifetime); } - pub fn opt_encl_scope(&self, id: CodeExtent) -> Option { + pub fn opt_encl_scope(&self, id: CodeExtent<'tcx>) -> Option> { //! Returns the narrowest scope that encloses `id`, if any. - self.scope_map.borrow()[id.0 as usize].into_option() + self.scope_map.get(&id).cloned() } #[allow(dead_code)] // used in cfg - pub fn encl_scope(&self, id: CodeExtent) -> CodeExtent { + pub fn encl_scope(&self, id: CodeExtent<'tcx>) -> CodeExtent<'tcx> { //! Returns the narrowest scope that encloses `id`, if any. self.opt_encl_scope(id).unwrap() } /// Returns the lifetime of the local variable `var_id` - pub fn var_scope(&self, var_id: ast::NodeId) -> CodeExtent { - match self.var_map.borrow().get(&var_id) { + pub fn var_scope(&self, var_id: ast::NodeId) -> CodeExtent<'tcx> { + match self.var_map.get(&var_id) { Some(&r) => r, None => { bug!("no enclosing scope for id {:?}", var_id); } } } - pub fn temporary_scope2(&self, expr_id: ast::NodeId) -> (Option, bool) { - let temporary_scope = self.temporary_scope(expr_id); - let was_shrunk = match self.shrunk_rvalue_scopes.borrow().get(&expr_id) { + pub fn temporary_scope2<'a, 'gcx: 'tcx>(&self, + tcx: TyCtxt<'a, 'gcx, 'tcx>, + expr_id: ast::NodeId) + -> (Option>, bool) { + let temporary_scope = self.temporary_scope(tcx, expr_id); + let was_shrunk = match self.shrunk_rvalue_scopes.get(&expr_id) { Some(&s) => { info!("temporary_scope2({:?}, scope={:?}, shrunk={:?})", expr_id, temporary_scope, s); @@ -499,36 +425,39 @@ impl RegionMaps { (temporary_scope, was_shrunk) } - pub fn old_and_new_temporary_scope(&self, expr_id: ast::NodeId) -> - (Option, Option) + pub fn old_and_new_temporary_scope<'a, 'gcx: 'tcx>(&self, + tcx: TyCtxt<'a, 'gcx, 'tcx>, + expr_id: ast::NodeId) + -> (Option>, + Option>) { - let temporary_scope = self.temporary_scope(expr_id); + let temporary_scope = self.temporary_scope(tcx, expr_id); (temporary_scope, self.shrunk_rvalue_scopes - .borrow().get(&expr_id).cloned() + .get(&expr_id).cloned() .or(temporary_scope)) } - pub fn temporary_scope(&self, expr_id: ast::NodeId) -> Option { + pub fn temporary_scope<'a, 'gcx: 'tcx>(&self, + tcx: TyCtxt<'a, 'gcx, 'tcx>, + expr_id: ast::NodeId) + -> Option> { //! Returns the scope when temp created by expr_id will be cleaned up // check for a designated rvalue scope - if let Some(&s) = self.rvalue_scopes.borrow().get(&expr_id) { + if let Some(&s) = self.rvalue_scopes.get(&expr_id) { debug!("temporary_scope({:?}) = {:?} [custom]", expr_id, s); return Some(s); } - let scope_map : &[CodeExtent] = &self.scope_map.borrow(); - let code_extents: &[CodeExtentData] = &self.code_extents.borrow(); - // else, locate the innermost terminating scope // if there's one. Static items, for instance, won't // have an enclosing scope, hence no scope will be // returned. - let mut id = self.node_extent(expr_id); + let mut id = tcx.node_extent(expr_id); - while let Some(p) = scope_map[id.0 as usize].into_option() { - match code_extents[p.0 as usize] { + while let Some(&p) = self.scope_map.get(id) { + match *p { CodeExtentData::DestructionScope(..) => { debug!("temporary_scope({:?}) = {:?} [enclosing]", expr_id, id); @@ -542,7 +471,7 @@ impl RegionMaps { return None; } - pub fn var_region(&self, id: ast::NodeId) -> ty::Region { + pub fn var_region(&self, id: ast::NodeId) -> ty::RegionKind<'tcx> { //! Returns the lifetime of the variable `id`. let scope = ty::ReScope(self.var_scope(id)); @@ -584,20 +513,22 @@ impl RegionMaps { /// Finds the nearest common ancestor (if any) of two scopes. That is, finds the smallest /// scope which is greater than or equal to both `scope_a` and `scope_b`. pub fn nearest_common_ancestor(&self, - scope_a: CodeExtent, - scope_b: CodeExtent) - -> CodeExtent { + scope_a: CodeExtent<'tcx>, + scope_b: CodeExtent<'tcx>) + -> CodeExtent<'tcx> { if scope_a == scope_b { return scope_a; } - let mut a_buf: [CodeExtent; 32] = [ROOT_CODE_EXTENT; 32]; - let mut a_vec: Vec = vec![]; - let mut b_buf: [CodeExtent; 32] = [ROOT_CODE_EXTENT; 32]; - let mut b_vec: Vec = vec![]; - let scope_map : &[CodeExtent] = &self.scope_map.borrow(); - let a_ancestors = ancestors_of(scope_map, - scope_a, &mut a_buf, &mut a_vec); - let b_ancestors = ancestors_of(scope_map, - scope_b, &mut b_buf, &mut b_vec); + /// [1] The initial values for `a_buf` and `b_buf` are not used. + /// The `ancestors_of` function will return some prefix that + /// is re-initialized with new values (or else fallback to a + /// heap-allocated vector). + let mut a_buf: [CodeExtent; 32] = [scope_a /* [1] */; 32]; + let mut a_vec: Vec> = vec![]; + let mut b_buf: [CodeExtent; 32] = [scope_b /* [1] */; 32]; + let mut b_vec: Vec> = vec![]; + let scope_map = &self.scope_map; + let a_ancestors = ancestors_of(scope_map, scope_a, &mut a_buf, &mut a_vec); + let b_ancestors = ancestors_of(scope_map, scope_b, &mut b_buf, &mut b_vec); let mut a_index = a_ancestors.len() - 1; let mut b_index = b_ancestors.len() - 1; @@ -615,11 +546,11 @@ impl RegionMaps { // nesting. The reasoning behind this is subtle. See the // "Modeling closures" section of the README in // infer::region_inference for more details. - let a_root_scope = self.code_extent_data(a_ancestors[a_index]); - let b_root_scope = self.code_extent_data(a_ancestors[a_index]); + let a_root_scope = a_ancestors[a_index]; + let b_root_scope = a_ancestors[a_index]; return match (a_root_scope, b_root_scope) { - (CodeExtentData::DestructionScope(a_root_id), - CodeExtentData::DestructionScope(b_root_id)) => { + (&CodeExtentData::DestructionScope(a_root_id), + &CodeExtentData::DestructionScope(b_root_id)) => { if self.fn_is_enclosed_by(a_root_id, b_root_id) { // `a` is enclosed by `b`, hence `b` is the ancestor of everything in `a` scope_b @@ -650,17 +581,18 @@ impl RegionMaps { } } - fn ancestors_of<'a>(scope_map: &[CodeExtent], - scope: CodeExtent, - buf: &'a mut [CodeExtent; 32], - vec: &'a mut Vec) -> &'a [CodeExtent] { + fn ancestors_of<'a, 'tcx>(scope_map: &FxHashMap, CodeExtent<'tcx>>, + scope: CodeExtent<'tcx>, + buf: &'a mut [CodeExtent<'tcx>; 32], + vec: &'a mut Vec>) + -> &'a [CodeExtent<'tcx>] { // debug!("ancestors_of(scope={:?})", scope); let mut scope = scope; let mut i = 0; while i < 32 { buf[i] = scope; - match scope_map[scope.0 as usize].into_option() { + match scope_map.get(&scope) { Some(superscope) => scope = superscope, _ => return &buf[..i+1] } @@ -671,7 +603,7 @@ impl RegionMaps { vec.extend_from_slice(buf); loop { vec.push(scope); - match scope_map[scope.0 as usize].into_option() { + match scope_map.get(&scope) { Some(superscope) => scope = superscope, _ => return &*vec } @@ -685,17 +617,17 @@ fn record_var_lifetime(visitor: &mut RegionResolutionVisitor, var_id: ast::NodeId, _sp: Span) { match visitor.cx.var_parent { - ROOT_CODE_EXTENT => { + None => { // this can happen in extern fn declarations like // // extern fn isalnum(c: c_int) -> c_int } - parent_scope => + Some(parent_scope) => visitor.region_maps.record_var_scope(var_id, parent_scope), } } -fn resolve_block<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>, blk: &'tcx hir::Block) { +fn resolve_block<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, blk: &'tcx hir::Block) { debug!("resolve_block(blk.id={:?})", blk.id); let prev_cx = visitor.cx; @@ -728,8 +660,8 @@ fn resolve_block<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>, blk: visitor.cx = Context { root_id: prev_cx.root_id, - var_parent: block_extent, - parent: block_extent, + var_parent: Some(block_extent), + parent: Some(block_extent), }; { @@ -754,8 +686,8 @@ fn resolve_block<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>, blk: ); visitor.cx = Context { root_id: prev_cx.root_id, - var_parent: stmt_extent, - parent: stmt_extent, + var_parent: Some(stmt_extent), + parent: Some(stmt_extent), }; } visitor.visit_stmt(statement) @@ -766,7 +698,7 @@ fn resolve_block<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>, blk: visitor.cx = prev_cx; } -fn resolve_arm<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>, arm: &'tcx hir::Arm) { +fn resolve_arm<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, arm: &'tcx hir::Arm) { visitor.terminating_scopes.insert(arm.body.id); if let Some(ref expr) = arm.guard { @@ -776,7 +708,7 @@ fn resolve_arm<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>, arm: & intravisit::walk_arm(visitor, arm); } -fn resolve_pat<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>, pat: &'tcx hir::Pat) { +fn resolve_pat<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, pat: &'tcx hir::Pat) { visitor.new_node_extent(pat.id); // If this is a binding then record the lifetime of that binding. @@ -787,7 +719,7 @@ fn resolve_pat<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>, pat: & intravisit::walk_pat(visitor, pat); } -fn resolve_stmt<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>, stmt: &'tcx hir::Stmt) { +fn resolve_stmt<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, stmt: &'tcx hir::Stmt) { let stmt_id = stmt.node.id(); debug!("resolve_stmt(stmt.id={:?})", stmt_id); @@ -800,17 +732,17 @@ fn resolve_stmt<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>, stmt: let stmt_extent = visitor.new_node_extent_with_dtor(stmt_id); let prev_parent = visitor.cx.parent; - visitor.cx.parent = stmt_extent; + visitor.cx.parent = Some(stmt_extent); intravisit::walk_stmt(visitor, stmt); visitor.cx.parent = prev_parent; } -fn resolve_expr<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>, expr: &'tcx hir::Expr) { +fn resolve_expr<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, expr: &'tcx hir::Expr) { debug!("resolve_expr(expr.id={:?})", expr.id); let expr_extent = visitor.new_node_extent_with_dtor(expr.id); let prev_cx = visitor.cx; - visitor.cx.parent = expr_extent; + visitor.cx.parent = Some(expr_extent); { let terminating_scopes = &mut visitor.terminating_scopes; @@ -850,7 +782,7 @@ fn resolve_expr<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>, expr: } hir::ExprMatch(..) => { - visitor.cx.var_parent = expr_extent; + visitor.cx.var_parent = Some(expr_extent); } hir::ExprAssignOp(..) | hir::ExprIndex(..) | @@ -883,7 +815,7 @@ fn resolve_expr<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>, expr: visitor.cx = prev_cx; } -fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>, +fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, local: &'tcx hir::Local) { debug!("resolve_local(local.id={:?},local.init={:?})", local.id,local.init.is_some()); @@ -892,7 +824,7 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>, // scope that will be used for any bindings declared in this // pattern. let blk_scope = visitor.cx.var_parent; - assert!(blk_scope != ROOT_CODE_EXTENT); // locals must be within a block + let blk_scope = blk_scope.expect("locals must be within a block"); visitor.region_maps.record_var_scope(local.id, blk_scope); // As an exception to the normal rules governing temporary @@ -1024,9 +956,11 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>, /// | box E& /// | E& as ... /// | ( E& ) - fn record_rvalue_scope_if_borrow_expr(visitor: &mut RegionResolutionVisitor, - expr: &hir::Expr, - blk_id: CodeExtent) { + fn record_rvalue_scope_if_borrow_expr<'a, 'tcx>( + visitor: &mut RegionResolutionVisitor<'a, 'tcx>, + expr: &hir::Expr, + blk_id: CodeExtent<'tcx>) + { match expr.node { hir::ExprAddrOf(_, ref subexpr) => { record_rvalue_scope_if_borrow_expr(visitor, &subexpr, blk_id); @@ -1073,10 +1007,10 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>, /// | /// /// Note: ET is intended to match "rvalues or lvalues based on rvalues". - fn record_rvalue_scope<'a>(visitor: &mut RegionResolutionVisitor, - expr: &'a hir::Expr, - blk_scope: CodeExtent, - is_shrunk: bool) { + fn record_rvalue_scope<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, + expr: &hir::Expr, + blk_scope: CodeExtent<'tcx>, + is_shrunk: bool) { let mut expr = expr; loop { // Note: give all the expressions matching `ET` with the @@ -1107,43 +1041,40 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>, } } -fn resolve_item_like<'a, 'tcx, F>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>, - id: ast::NodeId, - walk: F) - where F: FnOnce(&mut RegionResolutionVisitor<'tcx, 'a>) +fn resolve_item_like<'a, 'tcx, F>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, walk: F) + where F: FnOnce(&mut RegionResolutionVisitor<'a, 'tcx>) { // Items create a new outer block scope as far as we're concerned. let prev_cx = visitor.cx; let prev_ts = mem::replace(&mut visitor.terminating_scopes, NodeSet()); visitor.cx = Context { root_id: None, - var_parent: ROOT_CODE_EXTENT, - parent: ROOT_CODE_EXTENT + var_parent: None, + parent: None, }; walk(visitor); - visitor.create_item_scope_if_needed(id); visitor.cx = prev_cx; visitor.terminating_scopes = prev_ts; } -fn resolve_fn<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>, +fn resolve_fn<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, kind: FnKind<'tcx>, decl: &'tcx hir::FnDecl, body_id: hir::BodyId, sp: Span, id: ast::NodeId) { + visitor.cx.parent = Some(visitor.new_code_extent( + CodeExtentData::CallSiteScope { fn_id: id, body_id: body_id.node_id })); + debug!("region::resolve_fn(id={:?}, \ - span={:?}, \ - body.id={:?}, \ - cx.parent={:?})", + span={:?}, \ + body.id={:?}, \ + cx.parent={:?})", id, - visitor.sess.codemap().span_to_string(sp), + visitor.tcx.sess.codemap().span_to_string(sp), body_id, visitor.cx.parent); - visitor.cx.parent = visitor.new_code_extent( - CodeExtentData::CallSiteScope { fn_id: id, body_id: body_id.node_id }); - let fn_decl_scope = visitor.new_code_extent( CodeExtentData::ParameterScope { fn_id: id, body_id: body_id.node_id }); @@ -1158,8 +1089,8 @@ fn resolve_fn<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>, // The arguments and `self` are parented to the fn. visitor.cx = Context { root_id: Some(body_id.node_id), - parent: ROOT_CODE_EXTENT, - var_parent: fn_decl_scope, + parent: None, + var_parent: Some(fn_decl_scope), }; intravisit::walk_fn_decl(visitor, decl); @@ -1168,8 +1099,8 @@ fn resolve_fn<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>, // The body of the every fn is a root scope. visitor.cx = Context { root_id: Some(body_id.node_id), - parent: fn_decl_scope, - var_parent: fn_decl_scope + parent: Some(fn_decl_scope), + var_parent: Some(fn_decl_scope), }; visitor.visit_nested_body(body_id); @@ -1178,17 +1109,33 @@ fn resolve_fn<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>, visitor.terminating_scopes = outer_ts; } -impl<'hir, 'a> RegionResolutionVisitor<'hir, 'a> { - /// Records the current parent (if any) as the parent of `child_scope`. - fn new_code_extent(&mut self, child_scope: CodeExtentData) -> CodeExtent { - self.region_maps.intern_code_extent(child_scope, self.cx.parent) +impl<'a, 'tcx> RegionResolutionVisitor<'a, 'tcx> { + pub fn intern_code_extent(&mut self, + data: CodeExtentData, + parent: Option>) + -> CodeExtent<'tcx> { + let code_extent = self.tcx.intern_code_extent(data); + self.region_maps.record_code_extent(code_extent, parent); + code_extent } - fn new_node_extent(&mut self, child_scope: ast::NodeId) -> CodeExtent { + pub fn intern_node(&mut self, + n: ast::NodeId, + parent: Option>) -> CodeExtent<'tcx> { + self.intern_code_extent(CodeExtentData::Misc(n), parent) + } + + /// Records the current parent (if any) as the parent of `child_scope`. + fn new_code_extent(&mut self, child_scope: CodeExtentData) -> CodeExtent<'tcx> { + let parent = self.cx.parent; + self.intern_code_extent(child_scope, parent) + } + + fn new_node_extent(&mut self, child_scope: ast::NodeId) -> CodeExtent<'tcx> { self.new_code_extent(CodeExtentData::Misc(child_scope)) } - fn new_node_extent_with_dtor(&mut self, id: ast::NodeId) -> CodeExtent { + fn new_node_extent_with_dtor(&mut self, id: ast::NodeId) -> CodeExtent<'tcx> { // If node was previously marked as a terminating scope during the // recursive visit of its parent node in the AST, then we need to // account for the destruction scope representing the extent of @@ -1196,98 +1143,90 @@ impl<'hir, 'a> RegionResolutionVisitor<'hir, 'a> { if self.terminating_scopes.contains(&id) { let ds = self.new_code_extent( CodeExtentData::DestructionScope(id)); - self.region_maps.intern_node(id, ds) + self.intern_node(id, Some(ds)) } else { self.new_node_extent(id) } } - - fn create_item_scope_if_needed(&mut self, id: ast::NodeId) { - // create a region for the destruction scope - this is needed - // for constructing parameter environments based on the item. - // functions put their destruction scopes *inside* their parameter - // scopes. - let scope = CodeExtentData::DestructionScope(id); - if !self.region_maps.code_extent_interner.borrow().contains_key(&scope) { - self.region_maps.intern_code_extent(scope, ROOT_CODE_EXTENT); - } - } } -impl<'hir, 'a> Visitor<'hir> for RegionResolutionVisitor<'hir, 'a> { - fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'hir> { +impl<'a, 'tcx> Visitor<'tcx> for RegionResolutionVisitor<'a, 'tcx> { + fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { NestedVisitorMap::OnlyBodies(&self.map) } - fn visit_block(&mut self, b: &'hir Block) { + fn visit_block(&mut self, b: &'tcx Block) { resolve_block(self, b); } - fn visit_item(&mut self, i: &'hir Item) { - resolve_item_like(self, i.id, |this| intravisit::walk_item(this, i)); + fn visit_item(&mut self, i: &'tcx Item) { + resolve_item_like(self, |this| intravisit::walk_item(this, i)); } - fn visit_impl_item(&mut self, ii: &'hir hir::ImplItem) { - resolve_item_like(self, ii.id, |this| intravisit::walk_impl_item(this, ii)); + fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem) { + resolve_item_like(self, |this| intravisit::walk_impl_item(this, ii)); } - fn visit_trait_item(&mut self, ti: &'hir hir::TraitItem) { - resolve_item_like(self, ti.id, |this| intravisit::walk_trait_item(this, ti)); + fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem) { + resolve_item_like(self, |this| intravisit::walk_trait_item(this, ti)); } - fn visit_fn(&mut self, fk: FnKind<'hir>, fd: &'hir FnDecl, + fn visit_fn(&mut self, fk: FnKind<'tcx>, fd: &'tcx FnDecl, b: hir::BodyId, s: Span, n: NodeId) { resolve_fn(self, fk, fd, b, s, n); } - fn visit_arm(&mut self, a: &'hir Arm) { + fn visit_arm(&mut self, a: &'tcx Arm) { resolve_arm(self, a); } - fn visit_pat(&mut self, p: &'hir Pat) { + fn visit_pat(&mut self, p: &'tcx Pat) { resolve_pat(self, p); } - fn visit_stmt(&mut self, s: &'hir Stmt) { + fn visit_stmt(&mut self, s: &'tcx Stmt) { resolve_stmt(self, s); } - fn visit_expr(&mut self, ex: &'hir Expr) { + fn visit_expr(&mut self, ex: &'tcx Expr) { resolve_expr(self, ex); } - fn visit_local(&mut self, l: &'hir Local) { + fn visit_local(&mut self, l: &'tcx Local) { resolve_local(self, l); } } -pub fn resolve_crate(sess: &Session, map: &hir_map::Map) -> RegionMaps { - let _task = map.dep_graph.in_task(DepNode::RegionResolveCrate); - let krate = map.krate(); +fn region_maps<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn_id: DefId) + -> Rc> +{ + let closure_base_def_id = tcx.closure_base_def_id(fn_id); + if closure_base_def_id != fn_id { + return tcx.region_maps(closure_base_def_id); + } + + let mut maps = RegionMaps::new(); + + let fn_node_id = tcx.hir.as_local_node_id(fn_id) + .expect("fn DefId should be for LOCAL_CRATE"); + let node = tcx.hir.get(fn_node_id); - let maps = RegionMaps { - code_extents: RefCell::new(vec![]), - code_extent_interner: RefCell::new(FxHashMap()), - scope_map: RefCell::new(vec![]), - var_map: RefCell::new(NodeMap()), - rvalue_scopes: RefCell::new(NodeMap()), - shrunk_rvalue_scopes: RefCell::new(NodeMap()), - fn_tree: RefCell::new(NodeMap()), - }; - let root_extent = maps.bogus_code_extent( - CodeExtentData::DestructionScope(ast::DUMMY_NODE_ID)); - assert_eq!(root_extent, ROOT_CODE_EXTENT); - let bogus_extent = maps.bogus_code_extent( - CodeExtentData::Misc(ast::DUMMY_NODE_ID)); - assert_eq!(bogus_extent, DUMMY_CODE_EXTENT); { let mut visitor = RegionResolutionVisitor { - sess: sess, - region_maps: &maps, - map: map, + tcx: tcx, + region_maps: &mut maps, + map: &tcx.hir, cx: Context { root_id: None, - parent: ROOT_CODE_EXTENT, - var_parent: ROOT_CODE_EXTENT + parent: None, + var_parent: None, }, - terminating_scopes: NodeSet() + terminating_scopes: NodeSet(), }; - krate.visit_all_item_likes(&mut visitor.as_deep_visitor()); + visitor.visit_hir_map_node(node); } - return maps; + + Rc::new(maps) +} + +pub fn provide(providers: &mut Providers) { + *providers = Providers { + region_maps, + ..*providers + }; } diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 37749816eb15..a8ba708cc2cd 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -15,7 +15,6 @@ //! used between functions, and they operate in a purely top-down //! way. Therefore we break lifetime name resolution into a separate pass. -use dep_graph::DepNode; use hir::map::Map; use session::Session; use hir::def::Def; @@ -259,7 +258,6 @@ const ROOT_SCOPE: ScopeRef<'static> = &Scope::Root; pub fn krate(sess: &Session, hir_map: &Map) -> Result { - let _task = hir_map.dep_graph.in_task(DepNode::ResolveLifetimes); let krate = hir_map.krate(); let mut map = NamedRegionMap { defs: NodeMap(), @@ -314,7 +312,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { hir::ItemUse(..) | hir::ItemMod(..) | hir::ItemDefaultImpl(..) | - hir::ItemForeignMod(..) => { + hir::ItemForeignMod(..) | + hir::ItemGlobalAsm(..) => { // These sorts of items have no lifetime parameters at all. intravisit::walk_item(self, item); } @@ -332,7 +331,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { hir::ItemStruct(_, ref generics) | hir::ItemUnion(_, ref generics) | hir::ItemTrait(_, ref generics, ..) | - hir::ItemImpl(_, _, ref generics, ..) => { + hir::ItemImpl(_, _, _, ref generics, ..) => { // These kinds of items have only early bound lifetime parameters. let mut index = if let hir::ItemTrait(..) = item.node { 1 // Self comes before lifetimes @@ -434,7 +433,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { self.resolve_elided_lifetimes(slice::ref_slice(lifetime_ref)); return; } - if lifetime_ref.name == keywords::StaticLifetime.name() { + if lifetime_ref.is_static() { self.insert_lifetime(lifetime_ref, Region::Static); return; } @@ -835,7 +834,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } match parent.node { hir::ItemTrait(_, ref generics, ..) | - hir::ItemImpl(_, _, ref generics, ..) => { + hir::ItemImpl(_, _, _, ref generics, ..) => { index += (generics.lifetimes.len() + generics.ty_params.len()) as u32; } _ => {} @@ -1434,7 +1433,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { let lifetime_i = &lifetimes[i]; for lifetime in lifetimes { - if lifetime.lifetime.name == keywords::StaticLifetime.name() { + if lifetime.lifetime.is_static() { let lifetime = lifetime.lifetime; let mut err = struct_span_err!(self.sess, lifetime.span, E0262, "invalid lifetime parameter name: `{}`", lifetime.name); @@ -1464,7 +1463,16 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { self.check_lifetime_def_for_shadowing(old_scope, &lifetime_i.lifetime); for bound in &lifetime_i.bounds { - self.resolve_lifetime_ref(bound); + if !bound.is_static() { + self.resolve_lifetime_ref(bound); + } else { + self.insert_lifetime(bound, Region::Static); + self.sess.struct_span_warn(lifetime_i.lifetime.span.to(bound.span), + &format!("unnecessary lifetime parameter `{}`", lifetime_i.lifetime.name)) + .help(&format!("you can use the `'static` lifetime directly, in place \ + of `{}`", lifetime_i.lifetime.name)) + .emit(); + } } } } diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 1fb537140257..198f7420f5d2 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -13,7 +13,6 @@ pub use self::StabilityLevel::*; -use dep_graph::DepNode; use hir::map as hir_map; use lint; use hir::def::Def; @@ -383,7 +382,6 @@ impl<'a, 'tcx> Index<'tcx> { // Put the active features into a map for quick lookup self.active_features = active_lib_features.iter().map(|&(ref s, _)| s.clone()).collect(); - let _task = tcx.dep_graph.in_task(DepNode::StabilityIndex); let krate = tcx.hir.krate(); let mut annotator = Annotator { tcx: tcx, @@ -397,7 +395,6 @@ impl<'a, 'tcx> Index<'tcx> { } pub fn new(hir_map: &hir_map::Map) -> Index<'tcx> { - let _task = hir_map.dep_graph.in_task(DepNode::StabilityIndex); let krate = hir_map.krate(); let mut is_staged_api = false; @@ -424,7 +421,7 @@ impl<'a, 'tcx> Index<'tcx> { /// features and possibly prints errors. pub fn check_unstable_api_usage<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let mut checker = Checker { tcx: tcx }; - tcx.visit_all_item_likes_in_krate(DepNode::StabilityCheck, &mut checker.as_deep_visitor()); + tcx.hir.krate().visit_all_item_likes(&mut checker.as_deep_visitor()); } struct Checker<'a, 'tcx: 'a> { @@ -435,7 +432,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // (See issue #38412) fn skip_stability_check_due_to_privacy(self, mut def_id: DefId) -> bool { // Check if `def_id` is a trait method. - match self.sess.cstore.describe_def(def_id) { + match self.describe_def(def_id) { Some(Def::Method(_)) | Some(Def::AssociatedTy(_)) | Some(Def::AssociatedConst(_)) => { @@ -467,7 +464,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } pub fn check_stability(self, def_id: DefId, id: NodeId, span: Span) { - if self.sess.codemap().span_allows_unstable(span) { + if span.allows_unstable() { debug!("stability: \ skipping span={:?} since it is internal", span); return; @@ -536,7 +533,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { if !self.stability.borrow().active_features.contains(feature) { let msg = match *reason { Some(ref r) => format!("use of unstable library feature '{}': {}", - &feature.as_str(), &r), + feature.as_str(), &r), None => format!("use of unstable library feature '{}'", &feature) }; emit_feature_err(&self.sess.parse_sess, &feature.as_str(), span, @@ -639,7 +636,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { if id.is_local() { None // The stability cache is filled partially lazily } else { - self.sess.cstore.stability(id).map(|st| self.intern_stability(st)) + self.stability(id).map(|st| self.intern_stability(st)) } } @@ -648,7 +645,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { if id.is_local() { None // The stability cache is filled partially lazily } else { - self.sess.cstore.deprecation(id).map(DeprecationEntry::external) + self.deprecation(id).map(DeprecationEntry::external) } } } @@ -656,12 +653,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// Given the list of enabled features that were not language features (i.e. that /// were expected to be library features), and the list of features used from /// libraries, identify activated features that don't exist and error about them. -pub fn check_unused_or_stable_features<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - access_levels: &AccessLevels) { +pub fn check_unused_or_stable_features<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let sess = &tcx.sess; + let access_levels = &tcx.privacy_access_levels(LOCAL_CRATE); + if tcx.stability.borrow().staged_api[&LOCAL_CRATE] && tcx.sess.features.borrow().staged_api { - let _task = tcx.dep_graph.in_task(DepNode::StabilityIndex); let krate = tcx.hir.krate(); let mut missing = MissingStabilityAnnotations { tcx: tcx, diff --git a/src/librustc/mir/README.md b/src/librustc/mir/README.md new file mode 100644 index 000000000000..e8ed8bf104cc --- /dev/null +++ b/src/librustc/mir/README.md @@ -0,0 +1,90 @@ +# MIR definition and pass system + +This file contains the definition of the MIR datatypes along with the +various types for the "MIR Pass" system, which lets you easily +register and define new MIR transformations and analyses. + +Most of the code that operates on MIR can be found in the +`librustc_mir` crate or other crates. The code found here in +`librustc` is just the datatype definitions, alonging the functions +which operate on MIR to be placed everywhere else. + +## MIR Data Types and visitor + +The main MIR data type is `rustc::mir::Mir`, defined in `mod.rs`. +There is also the MIR visitor (in `visit.rs`) which allows you to walk +the MIR and override what actions will be taken at various points (you +can visit in either shared or mutable mode; the latter allows changing +the MIR in place). Finally `traverse.rs` contains various traversal +routines for visiting the MIR CFG in [different standard orders][traversal] +(e.g. pre-order, reverse post-order, and so forth). + +[traversal]: https://en.wikipedia.org/wiki/Tree_traversal + +## MIR pass suites and their integration into the query system + +As a MIR *consumer*, you are expected to use one of the queries that +returns a "final MIR". As of the time of this writing, there is only +one: `optimized_mir(def_id)`, but more are expected to come in the +future. For foreign def-ids, we simply read the MIR from the other +crate's metadata. But for local query, this query will construct the +MIR and then iteratively optimize it by putting it through various +pipeline stages. This section describes those pipeline stages and how +you can extend them. + +To produce the `optimized_mir(D)` for a given def-id `D`, the MIR +passes through several suites of optimizations, each represented by a +query. Each suite consists of multiple optimizations and +transformations. These suites represent useful intermediate points +where we want to access the MIR for type checking or other purposes: + +- `mir_build(D)` -- not a query, but this constructs the initial MIR +- `mir_const(D)` -- applies some simple transformations to make MIR ready for constant evaluation; +- `mir_validated(D)` -- applies some more transformations, making MIR ready for borrow checking; +- `optimized_mir(D)` -- the final state, after all optimizations have been performed. + +### Stealing + +The intermediate queries `mir_const()` and `mir_validated()` yield up +a `&'tcx Steal>`, allocated using +`tcx.alloc_steal_mir()`. This indicates that the result may be +**stolen** by the next suite of optimizations -- this is an +optimization to avoid cloning the MIR. Attempting to use a stolen +result will cause a panic in the compiler. Therefore, it is important +that you not read directly from these intermediate queries except as +part of the MIR processing pipeline. + +Because of this stealing mechanism, some care must also be taken to +ensure that, before the MIR at a particular phase in the processing +pipeline is stolen, anyone who may want to read from it has already +done so. Concretely, this means that if you have some query `foo(D)` +that wants to access the result of `mir_const(D)` or +`mir_validated(D)`, you need to have the successor pass either "force" +`foo(D)` using `ty::queries::foo::force(...)`. This will force a query +to execute even though you don't directly require its result. + +As an example, consider MIR const qualification. It wants to read the +result produced by the `mir_const()` suite. However, that result will +be **stolen** by the `mir_validated()` suite. If nothing was done, +then `mir_const_qualif(D)` would succeed if it came before +`mir_validated(D)`, but fail otherwise. Therefore, `mir_validated(D)` +will **force** `mir_const_qualif` before it actually steals, thus +ensuring that the reads have already happened: + +``` +mir_const(D) --read-by--> mir_const_qualif(D) + | ^ + stolen-by | + | (forces) + v | +mir_validated(D) ------------+ +``` + +### Implementing and registering a pass + +To create a new MIR pass, you simply implement the `MirPass` trait for +some fresh singleton type `Foo`. Once you have implemented a trait for +your type `Foo`, you then have to insert `Foo` into one of the suites; +this is done in `librustc_driver/driver.rs` by invoking `push_pass(S, +Foo)` with the appropriate suite substituted for `S`. + diff --git a/src/librustc/mir/cache.rs b/src/librustc/mir/cache.rs index bc9bbebb1796..799686ceca4a 100644 --- a/src/librustc/mir/cache.rs +++ b/src/librustc/mir/cache.rs @@ -10,7 +10,9 @@ use std::cell::{Ref, RefCell}; use rustc_data_structures::indexed_vec::IndexVec; - +use rustc_data_structures::stable_hasher::{HashStable, StableHasher, + StableHasherResult}; +use ich::StableHashingContext; use mir::{Mir, BasicBlock}; use rustc_serialize as serialize; @@ -33,6 +35,13 @@ impl serialize::Decodable for Cache { } } +impl<'a, 'tcx> HashStable> for Cache { + fn hash_stable(&self, + _: &mut StableHashingContext<'a, 'tcx>, + _: &mut StableHasher) { + // do nothing + } +} impl Cache { pub fn new() -> Self { diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 01dc7f51e29d..b517ebabbe76 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +//! MIR datatypes and passes. See [the README](README.md) for details. + use graphviz::IntoCow; use middle::const_val::ConstVal; use rustc_const_math::{ConstUsize, ConstInt, ConstMathErr}; @@ -197,10 +199,10 @@ impl<'tcx> Mir<'tcx> { pub fn temps_iter<'a>(&'a self) -> impl Iterator + 'a { (self.arg_count+1..self.local_decls.len()).filter_map(move |index| { let local = Local::new(index); - if self.local_decls[local].source_info.is_none() { - Some(local) - } else { + if self.local_decls[local].is_user_variable { None + } else { + Some(local) } }) } @@ -210,10 +212,10 @@ impl<'tcx> Mir<'tcx> { pub fn vars_iter<'a>(&'a self) -> impl Iterator + 'a { (self.arg_count+1..self.local_decls.len()).filter_map(move |index| { let local = Local::new(index); - if self.local_decls[local].source_info.is_none() { - None - } else { + if self.local_decls[local].is_user_variable { Some(local) + } else { + None } }) } @@ -243,6 +245,19 @@ impl<'tcx> Mir<'tcx> { } } +impl_stable_hash_for!(struct Mir<'tcx> { + basic_blocks, + visibility_scopes, + promoted, + return_ty, + local_decls, + arg_count, + upvar_decls, + spread_arg, + span, + cache +}); + impl<'tcx> Index for Mir<'tcx> { type Output = BasicBlockData<'tcx>; @@ -357,6 +372,9 @@ pub struct LocalDecl<'tcx> { /// Temporaries and the return pointer are always mutable. pub mutability: Mutability, + /// True if this corresponds to a user-declared local variable. + pub is_user_variable: bool, + /// Type of this local. pub ty: Ty<'tcx>, @@ -366,24 +384,23 @@ pub struct LocalDecl<'tcx> { /// to generate better debuginfo. pub name: Option, - /// For user-declared variables, stores their source information. - /// - /// For temporaries, this is `None`. - /// - /// This is the primary way to differentiate between user-declared - /// variables and compiler-generated temporaries. - pub source_info: Option, + /// Source info of the local. + pub source_info: SourceInfo, } impl<'tcx> LocalDecl<'tcx> { /// Create a new `LocalDecl` for a temporary. #[inline] - pub fn new_temp(ty: Ty<'tcx>) -> Self { + pub fn new_temp(ty: Ty<'tcx>, span: Span) -> Self { LocalDecl { mutability: Mutability::Mut, ty: ty, name: None, - source_info: None, + source_info: SourceInfo { + span: span, + scope: ARGUMENT_VISIBILITY_SCOPE + }, + is_user_variable: false } } @@ -391,12 +408,16 @@ impl<'tcx> LocalDecl<'tcx> { /// /// This must be inserted into the `local_decls` list as the first local. #[inline] - pub fn new_return_pointer(return_ty: Ty) -> LocalDecl { + pub fn new_return_pointer(return_ty: Ty, span: Span) -> LocalDecl { LocalDecl { mutability: Mutability::Mut, ty: return_ty, - source_info: None, + source_info: SourceInfo { + span: span, + scope: ARGUMENT_VISIBILITY_SCOPE + }, name: None, // FIXME maybe we do want some name here? + is_user_variable: false } } } @@ -830,6 +851,11 @@ pub struct Static<'tcx> { pub ty: Ty<'tcx>, } +impl_stable_hash_for!(struct Static<'tcx> { + def_id, + ty +}); + /// The `Projection` data structure defines things of the form `B.x` /// or `*B` or `B[index]`. Note that it is parameterized because it is /// shared between `Constant` and `Lvalue`. See the aliases @@ -991,7 +1017,7 @@ impl<'tcx> Operand<'tcx> { ) -> Self { Operand::Constant(Constant { span: span, - ty: tcx.item_type(def_id).subst(tcx, substs), + ty: tcx.type_of(def_id).subst(tcx, substs), literal: Literal::Value { value: ConstVal::Function(def_id, substs) }, }) } @@ -1010,7 +1036,7 @@ pub enum Rvalue<'tcx> { Repeat(Operand<'tcx>, ConstUsize), /// &x or &mut x - Ref(&'tcx Region, BorrowKind, Lvalue<'tcx>), + Ref(Region<'tcx>, BorrowKind, Lvalue<'tcx>), /// length of a [X] or [X;n] value Len(Lvalue<'tcx>), @@ -1283,10 +1309,11 @@ fn fmt_const_val(fmt: &mut W, const_val: &ConstVal) -> fmt::Result { write!(fmt, "b\"{}\"", escaped) } Bool(b) => write!(fmt, "{:?}", b), + Char(c) => write!(fmt, "{:?}", c), + Variant(def_id) | Function(def_id, _) => write!(fmt, "{}", item_path_str(def_id)), Struct(_) | Tuple(_) | Array(_) | Repeat(..) => bug!("ConstVal `{:?}` should not be in MIR", const_val), - Char(c) => write!(fmt, "{:?}", c), } } diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index f40b9c605375..b6020df07285 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -194,7 +194,7 @@ impl<'tcx> Rvalue<'tcx> { ) } AggregateKind::Adt(def, _, substs, _) => { - tcx.item_type(def.did).subst(tcx, substs) + tcx.type_of(def.did).subst(tcx, substs) } AggregateKind::Closure(did, substs) => { tcx.mk_closure_from_closure_substs(did, substs) diff --git a/src/librustc/mir/transform.rs b/src/librustc/mir/transform.rs index 4cbbb67c7e43..aa91123ef695 100644 --- a/src/librustc/mir/transform.rs +++ b/src/librustc/mir/transform.rs @@ -8,16 +8,17 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use dep_graph::DepNode; +//! See [the README](README.md) for details on writing your own pass. + use hir; +use hir::def_id::DefId; use hir::map::DefPathData; use mir::{Mir, Promoted}; use ty::TyCtxt; +use std::rc::Rc; use syntax::ast::NodeId; -use util::common::time; use std::borrow::Cow; -use std::fmt; /// Where a specific Mir comes from. #[derive(Debug, Copy, Clone)] @@ -36,6 +37,11 @@ pub enum MirSource { } impl<'a, 'tcx> MirSource { + pub fn from_local_def_id(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> MirSource { + let id = tcx.hir.as_local_node_id(def_id).expect("mir source requires local def-id"); + Self::from_node(tcx, id) + } + pub fn from_node(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: NodeId) -> MirSource { use hir::*; @@ -70,124 +76,111 @@ impl<'a, 'tcx> MirSource { } } -/// Various information about pass. -pub trait Pass { - // fn should_run(Session) to check if pass should run? - fn name<'a>(&self) -> Cow<'static, str> { - let name = unsafe { ::std::intrinsics::type_name::() }; - if let Some(tail) = name.rfind(":") { - Cow::from(&name[tail+1..]) - } else { - Cow::from(name) - } +/// Generates a default name for the pass based on the name of the +/// type `T`. +pub fn default_name() -> Cow<'static, str> { + let name = unsafe { ::std::intrinsics::type_name::() }; + if let Some(tail) = name.rfind(":") { + Cow::from(&name[tail+1..]) + } else { + Cow::from(name) } - fn disambiguator<'a>(&'a self) -> Option> { None } } -/// A pass which inspects the whole Mir map. -pub trait MirMapPass<'tcx>: Pass { - fn run_pass<'a>( - &mut self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - hooks: &mut [Box MirPassHook<'s>>]); +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct MirSuite(pub usize); + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct MirPassIndex(pub usize); + +/// A pass hook is invoked both before and after each pass executes. +/// This is primarily used to dump MIR for debugging. +/// +/// You can tell whether this is before or after by inspecting the +/// `mir` parameter -- before the pass executes, it will be `None` (in +/// which case you can inspect the MIR from previous pass by executing +/// `mir_cx.read_previous_mir()`); after the pass executes, it will be +/// `Some()` with the result of the pass (in which case the output +/// from the previous pass is most likely stolen, so you would not +/// want to try and access it). If the pass is interprocedural, then +/// the hook will be invoked once per output. +pub trait PassHook { + fn on_mir_pass<'a, 'tcx: 'a>(&self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + suite: MirSuite, + pass_num: MirPassIndex, + pass_name: &str, + source: MirSource, + mir: &Mir<'tcx>, + is_after: bool); } -pub trait MirPassHook<'tcx>: Pass { - fn on_mir_pass<'a>( - &mut self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - src: MirSource, - mir: &Mir<'tcx>, - pass: &Pass, - is_after: bool - ); -} +/// The full suite of types that identifies a particular +/// application of a pass to a def-id. +pub type PassId = (MirSuite, MirPassIndex, DefId); -/// A pass which inspects Mir of functions in isolation. -pub trait MirPass<'tcx>: Pass { - fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - src: MirSource, mir: &mut Mir<'tcx>); -} - -impl<'tcx, T: MirPass<'tcx>> MirMapPass<'tcx> for T { - fn run_pass<'a>(&mut self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - hooks: &mut [Box MirPassHook<'s>>]) - { - let def_ids = tcx.maps.mir.borrow().keys(); - for def_id in def_ids { - if !def_id.is_local() { - continue; - } - - let _task = tcx.dep_graph.in_task(DepNode::Mir(def_id)); - let mir = &mut tcx.maps.mir.borrow()[&def_id].borrow_mut(); - tcx.dep_graph.write(DepNode::Mir(def_id)); - - let id = tcx.hir.as_local_node_id(def_id).unwrap(); - let src = MirSource::from_node(tcx, id); - - for hook in &mut *hooks { - hook.on_mir_pass(tcx, src, mir, self, false); - } - MirPass::run_pass(self, tcx, src, mir); - for hook in &mut *hooks { - hook.on_mir_pass(tcx, src, mir, self, true); - } - - for (i, mir) in mir.promoted.iter_enumerated_mut() { - let src = MirSource::Promoted(id, i); - for hook in &mut *hooks { - hook.on_mir_pass(tcx, src, mir, self, false); - } - MirPass::run_pass(self, tcx, src, mir); - for hook in &mut *hooks { - hook.on_mir_pass(tcx, src, mir, self, true); - } - } - } +/// A streamlined trait that you can implement to create a pass; the +/// pass will be named after the type, and it will consist of a main +/// loop that goes over each available MIR and applies `run_pass`. +pub trait MirPass { + fn name<'a>(&'a self) -> Cow<'a, str> { + default_name::() } + + fn run_pass<'a, 'tcx>(&self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + source: MirSource, + mir: &mut Mir<'tcx>); } /// A manager for MIR passes. +/// +/// FIXME(#41712) -- it is unclear whether we should have this struct. +#[derive(Clone)] pub struct Passes { - passes: Vec MirMapPass<'tcx>>>, - pass_hooks: Vec MirPassHook<'tcx>>>, - plugin_passes: Vec MirMapPass<'tcx>>> + pass_hooks: Vec>, + suites: Vec>>, } +/// The number of "pass suites" that we have: +/// +/// - ready for constant evaluation +/// - unopt +/// - optimized +pub const MIR_SUITES: usize = 3; + +/// Run the passes we need to do constant qualification and evaluation. +pub const MIR_CONST: MirSuite = MirSuite(0); + +/// Run the passes we need to consider the MIR validated and ready for borrowck etc. +pub const MIR_VALIDATED: MirSuite = MirSuite(1); + +/// Run the passes we need to consider the MIR *optimized*. +pub const MIR_OPTIMIZED: MirSuite = MirSuite(2); + impl<'a, 'tcx> Passes { pub fn new() -> Passes { - let passes = Passes { - passes: Vec::new(), + Passes { pass_hooks: Vec::new(), - plugin_passes: Vec::new() - }; - passes - } - - pub fn run_passes(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>) { - let Passes { ref mut passes, ref mut plugin_passes, ref mut pass_hooks } = *self; - for pass in plugin_passes.iter_mut().chain(passes.iter_mut()) { - time(tcx.sess.time_passes(), &*pass.name(), - || pass.run_pass(tcx, pass_hooks)); + suites: (0..MIR_SUITES).map(|_| Vec::new()).collect(), } } /// Pushes a built-in pass. - pub fn push_pass(&mut self, pass: Box MirMapPass<'b>>) { - self.passes.push(pass); + pub fn push_pass(&mut self, suite: MirSuite, pass: T) { + self.suites[suite.0].push(Rc::new(pass)); } /// Pushes a pass hook. - pub fn push_hook(&mut self, hook: Box MirPassHook<'b>>) { - self.pass_hooks.push(hook); + pub fn push_hook(&mut self, hook: T) { + self.pass_hooks.push(Rc::new(hook)); } -} -/// Copies the plugin passes. -impl ::std::iter::Extend MirMapPass<'a>>> for Passes { - fn extend MirMapPass<'a>>>>(&mut self, it: I) { - self.plugin_passes.extend(it); + pub fn passes(&self, suite: MirSuite) -> &[Rc] { + &self.suites[suite.0] + } + + pub fn hooks(&self) -> &[Rc] { + &self.pass_hooks } } diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 733ad36de90e..31bdd99ef322 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -630,12 +630,11 @@ macro_rules! make_mir_visitor { ref $($mutability)* ty, name: _, ref $($mutability)* source_info, + is_user_variable: _, } = *local_decl; self.visit_ty(ty); - if let Some(ref $($mutability)* info) = *source_info { - self.visit_source_info(info); - } + self.visit_source_info(source_info); } fn super_visibility_scope(&mut self, @@ -748,7 +747,7 @@ pub enum LvalueContext<'tcx> { Inspect, // Being borrowed - Borrow { region: &'tcx Region, kind: BorrowKind }, + Borrow { region: Region<'tcx>, kind: BorrowKind }, // Used as base for another lvalue, e.g. `x` in `x.y`. // diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index a0603c579524..75bc940625d8 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -19,12 +19,13 @@ pub use self::DebugInfoLevel::*; use session::{early_error, early_warn, Session}; use session::search_paths::SearchPaths; -use rustc_back::PanicStrategy; +use rustc_back::{LinkerFlavor, PanicStrategy}; use rustc_back::target::Target; use lint; use middle::cstore; use syntax::ast::{self, IntTy, UintTy}; +use syntax::codemap::FilePathMapping; use syntax::parse::token; use syntax::parse; use syntax::symbol::Symbol; @@ -51,7 +52,7 @@ pub struct Config { pub uint_type: UintTy, } -#[derive(Clone, Hash)] +#[derive(Clone, Hash, Debug)] pub enum Sanitizer { Address, Leak, @@ -492,6 +493,14 @@ impl Options { self.incremental.is_none() || self.cg.codegen_units == 1 } + + pub fn file_path_mapping(&self) -> FilePathMapping { + FilePathMapping::new( + self.debugging_opts.remap_path_prefix_from.iter().zip( + self.debugging_opts.remap_path_prefix_to.iter() + ).map(|(src, dst)| (src.clone(), dst.clone())).collect() + ) + } } // The type of entry function, so @@ -641,12 +650,16 @@ macro_rules! options { Some("either `panic` or `abort`"); pub const parse_sanitizer: Option<&'static str> = Some("one of: `address`, `leak`, `memory` or `thread`"); + pub const parse_linker_flavor: Option<&'static str> = + Some(::rustc_back::LinkerFlavor::one_of()); + pub const parse_optimization_fuel: Option<&'static str> = + Some("crate=integer"); } #[allow(dead_code)] mod $mod_set { use super::{$struct_name, Passes, SomePasses, AllPasses, Sanitizer}; - use rustc_back::PanicStrategy; + use rustc_back::{LinkerFlavor, PanicStrategy}; $( pub fn $opt(cg: &mut $struct_name, v: Option<&str>) -> bool { @@ -777,6 +790,29 @@ macro_rules! options { } true } + + fn parse_linker_flavor(slote: &mut Option, v: Option<&str>) -> bool { + match v.and_then(LinkerFlavor::from_str) { + Some(lf) => *slote = Some(lf), + _ => return false, + } + true + } + + fn parse_optimization_fuel(slot: &mut Option<(String, u64)>, v: Option<&str>) -> bool { + match v { + None => false, + Some(s) => { + let parts = s.split('=').collect::>(); + if parts.len() != 2 { return false; } + let crate_name = parts[0].to_string(); + let fuel = parts[1].parse::(); + if fuel.is_err() { return false; } + *slot = Some((crate_name, fuel.unwrap())); + true + } + } + } } ) } @@ -967,6 +1003,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "dump MIR state at various points in translation"), dump_mir_dir: Option = (None, parse_opt_string, [UNTRACKED], "the directory the MIR is dumped into"), + dump_mir_exclude_pass_number: bool = (false, parse_bool, [UNTRACKED], + "if set, exclude the pass number when dumping MIR (used in tests)"), perf_stats: bool = (false, parse_bool, [UNTRACKED], "print some performance-related statistics"), hir_stats: bool = (false, parse_bool, [UNTRACKED], @@ -979,6 +1017,16 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "pass `-install_name @rpath/...` to the macOS linker"), sanitizer: Option = (None, parse_sanitizer, [TRACKED], "Use a sanitizer"), + linker_flavor: Option = (None, parse_linker_flavor, [UNTRACKED], + "Linker flavor"), + fuel: Option<(String, u64)> = (None, parse_optimization_fuel, [TRACKED], + "Set the optimization fuel quota for a crate."), + print_fuel: Option = (None, parse_opt_string, [TRACKED], + "Make Rustc print the total optimization fuel used by a crate."), + remap_path_prefix_from: Vec = (vec![], parse_string_push, [TRACKED], + "add a source pattern to the file path remapping config"), + remap_path_prefix_to: Vec = (vec![], parse_string_push, [TRACKED], + "add a mapping target to the file path remapping config"), } pub fn default_lib_output() -> CrateType { @@ -1074,14 +1122,6 @@ pub fn build_target_config(opts: &Options, sp: &Handler) -> Config { pub enum OptionStability { Stable, - // FIXME: historically there were some options which were either `-Z` or - // required the `-Z unstable-options` flag, which were all intended - // to be unstable. Unfortunately we didn't actually gate usage of - // these options on the stable compiler, so we still allow them there - // today. There are some warnings printed out about this in the - // driver. - UnstableButNotReally, - Unstable, } @@ -1100,17 +1140,9 @@ impl RustcOptGroup { RustcOptGroup { opt_group: g, stability: OptionStability::Stable } } - #[allow(dead_code)] // currently we have no "truly unstable" options pub fn unstable(g: getopts::OptGroup) -> RustcOptGroup { RustcOptGroup { opt_group: g, stability: OptionStability::Unstable } } - - fn unstable_bnr(g: getopts::OptGroup) -> RustcOptGroup { - RustcOptGroup { - opt_group: g, - stability: OptionStability::UnstableButNotReally, - } - } } // The `opt` local module holds wrappers around the `getopts` API that @@ -1132,7 +1164,6 @@ mod opt { fn stable(g: getopts::OptGroup) -> R { RustcOptGroup::stable(g) } fn unstable(g: getopts::OptGroup) -> R { RustcOptGroup::unstable(g) } - fn unstable_bnr(g: getopts::OptGroup) -> R { RustcOptGroup::unstable_bnr(g) } pub fn opt_s(a: S, b: S, c: S, d: S) -> R { stable(getopts::optopt(a, b, c, d)) @@ -1165,24 +1196,6 @@ mod opt { pub fn flagmulti(a: S, b: S, c: S) -> R { unstable(getopts::optflagmulti(a, b, c)) } - - // Do not use these functions for any new options added to the compiler, all - // new options should use the `*_u` variants above to be truly unstable. - pub fn opt_ubnr(a: S, b: S, c: S, d: S) -> R { - unstable_bnr(getopts::optopt(a, b, c, d)) - } - pub fn multi_ubnr(a: S, b: S, c: S, d: S) -> R { - unstable_bnr(getopts::optmulti(a, b, c, d)) - } - pub fn flag_ubnr(a: S, b: S, c: S) -> R { - unstable_bnr(getopts::optflag(a, b, c)) - } - pub fn flagopt_ubnr(a: S, b: S, c: S, d: S) -> R { - unstable_bnr(getopts::optflagopt(a, b, c, d)) - } - pub fn flagmulti_ubnr(a: S, b: S, c: S) -> R { - unstable_bnr(getopts::optflagmulti(a, b, c)) - } } /// Returns the "short" subset of the rustc command line options, @@ -1213,7 +1226,7 @@ pub fn rustc_short_optgroups() -> Vec { "NAME"), opt::multi_s("", "emit", "Comma separated list of types of output for \ the compiler to emit", - "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info]"), + "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]"), opt::multi_s("", "print", "Comma separated list of compiler information to \ print on stdout", &format!("[{}]", &print_opts.join("|"))), @@ -1248,7 +1261,7 @@ pub fn rustc_optgroups() -> Vec { opt::multi_s("", "extern", "Specify where an external rust library is located", "NAME=PATH"), opt::opt_s("", "sysroot", "Override the system root", "PATH"), - opt::multi_ubnr("Z", "", "Set internal debugging options", "FLAG"), + opt::multi("Z", "", "Set internal debugging options", "FLAG"), opt::opt_s("", "error-format", "How errors and other messages are produced", "human|json"), @@ -1257,28 +1270,20 @@ pub fn rustc_optgroups() -> Vec { always = always colorize output; never = never colorize output", "auto|always|never"), - opt::flagopt_ubnr("", "pretty", - "Pretty-print the input instead of compiling; - valid types are: `normal` (un-annotated source), - `expanded` (crates expanded), or - `expanded,identified` (fully parenthesized, AST nodes with IDs).", - "TYPE"), - opt::flagopt_ubnr("", "unpretty", - "Present the input source, unstable (and less-pretty) variants; - valid types are any of the types for `--pretty`, as well as: - `flowgraph=` (graphviz formatted flowgraph for node), - `everybody_loops` (all function bodies replaced with `loop {}`), - `hir` (the HIR), `hir,identified`, or - `hir,typed` (HIR with types for each node).", - "TYPE"), - - // new options here should **not** use the `_ubnr` functions, all new - // unstable options should use the short variants to indicate that they - // are truly unstable. All `_ubnr` flags are just that way because they - // were so historically. - // - // You may also wish to keep this comment at the bottom of this list to - // ensure that others see it. + opt::flagopt("", "pretty", + "Pretty-print the input instead of compiling; + valid types are: `normal` (un-annotated source), + `expanded` (crates expanded), or + `expanded,identified` (fully parenthesized, AST nodes with IDs).", + "TYPE"), + opt::flagopt("", "unpretty", + "Present the input source, unstable (and less-pretty) variants; + valid types are any of the types for `--pretty`, as well as: + `flowgraph=` (graphviz formatted flowgraph for node), + `everybody_loops` (all function bodies replaced with `loop {}`), + `hir` (the HIR), `hir,identified`, or + `hir,typed` (HIR with types for each node).", + "TYPE"), ]); opts } @@ -1286,7 +1291,7 @@ pub fn rustc_optgroups() -> Vec { // Convert strings provided as --cfg [cfgspec] into a crate_cfg pub fn parse_cfgspecs(cfgspecs: Vec ) -> ast::CrateConfig { cfgspecs.into_iter().map(|s| { - let sess = parse::ParseSess::new(); + let sess = parse::ParseSess::new(FilePathMapping::empty()); let mut parser = parse::new_parser_from_source_str(&sess, "cfgspec".to_string(), s.to_string()); @@ -1397,6 +1402,23 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches) output_types.insert(OutputType::Exe, None); } + let remap_path_prefix_sources = debugging_opts.remap_path_prefix_from.len(); + let remap_path_prefix_targets = debugging_opts.remap_path_prefix_from.len(); + + if remap_path_prefix_targets < remap_path_prefix_sources { + for source in &debugging_opts.remap_path_prefix_from[remap_path_prefix_targets..] { + early_error(error_format, + &format!("option `-Zremap-path-prefix-from='{}'` does not have \ + a corresponding `-Zremap-path-prefix-to`", source)) + } + } else if remap_path_prefix_targets > remap_path_prefix_sources { + for target in &debugging_opts.remap_path_prefix_to[remap_path_prefix_sources..] { + early_error(error_format, + &format!("option `-Zremap-path-prefix-to='{}'` does not have \ + a corresponding `-Zremap-path-prefix-from`", target)) + } + } + let mut cg = build_codegen_options(matches, error_format); // Issue #30063: if user requests llvm-related output to one @@ -1639,7 +1661,7 @@ pub mod nightly_options { use getopts; use syntax::feature_gate::UnstableFeatures; use super::{ErrorOutputType, OptionStability, RustcOptGroup}; - use session::{early_error, early_warn}; + use session::early_error; pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool { is_nightly_build() && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options") @@ -1681,15 +1703,6 @@ pub mod nightly_options { nightly compiler", opt_name); early_error(ErrorOutputType::default(), &msg); } - OptionStability::UnstableButNotReally => { - let msg = format!("the option `{}` is unstable and should \ - only be used on the nightly compiler, but \ - it is currently accepted for backwards \ - compatibility; this will soon change, \ - see issue #31847 for more details", - opt_name); - early_warn(ErrorOutputType::default(), &msg); - } OptionStability::Stable => {} } } @@ -1741,7 +1754,7 @@ mod dep_tracking { use rustc_back::PanicStrategy; pub trait DepTrackingHash { - fn hash(&self, &mut DefaultHasher, ErrorOutputType); + fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType); } macro_rules! impl_dep_tracking_hash_via_hash { @@ -1772,11 +1785,13 @@ mod dep_tracking { impl_dep_tracking_hash_via_hash!(bool); impl_dep_tracking_hash_via_hash!(usize); + impl_dep_tracking_hash_via_hash!(u64); impl_dep_tracking_hash_via_hash!(String); impl_dep_tracking_hash_via_hash!(lint::Level); impl_dep_tracking_hash_via_hash!(Option); impl_dep_tracking_hash_via_hash!(Option); impl_dep_tracking_hash_via_hash!(Option); + impl_dep_tracking_hash_via_hash!(Option<(String, u64)>); impl_dep_tracking_hash_via_hash!(Option); impl_dep_tracking_hash_via_hash!(Option); impl_dep_tracking_hash_via_hash!(Option); @@ -1798,6 +1813,7 @@ mod dep_tracking { impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level)); impl_dep_tracking_hash_for_sortable_vec_of!((String, Option, Option)); + impl_dep_tracking_hash_for_sortable_vec_of!((String, u64)); impl DepTrackingHash for SearchPaths { fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType) { let mut elems: Vec<_> = self diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 3ba82f34c326..ec3eaa124c30 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -13,7 +13,6 @@ pub use self::code_stats::{SizeKind, TypeSizeInfo, VariantInfo}; use dep_graph::DepGraph; use hir::def_id::{CrateNum, DefIndex}; -use hir::svh::Svh; use lint; use middle::cstore::CrateStore; use middle::dependency_format; @@ -22,7 +21,6 @@ use session::config::DebugInfoLevel; use ty::tls; use util::nodemap::{FxHashMap, FxHashSet}; use util::common::duration_to_secs_str; -use mir::transform as mir_pass; use syntax::ast::NodeId; use errors::{self, DiagnosticBuilder}; @@ -36,7 +34,7 @@ use syntax::{ast, codemap}; use syntax::feature_gate::AttributeType; use syntax_pos::{Span, MultiSpan}; -use rustc_back::PanicStrategy; +use rustc_back::{LinkerFlavor, PanicStrategy}; use rustc_back::target::Target; use rustc_data_structures::flock; use llvm; @@ -75,8 +73,10 @@ pub struct Session { // The name of the root source file of the crate, in the local file system. // The path is always expected to be absolute. `None` means that there is no // source file. - pub local_crate_source_file: Option, - pub working_dir: PathBuf, + pub local_crate_source_file: Option, + // The directory the compiler has been executed in plus a flag indicating + // if the value stored here has been affected by path remapping. + pub working_dir: (String, bool), pub lint_store: RefCell, pub lints: RefCell, /// Set of (LintId, span, message) tuples tracking lint (sub)diagnostics @@ -84,7 +84,6 @@ pub struct Session { /// redundantly verbose output (Issue #24690). pub one_time_diagnostics: RefCell>, pub plugin_llvm_passes: RefCell>, - pub mir_passes: RefCell, pub plugin_attributes: RefCell>, pub crate_types: RefCell>, pub dependency_formats: RefCell, @@ -123,6 +122,20 @@ pub struct Session { pub code_stats: RefCell, next_node_id: Cell, + + /// If -zfuel=crate=n is specified, Some(crate). + optimization_fuel_crate: Option, + /// If -zfuel=crate=n is specified, initially set to n. Otherwise 0. + optimization_fuel_limit: Cell, + /// We're rejecting all further optimizations. + out_of_fuel: Cell, + + // The next two are public because the driver needs to read them. + + /// If -zprint-fuel=crate, Some(crate). + pub print_fuel_crate: Option, + /// Always set to zero and incremented so that we can print fuel expended by a crate. + pub print_fuel: Cell, } pub struct PerfStats { @@ -363,6 +376,9 @@ impl Session { pub fn panic_strategy(&self) -> PanicStrategy { self.opts.cg.panic.unwrap_or(self.target.target.options.panic_strategy) } + pub fn linker_flavor(&self) -> LinkerFlavor { + self.opts.debugging_opts.linker_flavor.unwrap_or(self.target.target.linker_flavor) + } pub fn no_landing_pads(&self) -> bool { self.opts.debugging_opts.no_landing_pads || self.panic_strategy() == PanicStrategy::Abort } @@ -385,15 +401,14 @@ impl Session { /// Returns the symbol name for the registrar function, /// given the crate Svh and the function DefIndex. - pub fn generate_plugin_registrar_symbol(&self, svh: &Svh, index: DefIndex) + pub fn generate_plugin_registrar_symbol(&self, disambiguator: Symbol, index: DefIndex) -> String { - format!("__rustc_plugin_registrar__{}_{}", svh, index.as_usize()) + format!("__rustc_plugin_registrar__{}_{}", disambiguator, index.as_usize()) } - pub fn generate_derive_registrar_symbol(&self, - svh: &Svh, - index: DefIndex) -> String { - format!("__rustc_derive_registrar__{}_{}", svh, index.as_usize()) + pub fn generate_derive_registrar_symbol(&self, disambiguator: Symbol, index: DefIndex) + -> String { + format!("__rustc_derive_registrar__{}_{}", disambiguator, index.as_usize()) } pub fn sysroot<'a>(&'a self) -> &'a Path { @@ -504,6 +519,32 @@ impl Session { println!("Total time spent decoding DefPath tables: {}", duration_to_secs_str(self.perf_stats.decode_def_path_tables_time.get())); } + + /// We want to know if we're allowed to do an optimization for crate foo from -z fuel=foo=n. + /// This expends fuel if applicable, and records fuel if applicable. + pub fn consider_optimizing String>(&self, crate_name: &str, msg: T) -> bool { + let mut ret = true; + match self.optimization_fuel_crate { + Some(ref c) if c == crate_name => { + let fuel = self.optimization_fuel_limit.get(); + ret = fuel != 0; + if fuel == 0 && !self.out_of_fuel.get() { + println!("optimization-fuel-exhausted: {}", msg()); + self.out_of_fuel.set(true); + } else if fuel > 0 { + self.optimization_fuel_limit.set(fuel-1); + } + } + _ => {} + } + match self.print_fuel_crate { + Some(ref c) if c == crate_name=> { + self.print_fuel.set(self.print_fuel.get()+1); + }, + _ => {} + } + ret + } } pub fn build_session(sopts: config::Options, @@ -512,12 +553,14 @@ pub fn build_session(sopts: config::Options, registry: errors::registry::Registry, cstore: Rc) -> Session { + let file_path_mapping = sopts.file_path_mapping(); + build_session_with_codemap(sopts, dep_graph, local_crate_source_file, registry, cstore, - Rc::new(codemap::CodeMap::new()), + Rc::new(codemap::CodeMap::new(file_path_mapping)), None) } @@ -581,7 +624,7 @@ pub fn build_session_(sopts: config::Options, Ok(t) => t, Err(e) => { panic!(span_diagnostic.fatal(&format!("Error loading host specification: {}", e))); - } + } }; let target_cfg = config::build_target_config(&sopts, &span_diagnostic); let p_s = parse::ParseSess::with_span_handler(span_diagnostic, codemap); @@ -590,14 +633,21 @@ pub fn build_session_(sopts: config::Options, None => Some(filesearch::get_or_default_sysroot()) }; + let file_path_mapping = sopts.file_path_mapping(); + // Make the path absolute, if necessary - let local_crate_source_file = local_crate_source_file.map(|path| - if path.is_absolute() { - path.clone() - } else { - env::current_dir().unwrap().join(&path) - } - ); + let local_crate_source_file = local_crate_source_file.map(|path| { + file_path_mapping.map_prefix(path.to_string_lossy().into_owned()).0 + }); + + let optimization_fuel_crate = sopts.debugging_opts.fuel.as_ref().map(|i| i.0.clone()); + let optimization_fuel_limit = Cell::new(sopts.debugging_opts.fuel.as_ref() + .map(|i| i.1).unwrap_or(0)); + let print_fuel_crate = sopts.debugging_opts.print_fuel.clone(); + let print_fuel = Cell::new(0); + + let working_dir = env::current_dir().unwrap().to_string_lossy().into_owned(); + let working_dir = file_path_mapping.map_prefix(working_dir); let sess = Session { dep_graph: dep_graph.clone(), @@ -613,12 +663,11 @@ pub fn build_session_(sopts: config::Options, derive_registrar_fn: Cell::new(None), default_sysroot: default_sysroot, local_crate_source_file: local_crate_source_file, - working_dir: env::current_dir().unwrap(), + working_dir: working_dir, lint_store: RefCell::new(lint::LintStore::new()), lints: RefCell::new(lint::LintTable::new()), one_time_diagnostics: RefCell::new(FxHashSet()), plugin_llvm_passes: RefCell::new(Vec::new()), - mir_passes: RefCell::new(mir_pass::Passes::new()), plugin_attributes: RefCell::new(Vec::new()), crate_types: RefCell::new(Vec::new()), dependency_formats: RefCell::new(FxHashMap()), @@ -640,6 +689,11 @@ pub fn build_session_(sopts: config::Options, decode_def_path_tables_time: Cell::new(Duration::from_secs(0)), }, code_stats: RefCell::new(CodeStats::new()), + optimization_fuel_crate: optimization_fuel_crate, + optimization_fuel_limit: optimization_fuel_limit, + print_fuel_crate: print_fuel_crate, + print_fuel: print_fuel, + out_of_fuel: Cell::new(false), }; init_llvm(&sess); diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs index 383fab3fcd76..a943ef30e534 100644 --- a/src/librustc/traits/coherence.rs +++ b/src/librustc/traits/coherence.rs @@ -55,16 +55,15 @@ fn overlap<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>, debug!("overlap: b_impl_header={:?}", b_impl_header); // Do `a` and `b` unify? If not, no overlap. - match selcx.infcx().eq_impl_headers(true, + let obligations = match selcx.infcx().eq_impl_headers(true, &ObligationCause::dummy(), &a_impl_header, &b_impl_header) { Ok(InferOk { obligations, .. }) => { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()); + obligations } Err(_) => return None - } + }; debug!("overlap: unification check succeeded"); @@ -78,6 +77,7 @@ fn overlap<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>, .map(|p| Obligation { cause: ObligationCause::dummy(), recursion_depth: 0, predicate: p }) + .chain(obligations) .find(|o| !selcx.evaluate_obligation(o)); if let Some(failing_obligation) = opt_failing_obligation { diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 27525d550ff2..e846d74febfb 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -25,7 +25,7 @@ use super::{ use errors::DiagnosticBuilder; use fmt_macros::{Parser, Piece, Position}; -use hir::{intravisit, Local, Pat}; +use hir::{self, intravisit, Local, Pat, Body}; use hir::intravisit::{Visitor, NestedVisitorMap}; use hir::map::NodeExpr; use hir::def_id::DefId; @@ -33,12 +33,13 @@ use infer::{self, InferCtxt}; use infer::type_variable::TypeVariableOrigin; use rustc::lint::builtin::EXTRA_REQUIREMENT_IN_IMPL; use std::fmt; -use syntax::ast; -use ty::{self, AdtKind, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; -use ty::error::ExpectedFound; +use syntax::ast::{self, NodeId}; +use ty::{self, AdtKind, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable, TyInfer, TyVar}; +use ty::error::{ExpectedFound, TypeError}; use ty::fast_reject; use ty::fold::TypeFolder; use ty::subst::Subst; +use ty::SubtypePredicate; use util::nodemap::{FxHashMap, FxHashSet}; use syntax_pos::{DUMMY_SP, Span}; @@ -65,25 +66,53 @@ impl<'a, 'gcx, 'tcx> TraitErrorKey<'tcx> { struct FindLocalByTypeVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, target_ty: &'a Ty<'tcx>, - found_pattern: Option<&'a Pat>, + hir_map: &'a hir::map::Map<'gcx>, + found_local_pattern: Option<&'gcx Pat>, + found_arg_pattern: Option<&'gcx Pat>, } -impl<'a, 'gcx, 'tcx> Visitor<'a> for FindLocalByTypeVisitor<'a, 'gcx, 'tcx> { - fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'a> { - NestedVisitorMap::None +impl<'a, 'gcx, 'tcx> FindLocalByTypeVisitor<'a, 'gcx, 'tcx> { + fn node_matches_type(&mut self, node_id: &'gcx NodeId) -> bool { + match self.infcx.tables.borrow().node_types.get(node_id) { + Some(&ty) => { + let ty = self.infcx.resolve_type_vars_if_possible(&ty); + ty.walk().any(|inner_ty| { + inner_ty == *self.target_ty || match (&inner_ty.sty, &self.target_ty.sty) { + (&TyInfer(TyVar(a_vid)), &TyInfer(TyVar(b_vid))) => { + self.infcx + .type_variables + .borrow_mut() + .sub_unified(a_vid, b_vid) + } + _ => false, + } + }) + } + _ => false, + } + } +} + +impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindLocalByTypeVisitor<'a, 'gcx, 'tcx> { + fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> { + NestedVisitorMap::OnlyBodies(&self.hir_map) } - fn visit_local(&mut self, local: &'a Local) { - if let Some(&ty) = self.infcx.tables.borrow().node_types.get(&local.id) { - let ty = self.infcx.resolve_type_vars_if_possible(&ty); - let is_match = ty.walk().any(|t| t == *self.target_ty); - - if is_match && self.found_pattern.is_none() { - self.found_pattern = Some(&*local.pat); - } + fn visit_local(&mut self, local: &'gcx Local) { + if self.found_local_pattern.is_none() && self.node_matches_type(&local.id) { + self.found_local_pattern = Some(&*local.pat); } intravisit::walk_local(self, local); } + + fn visit_body(&mut self, body: &'gcx Body) { + for argument in &body.arguments { + if self.found_arg_pattern.is_none() && self.node_matches_type(&argument.id) { + self.found_arg_pattern = Some(&*argument.pat); + } + } + intravisit::walk_body(self, body); + } } impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { @@ -112,6 +141,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { FulfillmentErrorCode::CodeAmbiguity => { self.maybe_report_ambiguity(&error.obligation); } + FulfillmentErrorCode::CodeSubtypeError(ref expected_found, ref err) => { + self.report_mismatched_types(&error.obligation.cause, + expected_found.expected, + expected_found.found, + err.clone()) + .emit(); + } } } @@ -222,7 +258,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let mut self_match_impls = vec![]; let mut fuzzy_match_impls = vec![]; - self.tcx.lookup_trait_def(trait_ref.def_id) + self.tcx.trait_def(trait_ref.def_id) .for_each_relevant_impl(self.tcx, trait_self_ty, |def_id| { let impl_substs = self.fresh_substs_for_item(obligation.cause.span, def_id); let impl_trait_ref = tcx @@ -278,7 +314,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let trait_str = self.tcx.item_path_str(trait_ref.def_id); if let Some(istring) = item.value_str() { let istring = &*istring.as_str(); - let generics = self.tcx.item_generics(trait_ref.def_id); + let generics = self.tcx.generics_of(trait_ref.def_id); let generic_map = generics.types.iter().map(|param| { (param.name.as_str().to_string(), trait_ref.substs.type_for_def(param).to_string()) @@ -293,22 +329,20 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { Some(val) => Some(val), None => { span_err!(self.tcx.sess, err_sp, E0272, - "the #[rustc_on_unimplemented] \ - attribute on \ - trait definition for {} refers to \ - non-existent type parameter {}", - trait_str, s); + "the #[rustc_on_unimplemented] attribute on trait \ + definition for {} refers to non-existent type \ + parameter {}", + trait_str, s); errored = true; None } }, _ => { span_err!(self.tcx.sess, err_sp, E0273, - "the #[rustc_on_unimplemented] attribute \ - on trait definition for {} must have \ - named format arguments, eg \ - `#[rustc_on_unimplemented = \ - \"foo {{T}}\"]`", trait_str); + "the #[rustc_on_unimplemented] attribute on trait \ + definition for {} must have named format arguments, eg \ + `#[rustc_on_unimplemented = \"foo {{T}}\"]`", + trait_str); errored = true; None } @@ -338,7 +372,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { trait_ref.skip_binder().self_ty(), true); let mut impl_candidates = Vec::new(); - let trait_def = self.tcx.lookup_trait_def(trait_ref.def_id()); + let trait_def = self.tcx.trait_def(trait_ref.def_id()); match simp { Some(simp) => trait_def.for_each_impl(self.tcx, |def_id| { @@ -449,8 +483,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { "impl has stricter requirements than trait"); if let Some(trait_item_span) = self.tcx.hir.span_if_local(trait_item_def_id) { - err.span_label(trait_item_span, - &format!("definition of `{}` from trait", item_name)); + let span = self.tcx.sess.codemap().def_span(trait_item_span); + err.span_label(span, &format!("definition of `{}` from trait", item_name)); } err.span_label( @@ -524,15 +558,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { "the trait bound `{}` is not satisfied{}", trait_ref.to_predicate(), post_message); - err.span_label(span, - &format!("{}the trait `{}` is not \ - implemented for `{}`", - pre_message, - trait_ref, - trait_ref.self_ty())); // Try to report a help message - if !trait_ref.has_infer_types() && self.predicate_can_apply(trait_ref) { // If a where-clause may be useful, remind the @@ -544,20 +571,31 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // which is somewhat confusing. err.help(&format!("consider adding a `where {}` bound", trait_ref.to_predicate())); - } else if let Some(s) = self.on_unimplemented_note(trait_ref, - obligation) { + } else if let Some(s) = self.on_unimplemented_note(trait_ref, obligation) { // If it has a custom "#[rustc_on_unimplemented]" // error message, let's display it! err.note(&s); } else { - // If we can't show anything useful, try to find - // similar impls. + // Can't show anything else useful, try to find similar impls. let impl_candidates = self.find_similar_impl_candidates(trait_ref); self.report_similar_impl_candidates(impl_candidates, &mut err); } + + err.span_label(span, + &format!("{}the trait `{}` is not implemented for `{}`", + pre_message, + trait_ref, + trait_ref.self_ty())); err } + ty::Predicate::Subtype(ref predicate) => { + // Errors for Subtype predicates show up as + // `FulfillmentErrorCode::CodeSubtypeError`, + // not selection error. + span_bug!(span, "subtype requirement gave wrong error: `{:?}`", predicate) + } + ty::Predicate::Equate(ref predicate) => { let predicate = self.resolve_type_vars_if_possible(predicate); let err = self.equality_predicate(&obligation.cause, @@ -625,13 +663,54 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { if actual_trait_ref.self_ty().references_error() { return; } - struct_span_err!(self.tcx.sess, span, E0281, - "type mismatch: the type `{}` implements the trait `{}`, \ - but the trait `{}` is required ({})", - expected_trait_ref.self_ty(), - expected_trait_ref, - actual_trait_ref, - e) + let expected_trait_ty = expected_trait_ref.self_ty(); + let found_span = expected_trait_ty.ty_to_def_id().and_then(|did| { + self.tcx.hir.span_if_local(did) + }); + + if let &TypeError::TupleSize(ref expected_found) = e { + // Expected `|x| { }`, found `|x, y| { }` + self.report_arg_count_mismatch(span, + found_span, + expected_found.expected, + expected_found.found, + expected_trait_ty.is_closure()) + } else if let &TypeError::Sorts(ref expected_found) = e { + let expected = if let ty::TyTuple(tys, _) = expected_found.expected.sty { + tys.len() + } else { + 1 + }; + let found = if let ty::TyTuple(tys, _) = expected_found.found.sty { + tys.len() + } else { + 1 + }; + + if expected != found { + // Expected `|| { }`, found `|x, y| { }` + // Expected `fn(x) -> ()`, found `|| { }` + self.report_arg_count_mismatch(span, + found_span, + expected, + found, + expected_trait_ty.is_closure()) + } else { + self.report_type_argument_mismatch(span, + found_span, + expected_trait_ty, + expected_trait_ref, + actual_trait_ref, + e) + } + } else { + self.report_type_argument_mismatch(span, + found_span, + expected_trait_ty, + expected_trait_ref, + actual_trait_ref, + e) + } } TraitNotObjectSafe(did) => { @@ -643,6 +722,60 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.note_obligation_cause(&mut err, obligation); err.emit(); } + + fn report_type_argument_mismatch(&self, + span: Span, + found_span: Option, + expected_ty: Ty<'tcx>, + expected_ref: ty::PolyTraitRef<'tcx>, + found_ref: ty::PolyTraitRef<'tcx>, + type_error: &TypeError<'tcx>) + -> DiagnosticBuilder<'tcx> + { + let mut err = struct_span_err!(self.tcx.sess, span, E0281, + "type mismatch: `{}` implements the trait `{}`, but the trait `{}` is required", + expected_ty, + expected_ref, + found_ref); + + err.span_label(span, &format!("{}", type_error)); + + if let Some(sp) = found_span { + err.span_label(span, &format!("requires `{}`", found_ref)); + err.span_label(sp, &format!("implements `{}`", expected_ref)); + } + + err + } + + fn report_arg_count_mismatch(&self, + span: Span, + found_span: Option, + expected: usize, + found: usize, + is_closure: bool) + -> DiagnosticBuilder<'tcx> + { + let mut err = struct_span_err!(self.tcx.sess, span, E0593, + "{} takes {} argument{} but {} argument{} {} required", + if is_closure { "closure" } else { "function" }, + found, + if found == 1 { "" } else { "s" }, + expected, + if expected == 1 { "" } else { "s" }, + if expected == 1 { "is" } else { "are" }); + + err.span_label(span, &format!("expected {} that takes {} argument{}", + if is_closure { "closure" } else { "function" }, + expected, + if expected == 1 { "" } else { "s" })); + if let Some(span) = found_span { + err.span_label(span, &format!("takes {} argument{}", + found, + if found == 1 { "" } else { "s" })); + } + err + } } impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { @@ -652,6 +785,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { { assert!(type_def_id.is_local()); let span = self.hir.span_if_local(type_def_id).unwrap(); + let span = self.sess.codemap().def_span(span); let mut err = struct_span_err!(self.sess, span, E0072, "recursive type `{}` has infinite size", self.item_path_str(type_def_id)); @@ -669,13 +803,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { -> DiagnosticBuilder<'tcx> { let trait_str = self.item_path_str(trait_def_id); + let span = self.sess.codemap().def_span(span); let mut err = struct_span_err!( self.sess, span, E0038, "the trait `{}` cannot be made into an object", trait_str); - err.span_label(span, &format!( - "the trait `{}` cannot be made into an object", trait_str - )); + err.span_label(span, &format!("the trait `{}` cannot be made into an object", trait_str)); let mut reported_violations = FxHashSet(); for violation in violations { @@ -696,6 +829,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // coherence violation, so we don't report it here. let predicate = self.resolve_type_vars_if_possible(&obligation.predicate); + let body_id = hir::BodyId { node_id: obligation.cause.body_id }; + let span = obligation.cause.span; debug!("maybe_report_ambiguity(predicate={:?}, obligation={:?})", predicate, @@ -743,10 +878,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.tcx.lang_items.sized_trait() .map_or(false, |sized_id| sized_id == trait_ref.def_id()) { - self.need_type_info(obligation, self_ty); + self.need_type_info(body_id, span, self_ty); } else { let mut err = struct_span_err!(self.tcx.sess, - obligation.cause.span, E0283, + span, E0283, "type annotations required: \ cannot resolve `{}`", predicate); @@ -760,7 +895,20 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // Same hacky approach as above to avoid deluging user // with error messages. if !ty.references_error() && !self.tcx.sess.has_errors() { - self.need_type_info(obligation, ty); + self.need_type_info(body_id, span, ty); + } + } + + ty::Predicate::Subtype(ref data) => { + if data.references_error() || self.tcx.sess.has_errors() { + // no need to overload user in such cases + } else { + let &SubtypePredicate { a_is_expected: _, a, b } = data.skip_binder(); + // both must be type variables, or the other would've been instantiated + assert!(a.is_ty_var() && b.is_ty_var()); + self.need_type_info(hir::BodyId { node_id: obligation.cause.body_id }, + obligation.cause.span, + a); } } @@ -838,42 +986,66 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } - fn need_type_info(&self, obligation: &PredicateObligation<'tcx>, ty: Ty<'tcx>) { + pub fn need_type_info(&self, body_id: hir::BodyId, span: Span, ty: Ty<'tcx>) { let ty = self.resolve_type_vars_if_possible(&ty); let name = self.extract_type_name(&ty); - let ref cause = obligation.cause; - let mut err = struct_span_err!(self.tcx.sess, - cause.span, - E0282, - "type annotations needed"); - - err.span_label(cause.span, &format!("cannot infer type for `{}`", name)); + let mut err_span = span; + let mut labels = vec![(span, format!("cannot infer type for `{}`", name))]; let mut local_visitor = FindLocalByTypeVisitor { infcx: &self, target_ty: &ty, - found_pattern: None, + hir_map: &self.tcx.hir, + found_local_pattern: None, + found_arg_pattern: None, }; // #40294: cause.body_id can also be a fn declaration. // Currently, if it's anything other than NodeExpr, we just ignore it - match self.tcx.hir.find(cause.body_id) { + match self.tcx.hir.find(body_id.node_id) { Some(NodeExpr(expr)) => local_visitor.visit_expr(expr), _ => () } - if let Some(pattern) = local_visitor.found_pattern { - let pattern_span = pattern.span; + if let Some(pattern) = local_visitor.found_arg_pattern { + err_span = pattern.span; + // We don't want to show the default label for closures. + // + // So, before clearing, the output would look something like this: + // ``` + // let x = |_| { }; + // - ^^^^ cannot infer type for `[_; 0]` + // | + // consider giving this closure parameter a type + // ``` + // + // After clearing, it looks something like this: + // ``` + // let x = |_| { }; + // ^ consider giving this closure parameter a type + // ``` + labels.clear(); + labels.push((pattern.span, format!("consider giving this closure parameter a type"))); + } + + if let Some(pattern) = local_visitor.found_local_pattern { if let Some(simple_name) = pattern.simple_name() { - err.span_label(pattern_span, - &format!("consider giving `{}` a type", - simple_name)); + labels.push((pattern.span, format!("consider giving `{}` a type", simple_name))); } else { - err.span_label(pattern_span, &format!("consider giving a type to pattern")); + labels.push((pattern.span, format!("consider giving the pattern a type"))); } } + let mut err = struct_span_err!(self.tcx.sess, + err_span, + E0282, + "type annotations needed"); + + for (target_span, label_message) in labels { + err.span_label(target_span, &label_message); + } + err.emit(); } @@ -904,6 +1076,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ObligationCauseCode::StartFunctionType | ObligationCauseCode::IntrinsicType | ObligationCauseCode::MethodReceiver | + ObligationCauseCode::ReturnNoExpression | ObligationCauseCode::MiscObligation => { } ObligationCauseCode::SliceOrArrayElem => { @@ -996,3 +1169,4 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { suggested_limit)); } } + diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index b87d18464377..e8baaa7ffb26 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -11,6 +11,7 @@ use dep_graph::DepGraph; use infer::{InferCtxt, InferOk}; use ty::{self, Ty, TypeFoldable, ToPolyTraitRef, TyCtxt, ToPredicate}; +use ty::error::ExpectedFound; use rustc_data_structures::obligation_forest::{ObligationForest, Error}; use rustc_data_structures::obligation_forest::{ForestObligation, ObligationProcessor}; use std::marker::PhantomData; @@ -83,7 +84,7 @@ pub struct FulfillmentContext<'tcx> { #[derive(Clone)] pub struct RegionObligation<'tcx> { - pub sub_region: &'tcx ty::Region, + pub sub_region: ty::Region<'tcx>, pub sup_type: Ty<'tcx>, pub cause: ObligationCause<'tcx>, } @@ -154,7 +155,7 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> { pub fn register_region_obligation(&mut self, t_a: Ty<'tcx>, - r_b: &'tcx ty::Region, + r_b: ty::Region<'tcx>, cause: ObligationCause<'tcx>) { register_region_obligation(t_a, r_b, cause, &mut self.region_obligations); @@ -170,7 +171,7 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> { debug!("register_predicate_obligation(obligation={:?})", obligation); - infcx.obligations_in_snapshot.set(true); + assert!(!infcx.is_in_snapshot()); if infcx.tcx.fulfilled_predicates.borrow().check_duplicate(&obligation.predicate) { debug!("register_predicate_obligation: duplicate"); @@ -183,6 +184,16 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> { }); } + pub fn register_predicate_obligations(&mut self, + infcx: &InferCtxt<'a, 'gcx, 'tcx>, + obligations: Vec>) + { + for obligation in obligations { + self.register_predicate_obligation(infcx, obligation); + } + } + + pub fn region_obligations(&self, body_id: ast::NodeId) -> &[RegionObligation<'tcx>] @@ -432,7 +443,7 @@ fn process_predicate<'a, 'gcx, 'tcx>( // Otherwise, we have something of the form // `for<'a> T: 'a where 'a not in T`, which we can treat as `T: 'static`. Some(t_a) => { - let r_static = selcx.tcx().mk_region(ty::ReStatic); + let r_static = selcx.tcx().types.re_static; register_region_obligation(t_a, r_static, obligation.cause.clone(), region_obligations); @@ -496,6 +507,26 @@ fn process_predicate<'a, 'gcx, 'tcx>( s => Ok(s) } } + + ty::Predicate::Subtype(ref subtype) => { + match selcx.infcx().subtype_predicate(&obligation.cause, subtype) { + None => { + // none means that both are unresolved + pending_obligation.stalled_on = vec![subtype.skip_binder().a, + subtype.skip_binder().b]; + Ok(None) + } + Some(Ok(ok)) => { + Ok(Some(ok.obligations)) + } + Some(Err(err)) => { + let expected_found = ExpectedFound::new(subtype.skip_binder().a_is_expected, + subtype.skip_binder().a, + subtype.skip_binder().b); + Err(FulfillmentErrorCode::CodeSubtypeError(expected_found, err)) + } + } + } } } @@ -535,7 +566,7 @@ fn coinductive_obligation<'a,'gcx,'tcx>(selcx: &SelectionContext<'a,'gcx,'tcx>, } fn register_region_obligation<'tcx>(t_a: Ty<'tcx>, - r_b: &'tcx ty::Region, + r_b: ty::Region<'tcx>, cause: ObligationCause<'tcx>, region_obligations: &mut NodeMap>>) { diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index c71fc28b4d6b..2f525e1b8b45 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -17,10 +17,12 @@ pub use self::ObligationCauseCode::*; use hir; use hir::def_id::DefId; +use middle::region::RegionMaps; use middle::free_region::FreeRegionMap; use ty::subst::Substs; use ty::{self, Ty, TyCtxt, TypeFoldable, ToPredicate}; -use infer::InferCtxt; +use ty::error::{ExpectedFound, TypeError}; +use infer::{InferCtxt}; use std::rc::Rc; use syntax::ast; @@ -37,8 +39,6 @@ pub use self::project::{ProjectionCache, ProjectionCacheSnapshot, Reveal}; pub use self::object_safety::ObjectSafetyViolation; pub use self::object_safety::MethodViolationCode; pub use self::select::{EvaluationCache, SelectionContext, SelectionCache}; -pub use self::select::{MethodMatchResult, MethodMatched, MethodAmbiguous, MethodDidNotMatch}; -pub use self::select::{MethodMatchedData}; // intentionally don't export variants pub use self::specialize::{OverlapError, specialization_graph, specializes, translate_substs}; pub use self::specialize::{SpecializesCache, find_associated_item}; pub use self::util::elaborate_predicates; @@ -56,6 +56,7 @@ mod object_safety; mod select; mod specialize; mod structural_impls; +pub mod trans; mod util; /// An `Obligation` represents some trait reference (e.g. `int:Eq`) for @@ -112,7 +113,7 @@ pub enum ObligationCauseCode<'tcx> { ReferenceOutlivesReferent(Ty<'tcx>), /// A type like `Box + 'b>` is WF only if `'b: 'a`. - ObjectTypeBound(Ty<'tcx>, &'tcx ty::Region), + ObjectTypeBound(Ty<'tcx>, ty::Region<'tcx>), /// Obligation incurred due to an object cast. ObjectCastObligation(/* Object type */ Ty<'tcx>), @@ -173,6 +174,9 @@ pub enum ObligationCauseCode<'tcx> { // method receiver MethodReceiver, + + // `return` with no expression + ReturnNoExpression, } #[derive(Clone, Debug, PartialEq, Eq)] @@ -211,6 +215,8 @@ pub struct FulfillmentError<'tcx> { pub enum FulfillmentErrorCode<'tcx> { CodeSelectionError(SelectionError<'tcx>), CodeProjectionError(MismatchedProjectionTypes<'tcx>), + CodeSubtypeError(ExpectedFound>, + TypeError<'tcx>), // always comes from a SubtypePredicate CodeAmbiguity, } @@ -430,9 +436,10 @@ pub fn type_known_to_meet_bound<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx // FIXME: this is gonna need to be removed ... /// Normalizes the parameter environment, reporting errors if they occur. pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - unnormalized_env: ty::ParameterEnvironment<'tcx>, - cause: ObligationCause<'tcx>) - -> ty::ParameterEnvironment<'tcx> + region_context: DefId, + unnormalized_env: ty::ParameterEnvironment<'tcx>, + cause: ObligationCause<'tcx>) + -> ty::ParameterEnvironment<'tcx> { // I'm not wild about reporting errors here; I'd prefer to // have the errors get reported at a defined place (e.g., @@ -450,13 +457,12 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // can be sure that no errors should occur. let span = cause.span; - let body_id = cause.body_id; debug!("normalize_param_env_or_error(unnormalized_env={:?})", unnormalized_env); let predicates: Vec<_> = - util::elaborate_predicates(tcx, unnormalized_env.caller_bounds.clone()) + util::elaborate_predicates(tcx, unnormalized_env.caller_bounds.to_vec()) .filter(|p| !p.is_global()) // (*) .collect(); @@ -471,11 +477,19 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, debug!("normalize_param_env_or_error: elaborated-predicates={:?}", predicates); - let elaborated_env = unnormalized_env.with_caller_bounds(predicates); + let elaborated_env = unnormalized_env.with_caller_bounds(tcx.intern_predicates(&predicates)); tcx.infer_ctxt(elaborated_env, Reveal::UserFacing).enter(|infcx| { - let predicates = match fully_normalize(&infcx, cause, - &infcx.parameter_environment.caller_bounds) { + let predicates = match fully_normalize( + &infcx, cause, + // You would really want to pass infcx.parameter_environment.caller_bounds here, + // but that is an interned slice, and fully_normalize takes &T and returns T, so + // without further refactoring, a slice can't be used. Luckily, we still have the + // predicate vector from which we created the ParameterEnvironment in infcx, so we + // can pass that instead. It's roundabout and a bit brittle, but this code path + // ought to be refactored anyway, and until then it saves us from having to copy. + &predicates, + ) { Ok(predicates) => predicates, Err(errors) => { infcx.report_fulfillment_errors(&errors); @@ -487,8 +501,9 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, debug!("normalize_param_env_or_error: normalized predicates={:?}", predicates); + let region_maps = RegionMaps::new(); let free_regions = FreeRegionMap::new(); - infcx.resolve_regions_and_report_errors(&free_regions, body_id); + infcx.resolve_regions_and_report_errors(region_context, ®ion_maps, &free_regions); let predicates = match infcx.fully_resolve(&predicates) { Ok(predicates) => predicates, Err(fixup_err) => { @@ -513,7 +528,7 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, debug!("normalize_param_env_or_error: resolved predicates={:?}", predicates); - infcx.parameter_environment.with_caller_bounds(predicates) + infcx.parameter_environment.with_caller_bounds(tcx.intern_predicates(&predicates)) }) } @@ -624,7 +639,7 @@ pub fn get_vtable_methods<'a, 'tcx>( // the method may have some early-bound lifetimes, add // regions for those let substs = Substs::for_item(tcx, def_id, - |_, _| tcx.mk_region(ty::ReErased), + |_, _| tcx.types.re_erased, |def, _| trait_ref.substs().type_for_def(def)); // the trait type may have higher-ranked lifetimes in it; @@ -636,7 +651,7 @@ pub fn get_vtable_methods<'a, 'tcx>( // do not hold for this particular set of type parameters. // Note that this method could then never be called, so we // do not want to try and trans it, in that case (see #23435). - let predicates = tcx.item_predicates(def_id).instantiate_own(tcx, substs); + let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs); if !normalize_and_test_predicates(tcx, predicates.predicates) { debug!("get_vtable_methods: predicates do not hold"); return None; diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index 7cd0b26940d9..ea1a2f9a982c 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -37,6 +37,9 @@ pub enum ObjectSafetyViolation { /// Method has something illegal Method(ast::Name, MethodViolationCode), + + /// Associated const + AssociatedConst(ast::Name), } impl ObjectSafetyViolation { @@ -54,6 +57,8 @@ impl ObjectSafetyViolation { in its arguments or return type", name).into(), ObjectSafetyViolation::Method(name, MethodViolationCode::Generic) => format!("method `{}` has generic type parameters", name).into(), + ObjectSafetyViolation::AssociatedConst(name) => + format!("the trait cannot contain associated consts like `{}`", name).into(), } } } @@ -74,7 +79,7 @@ pub enum MethodViolationCode { impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn is_object_safe(self, trait_def_id: DefId) -> bool { // Because we query yes/no results frequently, we keep a cache: - let def = self.lookup_trait_def(trait_def_id); + let def = self.trait_def(trait_def_id); let result = def.object_safety().unwrap_or_else(|| { let result = self.object_safety_violations(trait_def_id).is_empty(); @@ -141,6 +146,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { violations.push(ObjectSafetyViolation::SupertraitSelf); } + violations.extend(self.associated_items(trait_def_id) + .filter(|item| item.kind == ty::AssociatedKind::Const) + .map(|item| ObjectSafetyViolation::AssociatedConst(item.name))); + debug!("object_safety_violations_for_trait(trait_def_id={:?}) = {:?}", trait_def_id, violations); @@ -158,9 +167,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { substs: Substs::identity_for_item(self, trait_def_id) }); let predicates = if supertraits_only { - self.item_super_predicates(trait_def_id) + self.super_predicates_of(trait_def_id) } else { - self.item_predicates(trait_def_id) + self.predicates_of(trait_def_id) }; predicates .predicates @@ -178,6 +187,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { ty::Predicate::TypeOutlives(..) | ty::Predicate::RegionOutlives(..) | ty::Predicate::ClosureKind(..) | + ty::Predicate::Subtype(..) | ty::Predicate::Equate(..) => { false } @@ -196,9 +206,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { }; // Search for a predicate like `Self : Sized` amongst the trait bounds. - let free_substs = self.construct_free_substs(def_id, - self.region_maps.node_extent(ast::DUMMY_NODE_ID)); - let predicates = self.item_predicates(def_id); + let free_substs = self.construct_free_substs(def_id, None); + let predicates = self.predicates_of(def_id); let predicates = predicates.instantiate(self, free_substs).predicates; elaborate_predicates(self, predicates) .any(|predicate| { @@ -209,6 +218,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { ty::Predicate::Projection(..) | ty::Predicate::Trait(..) | ty::Predicate::Equate(..) | + ty::Predicate::Subtype(..) | ty::Predicate::RegionOutlives(..) | ty::Predicate::WellFormed(..) | ty::Predicate::ObjectSafe(..) | @@ -270,7 +280,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // The `Self` type is erased, so it should not appear in list of // arguments or return type apart from the receiver. - let ref sig = self.item_type(method.def_id).fn_sig(); + let ref sig = self.type_of(method.def_id).fn_sig(); for input_ty in &sig.skip_binder().inputs()[1..] { if self.contains_illegal_self_type_reference(trait_def_id, input_ty) { return Some(MethodViolationCode::ReferencesSelf); @@ -281,7 +291,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } // We can't monomorphize things like `fn foo(...)`. - if !self.item_generics(method.def_id).types.is_empty() { + if !self.generics_of(method.def_id).types.is_empty() { return Some(MethodViolationCode::Generic); } diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index 3d8f9e41c675..e01f97eb1f3a 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -279,7 +279,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssociatedTypeNormalizer<'a, ty::TyAnon(def_id, substs) if !substs.has_escaping_regions() => { // (*) // Only normalize `impl Trait` after type-checking, usually in trans. if self.selcx.projection_mode() == Reveal::All { - let generic_ty = self.tcx().item_type(def_id); + let generic_ty = self.tcx().type_of(def_id); let concrete_ty = generic_ty.subst(self.tcx(), substs); self.fold_ty(concrete_ty) } else { @@ -787,7 +787,7 @@ fn assemble_candidates_from_trait_def<'cx, 'gcx, 'tcx>( }; // If so, extract what we know from the trait and try to come up with a good answer. - let trait_predicates = selcx.tcx().item_predicates(def_id); + let trait_predicates = selcx.tcx().predicates_of(def_id); let bounds = trait_predicates.instantiate(selcx.tcx(), substs); let bounds = elaborate_predicates(selcx.tcx(), bounds.predicates); assemble_candidates_from_predicates(selcx, @@ -923,7 +923,8 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>( // being invoked). node_item.item.defaultness.has_value() } else { - node_item.item.defaultness.is_default() + node_item.item.defaultness.is_default() || + selcx.tcx().impl_is_default(node_item.node.def_id()) }; // Only reveal a specializable default if we're past type-checking @@ -1288,7 +1289,7 @@ fn confirm_impl_candidate<'cx, 'gcx, 'tcx>( obligation.predicate.trait_ref); tcx.types.err } else { - tcx.item_type(node_item.item.def_id) + tcx.type_of(node_item.item.def_id) }; let substs = translate_substs(selcx.infcx(), impl_def_id, substs, node_item.node); Progress { @@ -1317,7 +1318,7 @@ fn assoc_ty_def<'cx, 'gcx, 'tcx>( -> Option> { let trait_def_id = selcx.tcx().impl_trait_ref(impl_def_id).unwrap().def_id; - let trait_def = selcx.tcx().lookup_trait_def(trait_def_id); + let trait_def = selcx.tcx().trait_def(trait_def_id); if !trait_def.is_complete(selcx.tcx()) { let impl_node = specialization_graph::Node::Impl(impl_def_id); diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 38ea1e4a19b9..cccc20e5b296 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -10,8 +10,6 @@ //! See `README.md` for high-level documentation -pub use self::MethodMatchResult::*; -pub use self::MethodMatchedData::*; use self::SelectionCandidate::*; use self::EvaluationResult::*; @@ -110,23 +108,6 @@ pub struct SelectionCache<'tcx> { SelectionResult<'tcx, SelectionCandidate<'tcx>>>>, } -pub enum MethodMatchResult { - MethodMatched(MethodMatchedData), - MethodAmbiguous(/* list of impls that could apply */ Vec), - MethodDidNotMatch, -} - -#[derive(Copy, Clone, Debug)] -pub enum MethodMatchedData { - // In the case of a precise match, we don't really need to store - // how the match was found. So don't. - PreciseMethodMatch, - - // In the case of a coercion, we need to know the precise impl so - // that we can determine the type to which things were coerced. - CoerciveMethodMatch(/* impl we matched */ DefId) -} - /// The selection process begins by considering all impls, where /// clauses, and so forth that might resolve an obligation. Sometimes /// we'll be able to say definitively that (e.g.) an impl does not @@ -568,6 +549,18 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } } + ty::Predicate::Subtype(ref p) => { + // does this code ever run? + match self.infcx.subtype_predicate(&obligation.cause, p) { + Some(Ok(InferOk { obligations, .. })) => { + self.inferred_obligations.extend(obligations); + EvaluatedToOk + }, + Some(Err(_)) => EvaluatedToErr, + None => EvaluatedToAmbig, + } + } + ty::Predicate::WellFormed(ty) => { match ty::wf::obligations(self.infcx, obligation.cause.body_id, ty, obligation.cause.span) { @@ -849,7 +842,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { fn filter_negative_impls(&self, candidate: SelectionCandidate<'tcx>) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> { if let ImplCandidate(def_id) = candidate { - if self.tcx().trait_impl_polarity(def_id) == hir::ImplPolarity::Negative { + if self.tcx().impl_polarity(def_id) == hir::ImplPolarity::Negative { return Err(Unimplemented) } } @@ -950,17 +943,17 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { debug!("Retaining candidate #{}/{}: {:?}", i, candidates.len(), candidates[i]); i += 1; + + // If there are *STILL* multiple candidates, give up + // and report ambiguity. + if i > 1 { + debug!("multiple matches, ambig"); + return Ok(None); + } } } } - // If there are *STILL* multiple candidates, give up and - // report ambiguity. - if candidates.len() > 1 { - debug!("multiple matches, ambig"); - return Ok(None); - } - // If there are *NO* candidates, then there are no impls -- // that we know of, anyway. Note that in the case where there // are unbound type variables within the obligation, it might @@ -1229,8 +1222,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { def_id={:?}, substs={:?}", def_id, substs); - let item_predicates = self.tcx().item_predicates(def_id); - let bounds = item_predicates.instantiate(self.tcx(), substs); + let predicates_of = self.tcx().predicates_of(def_id); + let bounds = predicates_of.instantiate(self.tcx(), substs); debug!("match_projection_obligation_against_definition_bounds: \ bounds={:?}", bounds); @@ -1307,8 +1300,13 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { .iter() .filter_map(|o| o.to_opt_poly_trait_ref()); + // micro-optimization: filter out predicates relating to different + // traits. let matching_bounds = - all_bounds.filter( + all_bounds.filter(|p| p.def_id() == stack.obligation.predicate.def_id()); + + let matching_bounds = + matching_bounds.filter( |bound| self.evaluate_where_clause(stack, bound.clone()).may_apply()); let param_candidates = @@ -1434,7 +1432,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { { debug!("assemble_candidates_from_impls(obligation={:?})", obligation); - let def = self.tcx().lookup_trait_def(obligation.predicate.def_id()); + let def = self.tcx().trait_def(obligation.predicate.def_id()); def.for_each_relevant_impl( self.tcx(), @@ -1724,7 +1722,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { if other.evaluation == EvaluatedToOk { if let ImplCandidate(victim_def) = victim.candidate { let tcx = self.tcx().global_tcx(); - return traits::specializes(tcx, other_def, victim_def); + return traits::specializes(tcx, other_def, victim_def) || + tcx.impls_are_allowed_to_overlap(other_def, victim_def); } } @@ -1796,11 +1795,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ty::TyAdt(def, substs) => { let sized_crit = def.sized_constraint(self.tcx()); // (*) binder moved here - Where(ty::Binder(match sized_crit.sty { - ty::TyTuple(tys, _) => tys.to_vec().subst(self.tcx(), substs), - ty::TyBool => vec![], - _ => vec![sized_crit.subst(self.tcx(), substs)] - })) + Where(ty::Binder( + sized_crit.iter().map(|ty| ty.subst(self.tcx(), substs)).collect() + )) } ty::TyProjection(_) | ty::TyParam(_) | ty::TyAnon(..) => None, @@ -1950,7 +1947,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // We can resolve the `impl Trait` to its concrete type, // which enforces a DAG between the functions requiring // the auto trait bounds in question. - vec![self.tcx().item_type(def_id).subst(self.tcx(), substs)] + vec![self.tcx().type_of(def_id).subst(self.tcx(), substs)] } } } @@ -2529,7 +2526,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { (&ty::TyAdt(def, substs_a), &ty::TyAdt(_, substs_b)) => { let fields = def .all_fields() - .map(|f| tcx.item_type(f.did)) + .map(|f| tcx.type_of(f.did)) .collect::>(); // The last field of the structure has to exist and contain type parameters. @@ -2847,7 +2844,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // obligation will normalize to `<$0 as Iterator>::Item = $1` and // `$1: Copy`, so we must ensure the obligations are emitted in // that order. - let predicates = tcx.item_predicates(def_id); + let predicates = tcx.predicates_of(def_id); assert_eq!(predicates.parent, None); let predicates = predicates.predicates.iter().flat_map(|predicate| { let predicate = normalize_with_depth(self, cause.clone(), recursion_depth, @@ -2969,13 +2966,3 @@ impl EvaluationResult { } } } - -impl MethodMatchResult { - pub fn may_apply(&self) -> bool { - match *self { - MethodMatched(_) => true, - MethodAmbiguous(_) => true, - MethodDidNotMatch => false, - } - } -} diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index 50a4d982832a..d5d17e3c8121 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -23,7 +23,6 @@ use super::util::impl_trait_ref_and_oblig; use rustc_data_structures::fx::FxHashMap; use hir::def_id::DefId; use infer::{InferCtxt, InferOk}; -use middle::region; use ty::subst::{Subst, Substs}; use traits::{self, Reveal, ObligationCause}; use ty::{self, TyCtxt, TypeFoldable}; @@ -117,7 +116,7 @@ pub fn find_associated_item<'a, 'tcx>( assert!(!substs.needs_infer()); let trait_def_id = tcx.trait_id_of_impl(impl_data.impl_def_id).unwrap(); - let trait_def = tcx.lookup_trait_def(trait_def_id); + let trait_def = tcx.trait_def(trait_def_id); let ancestors = trait_def.ancestors(impl_data.impl_def_id); match ancestors.defs(tcx, item.name, item.kind).next() { @@ -175,14 +174,14 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // See RFC 1210 for more details and justification. // Currently we do not allow e.g. a negative impl to specialize a positive one - if tcx.trait_impl_polarity(impl1_def_id) != tcx.trait_impl_polarity(impl2_def_id) { + if tcx.impl_polarity(impl1_def_id) != tcx.impl_polarity(impl2_def_id) { return false; } // create a parameter environment corresponding to a (skolemized) instantiation of impl1 let penv = tcx.construct_parameter_environment(DUMMY_SP, impl1_def_id, - region::DUMMY_CODE_EXTENT); + None); let impl1_trait_ref = tcx.impl_trait_ref(impl1_def_id) .unwrap() .subst(tcx, &penv.free_substs); @@ -218,7 +217,7 @@ fn fulfill_implication<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, -> Result<&'tcx Substs<'tcx>, ()> { let selcx = &mut SelectionContext::new(&infcx); let target_substs = infcx.fresh_substs_for_item(DUMMY_SP, target_impl); - let (target_trait_ref, obligations) = impl_trait_ref_and_oblig(selcx, + let (target_trait_ref, mut obligations) = impl_trait_ref_and_oblig(selcx, target_impl, target_substs); @@ -227,9 +226,8 @@ fn fulfill_implication<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, &ObligationCause::dummy(), source_trait_ref, target_trait_ref) { - Ok(InferOk { obligations, .. }) => { - // FIXME(#32730) propagate obligations - assert!(obligations.is_empty()) + Ok(InferOk { obligations: o, .. }) => { + obligations.extend(o); } Err(_) => { debug!("fulfill_implication: {:?} does not unify with {:?}", @@ -242,7 +240,7 @@ fn fulfill_implication<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, // attempt to prove all of the predicates for impl2 given those for impl1 // (which are packed up in penv) - infcx.save_and_restore_obligations_in_snapshot_flag(|infcx| { + infcx.save_and_restore_in_snapshot_flag(|infcx| { let mut fulfill_cx = FulfillmentContext::new(); for oblig in obligations.into_iter() { fulfill_cx.register_predicate_obligation(&infcx, oblig); diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc/traits/specialize/specialization_graph.rs index 40eb69395678..6e2c16c82aeb 100644 --- a/src/librustc/traits/specialize/specialization_graph.rs +++ b/src/librustc/traits/specialize/specialization_graph.rs @@ -113,6 +113,10 @@ impl<'a, 'gcx, 'tcx> Children { possible_sibling, impl_def_id); if let Some(impl_header) = overlap { + if tcx.impls_are_allowed_to_overlap(impl_def_id, possible_sibling) { + return Ok((false, false)); + } + let le = specializes(tcx, impl_def_id, possible_sibling); let ge = specializes(tcx, possible_sibling, impl_def_id); diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index 717c171db2ac..9d0b1035ade4 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -130,6 +130,8 @@ impl<'tcx> fmt::Debug for traits::FulfillmentErrorCode<'tcx> { match *self { super::CodeSelectionError(ref e) => write!(f, "{:?}", e), super::CodeProjectionError(ref e) => write!(f, "{:?}", e), + super::CodeSubtypeError(ref a, ref b) => + write!(f, "CodeSubtypeError({:?}, {:?})", a, b), super::CodeAmbiguity => write!(f, "Ambiguity") } } @@ -167,6 +169,7 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> { type Lifted = traits::ObligationCauseCode<'tcx>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { match *self { + super::ReturnNoExpression => Some(super::ReturnNoExpression), super::MiscObligation => Some(super::MiscObligation), super::SliceOrArrayElem => Some(super::SliceOrArrayElem), super::TupleElem => Some(super::TupleElem), @@ -489,6 +492,7 @@ impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCauseCode<'tcx> { super::StructInitializerSized | super::VariableType(_) | super::ReturnType | + super::ReturnNoExpression | super::RepeatVec | super::FieldSized | super::ConstSized | @@ -533,6 +537,7 @@ impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCauseCode<'tcx> { super::StructInitializerSized | super::VariableType(_) | super::ReturnType | + super::ReturnNoExpression | super::RepeatVec | super::FieldSized | super::ConstSized | diff --git a/src/librustc/traits/trans/mod.rs b/src/librustc/traits/trans/mod.rs new file mode 100644 index 000000000000..e38306aed2a9 --- /dev/null +++ b/src/librustc/traits/trans/mod.rs @@ -0,0 +1,212 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This file contains various trait resolution methods used by trans. +// They all assume regions can be erased and monomorphic types. It +// seems likely that they should eventually be merged into more +// general routines. + +use dep_graph::{DepGraph, DepNode, DepTrackingMap, DepTrackingMapConfig}; +use hir::def_id::DefId; +use infer::TransNormalize; +use std::cell::RefCell; +use std::marker::PhantomData; +use syntax::ast; +use syntax_pos::Span; +use traits::{FulfillmentContext, Obligation, ObligationCause, Reveal, SelectionContext, Vtable}; +use ty::{self, Ty, TyCtxt}; +use ty::subst::{Subst, Substs}; +use ty::fold::{TypeFoldable, TypeFolder}; +use util::common::MemoizationMap; + +impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { + /// Attempts to resolve an obligation to a vtable.. The result is + /// a shallow vtable resolution -- meaning that we do not + /// (necessarily) resolve all nested obligations on the impl. Note + /// that type check should guarantee to us that all nested + /// obligations *could be* resolved if we wanted to. + pub fn trans_fulfill_obligation(self, + span: Span, + trait_ref: ty::PolyTraitRef<'tcx>) + -> Vtable<'tcx, ()> + { + // Remove any references to regions; this helps improve caching. + let trait_ref = self.erase_regions(&trait_ref); + + self.trans_trait_caches.trait_cache.memoize(trait_ref, || { + debug!("trans::fulfill_obligation(trait_ref={:?}, def_id={:?})", + trait_ref, trait_ref.def_id()); + + // Do the initial selection for the obligation. This yields the + // shallow result we are looking for -- that is, what specific impl. + self.infer_ctxt((), Reveal::All).enter(|infcx| { + let mut selcx = SelectionContext::new(&infcx); + + let obligation_cause = ObligationCause::misc(span, + ast::DUMMY_NODE_ID); + let obligation = Obligation::new(obligation_cause, + trait_ref.to_poly_trait_predicate()); + + let selection = match selcx.select(&obligation) { + Ok(Some(selection)) => selection, + Ok(None) => { + // Ambiguity can happen when monomorphizing during trans + // expands to some humongo type that never occurred + // statically -- this humongo type can then overflow, + // leading to an ambiguous result. So report this as an + // overflow bug, since I believe this is the only case + // where ambiguity can result. + debug!("Encountered ambiguity selecting `{:?}` during trans, \ + presuming due to overflow", + trait_ref); + self.sess.span_fatal(span, + "reached the recursion limit during monomorphization \ + (selection ambiguity)"); + } + Err(e) => { + span_bug!(span, "Encountered error `{:?}` selecting `{:?}` during trans", + e, trait_ref) + } + }; + + debug!("fulfill_obligation: selection={:?}", selection); + + // Currently, we use a fulfillment context to completely resolve + // all nested obligations. This is because they can inform the + // inference of the impl's type parameters. + let mut fulfill_cx = FulfillmentContext::new(); + let vtable = selection.map(|predicate| { + debug!("fulfill_obligation: register_predicate_obligation {:?}", predicate); + fulfill_cx.register_predicate_obligation(&infcx, predicate); + }); + let vtable = infcx.drain_fulfillment_cx_or_panic(span, &mut fulfill_cx, &vtable); + + info!("Cache miss: {:?} => {:?}", trait_ref, vtable); + vtable + }) + }) + } + + /// Monomorphizes a type from the AST by first applying the in-scope + /// substitutions and then normalizing any associated types. + pub fn trans_apply_param_substs(self, + param_substs: &Substs<'tcx>, + value: &T) + -> T + where T: TransNormalize<'tcx> + { + debug!("apply_param_substs(param_substs={:?}, value={:?})", param_substs, value); + let substituted = value.subst(self, param_substs); + let substituted = self.erase_regions(&substituted); + AssociatedTypeNormalizer::new(self).fold(&substituted) + } +} + +struct AssociatedTypeNormalizer<'a, 'gcx: 'a> { + tcx: TyCtxt<'a, 'gcx, 'gcx>, +} + +impl<'a, 'gcx> AssociatedTypeNormalizer<'a, 'gcx> { + fn new(tcx: TyCtxt<'a, 'gcx, 'gcx>) -> Self { + AssociatedTypeNormalizer { tcx } + } + + fn fold>(&mut self, value: &T) -> T { + if !value.has_projection_types() { + value.clone() + } else { + value.fold_with(self) + } + } +} + +impl<'a, 'gcx> TypeFolder<'gcx, 'gcx> for AssociatedTypeNormalizer<'a, 'gcx> { + fn tcx<'c>(&'c self) -> TyCtxt<'c, 'gcx, 'gcx> { + self.tcx + } + + fn fold_ty(&mut self, ty: Ty<'gcx>) -> Ty<'gcx> { + if !ty.has_projection_types() { + ty + } else { + self.tcx.trans_trait_caches.project_cache.memoize(ty, || { + debug!("AssociatedTypeNormalizer: ty={:?}", ty); + self.tcx.normalize_associated_type(&ty) + }) + } + } +} + +/// Specializes caches used in trans -- in particular, they assume all +/// types are fully monomorphized and that free regions can be erased. +pub struct TransTraitCaches<'tcx> { + trait_cache: RefCell>>, + project_cache: RefCell>>, +} + +impl<'tcx> TransTraitCaches<'tcx> { + pub fn new(graph: DepGraph) -> Self { + TransTraitCaches { + trait_cache: RefCell::new(DepTrackingMap::new(graph.clone())), + project_cache: RefCell::new(DepTrackingMap::new(graph)), + } + } +} + +// Implement DepTrackingMapConfig for `trait_cache` +pub struct TraitSelectionCache<'tcx> { + data: PhantomData<&'tcx ()> +} + +impl<'tcx> DepTrackingMapConfig for TraitSelectionCache<'tcx> { + type Key = ty::PolyTraitRef<'tcx>; + type Value = Vtable<'tcx, ()>; + fn to_dep_node(key: &ty::PolyTraitRef<'tcx>) -> DepNode { + key.to_poly_trait_predicate().dep_node() + } +} + +// # Global Cache + +pub struct ProjectionCache<'gcx> { + data: PhantomData<&'gcx ()> +} + +impl<'gcx> DepTrackingMapConfig for ProjectionCache<'gcx> { + type Key = Ty<'gcx>; + type Value = Ty<'gcx>; + fn to_dep_node(key: &Self::Key) -> DepNode { + // Ideally, we'd just put `key` into the dep-node, but we + // can't put full types in there. So just collect up all the + // def-ids of structs/enums as well as any traits that we + // project out of. It doesn't matter so much what we do here, + // except that if we are too coarse, we'll create overly + // coarse edges between impls and the trans. For example, if + // we just used the def-id of things we are projecting out of, + // then the key for `::T` and `::T` would both share a dep-node + // (`TraitSelect(SomeTrait)`), and hence the impls for both + // `Foo` and `Bar` would be considered inputs. So a change to + // `Bar` would affect things that just normalized `Foo`. + // Anyway, this heuristic is not ideal, but better than + // nothing. + let def_ids: Vec = + key.walk() + .filter_map(|t| match t.sty { + ty::TyAdt(adt_def, _) => Some(adt_def.did), + ty::TyProjection(ref proj) => Some(proj.trait_ref.def_id), + _ => None, + }) + .collect(); + + DepNode::ProjectionCache { def_ids: def_ids } + } +} + diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index 602f27a64d4d..1d10c3a96950 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -13,6 +13,8 @@ use ty::subst::{Subst, Substs}; use ty::{self, Ty, TyCtxt, ToPredicate, ToPolyTraitRef}; use ty::outlives::Component; use util::nodemap::FxHashSet; +use hir::{self}; +use traits::specialize::specialization_graph::NodeItem; use super::{Obligation, ObligationCause, PredicateObligation, SelectionContext, Normalized}; @@ -42,7 +44,10 @@ fn anonymize_predicate<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, ty::Predicate::ObjectSafe(data), ty::Predicate::ClosureKind(closure_def_id, kind) => - ty::Predicate::ClosureKind(closure_def_id, kind) + ty::Predicate::ClosureKind(closure_def_id, kind), + + ty::Predicate::Subtype(ref data) => + ty::Predicate::Subtype(tcx.anonymize_late_bound_regions(data)), } } @@ -127,7 +132,7 @@ impl<'cx, 'gcx, 'tcx> Elaborator<'cx, 'gcx, 'tcx> { match *predicate { ty::Predicate::Trait(ref data) => { // Predicates declared on the trait. - let predicates = tcx.item_super_predicates(data.def_id()); + let predicates = tcx.super_predicates_of(data.def_id()); let mut predicates: Vec<_> = predicates.predicates @@ -160,6 +165,10 @@ impl<'cx, 'gcx, 'tcx> Elaborator<'cx, 'gcx, 'tcx> { // `X == Y`, though conceivably we might. For example, // `&X == &Y` implies that `X == Y`. } + ty::Predicate::Subtype(..) => { + // Currently, we do not "elaborate" predicates like `X + // <: Y`, though conceivably we might. + } ty::Predicate::Projection(..) => { // Nothing to elaborate in a projection predicate. } @@ -294,7 +303,7 @@ impl<'cx, 'gcx, 'tcx> Iterator for SupertraitDefIds<'cx, 'gcx, 'tcx> { None => { return None; } }; - let predicates = self.tcx.item_super_predicates(def_id); + let predicates = self.tcx.super_predicates_of(def_id); let visited = &mut self.visited; self.stack.extend( predicates.predicates @@ -361,7 +370,7 @@ pub fn impl_trait_ref_and_oblig<'a, 'gcx, 'tcx>(selcx: &mut SelectionContext<'a, let Normalized { value: impl_trait_ref, obligations: normalization_obligations1 } = super::normalize(selcx, ObligationCause::dummy(), &impl_trait_ref); - let predicates = selcx.tcx().item_predicates(impl_def_id); + let predicates = selcx.tcx().predicates_of(impl_def_id); let predicates = predicates.instantiate(selcx.tcx(), impl_substs); let Normalized { value: predicates, obligations: normalization_obligations2 } = super::normalize(selcx, ObligationCause::dummy(), &predicates); @@ -497,6 +506,30 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { }; ty::Binder((trait_ref, sig.skip_binder().output())) } + + pub fn impl_is_default(self, node_item_def_id: DefId) -> bool { + match self.hir.as_local_node_id(node_item_def_id) { + Some(node_id) => { + let item = self.hir.expect_item(node_id); + if let hir::ItemImpl(_, _, defaultness, ..) = item.node { + defaultness.is_default() + } else { + false + } + } + None => { + self.global_tcx() + .sess + .cstore + .impl_defaultness(node_item_def_id) + .is_default() + } + } + } + + pub fn impl_item_is_final(self, node_item: &NodeItem) -> bool { + node_item.item.is_final() && !self.impl_is_default(node_item.node.def_id()) + } } pub enum TupleArgumentsFlag { Yes, No } diff --git a/src/librustc/ty/_match.rs b/src/librustc/ty/_match.rs index b1846e039414..f86c1cf0dd6a 100644 --- a/src/librustc/ty/_match.rs +++ b/src/librustc/ty/_match.rs @@ -52,8 +52,8 @@ impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Match<'a, 'gcx, 'tcx> { self.relate(a, b) } - fn regions(&mut self, a: &'tcx ty::Region, b: &'tcx ty::Region) - -> RelateResult<'tcx, &'tcx ty::Region> { + fn regions(&mut self, a: ty::Region<'tcx>, b: ty::Region<'tcx>) + -> RelateResult<'tcx, ty::Region<'tcx>> { debug!("{}.regions({:?}, {:?})", self.tag(), a, diff --git a/src/librustc/ty/adjustment.rs b/src/librustc/ty/adjustment.rs index 34977822bc69..385591e10f74 100644 --- a/src/librustc/ty/adjustment.rs +++ b/src/librustc/ty/adjustment.rs @@ -33,7 +33,7 @@ pub enum Adjust<'tcx> { /// Go from a safe fn pointer to an unsafe fn pointer. UnsafeFnPointer, - // Go from a non-capturing closure to an fn pointer. + /// Go from a non-capturing closure to an fn pointer. ClosureFnPointer, /// Go from a mut raw pointer to a const raw pointer. @@ -133,12 +133,27 @@ impl<'tcx> Adjustment<'tcx> { #[derive(Copy, Clone, PartialEq, Debug, RustcEncodable, RustcDecodable)] pub enum AutoBorrow<'tcx> { /// Convert from T to &T. - Ref(&'tcx ty::Region, hir::Mutability), + Ref(ty::Region<'tcx>, hir::Mutability), /// Convert from T to *T. RawPtr(hir::Mutability), } +/// Information for `CoerceUnsized` impls, storing information we +/// have computed about the coercion. +/// +/// This struct can be obtained via the `coerce_impl_info` query. +/// Demanding this struct also has the side-effect of reporting errors +/// for inappropriate impls. +#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)] +pub struct CoerceUnsizedInfo { + /// If this is a "custom coerce" impl, then what kind of custom + /// coercion is it? This applies to impls of `CoerceUnsized` for + /// structs, primarily, where we store a bit of info about which + /// fields need to be coerced. + pub custom_kind: Option +} + #[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)] pub enum CustomCoerceUnsized { /// Records the index of the field being coerced. diff --git a/src/librustc/ty/contents.rs b/src/librustc/ty/contents.rs deleted file mode 100644 index e14295982916..000000000000 --- a/src/librustc/ty/contents.rs +++ /dev/null @@ -1,255 +0,0 @@ -// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use hir::def_id::{DefId}; -use ty::{self, Ty, TyCtxt}; -use util::common::MemoizationMap; -use util::nodemap::FxHashMap; - -use std::fmt; -use std::ops; - -use syntax::ast; - -/// Type contents is how the type checker reasons about kinds. -/// They track what kinds of things are found within a type. You can -/// think of them as kind of an "anti-kind". They track the kinds of values -/// and thinks that are contained in types. Having a larger contents for -/// a type tends to rule that type *out* from various kinds. For example, -/// a type that contains a reference is not sendable. -/// -/// The reason we compute type contents and not kinds is that it is -/// easier for me (nmatsakis) to think about what is contained within -/// a type than to think about what is *not* contained within a type. -#[derive(Clone, Copy)] -pub struct TypeContents { - pub bits: u64 -} - -macro_rules! def_type_content_sets { - (mod $mname:ident { $($name:ident = $bits:expr),+ }) => { - #[allow(non_snake_case)] - mod $mname { - use super::TypeContents; - $( - #[allow(non_upper_case_globals)] - pub const $name: TypeContents = TypeContents { bits: $bits }; - )+ - } - } -} - -def_type_content_sets! { - mod TC { - None = 0b0000_0000__0000_0000__0000, - - // Things that are interior to the value (first nibble): - InteriorUnsafe = 0b0000_0000__0000_0000__0010, - InteriorParam = 0b0000_0000__0000_0000__0100, - // InteriorAll = 0b00000000__00000000__1111, - - // Things that are owned by the value (second and third nibbles): - OwnsDtor = 0b0000_0000__0000_0010__0000, - // OwnsAll = 0b0000_0000__1111_1111__0000, - - // All bits - All = 0b1111_1111__1111_1111__1111 - } -} - -impl TypeContents { - pub fn when(&self, cond: bool) -> TypeContents { - if cond {*self} else {TC::None} - } - - pub fn intersects(&self, tc: TypeContents) -> bool { - (self.bits & tc.bits) != 0 - } - - pub fn interior_param(&self) -> bool { - self.intersects(TC::InteriorParam) - } - - pub fn interior_unsafe(&self) -> bool { - self.intersects(TC::InteriorUnsafe) - } - - pub fn needs_drop(&self, _: TyCtxt) -> bool { - self.intersects(TC::OwnsDtor) - } - - pub fn union(v: I, mut f: F) -> TypeContents where - I: IntoIterator, - F: FnMut(T) -> TypeContents, - { - v.into_iter().fold(TC::None, |tc, ty| tc | f(ty)) - } -} - -impl ops::BitOr for TypeContents { - type Output = TypeContents; - - fn bitor(self, other: TypeContents) -> TypeContents { - TypeContents {bits: self.bits | other.bits} - } -} - -impl ops::BitAnd for TypeContents { - type Output = TypeContents; - - fn bitand(self, other: TypeContents) -> TypeContents { - TypeContents {bits: self.bits & other.bits} - } -} - -impl ops::Sub for TypeContents { - type Output = TypeContents; - - fn sub(self, other: TypeContents) -> TypeContents { - TypeContents {bits: self.bits & !other.bits} - } -} - -impl fmt::Debug for TypeContents { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "TypeContents({:b})", self.bits) - } -} - -impl<'a, 'tcx> ty::TyS<'tcx> { - pub fn type_contents(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> TypeContents { - return tcx.tc_cache.memoize(self, || tc_ty(tcx, self, &mut FxHashMap())); - - fn tc_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - ty: Ty<'tcx>, - cache: &mut FxHashMap, TypeContents>) -> TypeContents - { - // Subtle: Note that we are *not* using tcx.tc_cache here but rather a - // private cache for this walk. This is needed in the case of cyclic - // types like: - // - // struct List { next: Box>, ... } - // - // When computing the type contents of such a type, we wind up deeply - // recursing as we go. So when we encounter the recursive reference - // to List, we temporarily use TC::None as its contents. Later we'll - // patch up the cache with the correct value, once we've computed it - // (this is basically a co-inductive process, if that helps). So in - // the end we'll compute TC::OwnsOwned, in this case. - // - // The problem is, as we are doing the computation, we will also - // compute an *intermediate* contents for, e.g., Option of - // TC::None. This is ok during the computation of List itself, but if - // we stored this intermediate value into tcx.tc_cache, then later - // requests for the contents of Option would also yield TC::None - // which is incorrect. This value was computed based on the crutch - // value for the type contents of list. The correct value is - // TC::OwnsOwned. This manifested as issue #4821. - if let Some(tc) = cache.get(&ty) { - return *tc; - } - // Must check both caches! - if let Some(tc) = tcx.tc_cache.borrow().get(&ty) { - return *tc; - } - cache.insert(ty, TC::None); - - let result = match ty.sty { - // usize and isize are ffi-unsafe - ty::TyUint(ast::UintTy::Us) | ty::TyInt(ast::IntTy::Is) => { - TC::None - } - - // Scalar and unique types are sendable, and durable - ty::TyInfer(ty::FreshIntTy(_)) | ty::TyInfer(ty::FreshFloatTy(_)) | - ty::TyBool | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) | ty::TyNever | - ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyChar => { - TC::None - } - - ty::TyDynamic(..) => { - TC::All - TC::InteriorParam - } - - ty::TyRawPtr(_) => { - TC::None - } - - ty::TyRef(..) => { - TC::None - } - - ty::TyArray(ty, _) => { - tc_ty(tcx, ty, cache) - } - - ty::TySlice(ty) => { - tc_ty(tcx, ty, cache) - } - ty::TyStr => TC::None, - - ty::TyClosure(def_id, ref substs) => { - TypeContents::union( - substs.upvar_tys(def_id, tcx), - |ty| tc_ty(tcx, &ty, cache)) - } - - ty::TyTuple(ref tys, _) => { - TypeContents::union(&tys[..], - |ty| tc_ty(tcx, *ty, cache)) - } - - ty::TyAdt(def, substs) => { - let mut res = - TypeContents::union(&def.variants, |v| { - TypeContents::union(&v.fields, |f| { - tc_ty(tcx, f.ty(tcx, substs), cache) - }) - }); - - if def.is_union() { - // unions don't have destructors regardless of the child types - res = res - TC::OwnsDtor; - } - - if def.has_dtor(tcx) { - res = res | TC::OwnsDtor; - } - - apply_lang_items(tcx, def.did, res) - } - - ty::TyProjection(..) | - ty::TyParam(_) | - ty::TyAnon(..) => { - TC::All - } - - ty::TyInfer(_) | - ty::TyError => { - bug!("asked to compute contents of error type"); - } - }; - - cache.insert(ty, result); - result - } - - fn apply_lang_items<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - did: DefId, tc: TypeContents) - -> TypeContents { - if Some(did) == tcx.lang_items.unsafe_cell_type() { - tc | TC::InteriorUnsafe - } else { - tc - } - } - } -} diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 5543223105b4..c782bea72f4b 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -15,16 +15,17 @@ use session::Session; use lint; use middle; use hir::TraitMap; -use hir::def::Def; +use hir::def::{Def, ExportMap}; use hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use hir::map as hir_map; use hir::map::DisambiguatedDefPathData; use middle::free_region::FreeRegionMap; use middle::lang_items; -use middle::region::RegionMaps; +use middle::region::{CodeExtent, CodeExtentData}; use middle::resolve_lifetime; use middle::stability; use mir::Mir; +use mir::transform::Passes; use ty::subst::{Kind, Substs}; use ty::ReprOptions; use traits; @@ -32,12 +33,14 @@ use ty::{self, TraitRef, Ty, TypeAndMut}; use ty::{TyS, TypeVariants, Slice}; use ty::{AdtKind, AdtDef, ClosureSubsts, Region}; use hir::FreevarMap; -use ty::{PolyFnSig, InferTy, ParamTy, ProjectionTy, ExistentialPredicate}; +use ty::{PolyFnSig, InferTy, ParamTy, ProjectionTy, ExistentialPredicate, Predicate}; +use ty::RegionKind; use ty::{TyVar, TyVid, IntVar, IntVid, FloatVar, FloatVid}; use ty::TypeVariants::*; use ty::layout::{Layout, TargetDataLayout}; use ty::inhabitedness::DefIdForest; use ty::maps; +use ty::steal::Steal; use util::nodemap::{NodeMap, NodeSet, DefIdMap, DefIdSet}; use util::nodemap::{FxHashMap, FxHashSet}; use rustc_data_structures::accumulate_vec::AccumulateVec; @@ -46,11 +49,12 @@ use arena::{TypedArena, DroplessArena}; use rustc_data_structures::indexed_vec::IndexVec; use std::borrow::Borrow; use std::cell::{Cell, RefCell}; +use std::cmp::Ordering; use std::hash::{Hash, Hasher}; use std::mem; use std::ops::Deref; use std::iter; -use std::cmp::Ordering; +use std::rc::Rc; use syntax::abi; use syntax::ast::{self, Name, NodeId}; use syntax::attr; @@ -67,7 +71,8 @@ pub struct GlobalArenas<'tcx> { generics: TypedArena, trait_def: TypedArena, adt_def: TypedArena, - mir: TypedArena>>, + steal_mir: TypedArena>>, + mir: TypedArena>, tables: TypedArena>, } @@ -78,6 +83,7 @@ impl<'tcx> GlobalArenas<'tcx> { generics: TypedArena::new(), trait_def: TypedArena::new(), adt_def: TypedArena::new(), + steal_mir: TypedArena::new(), mir: TypedArena::new(), tables: TypedArena::new(), } @@ -93,8 +99,9 @@ pub struct CtxtInterners<'tcx> { type_: RefCell>>>, type_list: RefCell>>>>, substs: RefCell>>>, - region: RefCell>>, + region: RefCell>>>, existential_predicates: RefCell>>>>, + predicates: RefCell>>>>, } impl<'gcx: 'tcx, 'tcx> CtxtInterners<'tcx> { @@ -106,6 +113,7 @@ impl<'gcx: 'tcx, 'tcx> CtxtInterners<'tcx> { substs: RefCell::new(FxHashSet()), region: RefCell::new(FxHashSet()), existential_predicates: RefCell::new(FxHashSet()), + predicates: RefCell::new(FxHashSet()), } } @@ -190,6 +198,10 @@ pub struct CommonTypes<'tcx> { pub f64: Ty<'tcx>, pub never: Ty<'tcx>, pub err: Ty<'tcx>, + + pub re_empty: Region<'tcx>, + pub re_static: Region<'tcx>, + pub re_erased: Region<'tcx>, } #[derive(RustcEncodable, RustcDecodable)] @@ -252,7 +264,7 @@ pub struct TypeckTables<'tcx> { /// Stores the free-region relationships that were deduced from /// its where clauses and parameter types. These are then /// read-again by borrowck. - pub free_region_map: FreeRegionMap, + pub free_region_map: FreeRegionMap<'tcx>, } impl<'tcx> TypeckTables<'tcx> { @@ -360,6 +372,14 @@ impl<'tcx> TypeckTables<'tcx> { impl<'tcx> CommonTypes<'tcx> { fn new(interners: &CtxtInterners<'tcx>) -> CommonTypes<'tcx> { let mk = |sty| interners.intern_ty(sty, None); + let mk_region = |r| { + if let Some(r) = interners.region.borrow().get(&r) { + return r.0; + } + let r = interners.arena.alloc(r); + interners.region.borrow_mut().insert(Interned(r)); + &*r + }; CommonTypes { bool: mk(TyBool), char: mk(TyChar), @@ -379,6 +399,10 @@ impl<'tcx> CommonTypes<'tcx> { u128: mk(TyUint(ast::UintTy::U128)), f32: mk(TyFloat(ast::FloatTy::F32)), f64: mk(TyFloat(ast::FloatTy::F64)), + + re_empty: mk_region(RegionKind::ReEmpty), + re_static: mk_region(RegionKind::ReStatic), + re_erased: mk_region(RegionKind::ReErased), } } } @@ -407,6 +431,8 @@ pub struct GlobalCtxt<'tcx> { pub specializes_cache: RefCell, + pub trans_trait_caches: traits::trans::TransTraitCaches<'tcx>, + pub dep_graph: DepGraph, /// Common types, pre-interned for your convenience. @@ -416,13 +442,17 @@ pub struct GlobalCtxt<'tcx> { /// is relevant; generated by resolve. pub trait_map: TraitMap, + /// Export map produced by name resolution. + pub export_map: ExportMap, + pub named_region_map: resolve_lifetime::NamedRegionMap, - pub region_maps: RegionMaps, - pub hir: hir_map::Map<'tcx>, + pub maps: maps::Maps<'tcx>, + pub mir_passes: Rc, + // Records the free variables refrenced by every closure // expression. Do not track deps for this, just recompute it from // scratch every time. @@ -433,9 +463,6 @@ pub struct GlobalCtxt<'tcx> { // Internal cache for metadata decoding. No need to track deps on this. pub rcache: RefCell>>, - // Cache for the type-contents routine. FIXME -- track deps? - pub tc_cache: RefCell, ty::contents::TypeContents>>, - // FIXME dep tracking -- should be harmless enough pub normalized_cache: RefCell, Ty<'tcx>>>, @@ -455,14 +482,6 @@ pub struct GlobalCtxt<'tcx> { /// about. pub used_mut_nodes: RefCell, - /// The set of external nominal types whose implementations have been read. - /// This is used for lazy resolution of methods. - pub populated_external_types: RefCell, - - /// The set of external primitive types whose implementations have been read. - /// FIXME(arielb1): why is this separate from populated_external_types? - pub populated_external_primitive_impls: RefCell, - /// Maps any item's def-id to its stability index. pub stability: RefCell>, @@ -532,14 +551,13 @@ pub struct GlobalCtxt<'tcx> { layout_interner: RefCell>, + code_extent_interner: RefCell>>, + /// A vector of every trait accessible in the whole crate /// (i.e. including those from subcrates). This is used only for /// error reporting, and so is lazily initialised and generally /// shouldn't taint the common path (hence the RefCell). pub all_traits: RefCell>>, - - /// HIR Ty -> Ty lowering cache. - pub ast_ty_to_ty_cache: RefCell>>, } impl<'tcx> GlobalCtxt<'tcx> { @@ -598,8 +616,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.global_arenas.generics.alloc(generics) } - pub fn alloc_mir(self, mir: Mir<'gcx>) -> &'gcx RefCell> { - self.global_arenas.mir.alloc(RefCell::new(mir)) + pub fn alloc_steal_mir(self, mir: Mir<'gcx>) -> &'gcx Steal> { + self.global_arenas.steal_mir.alloc(Steal::new(mir)) + } + + pub fn alloc_mir(self, mir: Mir<'gcx>) -> &'gcx Mir<'gcx> { + self.global_arenas.mir.alloc(mir) } pub fn alloc_tables(self, tables: ty::TypeckTables<'gcx>) -> &'gcx ty::TypeckTables<'gcx> { @@ -632,6 +654,32 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { interned } + pub fn node_extent(self, n: ast::NodeId) -> CodeExtent<'gcx> { + self.intern_code_extent(CodeExtentData::Misc(n)) + } + + // Returns the code extent for an item - the destruction scope. + pub fn item_extent(self, n: ast::NodeId) -> CodeExtent<'gcx> { + self.intern_code_extent(CodeExtentData::DestructionScope(n)) + } + + pub fn call_site_extent(self, fn_id: ast::NodeId, body_id: ast::NodeId) -> CodeExtent<'gcx> { + assert!(fn_id != body_id); + self.intern_code_extent(CodeExtentData::CallSiteScope { fn_id: fn_id, body_id: body_id }) + } + + pub fn intern_code_extent(self, data: CodeExtentData) -> CodeExtent<'gcx> { + if let Some(st) = self.code_extent_interner.borrow().get(&data) { + return st; + } + + let interned = self.global_interners.arena.alloc(data); + if let Some(prev) = self.code_extent_interner.borrow_mut().replace(interned) { + bug!("Tried to overwrite interned code-extent: {:?}", prev) + } + interned + } + pub fn intern_layout(self, layout: Layout) -> &'gcx Layout { if let Some(layout) = self.layout_interner.borrow().get(&layout) { return layout; @@ -667,12 +715,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn create_and_enter(s: &'tcx Session, local_providers: ty::maps::Providers<'tcx>, extern_providers: ty::maps::Providers<'tcx>, + mir_passes: Rc, arenas: &'tcx GlobalArenas<'tcx>, arena: &'tcx DroplessArena, resolutions: ty::Resolutions, named_region_map: resolve_lifetime::NamedRegionMap, hir: hir_map::Map<'tcx>, - region_maps: RegionMaps, lang_items: middle::lang_items::LanguageItems, stability: stability::Index<'tcx>, crate_name: &str, @@ -689,29 +737,28 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { providers[LOCAL_CRATE] = local_providers; tls::enter_global(GlobalCtxt { sess: s, + trans_trait_caches: traits::trans::TransTraitCaches::new(dep_graph.clone()), specializes_cache: RefCell::new(traits::SpecializesCache::new()), global_arenas: arenas, global_interners: interners, dep_graph: dep_graph.clone(), types: common_types, named_region_map: named_region_map, - region_maps: region_maps, variance_computed: Cell::new(false), trait_map: resolutions.trait_map, + export_map: resolutions.export_map, fulfilled_predicates: RefCell::new(fulfilled_predicates), hir: hir, maps: maps::Maps::new(dep_graph, providers), + mir_passes, freevars: RefCell::new(resolutions.freevars), maybe_unused_trait_imports: resolutions.maybe_unused_trait_imports, rcache: RefCell::new(FxHashMap()), - tc_cache: RefCell::new(FxHashMap()), normalized_cache: RefCell::new(FxHashMap()), inhabitedness_cache: RefCell::new(FxHashMap()), lang_items: lang_items, used_unsafe: RefCell::new(NodeSet()), used_mut_nodes: RefCell::new(NodeSet()), - populated_external_types: RefCell::new(DefIdSet()), - populated_external_primitive_impls: RefCell::new(DefIdSet()), stability: RefCell::new(stability), selection_cache: traits::SelectionCache::new(), evaluation_cache: traits::EvaluationCache::new(), @@ -721,13 +768,18 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { data_layout: data_layout, layout_cache: RefCell::new(FxHashMap()), layout_interner: RefCell::new(FxHashSet()), + code_extent_interner: RefCell::new(FxHashSet()), layout_depth: Cell::new(0), derive_macros: RefCell::new(NodeMap()), stability_interner: RefCell::new(FxHashSet()), all_traits: RefCell::new(None), - ast_ty_to_ty_cache: RefCell::new(NodeMap()), }, f) } + + pub fn consider_optimizing String>(&self, msg: T) -> bool { + let cname = self.crate_name(LOCAL_CRATE).as_str(); + self.sess.consider_optimizing(&cname, msg) + } } impl<'gcx: 'tcx, 'tcx> GlobalCtxt<'gcx> { @@ -795,9 +847,18 @@ impl<'a, 'tcx> Lift<'tcx> for &'a Substs<'a> { } } -impl<'a, 'tcx> Lift<'tcx> for &'a Region { - type Lifted = &'tcx Region; - fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<&'tcx Region> { +impl<'a, 'tcx> Lift<'tcx> for ty::FreeRegion<'a> { + type Lifted = ty::FreeRegion<'tcx>; + fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { + let scope = self.scope.map(|code_extent| tcx.intern_code_extent(*code_extent)); + let bound_region = self.bound_region; + Some(ty::FreeRegion { scope, bound_region }) + } +} + +impl<'a, 'tcx> Lift<'tcx> for Region<'a> { + type Lifted = Region<'tcx>; + fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option> { if tcx.interners.arena.in_arena(*self as *const _) { return Some(unsafe { mem::transmute(*self) }); } @@ -1058,9 +1119,9 @@ impl<'tcx: 'lcx, 'lcx> Borrow<[Kind<'lcx>]> for Interned<'tcx, Substs<'tcx>> { } } -impl<'tcx> Borrow for Interned<'tcx, Region> { - fn borrow<'a>(&'a self) -> &'a Region { - self.0 +impl<'tcx> Borrow> for Interned<'tcx, RegionKind<'tcx>> { + fn borrow<'a>(&'a self) -> &'a RegionKind<'tcx> { + &self.0 } } @@ -1071,6 +1132,13 @@ impl<'tcx: 'lcx, 'lcx> Borrow<[ExistentialPredicate<'lcx>]> } } +impl<'tcx: 'lcx, 'lcx> Borrow<[Predicate<'lcx>]> + for Interned<'tcx, Slice>> { + fn borrow<'a>(&'a self) -> &'a [Predicate<'lcx>] { + &self.0[..] + } +} + macro_rules! intern_method { ($lt_tcx:tt, $name:ident: $method:ident($alloc:ty, $alloc_method:ident, @@ -1151,7 +1219,7 @@ direct_interners!('tcx, &ty::ReVar(_) | &ty::ReSkolemized(..) => true, _ => false } - }) -> Region + }) -> RegionKind<'tcx> ); macro_rules! slice_interners { @@ -1165,6 +1233,7 @@ macro_rules! slice_interners { slice_interners!( existential_predicates: _intern_existential_predicates(ExistentialPredicate), + predicates: _intern_predicates(Predicate), type_list: _intern_type_list(Ty), substs: _intern_substs(Kind) ); @@ -1224,7 +1293,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } pub fn mk_static_str(self) -> Ty<'tcx> { - self.mk_imm_ref(self.mk_region(ty::ReStatic), self.mk_str()) + self.mk_imm_ref(self.types.re_static, self.mk_str()) } pub fn mk_adt(self, def: &'tcx AdtDef, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { @@ -1234,7 +1303,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn mk_box(self, ty: Ty<'tcx>) -> Ty<'tcx> { let def_id = self.require_lang_item(lang_items::OwnedBoxLangItem); - let adt_def = self.lookup_adt_def(def_id); + let adt_def = self.adt_def(def_id); let substs = self.mk_substs(iter::once(Kind::from(ty))); self.mk_ty(TyAdt(adt_def, substs)) } @@ -1243,15 +1312,15 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.mk_ty(TyRawPtr(tm)) } - pub fn mk_ref(self, r: &'tcx Region, tm: TypeAndMut<'tcx>) -> Ty<'tcx> { + pub fn mk_ref(self, r: Region<'tcx>, tm: TypeAndMut<'tcx>) -> Ty<'tcx> { self.mk_ty(TyRef(r, tm)) } - pub fn mk_mut_ref(self, r: &'tcx Region, ty: Ty<'tcx>) -> Ty<'tcx> { + pub fn mk_mut_ref(self, r: Region<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { self.mk_ref(r, TypeAndMut {ty: ty, mutbl: hir::MutMutable}) } - pub fn mk_imm_ref(self, r: &'tcx Region, ty: Ty<'tcx>) -> Ty<'tcx> { + pub fn mk_imm_ref(self, r: Region<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { self.mk_ref(r, TypeAndMut {ty: ty, mutbl: hir::MutImmutable}) } @@ -1313,7 +1382,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn mk_dynamic( self, obj: ty::Binder<&'tcx Slice>>, - reg: &'tcx ty::Region + reg: ty::Region<'tcx> ) -> Ty<'tcx> { self.mk_ty(TyDynamic(obj, reg)) } @@ -1384,6 +1453,19 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self._intern_existential_predicates(eps) } + pub fn intern_predicates(self, preds: &[Predicate<'tcx>]) + -> &'tcx Slice> { + // FIXME consider asking the input slice to be sorted to avoid + // re-interning permutations, in which case that would be asserted + // here. + if preds.len() == 0 { + // The macro-generated method below asserts we don't intern an empty slice. + Slice::empty() + } else { + self._intern_predicates(preds) + } + } + pub fn intern_type_list(self, ts: &[Ty<'tcx>]) -> &'tcx Slice> { if ts.len() == 0 { Slice::empty() @@ -1422,6 +1504,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { iter.intern_with(|xs| self.intern_existential_predicates(xs)) } + pub fn mk_predicates], + &'tcx Slice>>>(self, iter: I) + -> I::Output { + iter.intern_with(|xs| self.intern_predicates(xs)) + } + pub fn mk_type_list], &'tcx Slice>>>(self, iter: I) -> I::Output { iter.intern_with(|xs| self.intern_type_list(xs)) @@ -1443,7 +1531,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub trait InternAs { type Output; - fn intern_with(self, F) -> Self::Output + fn intern_with(self, f: F) -> Self::Output where F: FnOnce(&T) -> R; } diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index 5a696446b4bb..d6804976e84c 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -36,11 +36,11 @@ pub enum TypeError<'tcx> { TupleSize(ExpectedFound), FixedArraySize(ExpectedFound), ArgCount, - RegionsDoesNotOutlive(&'tcx Region, &'tcx Region), - RegionsNotSame(&'tcx Region, &'tcx Region), - RegionsNoOverlap(&'tcx Region, &'tcx Region), - RegionsInsufficientlyPolymorphic(BoundRegion, &'tcx Region), - RegionsOverlyPolymorphic(BoundRegion, &'tcx Region), + RegionsDoesNotOutlive(Region<'tcx>, Region<'tcx>), + RegionsNotSame(Region<'tcx>, Region<'tcx>), + RegionsNoOverlap(Region<'tcx>, Region<'tcx>), + RegionsInsufficientlyPolymorphic(BoundRegion, Region<'tcx>, Option>), + RegionsOverlyPolymorphic(BoundRegion, Region<'tcx>, Option>), Sorts(ExpectedFound>), IntMismatch(ExpectedFound), FloatMismatch(ExpectedFound), @@ -116,13 +116,17 @@ impl<'tcx> fmt::Display for TypeError<'tcx> { RegionsNoOverlap(..) => { write!(f, "lifetimes do not intersect") } - RegionsInsufficientlyPolymorphic(br, _) => { - write!(f, "expected bound lifetime parameter {}, \ - found concrete lifetime", br) + 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 {}", br) + RegionsOverlyPolymorphic(br, _, _) => { + write!(f, + "expected concrete lifetime, found bound lifetime parameter{}{}", + if br.is_named() { " " } else { "" }, + br) } Sorts(values) => ty::tls::with(|tcx| { report_maybe_different(f, values.expected.sort_string(tcx), @@ -253,15 +257,15 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.note_and_explain_region(db, "...does not overlap ", region2, ""); } - RegionsInsufficientlyPolymorphic(_, conc_region) => { + RegionsInsufficientlyPolymorphic(_, conc_region, _) => { self.note_and_explain_region(db, "concrete lifetime that was found is ", conc_region, ""); } - RegionsOverlyPolymorphic(_, &ty::ReVar(_)) => { + RegionsOverlyPolymorphic(_, &ty::ReVar(_), _) => { // don't bother to print out the message below for // inference variables, it's not very illuminating. } - RegionsOverlyPolymorphic(_, conc_region) => { + RegionsOverlyPolymorphic(_, conc_region, _) => { self.note_and_explain_region(db, "expected concrete lifetime is ", conc_region, ""); } diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index 384f99ceb4e8..686b99ba6809 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -186,7 +186,7 @@ impl FlagComputation { self.add_bound_computation(&computation); } - fn add_region(&mut self, r: &ty::Region) { + fn add_region(&mut self, r: ty::Region) { self.add_flags(r.type_flags()); if let ty::ReLateBound(debruijn, _) = *r { self.add_depth(debruijn.depth); diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index e29653c9e88a..21ccf6f987b8 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -159,7 +159,7 @@ pub trait TypeFolder<'gcx: 'tcx, 'tcx> : Sized { sig.super_fold_with(self) } - fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region { + fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { r.super_fold_with(self) } @@ -182,7 +182,7 @@ pub trait TypeVisitor<'tcx> : Sized { trait_ref.super_visit_with(self) } - fn visit_region(&mut self, r: &'tcx ty::Region) -> bool { + fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { r.super_visit_with(self) } } @@ -216,7 +216,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// whether any late-bound regions were skipped pub fn collect_regions(self, value: &T, - region_set: &mut FxHashSet<&'tcx ty::Region>) + region_set: &mut FxHashSet>) -> bool where T : TypeFoldable<'tcx> { @@ -236,7 +236,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { skipped_regions: &mut bool, mut f: F) -> T - where F : FnMut(&'tcx ty::Region, u32) -> &'tcx ty::Region, + where F : FnMut(ty::Region<'tcx>, u32) -> ty::Region<'tcx>, T : TypeFoldable<'tcx>, { value.fold_with(&mut RegionFolder::new(self, skipped_regions, &mut f)) @@ -256,14 +256,14 @@ pub struct RegionFolder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { tcx: TyCtxt<'a, 'gcx, 'tcx>, skipped_regions: &'a mut bool, current_depth: u32, - fld_r: &'a mut (FnMut(&'tcx ty::Region, u32) -> &'tcx ty::Region + 'a), + fld_r: &'a mut (FnMut(ty::Region<'tcx>, u32) -> ty::Region<'tcx> + 'a), } impl<'a, 'gcx, 'tcx> RegionFolder<'a, 'gcx, 'tcx> { pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>, skipped_regions: &'a mut bool, fld_r: &'a mut F) -> RegionFolder<'a, 'gcx, 'tcx> - where F : FnMut(&'tcx ty::Region, u32) -> &'tcx ty::Region + where F : FnMut(ty::Region<'tcx>, u32) -> ty::Region<'tcx> { RegionFolder { tcx: tcx, @@ -284,7 +284,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionFolder<'a, 'gcx, 'tcx> { t } - fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region { + fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { match *r { ty::ReLateBound(debruijn, _) if debruijn.depth < self.current_depth => { debug!("RegionFolder.fold_region({:?}) skipped bound region (current depth={})", @@ -309,16 +309,16 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionFolder<'a, 'gcx, 'tcx> { struct RegionReplacer<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { tcx: TyCtxt<'a, 'gcx, 'tcx>, current_depth: u32, - fld_r: &'a mut (FnMut(ty::BoundRegion) -> &'tcx ty::Region + 'a), - map: FxHashMap + fld_r: &'a mut (FnMut(ty::BoundRegion) -> ty::Region<'tcx> + 'a), + map: FxHashMap> } impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn replace_late_bound_regions(self, value: &Binder, mut f: F) - -> (T, FxHashMap) - where F : FnMut(ty::BoundRegion) -> &'tcx ty::Region, + -> (T, FxHashMap>) + where F : FnMut(ty::BoundRegion) -> ty::Region<'tcx>, T : TypeFoldable<'tcx>, { let mut replacer = RegionReplacer::new(self, &mut f); @@ -330,7 +330,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// Replace any late-bound regions bound in `value` with free variants attached to scope-id /// `scope_id`. pub fn liberate_late_bound_regions(self, - all_outlive_scope: region::CodeExtent, + all_outlive_scope: Option>, value: &Binder) -> T where T : TypeFoldable<'tcx> @@ -410,7 +410,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn erase_late_bound_regions(self, value: &Binder) -> T where T : TypeFoldable<'tcx> { - self.replace_late_bound_regions(value, |_| self.mk_region(ty::ReErased)).0 + self.replace_late_bound_regions(value, |_| self.types.re_erased).0 } /// Rewrite any late-bound regions so that they are anonymous. Region numbers are @@ -435,7 +435,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { impl<'a, 'gcx, 'tcx> RegionReplacer<'a, 'gcx, 'tcx> { fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>, fld_r: &'a mut F) -> RegionReplacer<'a, 'gcx, 'tcx> - where F : FnMut(ty::BoundRegion) -> &'tcx ty::Region + where F : FnMut(ty::BoundRegion) -> ty::Region<'tcx> { RegionReplacer { tcx: tcx, @@ -464,7 +464,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionReplacer<'a, 'gcx, 'tcx> { t.super_fold_with(self) } - fn fold_region(&mut self, r:&'tcx ty::Region) -> &'tcx ty::Region { + fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { match *r { ty::ReLateBound(debruijn, br) if debruijn.depth == self.current_depth => { let fld_r = &mut self.fld_r; @@ -527,7 +527,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { u.super_fold_with(self) } - fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region { + fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { // because late-bound regions affect subtyping, we can't // erase the bound/free distinction, but we can replace // all free regions with 'erased. @@ -538,7 +538,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // whenever a substitution occurs. match *r { ty::ReLateBound(..) => r, - _ => self.tcx().mk_region(ty::ReErased) + _ => self.tcx().types.re_erased } } } @@ -554,7 +554,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // regions. See comment on `shift_regions_through_binders` method in // `subst.rs` for more details. -pub fn shift_region(region: ty::Region, amount: u32) -> ty::Region { +pub fn shift_region<'tcx>(region: ty::RegionKind<'tcx>, amount: u32) -> ty::RegionKind<'tcx> { match region { ty::ReLateBound(debruijn, br) => { ty::ReLateBound(debruijn.shifted(amount), br) @@ -565,15 +565,32 @@ pub fn shift_region(region: ty::Region, amount: u32) -> ty::Region { } } +pub fn shift_region_ref<'a, 'gcx, 'tcx>( + tcx: TyCtxt<'a, 'gcx, 'tcx>, + region: ty::Region<'tcx>, + amount: u32) + -> ty::Region<'tcx> +{ + match region { + &ty::ReLateBound(debruijn, br) if amount > 0 => { + tcx.mk_region(ty::ReLateBound(debruijn.shifted(amount), br)) + } + _ => { + region + } + } +} + pub fn shift_regions<'a, 'gcx, 'tcx, T>(tcx: TyCtxt<'a, 'gcx, 'tcx>, - amount: u32, value: &T) -> T + amount: u32, + value: &T) -> T where T: TypeFoldable<'tcx> { debug!("shift_regions(value={:?}, amount={})", value, amount); value.fold_with(&mut RegionFolder::new(tcx, &mut false, &mut |region, _current_depth| { - tcx.mk_region(shift_region(*region, amount)) + shift_region_ref(tcx, region, amount) })) } @@ -615,7 +632,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasEscapingRegionsVisitor { t.region_depth > self.depth } - fn visit_region(&mut self, r: &'tcx ty::Region) -> bool { + fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { r.escapes_depth(self.depth) } } @@ -631,7 +648,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { flags.intersects(self.flags) } - fn visit_region(&mut self, r: &'tcx ty::Region) -> bool { + fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { let flags = r.type_flags(); debug!("HasTypeFlagsVisitor: r={:?} r.flags={:?} self.flags={:?}", r, flags, self.flags); flags.intersects(self.flags) @@ -677,7 +694,7 @@ impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector { t.super_visit_with(self) } - fn visit_region(&mut self, r: &'tcx ty::Region) -> bool { + fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { match *r { ty::ReLateBound(debruijn, br) if debruijn.depth == self.current_depth => { self.regions.insert(br); diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index 67287f1b4ff7..7dca28df9da3 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -13,10 +13,7 @@ use hir::def_id::DefId; use ty::{self, Ty, TypeFoldable, Substs}; use util::ppaux; -use std::borrow::Cow; use std::fmt; -use syntax::ast; - #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub struct Instance<'tcx> { @@ -55,11 +52,11 @@ impl<'tcx> InstanceDef<'tcx> { #[inline] pub fn def_ty<'a>(&self, tcx: ty::TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx> { - tcx.item_type(self.def_id()) + tcx.type_of(self.def_id()) } #[inline] - pub fn attrs<'a>(&self, tcx: ty::TyCtxt<'a, 'tcx, 'tcx>) -> Cow<'tcx, [ast::Attribute]> { + pub fn attrs<'a>(&self, tcx: ty::TyCtxt<'a, 'tcx, 'tcx>) -> ty::Attributes<'tcx> { tcx.get_attrs(self.def_id()) } diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs index 874e032bc464..16d5d1187fc8 100644 --- a/src/librustc/ty/item_path.rs +++ b/src/librustc/ty/item_path.rs @@ -13,16 +13,19 @@ use hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use ty::{self, Ty, TyCtxt}; use syntax::ast; use syntax::symbol::Symbol; +use syntax_pos::DUMMY_SP; use std::cell::Cell; thread_local! { - static FORCE_ABSOLUTE: Cell = Cell::new(false) + static FORCE_ABSOLUTE: Cell = Cell::new(false); + static FORCE_IMPL_FILENAME_LINE: Cell = Cell::new(false); } -/// Enforces that item_path_str always returns an absolute path. -/// This is useful when building symbols that contain types, -/// where we want the crate name to be part of the symbol. +/// Enforces that item_path_str always returns an absolute path and +/// also enables "type-based" impl paths. This is used when building +/// symbols that contain types, where we want the crate name to be +/// part of the symbol. pub fn with_forced_absolute_paths R, R>(f: F) -> R { FORCE_ABSOLUTE.with(|force| { let old = force.get(); @@ -33,6 +36,20 @@ pub fn with_forced_absolute_paths R, R>(f: F) -> R { }) } +/// Force us to name impls with just the filename/line number. We +/// normally try to use types. But at some points, notably while printing +/// cycle errors, this can result in extra or suboptimal error output, +/// so this variable disables that check. +pub fn with_forced_impl_filename_line R, R>(f: F) -> R { + FORCE_IMPL_FILENAME_LINE.with(|force| { + let old = force.get(); + force.set(true); + let result = f(); + force.set(old); + result + }) +} + impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// Returns a string identifying this def-id. This string is /// suitable for user output. It is relative to the current crate @@ -175,7 +192,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { data @ DefPathData::LifetimeDef(..) | data @ DefPathData::EnumVariant(..) | data @ DefPathData::Field(..) | - data @ DefPathData::StructCtor | data @ DefPathData::Initializer | data @ DefPathData::MacroDef(..) | data @ DefPathData::ClosureExpr | @@ -186,6 +202,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.push_item_path(buffer, parent_def_id); buffer.push(&data.as_interned_str()); } + DefPathData::StructCtor => { // present `X` instead of `X::{{constructor}}` + let parent_def_id = self.parent_def_id(def_id).unwrap(); + self.push_item_path(buffer, parent_def_id); + } } } @@ -196,13 +216,16 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { { let parent_def_id = self.parent_def_id(impl_def_id).unwrap(); - let use_types = if !impl_def_id.is_local() { - // always have full types available for extern crates - true - } else { - // for local crates, check whether type info is - // available; typeck might not have completed yet - self.maps.impl_trait_ref.borrow().contains_key(&impl_def_id) + // Always use types for non-local impls, where types are always + // available, and filename/line-number is mostly uninteresting. + let use_types = !impl_def_id.is_local() || { + // Otherwise, use filename/line-number if forced. + let force_no_types = FORCE_IMPL_FILENAME_LINE.with(|f| f.get()); + !force_no_types && { + // Otherwise, use types if we can query them without inducing a cycle. + ty::queries::impl_trait_ref::try_get(self, DUMMY_SP, impl_def_id).is_ok() && + ty::queries::type_of::try_get(self, DUMMY_SP, impl_def_id).is_ok() + } }; if !use_types { @@ -214,7 +237,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // users may find it useful. Currently, we omit the parent if // the impl is either in the same module as the self-type or // as the trait. - let self_ty = self.item_type(impl_def_id); + let self_ty = self.type_of(impl_def_id); let in_self_mod = match characteristic_def_id_of_type(self_ty) { None => false, Some(ty_def_id) => self.parent_def_id(ty_def_id) == Some(parent_def_id), diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 123db6e89476..480b8967a79e 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -15,7 +15,7 @@ pub use self::Primitive::*; use infer::InferCtxt; use session::Session; use traits; -use ty::{self, Ty, TyCtxt, TypeFoldable, ReprOptions}; +use ty::{self, Ty, TyCtxt, TypeFoldable, ReprOptions, ReprFlags}; use syntax::ast::{FloatTy, IntTy, UintTy}; use syntax::attr; @@ -25,6 +25,7 @@ use std::cmp; use std::fmt; use std::i64; use std::iter; +use std::ops::Deref; /// Parsed [Data layout](http://llvm.org/docs/LangRef.html#data-layout) /// for a target, which contains everything needed to compute layouts. @@ -201,6 +202,16 @@ impl TargetDataLayout { } } +pub trait HasDataLayout: Copy { + fn data_layout(&self) -> &TargetDataLayout; +} + +impl<'a> HasDataLayout for &'a TargetDataLayout { + fn data_layout(&self) -> &TargetDataLayout { + self + } +} + /// Endianness of the target, which must match cfg(target-endian). #[derive(Copy, Clone)] pub enum Endian { @@ -241,7 +252,9 @@ impl Size { Size::from_bytes((self.bytes() + mask) & !mask) } - pub fn checked_add(self, offset: Size, dl: &TargetDataLayout) -> Option { + pub fn checked_add(self, offset: Size, cx: C) -> Option { + let dl = cx.data_layout(); + // Each Size is less than dl.obj_size_bound(), so the sum is // also less than 1 << 62 (and therefore can't overflow). let bytes = self.bytes() + offset.bytes(); @@ -253,7 +266,9 @@ impl Size { } } - pub fn checked_mul(self, count: u64, dl: &TargetDataLayout) -> Option { + pub fn checked_mul(self, count: u64, cx: C) -> Option { + let dl = cx.data_layout(); + // Each Size is less than dl.obj_size_bound(), so the sum is // also less than 1 << 62 (and therefore can't overflow). match self.bytes().checked_mul(count) { @@ -267,7 +282,7 @@ impl Size { /// Alignment of a type in bytes, both ABI-mandated and preferred. /// Since alignments are always powers of 2, we can pack both in one byte, -/// giving each a nibble (4 bits) for a maximum alignment of 2^15 = 32768. +/// giving each a nibble (4 bits) for a maximum alignment of 215 = 32768. #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub struct Align { raw: u8 @@ -353,7 +368,9 @@ impl Integer { } } - pub fn align(&self, dl: &TargetDataLayout)-> Align { + pub fn align(&self, cx: C) -> Align { + let dl = cx.data_layout(); + match *self { I1 => dl.i1_align, I8 => dl.i8_align, @@ -407,7 +424,9 @@ impl Integer { } /// Find the smallest integer with the given alignment. - pub fn for_abi_align(dl: &TargetDataLayout, align: Align) -> Option { + pub fn for_abi_align(cx: C, align: Align) -> Option { + let dl = cx.data_layout(); + let wanted = align.abi(); for &candidate in &[I8, I16, I32, I64] { let ty = Int(candidate); @@ -419,7 +438,9 @@ impl Integer { } /// Get the Integer type from an attr::IntType. - pub fn from_attr(dl: &TargetDataLayout, ity: attr::IntType) -> Integer { + pub fn from_attr(cx: C, ity: attr::IntType) -> Integer { + let dl = cx.data_layout(); + match ity { attr::SignedInt(IntTy::I8) | attr::UnsignedInt(UintTy::U8) => I8, attr::SignedInt(IntTy::I16) | attr::UnsignedInt(UintTy::U16) => I16, @@ -449,7 +470,7 @@ impl Integer { let min_default = I8; if let Some(ity) = repr.int { - let discr = Integer::from_attr(&tcx.data_layout, ity); + let discr = Integer::from_attr(tcx, ity); let fit = if ity.is_signed() { signed_fit } else { unsigned_fit }; if discr < fit { bug!("Integer::repr_discr: `#[repr]` hint too small for \ @@ -458,7 +479,7 @@ impl Integer { return (discr, ity.is_signed()); } - if repr.c { + if repr.c() { match &tcx.sess.target.target.arch[..] { // WARNING: the ARM EABI has two variants; the one corresponding // to `at_least == I32` appears to be used on Linux and NetBSD, @@ -490,7 +511,9 @@ pub enum Primitive { } impl Primitive { - pub fn size(self, dl: &TargetDataLayout) -> Size { + pub fn size(self, cx: C) -> Size { + let dl = cx.data_layout(); + match self { Int(I1) | Int(I8) => Size::from_bits(8), Int(I16) => Size::from_bits(16), @@ -501,7 +524,9 @@ impl Primitive { } } - pub fn align(self, dl: &TargetDataLayout) -> Align { + pub fn align(self, cx: C) -> Align { + let dl = cx.data_layout(); + match self { Int(I1) => dl.i1_align, Int(I8) => dl.i8_align, @@ -523,8 +548,12 @@ pub type FieldPath = Vec; /// A structure, a product type in ADT terms. #[derive(PartialEq, Eq, Hash, Debug)] pub struct Struct { + /// Maximum alignment of fields and repr alignment. pub align: Align, + /// Primitive alignment of fields without repr alignment. + pub primitive_align: Align, + /// If true, no alignment padding is used. pub packed: bool, @@ -555,14 +584,23 @@ enum StructKind { } impl<'a, 'gcx, 'tcx> Struct { - // FIXME(camlorn): reprs need a better representation to deal with multiple reprs on one type. fn new(dl: &TargetDataLayout, fields: &Vec<&'a Layout>, repr: &ReprOptions, kind: StructKind, scapegoat: Ty<'gcx>) -> Result> { - let packed = repr.packed; + if repr.packed() && repr.align > 0 { + bug!("Struct cannot be packed and aligned"); + } + + let align = if repr.packed() { + dl.i8_align + } else { + dl.aggregate_align + }; + let mut ret = Struct { - align: if packed { dl.i8_align } else { dl.aggregate_align }, - packed: packed, + align: align, + primitive_align: align, + packed: repr.packed(), sized: true, offsets: vec![], memory_index: vec![], @@ -573,12 +611,8 @@ impl<'a, 'gcx, 'tcx> Struct { // Neither do 1-member and 2-member structs. // In addition, code in trans assume that 2-element structs can become pairs. // It's easier to just short-circuit here. - let mut can_optimize = (fields.len() > 2 || StructKind::EnumVariant == kind) - && ! (repr.c || repr.packed); - - // Disable field reordering until we can decide what to do. - // The odd pattern here avoids a warning about the value never being read. - if can_optimize { can_optimize = false; } + let can_optimize = (fields.len() > 2 || StructKind::EnumVariant == kind) + && (repr.flags & ReprFlags::IS_UNOPTIMISABLE).is_empty(); let (optimize, sort_ascending) = match kind { StructKind::AlwaysSizedUnivariant => (can_optimize, false), @@ -640,7 +674,9 @@ impl<'a, 'gcx, 'tcx> Struct { // Invariant: offset < dl.obj_size_bound() <= 1<<61 if !ret.packed { let align = field.align(dl); + let primitive_align = field.primitive_align(dl); ret.align = ret.align.max(align); + ret.primitive_align = ret.primitive_align.max(primitive_align); offset = offset.abi_align(align); } @@ -651,6 +687,11 @@ impl<'a, 'gcx, 'tcx> Struct { .map_or(Err(LayoutError::SizeOverflow(scapegoat)), Ok)?; } + if repr.align > 0 { + let repr_align = repr.align as u64; + ret.align = ret.align.max(Align::from_bytes(repr_align, repr_align).unwrap()); + debug!("Struct::new repr_align: {:?}", repr_align); + } debug!("Struct::new min_size: {:?}", offset); ret.min_size = offset; @@ -681,8 +722,8 @@ impl<'a, 'gcx, 'tcx> Struct { } /// Determine whether a structure would be zero-sized, given its fields. - pub fn would_be_zero_sized(dl: &TargetDataLayout, fields: I) - -> Result> + fn would_be_zero_sized(dl: &TargetDataLayout, fields: I) + -> Result> where I: Iterator>> { for field in fields { let field = field?; @@ -781,7 +822,7 @@ impl<'a, 'gcx, 'tcx> Struct { } (_, &ty::TyProjection(_)) | (_, &ty::TyAnon(..)) => { - let normalized = normalize_associated_type(infcx, ty); + let normalized = infcx.normalize_projections(ty); if ty == normalized { return Ok(None); } @@ -816,12 +857,23 @@ impl<'a, 'gcx, 'tcx> Struct { } Ok(None) } + + pub fn over_align(&self) -> Option { + let align = self.align.abi(); + let primitive_align = self.primitive_align.abi(); + if align > primitive_align { + Some(align as u32) + } else { + None + } + } } /// An untagged union. #[derive(PartialEq, Eq, Hash, Debug)] pub struct Union { pub align: Align, + pub primitive_align: Align, pub min_size: Size, @@ -830,19 +882,21 @@ pub struct Union { } impl<'a, 'gcx, 'tcx> Union { - pub fn new(dl: &TargetDataLayout, packed: bool) -> Union { + fn new(dl: &TargetDataLayout, packed: bool) -> Union { + let align = if packed { dl.i8_align } else { dl.aggregate_align }; Union { - align: if packed { dl.i8_align } else { dl.aggregate_align }, + align: align, + primitive_align: align, min_size: Size::from_bytes(0), packed: packed, } } /// Extend the Struct with more fields. - pub fn extend(&mut self, dl: &TargetDataLayout, - fields: I, - scapegoat: Ty<'gcx>) - -> Result<(), LayoutError<'gcx>> + fn extend(&mut self, dl: &TargetDataLayout, + fields: I, + scapegoat: Ty<'gcx>) + -> Result<(), LayoutError<'gcx>> where I: Iterator>> { for (index, field) in fields.enumerate() { let field = field?; @@ -855,6 +909,7 @@ impl<'a, 'gcx, 'tcx> Union { if !self.packed { self.align = self.align.max(field.align(dl)); + self.primitive_align = self.primitive_align.max(field.primitive_align(dl)); } self.min_size = cmp::max(self.min_size, field.size(dl)); } @@ -868,6 +923,16 @@ impl<'a, 'gcx, 'tcx> Union { pub fn stride(&self) -> Size { self.min_size.abi_align(self.align) } + + pub fn over_align(&self) -> Option { + let align = self.align.abi(); + let primitive_align = self.primitive_align.abi(); + if align > primitive_align { + Some(align as u32) + } else { + None + } + } } /// The first half of a fat pointer. @@ -904,7 +969,9 @@ pub enum Layout { /// If true, the size is exact, otherwise it's only a lower bound. sized: bool, align: Align, - size: Size + primitive_align: Align, + element_size: Size, + count: u64 }, /// TyRawPtr or TyRef with a !Sized pointee. @@ -949,7 +1016,8 @@ pub enum Layout { discr: Integer, variants: Vec, size: Size, - align: Align + align: Align, + primitive_align: Align, }, /// Two cases distinguished by a nullable pointer: the case with discriminant @@ -999,28 +1067,6 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> { } } -/// Helper function for normalizing associated types in an inference context. -fn normalize_associated_type<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, - ty: Ty<'gcx>) - -> Ty<'gcx> { - if !ty.has_projection_types() { - return ty; - } - - let mut selcx = traits::SelectionContext::new(infcx); - let cause = traits::ObligationCause::dummy(); - let traits::Normalized { value: result, obligations } = - traits::normalize(&mut selcx, cause, &ty); - - let mut fulfill_cx = traits::FulfillmentContext::new(); - - for obligation in obligations { - fulfill_cx.register_predicate_obligation(infcx, obligation); - } - - infcx.drain_fulfillment_cx_or_panic(DUMMY_SP, &mut fulfill_cx, &result) -} - impl<'a, 'gcx, 'tcx> Layout { pub fn compute_uncached(ty: Ty<'gcx>, infcx: &InferCtxt<'a, 'gcx, 'tcx>) @@ -1032,7 +1078,7 @@ impl<'a, 'gcx, 'tcx> Layout { let ptr_layout = |pointee: Ty<'gcx>| { let non_zero = !ty.is_unsafe_ptr(); - let pointee = normalize_associated_type(infcx, pointee); + let pointee = infcx.normalize_projections(pointee); if pointee.is_sized(tcx, &infcx.parameter_environment, DUMMY_SP) { Ok(Scalar { value: Pointer, non_zero: non_zero }) } else { @@ -1087,25 +1133,38 @@ impl<'a, 'gcx, 'tcx> Layout { // Arrays and slices. ty::TyArray(element, count) => { let element = element.layout(infcx)?; + let element_size = element.size(dl); + // FIXME(eddyb) Don't use host `usize` for array lengths. + let usize_count: usize = count; + let count = usize_count as u64; + if element_size.checked_mul(count, dl).is_none() { + return Err(LayoutError::SizeOverflow(ty)); + } Array { sized: true, align: element.align(dl), - size: element.size(dl).checked_mul(count as u64, dl) - .map_or(Err(LayoutError::SizeOverflow(ty)), Ok)? + primitive_align: element.primitive_align(dl), + element_size: element_size, + count: count } } ty::TySlice(element) => { + let element = element.layout(infcx)?; Array { sized: false, - align: element.layout(infcx)?.align(dl), - size: Size::from_bytes(0) + align: element.align(dl), + primitive_align: element.primitive_align(dl), + element_size: element.size(dl), + count: 0 } } ty::TyStr => { Array { sized: false, align: dl.i8_align, - size: Size::from_bytes(0) + primitive_align: dl.i8_align, + element_size: Size::from_bytes(1), + count: 0 } } @@ -1146,7 +1205,7 @@ impl<'a, 'gcx, 'tcx> Layout { } // SIMD vector types. - ty::TyAdt(def, ..) if def.repr.simd => { + ty::TyAdt(def, ..) if def.repr.simd() => { let element = ty.simd_type(tcx); match *element.layout(infcx)? { Scalar { value, .. } => { @@ -1209,9 +1268,8 @@ impl<'a, 'gcx, 'tcx> Layout { let kind = if def.is_enum() || def.variants[0].fields.len() == 0{ StructKind::AlwaysSizedUnivariant } else { - use middle::region::ROOT_CODE_EXTENT; let param_env = tcx.construct_parameter_environment(DUMMY_SP, - def.did, ROOT_CODE_EXTENT); + def.did, None); let fields = &def.variants[0].fields; let last_field = &fields[fields.len()-1]; let always_sized = last_field.ty(tcx, param_env.free_substs) @@ -1224,7 +1282,7 @@ impl<'a, 'gcx, 'tcx> Layout { field.ty(tcx, substs).layout(infcx) }).collect::, _>>()?; let layout = if def.is_union() { - let mut un = Union::new(dl, def.repr.packed); + let mut un = Union::new(dl, def.repr.packed()); un.extend(dl, fields.iter().map(|&f| Ok(f)), ty)?; UntaggedUnion { variants: un } } else { @@ -1309,6 +1367,7 @@ impl<'a, 'gcx, 'tcx> Layout { assert!(discr_max >= 0); let (min_ity, _) = Integer::repr_discr(tcx, ty, &def.repr, 0, discr_max); let mut align = dl.aggregate_align; + let mut primitive_align = dl.aggregate_align; let mut size = Size::from_bytes(0); // We're interested in the smallest alignment, so start large. @@ -1338,6 +1397,7 @@ impl<'a, 'gcx, 'tcx> Layout { } size = cmp::max(size, st.min_size); align = align.max(st.align); + primitive_align = primitive_align.max(st.primitive_align); Ok(st) }).collect::, _>>()?; @@ -1404,13 +1464,14 @@ impl<'a, 'gcx, 'tcx> Layout { discr: ity, variants: variants, size: size, - align: align + align: align, + primitive_align: primitive_align } } // Types with no meaningful known layout. ty::TyProjection(_) | ty::TyAnon(..) => { - let normalized = normalize_associated_type(infcx, ty); + let normalized = infcx.normalize_projections(ty); if ty == normalized { return Err(LayoutError::Unknown(ty)); } @@ -1440,22 +1501,32 @@ impl<'a, 'gcx, 'tcx> Layout { } } - pub fn size(&self, dl: &TargetDataLayout) -> Size { + pub fn size(&self, cx: C) -> Size { + let dl = cx.data_layout(); + match *self { Scalar { value, .. } | RawNullablePointer { value, .. } => { value.size(dl) } Vector { element, count } => { - let elem_size = element.size(dl); - let vec_size = match elem_size.checked_mul(count, dl) { + let element_size = element.size(dl); + let vec_size = match element_size.checked_mul(count, dl) { Some(size) => size, None => bug!("Layout::size({:?}): {} * {} overflowed", - self, elem_size.bytes(), count) + self, element_size.bytes(), count) }; vec_size.abi_align(self.align(dl)) } + Array { element_size, count, .. } => { + match element_size.checked_mul(count, dl) { + Some(size) => size, + None => bug!("Layout::size({:?}): {} * {} overflowed", + self, element_size.bytes(), count) + } + } + FatPointer { metadata, .. } => { // Effectively a (ptr, meta) tuple. Pointer.size(dl).abi_align(metadata.align(dl)) @@ -1464,7 +1535,7 @@ impl<'a, 'gcx, 'tcx> Layout { } CEnum { discr, .. } => Int(discr).size(dl), - Array { size, .. } | General { size, .. } => size, + General { size, .. } => size, UntaggedUnion { ref variants } => variants.stride(), Univariant { ref variant, .. } | @@ -1474,7 +1545,9 @@ impl<'a, 'gcx, 'tcx> Layout { } } - pub fn align(&self, dl: &TargetDataLayout) -> Align { + pub fn align(&self, cx: C) -> Align { + let dl = cx.data_layout(); + match *self { Scalar { value, .. } | RawNullablePointer { value, .. } => { value.align(dl) @@ -1513,6 +1586,85 @@ impl<'a, 'gcx, 'tcx> Layout { } } } + + /// Returns alignment before repr alignment is applied + pub fn primitive_align(&self, dl: &TargetDataLayout) -> Align { + match *self { + Array { primitive_align, .. } | General { primitive_align, .. } => primitive_align, + Univariant { ref variant, .. } | + StructWrappedNullablePointer { nonnull: ref variant, .. } => { + variant.primitive_align + }, + + _ => self.align(dl) + } + } + + /// Returns repr alignment if it is greater than the primitive alignment. + pub fn over_align(&self, dl: &TargetDataLayout) -> Option { + let align = self.align(dl); + let primitive_align = self.primitive_align(dl); + if align.abi() > primitive_align.abi() { + Some(align.abi() as u32) + } else { + None + } + } + + pub fn field_offset(&self, + cx: C, + i: usize, + variant_index: Option) + -> Size { + let dl = cx.data_layout(); + + match *self { + Scalar { .. } | + CEnum { .. } | + UntaggedUnion { .. } | + RawNullablePointer { .. } => { + Size::from_bytes(0) + } + + Vector { element, count } => { + let element_size = element.size(dl); + let i = i as u64; + assert!(i < count); + Size::from_bytes(element_size.bytes() * count) + } + + Array { element_size, count, .. } => { + let i = i as u64; + assert!(i < count); + Size::from_bytes(element_size.bytes() * count) + } + + FatPointer { metadata, .. } => { + // Effectively a (ptr, meta) tuple. + assert!(i < 2); + if i == 0 { + Size::from_bytes(0) + } else { + Pointer.size(dl).abi_align(metadata.align(dl)) + } + } + + Univariant { ref variant, .. } => variant.offsets[i], + + General { ref variants, .. } => { + let v = variant_index.expect("variant index required"); + variants[v].offsets[i + 1] + } + + StructWrappedNullablePointer { nndiscr, ref nonnull, .. } => { + if Some(nndiscr as usize) == variant_index { + nonnull.offsets[i] + } else { + Size::from_bytes(0) + } + } + } + } } /// Type size "skeleton", i.e. the only information determining a type's size. @@ -1544,7 +1696,7 @@ impl<'a, 'gcx, 'tcx> SizeSkeleton<'gcx> { // First try computing a static layout. let err = match ty.layout(infcx) { Ok(layout) => { - return Ok(SizeSkeleton::Known(layout.size(&tcx.data_layout))); + return Ok(SizeSkeleton::Known(layout.size(tcx))); } Err(err) => err }; @@ -1637,7 +1789,7 @@ impl<'a, 'gcx, 'tcx> SizeSkeleton<'gcx> { } ty::TyProjection(_) | ty::TyAnon(..) => { - let normalized = normalize_associated_type(infcx, ty); + let normalized = infcx.normalize_projections(ty); if ty == normalized { Err(err) } else { @@ -1658,3 +1810,212 @@ impl<'a, 'gcx, 'tcx> SizeSkeleton<'gcx> { } } } + +/// A pair of a type and its layout. Implements various +/// type traversal APIs (e.g. recursing into fields). +#[derive(Copy, Clone, Debug)] +pub struct TyLayout<'tcx> { + pub ty: Ty<'tcx>, + pub layout: &'tcx Layout, + pub variant_index: Option, +} + +impl<'tcx> Deref for TyLayout<'tcx> { + type Target = Layout; + fn deref(&self) -> &Layout { + self.layout + } +} + +pub trait HasTyCtxt<'tcx>: HasDataLayout { + fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx>; +} + +impl<'a, 'gcx, 'tcx> HasDataLayout for TyCtxt<'a, 'gcx, 'tcx> { + fn data_layout(&self) -> &TargetDataLayout { + &self.data_layout + } +} + +impl<'a, 'gcx, 'tcx> HasTyCtxt<'gcx> for TyCtxt<'a, 'gcx, 'tcx> { + fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'gcx> { + self.global_tcx() + } +} + +impl<'a, 'gcx, 'tcx> HasDataLayout for &'a InferCtxt<'a, 'gcx, 'tcx> { + fn data_layout(&self) -> &TargetDataLayout { + &self.tcx.data_layout + } +} + +impl<'a, 'gcx, 'tcx> HasTyCtxt<'gcx> for &'a InferCtxt<'a, 'gcx, 'tcx> { + fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'gcx> { + self.tcx.global_tcx() + } +} + +pub trait LayoutTyper<'tcx>: HasTyCtxt<'tcx> { + type TyLayout; + + fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout; + fn normalize_projections(self, ty: Ty<'tcx>) -> Ty<'tcx>; +} + +impl<'a, 'gcx, 'tcx> LayoutTyper<'gcx> for &'a InferCtxt<'a, 'gcx, 'tcx> { + type TyLayout = Result, LayoutError<'gcx>>; + + fn layout_of(self, ty: Ty<'gcx>) -> Self::TyLayout { + let ty = self.normalize_projections(ty); + + Ok(TyLayout { + ty: ty, + layout: ty.layout(self)?, + variant_index: None + }) + } + + fn normalize_projections(self, ty: Ty<'gcx>) -> Ty<'gcx> { + if !ty.has_projection_types() { + return ty; + } + + let mut selcx = traits::SelectionContext::new(self); + let cause = traits::ObligationCause::dummy(); + let traits::Normalized { value: result, obligations } = + traits::normalize(&mut selcx, cause, &ty); + + let mut fulfill_cx = traits::FulfillmentContext::new(); + + for obligation in obligations { + fulfill_cx.register_predicate_obligation(self, obligation); + } + + self.drain_fulfillment_cx_or_panic(DUMMY_SP, &mut fulfill_cx, &result) + } +} + +impl<'a, 'tcx> TyLayout<'tcx> { + pub fn for_variant(&self, variant_index: usize) -> Self { + TyLayout { + variant_index: Some(variant_index), + ..*self + } + } + + pub fn field_offset(&self, cx: C, i: usize) -> Size { + self.layout.field_offset(cx, i, self.variant_index) + } + + pub fn field_count(&self) -> usize { + // Handle enum/union through the type rather than Layout. + if let ty::TyAdt(def, _) = self.ty.sty { + let v = self.variant_index.unwrap_or(0); + if def.variants.is_empty() { + assert_eq!(v, 0); + return 0; + } else { + return def.variants[v].fields.len(); + } + } + + match *self.layout { + Scalar { .. } => { + bug!("TyLayout::field_count({:?}): not applicable", self) + } + + // Handled above (the TyAdt case). + CEnum { .. } | + General { .. } | + UntaggedUnion { .. } | + RawNullablePointer { .. } | + StructWrappedNullablePointer { .. } => bug!(), + + FatPointer { .. } => 2, + + Vector { count, .. } | + Array { count, .. } => { + let usize_count = count as usize; + assert_eq!(usize_count as u64, count); + usize_count + } + + Univariant { ref variant, .. } => variant.offsets.len(), + } + } + + pub fn field_type>(&self, cx: C, i: usize) -> Ty<'tcx> { + let tcx = cx.tcx(); + + let ptr_field_type = |pointee: Ty<'tcx>| { + let slice = |element: Ty<'tcx>| { + assert!(i < 2); + if i == 0 { + tcx.mk_mut_ptr(element) + } else { + tcx.types.usize + } + }; + match tcx.struct_tail(pointee).sty { + ty::TySlice(element) => slice(element), + ty::TyStr => slice(tcx.types.u8), + ty::TyDynamic(..) => tcx.mk_mut_ptr(tcx.mk_nil()), + _ => bug!("TyLayout::field_type({:?}): not applicable", self) + } + }; + + match self.ty.sty { + ty::TyBool | + ty::TyChar | + ty::TyInt(_) | + ty::TyUint(_) | + ty::TyFloat(_) | + ty::TyFnPtr(_) | + ty::TyNever | + ty::TyFnDef(..) | + ty::TyDynamic(..) => { + bug!("TyLayout::field_type({:?}): not applicable", self) + } + + // Potentially-fat pointers. + ty::TyRef(_, ty::TypeAndMut { ty: pointee, .. }) | + ty::TyRawPtr(ty::TypeAndMut { ty: pointee, .. }) => { + ptr_field_type(pointee) + } + ty::TyAdt(def, _) if def.is_box() => { + ptr_field_type(self.ty.boxed_ty()) + } + + // Arrays and slices. + ty::TyArray(element, _) | + ty::TySlice(element) => element, + ty::TyStr => tcx.types.u8, + + // Tuples and closures. + ty::TyClosure(def_id, ref substs) => { + substs.upvar_tys(def_id, tcx).nth(i).unwrap() + } + + ty::TyTuple(tys, _) => tys[i], + + // SIMD vector types. + ty::TyAdt(def, ..) if def.repr.simd() => { + self.ty.simd_type(tcx) + } + + // ADTs. + ty::TyAdt(def, substs) => { + def.variants[self.variant_index.unwrap_or(0)].fields[i].ty(tcx, substs) + } + + ty::TyProjection(_) | ty::TyAnon(..) | ty::TyParam(_) | + ty::TyInfer(_) | ty::TyError => { + bug!("TyLayout::field_type: unexpected type `{}`", self.ty) + } + } + } + + pub fn field>(&self, cx: C, i: usize) -> C::TyLayout { + cx.layout_of(cx.normalize_projections(self.field_type(cx, i))) + } +} diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index ac8c38c7d585..66df8dc050a2 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -10,16 +10,33 @@ use dep_graph::{DepGraph, DepNode, DepTrackingMap, DepTrackingMapConfig}; use hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; -use middle::const_val::ConstVal; +use hir::def::Def; +use hir; +use middle::const_val; +use middle::privacy::AccessLevels; +use middle::region::RegionMaps; use mir; -use ty::{self, Ty, TyCtxt}; +use mir::transform::{MirSuite, MirPassIndex}; +use session::CompileResult; +use ty::{self, CrateInherentImpls, Ty, TyCtxt}; +use ty::item_path; +use ty::steal::Steal; +use ty::subst::Substs; +use util::nodemap::{DefIdSet, NodeSet}; use rustc_data_structures::indexed_vec::IndexVec; use std::cell::{RefCell, RefMut}; +use std::fmt::Debug; +use std::hash::Hash; +use std::mem; +use std::collections::BTreeMap; +use std::ops::Deref; use std::rc::Rc; use syntax_pos::{Span, DUMMY_SP}; +use syntax::attr; +use syntax::symbol::Symbol; -trait Key { +pub trait Key: Clone + Hash + Eq + Debug { fn map_crate(&self) -> CrateNum; fn default_span(&self, tcx: TyCtxt) -> Span; } @@ -34,6 +51,16 @@ impl<'tcx> Key for ty::InstanceDef<'tcx> { } } +impl<'tcx> Key for ty::Instance<'tcx> { + fn map_crate(&self) -> CrateNum { + LOCAL_CRATE + } + + fn default_span(&self, tcx: TyCtxt) -> Span { + tcx.def_span(self.def_id()) + } +} + impl Key for CrateNum { fn map_crate(&self) -> CrateNum { *self @@ -70,6 +97,33 @@ impl Key for (CrateNum, DefId) { } } +impl<'tcx> Key for (DefId, &'tcx Substs<'tcx>) { + fn map_crate(&self) -> CrateNum { + self.0.krate + } + fn default_span(&self, tcx: TyCtxt) -> Span { + self.0.default_span(tcx) + } +} + +impl Key for (MirSuite, DefId) { + fn map_crate(&self) -> CrateNum { + self.1.map_crate() + } + fn default_span(&self, tcx: TyCtxt) -> Span { + self.1.default_span(tcx) + } +} + +impl Key for (MirSuite, MirPassIndex, DefId) { + fn map_crate(&self) -> CrateNum { + self.2.map_crate() + } + fn default_span(&self, tcx: TyCtxt) -> Span { + self.2.default_span(tcx) + } +} + trait Value<'tcx>: Sized { fn from_cycle_error<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self; } @@ -93,6 +147,18 @@ impl<'tcx> Value<'tcx> for Ty<'tcx> { } } +impl<'tcx> Value<'tcx> for ty::DtorckConstraint<'tcx> { + fn from_cycle_error<'a>(_: TyCtxt<'a, 'tcx, 'tcx>) -> Self { + Self::empty() + } +} + +impl<'tcx> Value<'tcx> for ty::SymbolName { + fn from_cycle_error<'a>(_: TyCtxt<'a, 'tcx, 'tcx>) -> Self { + ty::SymbolName { name: Symbol::intern("").as_str() } + } +} + pub struct CycleError<'a, 'tcx: 'a> { span: Span, cycle: RefMut<'a, [(Span, Query<'tcx>)]>, @@ -100,24 +166,36 @@ pub struct CycleError<'a, 'tcx: 'a> { impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn report_cycle(self, CycleError { span, cycle }: CycleError) { - assert!(!cycle.is_empty()); + // Subtle: release the refcell lock before invoking `describe()` + // below by dropping `cycle`. + let stack = cycle.to_vec(); + mem::drop(cycle); - let mut err = struct_span_err!(self.sess, span, E0391, - "unsupported cyclic reference between types/traits detected"); - err.span_label(span, &format!("cyclic reference")); + assert!(!stack.is_empty()); - err.span_note(cycle[0].0, &format!("the cycle begins when {}...", - cycle[0].1.describe(self))); + // Disable naming impls with types in this path, since that + // sometimes cycles itself, leading to extra cycle errors. + // (And cycle errors around impls tend to occur during the + // collect/coherence phases anyhow.) + item_path::with_forced_impl_filename_line(|| { + let mut err = + struct_span_err!(self.sess, span, E0391, + "unsupported cyclic reference between types/traits detected"); + err.span_label(span, &format!("cyclic reference")); - for &(span, ref query) in &cycle[1..] { - err.span_note(span, &format!("...which then requires {}...", - query.describe(self))); - } + err.span_note(stack[0].0, &format!("the cycle begins when {}...", + stack[0].1.describe(self))); - err.note(&format!("...which then again requires {}, completing the cycle.", - cycle[0].1.describe(self))); + for &(span, ref query) in &stack[1..] { + err.span_note(span, &format!("...which then requires {}...", + query.describe(self))); + } - err.emit(); + err.note(&format!("...which then again requires {}, completing the cycle.", + stack[0].1.describe(self))); + + err.emit(); + }); } fn cycle_check(self, span: Span, query: Query<'gcx>, compute: F) @@ -154,7 +232,7 @@ impl> QueryDescription for M { } } -impl<'tcx> QueryDescription for queries::super_predicates<'tcx> { +impl<'tcx> QueryDescription for queries::super_predicates_of<'tcx> { fn describe(tcx: TyCtxt, def_id: DefId) -> String { format!("computing the supertraits of `{}`", tcx.item_path_str(def_id)) @@ -176,9 +254,15 @@ impl<'tcx> QueryDescription for queries::coherent_trait<'tcx> { } } -impl<'tcx> QueryDescription for queries::coherent_inherent_impls<'tcx> { +impl<'tcx> QueryDescription for queries::crate_inherent_impls<'tcx> { + fn describe(_: TyCtxt, k: CrateNum) -> String { + format!("all inherent impls defined in crate `{:?}`", k) + } +} + +impl<'tcx> QueryDescription for queries::crate_inherent_impls_overlap_check<'tcx> { fn describe(_: TyCtxt, _: CrateNum) -> String { - format!("coherence checking all inherent impls") + format!("check for overlap between inherent impls defined in this crate") } } @@ -189,14 +273,94 @@ impl<'tcx> QueryDescription for queries::mir_shims<'tcx> { } } +impl<'tcx> QueryDescription for queries::privacy_access_levels<'tcx> { + fn describe(_: TyCtxt, _: CrateNum) -> String { + format!("privacy access levels") + } +} + +impl<'tcx> QueryDescription for queries::typeck_item_bodies<'tcx> { + fn describe(_: TyCtxt, _: CrateNum) -> String { + format!("type-checking all item bodies") + } +} + +impl<'tcx> QueryDescription for queries::reachable_set<'tcx> { + fn describe(_: TyCtxt, _: CrateNum) -> String { + format!("reachability") + } +} + +impl<'tcx> QueryDescription for queries::const_eval<'tcx> { + fn describe(tcx: TyCtxt, (def_id, _): (DefId, &'tcx Substs<'tcx>)) -> String { + format!("const-evaluating `{}`", tcx.item_path_str(def_id)) + } +} + +impl<'tcx> QueryDescription for queries::mir_keys<'tcx> { + fn describe(_: TyCtxt, _: CrateNum) -> String { + format!("getting a list of all mir_keys") + } +} + +impl<'tcx> QueryDescription for queries::symbol_name<'tcx> { + fn describe(_tcx: TyCtxt, instance: ty::Instance<'tcx>) -> String { + format!("computing the symbol for `{}`", instance) + } +} + +impl<'tcx> QueryDescription for queries::describe_def<'tcx> { + fn describe(_: TyCtxt, _: DefId) -> String { + bug!("describe_def") + } +} + +impl<'tcx> QueryDescription for queries::def_span<'tcx> { + fn describe(_: TyCtxt, _: DefId) -> String { + bug!("def_span") + } +} + + +impl<'tcx> QueryDescription for queries::stability<'tcx> { + fn describe(_: TyCtxt, _: DefId) -> String { + bug!("stability") + } +} + +impl<'tcx> QueryDescription for queries::deprecation<'tcx> { + fn describe(_: TyCtxt, _: DefId) -> String { + bug!("deprecation") + } +} + +impl<'tcx> QueryDescription for queries::item_body_nested_bodies<'tcx> { + fn describe(tcx: TyCtxt, def_id: DefId) -> String { + format!("nested item bodies of `{}`", tcx.item_path_str(def_id)) + } +} + +impl<'tcx> QueryDescription for queries::const_is_rvalue_promotable_to_static<'tcx> { + fn describe(tcx: TyCtxt, def_id: DefId) -> String { + format!("const checking if rvalue is promotable to static `{}`", + tcx.item_path_str(def_id)) + } +} + +impl<'tcx> QueryDescription for queries::is_mir_available<'tcx> { + fn describe(tcx: TyCtxt, def_id: DefId) -> String { + format!("checking if item is mir available: `{}`", + tcx.item_path_str(def_id)) + } +} + macro_rules! define_maps { (<$tcx:tt> $($(#[$attr:meta])* - pub $name:ident: $node:ident($K:ty) -> $V:ty),*) => { - pub struct Maps<$tcx> { - providers: IndexVec>, - query_stack: RefCell)>>, - $($(#[$attr])* pub $name: RefCell>>),* + [$($modifiers:tt)*] $name:ident: $node:ident($K:ty) -> $V:ty,)*) => { + define_map_struct! { + tcx: $tcx, + input: ($(([$($modifiers)*] [$($attr)*] [$name]))*) } impl<$tcx> Maps<$tcx> { @@ -253,13 +417,20 @@ macro_rules! define_maps { -> Result> where F: FnOnce(&$V) -> R { + debug!("ty::queries::{}::try_get_with(key={:?}, span={:?})", + stringify!($name), + key, + span); + if let Some(result) = tcx.maps.$name.borrow().get(&key) { return Ok(f(result)); } // FIXME(eddyb) Get more valid Span's on queries. - if span == DUMMY_SP { - span = key.default_span(tcx); + // def_span guard is necesary to prevent a recursive loop, + // default_span calls def_span query internally. + if span == DUMMY_SP && stringify!($name) != "def_span" { + span = key.default_span(tcx) } let _task = tcx.dep_graph.in_task(Self::to_dep_node(&key)); @@ -269,7 +440,7 @@ macro_rules! define_maps { provider(tcx.global_tcx(), key) })?; - Ok(f(&tcx.maps.$name.borrow_mut().entry(key).or_insert(result))) + Ok(f(tcx.maps.$name.borrow_mut().entry(key).or_insert(result))) } pub fn try_get(tcx: TyCtxt<'a, $tcx, 'lcx>, span: Span, key: $K) @@ -277,14 +448,6 @@ macro_rules! define_maps { Self::try_get_with(tcx, span, key, Clone::clone) } - $(#[$attr])* - pub fn get(tcx: TyCtxt<'a, $tcx, 'lcx>, span: Span, key: $K) -> $V { - Self::try_get(tcx, span, key).unwrap_or_else(|e| { - tcx.report_cycle(e); - Value::from_cycle_error(tcx.global_tcx()) - }) - } - pub fn force(tcx: TyCtxt<'a, $tcx, 'lcx>, span: Span, key: $K) { // FIXME(eddyb) Move away from using `DepTrackingMap` // so we don't have to explicitly ignore a false edge: @@ -299,25 +462,192 @@ macro_rules! define_maps { } })* - pub struct Providers<$tcx> { - $(pub $name: for<'a> fn(TyCtxt<'a, $tcx, $tcx>, $K) -> $V),* + #[derive(Copy, Clone)] + pub struct TyCtxtAt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { + pub tcx: TyCtxt<'a, 'gcx, 'tcx>, + pub span: Span, + } + + impl<'a, 'gcx, 'tcx> Deref for TyCtxtAt<'a, 'gcx, 'tcx> { + type Target = TyCtxt<'a, 'gcx, 'tcx>; + fn deref(&self) -> &Self::Target { + &self.tcx + } + } + + impl<'a, $tcx, 'lcx> TyCtxt<'a, $tcx, 'lcx> { + /// Return a transparent wrapper for `TyCtxt` which uses + /// `span` as the location of queries performed through it. + pub fn at(self, span: Span) -> TyCtxtAt<'a, $tcx, 'lcx> { + TyCtxtAt { + tcx: self, + span + } + } + + $($(#[$attr])* + pub fn $name(self, key: $K) -> $V { + self.at(DUMMY_SP).$name(key) + })* + } + + impl<'a, $tcx, 'lcx> TyCtxtAt<'a, $tcx, 'lcx> { + $($(#[$attr])* + pub fn $name(self, key: $K) -> $V { + queries::$name::try_get(self.tcx, self.span, key).unwrap_or_else(|e| { + self.report_cycle(e); + Value::from_cycle_error(self.global_tcx()) + }) + })* + } + + define_provider_struct! { + tcx: $tcx, + input: ($(([$($modifiers)*] [$name] [$K] [$V]))*), + output: () } impl<$tcx> Copy for Providers<$tcx> {} impl<$tcx> Clone for Providers<$tcx> { fn clone(&self) -> Self { *self } } + } +} + +macro_rules! define_map_struct { + // Initial state + (tcx: $tcx:tt, + input: $input:tt) => { + define_map_struct! { + tcx: $tcx, + input: $input, + output: () + } + }; + + // Final output + (tcx: $tcx:tt, + input: (), + output: ($($output:tt)*)) => { + pub struct Maps<$tcx> { + providers: IndexVec>, + query_stack: RefCell)>>, + $($output)* + } + }; + + // Field recognized and ready to shift into the output + (tcx: $tcx:tt, + ready: ([$($pub:tt)*] [$($attr:tt)*] [$name:ident]), + input: $input:tt, + output: ($($output:tt)*)) => { + define_map_struct! { + tcx: $tcx, + input: $input, + output: ($($output)* + $(#[$attr])* $($pub)* $name: RefCell>>,) + } + }; + + // Detect things with the `pub` modifier + (tcx: $tcx:tt, + input: (([pub $($other_modifiers:tt)*] $attrs:tt $name:tt) $($input:tt)*), + output: $output:tt) => { + define_map_struct! { + tcx: $tcx, + ready: ([pub] $attrs $name), + input: ($($input)*), + output: $output + } + }; + + // No modifiers left? This is a private item. + (tcx: $tcx:tt, + input: (([] $attrs:tt $name:tt) $($input:tt)*), + output: $output:tt) => { + define_map_struct! { + tcx: $tcx, + ready: ([pub] $attrs $name), + input: ($($input)*), + output: $output + } + }; + + // Skip other modifiers + (tcx: $tcx:tt, + input: (([$other_modifier:tt $($modifiers:tt)*] $($fields:tt)*) $($input:tt)*), + output: $output:tt) => { + define_map_struct! { + tcx: $tcx, + input: (([$($modifiers)*] $($fields)*) $($input)*), + output: $output + } + }; +} + +macro_rules! define_provider_struct { + // Initial state: + (tcx: $tcx:tt, input: $input:tt) => { + define_provider_struct! { + tcx: $tcx, + input: $input, + output: () + } + }; + + // Final state: + (tcx: $tcx:tt, + input: (), + output: ($(([$name:ident] [$K:ty] [$R:ty]))*)) => { + pub struct Providers<$tcx> { + $(pub $name: for<'a> fn(TyCtxt<'a, $tcx, $tcx>, $K) -> $R,)* + } impl<$tcx> Default for Providers<$tcx> { fn default() -> Self { - $(fn $name<'a, $tcx>(_: TyCtxt<'a, $tcx, $tcx>, key: $K) -> $V { + $(fn $name<'a, $tcx>(_: TyCtxt<'a, $tcx, $tcx>, key: $K) -> $R { bug!("tcx.maps.{}({:?}) unsupported by its crate", stringify!($name), key); })* Providers { $($name),* } } } - } + }; + + // Something ready to shift: + (tcx: $tcx:tt, + ready: ($name:tt $K:tt $V:tt), + input: $input:tt, + output: ($($output:tt)*)) => { + define_provider_struct! { + tcx: $tcx, + input: $input, + output: ($($output)* ($name $K $V)) + } + }; + + // Regular queries produce a `V` only. + (tcx: $tcx:tt, + input: (([] $name:tt $K:tt $V:tt) $($input:tt)*), + output: $output:tt) => { + define_provider_struct! { + tcx: $tcx, + ready: ($name $K $V), + input: ($($input)*), + output: $output + } + }; + + // Skip modifiers. + (tcx: $tcx:tt, + input: (([$other_modifier:tt $($modifiers:tt)*] $($fields:tt)*) $($input:tt)*), + output: $output:tt) => { + define_provider_struct! { + tcx: $tcx, + input: (([$($modifiers)*] $($fields)*) $($input)*), + output: $output + } + }; } // Each of these maps also corresponds to a method on a @@ -328,12 +658,12 @@ macro_rules! define_maps { // the driver creates (using several `rustc_*` crates). define_maps! { <'tcx> /// Records the type of every item. - pub ty: ItemSignature(DefId) -> Ty<'tcx>, + [] type_of: ItemSignature(DefId) -> Ty<'tcx>, /// Maps from the def-id of an item (trait/struct/enum/fn) to its /// associated generics and predicates. - pub generics: ItemSignature(DefId) -> &'tcx ty::Generics, - pub predicates: ItemSignature(DefId) -> ty::GenericPredicates<'tcx>, + [] generics_of: ItemSignature(DefId) -> &'tcx ty::Generics, + [] predicates_of: ItemSignature(DefId) -> ty::GenericPredicates<'tcx>, /// Maps from the def-id of a trait to the list of /// super-predicates. This is a subset of the full list of @@ -341,82 +671,157 @@ define_maps! { <'tcx> /// evaluate them even during type conversion, often before the /// full predicates are available (note that supertraits have /// additional acyclicity requirements). - pub super_predicates: ItemSignature(DefId) -> ty::GenericPredicates<'tcx>, + [] super_predicates_of: ItemSignature(DefId) -> ty::GenericPredicates<'tcx>, /// To avoid cycles within the predicates of a single item we compute /// per-type-parameter predicates for resolving `T::AssocTy`. - pub type_param_predicates: TypeParamPredicates((DefId, DefId)) + [] type_param_predicates: TypeParamPredicates((DefId, DefId)) -> ty::GenericPredicates<'tcx>, - pub trait_def: ItemSignature(DefId) -> &'tcx ty::TraitDef, - pub adt_def: ItemSignature(DefId) -> &'tcx ty::AdtDef, - pub adt_destructor: AdtDestructor(DefId) -> Option, - pub adt_sized_constraint: SizedConstraint(DefId) -> Ty<'tcx>, + [] trait_def: ItemSignature(DefId) -> &'tcx ty::TraitDef, + [] adt_def: ItemSignature(DefId) -> &'tcx ty::AdtDef, + [] adt_destructor: AdtDestructor(DefId) -> Option, + [] adt_sized_constraint: SizedConstraint(DefId) -> &'tcx [Ty<'tcx>], + [] adt_dtorck_constraint: DtorckConstraint(DefId) -> ty::DtorckConstraint<'tcx>, + + /// True if this is a foreign item (i.e., linked via `extern { ... }`). + [] is_foreign_item: IsForeignItem(DefId) -> bool, /// Maps from def-id of a type or region parameter to its /// (inferred) variance. - pub variances: ItemSignature(DefId) -> Rc>, + [pub] variances_of: ItemSignature(DefId) -> Rc>, /// Maps from an impl/trait def-id to a list of the def-ids of its items - pub associated_item_def_ids: AssociatedItemDefIds(DefId) -> Rc>, + [] associated_item_def_ids: AssociatedItemDefIds(DefId) -> Rc>, /// Maps from a trait item to the trait item "descriptor" - pub associated_item: AssociatedItems(DefId) -> ty::AssociatedItem, + [] associated_item: AssociatedItems(DefId) -> ty::AssociatedItem, - pub impl_trait_ref: ItemSignature(DefId) -> Option>, + [] impl_trait_ref: ItemSignature(DefId) -> Option>, + [] impl_polarity: ItemSignature(DefId) -> hir::ImplPolarity, /// Maps a DefId of a type to a list of its inherent impls. /// Contains implementations of methods that are inherent to a type. /// Methods in these implementations don't need to be exported. - pub inherent_impls: InherentImpls(DefId) -> Vec, + [] inherent_impls: InherentImpls(DefId) -> Rc>, - /// Maps from the def-id of a function/method or const/static - /// to its MIR. Mutation is done at an item granularity to - /// allow MIR optimization passes to function and still - /// access cross-crate MIR (e.g. inlining or const eval). - /// - /// Note that cross-crate MIR appears to be always borrowed - /// (in the `RefCell` sense) to prevent accidental mutation. - pub mir: Mir(DefId) -> &'tcx RefCell>, + /// Set of all the def-ids in this crate that have MIR associated with + /// them. This includes all the body owners, but also things like struct + /// constructors. + [] mir_keys: mir_keys(CrateNum) -> Rc, /// Maps DefId's that have an associated Mir to the result /// of the MIR qualify_consts pass. The actual meaning of /// the value isn't known except to the pass itself. - pub mir_const_qualif: Mir(DefId) -> u8, + [] mir_const_qualif: Mir(DefId) -> u8, + + /// Fetch the MIR for a given def-id up till the point where it is + /// ready for const evaluation. + /// + /// See the README for the `mir` module for details. + [] mir_const: Mir(DefId) -> &'tcx Steal>, + + [] mir_validated: Mir(DefId) -> &'tcx Steal>, + + /// MIR after our optimization passes have run. This is MIR that is ready + /// for trans. This is also the only query that can fetch non-local MIR, at present. + [] optimized_mir: Mir(DefId) -> &'tcx mir::Mir<'tcx>, /// Records the type of each closure. The def ID is the ID of the /// expression defining the closure. - pub closure_kind: ItemSignature(DefId) -> ty::ClosureKind, + [] closure_kind: ItemSignature(DefId) -> ty::ClosureKind, /// Records the type of each closure. The def ID is the ID of the /// expression defining the closure. - pub closure_type: ItemSignature(DefId) -> ty::PolyFnSig<'tcx>, + [] closure_type: ItemSignature(DefId) -> ty::PolyFnSig<'tcx>, /// Caches CoerceUnsized kinds for impls on custom types. - pub custom_coerce_unsized_kind: ItemSignature(DefId) - -> ty::adjustment::CustomCoerceUnsized, + [] coerce_unsized_info: ItemSignature(DefId) + -> ty::adjustment::CoerceUnsizedInfo, - pub typeck_tables: TypeckTables(DefId) -> &'tcx ty::TypeckTables<'tcx>, + [] typeck_item_bodies: typeck_item_bodies_dep_node(CrateNum) -> CompileResult, - pub coherent_trait: coherent_trait_dep_node((CrateNum, DefId)) -> (), + [] typeck_tables_of: TypeckTables(DefId) -> &'tcx ty::TypeckTables<'tcx>, - pub coherent_inherent_impls: coherent_inherent_impls_dep_node(CrateNum) -> (), + [] has_typeck_tables: TypeckTables(DefId) -> bool, - /// Results of evaluating monomorphic constants embedded in - /// other items, such as enum variant explicit discriminants. - pub monomorphic_const_eval: MonomorphicConstEval(DefId) -> Result, ()>, + [] coherent_trait: coherent_trait_dep_node((CrateNum, DefId)) -> (), - pub mir_shims: mir_shim(ty::InstanceDef<'tcx>) -> &'tcx RefCell> + [] borrowck: BorrowCheck(DefId) -> (), + + /// 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) + [] crate_inherent_impls: crate_inherent_impls_dep_node(CrateNum) -> CrateInherentImpls, + + /// Checks all types in the krate for overlap in their inherent impls. Reports errors. + /// Not meant to be used directly outside of coherence. + /// (Defined only for LOCAL_CRATE) + [] crate_inherent_impls_overlap_check: crate_inherent_impls_dep_node(CrateNum) -> (), + + /// Results of evaluating const items or constants embedded in + /// other items (such as enum variant explicit discriminants). + [] const_eval: const_eval_dep_node((DefId, &'tcx Substs<'tcx>)) + -> const_val::EvalResult<'tcx>, + + /// Performs the privacy check and computes "access levels". + [] privacy_access_levels: PrivacyAccessLevels(CrateNum) -> Rc, + + [] reachable_set: reachability_dep_node(CrateNum) -> Rc, + + /// Per-function `RegionMaps`. The `DefId` should be the owner-def-id for the fn body; + /// in the case of closures or "inline" expressions, this will be redirected to the enclosing + /// fn item. + [] region_maps: RegionMaps(DefId) -> Rc>, + + [] mir_shims: mir_shim_dep_node(ty::InstanceDef<'tcx>) -> &'tcx mir::Mir<'tcx>, + + [] def_symbol_name: SymbolName(DefId) -> ty::SymbolName, + [] symbol_name: symbol_name_dep_node(ty::Instance<'tcx>) -> ty::SymbolName, + + [] describe_def: DescribeDef(DefId) -> Option, + [] def_span: DefSpan(DefId) -> Span, + [] stability: Stability(DefId) -> Option, + [] deprecation: Deprecation(DefId) -> Option, + [] item_body_nested_bodies: metadata_dep_node(DefId) -> Rc>, + [] const_is_rvalue_promotable_to_static: metadata_dep_node(DefId) -> bool, + [] is_mir_available: metadata_dep_node(DefId) -> bool, } fn coherent_trait_dep_node((_, def_id): (CrateNum, DefId)) -> DepNode { DepNode::CoherenceCheckTrait(def_id) } -fn coherent_inherent_impls_dep_node(_: CrateNum) -> DepNode { +fn crate_inherent_impls_dep_node(_: CrateNum) -> DepNode { DepNode::Coherence } -fn mir_shim(instance: ty::InstanceDef) -> DepNode { +fn reachability_dep_node(_: CrateNum) -> DepNode { + DepNode::Reachability +} + +fn metadata_dep_node(def_id: DefId) -> DepNode { + DepNode::MetaData(def_id) +} + +fn mir_shim_dep_node(instance: ty::InstanceDef) -> DepNode { instance.dep_node() } + +fn symbol_name_dep_node(instance: ty::Instance) -> DepNode { + // symbol_name uses the substs only to traverse them to find the + // hash, and that does not create any new dep-nodes. + DepNode::SymbolName(instance.def.def_id()) +} + +fn typeck_item_bodies_dep_node(_: CrateNum) -> DepNode { + DepNode::TypeckBodiesKrate +} + +fn const_eval_dep_node((def_id, _): (DefId, &Substs)) -> DepNode { + DepNode::ConstEval(def_id) +} + +fn mir_keys(_: CrateNum) -> DepNode { + DepNode::MirKeys +} diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 36d1ae74e911..55466b1f36da 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -17,12 +17,13 @@ pub use self::fold::TypeFoldable; use dep_graph::{self, DepNode}; use hir::{map as hir_map, FreevarMap, TraitMap}; -use middle; use hir::def::{Def, CtorKind, ExportMap}; use hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE}; +use ich::StableHashingContext; use middle::const_val::ConstVal; use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem}; -use middle::region::{CodeExtent, ROOT_CODE_EXTENT}; +use middle::privacy::AccessLevels; +use middle::region::CodeExtent; use middle::resolve_lifetime::ObjectLifetimeDefault; use mir::Mir; use traits; @@ -30,26 +31,30 @@ use ty; use ty::subst::{Subst, Substs}; use ty::util::IntTypeExt; use ty::walk::TypeWalker; -use util::common::MemoizationMap; -use util::nodemap::{NodeSet, FxHashMap}; +use util::common::ErrorReported; +use util::nodemap::{NodeSet, DefIdMap, FxHashMap, FxHashSet}; use serialize::{self, Encodable, Encoder}; -use std::borrow::Cow; -use std::cell::{Cell, RefCell, Ref}; +use std::cell::{Cell, RefCell}; use std::collections::BTreeMap; +use std::cmp; +use std::fmt; use std::hash::{Hash, Hasher}; +use std::iter::FromIterator; use std::ops::Deref; use std::rc::Rc; use std::slice; use std::vec::IntoIter; use std::mem; -use syntax::ast::{self, Name, NodeId}; +use syntax::ast::{self, DUMMY_NODE_ID, Name, NodeId}; use syntax::attr; use syntax::symbol::{Symbol, InternedString}; use syntax_pos::{DUMMY_SP, Span}; use rustc_const_math::ConstInt; use rustc_data_structures::accumulate_vec::IntoIter as AccIntoIter; +use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult, + HashStable}; use hir; use hir::itemlikevisit::ItemLikeVisitor; @@ -62,14 +67,14 @@ pub use self::sty::{TraitRef, TypeVariants, PolyTraitRef}; pub use self::sty::{ExistentialTraitRef, PolyExistentialTraitRef}; pub use self::sty::{ExistentialProjection, PolyExistentialProjection}; pub use self::sty::{BoundRegion, EarlyBoundRegion, FreeRegion, Region}; +pub use self::sty::RegionKind; pub use self::sty::Issue32330; pub use self::sty::{TyVid, IntVid, FloatVid, RegionVid, SkolemizedRegionVid}; pub use self::sty::BoundRegion::*; pub use self::sty::InferTy::*; -pub use self::sty::Region::*; +pub use self::sty::RegionKind::*; pub use self::sty::TypeVariants::*; -pub use self::contents::TypeContents; pub use self::context::{TyCtxt, GlobalArenas, tls}; pub use self::context::{Lift, TypeckTables}; @@ -91,13 +96,13 @@ pub mod _match; pub mod maps; pub mod outlives; pub mod relate; +pub mod steal; pub mod subst; pub mod trait_def; pub mod walk; pub mod wf; pub mod util; -mod contents; mod context; mod flags; mod instance; @@ -108,11 +113,13 @@ mod sty; /// The complete set of all analyses described in this module. This is /// produced by the driver and fed to trans and later passes. +/// +/// NB: These contents are being migrated into queries using the +/// *on-demand* infrastructure. #[derive(Clone)] pub struct CrateAnalysis { - pub export_map: ExportMap, - pub access_levels: middle::privacy::AccessLevels, - pub reachable: NodeSet, + pub access_levels: Rc, + pub reachable: Rc, pub name: String, pub glob_map: Option, } @@ -122,6 +129,7 @@ pub struct Resolutions { pub freevars: FreevarMap, pub trait_map: TraitMap, pub maybe_unused_trait_imports: NodeSet, + pub export_map: ExportMap, } #[derive(Clone, Copy, PartialEq, Eq, Debug)] @@ -160,9 +168,9 @@ impl<'a, 'gcx, 'tcx> ImplHeader<'tcx> { let header = ImplHeader { impl_def_id: impl_def_id, - self_ty: tcx.item_type(impl_def_id), + self_ty: tcx.type_of(impl_def_id), trait_ref: tcx.impl_trait_ref(impl_def_id), - predicates: tcx.item_predicates(impl_def_id).predicates + predicates: tcx.predicates_of(impl_def_id).predicates }.subst(tcx, impl_substs); let traits::Normalized { value: mut header, obligations } = @@ -420,6 +428,10 @@ bitflags! { const IS_SIZED = 1 << 17, const MOVENESS_CACHED = 1 << 18, const MOVES_BY_DEFAULT = 1 << 19, + const FREEZENESS_CACHED = 1 << 20, + const IS_FREEZE = 1 << 21, + const NEEDS_DROP_CACHED = 1 << 22, + const NEEDS_DROP = 1 << 23, } } @@ -446,6 +458,23 @@ impl<'tcx> Hash for TyS<'tcx> { } } +impl<'a, 'tcx> HashStable> for ty::TyS<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let ty::TyS { + ref sty, + + // The other fields just provide fast access to information that is + // also contained in `sty`, so no need to hash them. + flags: _, + region_depth: _, + } = *self; + + sty.hash_stable(hcx, hasher); + } +} + pub type Ty<'tcx> = &'tcx TyS<'tcx>; impl<'tcx> serialize::UseSpecializedEncodable for Ty<'tcx> {} @@ -574,7 +603,7 @@ pub struct UpvarBorrow<'tcx> { pub kind: BorrowKind, /// Region of the resulting reference. - pub region: &'tcx ty::Region, + pub region: ty::Region<'tcx>, } pub type UpvarCaptureMap<'tcx> = FxHashMap>; @@ -701,7 +730,7 @@ impl<'a, 'gcx, 'tcx> GenericPredicates<'tcx> { instantiated: &mut InstantiatedPredicates<'tcx>, substs: &Substs<'tcx>) { if let Some(def_id) = self.parent { - tcx.item_predicates(def_id).instantiate_into(tcx, instantiated, substs); + tcx.predicates_of(def_id).instantiate_into(tcx, instantiated, substs); } instantiated.predicates.extend(self.predicates.iter().map(|p| p.subst(tcx, substs))) } @@ -719,7 +748,7 @@ impl<'a, 'gcx, 'tcx> GenericPredicates<'tcx> { } } -#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub enum Predicate<'tcx> { /// Corresponds to `where Foo : Bar`. `Foo` here would be /// the `Self` type of the trait reference and `A`, `B`, and `C` @@ -749,6 +778,9 @@ pub enum Predicate<'tcx> { /// for some substitutions `...` and T being a closure type. /// Satisfied (or refuted) once we know the closure's kind. ClosureKind(DefId, ClosureKind), + + /// `T1 <: T2` + Subtype(PolySubtypePredicate<'tcx>), } impl<'a, 'gcx, 'tcx> Predicate<'tcx> { @@ -827,6 +859,8 @@ impl<'a, 'gcx, 'tcx> Predicate<'tcx> { Predicate::Trait(ty::Binder(data.subst(tcx, substs))), Predicate::Equate(ty::Binder(ref data)) => Predicate::Equate(ty::Binder(data.subst(tcx, substs))), + Predicate::Subtype(ty::Binder(ref data)) => + Predicate::Subtype(ty::Binder(data.subst(tcx, substs))), Predicate::RegionOutlives(ty::Binder(ref data)) => Predicate::RegionOutlives(ty::Binder(data.subst(tcx, substs))), Predicate::TypeOutlives(ty::Binder(ref data)) => @@ -843,7 +877,7 @@ impl<'a, 'gcx, 'tcx> Predicate<'tcx> { } } -#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub struct TraitPredicate<'tcx> { pub trait_ref: TraitRef<'tcx> } @@ -895,16 +929,24 @@ impl<'tcx> PolyTraitPredicate<'tcx> { } } -#[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct EquatePredicate<'tcx>(pub Ty<'tcx>, pub Ty<'tcx>); // `0 == 1` pub type PolyEquatePredicate<'tcx> = ty::Binder>; -#[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct OutlivesPredicate(pub A, pub B); // `A : B` pub type PolyOutlivesPredicate = ty::Binder>; -pub type PolyRegionOutlivesPredicate<'tcx> = PolyOutlivesPredicate<&'tcx ty::Region, - &'tcx ty::Region>; -pub type PolyTypeOutlivesPredicate<'tcx> = PolyOutlivesPredicate, &'tcx ty::Region>; +pub type PolyRegionOutlivesPredicate<'tcx> = PolyOutlivesPredicate, + ty::Region<'tcx>>; +pub type PolyTypeOutlivesPredicate<'tcx> = PolyOutlivesPredicate, ty::Region<'tcx>>; + +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] +pub struct SubtypePredicate<'tcx> { + pub a_is_expected: bool, + pub a: Ty<'tcx>, + pub b: Ty<'tcx> +} +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: @@ -1019,6 +1061,9 @@ impl<'tcx> Predicate<'tcx> { ty::Predicate::Equate(ty::Binder(ref data)) => { vec![data.0, data.1] } + ty::Predicate::Subtype(ty::Binder(SubtypePredicate { a, b, a_is_expected: _ })) => { + vec![a, b] + } ty::Predicate::TypeOutlives(ty::Binder(ref data)) => { vec![data.0] } @@ -1055,6 +1100,7 @@ impl<'tcx> Predicate<'tcx> { } Predicate::Projection(..) | Predicate::Equate(..) | + Predicate::Subtype(..) | Predicate::RegionOutlives(..) | Predicate::WellFormed(..) | Predicate::ObjectSafe(..) | @@ -1120,33 +1166,38 @@ pub struct ParameterEnvironment<'tcx> { /// Each type parameter has an implicit region bound that /// indicates it must outlive at least the function body (the user /// may specify stronger requirements). This field indicates the - /// region of the callee. - pub implicit_region_bound: &'tcx ty::Region, + /// region of the callee. If it is `None`, then the parameter + /// environment is for an item or something where the "callee" is + /// not clear. + pub implicit_region_bound: Option>, /// Obligations that the caller must satisfy. This is basically /// the set of bounds on the in-scope type parameters, translated /// into Obligations, and elaborated and normalized. - pub caller_bounds: Vec>, + pub caller_bounds: &'tcx [ty::Predicate<'tcx>], - /// Scope that is attached to free regions for this scope. This - /// is usually the id of the fn body, but for more abstract scopes - /// like structs we often use the node-id of the struct. + /// Scope that is attached to free regions for this scope. This is + /// usually the id of the fn body, but for more abstract scopes + /// like structs we use None or the item extent. /// /// FIXME(#3696). It would be nice to refactor so that free /// regions don't have this implicit scope and instead introduce /// relationships in the environment. - pub free_id_outlive: CodeExtent, + pub free_id_outlive: Option>, /// A cache for `moves_by_default`. pub is_copy_cache: RefCell, bool>>, /// A cache for `type_is_sized` pub is_sized_cache: RefCell, bool>>, + + /// A cache for `type_is_freeze` + pub is_freeze_cache: RefCell, bool>>, } impl<'a, 'tcx> ParameterEnvironment<'tcx> { pub fn with_caller_bounds(&self, - caller_bounds: Vec>) + caller_bounds: &'tcx [ty::Predicate<'tcx>]) -> ParameterEnvironment<'tcx> { ParameterEnvironment { @@ -1156,6 +1207,7 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> { free_id_outlive: self.free_id_outlive, is_copy_cache: RefCell::new(FxHashMap()), is_sized_cache: RefCell::new(FxHashMap()), + is_freeze_cache: RefCell::new(FxHashMap()), } } @@ -1172,13 +1224,13 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> { let impl_def_id = tcx.hir.local_def_id(impl_id); tcx.construct_parameter_environment(impl_item.span, impl_def_id, - tcx.region_maps.item_extent(id)) + Some(tcx.item_extent(id))) } hir::ImplItemKind::Method(_, ref body) => { tcx.construct_parameter_environment( impl_item.span, tcx.hir.local_def_id(id), - tcx.region_maps.call_site_extent(id, body.node_id)) + Some(tcx.call_site_extent(id, body.node_id))) } } } @@ -1191,7 +1243,7 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> { let trait_def_id = tcx.hir.local_def_id(trait_id); tcx.construct_parameter_environment(trait_item.span, trait_def_id, - tcx.region_maps.item_extent(id)) + Some(tcx.item_extent(id))) } hir::TraitItemKind::Method(_, ref body) => { // Use call-site for extent (unless this is a @@ -1199,15 +1251,15 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> { // to the method id). let extent = if let hir::TraitMethod::Provided(body_id) = *body { // default impl: use call_site extent as free_id_outlive bound. - tcx.region_maps.call_site_extent(id, body_id.node_id) + tcx.call_site_extent(id, body_id.node_id) } else { // no default impl: use item extent as free_id_outlive bound. - tcx.region_maps.item_extent(id) + tcx.item_extent(id) }; tcx.construct_parameter_environment( trait_item.span, tcx.hir.local_def_id(id), - extent) + Some(extent)) } } } @@ -1220,7 +1272,7 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> { tcx.construct_parameter_environment( item.span, fn_def_id, - tcx.region_maps.call_site_extent(id, body_id.node_id)) + Some(tcx.call_site_extent(id, body_id.node_id))) } hir::ItemEnum(..) | hir::ItemStruct(..) | @@ -1232,13 +1284,13 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> { let def_id = tcx.hir.local_def_id(id); tcx.construct_parameter_environment(item.span, def_id, - tcx.region_maps.item_extent(id)) + Some(tcx.item_extent(id))) } hir::ItemTrait(..) => { let def_id = tcx.hir.local_def_id(id); tcx.construct_parameter_environment(item.span, def_id, - tcx.region_maps.item_extent(id)) + Some(tcx.item_extent(id))) } _ => { span_bug!(item.span, @@ -1256,7 +1308,7 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> { tcx.construct_parameter_environment( expr.span, base_def_id, - tcx.region_maps.call_site_extent(id, body.node_id)) + Some(tcx.call_site_extent(id, body.node_id))) } else { tcx.empty_parameter_environment() } @@ -1265,14 +1317,14 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> { let def_id = tcx.hir.local_def_id(id); tcx.construct_parameter_environment(item.span, def_id, - ROOT_CODE_EXTENT) + None) } Some(hir_map::NodeStructCtor(..)) | Some(hir_map::NodeVariant(..)) => { let def_id = tcx.hir.local_def_id(id); tcx.construct_parameter_environment(tcx.hir.span(id), def_id, - ROOT_CODE_EXTENT) + None) } it => { bug!("ParameterEnvironment::from_item(): \ @@ -1287,17 +1339,6 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> { pub struct Destructor { /// The def-id of the destructor method pub did: DefId, - /// Invoking the destructor of a dtorck type during usual cleanup - /// (e.g. the glue emitted for stack unwinding) requires all - /// lifetimes in the type-structure of `adt` to strictly outlive - /// the adt value itself. - /// - /// If `adt` is not dtorck, then the adt's destructor can be - /// invoked even when there are lifetimes in the type-structure of - /// `adt` that do not strictly outlive the adt value itself. - /// (This allows programs to make cyclic structures without - /// resorting to unsafe means; see RFCs 769 and 1238). - pub is_dtorck: bool, } bitflags! { @@ -1376,41 +1417,109 @@ impl<'tcx> serialize::UseSpecializedEncodable for &'tcx AdtDef { impl<'tcx> serialize::UseSpecializedDecodable for &'tcx AdtDef {} + +impl<'a, 'tcx> HashStable> for AdtDef { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'tcx>, + hasher: &mut StableHasher) { + let ty::AdtDef { + did, + ref variants, + ref flags, + ref repr, + } = *self; + + did.hash_stable(hcx, hasher); + variants.hash_stable(hcx, hasher); + flags.hash_stable(hcx, hasher); + repr.hash_stable(hcx, hasher); + } +} + #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum AdtKind { Struct, Union, Enum } +bitflags! { + #[derive(RustcEncodable, RustcDecodable, Default)] + flags ReprFlags: u8 { + const IS_C = 1 << 0, + const IS_PACKED = 1 << 1, + const IS_SIMD = 1 << 2, + // Internal only for now. If true, don't reorder fields. + const IS_LINEAR = 1 << 3, + + // Any of these flags being set prevent field reordering optimisation. + const IS_UNOPTIMISABLE = ReprFlags::IS_C.bits | + ReprFlags::IS_PACKED.bits | + ReprFlags::IS_SIMD.bits | + ReprFlags::IS_LINEAR.bits, + } +} + +impl_stable_hash_for!(struct ReprFlags { + bits +}); + + + /// Represents the repr options provided by the user, #[derive(Copy, Clone, Eq, PartialEq, RustcEncodable, RustcDecodable, Default)] pub struct ReprOptions { - pub c: bool, - pub packed: bool, - pub simd: bool, pub int: Option, + pub align: u16, + pub flags: ReprFlags, } +impl_stable_hash_for!(struct ReprOptions { + align, + int, + flags +}); + impl ReprOptions { pub fn new(tcx: TyCtxt, did: DefId) -> ReprOptions { - let mut ret = ReprOptions::default(); - + let mut flags = ReprFlags::empty(); + let mut size = None; + let mut max_align = 0; for attr in tcx.get_attrs(did).iter() { for r in attr::find_repr_attrs(tcx.sess.diagnostic(), attr) { - match r { - attr::ReprExtern => ret.c = true, - attr::ReprPacked => ret.packed = true, - attr::ReprSimd => ret.simd = true, - attr::ReprInt(i) => ret.int = Some(i), - } + flags.insert(match r { + attr::ReprExtern => ReprFlags::IS_C, + attr::ReprPacked => ReprFlags::IS_PACKED, + attr::ReprSimd => ReprFlags::IS_SIMD, + attr::ReprInt(i) => { + size = Some(i); + ReprFlags::empty() + }, + attr::ReprAlign(align) => { + max_align = cmp::max(align, max_align); + ReprFlags::empty() + }, + }); } } // FIXME(eddyb) This is deprecated and should be removed. if tcx.has_attr(did, "simd") { - ret.simd = true; + flags.insert(ReprFlags::IS_SIMD); } - ret + // This is here instead of layout because the choice must make it into metadata. + if !tcx.consider_optimizing(|| format!("Reorder fields of {:?}", tcx.item_path_str(did))) { + flags.insert(ReprFlags::IS_LINEAR); + } + ReprOptions { int: size, align: max_align, flags: flags } } + #[inline] + pub fn simd(&self) -> bool { self.flags.contains(ReprFlags::IS_SIMD) } + #[inline] + pub fn c(&self) -> bool { self.flags.contains(ReprFlags::IS_C) } + #[inline] + pub fn packed(&self) -> bool { self.flags.contains(ReprFlags::IS_PACKED) } + #[inline] + pub fn linear(&self) -> bool { self.flags.contains(ReprFlags::IS_LINEAR) } + pub fn discr_type(&self) -> attr::IntType { self.int.unwrap_or(attr::SignedInt(ast::IntTy::Is)) } @@ -1419,7 +1528,7 @@ impl ReprOptions { /// layout" optimizations, such as representing `Foo<&T>` as a /// single pointer. pub fn inhibit_enum_layout_opt(&self) -> bool { - self.c || self.int.is_some() + self.c() || self.int.is_some() } } @@ -1496,14 +1605,6 @@ impl<'a, 'gcx, 'tcx> AdtDef { } } - /// Returns whether this is a dtorck type. If this returns - /// true, this type being safe for destruction requires it to be - /// alive; Otherwise, only the contents are required to be. - #[inline] - pub fn is_dtorck(&'gcx self, tcx: TyCtxt) -> bool { - self.destructor(tcx).map_or(false, |d| d.is_dtorck) - } - /// Returns whether this type is #[fundamental] for the purposes /// of coherence checking. #[inline] @@ -1537,7 +1638,7 @@ impl<'a, 'gcx, 'tcx> AdtDef { #[inline] pub fn predicates(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> GenericPredicates<'gcx> { - tcx.item_predicates(self.did) + tcx.predicates_of(self.did) } /// Returns an iterator over all fields contained @@ -1580,6 +1681,7 @@ impl<'a, 'gcx, 'tcx> AdtDef { } } + #[inline] pub fn discriminants(&'a self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> impl Iterator + 'a { let repr_type = self.repr.discr_type(); @@ -1588,11 +1690,18 @@ impl<'a, 'gcx, 'tcx> AdtDef { self.variants.iter().map(move |v| { let mut discr = prev_discr.map_or(initial, |d| d.wrap_incr()); if let VariantDiscr::Explicit(expr_did) = v.discr { - match tcx.maps.monomorphic_const_eval.borrow()[&expr_did] { + let substs = Substs::empty(); + match tcx.const_eval((expr_did, substs)) { Ok(ConstVal::Integral(v)) => { discr = v; } - _ => {} + err => { + if !expr_did.is_local() { + span_bug!(tcx.def_span(expr_did), + "variant discriminant evaluation succeeded \ + in its crate but failed locally: {:?}", err); + } + } } } prev_discr = Some(discr); @@ -1601,20 +1710,67 @@ impl<'a, 'gcx, 'tcx> AdtDef { }) } - pub fn destructor(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option { - queries::adt_destructor::get(tcx, DUMMY_SP, self.did) + /// Compute 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), + /// assuming there are no constant-evaluation errors there. + pub fn discriminant_for_variant(&self, + tcx: TyCtxt<'a, 'gcx, 'tcx>, + variant_index: usize) + -> ConstInt { + let repr_type = self.repr.discr_type(); + let mut explicit_value = repr_type.initial_discriminant(tcx.global_tcx()); + let mut explicit_index = variant_index; + loop { + match self.variants[explicit_index].discr { + ty::VariantDiscr::Relative(0) => break, + ty::VariantDiscr::Relative(distance) => { + explicit_index -= distance; + } + ty::VariantDiscr::Explicit(expr_did) => { + let substs = Substs::empty(); + match tcx.const_eval((expr_did, substs)) { + Ok(ConstVal::Integral(v)) => { + explicit_value = v; + break; + } + err => { + if !expr_did.is_local() { + span_bug!(tcx.def_span(expr_did), + "variant discriminant evaluation succeeded \ + in its crate but failed locally: {:?}", err); + } + if explicit_index == 0 { + break; + } + explicit_index -= 1; + } + } + } + } + } + let discr = explicit_value.to_u128_unchecked() + .wrapping_add((variant_index - explicit_index) as u128); + match repr_type { + attr::UnsignedInt(ty) => { + ConstInt::new_unsigned_truncating(discr, ty, + tcx.sess.target.uint_type) + } + attr::SignedInt(ty) => { + ConstInt::new_signed_truncating(discr as i128, ty, + tcx.sess.target.int_type) + } + } } - /// Returns a simpler type such that `Self: Sized` if and only + pub fn destructor(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option { + tcx.adt_destructor(self.did) + } + + /// Returns a list of types such that `Self: Sized` if and only /// if that type is Sized, or `TyErr` if this type is recursive. /// - /// HACK: instead of returning a list of types, this function can - /// return a tuple. In that case, the result is Sized only if - /// all elements of the tuple are Sized. - /// - /// This is generally the `struct_tail` if this is a struct, or a - /// tuple of them if this is an enum. - /// /// 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 @@ -1622,86 +1778,22 @@ impl<'a, 'gcx, 'tcx> AdtDef { /// /// Due to normalization being eager, this applies even if /// the associated type is behind a pointer, e.g. issue #31299. - pub fn sized_constraint(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> { - self.calculate_sized_constraint_inner(tcx.global_tcx(), &mut Vec::new()) - } - - /// Calculates the Sized-constraint. - /// - /// As the Sized-constraint of enums can be a *set* of types, - /// the Sized-constraint may need to be a set also. Because introducing - /// a new type of IVar is currently a complex affair, the Sized-constraint - /// may be a tuple. - /// - /// In fact, there are only a few options for the constraint: - /// - `bool`, if the type is always Sized - /// - an obviously-unsized type - /// - a type parameter or projection whose Sizedness can't be known - /// - a tuple of type parameters or projections, if there are multiple - /// such. - /// - a TyError, if a type contained itself. The representability - /// check should catch this case. - fn calculate_sized_constraint_inner(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - stack: &mut Vec) - -> Ty<'tcx> - { - if let Some(ty) = tcx.maps.adt_sized_constraint.borrow().get(&self.did) { - return ty; - } - - // Follow the memoization pattern: push the computation of - // DepNode::SizedConstraint as our current task. - let _task = tcx.dep_graph.in_task(DepNode::SizedConstraint(self.did)); - - if stack.contains(&self.did) { - debug!("calculate_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. - tcx.maps.adt_sized_constraint.borrow_mut().insert(self.did, tcx.types.err); - return tcx.types.err; - } - - stack.push(self.did); - - let tys : Vec<_> = - self.variants.iter().flat_map(|v| { - v.fields.last() - }).flat_map(|f| { - let ty = tcx.item_type(f.did); - self.sized_constraint_for_ty(tcx, stack, ty) - }).collect(); - - let self_ = stack.pop().unwrap(); - assert_eq!(self_, self.did); - - let ty = match tys.len() { - _ if tys.references_error() => tcx.types.err, - 0 => tcx.types.bool, - 1 => tys[0], - _ => tcx.intern_tup(&tys[..], false) - }; - - let old = tcx.maps.adt_sized_constraint.borrow().get(&self.did).cloned(); - match old { - Some(old_ty) => { - debug!("calculate_sized_constraint: {:?} recurred", self); - assert_eq!(old_ty, tcx.types.err); - old_ty - } - None => { - debug!("calculate_sized_constraint: {:?} => {:?}", self, ty); - tcx.maps.adt_sized_constraint.borrow_mut().insert(self.did, ty); - ty + pub fn sized_constraint(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> &'tcx [Ty<'tcx>] { + match queries::adt_sized_constraint::try_get(tcx, DUMMY_SP, self.did) { + Ok(tys) => tys, + Err(_) => { + 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. + tcx.intern_type_list(&[tcx.types.err]) } } } fn sized_constraint_for_ty(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - stack: &mut Vec, ty: Ty<'tcx>) -> Vec> { let result = match ty.sty { @@ -1719,24 +1811,19 @@ impl<'a, 'gcx, 'tcx> AdtDef { TyTuple(ref tys, _) => { match tys.last() { None => vec![], - Some(ty) => self.sized_constraint_for_ty(tcx, stack, ty) + Some(ty) => self.sized_constraint_for_ty(tcx, ty) } } TyAdt(adt, substs) => { // recursive case - let adt_ty = - adt.calculate_sized_constraint_inner(tcx, stack) - .subst(tcx, substs); + let adt_tys = adt.sized_constraint(tcx); debug!("sized_constraint_for_ty({:?}) intermediate = {:?}", - ty, adt_ty); - if let ty::TyTuple(ref tys, _) = adt_ty.sty { - tys.iter().flat_map(|ty| { - self.sized_constraint_for_ty(tcx, stack, ty) - }).collect() - } else { - self.sized_constraint_for_ty(tcx, stack, adt_ty) - } + ty, adt_tys); + adt_tys.iter() + .map(|ty| ty.subst(tcx, substs)) + .flat_map(|ty| self.sized_constraint_for_ty(tcx, ty)) + .collect() } TyProjection(..) | TyAnon(..) => { @@ -1758,7 +1845,7 @@ impl<'a, 'gcx, 'tcx> AdtDef { def_id: sized_trait, substs: tcx.mk_substs_trait(ty, &[]) }).to_predicate(); - let predicates = tcx.item_predicates(self.did).predicates; + let predicates = tcx.predicates_of(self.did).predicates; if predicates.into_iter().any(|p| p == sized_predicate) { vec![] } else { @@ -1799,7 +1886,7 @@ impl<'a, 'gcx, 'tcx> VariantDef { impl<'a, 'gcx, 'tcx> FieldDef { pub fn ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, subst: &Substs<'tcx>) -> Ty<'tcx> { - tcx.item_type(self.did).subst(tcx, subst) + tcx.type_of(self.did).subst(tcx, subst) } } @@ -1941,13 +2028,36 @@ impl BorrowKind { } } +#[derive(Debug, Clone)] +pub enum Attributes<'gcx> { + Owned(Rc<[ast::Attribute]>), + Borrowed(&'gcx [ast::Attribute]) +} + +impl<'gcx> ::std::ops::Deref for Attributes<'gcx> { + type Target = [ast::Attribute]; + + fn deref(&self) -> &[ast::Attribute] { + match self { + &Attributes::Owned(ref data) => &data, + &Attributes::Borrowed(data) => data + } + } +} + impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn body_tables(self, body: hir::BodyId) -> &'gcx TypeckTables<'gcx> { - self.item_tables(self.hir.body_owner_def_id(body)) + self.typeck_tables_of(self.hir.body_owner_def_id(body)) } - pub fn item_tables(self, def_id: DefId) -> &'gcx TypeckTables<'gcx> { - queries::typeck_tables::get(self, DUMMY_SP, def_id) + /// Returns an iterator of the def-ids 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(self) -> impl Iterator + 'a { + self.hir.krate() + .body_ids + .iter() + .map(move |&body_id| self.hir.body_owner_def_id(body_id)) } pub fn expr_span(self, id: NodeId) -> Span { @@ -2037,33 +2147,35 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { .collect() } - pub fn trait_impl_polarity(self, id: DefId) -> hir::ImplPolarity { - if let Some(id) = self.hir.as_local_node_id(id) { - match self.hir.expect_item(id).node { - hir::ItemImpl(_, polarity, ..) => polarity, - ref item => bug!("trait_impl_polarity: {:?} not an impl", item) - } - } else { - self.sess.cstore.impl_polarity(id) - } - } - pub fn trait_relevant_for_never(self, did: DefId) -> bool { self.associated_items(did).any(|item| { item.relevant_for_never() }) } - pub fn custom_coerce_unsized_kind(self, did: DefId) -> adjustment::CustomCoerceUnsized { - queries::custom_coerce_unsized_kind::get(self, DUMMY_SP, did) - } + pub fn opt_associated_item(self, def_id: DefId) -> Option { + let is_associated_item = if let Some(node_id) = self.hir.as_local_node_id(def_id) { + match self.hir.get(node_id) { + hir_map::NodeTraitItem(_) | hir_map::NodeImplItem(_) => true, + _ => false, + } + } else { + match self.describe_def(def_id).expect("no def for def-id") { + Def::AssociatedConst(_) | Def::Method(_) | Def::AssociatedTy(_) => true, + _ => false, + } + }; - pub fn associated_item(self, def_id: DefId) -> AssociatedItem { - queries::associated_item::get(self, DUMMY_SP, def_id) + if is_associated_item { + Some(self.associated_item(def_id)) + } else { + None + } } fn associated_item_from_trait_item_ref(self, parent_def_id: DefId, + parent_vis: &hir::Visibility, trait_item_ref: &hir::TraitItemRef) -> AssociatedItem { let def_id = self.hir.local_def_id(trait_item_ref.id.node_id); @@ -2078,7 +2190,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { AssociatedItem { name: trait_item_ref.name, kind: kind, - vis: Visibility::from_hir(&hir::Inherited, trait_item_ref.id.node_id, self), + // Visibility of trait items is inherited from their traits. + vis: Visibility::from_hir(parent_vis, trait_item_ref.id.node_id, self), defaultness: trait_item_ref.defaultness, def_id: def_id, container: TraitContainer(parent_def_id), @@ -2088,7 +2201,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { fn associated_item_from_impl_item_ref(self, parent_def_id: DefId, - from_trait_impl: bool, impl_item_ref: &hir::ImplItemRef) -> AssociatedItem { let def_id = self.hir.local_def_id(impl_item_ref.id.node_id); @@ -2100,14 +2212,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { hir::AssociatedItemKind::Type => (ty::AssociatedKind::Type, false), }; - // Trait impl items are always public. - let public = hir::Public; - let vis = if from_trait_impl { &public } else { &impl_item_ref.vis }; - ty::AssociatedItem { name: impl_item_ref.name, kind: kind, - vis: ty::Visibility::from_hir(vis, impl_item_ref.id.node_id, self), + // Visibility of trait impl items doesn't matter. + vis: ty::Visibility::from_hir(&impl_item_ref.vis, impl_item_ref.id.node_id, self), defaultness: impl_item_ref.defaultness, def_id: def_id, container: ImplContainer(parent_def_id), @@ -2115,33 +2224,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } - pub fn associated_item_def_ids(self, def_id: DefId) -> Rc> { - if !def_id.is_local() { - return queries::associated_item_def_ids::get(self, DUMMY_SP, def_id); - } - - self.maps.associated_item_def_ids.memoize(def_id, || { - let id = self.hir.as_local_node_id(def_id).unwrap(); - let item = self.hir.expect_item(id); - let vec: Vec<_> = match item.node { - hir::ItemTrait(.., ref trait_item_refs) => { - trait_item_refs.iter() - .map(|trait_item_ref| trait_item_ref.id) - .map(|id| self.hir.local_def_id(id.node_id)) - .collect() - } - hir::ItemImpl(.., ref impl_item_refs) => { - impl_item_refs.iter() - .map(|impl_item_ref| impl_item_ref.id) - .map(|id| self.hir.local_def_id(id.node_id)) - .collect() - } - _ => span_bug!(item.span, "associated_item_def_ids: not impl or trait") - }; - Rc::new(vec) - }) - } - #[inline] // FIXME(#35870) Avoid closures being unexported due to impl Trait. pub fn associated_items(self, def_id: DefId) -> impl Iterator + 'a { @@ -2149,10 +2231,23 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { (0..def_ids.len()).map(move |i| self.associated_item(def_ids[i])) } - /// Returns the trait-ref corresponding to a given impl, or None if it is - /// an inherent impl. - pub fn impl_trait_ref(self, id: DefId) -> Option> { - queries::impl_trait_ref::get(self, DUMMY_SP, id) + /// Returns true if the impls are the same polarity and are implementing + /// a trait which contains no items + pub fn impls_are_allowed_to_overlap(self, def_id1: DefId, def_id2: DefId) -> bool { + if !self.sess.features.borrow().overlapping_marker_traits { + return false; + } + let trait1_is_empty = self.impl_trait_ref(def_id1) + .map_or(false, |trait_ref| { + self.associated_item_def_ids(trait_ref.def_id).is_empty() + }); + let trait2_is_empty = self.impl_trait_ref(def_id2) + .map_or(false, |trait_ref| { + self.associated_item_def_ids(trait_ref.def_id).is_empty() + }); + self.impl_polarity(def_id1) == self.impl_polarity(def_id2) + && trait1_is_empty + && trait2_is_empty } // Returns `ty::VariantDef` if `def` refers to a struct, @@ -2161,14 +2256,14 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { match def { Def::Variant(did) | Def::VariantCtor(did, ..) => { let enum_did = self.parent_def_id(did).unwrap(); - self.lookup_adt_def(enum_did).variant_with_id(did) + self.adt_def(enum_did).variant_with_id(did) } Def::Struct(did) | Def::Union(did) => { - self.lookup_adt_def(did).struct_variant() + self.adt_def(did).struct_variant() } Def::StructCtor(ctor_did, ..) => { let did = self.parent_def_id(ctor_did).expect("struct ctor has no parent"); - self.lookup_adt_def(did).struct_variant() + self.adt_def(did).struct_variant() } _ => bug!("expect_variant_def used with unexpected def {:?}", def) } @@ -2186,7 +2281,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// `DefId` is really just an interned def-path). /// /// Note that if `id` is not local to this crate, the result will - // be a non-local `DefPath`. + /// be a non-local `DefPath`. pub fn def_path(self, id: DefId) -> hir_map::DefPath { if id.is_local() { self.hir.def_path(id) @@ -2195,11 +2290,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } - pub fn def_span(self, def_id: DefId) -> Span { - if let Some(id) = self.hir.as_local_node_id(def_id) { - self.hir.span(id) + #[inline] + pub fn def_path_hash(self, def_id: DefId) -> u64 { + if def_id.is_local() { + self.hir.definitions().def_path_hash(def_id.index) } else { - self.sess.cstore.def_span(&self.sess, def_id) + self.sess.cstore.def_path_hash(def_id) } } @@ -2228,106 +2324,40 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } - // If the given item is in an external crate, looks up its type and adds it to - // the type cache. Returns the type parameters and type. - pub fn item_type(self, did: DefId) -> Ty<'gcx> { - queries::ty::get(self, DUMMY_SP, did) - } - - /// Given the did of a trait, returns its canonical trait ref. - pub fn lookup_trait_def(self, did: DefId) -> &'gcx TraitDef { - queries::trait_def::get(self, DUMMY_SP, did) - } - - /// Given the did of an ADT, return a reference to its definition. - pub fn lookup_adt_def(self, did: DefId) -> &'gcx AdtDef { - queries::adt_def::get(self, DUMMY_SP, did) - } - - /// Given the did of an item, returns its generics. - pub fn item_generics(self, did: DefId) -> &'gcx Generics { - queries::generics::get(self, DUMMY_SP, did) - } - - /// Given the did of an item, returns its full set of predicates. - pub fn item_predicates(self, did: DefId) -> GenericPredicates<'gcx> { - queries::predicates::get(self, DUMMY_SP, did) - } - - /// Given the did of a trait, returns its superpredicates. - pub fn item_super_predicates(self, did: DefId) -> GenericPredicates<'gcx> { - queries::super_predicates::get(self, DUMMY_SP, did) - } - - /// Given the did of an item, returns its MIR, borrowed immutably. - pub fn item_mir(self, did: DefId) -> Ref<'gcx, Mir<'gcx>> { - queries::mir::get(self, DUMMY_SP, did).borrow() - } - /// Return the possibly-auto-generated MIR of a (DefId, Subst) pair. pub fn instance_mir(self, instance: ty::InstanceDef<'gcx>) - -> Ref<'gcx, Mir<'gcx>> + -> &'gcx Mir<'gcx> { match instance { - ty::InstanceDef::Item(did) if true => self.item_mir(did), - _ => queries::mir_shims::get(self, DUMMY_SP, instance).borrow(), + ty::InstanceDef::Item(did) => { + self.optimized_mir(did) + } + ty::InstanceDef::Intrinsic(..) | + ty::InstanceDef::FnPtrShim(..) | + ty::InstanceDef::Virtual(..) | + ty::InstanceDef::ClosureOnceShim { .. } | + ty::InstanceDef::DropGlue(..) => { + self.mir_shims(instance) + } } } /// Given the DefId of an item, returns its MIR, borrowed immutably. /// Returns None if there is no MIR for the DefId - pub fn maybe_item_mir(self, did: DefId) -> Option>> { - if did.is_local() && !self.maps.mir.borrow().contains_key(&did) { - return None; + 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 } - - if !did.is_local() && !self.sess.cstore.is_item_mir_available(did) { - return None; - } - - Some(self.item_mir(did)) - } - - /// If `type_needs_drop` returns true, then `ty` is definitely - /// non-copy and *might* have a destructor attached; if it returns - /// false, then `ty` definitely has no destructor (i.e. no drop glue). - /// - /// (Note that this implies that if `ty` has a destructor attached, - /// then `type_needs_drop` will definitely return `true` for `ty`.) - pub fn type_needs_drop_given_env(self, - ty: Ty<'gcx>, - param_env: &ty::ParameterEnvironment<'gcx>) -> bool { - // Issue #22536: We first query type_moves_by_default. It sees a - // normalized version of the type, and therefore will definitely - // know whether the type implements Copy (and thus needs no - // cleanup/drop/zeroing) ... - let tcx = self.global_tcx(); - let implements_copy = !ty.moves_by_default(tcx, param_env, DUMMY_SP); - - if implements_copy { return false; } - - // ... (issue #22536 continued) but as an optimization, still use - // prior logic of asking if the `needs_drop` bit is set; we need - // not zero non-Copy types if they have no destructor. - - // FIXME(#22815): Note that calling `ty::type_contents` is a - // conservative heuristic; it may report that `needs_drop` is set - // when actual type does not actually have a destructor associated - // with it. But since `ty` absolutely did not have the `Copy` - // bound attached (see above), it is sound to treat it as having a - // destructor (e.g. zero its memory on move). - - let contents = ty.type_contents(tcx); - debug!("type_needs_drop ty={:?} contents={:?}", ty, contents); - contents.needs_drop(tcx) } /// Get the attributes of a definition. - pub fn get_attrs(self, did: DefId) -> Cow<'gcx, [ast::Attribute]> { + pub fn get_attrs(self, did: DefId) -> Attributes<'gcx> { if let Some(id) = self.hir.as_local_node_id(did) { - Cow::Borrowed(self.hir.attrs(id)) + Attributes::Borrowed(self.hir.attrs(id)) } else { - Cow::Owned(self.sess.cstore.item_attrs(did)) + Attributes::Owned(self.sess.cstore.item_attrs(did)) } } @@ -2336,43 +2366,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.get_attrs(did).iter().any(|item| item.check_name(attr)) } - pub fn item_variances(self, item_id: DefId) -> Rc> { - queries::variances::get(self, DUMMY_SP, item_id) - } - pub fn trait_has_default_impl(self, trait_def_id: DefId) -> bool { - let def = self.lookup_trait_def(trait_def_id); + let def = self.trait_def(trait_def_id); def.flags.get().intersects(TraitFlags::HAS_DEFAULT_IMPL) } - /// Populates the type context with all the inherent implementations for - /// the given type if necessary. - pub fn populate_inherent_implementations_for_type_if_necessary(self, - span: Span, - type_id: DefId) { - if type_id.is_local() { - // Make sure coherence of inherent impls ran already. - ty::queries::coherent_inherent_impls::force(self, span, LOCAL_CRATE); - return - } - - // The type is not local, hence we are reading this out of - // metadata and don't need to track edges. - let _ignore = self.dep_graph.in_ignore(); - - if self.populated_external_types.borrow().contains(&type_id) { - return - } - - debug!("populate_inherent_implementations_for_type_if_necessary: searching for {:?}", - type_id); - - let inherent_impls = self.sess.cstore.inherent_implementations_for_type(type_id); - - self.maps.inherent_impls.borrow_mut().insert(type_id, inherent_impls); - self.populated_external_types.borrow_mut().insert(type_id); - } - /// Populates the type context with all the implementations for the given /// trait if necessary. pub fn populate_implementations_for_trait_if_necessary(self, trait_id: DefId) { @@ -2384,7 +2382,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // metadata and don't need to track edges. let _ignore = self.dep_graph.in_ignore(); - let def = self.lookup_trait_def(trait_id); + let def = self.trait_def(trait_id); if def.flags.get().intersects(TraitFlags::HAS_REMOTE_IMPLS) { return; } @@ -2402,14 +2400,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { def.flags.set(def.flags.get() | TraitFlags::HAS_REMOTE_IMPLS); } - pub fn closure_kind(self, def_id: DefId) -> ty::ClosureKind { - queries::closure_kind::get(self, DUMMY_SP, def_id) - } - - pub fn closure_type(self, def_id: DefId) -> ty::PolyFnSig<'tcx> { - queries::closure_type::get(self, DUMMY_SP, def_id) - } - /// Given the def_id of an impl, return the def_id of the trait it implements. /// If it implements no trait, return `None`. pub fn trait_id_of_impl(self, def_id: DefId) -> Option { @@ -2420,13 +2410,13 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// ID of the impl that the method belongs to. Otherwise, return `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.sess.cstore.describe_def(def_id) { + if let Some(Def::Method(_)) = self.describe_def(def_id) { Some(self.associated_item(def_id)) } else { None } } else { - self.maps.associated_item.borrow().get(&def_id).cloned() + self.opt_associated_item(def_id) }; match item { @@ -2447,31 +2437,26 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { if def_id.krate != LOCAL_CRATE { return self.sess.cstore.trait_of_item(def_id); } - match self.maps.associated_item.borrow().get(&def_id) { - Some(associated_item) => { + self.opt_associated_item(def_id) + .and_then(|associated_item| { match associated_item.container { TraitContainer(def_id) => Some(def_id), ImplContainer(_) => None } - } - None => None - } + }) } /// Construct a parameter environment suitable for static contexts or other contexts where there /// are no free type/lifetime parameters in scope. pub fn empty_parameter_environment(self) -> ParameterEnvironment<'tcx> { - - // for an empty parameter environment, there ARE no free - // regions, so it shouldn't matter what we use for the free id - let free_id_outlive = self.region_maps.node_extent(ast::DUMMY_NODE_ID); ty::ParameterEnvironment { free_substs: self.intern_substs(&[]), - caller_bounds: Vec::new(), - implicit_region_bound: self.mk_region(ty::ReEmpty), - free_id_outlive: free_id_outlive, + caller_bounds: Slice::empty(), + implicit_region_bound: None, + free_id_outlive: None, is_copy_cache: RefCell::new(FxHashMap()), is_sized_cache: RefCell::new(FxHashMap()), + is_freeze_cache: RefCell::new(FxHashMap()), } } @@ -2480,8 +2465,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// In general, this means converting from bound parameters to /// free parameters. Since we currently represent bound/free type /// parameters in the same way, this only has an effect on regions. - pub fn construct_free_substs(self, def_id: DefId, - free_id_outlive: CodeExtent) + pub fn construct_free_substs(self, + def_id: DefId, + free_id_outlive: Option>) -> &'gcx Substs<'gcx> { let substs = Substs::for_item(self.global_tcx(), def_id, |def, _| { @@ -2500,12 +2486,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } /// See `ParameterEnvironment` struct def'n for details. - /// If you were using `free_id: NodeId`, you might try `self.region_maps.item_extent(free_id)` + /// If you were using `free_id: NodeId`, you might try `self.region_maps().item_extent(free_id)` /// for the `free_id_outlive` parameter. (But note that this is not always quite right.) pub fn construct_parameter_environment(self, span: Span, def_id: DefId, - free_id_outlive: CodeExtent) + free_id_outlive: Option>) -> ParameterEnvironment<'gcx> { // @@ -2519,7 +2505,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // let tcx = self.global_tcx(); - let generic_predicates = tcx.item_predicates(def_id); + let generic_predicates = tcx.predicates_of(def_id); let bounds = generic_predicates.instantiate(tcx, free_substs); let bounds = tcx.liberate_late_bound_regions(free_id_outlive, &ty::Binder(bounds)); let predicates = bounds.predicates; @@ -2539,19 +2525,22 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { let unnormalized_env = ty::ParameterEnvironment { free_substs: free_substs, - implicit_region_bound: tcx.mk_region(ty::ReScope(free_id_outlive)), - caller_bounds: predicates, + implicit_region_bound: free_id_outlive.map(|f| tcx.mk_region(ty::ReScope(f))), + caller_bounds: tcx.intern_predicates(&predicates), free_id_outlive: free_id_outlive, is_copy_cache: RefCell::new(FxHashMap()), is_sized_cache: RefCell::new(FxHashMap()), + is_freeze_cache: RefCell::new(FxHashMap()), }; - let cause = traits::ObligationCause::misc(span, free_id_outlive.node_id(&self.region_maps)); - traits::normalize_param_env_or_error(tcx, unnormalized_env, cause) + let body_id = free_id_outlive.map(|f| f.node_id()) + .unwrap_or(DUMMY_NODE_ID); + let cause = traits::ObligationCause::misc(span, body_id); + traits::normalize_param_env_or_error(tcx, def_id, unnormalized_env, cause) } - pub fn node_scope_region(self, id: NodeId) -> &'tcx Region { - self.mk_region(ty::ReScope(self.region_maps.node_extent(id))) + pub fn node_scope_region(self, id: NodeId) -> Region<'tcx> { + self.mk_region(ty::ReScope(self.node_extent(id))) } pub fn visit_all_item_likes_in_krate(self, @@ -2562,17 +2551,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { dep_graph::visit_all_item_likes_in_krate(self.global_tcx(), dep_node_fn, visitor); } - /// Invokes `callback` for each body in the krate. This will - /// create a read edge from `DepNode::Krate` to the current task; - /// it is meant to be run in the context of some global task like - /// `BorrowckCrate`. The callback would then create a task like - /// `BorrowckBody(DefId)` to process each individual item. - pub fn visit_all_bodies_in_krate(self, callback: C) - where C: Fn(/* body_owner */ DefId, /* body id */ hir::BodyId), - { - dep_graph::visit_all_bodies_in_krate(self.global_tcx(), callback) - } - /// Looks up the span of `impl_did` if the impl is local; otherwise returns `Err` /// with the name of the crate containing the impl. pub fn span_of_impl(self, impl_did: DefId) -> Result { @@ -2604,12 +2582,10 @@ fn associated_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) let parent_def_id = tcx.hir.local_def_id(parent_id); let parent_item = tcx.hir.expect_item(parent_id); match parent_item.node { - hir::ItemImpl(.., ref impl_trait_ref, _, ref impl_item_refs) => { + hir::ItemImpl(.., ref impl_item_refs) => { if let Some(impl_item_ref) = impl_item_refs.iter().find(|i| i.id.node_id == id) { - let assoc_item = - tcx.associated_item_from_impl_item_ref(parent_def_id, - impl_trait_ref.is_some(), - impl_item_ref); + let assoc_item = tcx.associated_item_from_impl_item_ref(parent_def_id, + impl_item_ref); debug_assert_eq!(assoc_item.def_id, def_id); return assoc_item; } @@ -2617,23 +2593,194 @@ fn associated_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) hir::ItemTrait(.., ref trait_item_refs) => { if let Some(trait_item_ref) = trait_item_refs.iter().find(|i| i.id.node_id == id) { - let assoc_item = - tcx.associated_item_from_trait_item_ref(parent_def_id, trait_item_ref); + let assoc_item = tcx.associated_item_from_trait_item_ref(parent_def_id, + &parent_item.vis, + trait_item_ref); debug_assert_eq!(assoc_item.def_id, def_id); return assoc_item; } } - ref r => { - panic!("unexpected container of associated items: {:?}", r) - } + _ => { } } - panic!("associated item not found for def_id: {:?}", def_id); + + span_bug!(parent_item.span, + "unexpected parent of trait or impl item or item not found: {:?}", + parent_item.node) +} + +/// Calculates the Sized-constraint. +/// +/// In fact, there are only a few options for the types in the constraint: +/// - an obviously-unsized type +/// - a type parameter or projection whose Sizedness can't be known +/// - a tuple of type parameters or projections, if there are multiple +/// such. +/// - a TyError, if a type contained itself. The representability +/// check should catch this case. +fn adt_sized_constraint<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId) + -> &'tcx [Ty<'tcx>] { + let def = tcx.adt_def(def_id); + + let result = tcx.intern_type_list(&def.variants.iter().flat_map(|v| { + v.fields.last() + }).flat_map(|f| { + def.sized_constraint_for_ty(tcx, tcx.type_of(f.did)) + }).collect::>()); + + debug!("adt_sized_constraint: {:?} => {:?}", def, result); + + result +} + +/// Calculates the dtorck constraint for a type. +fn adt_dtorck_constraint<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId) + -> DtorckConstraint<'tcx> { + let def = tcx.adt_def(def_id); + let span = tcx.def_span(def_id); + debug!("dtorck_constraint: {:?}", def); + + if def.is_phantom_data() { + let result = DtorckConstraint { + outlives: vec![], + dtorck_types: vec![ + tcx.mk_param_from_def(&tcx.generics_of(def_id).types[0]) + ] + }; + debug!("dtorck_constraint: {:?} => {:?}", def, result); + return result; + } + + let mut result = def.all_fields() + .map(|field| tcx.type_of(field.did)) + .map(|fty| tcx.dtorck_constraint_for_ty(span, fty, 0, fty)) + .collect::>() + .unwrap_or(DtorckConstraint::empty()); + result.outlives.extend(tcx.destructor_constraints(def)); + result.dedup(); + + debug!("dtorck_constraint: {:?} => {:?}", def, result); + + result +} + +fn associated_item_def_ids<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId) + -> Rc> { + let id = tcx.hir.as_local_node_id(def_id).unwrap(); + let item = tcx.hir.expect_item(id); + let vec: Vec<_> = match item.node { + hir::ItemTrait(.., ref trait_item_refs) => { + trait_item_refs.iter() + .map(|trait_item_ref| trait_item_ref.id) + .map(|id| tcx.hir.local_def_id(id.node_id)) + .collect() + } + hir::ItemImpl(.., ref impl_item_refs) => { + impl_item_refs.iter() + .map(|impl_item_ref| impl_item_ref.id) + .map(|id| tcx.hir.local_def_id(id.node_id)) + .collect() + } + _ => span_bug!(item.span, "associated_item_def_ids: not impl or trait") + }; + Rc::new(vec) +} + +fn def_span<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Span { + tcx.hir.span_if_local(def_id).unwrap() } pub fn provide(providers: &mut ty::maps::Providers) { *providers = ty::maps::Providers { associated_item, + associated_item_def_ids, + adt_sized_constraint, + adt_dtorck_constraint, + def_span, ..*providers }; } + +pub fn provide_extern(providers: &mut ty::maps::Providers) { + *providers = ty::maps::Providers { + adt_sized_constraint, + adt_dtorck_constraint, + ..*providers + }; +} + + +/// A map for the local crate mapping each type to a vector of its +/// inherent impls. This is not meant to be used outside of coherence; +/// rather, you should request the vector for a specific type via +/// `tcx.inherent_impls(def_id)` so as to minimize your dependencies +/// (constructing this map requires touching the entire crate). +#[derive(Clone, Debug)] +pub struct CrateInherentImpls { + pub inherent_impls: DefIdMap>>, +} + +/// A set of constraints that need to be satisfied in order for +/// a type to be valid for destruction. +#[derive(Clone, Debug)] +pub struct DtorckConstraint<'tcx> { + /// Types that are required to be alive in order for this + /// type to be valid for destruction. + pub outlives: Vec>, + /// Types that could not be resolved: projections and params. + pub dtorck_types: Vec>, +} + +impl<'tcx> FromIterator> for DtorckConstraint<'tcx> +{ + fn from_iter>>(iter: I) -> Self { + let mut result = Self::empty(); + + for constraint in iter { + result.outlives.extend(constraint.outlives); + result.dtorck_types.extend(constraint.dtorck_types); + } + + result + } +} + + +impl<'tcx> DtorckConstraint<'tcx> { + fn empty() -> DtorckConstraint<'tcx> { + DtorckConstraint { + outlives: vec![], + dtorck_types: vec![] + } + } + + fn dedup<'a>(&mut self) { + let mut outlives = FxHashSet(); + let mut dtorck_types = FxHashSet(); + + self.outlives.retain(|&val| outlives.replace(val).is_none()); + self.dtorck_types.retain(|&val| dtorck_types.replace(val).is_none()); + } +} + +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct SymbolName { + // FIXME: we don't rely on interning or equality here - better have + // this be a `&'tcx str`. + pub name: InternedString +} + +impl Deref for SymbolName { + type Target = str; + + fn deref(&self) -> &str { &self.name } +} + +impl fmt::Display for SymbolName { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.name, fmt) + } +} diff --git a/src/librustc/ty/outlives.rs b/src/librustc/ty/outlives.rs index bc30f1fb7172..a544b2dd3991 100644 --- a/src/librustc/ty/outlives.rs +++ b/src/librustc/ty/outlives.rs @@ -16,7 +16,7 @@ use ty::{self, Ty, TyCtxt, TypeFoldable}; #[derive(Debug)] pub enum Component<'tcx> { - Region(&'tcx ty::Region), + Region(ty::Region<'tcx>), Param(ty::ParamTy), UnresolvedInferenceVariable(ty::InferTy), @@ -202,7 +202,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } -fn push_region_constraints<'tcx>(out: &mut Vec>, regions: Vec<&'tcx ty::Region>) { +fn push_region_constraints<'tcx>(out: &mut Vec>, regions: Vec>) { for r in regions { if !r.is_bound() { out.push(Component::Region(r)); diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index cef24d44d687..ac434c01c6a8 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -67,8 +67,8 @@ pub trait TypeRelation<'a, 'gcx: 'a+'tcx, 'tcx: 'a> : Sized { fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>>; - fn regions(&mut self, a: &'tcx ty::Region, b: &'tcx ty::Region) - -> RelateResult<'tcx, &'tcx ty::Region>; + fn regions(&mut self, a: ty::Region<'tcx>, b: ty::Region<'tcx>) + -> RelateResult<'tcx, ty::Region<'tcx>>; fn binders(&mut self, a: &ty::Binder, b: &ty::Binder) -> RelateResult<'tcx, ty::Binder> @@ -126,7 +126,7 @@ fn relate_item_substs<'a, 'gcx, 'tcx, R>(relation: &mut R, let variances; let opt_variances = if relation.tcx().variance_computed.get() { - variances = relation.tcx().item_variances(item_def_id); + variances = relation.tcx().variances_of(item_def_id); Some(&*variances) } else { None @@ -529,11 +529,11 @@ impl<'tcx> Relate<'tcx> for &'tcx Substs<'tcx> { } } -impl<'tcx> Relate<'tcx> for &'tcx ty::Region { +impl<'tcx> Relate<'tcx> for ty::Region<'tcx> { fn relate<'a, 'gcx, R>(relation: &mut R, - a: &&'tcx ty::Region, - b: &&'tcx ty::Region) - -> RelateResult<'tcx, &'tcx ty::Region> + a: &ty::Region<'tcx>, + b: &ty::Region<'tcx>) + -> RelateResult<'tcx, ty::Region<'tcx>> where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a { relation.regions(*a, *b) diff --git a/src/librustc/ty/steal.rs b/src/librustc/ty/steal.rs new file mode 100644 index 000000000000..0b0818888812 --- /dev/null +++ b/src/librustc/ty/steal.rs @@ -0,0 +1,57 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::cell::{Ref, RefCell}; +use std::mem; + +/// The `Steal` struct is intended to used as the value for a query. +/// Specifically, we sometimes have queries (*cough* MIR *cough*) +/// where we create a large, complex value that we want to iteratively +/// update (e.g., optimize). We could clone the value for each +/// optimization, but that'd be expensive. And yet we don't just want +/// to mutate it in place, because that would spoil the idea that +/// queries are these pure functions that produce an immutable value +/// (since if you did the query twice, you could observe the +/// mutations). So instead we have the query produce a `&'tcx +/// 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 +/// 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? +pub struct Steal { + value: RefCell> +} + +impl Steal { + pub fn new(value: T) -> Self { + Steal { + value: RefCell::new(Some(value)) + } + } + + pub fn borrow(&self) -> Ref { + Ref::map(self.value.borrow(), |opt| match *opt { + None => bug!("attempted to read from stolen value"), + Some(ref v) => v + }) + } + + pub fn steal(&self) -> T { + let value_ref = &mut *self.value.borrow_mut(); + let value = mem::replace(value_ref, None); + value.expect("attempt to read from stolen value") + } +} diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 49824e8a738d..53d516e581b2 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -111,6 +111,18 @@ impl<'a, 'tcx> Lift<'tcx> for ty::EquatePredicate<'a> { } } +impl<'a, 'tcx> Lift<'tcx> for ty::SubtypePredicate<'a> { + type Lifted = ty::SubtypePredicate<'tcx>; + fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) + -> Option> { + tcx.lift(&(self.a, self.b)).map(|(a, b)| ty::SubtypePredicate { + a_is_expected: self.a_is_expected, + a: a, + b: b, + }) + } +} + impl<'tcx, A: Copy+Lift<'tcx>, B: Copy+Lift<'tcx>> Lift<'tcx> for ty::OutlivesPredicate { type Lifted = ty::OutlivesPredicate; fn lift_to_tcx<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option { @@ -167,6 +179,9 @@ impl<'a, 'tcx> Lift<'tcx> for ty::Predicate<'a> { ty::Predicate::Equate(ref binder) => { tcx.lift(binder).map(ty::Predicate::Equate) } + ty::Predicate::Subtype(ref binder) => { + tcx.lift(binder).map(ty::Predicate::Subtype) + } ty::Predicate::RegionOutlives(ref binder) => { tcx.lift(binder).map(ty::Predicate::RegionOutlives) } @@ -293,11 +308,13 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> { RegionsNoOverlap(a, b) => { return tcx.lift(&(a, b)).map(|(a, b)| RegionsNoOverlap(a, b)) } - RegionsInsufficientlyPolymorphic(a, b) => { - return tcx.lift(&b).map(|b| RegionsInsufficientlyPolymorphic(a, b)) + RegionsInsufficientlyPolymorphic(a, b, ref c) => { + let c = c.clone(); + return tcx.lift(&b).map(|b| RegionsInsufficientlyPolymorphic(a, b, c)) } - RegionsOverlyPolymorphic(a, b) => { - return tcx.lift(&b).map(|b| RegionsOverlyPolymorphic(a, b)) + RegionsOverlyPolymorphic(a, b, ref c) => { + let c = c.clone(); + return tcx.lift(&b).map(|b| RegionsOverlyPolymorphic(a, b, c)) } IntMismatch(x) => IntMismatch(x), FloatMismatch(x) => FloatMismatch(x), @@ -607,7 +624,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ImplHeader<'tcx> { } } -impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Region { +impl<'tcx> TypeFoldable<'tcx> for ty::Region<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, _folder: &mut F) -> Self { *self } @@ -691,6 +708,8 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> { ty::Predicate::Trait(a.fold_with(folder)), ty::Predicate::Equate(ref binder) => ty::Predicate::Equate(binder.fold_with(folder)), + ty::Predicate::Subtype(ref binder) => + ty::Predicate::Subtype(binder.fold_with(folder)), ty::Predicate::RegionOutlives(ref binder) => ty::Predicate::RegionOutlives(binder.fold_with(folder)), ty::Predicate::TypeOutlives(ref binder) => @@ -710,6 +729,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> { match *self { ty::Predicate::Trait(ref a) => a.visit_with(visitor), ty::Predicate::Equate(ref binder) => binder.visit_with(visitor), + ty::Predicate::Subtype(ref binder) => binder.visit_with(visitor), ty::Predicate::RegionOutlives(ref binder) => binder.visit_with(visitor), ty::Predicate::TypeOutlives(ref binder) => binder.visit_with(visitor), ty::Predicate::Projection(ref binder) => binder.visit_with(visitor), @@ -774,8 +794,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::InstantiatedPredicates<'tcx> { impl<'tcx> TypeFoldable<'tcx> for ty::EquatePredicate<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - ty::EquatePredicate(self.0.fold_with(folder), - self.1.fold_with(folder)) + ty::EquatePredicate(self.0.fold_with(folder), self.1.fold_with(folder)) } fn super_visit_with>(&self, visitor: &mut V) -> bool { @@ -783,6 +802,20 @@ impl<'tcx> TypeFoldable<'tcx> for ty::EquatePredicate<'tcx> { } } +impl<'tcx> TypeFoldable<'tcx> for ty::SubtypePredicate<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + ty::SubtypePredicate { + a_is_expected: self.a_is_expected, + a: self.a.fold_with(folder), + b: self.b.fold_with(folder) + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.a.visit_with(visitor) || self.b.visit_with(visitor) + } +} + impl<'tcx> TypeFoldable<'tcx> for ty::TraitPredicate<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { ty::TraitPredicate { diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 0e3005847bc2..630e4a239cc6 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -43,8 +43,12 @@ pub struct TypeAndMut<'tcx> { RustcEncodable, RustcDecodable, Copy)] /// A "free" region `fr` can be interpreted as "some region /// at least as big as the scope `fr.scope`". -pub struct FreeRegion { - pub scope: region::CodeExtent, +/// +/// If `fr.scope` is None, then this is in some context (e.g., an +/// impl) where lifetimes are more abstract and the notion of the +/// caller/callee stack frames are not applicable. +pub struct FreeRegion<'tcx> { + pub scope: Option>, pub bound_region: BoundRegion, } @@ -68,6 +72,15 @@ pub enum BoundRegion { BrEnv, } +impl BoundRegion { + pub fn is_named(&self) -> bool { + match *self { + BoundRegion::BrNamed(..) => true, + _ => false, + } + } +} + /// When a region changed from late-bound to early-bound when #32330 /// was fixed, its `RegionParameterDef` will have one of these /// structures that we can use to give nicer errors. @@ -124,7 +137,7 @@ pub enum TypeVariants<'tcx> { /// A reference; a pointer with an associated lifetime. Written as /// `&'a mut T` or `&'a T`. - TyRef(&'tcx Region, TypeAndMut<'tcx>), + TyRef(Region<'tcx>, TypeAndMut<'tcx>), /// The anonymous type of a function declaration/definition. Each /// function has a unique type. @@ -136,7 +149,7 @@ pub enum TypeVariants<'tcx> { TyFnPtr(PolyFnSig<'tcx>), /// A trait, defined with `trait`. - TyDynamic(Binder<&'tcx Slice>>, &'tcx ty::Region), + TyDynamic(Binder<&'tcx Slice>>, ty::Region<'tcx>), /// The anonymous type of a closure. Used to represent the type of /// `|a| a`. @@ -262,7 +275,7 @@ impl<'a, 'gcx, 'acx, 'tcx> ClosureSubsts<'tcx> { pub fn upvar_tys(self, def_id: DefId, tcx: TyCtxt<'a, 'gcx, 'acx>) -> impl Iterator> + 'tcx { - let generics = tcx.item_generics(def_id); + let generics = tcx.generics_of(def_id); self.substs[self.substs.len()-generics.own_count()..].iter().map( |t| t.as_type().expect("unexpected region in upvars")) } @@ -285,7 +298,7 @@ impl<'a, 'gcx, 'tcx> ExistentialPredicate<'tcx> { (Trait(_), Trait(_)) => Ordering::Equal, (Projection(ref a), Projection(ref b)) => a.sort_key(tcx).cmp(&b.sort_key(tcx)), (AutoTrait(ref a), AutoTrait(ref b)) => - tcx.lookup_trait_def(*a).def_path_hash.cmp(&tcx.lookup_trait_def(*b).def_path_hash), + tcx.trait_def(*a).def_path_hash.cmp(&tcx.trait_def(*b).def_path_hash), (Trait(_), _) => Ordering::Less, (Projection(_), Trait(_)) => Ordering::Greater, (Projection(_), _) => Ordering::Less, @@ -675,6 +688,8 @@ pub struct DebruijnIndex { pub depth: u32, } +pub type Region<'tcx> = &'tcx RegionKind<'tcx>; + /// Representation of regions. /// /// Unlike types, most region variants are "fictitious", not concrete, @@ -732,7 +747,7 @@ pub struct DebruijnIndex { /// [1] http://smallcultfollowing.com/babysteps/blog/2013/10/29/intermingled-parameter-lists/ /// [2] http://smallcultfollowing.com/babysteps/blog/2013/11/04/intermingled-parameter-lists/ #[derive(Clone, PartialEq, Eq, Hash, Copy, RustcEncodable, RustcDecodable)] -pub enum Region { +pub enum RegionKind<'tcx> { // Region bound in a type or fn declaration which will be // substituted 'early' -- that is, at the same time when type // parameters are substituted. @@ -745,12 +760,12 @@ pub enum Region { /// When checking a function body, the types of all arguments and so forth /// that refer to bound region parameters are modified to refer to free /// region parameters. - ReFree(FreeRegion), + ReFree(FreeRegion<'tcx>), /// A concrete region naming some statically determined extent /// (e.g. an expression or sequence of statements) within the /// current function. - ReScope(region::CodeExtent), + ReScope(region::CodeExtent<'tcx>), /// Static data that has an "infinite" lifetime. Top in the region lattice. ReStatic, @@ -775,7 +790,7 @@ pub enum Region { ReErased, } -impl<'tcx> serialize::UseSpecializedDecodable for &'tcx Region {} +impl<'tcx> serialize::UseSpecializedDecodable for Region<'tcx> {} #[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)] pub struct EarlyBoundRegion { @@ -841,7 +856,7 @@ impl<'a, 'tcx, 'gcx> ExistentialProjection<'tcx> { // We want something here that is stable across crate boundaries. // The DefId isn't but the `deterministic_hash` of the corresponding // DefPath is. - let trait_def = tcx.lookup_trait_def(self.trait_ref.def_id); + let trait_def = tcx.trait_def(self.trait_ref.def_id); let def_path_hash = trait_def.def_path_hash; // An `ast::Name` is also not stable (it's just an index into an @@ -894,7 +909,7 @@ impl DebruijnIndex { } // Region utilities -impl Region { +impl<'tcx> RegionKind<'tcx> { pub fn is_bound(&self) -> bool { match *self { ty::ReEarlyBound(..) => true, @@ -918,7 +933,7 @@ impl Region { } /// Returns the depth of `self` from the (1-based) binding level `depth` - pub fn from_depth(&self, depth: u32) -> Region { + pub fn from_depth(&self, depth: u32) -> RegionKind<'tcx> { match *self { ty::ReLateBound(debruijn, r) => ty::ReLateBound(DebruijnIndex { depth: debruijn.depth - (depth - 1) @@ -1095,7 +1110,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { #[inline] pub fn is_simd(&self) -> bool { match self.sty { - TyAdt(def, _) => def.repr.simd, + TyAdt(def, _) => def.repr.simd(), _ => false, } } @@ -1193,6 +1208,13 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } + pub fn is_closure(&self) -> bool { + match self.sty { + TyClosure(..) => true, + _ => false, + } + } + pub fn is_integral(&self) -> bool { match self.sty { TyInfer(IntVar(_)) | TyInt(_) | TyUint(_) => true, @@ -1330,7 +1352,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { /// Returns the regions directly referenced from this type (but /// not types reachable from this type via `walk_tys`). This /// ignores late-bound regions binders. - pub fn regions(&self) -> Vec<&'tcx ty::Region> { + pub fn regions(&self) -> Vec> { match self.sty { TyRef(region, _) => { vec![region] diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index 0a2cc1c30f40..c591845dd63b 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -11,7 +11,7 @@ // Type substitutions. use hir::def_id::DefId; -use ty::{self, Slice, Ty, TyCtxt}; +use ty::{self, Slice, Region, Ty, TyCtxt}; use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use serialize::{self, Encodable, Encoder, Decodable, Decoder}; @@ -32,7 +32,7 @@ use std::mem; #[derive(Copy, Clone, PartialEq, Eq, Hash)] pub struct Kind<'tcx> { ptr: NonZero, - marker: PhantomData<(Ty<'tcx>, &'tcx ty::Region)> + marker: PhantomData<(Ty<'tcx>, ty::Region<'tcx>)> } const TAG_MASK: usize = 0b11; @@ -54,8 +54,8 @@ impl<'tcx> From> for Kind<'tcx> { } } -impl<'tcx> From<&'tcx ty::Region> for Kind<'tcx> { - fn from(r: &'tcx ty::Region) -> Kind<'tcx> { +impl<'tcx> From> for Kind<'tcx> { + fn from(r: ty::Region<'tcx>) -> Kind<'tcx> { // Ensure we can use the tag bits. assert_eq!(mem::align_of_val(r) & TAG_MASK, 0); @@ -88,7 +88,7 @@ impl<'tcx> Kind<'tcx> { } #[inline] - pub fn as_region(self) -> Option<&'tcx ty::Region> { + pub fn as_region(self) -> Option> { unsafe { self.downcast(REGION_TAG) } @@ -153,7 +153,7 @@ impl<'tcx> Decodable for Kind<'tcx> { d.read_enum_variant(&["Ty", "Region"], |d, tag| { match tag { TYPE_TAG => Ty::decode(d).map(Kind::from), - REGION_TAG => <&ty::Region>::decode(d).map(Kind::from), + REGION_TAG => Region::decode(d).map(Kind::from), _ => Err(d.error("invalid Kind tag")) } }) @@ -183,9 +183,9 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { mut mk_region: FR, mut mk_type: FT) -> &'tcx Substs<'tcx> - where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> &'tcx ty::Region, + where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> ty::Region<'tcx>, FT: FnMut(&ty::TypeParameterDef, &[Kind<'tcx>]) -> Ty<'tcx> { - let defs = tcx.item_generics(def_id); + let defs = tcx.generics_of(def_id); let mut substs = Vec::with_capacity(defs.count()); Substs::fill_item(&mut substs, tcx, defs, &mut mk_region, &mut mk_type); tcx.intern_substs(&substs) @@ -197,10 +197,10 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { mut mk_region: FR, mut mk_type: FT) -> &'tcx Substs<'tcx> - where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> &'tcx ty::Region, + where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> ty::Region<'tcx>, FT: FnMut(&ty::TypeParameterDef, &[Kind<'tcx>]) -> Ty<'tcx> { - let defs = tcx.item_generics(def_id); + let defs = tcx.generics_of(def_id); let mut result = Vec::with_capacity(defs.count()); result.extend(self[..].iter().cloned()); Substs::fill_single(&mut result, defs, &mut mk_region, &mut mk_type); @@ -212,11 +212,11 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { defs: &ty::Generics, mk_region: &mut FR, mk_type: &mut FT) - where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> &'tcx ty::Region, + where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> ty::Region<'tcx>, FT: FnMut(&ty::TypeParameterDef, &[Kind<'tcx>]) -> Ty<'tcx> { if let Some(def_id) = defs.parent { - let parent_defs = tcx.item_generics(def_id); + let parent_defs = tcx.generics_of(def_id); Substs::fill_item(substs, tcx, parent_defs, mk_region, mk_type); } Substs::fill_single(substs, defs, mk_region, mk_type) @@ -226,7 +226,7 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { defs: &ty::Generics, mk_region: &mut FR, mk_type: &mut FT) - where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> &'tcx ty::Region, + where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> ty::Region<'tcx>, FT: FnMut(&ty::TypeParameterDef, &[Kind<'tcx>]) -> Ty<'tcx> { // Handle Self first, before all regions. let mut types = defs.types.iter(); @@ -260,7 +260,7 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { } #[inline] - pub fn regions(&'a self) -> impl DoubleEndedIterator + 'a { + pub fn regions(&'a self) -> impl DoubleEndedIterator> + 'a { self.iter().filter_map(|k| k.as_region()) } @@ -272,7 +272,7 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { } #[inline] - pub fn region_at(&self, i: usize) -> &'tcx ty::Region { + pub fn region_at(&self, i: usize) -> ty::Region<'tcx> { self[i].as_region().unwrap_or_else(|| { bug!("expected region for param #{} in {:?}", i, self); }) @@ -284,7 +284,7 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { } #[inline] - pub fn region_for_def(&self, def: &ty::RegionParameterDef) -> &'tcx ty::Region { + pub fn region_for_def(&self, def: &ty::RegionParameterDef) -> ty::Region<'tcx> { self.region_at(def.index as usize) } @@ -297,7 +297,7 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { source_ancestor: DefId, target_substs: &Substs<'tcx>) -> &'tcx Substs<'tcx> { - let defs = tcx.item_generics(source_ancestor); + let defs = tcx.generics_of(source_ancestor); tcx.mk_substs(target_substs.iter().chain(&self[defs.own_count()..]).cloned()) } @@ -396,7 +396,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for SubstFolder<'a, 'gcx, 'tcx> { t } - fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region { + fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { // Note: This routine only handles regions that are bound on // type declarations and other outer declarations, not those // bound in *fn types*. Region substitution of the bound @@ -538,7 +538,10 @@ impl<'a, 'gcx, 'tcx> SubstFolder<'a, 'gcx, 'tcx> { result } - fn shift_region_through_binders(&self, region: &'tcx ty::Region) -> &'tcx ty::Region { + fn shift_region_through_binders(&self, region: ty::Region<'tcx>) -> ty::Region<'tcx> { + if self.region_binders_passed == 0 || !region.has_escaping_regions() { + return region; + } self.tcx().mk_region(ty::fold::shift_region(*region, self.region_binders_passed)) } } @@ -550,7 +553,7 @@ impl<'a, 'gcx, 'tcx> ty::TraitRef<'tcx> { trait_id: DefId, substs: &Substs<'tcx>) -> ty::TraitRef<'tcx> { - let defs = tcx.item_generics(trait_id); + let defs = tcx.generics_of(trait_id); ty::TraitRef { def_id: trait_id, diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 1c1e0d91cb4d..24dfae3c5406 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -13,20 +13,21 @@ use hir::def_id::{DefId, LOCAL_CRATE}; use hir::map::DefPathData; use infer::InferCtxt; -use hir::map as hir_map; +use ich::{StableHashingContext, NodeIdHashingMode}; use traits::{self, Reveal}; use ty::{self, Ty, TyCtxt, TypeAndMut, TypeFlags, TypeFoldable}; use ty::ParameterEnvironment; use ty::fold::TypeVisitor; use ty::layout::{Layout, LayoutError}; +use ty::subst::{Subst, Kind}; use ty::TypeVariants::*; use util::common::ErrorReported; -use util::nodemap::FxHashMap; +use util::nodemap::{FxHashMap, FxHashSet}; use middle::lang_items; use rustc_const_math::{ConstInt, ConstIsize, ConstUsize}; -use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult}; - +use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult, + HashStable}; use std::cell::RefCell; use std::cmp; use std::hash::Hash; @@ -187,6 +188,22 @@ impl<'tcx> ParameterEnvironment<'tcx> { } } +impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { + /// Creates a hash of the type `Ty` which will be the same no matter what crate + /// context it's calculated within. This is used by the `type_id` intrinsic. + pub fn type_id_hash(self, ty: Ty<'tcx>) -> u64 { + let mut hasher = StableHasher::new(); + let mut hcx = StableHashingContext::new(self); + + hcx.while_hashing_spans(false, |hcx| { + hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { + ty.hash_stable(hcx, &mut hasher); + }); + }); + hasher.finish() + } +} + impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn has_error_field(self, ty: Ty<'tcx>) -> bool { match ty.sty { @@ -296,10 +313,13 @@ 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. pub fn required_region_bounds(self, erased_self_ty: Ty<'tcx>, predicates: Vec>) - -> Vec<&'tcx ty::Region> { + -> Vec> { debug!("required_region_bounds(erased_self_ty={:?}, predicates={:?})", erased_self_ty, predicates); @@ -312,6 +332,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { ty::Predicate::Projection(..) | ty::Predicate::Trait(..) | ty::Predicate::Equate(..) | + ty::Predicate::Subtype(..) | ty::Predicate::WellFormed(..) | ty::Predicate::ObjectSafe(..) | ty::Predicate::ClosureKind(..) | @@ -339,14 +360,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { .collect() } - /// Creates a hash of the type `Ty` which will be the same no matter what crate - /// context it's calculated within. This is used by the `type_id` intrinsic. - pub fn type_id_hash(self, ty: Ty<'tcx>) -> u64 { - let mut hasher = TypeIdHasher::new(self); - hasher.visit_ty(ty); - hasher.finish() - } - /// Calculate the destructor of a given type. pub fn calculate_dtor( self, @@ -359,11 +372,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { return None; }; - ty::queries::coherent_trait::get(self, DUMMY_SP, (LOCAL_CRATE, drop_trait)); + self.coherent_trait((LOCAL_CRATE, drop_trait)); let mut dtor_did = None; - let ty = self.item_type(adt_did); - self.lookup_trait_def(drop_trait).for_each_relevant_impl(self, ty, |impl_did| { + let ty = self.type_of(adt_did); + self.trait_def(drop_trait).for_each_relevant_impl(self, ty, |impl_did| { if let Some(item) = self.associated_items(impl_did).next() { if let Ok(()) = validate(self, impl_did) { dtor_did = Some(item.def_id); @@ -376,6 +389,27 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { None => return None, }; + Some(ty::Destructor { did: dtor_did }) + } + + /// Return the set of types that are required to be alive in + /// order to run the destructor of `def` (see RFCs 769 and + /// 1238). + /// + /// Note that this returns only the constraints for the + /// destructor of `def` itself. For the destructors of the + /// contents, you need `adt_dtorck_constraint`. + pub fn destructor_constraints(self, def: &'tcx ty::AdtDef) + -> Vec> + { + let dtor = match def.destructor(self) { + None => { + debug!("destructor_constraints({:?}) - no dtor", def.did); + return vec![] + } + Some(dtor) => dtor.did + }; + // RFC 1238: if the destructor method is tagged with the // attribute `unsafe_destructor_blind_to_params`, then the // compiler is being instructed to *assume* that the @@ -385,11 +419,147 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // Such access can be in plain sight (e.g. dereferencing // `*foo.0` of `Foo<'a>(&'a u32)`) or indirectly hidden // (e.g. calling `foo.0.clone()` of `Foo`). - let is_dtorck = !self.has_attr(dtor_did, "unsafe_destructor_blind_to_params"); - Some(ty::Destructor { did: dtor_did, is_dtorck: is_dtorck }) + if self.has_attr(dtor, "unsafe_destructor_blind_to_params") { + debug!("destructor_constraint({:?}) - blind", def.did); + return vec![]; + } + + let impl_def_id = self.associated_item(dtor).container.id(); + let impl_generics = self.generics_of(impl_def_id); + + // We have a destructor - all the parameters that are not + // pure_wrt_drop (i.e, don't have a #[may_dangle] attribute) + // must be live. + + // We need to return the list of parameters from the ADTs + // generics/substs that correspond to impure parameters on the + // impl's generics. This is a bit ugly, but conceptually simple: + // + // Suppose our ADT looks like the following + // + // struct S(X, Y, Z); + // + // and the impl is + // + // impl<#[may_dangle] P0, P1, P2> Drop for S + // + // We want to return the parameters (X, Y). For that, we match + // up the item-substs with the substs on the impl ADT, + // , and then look up which of the impl substs refer to + // parameters marked as pure. + + let impl_substs = match self.type_of(impl_def_id).sty { + ty::TyAdt(def_, substs) if def_ == def => substs, + _ => bug!() + }; + + let item_substs = match self.type_of(def.did).sty { + ty::TyAdt(def_, substs) if def_ == def => substs, + _ => bug!() + }; + + let result = item_substs.iter().zip(impl_substs.iter()) + .filter(|&(_, &k)| { + if let Some(&ty::RegionKind::ReEarlyBound(ref ebr)) = k.as_region() { + !impl_generics.region_param(ebr).pure_wrt_drop + } else if let Some(&ty::TyS { + sty: ty::TypeVariants::TyParam(ref pt), .. + }) = k.as_type() { + !impl_generics.type_param(pt).pure_wrt_drop + } else { + // not a type or region param - this should be reported + // as an error. + false + } + }).map(|(&item_param, _)| item_param).collect(); + debug!("destructor_constraint({:?}) = {:?}", def.did, result); + result } - pub fn closure_base_def_id(&self, def_id: DefId) -> DefId { + /// Return a set of constraints that needs to be satisfied in + /// order for `ty` to be valid for destruction. + pub fn dtorck_constraint_for_ty(self, + span: Span, + for_ty: Ty<'tcx>, + depth: usize, + ty: Ty<'tcx>) + -> Result, ErrorReported> + { + debug!("dtorck_constraint_for_ty({:?}, {:?}, {:?}, {:?})", + span, for_ty, depth, ty); + + if depth >= self.sess.recursion_limit.get() { + let mut err = struct_span_err!( + self.sess, span, E0320, + "overflow while adding drop-check rules for {}", for_ty); + err.note(&format!("overflowed on {}", ty)); + err.emit(); + return Err(ErrorReported); + } + + let result = match ty.sty { + ty::TyBool | ty::TyChar | ty::TyInt(_) | ty::TyUint(_) | + ty::TyFloat(_) | ty::TyStr | ty::TyNever | + ty::TyRawPtr(..) | ty::TyRef(..) | ty::TyFnDef(..) | ty::TyFnPtr(_) => { + // these types never have a destructor + Ok(ty::DtorckConstraint::empty()) + } + + ty::TyArray(ety, _) | ty::TySlice(ety) => { + // single-element containers, behave like their element + self.dtorck_constraint_for_ty(span, for_ty, depth+1, ety) + } + + ty::TyTuple(tys, _) => { + tys.iter().map(|ty| { + self.dtorck_constraint_for_ty(span, for_ty, depth+1, ty) + }).collect() + } + + ty::TyClosure(def_id, substs) => { + substs.upvar_tys(def_id, self).map(|ty| { + self.dtorck_constraint_for_ty(span, for_ty, depth+1, ty) + }).collect() + } + + ty::TyAdt(def, substs) => { + let ty::DtorckConstraint { + dtorck_types, outlives + } = self.at(span).adt_dtorck_constraint(def.did); + Ok(ty::DtorckConstraint { + // FIXME: we can try to recursively `dtorck_constraint_on_ty` + // there, but that needs some way to handle cycles. + dtorck_types: dtorck_types.subst(self, substs), + outlives: outlives.subst(self, substs) + }) + } + + // Objects must be alive in order for their destructor + // to be called. + ty::TyDynamic(..) => Ok(ty::DtorckConstraint { + outlives: vec![Kind::from(ty)], + dtorck_types: vec![], + }), + + // Types that can't be resolved. Pass them forward. + ty::TyProjection(..) | ty::TyAnon(..) | ty::TyParam(..) => { + Ok(ty::DtorckConstraint { + outlives: vec![], + dtorck_types: vec![ty], + }) + } + + ty::TyInfer(..) | ty::TyError => { + self.sess.delay_span_bug(span, "unresolved type in dtorck"); + Err(ErrorReported) + } + }; + + debug!("dtorck_constraint_for_ty({:?}) = {:?}", ty, result); + result + } + + pub fn closure_base_def_id(self, def_id: DefId) -> DefId { let mut def_id = def_id; while self.def_key(def_id).disambiguated_data.data == DefPathData::ClosureExpr { def_id = self.parent_def_id(def_id).unwrap_or_else(|| { @@ -403,7 +573,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// a suitable "empty substs" for it. pub fn empty_substs_for_def_id(self, item_def_id: DefId) -> &'tcx ty::Substs<'tcx> { ty::Substs::for_item(self, item_def_id, - |_, _| self.mk_region(ty::ReErased), + |_, _| self.types.re_erased, |_, _| { bug!("empty_substs_for_def_id: {:?} has type parameters", item_def_id) }) @@ -441,13 +611,11 @@ impl<'a, 'gcx, 'tcx, W> TypeIdHasher<'a, 'gcx, 'tcx, W> fn def_id(&mut self, did: DefId) { // Hash the DefPath corresponding to the DefId, which is independent - // of compiler internal state. - let path = self.tcx.def_path(did); - self.def_path(&path) - } - - pub fn def_path(&mut self, def_path: &hir_map::DefPath) { - def_path.deterministic_hash_to(self.tcx, &mut self.state); + // of compiler internal state. We already have a stable hash value of + // all DefPaths available via tcx.def_path_hash(), so we just feed that + // into the hasher. + let hash = self.tcx.def_path_hash(did); + self.hash(hash); } } @@ -508,7 +676,7 @@ impl<'a, 'gcx, 'tcx, W> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx, W> ty.super_visit_with(self) } - fn visit_region(&mut self, r: &'tcx ty::Region) -> bool { + fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { self.hash_discriminant_u8(r); match *r { ty::ReErased | @@ -648,6 +816,165 @@ impl<'a, 'tcx> ty::TyS<'tcx> { result } + /// Returns `true` if and only if there are no `UnsafeCell`s + /// nested within the type (ignoring `PhantomData` or pointers). + #[inline] + pub fn is_freeze(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, + param_env: &ParameterEnvironment<'tcx>, + span: Span) -> bool + { + if self.flags.get().intersects(TypeFlags::FREEZENESS_CACHED) { + return self.flags.get().intersects(TypeFlags::IS_FREEZE); + } + + self.is_freeze_uncached(tcx, param_env, span) + } + + fn is_freeze_uncached(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, + param_env: &ParameterEnvironment<'tcx>, + span: Span) -> bool { + assert!(!self.needs_infer()); + + // Fast-path for primitive types + let result = match self.sty { + TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | + TyRawPtr(..) | TyRef(..) | TyFnDef(..) | TyFnPtr(_) | + TyStr | TyNever => Some(true), + + TyArray(..) | TySlice(_) | + TyTuple(..) | TyClosure(..) | TyAdt(..) | + TyDynamic(..) | TyProjection(..) | TyParam(..) | + TyInfer(..) | TyAnon(..) | TyError => None + }.unwrap_or_else(|| { + self.impls_bound(tcx, param_env, tcx.require_lang_item(lang_items::FreezeTraitLangItem), + ¶m_env.is_freeze_cache, span) }); + + if !self.has_param_types() && !self.has_self_ty() { + self.flags.set(self.flags.get() | if result { + TypeFlags::FREEZENESS_CACHED | TypeFlags::IS_FREEZE + } else { + TypeFlags::FREEZENESS_CACHED + }); + } + + result + } + + /// If `ty.needs_drop(...)` returns `true`, then `ty` is definitely + /// non-copy and *might* have a destructor attached; if it returns + /// `false`, then `ty` definitely has no destructor (i.e. no drop glue). + /// + /// (Note that this implies that if `ty` has a destructor attached, + /// then `needs_drop` will definitely return `true` for `ty`.) + #[inline] + pub fn needs_drop(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, + param_env: &ty::ParameterEnvironment<'tcx>) -> bool { + if self.flags.get().intersects(TypeFlags::NEEDS_DROP_CACHED) { + return self.flags.get().intersects(TypeFlags::NEEDS_DROP); + } + + self.needs_drop_uncached(tcx, param_env, &mut FxHashSet()) + } + + fn needs_drop_inner(&'tcx self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + param_env: &ty::ParameterEnvironment<'tcx>, + stack: &mut FxHashSet>) + -> bool { + if self.flags.get().intersects(TypeFlags::NEEDS_DROP_CACHED) { + return self.flags.get().intersects(TypeFlags::NEEDS_DROP); + } + + // This should be reported as an error by `check_representable`. + // + // Consider the type as not needing drop in the meanwhile to avoid + // further errors. + if let Some(_) = stack.replace(self) { + return false; + } + + let needs_drop = self.needs_drop_uncached(tcx, param_env, stack); + + // "Pop" the cycle detection "stack". + stack.remove(self); + + needs_drop + } + + fn needs_drop_uncached(&'tcx self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + param_env: &ty::ParameterEnvironment<'tcx>, + stack: &mut FxHashSet>) + -> bool { + assert!(!self.needs_infer()); + + let result = match self.sty { + // Fast-path for primitive types + ty::TyInfer(ty::FreshIntTy(_)) | ty::TyInfer(ty::FreshFloatTy(_)) | + ty::TyBool | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) | ty::TyNever | + ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyChar | + ty::TyRawPtr(_) | ty::TyRef(..) | ty::TyStr => false, + + // Issue #22536: We first query type_moves_by_default. It sees a + // normalized version of the type, and therefore will definitely + // know whether the type implements Copy (and thus needs no + // cleanup/drop/zeroing) ... + _ if !self.moves_by_default(tcx, param_env, DUMMY_SP) => false, + + // ... (issue #22536 continued) but as an optimization, still use + // prior logic of asking for the structural "may drop". + + // FIXME(#22815): Note that this is a conservative heuristic; + // it may report that the type "may drop" when actual type does + // not actually have a destructor associated with it. But since + // the type absolutely did not have the `Copy` bound attached + // (see above), it is sound to treat it as having a destructor. + + // User destructors are the only way to have concrete drop types. + ty::TyAdt(def, _) if def.has_dtor(tcx) => true, + + // Can refer to a type which may drop. + // FIXME(eddyb) check this against a ParameterEnvironment. + ty::TyDynamic(..) | ty::TyProjection(..) | ty::TyParam(_) | + ty::TyAnon(..) | ty::TyInfer(_) | ty::TyError => true, + + // Structural recursion. + ty::TyArray(ty, _) | ty::TySlice(ty) => { + ty.needs_drop_inner(tcx, param_env, stack) + } + + ty::TyClosure(def_id, ref substs) => { + substs.upvar_tys(def_id, tcx) + .any(|ty| ty.needs_drop_inner(tcx, param_env, stack)) + } + + ty::TyTuple(ref tys, _) => { + tys.iter().any(|ty| ty.needs_drop_inner(tcx, param_env, stack)) + } + + // unions don't have destructors regardless of the child types + ty::TyAdt(def, _) if def.is_union() => false, + + ty::TyAdt(def, substs) => { + def.variants.iter().any(|v| { + v.fields.iter().any(|f| { + f.ty(tcx, substs).needs_drop_inner(tcx, param_env, stack) + }) + }) + } + }; + + if !self.has_param_types() && !self.has_self_ty() { + self.flags.set(self.flags.get() | if result { + TypeFlags::NEEDS_DROP_CACHED | TypeFlags::NEEDS_DROP + } else { + TypeFlags::NEEDS_DROP_CACHED + }); + } + + result + } + #[inline] pub fn layout<'lcx>(&'tcx self, infcx: &InferCtxt<'a, 'tcx, 'lcx>) -> Result<&'tcx Layout, LayoutError<'tcx>> { diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index 8a5bd6862cf4..d0cbbaf2c10b 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -94,6 +94,10 @@ pub fn predicate_obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, } ty::Predicate::ClosureKind(..) => { } + ty::Predicate::Subtype(ref data) => { + wf.compute(data.skip_binder().a); // (*) + wf.compute(data.skip_binder().b); // (*) + } } wf.normalize() @@ -112,9 +116,9 @@ pub fn predicate_obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, /// For `&'a T` to be WF, `T: 'a` must hold. So we can assume `T: 'a`. #[derive(Debug)] pub enum ImpliedBound<'tcx> { - RegionSubRegion(&'tcx ty::Region, &'tcx ty::Region), - RegionSubParam(&'tcx ty::Region, ty::ParamTy), - RegionSubProjection(&'tcx ty::Region, ty::ProjectionTy<'tcx>), + RegionSubRegion(ty::Region<'tcx>, ty::Region<'tcx>), + RegionSubParam(ty::Region<'tcx>, ty::ParamTy), + RegionSubProjection(ty::Region<'tcx>, ty::ProjectionTy<'tcx>), } /// Compute the implied bounds that a callee/impl can assume based on @@ -156,6 +160,7 @@ pub fn implied_bounds<'a, 'gcx, 'tcx>( match obligation.predicate { ty::Predicate::Trait(..) | ty::Predicate::Equate(..) | + ty::Predicate::Subtype(..) | ty::Predicate::Projection(..) | ty::Predicate::ClosureKind(..) | ty::Predicate::ObjectSafe(..) => @@ -193,7 +198,7 @@ pub fn implied_bounds<'a, 'gcx, 'tcx>( /// this down to determine what relationships would have to hold for /// `T: 'a` to hold. We get to assume that the caller has validated /// those relationships. -fn implied_bounds_from_components<'tcx>(sub_region: &'tcx ty::Region, +fn implied_bounds_from_components<'tcx>(sub_region: ty::Region<'tcx>, sup_components: Vec>) -> Vec> { @@ -438,7 +443,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { -> Vec> { let predicates = - self.infcx.tcx.item_predicates(def_id) + self.infcx.tcx.predicates_of(def_id) .instantiate(self.infcx.tcx, substs); let cause = self.cause(traits::ItemObligation(def_id)); predicates.predicates @@ -450,7 +455,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { fn from_object_ty(&mut self, ty: Ty<'tcx>, data: ty::Binder<&'tcx ty::Slice>>, - region: &'tcx ty::Region) { + region: ty::Region<'tcx>) { // Imagine a type like this: // // trait Foo { } @@ -507,7 +512,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { pub fn object_region_bounds<'a, 'gcx, 'tcx>( tcx: TyCtxt<'a, 'gcx, 'tcx>, existential_predicates: ty::Binder<&'tcx ty::Slice>>) - -> Vec<&'tcx ty::Region> + -> Vec> { // Since we don't actually *know* the self type for an object, // this "open(err)" serves as a kind of dummy standin -- basically diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 6323f1dc0d4c..d773bb2da089 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -104,7 +104,7 @@ pub fn parameterized(f: &mut fmt::Formatter, } } } - let mut generics = tcx.item_generics(item_def_id); + let mut generics = tcx.generics_of(item_def_id); let mut path_def_id = did; verbose = tcx.sess.verbose(); has_self = generics.has_self; @@ -114,7 +114,7 @@ pub fn parameterized(f: &mut fmt::Formatter, // Methods. assert!(is_value_path); child_types = generics.types.len(); - generics = tcx.item_generics(def_id); + generics = tcx.generics_of(def_id); num_regions = generics.regions.len(); num_types = generics.types.len(); @@ -144,7 +144,7 @@ pub fn parameterized(f: &mut fmt::Formatter, if !def.has_default { break; } - if tcx.item_type(def.def_id).subst(tcx, substs) != actual { + if tcx.type_of(def.def_id).subst(tcx, substs) != actual { break; } num_supplied_defaults += 1; @@ -177,12 +177,12 @@ pub fn parameterized(f: &mut fmt::Formatter, let print_regions = |f: &mut fmt::Formatter, start: &str, skip, count| { // Don't print any regions if they're all erased. let regions = || substs.regions().skip(skip).take(count); - if regions().all(|r: &ty::Region| *r == ty::ReErased) { + if regions().all(|r: ty::Region| *r == ty::ReErased) { return Ok(()); } for region in regions() { - let region: &ty::Region = region; + let region: ty::Region = region; start_or_continue(f, start, ", ")?; if verbose { write!(f, "{:?}", region)?; @@ -416,6 +416,7 @@ impl<'tcx> fmt::Debug for ty::Predicate<'tcx> { match *self { ty::Predicate::Trait(ref a) => write!(f, "{:?}", a), ty::Predicate::Equate(ref pair) => write!(f, "{:?}", pair), + ty::Predicate::Subtype(ref pair) => write!(f, "{:?}", pair), ty::Predicate::RegionOutlives(ref pair) => write!(f, "{:?}", pair), ty::Predicate::TypeOutlives(ref pair) => write!(f, "{:?}", pair), ty::Predicate::Projection(ref pair) => write!(f, "{:?}", pair), @@ -457,7 +458,7 @@ impl fmt::Debug for ty::BoundRegion { } } -impl fmt::Debug for ty::Region { +impl<'tcx> fmt::Debug for ty::RegionKind<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { ty::ReEarlyBound(ref data) => { @@ -515,7 +516,7 @@ impl<'tcx> fmt::Debug for ty::ParameterEnvironment<'tcx> { } } -impl fmt::Display for ty::Region { +impl<'tcx> fmt::Display for ty::RegionKind<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { if verbose() { return write!(f, "{:?}", *self); @@ -543,7 +544,7 @@ impl fmt::Display for ty::Region { } } -impl fmt::Debug for ty::FreeRegion { +impl<'tcx> fmt::Debug for ty::FreeRegion<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "ReFree({:?}, {:?})", self.scope, self.bound_region) @@ -676,20 +677,26 @@ impl<'tcx> fmt::Display for ty::Binder> { } } +impl<'tcx> fmt::Display for ty::Binder> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self))) + } +} + impl<'tcx> fmt::Display for ty::Binder> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self))) } } -impl<'tcx> fmt::Display for ty::Binder, &'tcx ty::Region>> { +impl<'tcx> fmt::Display for ty::Binder, ty::Region<'tcx>>> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self))) } } -impl<'tcx> fmt::Display for ty::Binder> { +impl<'tcx> fmt::Display for ty::Binder, + ty::Region<'tcx>>> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self))) } @@ -765,11 +772,11 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> { ty::tls::with(|tcx| { // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`, // by looking up the projections associated with the def_id. - let item_predicates = tcx.item_predicates(def_id); + let predicates_of = tcx.predicates_of(def_id); let substs = tcx.lift(&substs).unwrap_or_else(|| { tcx.intern_substs(&[]) }); - let bounds = item_predicates.instantiate(tcx, substs); + let bounds = predicates_of.instantiate(tcx, substs); let mut first = true; let mut is_sized = false; @@ -897,6 +904,12 @@ impl<'tcx> fmt::Display for ty::EquatePredicate<'tcx> { } } +impl<'tcx> fmt::Display for ty::SubtypePredicate<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{} <: {}", self.a, self.b) + } +} + impl<'tcx> fmt::Debug for ty::TraitPredicate<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "TraitPredicate({:?})", @@ -949,6 +962,7 @@ impl<'tcx> fmt::Display for ty::Predicate<'tcx> { match *self { ty::Predicate::Trait(ref data) => write!(f, "{}", data), ty::Predicate::Equate(ref predicate) => write!(f, "{}", predicate), + ty::Predicate::Subtype(ref predicate) => write!(f, "{}", predicate), ty::Predicate::RegionOutlives(ref predicate) => write!(f, "{}", predicate), ty::Predicate::TypeOutlives(ref predicate) => write!(f, "{}", predicate), ty::Predicate::Projection(ref predicate) => write!(f, "{}", predicate), diff --git a/src/librustc_asan/build.rs b/src/librustc_asan/build.rs index 2df2e001e6ff..3a80baa0485f 100644 --- a/src/librustc_asan/build.rs +++ b/src/librustc_asan/build.rs @@ -12,14 +12,13 @@ extern crate build_helper; extern crate cmake; use std::env; -use build_helper::native_lib_boilerplate; +use build_helper::sanitizer_lib_boilerplate; use cmake::Config; fn main() { if let Some(llvm_config) = env::var_os("LLVM_CONFIG") { - let native = match native_lib_boilerplate("compiler-rt", "asan", "clang_rt.asan-x86_64", - "build/lib/linux") { + let native = match sanitizer_lib_boilerplate("asan") { Ok(native) => native, _ => return, }; diff --git a/src/librustc_asan/lib.rs b/src/librustc_asan/lib.rs index 71a166b91ebc..54941362e845 100644 --- a/src/librustc_asan/lib.rs +++ b/src/librustc_asan/lib.rs @@ -8,8 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![cfg_attr(not(stage0), feature(sanitizer_runtime))] -#![cfg_attr(not(stage0), sanitizer_runtime)] +#![sanitizer_runtime] +#![feature(sanitizer_runtime)] #![feature(alloc_system)] #![feature(staged_api)] #![no_std] diff --git a/src/librustc_back/Cargo.toml b/src/librustc_back/Cargo.toml index 85e861b405a9..730abc54568e 100644 --- a/src/librustc_back/Cargo.toml +++ b/src/librustc_back/Cargo.toml @@ -11,7 +11,7 @@ crate-type = ["dylib"] [dependencies] syntax = { path = "../libsyntax" } serialize = { path = "../libserialize" } -log = { path = "../liblog" } +log = "0.3" [features] jemalloc = [] diff --git a/src/librustc_back/dynamic_lib.rs b/src/librustc_back/dynamic_lib.rs index 38e60060925e..e6f305c22b2d 100644 --- a/src/librustc_back/dynamic_lib.rs +++ b/src/librustc_back/dynamic_lib.rs @@ -68,6 +68,8 @@ impl DynamicLibrary { "PATH" } else if cfg!(target_os = "macos") { "DYLD_LIBRARY_PATH" + } else if cfg!(target_os = "haiku") { + "LIBRARY_PATH" } else { "LD_LIBRARY_PATH" } diff --git a/src/librustc_back/lib.rs b/src/librustc_back/lib.rs index 000e4eb59bf0..6679cc73029c 100644 --- a/src/librustc_back/lib.rs +++ b/src/librustc_back/lib.rs @@ -52,6 +52,48 @@ pub mod dynamic_lib; use serialize::json::{Json, ToJson}; +macro_rules! linker_flavor { + ($(($variant:ident, $string:expr),)+) => { + #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, Hash, + RustcEncodable, RustcDecodable)] + pub enum LinkerFlavor { + $($variant,)+ + } + + impl LinkerFlavor { + pub const fn one_of() -> &'static str { + concat!("one of: ", $($string, " ",)+) + } + + pub fn from_str(s: &str) -> Option { + Some(match s { + $($string => LinkerFlavor::$variant,)+ + _ => return None, + }) + } + + pub fn desc(&self) -> &str { + match *self { + $(LinkerFlavor::$variant => $string,)+ + } + } + } + + impl ToJson for LinkerFlavor { + fn to_json(&self) -> Json { + self.desc().to_json() + } + } + } +} + +linker_flavor! { + (Em, "em"), + (Gcc, "gcc"), + (Ld, "ld"), + (Msvc, "msvc"), +} + #[derive(Clone, Copy, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)] pub enum PanicStrategy { Unwind, diff --git a/src/librustc_back/target/aarch64_apple_ios.rs b/src/librustc_back/target/aarch64_apple_ios.rs index 5ef79359140f..802a8c77db05 100644 --- a/src/librustc_back/target/aarch64_apple_ios.rs +++ b/src/librustc_back/target/aarch64_apple_ios.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; use super::apple_ios_base::{opts, Arch}; @@ -22,6 +23,7 @@ pub fn target() -> TargetResult { target_os: "ios".to_string(), target_env: "".to_string(), target_vendor: "apple".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { features: "+neon,+fp-armv8,+cyclone".to_string(), eliminate_frame_pointer: false, diff --git a/src/librustc_back/target/aarch64_linux_android.rs b/src/librustc_back/target/aarch64_linux_android.rs index 54eead94986c..7d8610b4a368 100644 --- a/src/librustc_back/target/aarch64_linux_android.rs +++ b/src/librustc_back/target/aarch64_linux_android.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; // See https://developer.android.com/ndk/guides/abis.html#arm64-v8a @@ -28,6 +29,7 @@ pub fn target() -> TargetResult { target_os: "android".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { abi_blacklist: super::arm_base::abi_blacklist(), .. base diff --git a/src/librustc_back/target/aarch64_unknown_freebsd.rs b/src/librustc_back/target/aarch64_unknown_freebsd.rs index 3c5d6308ee6b..c5cfff0be03a 100644 --- a/src/librustc_back/target/aarch64_unknown_freebsd.rs +++ b/src/librustc_back/target/aarch64_unknown_freebsd.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -26,6 +27,7 @@ pub fn target() -> TargetResult { target_os: "freebsd".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { abi_blacklist: super::arm_base::abi_blacklist(), .. base diff --git a/src/librustc_back/target/aarch64_unknown_fuchsia.rs b/src/librustc_back/target/aarch64_unknown_fuchsia.rs index 6ba1732e67f7..5d680504a02d 100644 --- a/src/librustc_back/target/aarch64_unknown_fuchsia.rs +++ b/src/librustc_back/target/aarch64_unknown_fuchsia.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -23,6 +24,7 @@ pub fn target() -> TargetResult { target_os: "fuchsia".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { abi_blacklist: super::arm_base::abi_blacklist(), .. base diff --git a/src/librustc_back/target/aarch64_unknown_linux_gnu.rs b/src/librustc_back/target/aarch64_unknown_linux_gnu.rs index 5f6335d405f5..043bd881c729 100644 --- a/src/librustc_back/target/aarch64_unknown_linux_gnu.rs +++ b/src/librustc_back/target/aarch64_unknown_linux_gnu.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -26,6 +27,7 @@ pub fn target() -> TargetResult { arch: "aarch64".to_string(), target_os: "linux".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { abi_blacklist: super::arm_base::abi_blacklist(), .. base diff --git a/src/librustc_back/target/android_base.rs b/src/librustc_back/target/android_base.rs index 9791520e9339..49baa1b96cee 100644 --- a/src/librustc_back/target/android_base.rs +++ b/src/librustc_back/target/android_base.rs @@ -8,13 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::TargetOptions; pub fn opts() -> TargetOptions { let mut base = super::linux_base::opts(); // Many of the symbols defined in compiler-rt are also defined in libgcc. // Android's linker doesn't like that by default. - base.pre_link_args.push("-Wl,--allow-multiple-definition".to_string()); + base.pre_link_args + .get_mut(&LinkerFlavor::Gcc).unwrap().push("-Wl,--allow-multiple-definition".to_string()); base.is_like_android = true; base.position_independent_executables = true; base.has_elf_tls = false; diff --git a/src/librustc_back/target/apple_base.rs b/src/librustc_back/target/apple_base.rs index 3a551a2b124b..159f93a74c68 100644 --- a/src/librustc_back/target/apple_base.rs +++ b/src/librustc_back/target/apple_base.rs @@ -10,7 +10,7 @@ use std::env; -use target::TargetOptions; +use target::{LinkArgs, TargetOptions}; pub fn opts() -> TargetOptions { // ELF TLS is only available in macOS 10.7+. If you try to compile for 10.6 @@ -43,7 +43,7 @@ pub fn opts() -> TargetOptions { dll_prefix: "lib".to_string(), dll_suffix: ".dylib".to_string(), archive_format: "bsd".to_string(), - pre_link_args: Vec::new(), + pre_link_args: LinkArgs::new(), exe_allocation_crate: super::maybe_jemalloc(), has_elf_tls: version >= (10, 7), .. Default::default() diff --git a/src/librustc_back/target/apple_ios_base.rs b/src/librustc_back/target/apple_ios_base.rs index 17492b8bdcb6..2e7d30d969ec 100644 --- a/src/librustc_back/target/apple_ios_base.rs +++ b/src/librustc_back/target/apple_ios_base.rs @@ -8,9 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use std::io; use std::process::Command; -use target::TargetOptions; +use target::{LinkArgs, TargetOptions}; use self::Arch::*; @@ -60,7 +61,7 @@ pub fn get_sdk_root(sdk_name: &str) -> Result { } } -fn build_pre_link_args(arch: Arch) -> Result, String> { +fn build_pre_link_args(arch: Arch) -> Result { let sdk_name = match arch { Armv7 | Armv7s | Arm64 => "iphoneos", I386 | X86_64 => "iphonesimulator" @@ -70,8 +71,14 @@ fn build_pre_link_args(arch: Arch) -> Result, String> { let sdk_root = get_sdk_root(sdk_name)?; - Ok(vec!["-arch".to_string(), arch_name.to_string(), - "-Wl,-syslibroot".to_string(), sdk_root]) + let mut args = LinkArgs::new(); + args.insert(LinkerFlavor::Gcc, + vec!["-arch".to_string(), + arch_name.to_string(), + "-Wl,-syslibroot".to_string(), + sdk_root]); + + Ok(args) } fn target_cpu(arch: Arch) -> String { diff --git a/src/librustc_back/target/arm_linux_androideabi.rs b/src/librustc_back/target/arm_linux_androideabi.rs index c7d2df4344cb..6bfe90af2ca1 100644 --- a/src/librustc_back/target/arm_linux_androideabi.rs +++ b/src/librustc_back/target/arm_linux_androideabi.rs @@ -8,11 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { let mut base = super::android_base::opts(); - base.features = "+v7,+vfp3,+d16".to_string(); + // https://developer.android.com/ndk/guides/abis.html#armeabi + base.features = "+v5te".to_string(); base.max_atomic_width = Some(64); Ok(Target { @@ -24,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "android".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { abi_blacklist: super::arm_base::abi_blacklist(), .. base diff --git a/src/librustc_back/target/arm_unknown_linux_gnueabi.rs b/src/librustc_back/target/arm_unknown_linux_gnueabi.rs index 77d35edfbd09..165d34fe6c7c 100644 --- a/src/librustc_back/target/arm_unknown_linux_gnueabi.rs +++ b/src/librustc_back/target/arm_unknown_linux_gnueabi.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -22,6 +23,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { features: "+v6".to_string(), diff --git a/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs b/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs index b183412be193..731021d979bc 100644 --- a/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs +++ b/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -22,6 +23,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { features: "+v6,+vfp2".to_string(), diff --git a/src/librustc_back/target/arm_unknown_linux_musleabi.rs b/src/librustc_back/target/arm_unknown_linux_musleabi.rs index 261d4353c7a0..f81bcd78b03a 100644 --- a/src/librustc_back/target/arm_unknown_linux_musleabi.rs +++ b/src/librustc_back/target/arm_unknown_linux_musleabi.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -29,6 +30,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "musl".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { abi_blacklist: super::arm_base::abi_blacklist(), .. base diff --git a/src/librustc_back/target/arm_unknown_linux_musleabihf.rs b/src/librustc_back/target/arm_unknown_linux_musleabihf.rs index 1443dcf5bad4..6c47678ede6a 100644 --- a/src/librustc_back/target/arm_unknown_linux_musleabihf.rs +++ b/src/librustc_back/target/arm_unknown_linux_musleabihf.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -29,6 +30,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "musl".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { abi_blacklist: super::arm_base::abi_blacklist(), .. base diff --git a/src/librustc_back/target/armv5te_unknown_linux_gnueabi.rs b/src/librustc_back/target/armv5te_unknown_linux_gnueabi.rs index 37216e20762d..200c6ab74cc6 100644 --- a/src/librustc_back/target/armv5te_unknown_linux_gnueabi.rs +++ b/src/librustc_back/target/armv5te_unknown_linux_gnueabi.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -21,6 +22,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { features: "+soft-float".to_string(), @@ -31,4 +33,3 @@ pub fn target() -> TargetResult { } }) } - diff --git a/src/librustc_back/target/armv7_apple_ios.rs b/src/librustc_back/target/armv7_apple_ios.rs index 9e9c44393062..4d8745828329 100644 --- a/src/librustc_back/target/armv7_apple_ios.rs +++ b/src/librustc_back/target/armv7_apple_ios.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; use super::apple_ios_base::{opts, Arch}; @@ -22,6 +23,7 @@ pub fn target() -> TargetResult { target_os: "ios".to_string(), target_env: "".to_string(), target_vendor: "apple".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { features: "+v7,+vfp3,+neon".to_string(), max_atomic_width: Some(64), diff --git a/src/librustc_back/target/armv7_linux_androideabi.rs b/src/librustc_back/target/armv7_linux_androideabi.rs index 36f409b7948c..b49b1d1c2138 100644 --- a/src/librustc_back/target/armv7_linux_androideabi.rs +++ b/src/librustc_back/target/armv7_linux_androideabi.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; // See https://developer.android.com/ndk/guides/abis.html#v7a @@ -17,6 +18,8 @@ pub fn target() -> TargetResult { let mut base = super::android_base::opts(); base.features = "+v7,+thumb2,+vfp3,+d16,-neon".to_string(); base.max_atomic_width = Some(64); + base.pre_link_args + .get_mut(&LinkerFlavor::Gcc).unwrap().push("-march=armv7-a".to_string()); Ok(Target { llvm_target: "armv7-none-linux-android".to_string(), @@ -27,6 +30,7 @@ pub fn target() -> TargetResult { target_os: "android".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { abi_blacklist: super::arm_base::abi_blacklist(), .. base diff --git a/src/librustc_back/target/armv7_unknown_linux_gnueabihf.rs b/src/librustc_back/target/armv7_unknown_linux_gnueabihf.rs index 96ccedd5bea5..d3a6a68449c3 100644 --- a/src/librustc_back/target/armv7_unknown_linux_gnueabihf.rs +++ b/src/librustc_back/target/armv7_unknown_linux_gnueabihf.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -21,6 +22,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { // Info about features at https://wiki.debian.org/ArmHardFloatPort @@ -32,4 +34,3 @@ pub fn target() -> TargetResult { } }) } - diff --git a/src/librustc_back/target/armv7_unknown_linux_musleabihf.rs b/src/librustc_back/target/armv7_unknown_linux_musleabihf.rs index 8f66e6a4f58d..5086cd44f7ac 100644 --- a/src/librustc_back/target/armv7_unknown_linux_musleabihf.rs +++ b/src/librustc_back/target/armv7_unknown_linux_musleabihf.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -30,6 +31,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "musl".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { abi_blacklist: super::arm_base::abi_blacklist(), .. base diff --git a/src/librustc_back/target/armv7s_apple_ios.rs b/src/librustc_back/target/armv7s_apple_ios.rs index 6edde6e73efd..96c89a7ed3bd 100644 --- a/src/librustc_back/target/armv7s_apple_ios.rs +++ b/src/librustc_back/target/armv7s_apple_ios.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; use super::apple_ios_base::{opts, Arch}; @@ -22,6 +23,7 @@ pub fn target() -> TargetResult { target_os: "ios".to_string(), target_env: "".to_string(), target_vendor: "apple".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { features: "+v7,+vfp4,+neon".to_string(), max_atomic_width: Some(64), diff --git a/src/librustc_back/target/asmjs_unknown_emscripten.rs b/src/librustc_back/target/asmjs_unknown_emscripten.rs index 4d38b0d17059..b884d4e54101 100644 --- a/src/librustc_back/target/asmjs_unknown_emscripten.rs +++ b/src/librustc_back/target/asmjs_unknown_emscripten.rs @@ -8,10 +8,16 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use super::{Target, TargetOptions}; +use LinkerFlavor; +use super::{LinkArgs, Target, TargetOptions}; use super::emscripten_base::{cmd}; pub fn target() -> Result { + let mut args = LinkArgs::new(); + args.insert(LinkerFlavor::Em, + vec!["-s".to_string(), + "ERROR_ON_UNDEFINED_SYMBOLS=1".to_string()]); + let opts = TargetOptions { linker: cmd("emcc"), ar: cmd("emar"), @@ -24,7 +30,7 @@ pub fn target() -> Result { obj_is_bitcode: true, is_like_emscripten: true, max_atomic_width: Some(32), - post_link_args: vec!["-s".to_string(), "ERROR_ON_UNDEFINED_SYMBOLS=1".to_string()], + post_link_args: args, target_family: Some("unix".to_string()), .. Default::default() }; @@ -37,6 +43,7 @@ pub fn target() -> Result { target_vendor: "unknown".to_string(), data_layout: "e-p:32:32-i64:64-v128:32:128-n32-S128".to_string(), arch: "asmjs".to_string(), + linker_flavor: LinkerFlavor::Em, options: opts, }) } diff --git a/src/librustc_back/target/dragonfly_base.rs b/src/librustc_back/target/dragonfly_base.rs index dca33e45af7c..e44cd393289b 100644 --- a/src/librustc_back/target/dragonfly_base.rs +++ b/src/librustc_back/target/dragonfly_base.rs @@ -8,26 +8,30 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::TargetOptions; +use LinkerFlavor; +use target::{LinkArgs, TargetOptions}; use std::default::Default; pub fn opts() -> TargetOptions { + let mut args = LinkArgs::new(); + args.insert(LinkerFlavor::Gcc, vec![ + // GNU-style linkers will use this to omit linking to libraries + // which don't actually fulfill any relocations, but only for + // libraries which follow this flag. Thus, use it before + // specifying libraries to link to. + "-Wl,--as-needed".to_string(), + + // Always enable NX protection when it is available + "-Wl,-z,noexecstack".to_string(), + ]); + TargetOptions { dynamic_linking: true, executables: true, target_family: Some("unix".to_string()), linker_is_gnu: true, has_rpath: true, - pre_link_args: vec![ - // GNU-style linkers will use this to omit linking to libraries - // which don't actually fulfill any relocations, but only for - // libraries which follow this flag. Thus, use it before - // specifying libraries to link to. - "-Wl,--as-needed".to_string(), - - // Always enable NX protection when it is available - "-Wl,-z,noexecstack".to_string(), - ], + pre_link_args: args, position_independent_executables: true, exe_allocation_crate: super::maybe_jemalloc(), .. Default::default() diff --git a/src/librustc_back/target/freebsd_base.rs b/src/librustc_back/target/freebsd_base.rs index dca33e45af7c..e44cd393289b 100644 --- a/src/librustc_back/target/freebsd_base.rs +++ b/src/librustc_back/target/freebsd_base.rs @@ -8,26 +8,30 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::TargetOptions; +use LinkerFlavor; +use target::{LinkArgs, TargetOptions}; use std::default::Default; pub fn opts() -> TargetOptions { + let mut args = LinkArgs::new(); + args.insert(LinkerFlavor::Gcc, vec![ + // GNU-style linkers will use this to omit linking to libraries + // which don't actually fulfill any relocations, but only for + // libraries which follow this flag. Thus, use it before + // specifying libraries to link to. + "-Wl,--as-needed".to_string(), + + // Always enable NX protection when it is available + "-Wl,-z,noexecstack".to_string(), + ]); + TargetOptions { dynamic_linking: true, executables: true, target_family: Some("unix".to_string()), linker_is_gnu: true, has_rpath: true, - pre_link_args: vec![ - // GNU-style linkers will use this to omit linking to libraries - // which don't actually fulfill any relocations, but only for - // libraries which follow this flag. Thus, use it before - // specifying libraries to link to. - "-Wl,--as-needed".to_string(), - - // Always enable NX protection when it is available - "-Wl,-z,noexecstack".to_string(), - ], + pre_link_args: args, position_independent_executables: true, exe_allocation_crate: super::maybe_jemalloc(), .. Default::default() diff --git a/src/librustc_back/target/fuchsia_base.rs b/src/librustc_back/target/fuchsia_base.rs index 8c517224201b..c6207cdc4d9c 100644 --- a/src/librustc_back/target/fuchsia_base.rs +++ b/src/librustc_back/target/fuchsia_base.rs @@ -8,30 +8,34 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::TargetOptions; +use LinkerFlavor; +use target::{LinkArgs, TargetOptions}; use std::default::Default; pub fn opts() -> TargetOptions { + let mut args = LinkArgs::new(); + args.insert(LinkerFlavor::Gcc, vec![ + // We want to be able to strip as much executable code as possible + // from the linker command line, and this flag indicates to the + // linker that it can avoid linking in dynamic libraries that don't + // actually satisfy any symbols up to that point (as with many other + // resolutions the linker does). This option only applies to all + // following libraries so we're sure to pass it as one of the first + // arguments. + // FIXME: figure out whether these linker args are desirable + //"-Wl,--as-needed".to_string(), + + // Always enable NX protection when it is available + //"-Wl,-z,noexecstack".to_string(), + ]); + TargetOptions { dynamic_linking: true, executables: true, target_family: Some("unix".to_string()), linker_is_gnu: true, has_rpath: true, - pre_link_args: vec![ - // We want to be able to strip as much executable code as possible - // from the linker command line, and this flag indicates to the - // linker that it can avoid linking in dynamic libraries that don't - // actually satisfy any symbols up to that point (as with many other - // resolutions the linker does). This option only applies to all - // following libraries so we're sure to pass it as one of the first - // arguments. - // FIXME: figure out whether these linker args are desirable - //"-Wl,--as-needed".to_string(), - - // Always enable NX protection when it is available - //"-Wl,-z,noexecstack".to_string(), - ], + pre_link_args: args, position_independent_executables: true, exe_allocation_crate: "alloc_system".to_string(), has_elf_tls: true, diff --git a/src/librustc_back/target/haiku_base.rs b/src/librustc_back/target/haiku_base.rs index bfdc9faaa8a7..8e7f463563c3 100644 --- a/src/librustc_back/target/haiku_base.rs +++ b/src/librustc_back/target/haiku_base.rs @@ -16,9 +16,10 @@ pub fn opts() -> TargetOptions { linker: "cc".to_string(), dynamic_linking: true, executables: true, - has_rpath: true, + has_rpath: false, target_family: Some("unix".to_string()), linker_is_gnu: true, + no_integrated_as: true, .. Default::default() } } diff --git a/src/librustc_back/target/i386_apple_ios.rs b/src/librustc_back/target/i386_apple_ios.rs index 319ada4f8e17..a6383179f3ae 100644 --- a/src/librustc_back/target/i386_apple_ios.rs +++ b/src/librustc_back/target/i386_apple_ios.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; use super::apple_ios_base::{opts, Arch}; @@ -22,6 +23,7 @@ pub fn target() -> TargetResult { target_os: "ios".to_string(), target_env: "".to_string(), target_vendor: "apple".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { max_atomic_width: Some(64), .. base diff --git a/src/librustc_back/target/i686_apple_darwin.rs b/src/librustc_back/target/i686_apple_darwin.rs index d3b09d9a0f11..6b14972e9f75 100644 --- a/src/librustc_back/target/i686_apple_darwin.rs +++ b/src/librustc_back/target/i686_apple_darwin.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::apple_base::opts(); base.cpu = "yonah".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.push("-m32".to_string()); + base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m32".to_string()]); Ok(Target { llvm_target: "i686-apple-darwin".to_string(), @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "macos".to_string(), target_env: "".to_string(), target_vendor: "apple".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/i686_linux_android.rs b/src/librustc_back/target/i686_linux_android.rs index f8a8f5a3500b..a5390cbfb725 100644 --- a/src/librustc_back/target/i686_linux_android.rs +++ b/src/librustc_back/target/i686_linux_android.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; // See https://developer.android.com/ndk/guides/abis.html#x86 @@ -31,6 +32,7 @@ pub fn target() -> TargetResult { target_os: "android".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/i686_pc_windows_gnu.rs b/src/librustc_back/target/i686_pc_windows_gnu.rs index 294772613920..4a736a93be7d 100644 --- a/src/librustc_back/target/i686_pc_windows_gnu.rs +++ b/src/librustc_back/target/i686_pc_windows_gnu.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { @@ -18,7 +19,8 @@ pub fn target() -> TargetResult { // Mark all dynamic libraries and executables as compatible with the larger 4GiB address // space available to x86 Windows binaries on x86_64. - base.pre_link_args.push("-Wl,--large-address-aware".to_string()); + base.pre_link_args + .get_mut(&LinkerFlavor::Gcc).unwrap().push("-Wl,--large-address-aware".to_string()); Ok(Target { llvm_target: "i686-pc-windows-gnu".to_string(), @@ -29,6 +31,7 @@ pub fn target() -> TargetResult { target_os: "windows".to_string(), target_env: "gnu".to_string(), target_vendor: "pc".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/i686_pc_windows_msvc.rs b/src/librustc_back/target/i686_pc_windows_msvc.rs index 2290d2057f13..17fe306804f4 100644 --- a/src/librustc_back/target/i686_pc_windows_msvc.rs +++ b/src/librustc_back/target/i686_pc_windows_msvc.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { @@ -17,12 +18,13 @@ pub fn target() -> TargetResult { // Mark all dynamic libraries and executables as compatible with the larger 4GiB address // space available to x86 Windows binaries on x86_64. - base.pre_link_args.push("/LARGEADDRESSAWARE".to_string()); + base.pre_link_args + .get_mut(&LinkerFlavor::Msvc).unwrap().push("/LARGEADDRESSAWARE".to_string()); // Ensure the linker will only produce an image if it can also produce a table of // the image's safe exception handlers. // https://msdn.microsoft.com/en-us/library/9a89h429.aspx - base.pre_link_args.push("/SAFESEH".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Msvc).unwrap().push("/SAFESEH".to_string()); Ok(Target { llvm_target: "i686-pc-windows-msvc".to_string(), @@ -33,6 +35,7 @@ pub fn target() -> TargetResult { target_os: "windows".to_string(), target_env: "msvc".to_string(), target_vendor: "pc".to_string(), + linker_flavor: LinkerFlavor::Msvc, options: base, }) } diff --git a/src/librustc_back/target/i686_unknown_dragonfly.rs b/src/librustc_back/target/i686_unknown_dragonfly.rs index d8f8431e66e7..052bc23c119e 100644 --- a/src/librustc_back/target/i686_unknown_dragonfly.rs +++ b/src/librustc_back/target/i686_unknown_dragonfly.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::dragonfly_base::opts(); base.cpu = "pentium4".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.push("-m32".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string()); Ok(Target { llvm_target: "i686-unknown-dragonfly".to_string(), @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "dragonfly".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/i686_unknown_freebsd.rs b/src/librustc_back/target/i686_unknown_freebsd.rs index ddbc74f25c9c..d77a9cca2683 100644 --- a/src/librustc_back/target/i686_unknown_freebsd.rs +++ b/src/librustc_back/target/i686_unknown_freebsd.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::freebsd_base::opts(); base.cpu = "pentium4".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.push("-m32".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string()); Ok(Target { llvm_target: "i686-unknown-freebsd".to_string(), @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "freebsd".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/i686_unknown_haiku.rs b/src/librustc_back/target/i686_unknown_haiku.rs index 9078206c9e06..b0e67bd90ddd 100644 --- a/src/librustc_back/target/i686_unknown_haiku.rs +++ b/src/librustc_back/target/i686_unknown_haiku.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::haiku_base::opts(); base.cpu = "pentium4".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.push("-m32".to_string()); + base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m32".to_string()]); Ok(Target { llvm_target: "i686-unknown-haiku".to_string(), @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "haiku".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/i686_unknown_linux_gnu.rs b/src/librustc_back/target/i686_unknown_linux_gnu.rs index bf9c28b0c10e..3c5c10676260 100644 --- a/src/librustc_back/target/i686_unknown_linux_gnu.rs +++ b/src/librustc_back/target/i686_unknown_linux_gnu.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_base::opts(); base.cpu = "pentium4".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.push("-m32".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string()); Ok(Target { llvm_target: "i686-unknown-linux-gnu".to_string(), @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/i686_unknown_linux_musl.rs b/src/librustc_back/target/i686_unknown_linux_musl.rs index ced59448f7f6..3ed8c94d0bf2 100644 --- a/src/librustc_back/target/i686_unknown_linux_musl.rs +++ b/src/librustc_back/target/i686_unknown_linux_musl.rs @@ -8,14 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_musl_base::opts(); base.cpu = "pentium4".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.push("-m32".to_string()); - base.pre_link_args.push("-Wl,-melf_i386".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-Wl,-melf_i386".to_string()); // The unwinder used by i686-unknown-linux-musl, the LLVM libunwind // implementation, apparently relies on frame pointers existing... somehow. @@ -40,6 +41,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "musl".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/i686_unknown_netbsd.rs b/src/librustc_back/target/i686_unknown_netbsd.rs index e7e2ee3f9056..fc92e5aee6af 100644 --- a/src/librustc_back/target/i686_unknown_netbsd.rs +++ b/src/librustc_back/target/i686_unknown_netbsd.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::netbsd_base::opts(); base.cpu = "pentium4".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.push("-m32".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string()); Ok(Target { llvm_target: "i686-unknown-netbsdelf".to_string(), @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "netbsd".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/i686_unknown_openbsd.rs b/src/librustc_back/target/i686_unknown_openbsd.rs index 81efd37386a0..7ef68bd6d9c3 100644 --- a/src/librustc_back/target/i686_unknown_openbsd.rs +++ b/src/librustc_back/target/i686_unknown_openbsd.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::openbsd_base::opts(); base.cpu = "pentium4".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.push("-m32".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string()); Ok(Target { llvm_target: "i686-unknown-openbsd".to_string(), @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "openbsd".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/le32_unknown_nacl.rs b/src/librustc_back/target/le32_unknown_nacl.rs index 891e7dda14a2..f4265e0eb146 100644 --- a/src/librustc_back/target/le32_unknown_nacl.rs +++ b/src/librustc_back/target/le32_unknown_nacl.rs @@ -8,17 +8,25 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use super::{Target, TargetOptions, TargetResult}; +use LinkerFlavor; +use super::{LinkArgs, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { + let mut pre_link_args = LinkArgs::new(); + pre_link_args.insert(LinkerFlavor::Gcc, + vec!["--pnacl-exceptions=sjlj".to_string(), + "--target=le32-unknown-nacl".to_string(), + "-Wl,--start-group".to_string()]); + let mut post_link_args = LinkArgs::new(); + post_link_args.insert(LinkerFlavor::Gcc, + vec!["-Wl,--end-group".to_string()]); + let opts = TargetOptions { linker: "pnacl-clang".to_string(), ar: "pnacl-ar".to_string(), - pre_link_args: vec!["--pnacl-exceptions=sjlj".to_string(), - "--target=le32-unknown-nacl".to_string(), - "-Wl,--start-group".to_string()], - post_link_args: vec!["-Wl,--end-group".to_string()], + pre_link_args: pre_link_args, + post_link_args: post_link_args, dynamic_linking: false, executables: true, exe_suffix: ".pexe".to_string(), @@ -36,6 +44,7 @@ pub fn target() -> TargetResult { target_vendor: "unknown".to_string(), data_layout: "e-i64:64:64-p:32:32:32-v128:32:32".to_string(), arch: "le32".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: opts, }) } diff --git a/src/librustc_back/target/linux_base.rs b/src/librustc_back/target/linux_base.rs index 4b2ae9c8e699..722d2fa16ef7 100644 --- a/src/librustc_back/target/linux_base.rs +++ b/src/librustc_back/target/linux_base.rs @@ -8,29 +8,33 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::TargetOptions; +use LinkerFlavor; +use target::{LinkArgs, TargetOptions}; use std::default::Default; pub fn opts() -> TargetOptions { + let mut args = LinkArgs::new(); + args.insert(LinkerFlavor::Gcc, vec![ + // We want to be able to strip as much executable code as possible + // from the linker command line, and this flag indicates to the + // linker that it can avoid linking in dynamic libraries that don't + // actually satisfy any symbols up to that point (as with many other + // resolutions the linker does). This option only applies to all + // following libraries so we're sure to pass it as one of the first + // arguments. + "-Wl,--as-needed".to_string(), + + // Always enable NX protection when it is available + "-Wl,-z,noexecstack".to_string(), + ]); + TargetOptions { dynamic_linking: true, executables: true, target_family: Some("unix".to_string()), linker_is_gnu: true, has_rpath: true, - pre_link_args: vec![ - // We want to be able to strip as much executable code as possible - // from the linker command line, and this flag indicates to the - // linker that it can avoid linking in dynamic libraries that don't - // actually satisfy any symbols up to that point (as with many other - // resolutions the linker does). This option only applies to all - // following libraries so we're sure to pass it as one of the first - // arguments. - "-Wl,--as-needed".to_string(), - - // Always enable NX protection when it is available - "-Wl,-z,noexecstack".to_string(), - ], + pre_link_args: args, position_independent_executables: true, exe_allocation_crate: super::maybe_jemalloc(), has_elf_tls: true, diff --git a/src/librustc_back/target/linux_musl_base.rs b/src/librustc_back/target/linux_musl_base.rs index 18cca425a32c..236f2c1ef0aa 100644 --- a/src/librustc_back/target/linux_musl_base.rs +++ b/src/librustc_back/target/linux_musl_base.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::TargetOptions; pub fn opts() -> TargetOptions { @@ -15,13 +16,13 @@ pub fn opts() -> TargetOptions { // Make sure that the linker/gcc really don't pull in anything, including // default objects, libs, etc. - base.pre_link_args.push("-nostdlib".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-nostdlib".to_string()); // At least when this was tested, the linker would not add the // `GNU_EH_FRAME` program header to executables generated, which is required // when unwinding to locate the unwinding information. I'm not sure why this // argument is *not* necessary for normal builds, but it can't hurt! - base.pre_link_args.push("-Wl,--eh-frame-hdr".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-Wl,--eh-frame-hdr".to_string()); // There's a whole bunch of circular dependencies when dealing with MUSL // unfortunately. To put this in perspective libc is statically linked to @@ -45,8 +46,8 @@ pub fn opts() -> TargetOptions { // link everything as a group, not stripping anything out until everything // is processed. The linker will still perform a pass to strip out object // files but it won't do so until all objects/archives have been processed. - base.pre_link_args.push("-Wl,-(".to_string()); - base.post_link_args.push("-Wl,-)".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-Wl,-(".to_string()); + base.post_link_args.insert(LinkerFlavor::Gcc, vec!["-Wl,-)".to_string()]); // When generating a statically linked executable there's generally some // small setup needed which is listed in these files. These are provided by diff --git a/src/librustc_back/target/mips64_unknown_linux_gnuabi64.rs b/src/librustc_back/target/mips64_unknown_linux_gnuabi64.rs index c284840ecb4b..038a70ed6b17 100644 --- a/src/librustc_back/target/mips64_unknown_linux_gnuabi64.rs +++ b/src/librustc_back/target/mips64_unknown_linux_gnuabi64.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -20,6 +21,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { // NOTE(mips64r2) matches C toolchain cpu: "mips64r2".to_string(), diff --git a/src/librustc_back/target/mips64el_unknown_linux_gnuabi64.rs b/src/librustc_back/target/mips64el_unknown_linux_gnuabi64.rs index 17895836fe87..aed4c4fbb08d 100644 --- a/src/librustc_back/target/mips64el_unknown_linux_gnuabi64.rs +++ b/src/librustc_back/target/mips64el_unknown_linux_gnuabi64.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -20,6 +21,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { // NOTE(mips64r2) matches C toolchain cpu: "mips64r2".to_string(), diff --git a/src/librustc_back/target/mips_unknown_linux_gnu.rs b/src/librustc_back/target/mips_unknown_linux_gnu.rs index a6d8fae2536c..9ef61f9caddc 100644 --- a/src/librustc_back/target/mips_unknown_linux_gnu.rs +++ b/src/librustc_back/target/mips_unknown_linux_gnu.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -20,6 +21,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { cpu: "mips32r2".to_string(), features: "+mips32r2".to_string(), diff --git a/src/librustc_back/target/mips_unknown_linux_musl.rs b/src/librustc_back/target/mips_unknown_linux_musl.rs index e4a6d2a55d98..f54790bab970 100644 --- a/src/librustc_back/target/mips_unknown_linux_musl.rs +++ b/src/librustc_back/target/mips_unknown_linux_musl.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -20,6 +21,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "musl".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { cpu: "mips32r2".to_string(), features: "+mips32r2,+soft-float".to_string(), diff --git a/src/librustc_back/target/mips_unknown_linux_uclibc.rs b/src/librustc_back/target/mips_unknown_linux_uclibc.rs index ccc64ea393b7..59c07efe0fdc 100644 --- a/src/librustc_back/target/mips_unknown_linux_uclibc.rs +++ b/src/librustc_back/target/mips_unknown_linux_uclibc.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -20,6 +21,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "uclibc".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { cpu: "mips32r2".to_string(), features: "+mips32r2,+soft-float".to_string(), diff --git a/src/librustc_back/target/mipsel_unknown_linux_gnu.rs b/src/librustc_back/target/mipsel_unknown_linux_gnu.rs index 9b8b1d5713f1..ec19cc1a536a 100644 --- a/src/librustc_back/target/mipsel_unknown_linux_gnu.rs +++ b/src/librustc_back/target/mipsel_unknown_linux_gnu.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -20,6 +21,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { cpu: "mips32".to_string(), diff --git a/src/librustc_back/target/mipsel_unknown_linux_musl.rs b/src/librustc_back/target/mipsel_unknown_linux_musl.rs index 5693bddd0488..00085d18e6d0 100644 --- a/src/librustc_back/target/mipsel_unknown_linux_musl.rs +++ b/src/librustc_back/target/mipsel_unknown_linux_musl.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -20,6 +21,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "musl".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { cpu: "mips32".to_string(), features: "+mips32,+soft-float".to_string(), diff --git a/src/librustc_back/target/mipsel_unknown_linux_uclibc.rs b/src/librustc_back/target/mipsel_unknown_linux_uclibc.rs index 3acade5a4744..b3ca2edec1ed 100644 --- a/src/librustc_back/target/mipsel_unknown_linux_uclibc.rs +++ b/src/librustc_back/target/mipsel_unknown_linux_uclibc.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -20,6 +21,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "uclibc".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { cpu: "mips32".to_string(), diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index 559418d2c4f5..e60fdc386ce6 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -50,7 +50,7 @@ use std::default::Default; use std::io::prelude::*; use syntax::abi::{Abi, lookup as lookup_abi}; -use PanicStrategy; +use {LinkerFlavor, PanicStrategy}; mod android_base; mod apple_base; @@ -72,6 +72,7 @@ mod thumb_base; mod fuchsia_base; mod redox_base; +pub type LinkArgs = BTreeMap>; pub type TargetResult = Result; macro_rules! supported_targets { @@ -161,6 +162,7 @@ supported_targets! { ("sparc64-unknown-linux-gnu", sparc64_unknown_linux_gnu), ("i686-linux-android", i686_linux_android), + ("x86_64-linux-android", x86_64_linux_android), ("arm-linux-androideabi", arm_linux_androideabi), ("armv7-linux-androideabi", armv7_linux_androideabi), ("aarch64-linux-android", aarch64_linux_android), @@ -241,6 +243,8 @@ pub struct Target { pub arch: String, /// [Data layout](http://llvm.org/docs/LangRef.html#data-layout) to pass to LLVM. pub data_layout: String, + /// Linker flavor + pub linker_flavor: LinkerFlavor, /// Optional settings with defaults. pub options: TargetOptions, } @@ -261,7 +265,7 @@ pub struct TargetOptions { /// Linker arguments that are unconditionally passed *before* any /// user-defined libraries. - pub pre_link_args: Vec, + pub pre_link_args: LinkArgs, /// Objects to link before all others, always found within the /// sysroot folder. pub pre_link_objects_exe: Vec, // ... when linking an executable @@ -269,13 +273,13 @@ pub struct TargetOptions { /// Linker arguments that are unconditionally passed after any /// user-defined but before post_link_objects. Standard platform /// libraries that should be always be linked to, usually go here. - pub late_link_args: Vec, + pub late_link_args: LinkArgs, /// Objects to link after all others, always found within the /// sysroot folder. pub post_link_objects: Vec, /// Linker arguments that are unconditionally passed *after* any /// user-defined libraries. - pub post_link_args: Vec, + pub post_link_args: LinkArgs, /// Extra arguments to pass to the external assembler (when used) pub asm_args: Vec, @@ -412,8 +416,8 @@ impl Default for TargetOptions { is_builtin: false, linker: option_env!("CFG_DEFAULT_LINKER").unwrap_or("cc").to_string(), ar: option_env!("CFG_DEFAULT_AR").unwrap_or("ar").to_string(), - pre_link_args: Vec::new(), - post_link_args: Vec::new(), + pre_link_args: LinkArgs::new(), + post_link_args: LinkArgs::new(), asm_args: Vec::new(), cpu: "generic".to_string(), features: "".to_string(), @@ -445,7 +449,7 @@ impl Default for TargetOptions { pre_link_objects_exe: Vec::new(), pre_link_objects_dll: Vec::new(), post_link_objects: Vec::new(), - late_link_args: Vec::new(), + late_link_args: LinkArgs::new(), archive_format: "gnu".to_string(), custom_unwind_resume: false, lib_allocation_crate: "alloc_system".to_string(), @@ -529,6 +533,10 @@ impl Target { target_os: get_req_field("os")?, target_env: get_opt_field("env", ""), target_vendor: get_opt_field("vendor", "unknown"), + linker_flavor: LinkerFlavor::from_str(&*get_req_field("linker-flavor")?) + .ok_or_else(|| { + format!("linker flavor must be {}", LinkerFlavor::one_of()) + })?, options: Default::default(), }; @@ -579,17 +587,49 @@ impl Target { .map(|s| s.to_string() ); } } ); + ($key_name:ident, LinkerFlavor) => ( { + let name = (stringify!($key_name)).replace("_", "-"); + obj.find(&name[..]).and_then(|o| o.as_string().map(|s| { + LinkerFlavor::from_str(&s).ok_or_else(|| { + Err(format!("'{}' is not a valid value for linker-flavor. \ + Use 'em', 'gcc', 'ld' or 'msvc.", s)) + }) + })).unwrap_or(Ok(())) + } ); + ($key_name:ident, link_args) => ( { + let name = (stringify!($key_name)).replace("_", "-"); + if let Some(obj) = obj.find(&name[..]).and_then(|o| o.as_object()) { + let mut args = LinkArgs::new(); + for (k, v) in obj { + let k = LinkerFlavor::from_str(&k).ok_or_else(|| { + format!("{}: '{}' is not a valid value for linker-flavor. \ + Use 'em', 'gcc', 'ld' or 'msvc'", name, k) + })?; + + let v = v.as_array().map(|a| { + a + .iter() + .filter_map(|o| o.as_string()) + .map(|s| s.to_owned()) + .collect::>() + }).unwrap_or(vec![]); + + args.insert(k, v); + } + base.options.$key_name = args; + } + } ); } key!(is_builtin, bool); key!(linker); key!(ar); - key!(pre_link_args, list); + key!(pre_link_args, link_args); key!(pre_link_objects_exe, list); key!(pre_link_objects_dll, list); - key!(late_link_args, list); + key!(late_link_args, link_args); key!(post_link_objects, list); - key!(post_link_args, list); + key!(post_link_args, link_args); key!(asm_args, list); key!(cpu); key!(features); @@ -734,6 +774,16 @@ impl ToJson for Target { d.insert(name.to_string(), self.options.$attr.to_json()); } } ); + (link_args - $attr:ident) => ( { + let name = (stringify!($attr)).replace("_", "-"); + if default.$attr != self.options.$attr { + let obj = self.options.$attr + .iter() + .map(|(k, v)| (k.desc().to_owned(), v.clone())) + .collect::>(); + d.insert(name.to_string(), obj.to_json()); + } + } ); } target_val!(llvm_target); @@ -743,18 +793,18 @@ impl ToJson for Target { target_val!(target_os, "os"); target_val!(target_env, "env"); target_val!(target_vendor, "vendor"); - target_val!(arch); target_val!(data_layout); + target_val!(linker_flavor); target_option_val!(is_builtin); target_option_val!(linker); target_option_val!(ar); - target_option_val!(pre_link_args); + target_option_val!(link_args - pre_link_args); target_option_val!(pre_link_objects_exe); target_option_val!(pre_link_objects_dll); - target_option_val!(late_link_args); + target_option_val!(link_args - late_link_args); target_option_val!(post_link_objects); - target_option_val!(post_link_args); + target_option_val!(link_args - post_link_args); target_option_val!(asm_args); target_option_val!(cpu); target_option_val!(features); diff --git a/src/librustc_back/target/netbsd_base.rs b/src/librustc_back/target/netbsd_base.rs index 57179a68afd8..63245fcae767 100644 --- a/src/librustc_back/target/netbsd_base.rs +++ b/src/librustc_back/target/netbsd_base.rs @@ -8,26 +8,30 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::TargetOptions; +use LinkerFlavor; +use target::{LinkArgs, TargetOptions}; use std::default::Default; pub fn opts() -> TargetOptions { + let mut args = LinkArgs::new(); + args.insert(LinkerFlavor::Gcc, vec![ + // GNU-style linkers will use this to omit linking to libraries + // which don't actually fulfill any relocations, but only for + // libraries which follow this flag. Thus, use it before + // specifying libraries to link to. + "-Wl,--as-needed".to_string(), + + // Always enable NX protection when it is available + "-Wl,-z,noexecstack".to_string(), + ]); + TargetOptions { dynamic_linking: true, executables: true, target_family: Some("unix".to_string()), linker_is_gnu: true, has_rpath: true, - pre_link_args: vec![ - // GNU-style linkers will use this to omit linking to libraries - // which don't actually fulfill any relocations, but only for - // libraries which follow this flag. Thus, use it before - // specifying libraries to link to. - "-Wl,--as-needed".to_string(), - - // Always enable NX protection when it is available - "-Wl,-z,noexecstack".to_string(), - ], + pre_link_args: args, position_independent_executables: true, .. Default::default() } diff --git a/src/librustc_back/target/openbsd_base.rs b/src/librustc_back/target/openbsd_base.rs index 12b8e8bdc88f..2df9b8e03ff5 100644 --- a/src/librustc_back/target/openbsd_base.rs +++ b/src/librustc_back/target/openbsd_base.rs @@ -8,10 +8,23 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::TargetOptions; +use LinkerFlavor; +use target::{LinkArgs, TargetOptions}; use std::default::Default; pub fn opts() -> TargetOptions { + let mut args = LinkArgs::new(); + args.insert(LinkerFlavor::Gcc, vec![ + // GNU-style linkers will use this to omit linking to libraries + // which don't actually fulfill any relocations, but only for + // libraries which follow this flag. Thus, use it before + // specifying libraries to link to. + "-Wl,--as-needed".to_string(), + + // Always enable NX protection when it is available + "-Wl,-z,noexecstack".to_string(), + ]); + TargetOptions { dynamic_linking: true, executables: true, @@ -19,16 +32,7 @@ pub fn opts() -> TargetOptions { linker_is_gnu: true, has_rpath: true, is_like_openbsd: true, - pre_link_args: vec![ - // GNU-style linkers will use this to omit linking to libraries - // which don't actually fulfill any relocations, but only for - // libraries which follow this flag. Thus, use it before - // specifying libraries to link to. - "-Wl,--as-needed".to_string(), - - // Always enable NX protection when it is available - "-Wl,-z,noexecstack".to_string(), - ], + pre_link_args: args, position_independent_executables: true, exe_allocation_crate: "alloc_system".to_string(), .. Default::default() diff --git a/src/librustc_back/target/powerpc64_unknown_linux_gnu.rs b/src/librustc_back/target/powerpc64_unknown_linux_gnu.rs index 909c5488dcb7..55a5bfd1e674 100644 --- a/src/librustc_back/target/powerpc64_unknown_linux_gnu.rs +++ b/src/librustc_back/target/powerpc64_unknown_linux_gnu.rs @@ -8,12 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_base::opts(); base.cpu = "ppc64".to_string(); - base.pre_link_args.push("-m64".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); base.max_atomic_width = Some(64); // see #36994 @@ -28,6 +29,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/powerpc64le_unknown_linux_gnu.rs b/src/librustc_back/target/powerpc64le_unknown_linux_gnu.rs index a692346ca0ff..c22bc3b041a4 100644 --- a/src/librustc_back/target/powerpc64le_unknown_linux_gnu.rs +++ b/src/librustc_back/target/powerpc64le_unknown_linux_gnu.rs @@ -8,12 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_base::opts(); base.cpu = "ppc64le".to_string(); - base.pre_link_args.push("-m64".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); base.max_atomic_width = Some(64); // see #36994 @@ -28,6 +29,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/powerpc_unknown_linux_gnu.rs b/src/librustc_back/target/powerpc_unknown_linux_gnu.rs index 284772c43319..677d198b1a37 100644 --- a/src/librustc_back/target/powerpc_unknown_linux_gnu.rs +++ b/src/librustc_back/target/powerpc_unknown_linux_gnu.rs @@ -8,11 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_base::opts(); - base.pre_link_args.push("-m32".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string()); base.max_atomic_width = Some(32); // see #36994 @@ -27,6 +28,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/redox_base.rs b/src/librustc_back/target/redox_base.rs index c5e1e107753f..f26a86d4bdc0 100644 --- a/src/librustc_back/target/redox_base.rs +++ b/src/librustc_back/target/redox_base.rs @@ -8,25 +8,28 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use PanicStrategy; -use target::TargetOptions; +use {LinkerFlavor, PanicStrategy}; +use target::{LinkArgs, TargetOptions}; use std::default::Default; pub fn opts() -> TargetOptions { - TargetOptions { - pre_link_args: vec![ - // We want to be able to strip as much executable code as possible - // from the linker command line, and this flag indicates to the - // linker that it can avoid linking in dynamic libraries that don't - // actually satisfy any symbols up to that point (as with many other - // resolutions the linker does). This option only applies to all - // following libraries so we're sure to pass it as one of the first - // arguments. - "-Wl,--as-needed".to_string(), + let mut args = LinkArgs::new(); + args.insert(LinkerFlavor::Gcc, vec![ + // We want to be able to strip as much executable code as possible + // from the linker command line, and this flag indicates to the + // linker that it can avoid linking in dynamic libraries that don't + // actually satisfy any symbols up to that point (as with many other + // resolutions the linker does). This option only applies to all + // following libraries so we're sure to pass it as one of the first + // arguments. + "-Wl,--as-needed".to_string(), - // Always enable NX protection when it is available - "-Wl,-z,noexecstack".to_string() - ], + // Always enable NX protection when it is available + "-Wl,-z,noexecstack".to_string() + ]); + + TargetOptions { + pre_link_args: args, executables: true, relocation_model: "static".to_string(), disable_redzone: true, diff --git a/src/librustc_back/target/s390x_unknown_linux_gnu.rs b/src/librustc_back/target/s390x_unknown_linux_gnu.rs index 671fb4f4319b..cc8eb7c4e842 100644 --- a/src/librustc_back/target/s390x_unknown_linux_gnu.rs +++ b/src/librustc_back/target/s390x_unknown_linux_gnu.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { @@ -31,6 +32,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/sparc64_unknown_linux_gnu.rs b/src/librustc_back/target/sparc64_unknown_linux_gnu.rs index f627cc18f0b3..1bd51ac62581 100644 --- a/src/librustc_back/target/sparc64_unknown_linux_gnu.rs +++ b/src/librustc_back/target/sparc64_unknown_linux_gnu.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/sparc64_unknown_netbsd.rs b/src/librustc_back/target/sparc64_unknown_netbsd.rs index f30cebbc2d5a..bc65a17ce6ea 100644 --- a/src/librustc_back/target/sparc64_unknown_netbsd.rs +++ b/src/librustc_back/target/sparc64_unknown_netbsd.rs @@ -8,12 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::netbsd_base::opts(); base.cpu = "v9".to_string(); - base.pre_link_args.push("-m64".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); base.max_atomic_width = Some(64); Ok(Target { @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "netbsd".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/sparcv9_sun_solaris.rs b/src/librustc_back/target/sparcv9_sun_solaris.rs index c88e5a402f2f..122b38968a9c 100644 --- a/src/librustc_back/target/sparcv9_sun_solaris.rs +++ b/src/librustc_back/target/sparcv9_sun_solaris.rs @@ -8,11 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::solaris_base::opts(); - base.pre_link_args.push("-m64".to_string()); + base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string()]); // llvm calls this "v9" base.cpu = "v9".to_string(); base.max_atomic_width = Some(64); @@ -30,6 +31,7 @@ pub fn target() -> TargetResult { target_os: "solaris".to_string(), target_env: "".to_string(), target_vendor: "sun".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/thumbv6m_none_eabi.rs b/src/librustc_back/target/thumbv6m_none_eabi.rs index 6c22f9853845..08bf145e5518 100644 --- a/src/librustc_back/target/thumbv6m_none_eabi.rs +++ b/src/librustc_back/target/thumbv6m_none_eabi.rs @@ -10,6 +10,7 @@ // Targets the Cortex-M0, Cortex-M0+ and Cortex-M1 processors (ARMv6-M architecture) +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -22,6 +23,7 @@ pub fn target() -> TargetResult { target_os: "none".to_string(), target_env: "".to_string(), target_vendor: "".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { // The ARMv6-M architecture doesn't support unaligned loads/stores so we disable them diff --git a/src/librustc_back/target/thumbv7em_none_eabi.rs b/src/librustc_back/target/thumbv7em_none_eabi.rs index ddad4e3624f3..13f9cc5f65fb 100644 --- a/src/librustc_back/target/thumbv7em_none_eabi.rs +++ b/src/librustc_back/target/thumbv7em_none_eabi.rs @@ -19,6 +19,7 @@ // To opt-in to hardware accelerated floating point operations, you can use, for example, // `-C target-feature=+vfp4` or `-C target-cpu=cortex-m4`. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -31,6 +32,7 @@ pub fn target() -> TargetResult { target_os: "none".to_string(), target_env: "".to_string(), target_vendor: "".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { max_atomic_width: Some(32), diff --git a/src/librustc_back/target/thumbv7em_none_eabihf.rs b/src/librustc_back/target/thumbv7em_none_eabihf.rs index a9fac48e8e5a..929b6db6fb2c 100644 --- a/src/librustc_back/target/thumbv7em_none_eabihf.rs +++ b/src/librustc_back/target/thumbv7em_none_eabihf.rs @@ -18,6 +18,7 @@ // // To opt into double precision hardware support, use the `-C target-feature=-fp-only-sp` flag. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -30,6 +31,7 @@ pub fn target() -> TargetResult { target_os: "none".to_string(), target_env: "".to_string(), target_vendor: "".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { // `+vfp4` is the lowest common denominator between the Cortex-M4 (vfp4-16) and the diff --git a/src/librustc_back/target/thumbv7m_none_eabi.rs b/src/librustc_back/target/thumbv7m_none_eabi.rs index ed61dd0459b4..8d46e7cb9076 100644 --- a/src/librustc_back/target/thumbv7m_none_eabi.rs +++ b/src/librustc_back/target/thumbv7m_none_eabi.rs @@ -10,6 +10,7 @@ // Targets the Cortex-M3 processor (ARMv7-M) +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { @@ -22,6 +23,7 @@ pub fn target() -> TargetResult { target_os: "none".to_string(), target_env: "".to_string(), target_vendor: "".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { max_atomic_width: Some(32), diff --git a/src/librustc_back/target/wasm32_unknown_emscripten.rs b/src/librustc_back/target/wasm32_unknown_emscripten.rs index b1967fa8f37a..f5fb63038e91 100644 --- a/src/librustc_back/target/wasm32_unknown_emscripten.rs +++ b/src/librustc_back/target/wasm32_unknown_emscripten.rs @@ -8,10 +8,18 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use super::{Target, TargetOptions}; +use LinkerFlavor; +use super::{LinkArgs, Target, TargetOptions}; use super::emscripten_base::{cmd}; pub fn target() -> Result { + let mut post_link_args = LinkArgs::new(); + post_link_args.insert(LinkerFlavor::Em, + vec!["-s".to_string(), + "BINARYEN=1".to_string(), + "-s".to_string(), + "ERROR_ON_UNDEFINED_SYMBOLS=1".to_string()]); + let opts = TargetOptions { linker: cmd("emcc"), ar: cmd("emar"), @@ -26,8 +34,7 @@ pub fn target() -> Result { obj_is_bitcode: true, is_like_emscripten: true, max_atomic_width: Some(32), - post_link_args: vec!["-s".to_string(), "BINARYEN=1".to_string(), - "-s".to_string(), "ERROR_ON_UNDEFINED_SYMBOLS=1".to_string()], + post_link_args: post_link_args, target_family: Some("unix".to_string()), .. Default::default() }; @@ -40,6 +47,7 @@ pub fn target() -> Result { target_vendor: "unknown".to_string(), data_layout: "e-p:32:32-i64:64-v128:32:128-n32-S128".to_string(), arch: "wasm32".to_string(), + linker_flavor: LinkerFlavor::Em, options: opts, }) } diff --git a/src/librustc_back/target/windows_base.rs b/src/librustc_back/target/windows_base.rs index db02e142fcc8..9bde24a28dd9 100644 --- a/src/librustc_back/target/windows_base.rs +++ b/src/librustc_back/target/windows_base.rs @@ -8,26 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::TargetOptions; +use LinkerFlavor; +use target::{LinkArgs, TargetOptions}; use std::default::Default; pub fn opts() -> TargetOptions { - TargetOptions { - // FIXME(#13846) this should be enabled for windows - function_sections: false, - linker: "gcc".to_string(), - dynamic_linking: true, - executables: true, - dll_prefix: "".to_string(), - dll_suffix: ".dll".to_string(), - exe_suffix: ".exe".to_string(), - staticlib_prefix: "".to_string(), - staticlib_suffix: ".lib".to_string(), - no_default_libraries: true, - target_family: Some("windows".to_string()), - is_like_windows: true, - allows_weak_linkage: false, - pre_link_args: vec![ + let mut pre_link_args = LinkArgs::new(); + pre_link_args.insert(LinkerFlavor::Gcc, vec![ // And here, we see obscure linker flags #45. On windows, it has been // found to be necessary to have this flag to compile liblibc. // @@ -64,7 +51,34 @@ pub fn opts() -> TargetOptions { // Do not use the standard system startup files or libraries when linking "-nostdlib".to_string(), - ], + ]); + + let mut late_link_args = LinkArgs::new(); + late_link_args.insert(LinkerFlavor::Gcc, vec![ + "-lmingwex".to_string(), + "-lmingw32".to_string(), + "-lgcc".to_string(), // alas, mingw* libraries above depend on libgcc + "-lmsvcrt".to_string(), + "-luser32".to_string(), + "-lkernel32".to_string(), + ]); + + TargetOptions { + // FIXME(#13846) this should be enabled for windows + function_sections: false, + linker: "gcc".to_string(), + dynamic_linking: true, + executables: true, + dll_prefix: "".to_string(), + dll_suffix: ".dll".to_string(), + exe_suffix: ".exe".to_string(), + staticlib_prefix: "".to_string(), + staticlib_suffix: ".lib".to_string(), + no_default_libraries: true, + target_family: Some("windows".to_string()), + is_like_windows: true, + allows_weak_linkage: false, + pre_link_args: pre_link_args, pre_link_objects_exe: vec![ "crt2.o".to_string(), // mingw C runtime initialization for executables "rsbegin.o".to_string(), // Rust compiler runtime initialization, see rsbegin.rs @@ -73,14 +87,7 @@ pub fn opts() -> TargetOptions { "dllcrt2.o".to_string(), // mingw C runtime initialization for dlls "rsbegin.o".to_string(), ], - late_link_args: vec![ - "-lmingwex".to_string(), - "-lmingw32".to_string(), - "-lgcc".to_string(), // alas, mingw* libraries above depend on libgcc - "-lmsvcrt".to_string(), - "-luser32".to_string(), - "-lkernel32".to_string(), - ], + late_link_args: late_link_args, post_link_objects: vec![ "rsend.o".to_string() ], diff --git a/src/librustc_back/target/windows_msvc_base.rs b/src/librustc_back/target/windows_msvc_base.rs index efa215b419d7..421f59aea93b 100644 --- a/src/librustc_back/target/windows_msvc_base.rs +++ b/src/librustc_back/target/windows_msvc_base.rs @@ -8,10 +8,16 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::TargetOptions; +use LinkerFlavor; +use target::{LinkArgs, TargetOptions}; use std::default::Default; pub fn opts() -> TargetOptions { + let mut args = LinkArgs::new(); + args.insert(LinkerFlavor::Msvc, + vec!["/NOLOGO".to_string(), + "/NXCOMPAT".to_string()]); + TargetOptions { function_sections: true, linker: "link.exe".to_string(), @@ -56,10 +62,7 @@ pub fn opts() -> TargetOptions { target_family: Some("windows".to_string()), is_like_windows: true, is_like_msvc: true, - pre_link_args: vec![ - "/NOLOGO".to_string(), - "/NXCOMPAT".to_string(), - ], + pre_link_args: args, exe_allocation_crate: "alloc_system".to_string(), .. Default::default() diff --git a/src/librustc_back/target/x86_64_apple_darwin.rs b/src/librustc_back/target/x86_64_apple_darwin.rs index b3c1561dbcc0..8fd1b80430f4 100644 --- a/src/librustc_back/target/x86_64_apple_darwin.rs +++ b/src/librustc_back/target/x86_64_apple_darwin.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { @@ -15,7 +16,7 @@ pub fn target() -> TargetResult { base.cpu = "core2".to_string(); base.max_atomic_width = Some(128); // core2 support cmpxchg16b base.eliminate_frame_pointer = false; - base.pre_link_args.push("-m64".to_string()); + base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string()]); Ok(Target { llvm_target: "x86_64-apple-darwin".to_string(), @@ -26,6 +27,7 @@ pub fn target() -> TargetResult { target_os: "macos".to_string(), target_env: "".to_string(), target_vendor: "apple".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/x86_64_apple_ios.rs b/src/librustc_back/target/x86_64_apple_ios.rs index 7a58bb34ce7f..bbd81fd86ff5 100644 --- a/src/librustc_back/target/x86_64_apple_ios.rs +++ b/src/librustc_back/target/x86_64_apple_ios.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetOptions, TargetResult}; use super::apple_ios_base::{opts, Arch}; @@ -22,6 +23,7 @@ pub fn target() -> TargetResult { target_os: "ios".to_string(), target_env: "".to_string(), target_vendor: "apple".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: TargetOptions { max_atomic_width: Some(64), .. base diff --git a/src/librustc_back/target/x86_64_linux_android.rs b/src/librustc_back/target/x86_64_linux_android.rs new file mode 100644 index 000000000000..75cf3e124384 --- /dev/null +++ b/src/librustc_back/target/x86_64_linux_android.rs @@ -0,0 +1,34 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use LinkerFlavor; +use target::{Target, TargetResult}; + +pub fn target() -> TargetResult { + let mut base = super::android_base::opts(); + base.cpu = "x86-64".to_string(); + // https://developer.android.com/ndk/guides/abis.html#86-64 + base.features = "+mmx,+sse,+sse2,+sse3,+ssse3,+sse4.1,+sse4.2,+popcnt".to_string(); + base.max_atomic_width = Some(64); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); + + Ok(Target { + llvm_target: "x86_64-linux-android".to_string(), + target_endian: "little".to_string(), + target_pointer_width: "64".to_string(), + data_layout: "e-m:e-i64:64-f80:128-n8:16:32:64-S128".to_string(), + arch: "x86_64".to_string(), + target_os: "android".to_string(), + target_env: "".to_string(), + target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, + options: base, + }) +} diff --git a/src/librustc_back/target/x86_64_pc_windows_gnu.rs b/src/librustc_back/target/x86_64_pc_windows_gnu.rs index 321585cd65eb..10e88d88ee37 100644 --- a/src/librustc_back/target/x86_64_pc_windows_gnu.rs +++ b/src/librustc_back/target/x86_64_pc_windows_gnu.rs @@ -8,12 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::windows_base::opts(); base.cpu = "x86-64".to_string(); - base.pre_link_args.push("-m64".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); base.max_atomic_width = Some(64); Ok(Target { @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "windows".to_string(), target_env: "gnu".to_string(), target_vendor: "pc".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/x86_64_pc_windows_msvc.rs b/src/librustc_back/target/x86_64_pc_windows_msvc.rs index ea8909d213e8..b07031c4bf1a 100644 --- a/src/librustc_back/target/x86_64_pc_windows_msvc.rs +++ b/src/librustc_back/target/x86_64_pc_windows_msvc.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { @@ -24,6 +25,7 @@ pub fn target() -> TargetResult { target_os: "windows".to_string(), target_env: "msvc".to_string(), target_vendor: "pc".to_string(), + linker_flavor: LinkerFlavor::Msvc, options: base, }) } diff --git a/src/librustc_back/target/x86_64_rumprun_netbsd.rs b/src/librustc_back/target/x86_64_rumprun_netbsd.rs index 331372143969..eea4389cfd64 100644 --- a/src/librustc_back/target/x86_64_rumprun_netbsd.rs +++ b/src/librustc_back/target/x86_64_rumprun_netbsd.rs @@ -8,12 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::netbsd_base::opts(); base.cpu = "x86-64".to_string(); - base.pre_link_args.push("-m64".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); base.linker = "x86_64-rumprun-netbsd-gcc".to_string(); base.ar = "x86_64-rumprun-netbsd-ar".to_string(); base.max_atomic_width = Some(64); @@ -34,6 +35,7 @@ pub fn target() -> TargetResult { target_os: "netbsd".to_string(), target_env: "".to_string(), target_vendor: "rumprun".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/x86_64_sun_solaris.rs b/src/librustc_back/target/x86_64_sun_solaris.rs index 8e4fd94e7bce..fe8691f36950 100644 --- a/src/librustc_back/target/x86_64_sun_solaris.rs +++ b/src/librustc_back/target/x86_64_sun_solaris.rs @@ -8,11 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::solaris_base::opts(); - base.pre_link_args.push("-m64".to_string()); + base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string()]); base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "solaris".to_string(), target_env: "".to_string(), target_vendor: "sun".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/x86_64_unknown_bitrig.rs b/src/librustc_back/target/x86_64_unknown_bitrig.rs index eda16c29466b..5f87fe177a98 100644 --- a/src/librustc_back/target/x86_64_unknown_bitrig.rs +++ b/src/librustc_back/target/x86_64_unknown_bitrig.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::bitrig_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.push("-m64".to_string()); + base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string()]); Ok(Target { llvm_target: "x86_64-unknown-bitrig".to_string(), @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "bitrig".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/x86_64_unknown_dragonfly.rs b/src/librustc_back/target/x86_64_unknown_dragonfly.rs index 194efb8fc232..96f608409ffa 100644 --- a/src/librustc_back/target/x86_64_unknown_dragonfly.rs +++ b/src/librustc_back/target/x86_64_unknown_dragonfly.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::dragonfly_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.push("-m64".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); Ok(Target { llvm_target: "x86_64-unknown-dragonfly".to_string(), @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "dragonfly".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/x86_64_unknown_freebsd.rs b/src/librustc_back/target/x86_64_unknown_freebsd.rs index b127bee163b8..500629a16808 100644 --- a/src/librustc_back/target/x86_64_unknown_freebsd.rs +++ b/src/librustc_back/target/x86_64_unknown_freebsd.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::freebsd_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.push("-m64".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); Ok(Target { llvm_target: "x86_64-unknown-freebsd".to_string(), @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "freebsd".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/x86_64_unknown_fuchsia.rs b/src/librustc_back/target/x86_64_unknown_fuchsia.rs index 08fe17a556ec..6e37896d4148 100644 --- a/src/librustc_back/target/x86_64_unknown_fuchsia.rs +++ b/src/librustc_back/target/x86_64_unknown_fuchsia.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::fuchsia_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.push("-m64".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); Ok(Target { llvm_target: "x86_64-unknown-fuchsia".to_string(), @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "fuchsia".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/x86_64_unknown_haiku.rs b/src/librustc_back/target/x86_64_unknown_haiku.rs index 7cf0599037c1..7fab9128b295 100644 --- a/src/librustc_back/target/x86_64_unknown_haiku.rs +++ b/src/librustc_back/target/x86_64_unknown_haiku.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::haiku_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.push("-m64".to_string()); + base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string()]); Ok(Target { llvm_target: "x86_64-unknown-haiku".to_string(), @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "haiku".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/x86_64_unknown_linux_gnu.rs b/src/librustc_back/target/x86_64_unknown_linux_gnu.rs index f95bcb556e57..f73055cebaa2 100644 --- a/src/librustc_back/target/x86_64_unknown_linux_gnu.rs +++ b/src/librustc_back/target/x86_64_unknown_linux_gnu.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.push("-m64".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); Ok(Target { llvm_target: "x86_64-unknown-linux-gnu".to_string(), @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "gnu".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/x86_64_unknown_linux_musl.rs b/src/librustc_back/target/x86_64_unknown_linux_musl.rs index c3bf9dcca6ee..38b9c0bace52 100644 --- a/src/librustc_back/target/x86_64_unknown_linux_musl.rs +++ b/src/librustc_back/target/x86_64_unknown_linux_musl.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_musl_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.push("-m64".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); Ok(Target { llvm_target: "x86_64-unknown-linux-musl".to_string(), @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "linux".to_string(), target_env: "musl".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/x86_64_unknown_netbsd.rs b/src/librustc_back/target/x86_64_unknown_netbsd.rs index 87a7c184644d..6fe2e3fc08e2 100644 --- a/src/librustc_back/target/x86_64_unknown_netbsd.rs +++ b/src/librustc_back/target/x86_64_unknown_netbsd.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::netbsd_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.push("-m64".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); Ok(Target { llvm_target: "x86_64-unknown-netbsd".to_string(), @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "netbsd".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/x86_64_unknown_openbsd.rs b/src/librustc_back/target/x86_64_unknown_openbsd.rs index e9d645b0d38f..b292b5fc1e4e 100644 --- a/src/librustc_back/target/x86_64_unknown_openbsd.rs +++ b/src/librustc_back/target/x86_64_unknown_openbsd.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::openbsd_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.push("-m64".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); Ok(Target { llvm_target: "x86_64-unknown-openbsd".to_string(), @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "openbsd".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_back/target/x86_64_unknown_redox.rs b/src/librustc_back/target/x86_64_unknown_redox.rs index cecac06b2352..a693e76099bd 100644 --- a/src/librustc_back/target/x86_64_unknown_redox.rs +++ b/src/librustc_back/target/x86_64_unknown_redox.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use LinkerFlavor; use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::redox_base::opts(); base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); - base.pre_link_args.push("-m64".to_string()); + base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); Ok(Target { llvm_target: "x86_64-unknown-redox".to_string(), @@ -25,6 +26,7 @@ pub fn target() -> TargetResult { target_os: "redox".to_string(), target_env: "".to_string(), target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, options: base, }) } diff --git a/src/librustc_borrowck/Cargo.toml b/src/librustc_borrowck/Cargo.toml index d53318f17684..af99c0e93872 100644 --- a/src/librustc_borrowck/Cargo.toml +++ b/src/librustc_borrowck/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["dylib"] test = false [dependencies] -log = { path = "../liblog" } +log = "0.3" syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } graphviz = { path = "../libgraphviz" } diff --git a/src/librustc_borrowck/borrowck/README.md b/src/librustc_borrowck/borrowck/README.md index 5cfbd59d3336..034b7cbadd9c 100644 --- a/src/librustc_borrowck/borrowck/README.md +++ b/src/librustc_borrowck/borrowck/README.md @@ -347,7 +347,7 @@ ALIASABLE(*LV, MQ) // M-Deref-Unique ALIASABLE(LV, MQ) ``` -### Checking mutability of immutable pointer types +### Checking aliasability of immutable pointer types Immutable pointer types like `&T` are aliasable, and hence can only be borrowed immutably: @@ -357,7 +357,7 @@ ALIASABLE(*LV, imm) // M-Deref-Borrowed-Imm TYPE(LV) = &Ty ``` -### Checking mutability of mutable pointer types +### Checking aliasability of mutable pointer types `&mut T` can be frozen, so it is acceptable to borrow it as either imm or mut: @@ -633,7 +633,7 @@ Here is a concrete example of a bug this rule prevents: ```rust // Test region-reborrow-from-shorter-mut-ref.rs: -fn copy_pointer<'a,'b,T>(x: &'a mut &'b mut T) -> &'b mut T { +fn copy_borrowed_ptr<'a,'b,T>(x: &'a mut &'b mut T) -> &'b mut T { &mut **p // ERROR due to clause (1) } fn main() { diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs index 3ce31882b86c..1c5a6c3985cf 100644 --- a/src/librustc_borrowck/borrowck/check_loans.rs +++ b/src/librustc_borrowck/borrowck/check_loans.rs @@ -126,7 +126,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> { borrow_id: ast::NodeId, borrow_span: Span, cmt: mc::cmt<'tcx>, - loan_region: &'tcx ty::Region, + loan_region: ty::Region<'tcx>, bk: ty::BorrowKind, loan_cause: euv::LoanCause) { @@ -199,7 +199,7 @@ pub fn check_loans<'a, 'b, 'c, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, all_loans: all_loans, param_env: &infcx.parameter_environment }; - euv::ExprUseVisitor::new(&mut clcx, &infcx).consume_body(body); + euv::ExprUseVisitor::new(&mut clcx, &bccx.region_maps, &infcx).consume_body(body); } #[derive(PartialEq)] @@ -232,15 +232,14 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { }) } - pub fn each_in_scope_loan(&self, scope: region::CodeExtent, mut op: F) -> bool where + pub fn each_in_scope_loan(&self, scope: region::CodeExtent<'tcx>, mut op: F) -> bool where F: FnMut(&Loan<'tcx>) -> bool, { //! Like `each_issued_loan()`, but only considers loans that are //! currently in scope. - let tcx = self.tcx(); - self.each_issued_loan(scope.node_id(&tcx.region_maps), |loan| { - if tcx.region_maps.is_subscope_of(scope, loan.kill_scope) { + self.each_issued_loan(scope.node_id(), |loan| { + if self.bccx.region_maps.is_subscope_of(scope, loan.kill_scope) { op(loan) } else { true @@ -249,7 +248,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { } fn each_in_scope_loan_affecting_path(&self, - scope: region::CodeExtent, + scope: region::CodeExtent<'tcx>, loan_path: &LoanPath<'tcx>, mut op: F) -> bool where @@ -379,8 +378,8 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { new_loan); // Should only be called for loans that are in scope at the same time. - assert!(self.tcx().region_maps.scopes_intersect(old_loan.kill_scope, - new_loan.kill_scope)); + assert!(self.bccx.region_maps.scopes_intersect(old_loan.kill_scope, + new_loan.kill_scope)); self.report_error_if_loan_conflicts_with_restriction( old_loan, new_loan, old_loan, new_loan) && @@ -460,8 +459,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { // 3. Where does old loan expire. let previous_end_span = - self.tcx().hir.span(old_loan.kill_scope.node_id(&self.tcx().region_maps)) - .end_point(); + self.tcx().hir.span(old_loan.kill_scope.node_id()).end_point(); let mut err = match (new_loan.kind, old_loan.kind) { (ty::MutBorrow, ty::MutBorrow) => { @@ -710,7 +708,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { let mut ret = UseOk; self.each_in_scope_loan_affecting_path( - self.tcx().region_maps.node_extent(expr_id), use_path, |loan| { + self.tcx().node_extent(expr_id), use_path, |loan| { if !compatible_borrow_kinds(loan.kind, borrow_kind) { ret = UseWhileBorrowed(loan.loan_path.clone(), loan.span); false @@ -824,7 +822,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { // Check that we don't invalidate any outstanding loans if let Some(loan_path) = opt_loan_path(&assignee_cmt) { - let scope = self.tcx().region_maps.node_extent(assignment_id); + let scope = self.tcx().node_extent(assignment_id); self.each_in_scope_loan_affecting_path(scope, &loan_path, |loan| { self.report_illegal_mutation(assignment_span, &loan_path, loan); false diff --git a/src/librustc_borrowck/borrowck/fragments.rs b/src/librustc_borrowck/borrowck/fragments.rs index c0f681680a96..b728d4d53451 100644 --- a/src/librustc_borrowck/borrowck/fragments.rs +++ b/src/librustc_borrowck/borrowck/fragments.rs @@ -267,11 +267,11 @@ pub fn fixup_fragment_sets<'a, 'tcx>(this: &MoveData<'tcx>, tcx: TyCtxt<'a, 'tcx // First, filter out duplicates moved.sort(); moved.dedup(); - debug!("fragments 1 moved: {:?}", path_lps(&moved[..])); + debug!("fragments 1 moved: {:?}", path_lps(&moved)); assigned.sort(); assigned.dedup(); - debug!("fragments 1 assigned: {:?}", path_lps(&assigned[..])); + debug!("fragments 1 assigned: {:?}", path_lps(&assigned)); // Second, build parents from the moved and assigned. for m in &moved { @@ -291,14 +291,14 @@ pub fn fixup_fragment_sets<'a, 'tcx>(this: &MoveData<'tcx>, tcx: TyCtxt<'a, 'tcx parents.sort(); parents.dedup(); - debug!("fragments 2 parents: {:?}", path_lps(&parents[..])); + debug!("fragments 2 parents: {:?}", path_lps(&parents)); // Third, filter the moved and assigned fragments down to just the non-parents - moved.retain(|f| non_member(*f, &parents[..])); - debug!("fragments 3 moved: {:?}", path_lps(&moved[..])); + moved.retain(|f| non_member(*f, &parents)); + debug!("fragments 3 moved: {:?}", path_lps(&moved)); - assigned.retain(|f| non_member(*f, &parents[..])); - debug!("fragments 3 assigned: {:?}", path_lps(&assigned[..])); + assigned.retain(|f| non_member(*f, &parents)); + debug!("fragments 3 assigned: {:?}", path_lps(&assigned)); // Fourth, build the leftover from the moved, assigned, and parents. for m in &moved { @@ -316,16 +316,16 @@ pub fn fixup_fragment_sets<'a, 'tcx>(this: &MoveData<'tcx>, tcx: TyCtxt<'a, 'tcx unmoved.sort(); unmoved.dedup(); - debug!("fragments 4 unmoved: {:?}", frag_lps(&unmoved[..])); + debug!("fragments 4 unmoved: {:?}", frag_lps(&unmoved)); // Fifth, filter the leftover fragments down to its core. unmoved.retain(|f| match *f { AllButOneFrom(_) => true, - Just(mpi) => non_member(mpi, &parents[..]) && - non_member(mpi, &moved[..]) && - non_member(mpi, &assigned[..]) + Just(mpi) => non_member(mpi, &parents) && + non_member(mpi, &moved) && + non_member(mpi, &assigned) }); - debug!("fragments 5 unmoved: {:?}", frag_lps(&unmoved[..])); + debug!("fragments 5 unmoved: {:?}", frag_lps(&unmoved)); // Swap contents back in. fragments.unmoved_fragments = unmoved; diff --git a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs index 0577ba7f45a9..f193588dd7d6 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs @@ -11,7 +11,7 @@ //! Computes moves. use borrowck::*; -use borrowck::gather_loans::move_error::MoveSpanAndPath; +use borrowck::gather_loans::move_error::MovePlace; use borrowck::gather_loans::move_error::{MoveError, MoveErrorCollector}; use borrowck::move_data::*; use rustc::middle::expr_use_visitor as euv; @@ -23,13 +23,67 @@ use rustc::ty::{self, Ty}; use std::rc::Rc; use syntax::ast; use syntax_pos::Span; -use rustc::hir::{self, PatKind}; +use rustc::hir::*; +use rustc::hir::map::Node::*; struct GatherMoveInfo<'tcx> { id: ast::NodeId, kind: MoveKind, cmt: mc::cmt<'tcx>, - span_path_opt: Option + span_path_opt: Option> +} + +/// Represents the kind of pattern +#[derive(Debug, Clone, Copy)] +pub enum PatternSource<'tcx> { + MatchExpr(&'tcx Expr), + LetDecl(&'tcx Local), + Other, +} + +/// Analyzes the context where the pattern appears to determine the +/// kind of hint we want to give. In particular, if the pattern is in a `match` +/// or nested within other patterns, we want to suggest a `ref` binding: +/// +/// let (a, b) = v[0]; // like the `a` and `b` patterns here +/// match v[0] { a => ... } // or the `a` pattern here +/// +/// But if the pattern is the outermost pattern in a `let`, we would rather +/// suggest that the author add a `&` to the initializer: +/// +/// let x = v[0]; // suggest `&v[0]` here +/// +/// In this latter case, this function will return `PatternSource::LetDecl` +/// with a reference to the let +fn get_pattern_source<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pat: &Pat) -> PatternSource<'tcx> { + + let parent = tcx.hir.get_parent_node(pat.id); + + match tcx.hir.get(parent) { + NodeExpr(ref e) => { + // the enclosing expression must be a `match` or something else + assert!(match e.node { + ExprMatch(..) => true, + _ => return PatternSource::Other, + }); + PatternSource::MatchExpr(e) + } + NodeStmt(ref s) => { + // the enclosing statement must be a `let` or something else + match s.node { + StmtDecl(ref decl, _) => { + match decl.node { + DeclLocal(ref local) => PatternSource::LetDecl(local), + _ => return PatternSource::Other, + } + } + _ => return PatternSource::Other, + } + } + + _ => return PatternSource::Other, + + } } pub fn gather_decl<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, @@ -95,11 +149,15 @@ pub fn gather_move_from_pat<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, move_error_collector: &mut MoveErrorCollector<'tcx>, move_pat: &hir::Pat, cmt: mc::cmt<'tcx>) { + let source = get_pattern_source(bccx.tcx,move_pat); let pat_span_path_opt = match move_pat.node { PatKind::Binding(_, _, ref path1, _) => { - Some(MoveSpanAndPath{span: move_pat.span, - name: path1.node}) - }, + Some(MovePlace { + span: move_pat.span, + name: path1.node, + pat_source: source, + }) + } _ => None, }; let move_info = GatherMoveInfo { @@ -108,6 +166,11 @@ pub fn gather_move_from_pat<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, cmt: cmt, span_path_opt: pat_span_path_opt, }; + + debug!("gather_move_from_pat: move_pat={:?} source={:?}", + move_pat, + source); + gather_move(bccx, move_data, move_error_collector, move_info); } diff --git a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs index bbfb7e5874ea..12854d3c9792 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs @@ -24,11 +24,11 @@ use syntax_pos::Span; type R = Result<(),()>; pub fn guarantee_lifetime<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, - item_scope: region::CodeExtent, + item_scope: region::CodeExtent<'tcx>, span: Span, cause: euv::LoanCause, cmt: mc::cmt<'tcx>, - loan_region: &'tcx ty::Region, + loan_region: ty::Region<'tcx>, _: ty::BorrowKind) -> Result<(),()> { //! Reports error if `loan_region` is larger than S @@ -52,11 +52,11 @@ struct GuaranteeLifetimeContext<'a, 'tcx: 'a> { bccx: &'a BorrowckCtxt<'a, 'tcx>, // the scope of the function body for the enclosing item - item_scope: region::CodeExtent, + item_scope: region::CodeExtent<'tcx>, span: Span, cause: euv::LoanCause, - loan_region: &'tcx ty::Region, + loan_region: ty::Region<'tcx>, cmt_original: mc::cmt<'tcx> } @@ -92,7 +92,7 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> { } } - fn check_scope(&self, max_scope: &'tcx ty::Region) -> R { + fn check_scope(&self, max_scope: ty::Region<'tcx>) -> R { //! Reports an error if `loan_region` is larger than `max_scope` if !self.bccx.is_subregion_of(self.loan_region, max_scope) { @@ -102,7 +102,7 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> { } } - fn scope(&self, cmt: &mc::cmt<'tcx>) -> &'tcx ty::Region { + fn scope(&self, cmt: &mc::cmt<'tcx>) -> ty::Region<'tcx> { //! Returns the maximal region scope for the which the //! lvalue `cmt` is guaranteed to be valid without any //! rooting etc, and presuming `cmt` is not mutated. @@ -116,11 +116,11 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> { } Categorization::Local(local_id) => { self.bccx.tcx.mk_region(ty::ReScope( - self.bccx.tcx.region_maps.var_scope(local_id))) + self.bccx.region_maps.var_scope(local_id))) } Categorization::StaticItem | Categorization::Deref(.., mc::UnsafePtr(..)) => { - self.bccx.tcx.mk_region(ty::ReStatic) + self.bccx.tcx.types.re_static } Categorization::Deref(.., mc::BorrowedPtr(_, r)) | Categorization::Deref(.., mc::Implicit(_, r)) => { diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs index 28b6c7a13f17..8c1bcdc1fe2b 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs @@ -45,13 +45,13 @@ pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, bccx: bccx, infcx: &infcx, all_loans: Vec::new(), - item_ub: bccx.tcx.region_maps.node_extent(body.node_id), + item_ub: bccx.tcx.node_extent(body.node_id), move_data: MoveData::new(), move_error_collector: move_error::MoveErrorCollector::new(), }; let body = glcx.bccx.tcx.hir.body(body); - euv::ExprUseVisitor::new(&mut glcx, &infcx).consume_body(body); + euv::ExprUseVisitor::new(&mut glcx, &bccx.region_maps, &infcx).consume_body(body); glcx.report_potential_errors(); let GatherLoanCtxt { all_loans, move_data, .. } = glcx; @@ -66,7 +66,7 @@ struct GatherLoanCtxt<'a, 'tcx: 'a> { all_loans: Vec>, /// `item_ub` is used as an upper-bound on the lifetime whenever we /// ask for the scope of an expression categorized as an upvar. - item_ub: region::CodeExtent, + item_ub: region::CodeExtent<'tcx>, } impl<'a, 'tcx> euv::Delegate<'tcx> for GatherLoanCtxt<'a, 'tcx> { @@ -127,7 +127,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for GatherLoanCtxt<'a, 'tcx> { borrow_id: ast::NodeId, borrow_span: Span, cmt: mc::cmt<'tcx>, - loan_region: &'tcx ty::Region, + loan_region: ty::Region<'tcx>, bk: ty::BorrowKind, loan_cause: euv::LoanCause) { @@ -188,14 +188,6 @@ fn check_aliasability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, // user knows what they're doing in these cases. Ok(()) } - (mc::Aliasability::ImmutableUnique(_), ty::MutBorrow) => { - bccx.report_aliasability_violation( - borrow_span, - loan_cause, - mc::AliasableReason::UnaliasableImmutable, - cmt); - Err(()) - } (mc::Aliasability::FreelyAliasable(alias_cause), ty::UniqueImmBorrow) | (mc::Aliasability::FreelyAliasable(alias_cause), ty::MutBorrow) => { bccx.report_aliasability_violation( @@ -307,7 +299,7 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> { borrow_span: Span, cmt: mc::cmt<'tcx>, req_kind: ty::BorrowKind, - loan_region: &'tcx ty::Region, + loan_region: ty::Region<'tcx>, cause: euv::LoanCause) { debug!("guarantee_valid(borrow_id={}, cmt={:?}, \ req_mutbl={:?}, loan_region={:?})", @@ -361,7 +353,7 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> { let loan_scope = match *loan_region { ty::ReScope(scope) => scope, - ty::ReFree(ref fr) => fr.scope, + ty::ReFree(ref fr) => fr.scope.unwrap_or(self.item_ub), ty::ReStatic => self.item_ub, @@ -379,7 +371,7 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> { }; debug!("loan_scope = {:?}", loan_scope); - let borrow_scope = self.tcx().region_maps.node_extent(borrow_id); + let borrow_scope = self.tcx().node_extent(borrow_id); let gen_scope = self.compute_gen_scope(borrow_scope, loan_scope); debug!("gen_scope = {:?}", gen_scope); @@ -458,23 +450,23 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> { } pub fn compute_gen_scope(&self, - borrow_scope: region::CodeExtent, - loan_scope: region::CodeExtent) - -> region::CodeExtent { + borrow_scope: region::CodeExtent<'tcx>, + loan_scope: region::CodeExtent<'tcx>) + -> region::CodeExtent<'tcx> { //! Determine when to introduce the loan. 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. - if self.bccx.tcx.region_maps.is_subscope_of(borrow_scope, loan_scope) { + if self.bccx.region_maps.is_subscope_of(borrow_scope, loan_scope) { borrow_scope } else { loan_scope } } - pub fn compute_kill_scope(&self, loan_scope: region::CodeExtent, lp: &LoanPath<'tcx>) - -> region::CodeExtent { + pub fn compute_kill_scope(&self, loan_scope: region::CodeExtent<'tcx>, lp: &LoanPath<'tcx>) + -> region::CodeExtent<'tcx> { //! Determine when the loan restrictions go out of scope. //! This is either when the lifetime expires or when the //! local variable which roots the loan-path goes out of scope, @@ -496,12 +488,11 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> { //! with immutable `&` pointers, because borrows of such pointers //! do not require restrictions and hence do not cause a loan. - let lexical_scope = lp.kill_scope(self.bccx.tcx); - let rm = &self.bccx.tcx.region_maps; - if rm.is_subscope_of(lexical_scope, loan_scope) { + let lexical_scope = lp.kill_scope(self.bccx); + if self.bccx.region_maps.is_subscope_of(lexical_scope, loan_scope) { lexical_scope } else { - assert!(self.bccx.tcx.region_maps.is_subscope_of(loan_scope, lexical_scope)); + assert!(self.bccx.region_maps.is_subscope_of(loan_scope, lexical_scope)); loan_scope } } @@ -510,4 +501,3 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> { self.move_error_collector.report_potential_errors(self.bccx); } } - diff --git a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs index 3678c2e55c1f..b7ce9d982331 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs @@ -11,11 +11,13 @@ use borrowck::BorrowckCtxt; use rustc::middle::mem_categorization as mc; use rustc::middle::mem_categorization::Categorization; +use rustc::middle::mem_categorization::NoteClosureEnv; use rustc::middle::mem_categorization::InteriorOffsetKind as Kind; use rustc::ty; use syntax::ast; use syntax_pos; use errors::DiagnosticBuilder; +use borrowck::gather_loans::gather_moves::PatternSource; pub struct MoveErrorCollector<'tcx> { errors: Vec> @@ -39,12 +41,12 @@ impl<'tcx> MoveErrorCollector<'tcx> { pub struct MoveError<'tcx> { move_from: mc::cmt<'tcx>, - move_to: Option + move_to: Option> } impl<'tcx> MoveError<'tcx> { pub fn with_move_info(move_from: mc::cmt<'tcx>, - move_to: Option) + move_to: Option>) -> MoveError<'tcx> { MoveError { move_from: move_from, @@ -54,28 +56,48 @@ impl<'tcx> MoveError<'tcx> { } #[derive(Clone)] -pub struct MoveSpanAndPath { +pub struct MovePlace<'tcx> { pub span: syntax_pos::Span, pub name: ast::Name, + pub pat_source: PatternSource<'tcx>, } pub struct GroupedMoveErrors<'tcx> { move_from: mc::cmt<'tcx>, - move_to_places: Vec + move_to_places: Vec> } -fn report_move_errors<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, - errors: &Vec>) { +fn report_move_errors<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, errors: &Vec>) { let grouped_errors = group_errors_with_same_origin(errors); for error in &grouped_errors { let mut err = report_cannot_move_out_of(bccx, error.move_from.clone()); let mut is_first_note = true; - for move_to in &error.move_to_places { - err = note_move_destination(err, move_to.span, - move_to.name, is_first_note); - is_first_note = false; + match error.move_to_places.get(0) { + Some(&MovePlace { pat_source: PatternSource::LetDecl(ref e), .. }) => { + // ignore patterns that are found at the top-level of a `let`; + // see `get_pattern_source()` for details + let initializer = + e.init.as_ref().expect("should have an initializer to get an error"); + if let Ok(snippet) = bccx.tcx.sess.codemap().span_to_snippet(initializer.span) { + err.span_suggestion(initializer.span, + "consider using a reference instead", + format!("&{}", snippet)); + } + } + _ => { + for move_to in &error.move_to_places { + + err = note_move_destination(err, move_to.span, move_to.name, is_first_note); + is_first_note = false; + } + } + } + if let NoteClosureEnv(upvar_id) = error.move_from.note { + err.span_label(bccx.tcx.hir.span(upvar_id.var_id), + &"captured outer variable"); } err.emit(); + } } diff --git a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs index fdcefdc0d430..7f90a8b19d4a 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs @@ -31,7 +31,7 @@ pub fn compute_restrictions<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, span: Span, cause: euv::LoanCause, cmt: mc::cmt<'tcx>, - loan_region: &'tcx ty::Region) + loan_region: ty::Region<'tcx>) -> RestrictionResult<'tcx> { let ctxt = RestrictionsContext { bccx: bccx, @@ -49,7 +49,7 @@ pub fn compute_restrictions<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, struct RestrictionsContext<'a, 'tcx: 'a> { bccx: &'a BorrowckCtxt<'a, 'tcx>, span: Span, - loan_region: &'tcx ty::Region, + loan_region: ty::Region<'tcx>, cause: euv::LoanCause, } diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs index 8b246105f616..f0f082a2561c 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs @@ -181,6 +181,7 @@ pub struct DataflowAnalysis<'a, 'tcx: 'a, O> where O: BitDenotation { flow_state: DataflowState, + dead_unwinds: &'a IdxSet, mir: &'a Mir<'tcx>, } @@ -377,6 +378,7 @@ impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D> { pub fn new(_tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &'a Mir<'tcx>, + dead_unwinds: &'a IdxSet, denotation: D) -> Self { let bits_per_block = denotation.bits_per_block(); let usize_bits = mem::size_of::() * 8; @@ -397,6 +399,7 @@ impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D> DataflowAnalysis { mir: mir, + dead_unwinds: dead_unwinds, flow_state: DataflowState { sets: AllSets { bits_per_block: bits_per_block, @@ -452,7 +455,9 @@ impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D> ref target, value: _, location: _, unwind: Some(ref unwind) } => { self.propagate_bits_into_entry_set_for(in_out, changed, target); - self.propagate_bits_into_entry_set_for(in_out, changed, unwind); + if !self.dead_unwinds.contains(&bb) { + self.propagate_bits_into_entry_set_for(in_out, changed, unwind); + } } mir::TerminatorKind::SwitchInt { ref targets, .. } => { for target in targets { @@ -461,7 +466,9 @@ impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D> } mir::TerminatorKind::Call { ref cleanup, ref destination, func: _, args: _ } => { if let Some(ref unwind) = *cleanup { - self.propagate_bits_into_entry_set_for(in_out, changed, unwind); + if !self.dead_unwinds.contains(&bb) { + self.propagate_bits_into_entry_set_for(in_out, changed, unwind); + } } if let Some((ref dest_lval, ref dest_bb)) = *destination { // N.B.: This must be done *last*, after all other diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs index 88ec86cc95d6..4ae8bdc284b2 100644 --- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs +++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs @@ -11,12 +11,12 @@ use super::gather_moves::{HasMoveData, MoveData, MovePathIndex, LookupResult}; use super::dataflow::{MaybeInitializedLvals, MaybeUninitializedLvals}; use super::dataflow::{DataflowResults}; -use super::{drop_flag_effects_for_location, on_all_children_bits}; -use super::on_lookup_result_bits; +use super::{on_all_children_bits, on_all_drop_children_bits}; +use super::{drop_flag_effects_for_location, on_lookup_result_bits}; use super::MoveDataParamEnv; use rustc::ty::{self, TyCtxt}; use rustc::mir::*; -use rustc::mir::transform::{Pass, MirPass, MirSource}; +use rustc::mir::transform::{MirPass, MirSource}; use rustc::middle::const_val::ConstVal; use rustc::util::nodemap::FxHashMap; use rustc_data_structures::indexed_set::IdxSetBuf; @@ -24,6 +24,7 @@ use rustc_data_structures::indexed_vec::Idx; use rustc_mir::util::patch::MirPatch; use rustc_mir::util::elaborate_drops::{DropFlagState, elaborate_drop}; use rustc_mir::util::elaborate_drops::{DropElaborator, DropStyle, DropFlagMode}; +use syntax::ast; use syntax_pos::Span; use std::fmt; @@ -31,9 +32,11 @@ use std::u32; pub struct ElaborateDrops; -impl<'tcx> MirPass<'tcx> for ElaborateDrops { - fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - src: MirSource, mir: &mut Mir<'tcx>) +impl MirPass for ElaborateDrops { + fn run_pass<'a, 'tcx>(&self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + src: MirSource, + mir: &mut Mir<'tcx>) { debug!("elaborate_drops({:?} @ {:?})", src, mir.span); match src { @@ -49,12 +52,13 @@ impl<'tcx> MirPass<'tcx> for ElaborateDrops { move_data: move_data, param_env: param_env }; + let dead_unwinds = find_dead_unwinds(tcx, mir, id, &env); let flow_inits = - super::do_dataflow(tcx, mir, id, &[], + super::do_dataflow(tcx, mir, id, &[], &dead_unwinds, MaybeInitializedLvals::new(tcx, mir, &env), |bd, p| &bd.move_data().move_paths[p]); let flow_uninits = - super::do_dataflow(tcx, mir, id, &[], + super::do_dataflow(tcx, mir, id, &[], &dead_unwinds, MaybeUninitializedLvals::new(tcx, mir, &env), |bd, p| &bd.move_data().move_paths[p]); @@ -72,7 +76,66 @@ impl<'tcx> MirPass<'tcx> for ElaborateDrops { } } -impl Pass for ElaborateDrops {} +/// Return the set of basic blocks whose unwind edges are known +/// to not be reachable, because they are `drop` terminators +/// that can't drop anything. +fn find_dead_unwinds<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + mir: &Mir<'tcx>, + id: ast::NodeId, + env: &MoveDataParamEnv<'tcx>) + -> IdxSetBuf +{ + debug!("find_dead_unwinds({:?})", mir.span); + // We only need to do this pass once, because unwind edges can only + // reach cleanup blocks, which can't have unwind edges themselves. + let mut dead_unwinds = IdxSetBuf::new_empty(mir.basic_blocks().len()); + let flow_inits = + super::do_dataflow(tcx, mir, id, &[], &dead_unwinds, + MaybeInitializedLvals::new(tcx, mir, &env), + |bd, p| &bd.move_data().move_paths[p]); + for (bb, bb_data) in mir.basic_blocks().iter_enumerated() { + match bb_data.terminator().kind { + TerminatorKind::Drop { ref location, unwind: Some(_), .. } | + TerminatorKind::DropAndReplace { ref location, unwind: Some(_), .. } => { + let mut init_data = InitializationData { + live: flow_inits.sets().on_entry_set_for(bb.index()).to_owned(), + dead: IdxSetBuf::new_empty(env.move_data.move_paths.len()), + }; + debug!("find_dead_unwinds @ {:?}: {:?}; init_data={:?}", + bb, bb_data, init_data.live); + for stmt in 0..bb_data.statements.len() { + let loc = Location { block: bb, statement_index: stmt }; + init_data.apply_location(tcx, mir, env, loc); + } + + let path = match env.move_data.rev_lookup.find(location) { + LookupResult::Exact(e) => e, + LookupResult::Parent(..) => { + debug!("find_dead_unwinds: has parent; skipping"); + continue + } + }; + + debug!("find_dead_unwinds @ {:?}: path({:?})={:?}", bb, location, path); + + let mut maybe_live = false; + on_all_drop_children_bits(tcx, mir, &env, path, |child| { + let (child_maybe_live, _) = init_data.state(child); + maybe_live |= child_maybe_live; + }); + + debug!("find_dead_unwinds @ {:?}: maybe_live={}", bb, maybe_live); + if !maybe_live { + dead_unwinds.add(&bb); + } + } + _ => {} + } + } + + dead_unwinds +} struct InitializationData { live: IdxSetBuf, @@ -144,17 +207,14 @@ impl<'a, 'b, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, 'b, 'tcx> { let mut some_live = false; let mut some_dead = false; let mut children_count = 0; - on_all_children_bits( - self.tcx(), self.mir(), self.ctxt.move_data(), - path, |child| { - if self.ctxt.path_needs_drop(child) { - let (live, dead) = self.init_data.state(child); - debug!("elaborate_drop: state({:?}) = {:?}", - child, (live, dead)); - some_live |= live; - some_dead |= dead; - children_count += 1; - } + on_all_drop_children_bits( + self.tcx(), self.mir(), self.ctxt.env, path, |child| { + let (live, dead) = self.init_data.state(child); + debug!("elaborate_drop: state({:?}) = {:?}", + child, (live, dead)); + some_live |= live; + some_dead |= dead; + children_count += 1; }); ((some_live, some_dead), children_count != 1) } @@ -247,12 +307,12 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { data } - fn create_drop_flag(&mut self, index: MovePathIndex) { + fn create_drop_flag(&mut self, index: MovePathIndex, span: Span) { let tcx = self.tcx; let patch = &mut self.patch; debug!("create_drop_flag({:?})", self.mir.span); self.drop_flags.entry(index).or_insert_with(|| { - patch.new_temp(tcx.types.bool) + patch.new_temp(tcx.types.bool, span) }); } @@ -276,15 +336,6 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { self.patch } - fn path_needs_drop(&self, path: MovePathIndex) -> bool - { - let lvalue = &self.move_data().move_paths[path].lvalue; - let ty = lvalue.ty(self.mir, self.tcx).to_ty(self.tcx); - debug!("path_needs_drop({:?}, {:?} : {:?})", path, lvalue, ty); - - self.tcx.type_needs_drop_given_env(ty, self.param_env()) - } - fn collect_drop_flags(&mut self) { for (bb, data) in self.mir.basic_blocks().iter_enumerated() { @@ -318,14 +369,12 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { } }; - on_all_children_bits(self.tcx, self.mir, self.move_data(), path, |child| { - if self.path_needs_drop(child) { - let (maybe_live, maybe_dead) = init_data.state(child); - debug!("collect_drop_flags: collecting {:?} from {:?}@{:?} - {:?}", - child, location, path, (maybe_live, maybe_dead)); - if maybe_live && maybe_dead { - self.create_drop_flag(child) - } + on_all_drop_children_bits(self.tcx, self.mir, self.env, path, |child| { + let (maybe_live, maybe_dead) = init_data.state(child); + debug!("collect_drop_flags: collecting {:?} from {:?}@{:?} - {:?}", + child, location, path, (maybe_live, maybe_dead)); + if maybe_live && maybe_dead { + self.create_drop_flag(child, terminator.source_info.span) } }); } diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs index 9237bb31f6bd..47f708bf5836 100644 --- a/src/librustc_borrowck/borrowck/mir/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/mod.rs @@ -17,6 +17,7 @@ use rustc::mir::{self, BasicBlock, BasicBlockData, Mir, Statement, Terminator, L use rustc::session::Session; use rustc::ty::{self, TyCtxt}; use rustc_mir::util::elaborate_drops::DropFlagState; +use rustc_data_structures::indexed_set::{IdxSet, IdxSetBuf}; mod abs_domain; pub mod elaborate_drops; @@ -60,18 +61,25 @@ pub fn borrowck_mir(bcx: &mut BorrowckCtxt, let def_id = tcx.hir.local_def_id(id); debug!("borrowck_mir({}) UNIMPLEMENTED", tcx.item_path_str(def_id)); - let mir = &tcx.item_mir(def_id); + // It is safe for us to borrow `mir_validated()`: `optimized_mir` + // steals it, but it forces the `borrowck` query. + let mir = &tcx.mir_validated(def_id).borrow(); + let param_env = ty::ParameterEnvironment::for_item(tcx, id); let move_data = MoveData::gather_moves(mir, tcx, ¶m_env); let mdpe = MoveDataParamEnv { move_data: move_data, param_env: param_env }; + let dead_unwinds = IdxSetBuf::new_empty(mir.basic_blocks().len()); let flow_inits = - do_dataflow(tcx, mir, id, attributes, MaybeInitializedLvals::new(tcx, mir, &mdpe), + do_dataflow(tcx, mir, id, attributes, &dead_unwinds, + MaybeInitializedLvals::new(tcx, mir, &mdpe), |bd, i| &bd.move_data().move_paths[i]); let flow_uninits = - do_dataflow(tcx, mir, id, attributes, MaybeUninitializedLvals::new(tcx, mir, &mdpe), + do_dataflow(tcx, mir, id, attributes, &dead_unwinds, + MaybeUninitializedLvals::new(tcx, mir, &mdpe), |bd, i| &bd.move_data().move_paths[i]); let flow_def_inits = - do_dataflow(tcx, mir, id, attributes, DefinitelyInitializedLvals::new(tcx, mir, &mdpe), + do_dataflow(tcx, mir, id, attributes, &dead_unwinds, + DefinitelyInitializedLvals::new(tcx, mir, &mdpe), |bd, i| &bd.move_data().move_paths[i]); if has_rustc_mir_with(attributes, "rustc_peek_maybe_init").is_some() { @@ -108,6 +116,7 @@ fn do_dataflow<'a, 'tcx, BD, P>(tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &Mir<'tcx>, node_id: ast::NodeId, attributes: &[ast::Attribute], + dead_unwinds: &IdxSet, bd: BD, p: P) -> DataflowResults @@ -137,7 +146,7 @@ fn do_dataflow<'a, 'tcx, BD, P>(tcx: TyCtxt<'a, 'tcx, 'tcx>, node_id: node_id, print_preflow_to: print_preflow_to, print_postflow_to: print_postflow_to, - flow_state: DataflowAnalysis::new(tcx, mir, bd), + flow_state: DataflowAnalysis::new(tcx, mir, dead_unwinds, bd), }; mbcx.dataflow(p); @@ -303,6 +312,27 @@ fn on_all_children_bits<'a, 'tcx, F>( on_all_children_bits(tcx, mir, move_data, move_path_index, &mut each_child); } +fn on_all_drop_children_bits<'a, 'tcx, F>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + mir: &Mir<'tcx>, + ctxt: &MoveDataParamEnv<'tcx>, + path: MovePathIndex, + mut each_child: F) + where F: FnMut(MovePathIndex) +{ + on_all_children_bits(tcx, mir, &ctxt.move_data, path, |child| { + let lvalue = &ctxt.move_data.move_paths[path].lvalue; + let ty = lvalue.ty(mir, tcx).to_ty(tcx); + debug!("on_all_drop_children_bits({:?}, {:?} : {:?})", path, lvalue, ty); + + if ty.needs_drop(tcx, &ctxt.param_env) { + each_child(child); + } else { + debug!("on_all_drop_children_bits - skipping") + } + }) +} + fn drop_flag_effects_for_function_entry<'a, 'tcx, F>( tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &Mir<'tcx>, diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 20d495976b05..f8073455bd08 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -22,7 +22,6 @@ pub use self::mir::elaborate_drops::ElaborateDrops; use self::InteriorKind::*; -use rustc::dep_graph::DepNode; use rustc::hir::map as hir_map; use rustc::hir::map::blocks::FnLikeNode; use rustc::cfg; @@ -34,8 +33,11 @@ use rustc::hir::def_id::DefId; use rustc::middle::expr_use_visitor as euv; use rustc::middle::mem_categorization as mc; use rustc::middle::mem_categorization::Categorization; -use rustc::middle::region; +use rustc::middle::mem_categorization::ImmutabilityBlame; +use rustc::middle::region::{self, RegionMaps}; +use rustc::middle::free_region::RegionRelations; use rustc::ty::{self, TyCtxt}; +use rustc::ty::maps::Providers; use std::fmt; use std::rc::Rc; @@ -61,18 +63,18 @@ pub struct LoanDataFlowOperator; pub type LoanDataFlow<'a, 'tcx> = DataFlowContext<'a, 'tcx, LoanDataFlowOperator>; pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - tcx.dep_graph.with_task(DepNode::BorrowCheckKrate, tcx, (), check_crate_task); - - fn check_crate_task<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, (): ()) { - tcx.visit_all_bodies_in_krate(|body_owner_def_id, body_id| { - tcx.dep_graph.with_task(DepNode::BorrowCheck(body_owner_def_id), - tcx, - body_id, - borrowck_fn); - }); + for body_owner_def_id in tcx.body_owners() { + tcx.borrowck(body_owner_def_id); } } +pub fn provide(providers: &mut Providers) { + *providers = Providers { + borrowck, + ..*providers + }; +} + /// Collection of conclusions determined via borrow checker analyses. pub struct AnalysisData<'a, 'tcx: 'a> { pub all_loans: Vec>, @@ -80,23 +82,43 @@ pub struct AnalysisData<'a, 'tcx: 'a> { pub move_data: move_data::FlowedMoveData<'a, 'tcx>, } -fn borrowck_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, body_id: hir::BodyId) { - debug!("borrowck_fn(body_id={:?})", body_id); +fn borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, owner_def_id: DefId) { + debug!("borrowck(body_owner_def_id={:?})", owner_def_id); - let owner_id = tcx.hir.body_owner(body_id); - let owner_def_id = tcx.hir.local_def_id(owner_id); + let owner_id = tcx.hir.as_local_node_id(owner_def_id).unwrap(); + + match tcx.hir.get(owner_id) { + hir_map::NodeStructCtor(_) | + hir_map::NodeVariant(_) => { + // We get invoked with anything that has MIR, but some of + // those things (notably the synthesized constructors from + // tuple structs/variants) do not have an associated body + // and do not need borrowchecking. + return; + } + _ => { } + } + + let body_id = tcx.hir.body_owned_by(owner_id); let attributes = tcx.get_attrs(owner_def_id); - let tables = tcx.item_tables(owner_def_id); - - let mut bccx = &mut BorrowckCtxt { - tcx: tcx, - tables: tables, - }; + let tables = tcx.typeck_tables_of(owner_def_id); + let region_maps = tcx.region_maps(owner_def_id); + let mut bccx = &mut BorrowckCtxt { tcx, tables, region_maps, owner_def_id }; let body = bccx.tcx.hir.body(body_id); if bccx.tcx.has_attr(owner_def_id, "rustc_mir_borrowck") { mir::borrowck_mir(bccx, owner_id, &attributes); + } else { + // Eventually, borrowck will always read the MIR, but at the + // moment we do not. So, for now, we always force MIR to be + // constructed for a given fn, since this may result in errors + // being reported and we want that to happen. + // + // Note that `mir_validated` is a "stealable" result; the + // thief, `optimized_mir()`, forces borrowck, so we know that + // is not yet stolen. + tcx.mir_validated(owner_def_id).borrow(); } let cfg = cfg::CFG::new(bccx.tcx, &body); @@ -112,7 +134,7 @@ fn borrowck_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, body_id: hir::BodyId) { &flowed_moves.move_data, owner_id); - check_loans::check_loans(bccx, &loan_dfcx, &flowed_moves, &all_loans[..], body); + check_loans::check_loans(bccx, &loan_dfcx, &flowed_moves, &all_loans, body); } fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>, @@ -140,15 +162,15 @@ fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>, id_range, all_loans.len()); for (loan_idx, loan) in all_loans.iter().enumerate() { - loan_dfcx.add_gen(loan.gen_scope.node_id(&tcx.region_maps), loan_idx); + loan_dfcx.add_gen(loan.gen_scope.node_id(), loan_idx); loan_dfcx.add_kill(KillFrom::ScopeEnd, - loan.kill_scope.node_id(&tcx.region_maps), loan_idx); + loan.kill_scope.node_id(), loan_idx); } loan_dfcx.add_kills_from_flow_exits(cfg); loan_dfcx.propagate(cfg, body); let flowed_moves = move_data::FlowedMoveData::new(move_data, - this.tcx, + this, cfg, id_range, body); @@ -168,12 +190,9 @@ pub fn build_borrowck_dataflow_data_for_fn<'a, 'tcx>( { let owner_id = tcx.hir.body_owner(body_id); let owner_def_id = tcx.hir.local_def_id(owner_id); - let tables = tcx.item_tables(owner_def_id); - - let mut bccx = BorrowckCtxt { - tcx: tcx, - tables: tables, - }; + let tables = tcx.typeck_tables_of(owner_def_id); + let region_maps = tcx.region_maps(owner_def_id); + let mut bccx = BorrowckCtxt { tcx, tables, region_maps, owner_def_id }; let dataflow_data = build_borrowck_dataflow_data(&mut bccx, cfg, body_id); (bccx, dataflow_data) @@ -188,6 +207,10 @@ pub struct BorrowckCtxt<'a, 'tcx: 'a> { // tables for the current thing we are checking; set to // Some in `borrowck_fn` and cleared later tables: &'a ty::TypeckTables<'tcx>, + + region_maps: Rc>, + + owner_def_id: DefId, } /////////////////////////////////////////////////////////////////////////// @@ -205,13 +228,13 @@ pub struct Loan<'tcx> { /// cases, notably method arguments, the loan may be introduced /// only later, once it comes into scope. See also /// `GatherLoanCtxt::compute_gen_scope`. - gen_scope: region::CodeExtent, + gen_scope: region::CodeExtent<'tcx>, /// 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`. - kill_scope: region::CodeExtent, + kill_scope: region::CodeExtent<'tcx>, span: Span, cause: euv::LoanCause, } @@ -311,15 +334,15 @@ pub fn closure_to_block(closure_id: ast::NodeId, } impl<'a, 'tcx> LoanPath<'tcx> { - pub fn kill_scope(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> region::CodeExtent { + pub fn kill_scope(&self, bccx: &BorrowckCtxt<'a, 'tcx>) -> region::CodeExtent<'tcx> { match self.kind { - LpVar(local_id) => tcx.region_maps.var_scope(local_id), + LpVar(local_id) => bccx.region_maps.var_scope(local_id), LpUpvar(upvar_id) => { - let block_id = closure_to_block(upvar_id.closure_expr_id, tcx); - tcx.region_maps.node_extent(block_id) + let block_id = closure_to_block(upvar_id.closure_expr_id, bccx.tcx); + bccx.tcx.node_extent(block_id) } LpDowncast(ref base, _) | - LpExtend(ref base, ..) => base.kill_scope(tcx), + LpExtend(ref base, ..) => base.kill_scope(bccx), } } @@ -443,8 +466,8 @@ pub fn opt_loan_path<'tcx>(cmt: &mc::cmt<'tcx>) -> Option>> { pub enum bckerr_code<'tcx> { err_mutbl, /// superscope, subscope, loan cause - err_out_of_scope(&'tcx ty::Region, &'tcx ty::Region, euv::LoanCause), - err_borrowed_pointer_too_short(&'tcx ty::Region, &'tcx ty::Region), // loan, ptr + err_out_of_scope(ty::Region<'tcx>, ty::Region<'tcx>, euv::LoanCause), + err_borrowed_pointer_too_short(ty::Region<'tcx>, ty::Region<'tcx>), // loan, ptr } // Combination of an error code and the categorization of the expression @@ -474,11 +497,15 @@ pub enum MovedValueUseKind { impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { pub fn is_subregion_of(&self, - r_sub: &'tcx ty::Region, - r_sup: &'tcx ty::Region) + r_sub: ty::Region<'tcx>, + r_sup: ty::Region<'tcx>) -> bool { - self.tables.free_region_map.is_subregion_of(self.tcx, r_sub, r_sup) + let region_rels = RegionRelations::new(self.tcx, + self.owner_def_id, + &self.region_maps, + &self.tables.free_region_map); + region_rels.is_subregion_of(r_sub, r_sup) } pub fn report(&self, err: BckError<'tcx>) { @@ -659,12 +686,10 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { self.tcx.sess.span_err_with_code(s, msg, code); } - pub fn bckerr_to_diag(&self, err: &BckError<'tcx>) -> DiagnosticBuilder<'a> { + fn bckerr_to_diag(&self, err: &BckError<'tcx>) -> DiagnosticBuilder<'a> { let span = err.span.clone(); - let mut immutable_field = None; - let mut local_def = None; - let msg = &match err.code { + let msg = match err.code { err_mutbl => { let descr = match err.cmt.note { mc::NoteClosureEnv(_) | mc::NoteUpvarRef(_) => { @@ -700,27 +725,6 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { BorrowViolation(euv::AutoUnsafe) | BorrowViolation(euv::ForLoop) | BorrowViolation(euv::MatchDiscriminant) => { - // Check for this field's definition to see if it is an immutable reference - // and suggest making it mutable if that is the case. - immutable_field = err.cmt.get_field_name() - .and_then(|name| err.cmt.get_field(name)) - .and_then(|did| self.tcx.hir.as_local_node_id(did)) - .and_then(|nid| { - if let hir_map::Node::NodeField(ref field) = self.tcx.hir.get(nid) { - return self.suggest_mut_for_immutable(&field.ty) - .map(|msg| (self.tcx.hir.span(nid), msg)); - } - None - }); - local_def = err.cmt.get_def() - .and_then(|nid| { - if !self.tcx.hir.is_argument(nid) { - Some(self.tcx.hir.span(nid)) - } else { - None - } - }); - format!("cannot borrow {} as mutable", descr) } BorrowViolation(euv::ClosureInvocation) => { @@ -746,16 +750,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } }; - let mut db = self.struct_span_err(span, msg); - if let Some((span, msg)) = immutable_field { - db.span_label(span, &msg); - } - if let Some(let_span) = local_def { - if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(let_span) { - db.span_label(let_span, &format!("consider changing this to `mut {}`", snippet)); - } - } - db + self.struct_span_err(span, &msg) } pub fn report_aliasability_violation(&self, @@ -788,34 +783,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } }; - let mut err = match cause { - mc::AliasableOther => { - struct_span_err!( - self.tcx.sess, span, E0385, - "{} in an aliasable location", prefix) - } - mc::AliasableReason::UnaliasableImmutable => { - struct_span_err!( - self.tcx.sess, span, E0386, - "{} in an immutable container", prefix) - } - mc::AliasableClosure(id) => { - let mut err = struct_span_err!( - self.tcx.sess, span, E0387, - "{} in a captured outer variable in an `Fn` closure", prefix); - if let BorrowViolation(euv::ClosureCapture(_)) = kind { - // The aliasability violation with closure captures can - // happen for nested closures, so we know the enclosing - // closure incorrectly accepts an `Fn` while it needs to - // be `FnMut`. - span_help!(&mut err, self.tcx.hir.span(id), - "consider changing this to accept closures that implement `FnMut`"); - } else { - span_help!(&mut err, self.tcx.hir.span(id), - "consider changing this closure to take self by mutable reference"); - } - err - } + match cause { mc::AliasableStatic | mc::AliasableStaticMut => { // This path cannot occur. It happens when we have an @@ -826,17 +794,38 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { // ignored. span_bug!(span, "aliasability violation for static `{}`", prefix) } - mc::AliasableBorrowed => { - let mut e = struct_span_err!( + mc::AliasableBorrowed => {} + }; + let blame = cmt.immutability_blame(); + let mut err = match blame { + Some(ImmutabilityBlame::ClosureEnv(id)) => { + let mut err = struct_span_err!( + self.tcx.sess, span, E0387, + "{} in a captured outer variable in an `Fn` closure", prefix); + + // FIXME: the distinction between these 2 messages looks wrong. + let help = if let BorrowViolation(euv::ClosureCapture(_)) = kind { + // The aliasability violation with closure captures can + // happen for nested closures, so we know the enclosing + // closure incorrectly accepts an `Fn` while it needs to + // be `FnMut`. + "consider changing this to accept closures that implement `FnMut`" + + } else { + "consider changing this closure to take self by mutable reference" + }; + err.span_help(self.tcx.hir.span(id), help); + err + } + _ => { + let mut err = struct_span_err!( self.tcx.sess, span, E0389, "{} in a `&` reference", prefix); - e.span_label(span, &"assignment into an immutable reference"); - if let Some(nid) = cmt.get_arg_if_immutable(&self.tcx.hir) { - self.immutable_argument_should_be_mut(nid, &mut e); - } - e + err.span_label(span, &"assignment into an immutable reference"); + err } }; + self.note_immutability_blame(&mut err, blame); if is_closure { err.help("closures behind references must be called via `&mut`"); @@ -845,49 +834,124 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } /// Given a type, if it is an immutable reference, return a suggestion to make it mutable - fn suggest_mut_for_immutable(&self, pty: &hir::Ty) -> Option { + fn suggest_mut_for_immutable(&self, pty: &hir::Ty, is_implicit_self: bool) -> Option { // Check wether the argument is an immutable reference + debug!("suggest_mut_for_immutable({:?}, {:?})", pty, is_implicit_self); if let hir::TyRptr(lifetime, hir::MutTy { mutbl: hir::Mutability::MutImmutable, ref ty }) = pty.node { // Account for existing lifetimes when generating the message - if !lifetime.is_elided() { - if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(ty.span) { - if let Ok(lifetime_snippet) = self.tcx.sess.codemap() - .span_to_snippet(lifetime.span) { - return Some(format!("use `&{} mut {}` here to make mutable", - lifetime_snippet, - snippet)); - } - } - } else if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(pty.span) { - if snippet.starts_with("&") { - return Some(format!("use `{}` here to make mutable", - snippet.replace("&", "&mut "))); - } + let pointee_snippet = match self.tcx.sess.codemap().span_to_snippet(ty.span) { + Ok(snippet) => snippet, + _ => return None + }; + + let lifetime_snippet = if !lifetime.is_elided() { + format!("{} ", match self.tcx.sess.codemap().span_to_snippet(lifetime.span) { + Ok(lifetime_snippet) => lifetime_snippet, + _ => return None + }) } else { - bug!("couldn't find a snippet for span: {:?}", pty.span); - } + String::new() + }; + Some(format!("use `&{}mut {}` here to make mutable", + lifetime_snippet, + if is_implicit_self { "self" } else { &*pointee_snippet })) + } else { + None } - None } - fn immutable_argument_should_be_mut(&self, nid: ast::NodeId, db: &mut DiagnosticBuilder) { - let parent = self.tcx.hir.get_parent_node(nid); + fn local_binding_mode(&self, node_id: ast::NodeId) -> hir::BindingMode { + let pat = match self.tcx.hir.get(node_id) { + hir_map::Node::NodeLocal(pat) => pat, + node => bug!("bad node for local: {:?}", node) + }; + + match pat.node { + hir::PatKind::Binding(mode, ..) => mode, + _ => bug!("local is not a binding: {:?}", pat) + } + } + + fn local_ty(&self, node_id: ast::NodeId) -> (Option<&hir::Ty>, bool) { + let parent = self.tcx.hir.get_parent_node(node_id); let parent_node = self.tcx.hir.get(parent); // The parent node is like a fn if let Some(fn_like) = FnLikeNode::from_node(parent_node) { // `nid`'s parent's `Body` let fn_body = self.tcx.hir.body(fn_like.body()); - // Get the position of `nid` in the arguments list - let arg_pos = fn_body.arguments.iter().position(|arg| arg.pat.id == nid); + // Get the position of `node_id` in the arguments list + let arg_pos = fn_body.arguments.iter().position(|arg| arg.pat.id == node_id); if let Some(i) = arg_pos { // The argument's `Ty` - let arg_ty = &fn_like.decl().inputs[i]; - if let Some(msg) = self.suggest_mut_for_immutable(&arg_ty) { - db.span_label(arg_ty.span, &msg); + (Some(&fn_like.decl().inputs[i]), + i == 0 && fn_like.decl().has_implicit_self) + } else { + (None, false) + } + } else { + (None, false) + } + } + + fn note_immutability_blame(&self, + db: &mut DiagnosticBuilder, + blame: Option) { + match blame { + None => {} + Some(ImmutabilityBlame::ClosureEnv(_)) => {} + Some(ImmutabilityBlame::ImmLocal(node_id)) => { + let let_span = self.tcx.hir.span(node_id); + if let hir::BindingMode::BindByValue(..) = self.local_binding_mode(node_id) { + if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(let_span) { + let (_, is_implicit_self) = self.local_ty(node_id); + if is_implicit_self && snippet != "self" { + // avoid suggesting `mut &self`. + return + } + db.span_label( + let_span, + &format!("consider changing this to `mut {}`", snippet) + ); + } + } + } + Some(ImmutabilityBlame::LocalDeref(node_id)) => { + let let_span = self.tcx.hir.span(node_id); + match self.local_binding_mode(node_id) { + hir::BindingMode::BindByRef(..) => { + let snippet = self.tcx.sess.codemap().span_to_snippet(let_span); + if let Ok(snippet) = snippet { + db.span_label( + let_span, + &format!("consider changing this to `{}`", + snippet.replace("ref ", "ref mut ")) + ); + } + } + hir::BindingMode::BindByValue(..) => { + if let (Some(local_ty), is_implicit_self) = self.local_ty(node_id) { + if let Some(msg) = + self.suggest_mut_for_immutable(local_ty, is_implicit_self) { + db.span_label(local_ty.span, &msg); + } + } + } + } + } + Some(ImmutabilityBlame::AdtFieldDeref(_, field)) => { + let node_id = match self.tcx.hir.as_local_node_id(field.did) { + Some(node_id) => node_id, + None => return + }; + + if let hir_map::Node::NodeField(ref field) = self.tcx.hir.get(node_id) { + if let Some(msg) = self.suggest_mut_for_immutable(&field.ty, false) { + db.span_label(field.ty.span, &msg); + } } } } @@ -925,10 +989,10 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { .emit(); } - fn region_end_span(&self, region: &'tcx ty::Region) -> Option { + fn region_end_span(&self, region: ty::Region<'tcx>) -> Option { match *region { ty::ReScope(scope) => { - match scope.span(&self.tcx.region_maps, &self.tcx.hir) { + match scope.span(&self.tcx.hir) { Some(s) => { Some(s.end_point()) } @@ -941,10 +1005,13 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } } - pub fn note_and_explain_bckerr(&self, db: &mut DiagnosticBuilder, err: BckError<'tcx>) { + fn note_and_explain_bckerr(&self, db: &mut DiagnosticBuilder, err: BckError<'tcx>) { let error_span = err.span.clone(); match err.code { - err_mutbl => self.note_and_explain_mutbl_error(db, &err, &error_span), + err_mutbl => { + self.note_and_explain_mutbl_error(db, &err, &error_span); + self.note_immutability_blame(db, err.cmt.immutability_blame()); + } err_out_of_scope(super_scope, sub_scope, cause) => { let (value_kind, value_msg) = match err.cmt.cat { mc::Categorization::Rvalue(..) => @@ -1096,13 +1163,6 @@ before rustc 1.16, this temporary lived longer - see issue #39283 \ _ => { if let Categorization::Deref(..) = err.cmt.cat { db.span_label(*error_span, &"cannot borrow as mutable"); - if let Some(local_id) = err.cmt.get_arg_if_immutable(&self.tcx.hir) { - self.immutable_argument_should_be_mut(local_id, db); - } else if let Categorization::Deref(ref inner_cmt, ..) = err.cmt.cat { - if let Categorization::Local(local_id) = inner_cmt.cat { - self.immutable_argument_should_be_mut(local_id, db); - } - } } else if let Categorization::Local(local_id) = err.cmt.cat { let span = self.tcx.hir.span(local_id); if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(span) { @@ -1110,14 +1170,6 @@ before rustc 1.16, this temporary lived longer - see issue #39283 \ db.span_label(*error_span, &format!("cannot reborrow mutably")); db.span_label(*error_span, &format!("try removing `&mut` here")); } else { - if snippet.starts_with("ref ") { - db.span_label(span, &format!("use `{}` here to make mutable", - snippet.replace("ref ", "ref mut "))); - } else if snippet != "self" { - db.span_label(span, - &format!("use `mut {}` here to make mutable", - snippet)); - } db.span_label(*error_span, &format!("cannot borrow mutably")); } } else { @@ -1218,10 +1270,10 @@ before rustc 1.16, this temporary lived longer - see issue #39283 \ } } -fn statement_scope_span(tcx: TyCtxt, region: &ty::Region) -> Option { +fn statement_scope_span(tcx: TyCtxt, region: ty::Region) -> Option { match *region { ty::ReScope(scope) => { - match tcx.hir.find(scope.node_id(&tcx.region_maps)) { + match tcx.hir.find(scope.node_id()) { Some(hir_map::NodeStmt(stmt)) => Some(stmt.span), _ => None } diff --git a/src/librustc_borrowck/borrowck/move_data.rs b/src/librustc_borrowck/borrowck/move_data.rs index 2047a58f8ed8..3e23086ec7bd 100644 --- a/src/librustc_borrowck/borrowck/move_data.rs +++ b/src/librustc_borrowck/borrowck/move_data.rs @@ -362,31 +362,31 @@ impl<'a, 'tcx> MoveData<'tcx> { /// Adds a new move entry for a move of `lp` that occurs at location `id` with kind `kind`. pub fn add_move(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - lp: Rc>, + orig_lp: Rc>, id: ast::NodeId, kind: MoveKind) { - // Moving one union field automatically moves all its fields. - if let LpExtend(ref base_lp, mutbl, LpInterior(opt_variant_id, interior)) = lp.kind { - if let ty::TyAdt(adt_def, _) = base_lp.ty.sty { + // Moving one union field automatically moves all its fields. Also move siblings of + // all parent union fields, moves do not propagate upwards automatically. + let mut lp = orig_lp.clone(); + while let LpExtend(ref base_lp, mutbl, lp_elem) = lp.clone().kind { + if let (&ty::TyAdt(adt_def, _), LpInterior(opt_variant_id, interior)) + = (&base_lp.ty.sty, lp_elem) { if adt_def.is_union() { for field in &adt_def.struct_variant().fields { let field = InteriorKind::InteriorField(mc::NamedField(field.name)); - let field_ty = if field == interior { - lp.ty - } else { - tcx.types.err // Doesn't matter - }; - let sibling_lp_kind = LpExtend(base_lp.clone(), mutbl, - LpInterior(opt_variant_id, field)); - let sibling_lp = Rc::new(LoanPath::new(sibling_lp_kind, field_ty)); - self.add_move_helper(tcx, sibling_lp, id, kind); + if field != interior { + let sibling_lp_kind = + LpExtend(base_lp.clone(), mutbl, LpInterior(opt_variant_id, field)); + let sibling_lp = Rc::new(LoanPath::new(sibling_lp_kind, tcx.types.err)); + self.add_move_helper(tcx, sibling_lp, id, kind); + } } - return; } } + lp = base_lp.clone(); } - self.add_move_helper(tcx, lp.clone(), id, kind); + self.add_move_helper(tcx, orig_lp.clone(), id, kind); } fn add_move_helper(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -523,7 +523,8 @@ impl<'a, 'tcx> MoveData<'tcx> { /// Moves are generated by moves and killed by assignments and /// scoping. Assignments are generated by assignment to variables and /// killed by scoping. See `README.md` for more details. - fn add_gen_kills(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, + fn add_gen_kills(&self, + bccx: &BorrowckCtxt<'a, 'tcx>, dfcx_moves: &mut MoveDataFlow, dfcx_assign: &mut AssignDataFlow) { for (i, the_move) in self.moves.borrow().iter().enumerate() { @@ -546,9 +547,9 @@ impl<'a, 'tcx> MoveData<'tcx> { for path in self.paths.borrow().iter() { match path.loan_path.kind { LpVar(..) | LpUpvar(..) | LpDowncast(..) => { - let kill_scope = path.loan_path.kill_scope(tcx); + let kill_scope = path.loan_path.kill_scope(bccx); let path = *self.path_map.borrow().get(&path.loan_path).unwrap(); - self.kill_moves(path, kill_scope.node_id(&tcx.region_maps), + self.kill_moves(path, kill_scope.node_id(), KillFrom::ScopeEnd, dfcx_moves); } LpExtend(..) => {} @@ -561,9 +562,9 @@ impl<'a, 'tcx> MoveData<'tcx> { let lp = self.path_loan_path(assignment.path); match lp.kind { LpVar(..) | LpUpvar(..) | LpDowncast(..) => { - let kill_scope = lp.kill_scope(tcx); + let kill_scope = lp.kill_scope(bccx); dfcx_assign.add_kill(KillFrom::ScopeEnd, - kill_scope.node_id(&tcx.region_maps), + kill_scope.node_id(), assignment_index); } LpExtend(..) => { @@ -652,11 +653,13 @@ impl<'a, 'tcx> MoveData<'tcx> { impl<'a, 'tcx> FlowedMoveData<'a, 'tcx> { pub fn new(move_data: MoveData<'tcx>, - tcx: TyCtxt<'a, 'tcx, 'tcx>, + bccx: &BorrowckCtxt<'a, 'tcx>, cfg: &cfg::CFG, id_range: IdRange, body: &hir::Body) -> FlowedMoveData<'a, 'tcx> { + let tcx = bccx.tcx; + let mut dfcx_moves = DataFlowContext::new(tcx, "flowed_move_data_moves", @@ -676,7 +679,7 @@ impl<'a, 'tcx> FlowedMoveData<'a, 'tcx> { move_data.fixup_fragment_sets(tcx); - move_data.add_gen_kills(tcx, + move_data.add_gen_kills(bccx, &mut dfcx_moves, &mut dfcx_assign); diff --git a/src/librustc_borrowck/diagnostics.rs b/src/librustc_borrowck/diagnostics.rs index db4a1701e976..bfd342a9f213 100644 --- a/src/librustc_borrowck/diagnostics.rs +++ b/src/librustc_borrowck/diagnostics.rs @@ -198,7 +198,7 @@ fn main() { ``` "##, -E0386: r##" +/*E0386: r##" This error occurs when an attempt is made to mutate the target of a mutable reference stored inside an immutable container. @@ -228,7 +228,7 @@ let x: i64 = 1; let y: Box> = Box::new(Cell::new(x)); y.set(2); ``` -"##, +"##,*/ E0387: r##" This error occurs when an attempt is made to mutate or mutably reference data @@ -1117,6 +1117,6 @@ fn main() { } register_diagnostics! { - E0385, // {} in an aliasable location +// E0385, // {} in an aliasable location E0524, // two closures require unique access to `..` at the same time } diff --git a/src/librustc_borrowck/graphviz.rs b/src/librustc_borrowck/graphviz.rs index 0da9525efd85..e3a2bfa39273 100644 --- a/src/librustc_borrowck/graphviz.rs +++ b/src/librustc_borrowck/graphviz.rs @@ -88,7 +88,7 @@ impl<'a, 'tcx> DataflowLabeller<'a, 'tcx> { set.push_str(", "); } let loan_str = self.borrowck_ctxt.loan_path_to_string(&lp); - set.push_str(&loan_str[..]); + set.push_str(&loan_str); saw_some = true; true }); diff --git a/src/librustc_borrowck/lib.rs b/src/librustc_borrowck/lib.rs index d3b22884a3d8..a1d3357faf56 100644 --- a/src/librustc_borrowck/lib.rs +++ b/src/librustc_borrowck/lib.rs @@ -51,4 +51,6 @@ mod borrowck; pub mod graphviz; +pub use borrowck::provide; + __build_diagnostic_array! { librustc_borrowck, DIAGNOSTICS } diff --git a/src/librustc_const_eval/Cargo.toml b/src/librustc_const_eval/Cargo.toml index 780b2c16a32e..bbc614808249 100644 --- a/src/librustc_const_eval/Cargo.toml +++ b/src/librustc_const_eval/Cargo.toml @@ -10,12 +10,11 @@ crate-type = ["dylib"] [dependencies] arena = { path = "../libarena" } -log = { path = "../liblog" } +log = "0.3" rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } rustc_const_math = { path = "../librustc_const_math" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_errors = { path = "../librustc_errors" } syntax = { path = "../libsyntax" } -graphviz = { path = "../libgraphviz" } syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/librustc_const_eval/_match.rs b/src/librustc_const_eval/_match.rs index 53a7e8729281..c1dc5f5f7a2b 100644 --- a/src/librustc_const_eval/_match.rs +++ b/src/librustc_const_eval/_match.rs @@ -680,10 +680,10 @@ fn is_useful_specialized<'p, 'a:'p, 'tcx: 'a>( }).collect(); let wild_patterns: Vec<_> = wild_patterns_owned.iter().collect(); let matrix = Matrix(m.iter().flat_map(|r| { - specialize(cx, &r[..], &ctor, &wild_patterns) + specialize(cx, &r, &ctor, &wild_patterns) }).collect()); match specialize(cx, v, &ctor, &wild_patterns) { - Some(v) => match is_useful(cx, &matrix, &v[..], witness) { + Some(v) => match is_useful(cx, &matrix, &v, witness) { UsefulWithWitness(witnesses) => UsefulWithWitness( witnesses.into_iter() .map(|witness| witness.apply_constructor(cx, &ctor, lty)) diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index e2b9f174ff0c..6ec5f38aa5bb 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -14,14 +14,11 @@ use _match::WitnessPreference::*; use pattern::{Pattern, PatternContext, PatternError, PatternKind}; -use eval::report_const_eval_err; - -use rustc::dep_graph::DepNode; - use rustc::middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor}; use rustc::middle::expr_use_visitor::{LoanCause, MutateMode}; use rustc::middle::expr_use_visitor as euv; use rustc::middle::mem_categorization::{cmt}; +use rustc::middle::region::RegionMaps; use rustc::session::Session; use rustc::traits::Reveal; use rustc::ty::{self, Ty, TyCtxt}; @@ -49,17 +46,20 @@ impl<'a, 'tcx> Visitor<'tcx> for OuterVisitor<'a, 'tcx> { b: hir::BodyId, s: Span, id: ast::NodeId) { intravisit::walk_fn(self, fk, fd, b, s, id); + let region_context = self.tcx.hir.local_def_id(id); + let region_maps = self.tcx.region_maps(region_context); + MatchVisitor { tcx: self.tcx, tables: self.tcx.body_tables(b), + region_maps: ®ion_maps, param_env: &ty::ParameterEnvironment::for_item(self.tcx, id) }.visit_body(self.tcx.hir.body(b)); } } pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - tcx.visit_all_item_likes_in_krate(DepNode::MatchCheck, - &mut OuterVisitor { tcx: tcx }.as_deep_visitor()); + tcx.hir.krate().visit_all_item_likes(&mut OuterVisitor { tcx: tcx }.as_deep_visitor()); tcx.sess.abort_if_errors(); } @@ -70,7 +70,8 @@ fn create_e0004<'a>(sess: &'a Session, sp: Span, error_message: String) -> Diagn struct MatchVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, tables: &'a ty::TypeckTables<'tcx>, - param_env: &'a ty::ParameterEnvironment<'tcx> + param_env: &'a ty::ParameterEnvironment<'tcx>, + region_maps: &'a RegionMaps<'tcx>, } impl<'a, 'tcx> Visitor<'tcx> for MatchVisitor<'a, 'tcx> { @@ -108,6 +109,22 @@ impl<'a, 'tcx> Visitor<'tcx> for MatchVisitor<'a, 'tcx> { } } +impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> { + fn report_inlining_errors(&self, pat_span: Span) { + for error in &self.errors { + match *error { + PatternError::StaticInPattern(span) => { + span_err!(self.tcx.sess, span, E0158, + "statics cannot be referenced in patterns"); + } + PatternError::ConstEval(ref err) => { + err.report(self.tcx, pat_span, "pattern"); + } + } + } + } +} + impl<'a, 'tcx> MatchVisitor<'a, 'tcx> { fn check_patterns(&self, has_guard: bool, pats: &[P]) { check_legality_of_move_bindings(self, has_guard, pats); @@ -116,20 +133,6 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> { } } - fn report_inlining_errors(&self, patcx: PatternContext, pat_span: Span) { - for error in patcx.errors { - match error { - PatternError::StaticInPattern(span) => { - span_err!(self.tcx.sess, span, E0158, - "statics cannot be referenced in patterns"); - } - PatternError::ConstEval(err) => { - report_const_eval_err(self.tcx, &err, pat_span, "pattern"); - } - } - } - } - fn check_match( &self, scrut: &hir::Expr, @@ -161,7 +164,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> { let mut patcx = PatternContext::new(self.tcx, self.tables); let pattern = expand_pattern(cx, patcx.lower_pattern(&pat)); if !patcx.errors.is_empty() { - self.report_inlining_errors(patcx, pat.span); + patcx.report_inlining_errors(pat.span); have_errors = true; } (pattern, &**pat) @@ -311,7 +314,7 @@ fn check_arms<'a, 'tcx>(cx: &mut MatchCheckCtxt<'a, 'tcx>, for &(pat, hir_pat) in pats { let v = vec![pat]; - match is_useful(cx, &seen, &v[..], LeaveOutWitness) { + match is_useful(cx, &seen, &v, LeaveOutWitness) { NotUseful => { match source { hir::MatchSource::IfLetDesugar { .. } => { @@ -520,7 +523,7 @@ fn check_for_mutation_in_guard(cx: &MatchVisitor, guard: &hir::Expr) { let mut checker = MutationChecker { cx: cx, }; - ExprUseVisitor::new(&mut checker, &infcx).walk_expr(guard); + ExprUseVisitor::new(&mut checker, cx.region_maps, &infcx).walk_expr(guard); }); } @@ -536,7 +539,7 @@ impl<'a, 'gcx, 'tcx> Delegate<'tcx> for MutationChecker<'a, 'gcx> { _: ast::NodeId, span: Span, _: cmt, - _: &'tcx ty::Region, + _: ty::Region<'tcx>, kind:ty:: BorrowKind, _: LoanCause) { match kind { diff --git a/src/librustc_const_eval/diagnostics.rs b/src/librustc_const_eval/diagnostics.rs index 60eef8dd3bc5..04fc3e68c8cc 100644 --- a/src/librustc_const_eval/diagnostics.rs +++ b/src/librustc_const_eval/diagnostics.rs @@ -557,25 +557,6 @@ The `op_string_ref` binding has type `&Option<&String>` in both cases. See also https://github.com/rust-lang/rust/issues/14587 "##, -E0080: r##" -This error indicates that the compiler was unable to sensibly evaluate an -constant expression that had to be evaluated. Attempting to divide by 0 -or causing integer overflow are two ways to induce this error. For example: - -```compile_fail,E0080 -enum Enum { - X = (1 << 500), - Y = (1 / 0) -} -``` - -Ensure that the expressions given can be evaluated as the desired integer type. -See the FFI section of the Reference for more information about using a custom -integer type: - -https://doc.rust-lang.org/reference.html#ffi-attributes -"##, - } diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index c5d577ce571d..8b1aa0708807 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -9,31 +9,29 @@ // except according to those terms. use rustc::middle::const_val::ConstVal::*; -use rustc::middle::const_val::ConstVal; -use self::ErrKind::*; +use rustc::middle::const_val::ErrKind::*; +use rustc::middle::const_val::{ConstVal, ConstEvalErr, EvalResult, ErrKind}; use rustc::hir::map as hir_map; use rustc::hir::map::blocks::FnLikeNode; use rustc::traits; -use rustc::hir::def::Def; +use rustc::hir::def::{Def, CtorKind}; use rustc::hir::def_id::DefId; use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::maps::Providers; use rustc::ty::util::IntTypeExt; use rustc::ty::subst::{Substs, Subst}; use rustc::traits::Reveal; use rustc::util::common::ErrorReported; use rustc::util::nodemap::DefIdMap; -use graphviz::IntoCow; use syntax::ast; use rustc::hir::{self, Expr}; -use syntax_pos::{Span, DUMMY_SP}; +use syntax_pos::Span; -use std::borrow::Cow; use std::cmp::Ordering; use rustc_const_math::*; -use rustc_errors::DiagnosticBuilder; macro_rules! signal { ($e:expr, $exn:expr) => { @@ -50,174 +48,43 @@ macro_rules! math { } } -fn lookup_variant_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - variant_def: DefId) - -> Option<(&'tcx Expr, &'a ty::TypeckTables<'tcx>)> { - if let Some(variant_node_id) = tcx.hir.as_local_node_id(variant_def) { - let enum_node_id = tcx.hir.get_parent(variant_node_id); - if let Some(hir_map::NodeItem(it)) = tcx.hir.find(enum_node_id) { - if let hir::ItemEnum(ref edef, _) = it.node { - for variant in &edef.variants { - if variant.node.data.id() == variant_node_id { - return variant.node.disr_expr.map(|e| { - let def_id = tcx.hir.body_owner_def_id(e); - (&tcx.hir.body(e).value, - tcx.item_tables(def_id)) - }); - } - } - } - } - } - None -} - /// * `def_id` is the id of the constant. /// * `substs` is the monomorphized substitutions for the expression. /// /// `substs` is optional and is used for associated constants. /// This generally happens in late/trans const evaluation. -pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId, - substs: &'tcx Substs<'tcx>) - -> Option<(&'tcx Expr, - &'a ty::TypeckTables<'tcx>)> { +pub fn lookup_const_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId, + substs: &'tcx Substs<'tcx>) + -> Option<(DefId, &'tcx Substs<'tcx>)> { if let Some(node_id) = tcx.hir.as_local_node_id(def_id) { match tcx.hir.find(node_id) { - None => None, - Some(hir_map::NodeItem(&hir::Item { - node: hir::ItemConst(_, body), .. - })) | - Some(hir_map::NodeImplItem(&hir::ImplItem { - node: hir::ImplItemKind::Const(_, body), .. - })) => { - Some((&tcx.hir.body(body).value, - tcx.item_tables(def_id))) + Some(hir_map::NodeTraitItem(_)) => { + // If we have a trait item and the substitutions for it, + // `resolve_trait_associated_const` will select an impl + // or the default. + resolve_trait_associated_const(tcx, def_id, substs) } - Some(hir_map::NodeTraitItem(ti)) => match ti.node { - hir::TraitItemKind::Const(_, default) => { - // If we have a trait item and the substitutions for it, - // `resolve_trait_associated_const` will select an impl - // or the default. - let trait_id = tcx.hir.get_parent(node_id); - let trait_id = tcx.hir.local_def_id(trait_id); - let default_value = default.map(|body| { - (&tcx.hir.body(body).value, - tcx.item_tables(def_id)) - }); - resolve_trait_associated_const(tcx, def_id, default_value, trait_id, substs) - } - _ => None - }, - Some(_) => None + _ => Some((def_id, substs)) } } else { - let expr_and_tables = tcx.sess.cstore.maybe_get_item_body(tcx, def_id).map(|body| { - (&body.value, tcx.item_tables(def_id)) - }); - match tcx.sess.cstore.describe_def(def_id) { + match tcx.describe_def(def_id) { Some(Def::AssociatedConst(_)) => { - let trait_id = tcx.sess.cstore.trait_of_item(def_id); // As mentioned in the comments above for in-crate // constants, we only try to find the expression for a // trait-associated const if the caller gives us the // substitutions for the reference to it. - if let Some(trait_id) = trait_id { - resolve_trait_associated_const(tcx, def_id, expr_and_tables, - trait_id, substs) + if tcx.sess.cstore.trait_of_item(def_id).is_some() { + resolve_trait_associated_const(tcx, def_id, substs) } else { - expr_and_tables + Some((def_id, substs)) } - }, - Some(Def::Const(..)) => expr_and_tables, - _ => None - } - } -} - -fn lookup_const_fn_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) - -> Option<(&'tcx hir::Body, &'a ty::TypeckTables<'tcx>)> -{ - if let Some(node_id) = tcx.hir.as_local_node_id(def_id) { - FnLikeNode::from_node(tcx.hir.get(node_id)).and_then(|fn_like| { - if fn_like.constness() == hir::Constness::Const { - Some((tcx.hir.body(fn_like.body()), - tcx.item_tables(def_id))) - } else { - None } - }) - } else { - if tcx.sess.cstore.is_const_fn(def_id) { - tcx.sess.cstore.maybe_get_item_body(tcx, def_id).map(|body| { - (body, tcx.item_tables(def_id)) - }) - } else { - None + _ => Some((def_id, substs)) } } } -fn build_const_eval_err<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - err: &ConstEvalErr, - primary_span: Span, - primary_kind: &str) - -> DiagnosticBuilder<'tcx> -{ - let mut err = err; - while let &ConstEvalErr { kind: ErroneousReferencedConstant(box ref i_err), .. } = err { - err = i_err; - } - - let mut diag = struct_span_err!(tcx.sess, err.span, E0080, "constant evaluation error"); - note_const_eval_err(tcx, err, primary_span, primary_kind, &mut diag); - diag -} - -pub fn report_const_eval_err<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - err: &ConstEvalErr, - primary_span: Span, - primary_kind: &str) -{ - if let TypeckError = err.kind { - return; - } - build_const_eval_err(tcx, err, primary_span, primary_kind).emit(); -} - -pub fn fatal_const_eval_err<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - err: &ConstEvalErr, - primary_span: Span, - primary_kind: &str) - -> ! -{ - report_const_eval_err(tcx, err, primary_span, primary_kind); - tcx.sess.abort_if_errors(); - unreachable!() -} - -pub fn note_const_eval_err<'a, 'tcx>( - _tcx: TyCtxt<'a, 'tcx, 'tcx>, - err: &ConstEvalErr, - primary_span: Span, - primary_kind: &str, - diag: &mut DiagnosticBuilder) -{ - match err.description() { - ConstEvalErrDescription::Simple(message) => { - diag.span_label(err.span, &message); - } - } - - if !primary_span.contains(err.span) { - diag.span_note(primary_span, - &format!("for {} here", primary_kind)); - } -} - pub struct ConstContext<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, tables: &'a ty::TypeckTables<'tcx>, @@ -226,12 +93,6 @@ pub struct ConstContext<'a, 'tcx: 'a> { } impl<'a, 'tcx> ConstContext<'a, 'tcx> { - pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, body: hir::BodyId) -> Self { - let def_id = tcx.hir.body_owner_def_id(body); - ty::queries::mir_const_qualif::get(tcx, DUMMY_SP, def_id); - ConstContext::with_tables(tcx, tcx.item_tables(def_id)) - } - pub fn with_tables(tcx: TyCtxt<'a, 'tcx, 'tcx>, tables: &'a ty::TypeckTables<'tcx>) -> Self { ConstContext { tcx: tcx, @@ -251,107 +112,7 @@ impl<'a, 'tcx> ConstContext<'a, 'tcx> { } } -#[derive(Clone, Debug)] -pub struct ConstEvalErr<'tcx> { - pub span: Span, - pub kind: ErrKind<'tcx>, -} - -#[derive(Clone, Debug)] -pub enum ErrKind<'tcx> { - CannotCast, - MissingStructField, - NegateOn(ConstVal<'tcx>), - NotOn(ConstVal<'tcx>), - CallOn(ConstVal<'tcx>), - - NonConstPath, - UnimplementedConstVal(&'static str), - ExpectedConstTuple, - ExpectedConstStruct, - IndexedNonVec, - IndexNotUsize, - IndexOutOfBounds { len: u64, index: u64 }, - - MiscBinaryOp, - MiscCatchAll, - - IndexOpFeatureGated, - Math(ConstMathErr), - - ErroneousReferencedConstant(Box>), - - TypeckError -} - -impl<'tcx> From for ErrKind<'tcx> { - fn from(err: ConstMathErr) -> ErrKind<'tcx> { - match err { - ConstMathErr::UnsignedNegation => TypeckError, - _ => Math(err) - } - } -} - -#[derive(Clone, Debug)] -pub enum ConstEvalErrDescription<'a> { - Simple(Cow<'a, str>), -} - -impl<'a> ConstEvalErrDescription<'a> { - /// Return a one-line description of the error, for lints and such - pub fn into_oneline(self) -> Cow<'a, str> { - match self { - ConstEvalErrDescription::Simple(simple) => simple, - } - } -} - -impl<'tcx> ConstEvalErr<'tcx> { - pub fn description(&self) -> ConstEvalErrDescription { - use self::ErrKind::*; - use self::ConstEvalErrDescription::*; - - macro_rules! simple { - ($msg:expr) => ({ Simple($msg.into_cow()) }); - ($fmt:expr, $($arg:tt)+) => ({ - Simple(format!($fmt, $($arg)+).into_cow()) - }) - } - - match self.kind { - CannotCast => simple!("can't cast this type"), - NegateOn(ref const_val) => simple!("negate on {}", const_val.description()), - NotOn(ref const_val) => simple!("not on {}", const_val.description()), - CallOn(ref const_val) => simple!("call on {}", const_val.description()), - - MissingStructField => simple!("nonexistent struct field"), - NonConstPath => simple!("non-constant path in constant expression"), - UnimplementedConstVal(what) => - simple!("unimplemented constant expression: {}", what), - ExpectedConstTuple => simple!("expected constant tuple"), - ExpectedConstStruct => simple!("expected constant struct"), - IndexedNonVec => simple!("indexing is only supported for arrays"), - IndexNotUsize => simple!("indices must be of type `usize`"), - IndexOutOfBounds { len, index } => { - simple!("index out of bounds: the len is {} but the index is {}", - len, index) - } - - MiscBinaryOp => simple!("bad operands for binary"), - MiscCatchAll => simple!("unsupported constant expr"), - IndexOpFeatureGated => simple!("the index operation on const values is unstable"), - Math(ref err) => Simple(err.description().into_cow()), - - ErroneousReferencedConstant(_) => simple!("could not evaluate referenced constant"), - - TypeckError => simple!("type-checking failed"), - } - } -} - -pub type EvalResult<'tcx> = Result, ConstEvalErr<'tcx>>; -pub type CastResult<'tcx> = Result, ErrKind<'tcx>>; +type CastResult<'tcx> = Result, ErrKind<'tcx>>; fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, e: &Expr) -> EvalResult<'tcx> { @@ -490,14 +251,38 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, _ => span_bug!(e.span, "typeck error"), }) } + (Char(a), Char(b)) => { + Bool(match op.node { + hir::BiEq => a == b, + hir::BiNe => a != b, + hir::BiLt => a < b, + hir::BiLe => a <= b, + hir::BiGe => a >= b, + hir::BiGt => a > b, + _ => span_bug!(e.span, "typeck error"), + }) + } _ => signal!(e, MiscBinaryOp), } } hir::ExprCast(ref base, _) => { - match cast_const(tcx, cx.eval(base)?, ety) { - Ok(val) => val, - Err(kind) => return Err(ConstEvalErr { span: e.span, kind: kind }), + let base_val = cx.eval(base)?; + let base_ty = cx.tables.expr_ty(base); + + // Avoid applying substitutions if they're empty, that'd ICE. + let base_ty = if cx.substs.is_empty() { + base_ty + } else { + base_ty.subst(tcx, cx.substs) + }; + if ety == base_ty { + base_val + } else { + match cast_const(tcx, base_val, ety) { + Ok(val) => val, + Err(kind) => signal!(e, kind), + } } } hir::ExprPath(ref qpath) => { @@ -514,42 +299,29 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, match cx.tables.qpath_def(qpath, e.id) { Def::Const(def_id) | Def::AssociatedConst(def_id) => { - if let Some((expr, tables)) = lookup_const_by_id(tcx, def_id, substs) { - let cx = ConstContext::with_tables(tcx, tables); - match cx.eval(expr) { - Ok(val) => val, - Err(ConstEvalErr { kind: TypeckError, .. }) => { - signal!(e, TypeckError); - } - Err(err) => { - debug!("bad reference: {:?}, {:?}", err.description(), err.span); - signal!(e, ErroneousReferencedConstant(box err)) - }, - } - } else { - signal!(e, TypeckError); - } + match tcx.at(e.span).const_eval((def_id, substs)) { + Ok(val) => val, + Err(ConstEvalErr { kind: TypeckError, .. }) => { + signal!(e, TypeckError); + } + Err(err) => { + debug!("bad reference: {:?}, {:?}", err.description(), err.span); + signal!(e, ErroneousReferencedConstant(box err)) + }, + } }, - Def::VariantCtor(variant_def, ..) => { - if let Some((expr, tables)) = lookup_variant_by_id(tcx, variant_def) { - let cx = ConstContext::with_tables(tcx, tables); - match cx.eval(expr) { - Ok(val) => val, - Err(ConstEvalErr { kind: TypeckError, .. }) => { - signal!(e, TypeckError); - } - Err(err) => { - debug!("bad reference: {:?}, {:?}", err.description(), err.span); - signal!(e, ErroneousReferencedConstant(box err)) - }, - } - } else { - signal!(e, UnimplementedConstVal("enum variants")); - } + Def::VariantCtor(variant_def, CtorKind::Const) => { + Variant(variant_def) } - Def::StructCtor(..) => { + Def::VariantCtor(_, CtorKind::Fn) => { + signal!(e, UnimplementedConstVal("enum variants")); + } + Def::StructCtor(_, CtorKind::Const) => { ConstVal::Struct(Default::default()) } + Def::StructCtor(_, CtorKind::Fn) => { + signal!(e, UnimplementedConstVal("tuple struct constructors")) + } Def::Local(def_id) => { debug!("Def::Local({:?}): {:?}", def_id, cx.fn_args); if let Some(val) = cx.fn_args.as_ref().and_then(|args| args.get(&def_id)) { @@ -564,14 +336,27 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, } } hir::ExprCall(ref callee, ref args) => { - let (did, substs) = match cx.eval(callee)? { - Function(did, substs) => (did, substs), - Struct(_) => signal!(e, UnimplementedConstVal("tuple struct constructors")), - callee => signal!(e, CallOn(callee)), + let (def_id, substs) = match cx.eval(callee)? { + Function(def_id, substs) => (def_id, substs), + _ => signal!(e, TypeckError), }; - let (body, tables) = match lookup_const_fn_by_id(tcx, did) { - Some(x) => x, - None => signal!(e, NonConstPath), + + let body = if let Some(node_id) = tcx.hir.as_local_node_id(def_id) { + if let Some(fn_like) = FnLikeNode::from_node(tcx.hir.get(node_id)) { + if fn_like.constness() == hir::Constness::Const { + tcx.hir.body(fn_like.body()) + } else { + signal!(e, TypeckError) + } + } else { + signal!(e, TypeckError) + } + } else { + if tcx.sess.cstore.is_const_fn(def_id) { + tcx.sess.cstore.item_body(tcx, def_id) + } else { + signal!(e, TypeckError) + } }; let arg_defs = body.arguments.iter().map(|arg| match arg.pat.node { @@ -591,7 +376,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, debug!("const call({:?})", call_args); let callee_cx = ConstContext { tcx: tcx, - tables: tables, + tables: tcx.typeck_tables_of(def_id), substs: substs, fn_args: Some(call_args) }; @@ -689,19 +474,16 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, Ok(result) } -fn resolve_trait_associated_const<'a, 'tcx: 'a>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - trait_item_id: DefId, - default_value: Option<(&'tcx Expr, &'a ty::TypeckTables<'tcx>)>, - trait_id: DefId, - rcvr_substs: &'tcx Substs<'tcx> -) -> Option<(&'tcx Expr, &'a ty::TypeckTables<'tcx>)> -{ - let trait_ref = ty::Binder(ty::TraitRef::new(trait_id, rcvr_substs)); +fn resolve_trait_associated_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId, + substs: &'tcx Substs<'tcx>) + -> Option<(DefId, &'tcx Substs<'tcx>)> { + let trait_item = tcx.associated_item(def_id); + let trait_id = trait_item.container.id(); + let trait_ref = ty::Binder(ty::TraitRef::new(trait_id, substs)); debug!("resolve_trait_associated_const: trait_ref={:?}", trait_ref); - tcx.populate_implementations_for_trait_if_necessary(trait_id); tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| { let mut selcx = traits::SelectionContext::new(&infcx); let obligation = traits::Obligation::new(traits::ObligationCause::dummy(), @@ -726,12 +508,20 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>( // when constructing the inference context above. match selection { traits::VtableImpl(ref impl_data) => { - let name = tcx.associated_item(trait_item_id).name; + let name = trait_item.name; let ac = tcx.associated_items(impl_data.impl_def_id) .find(|item| item.kind == ty::AssociatedKind::Const && item.name == name); match ac { - Some(ic) => lookup_const_by_id(tcx, ic.def_id, Substs::empty()), - None => default_value, + // FIXME(eddyb) Use proper Instance resolution to + // get the correct Substs returned from here. + Some(ic) => Some((ic.def_id, Substs::empty())), + None => { + if trait_item.defaultness.has_value() { + Some((def_id, substs)) + } else { + None + } + } } } _ => { @@ -772,7 +562,7 @@ fn cast_const_int<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, U8(u) => Ok(Char(u as char)), _ => bug!(), }, - _ => bug!(), + _ => Err(CannotCast), } } @@ -816,6 +606,11 @@ fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, Bool(b) => cast_const_int(tcx, U8(b as u8), ty), Float(f) => cast_const_float(tcx, f, ty), Char(c) => cast_const_int(tcx, U32(c as u32), ty), + Variant(v) => { + let adt = tcx.adt_def(tcx.parent_def_id(v).unwrap()); + let idx = adt.variant_index_with_id(v); + cast_const_int(tcx, adt.discriminant_for_variant(tcx, idx), ty) + } Function(..) => Err(UnimplementedConstVal("casting fn pointers")), ByteStr(b) => match ty.sty { ty::TyRawPtr(_) => { @@ -936,14 +731,14 @@ impl<'a, 'tcx> ConstContext<'a, 'tcx> { let a = match self.eval(a) { Ok(a) => a, Err(e) => { - report_const_eval_err(tcx, &e, a.span, "expression"); + e.report(tcx, a.span, "expression"); return Err(ErrorReported); } }; let b = match self.eval(b) { Ok(b) => b, Err(e) => { - report_const_eval_err(tcx, &e, b.span, "expression"); + e.report(tcx, b.span, "expression"); return Err(ErrorReported); } }; @@ -951,35 +746,37 @@ impl<'a, 'tcx> ConstContext<'a, 'tcx> { } } - -/// Returns the value of the length-valued expression -pub fn eval_length<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - count: hir::BodyId, - reason: &str) - -> Result -{ - let count_expr = &tcx.hir.body(count).value; - match ConstContext::new(tcx, count).eval(count_expr) { - Ok(Integral(Usize(count))) => { - let val = count.as_u64(tcx.sess.target.uint_type); - assert_eq!(val as usize as u64, val); - Ok(val as usize) - }, - Ok(_) | - Err(ConstEvalErr { kind: TypeckError, .. }) => Err(ErrorReported), - Err(err) => { - let mut diag = build_const_eval_err( - tcx, &err, count_expr.span, reason); - - if let hir::ExprPath(hir::QPath::Resolved(None, ref path)) = count_expr.node { - if let Def::Local(..) = path.def { - diag.note(&format!("`{}` is a variable", - tcx.hir.node_to_pretty_string(count_expr.id))); - } - } - - diag.emit(); - Err(ErrorReported) - } - } +pub fn provide(providers: &mut Providers) { + *providers = Providers { + const_eval, + ..*providers + }; +} + +fn const_eval<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + (def_id, substs): (DefId, &'tcx Substs<'tcx>)) + -> EvalResult<'tcx> { + let (def_id, substs) = if let Some(resolved) = lookup_const_by_id(tcx, def_id, substs) { + resolved + } else { + return Err(ConstEvalErr { + span: tcx.def_span(def_id), + kind: TypeckError + }); + }; + + let cx = ConstContext { + tcx, + tables: tcx.typeck_tables_of(def_id), + substs: substs, + fn_args: None + }; + + let body = if let Some(id) = tcx.hir.as_local_node_id(def_id) { + tcx.mir_const_qualif(def_id); + tcx.hir.body(tcx.hir.body_owned_by(id)) + } else { + tcx.sess.cstore.item_body(tcx, def_id) + }; + cx.eval(&body.value) } diff --git a/src/librustc_const_eval/lib.rs b/src/librustc_const_eval/lib.rs index 4434a901f941..fa3161a86049 100644 --- a/src/librustc_const_eval/lib.rs +++ b/src/librustc_const_eval/lib.rs @@ -40,7 +40,6 @@ extern crate rustc_back; extern crate rustc_const_math; extern crate rustc_data_structures; extern crate rustc_errors; -extern crate graphviz; extern crate syntax_pos; // NB: This module needs to be declared first so diagnostics are diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_const_eval/pattern.rs index bd67dd2e6b25..e15d63a63c25 100644 --- a/src/librustc_const_eval/pattern.rs +++ b/src/librustc_const_eval/pattern.rs @@ -11,7 +11,7 @@ use eval; use rustc::lint; -use rustc::middle::const_val::ConstVal; +use rustc::middle::const_val::{ConstEvalErr, ConstVal}; use rustc::mir::{Field, BorrowKind, Mutability}; use rustc::ty::{self, TyCtxt, AdtDef, Ty, TypeVariants, Region}; use rustc::ty::subst::{Substs, Kind}; @@ -29,13 +29,13 @@ use syntax_pos::Span; #[derive(Clone, Debug)] pub enum PatternError<'tcx> { StaticInPattern(Span), - ConstEval(eval::ConstEvalErr<'tcx>), + ConstEval(ConstEvalErr<'tcx>), } #[derive(Copy, Clone, Debug)] pub enum BindingMode<'tcx> { ByValue, - ByRef(&'tcx Region, BorrowKind), + ByRef(Region<'tcx>, BorrowKind), } #[derive(Clone, Debug)] @@ -116,6 +116,7 @@ fn print_const_val(value: &ConstVal, f: &mut fmt::Formatter) -> fmt::Result { ConstVal::ByteStr(ref b) => write!(f, "{:?}", &b[..]), ConstVal::Bool(b) => write!(f, "{:?}", b), ConstVal::Char(c) => write!(f, "{:?}", c), + ConstVal::Variant(_) | ConstVal::Struct(_) | ConstVal::Tuple(_) | ConstVal::Function(..) | @@ -546,7 +547,7 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> { match def { Def::Variant(variant_id) | Def::VariantCtor(variant_id, ..) => { let enum_id = self.tcx.parent_def_id(variant_id).unwrap(); - let adt_def = self.tcx.lookup_adt_def(enum_id); + let adt_def = self.tcx.adt_def(enum_id); if adt_def.variants.len() > 1 { let substs = match ty.sty { TypeVariants::TyAdt(_, substs) => substs, @@ -587,11 +588,16 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> { let substs = self.tables.node_id_item_substs(id) .unwrap_or_else(|| tcx.intern_substs(&[])); match eval::lookup_const_by_id(tcx, def_id, substs) { - Some((const_expr, const_tables)) => { + Some((def_id, _substs)) => { // Enter the inlined constant's tables temporarily. let old_tables = self.tables; - self.tables = const_tables; - let pat = self.lower_const_expr(const_expr, pat_id, span); + self.tables = tcx.typeck_tables_of(def_id); + let body = if let Some(id) = tcx.hir.as_local_node_id(def_id) { + tcx.hir.body(tcx.hir.body_owned_by(id)) + } else { + tcx.sess.cstore.item_body(tcx, def_id) + }; + let pat = self.lower_const_expr(&body.value, pat_id, span); self.tables = old_tables; return pat; } @@ -615,7 +621,12 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> { let const_cx = eval::ConstContext::with_tables(self.tcx.global_tcx(), self.tables); match const_cx.eval(expr) { Ok(value) => { - PatternKind::Constant { value: value } + if let ConstVal::Variant(def_id) = value { + let ty = self.tables.expr_ty(expr); + self.lower_variant_or_leaf(Def::Variant(def_id), ty, vec![]) + } else { + PatternKind::Constant { value: value } + } } Err(e) => { self.errors.push(PatternError::ConstEval(e)); @@ -800,7 +811,7 @@ macro_rules! CloneImpls { } CloneImpls!{ <'tcx> - Span, Field, Mutability, ast::Name, ast::NodeId, usize, ConstVal<'tcx>, Region, + Span, Field, Mutability, ast::Name, ast::NodeId, usize, ConstVal<'tcx>, Region<'tcx>, Ty<'tcx>, BindingMode<'tcx>, &'tcx AdtDef, &'tcx Substs<'tcx>, &'tcx Kind<'tcx> } diff --git a/src/librustc_data_structures/Cargo.toml b/src/librustc_data_structures/Cargo.toml index e2e16059d987..343b1ed68b80 100644 --- a/src/librustc_data_structures/Cargo.toml +++ b/src/librustc_data_structures/Cargo.toml @@ -9,5 +9,5 @@ path = "lib.rs" crate-type = ["dylib"] [dependencies] -log = { path = "../liblog" } +log = "0.3" serialize = { path = "../libserialize" } diff --git a/src/librustc_data_structures/accumulate_vec.rs b/src/librustc_data_structures/accumulate_vec.rs index d4bd9e707fdc..c03c2890ba34 100644 --- a/src/librustc_data_structures/accumulate_vec.rs +++ b/src/librustc_data_structures/accumulate_vec.rs @@ -91,8 +91,8 @@ impl Deref for AccumulateVec { type Target = [A::Element]; fn deref(&self) -> &Self::Target { match *self { - AccumulateVec::Array(ref v) => &v[..], - AccumulateVec::Heap(ref v) => &v[..], + AccumulateVec::Array(ref v) => v, + AccumulateVec::Heap(ref v) => v, } } } @@ -100,8 +100,8 @@ impl Deref for AccumulateVec { impl DerefMut for AccumulateVec { fn deref_mut(&mut self) -> &mut [A::Element] { match *self { - AccumulateVec::Array(ref mut v) => &mut v[..], - AccumulateVec::Heap(ref mut v) => &mut v[..], + AccumulateVec::Array(ref mut v) => v, + AccumulateVec::Heap(ref mut v) => v, } } } diff --git a/src/librustc_data_structures/array_vec.rs b/src/librustc_data_structures/array_vec.rs index 29fbcb70756b..848e5a076bb9 100644 --- a/src/librustc_data_structures/array_vec.rs +++ b/src/librustc_data_structures/array_vec.rs @@ -20,10 +20,11 @@ use std::fmt; use std::mem; use std::collections::range::RangeArgument; use std::collections::Bound::{Excluded, Included, Unbounded}; +use std::mem::ManuallyDrop; pub unsafe trait Array { type Element; - type PartialStorage: Default + Unsize<[ManuallyDrop]>; + type PartialStorage: Unsize<[ManuallyDrop]>; const LEN: usize; } @@ -39,6 +40,12 @@ unsafe impl Array for [T; 8] { const LEN: usize = 8; } +unsafe impl Array for [T; 32] { + type Element = T; + type PartialStorage = [ManuallyDrop; 32]; + const LEN: usize = 32; +} + pub struct ArrayVec { count: usize, values: A::PartialStorage @@ -66,7 +73,7 @@ impl ArrayVec { pub fn new() -> Self { ArrayVec { count: 0, - values: Default::default(), + values: unsafe { ::std::mem::uninitialized() }, } } @@ -81,7 +88,7 @@ impl ArrayVec { /// Panics when the stack vector is full. pub fn push(&mut self, el: A::Element) { let arr = &mut self.values as &mut [ManuallyDrop<_>]; - arr[self.count] = ManuallyDrop { value: el }; + arr[self.count] = ManuallyDrop::new(el); self.count += 1; } @@ -90,8 +97,8 @@ impl ArrayVec { let arr = &mut self.values as &mut [ManuallyDrop<_>]; self.count -= 1; unsafe { - let value = ptr::read(&arr[self.count]); - Some(value.value) + let value = ptr::read(&*arr[self.count]); + Some(value) } } else { None @@ -210,7 +217,7 @@ impl Iterator for Iter { fn next(&mut self) -> Option { let arr = &self.store as &[ManuallyDrop<_>]; unsafe { - self.indices.next().map(|i| ptr::read(&arr[i]).value) + self.indices.next().map(|i| ptr::read(&*arr[i])) } } @@ -233,7 +240,7 @@ impl<'a, A: Array> Iterator for Drain<'a, A> { #[inline] fn next(&mut self) -> Option { - self.iter.next().map(|elt| unsafe { ptr::read(elt as *const ManuallyDrop<_>).value }) + self.iter.next().map(|elt| unsafe { ptr::read(&**elt) }) } fn size_hint(&self) -> (usize, Option) { @@ -295,25 +302,3 @@ impl<'a, A: Array> IntoIterator for &'a mut ArrayVec { self.iter_mut() } } - -// FIXME: This should use repr(transparent) from rust-lang/rfcs#1758. -#[allow(unions_with_drop_fields)] -pub union ManuallyDrop { - value: T, - #[allow(dead_code)] - empty: (), -} - -impl ManuallyDrop { - fn new() -> ManuallyDrop { - ManuallyDrop { - empty: () - } - } -} - -impl Default for ManuallyDrop { - fn default() -> Self { - ManuallyDrop::new() - } -} diff --git a/src/librustc_data_structures/base_n.rs b/src/librustc_data_structures/base_n.rs index 4359581a897f..cf54229fa7f5 100644 --- a/src/librustc_data_structures/base_n.rs +++ b/src/librustc_data_structures/base_n.rs @@ -48,7 +48,7 @@ pub fn encode(n: u64, base: u64) -> String { #[test] fn test_encode() { fn test(n: u64, base: u64) { - assert_eq!(Ok(n), u64::from_str_radix(&encode(n, base)[..], base as u32)); + assert_eq!(Ok(n), u64::from_str_radix(&encode(n, base), base as u32)); } for base in 2..37 { diff --git a/src/librustc_data_structures/blake2b.rs b/src/librustc_data_structures/blake2b.rs index 31492e262194..bdef9fefd41e 100644 --- a/src/librustc_data_structures/blake2b.rs +++ b/src/librustc_data_structures/blake2b.rs @@ -29,16 +29,23 @@ pub struct Blake2bCtx { t: [u64; 2], c: usize, outlen: u16, - finalized: bool + finalized: bool, + + #[cfg(debug_assertions)] + fnv_hash: u64, } +#[cfg(debug_assertions)] impl ::std::fmt::Debug for Blake2bCtx { - fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { - try!(write!(fmt, "hash: ")); - for v in &self.h[..] { - try!(write!(fmt, "{:x}", v)); - } - Ok(()) + fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + write!(fmt, "{:x}", self.fnv_hash) + } +} + +#[cfg(not(debug_assertions))] +impl ::std::fmt::Debug for Blake2bCtx { + fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + write!(fmt, "Enable debug_assertions() for more info.") } } @@ -157,6 +164,9 @@ fn blake2b_new(outlen: usize, key: &[u8]) -> Blake2bCtx { c: 0, outlen: outlen as u16, finalized: false, + + #[cfg(debug_assertions)] + fnv_hash: 0xcbf29ce484222325, }; ctx.h[0] ^= 0x01010000 ^ ((key.len() << 8) as u64) ^ (outlen as u64); @@ -194,6 +204,16 @@ fn blake2b_update(ctx: &mut Blake2bCtx, mut data: &[u8]) { checked_mem_copy(data, &mut ctx.b[ctx.c .. ], bytes_to_copy); ctx.c += bytes_to_copy; } + + #[cfg(debug_assertions)] + { + // compute additional FNV hash for simpler to read debug output + const MAGIC_PRIME: u64 = 0x00000100000001b3; + + for &byte in data { + ctx.fnv_hash = (ctx.fnv_hash ^ byte as u64).wrapping_mul(MAGIC_PRIME); + } + } } fn blake2b_final(ctx: &mut Blake2bCtx) diff --git a/src/librustc_data_structures/flock.rs b/src/librustc_data_structures/flock.rs index 26417e3ba7cd..32f0fd419977 100644 --- a/src/librustc_data_structures/flock.rs +++ b/src/librustc_data_structures/flock.rs @@ -113,6 +113,7 @@ mod imp { pub l_sysid: libc::c_int, } + pub const F_RDLCK: libc::c_short = 0x0040; pub const F_UNLCK: libc::c_short = 0x0200; pub const F_WRLCK: libc::c_short = 0x0400; pub const F_SETLK: libc::c_int = 0x0080; diff --git a/src/librustc_data_structures/indexed_set.rs b/src/librustc_data_structures/indexed_set.rs index 2e9e054e97ea..572ce98d3ae8 100644 --- a/src/librustc_data_structures/indexed_set.rs +++ b/src/librustc_data_structures/indexed_set.rs @@ -91,13 +91,13 @@ impl IdxSet { impl Deref for IdxSetBuf { type Target = IdxSet; fn deref(&self) -> &IdxSet { - unsafe { IdxSet::from_slice(&self.bits[..]) } + unsafe { IdxSet::from_slice(&self.bits) } } } impl DerefMut for IdxSetBuf { fn deref_mut(&mut self) -> &mut IdxSet { - unsafe { IdxSet::from_slice_mut(&mut self.bits[..]) } + unsafe { IdxSet::from_slice_mut(&mut self.bits) } } } @@ -135,11 +135,11 @@ impl IdxSet { } pub fn words(&self) -> &[Word] { - &self.bits[..] + &self.bits } pub fn words_mut(&mut self) -> &mut [Word] { - &mut self.bits[..] + &mut self.bits } pub fn clone_from(&mut self, other: &IdxSet) { diff --git a/src/librustc_data_structures/indexed_vec.rs b/src/librustc_data_structures/indexed_vec.rs index 62c430dda327..0642ddc71622 100644 --- a/src/librustc_data_structures/indexed_vec.rs +++ b/src/librustc_data_structures/indexed_vec.rs @@ -24,7 +24,7 @@ use rustc_serialize as serialize; /// /// (purpose: avoid mixing indexes for different bitvector domains.) pub trait Idx: Copy + 'static + Eq + Debug { - fn new(usize) -> Self; + fn new(idx: usize) -> Self; fn index(self) -> usize; } diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 8ecfd75dc95a..00c46d992bfd 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -27,7 +27,6 @@ #![feature(shared)] #![feature(collections_range)] -#![cfg_attr(stage0,feature(field_init_shorthand))] #![feature(nonzero)] #![feature(rustc_private)] #![feature(staged_api)] @@ -38,6 +37,10 @@ #![feature(unsize)] #![feature(i128_type)] #![feature(conservative_impl_trait)] +#![feature(discriminant_value)] +#![feature(specialization)] +#![feature(manually_drop)] +#![feature(struct_field_attributes)] #![cfg_attr(unix, feature(libc))] #![cfg_attr(test, feature(test))] diff --git a/src/librustc_data_structures/obligation_forest/mod.rs b/src/librustc_data_structures/obligation_forest/mod.rs index a46238309bb4..3515e5c5ede3 100644 --- a/src/librustc_data_structures/obligation_forest/mod.rs +++ b/src/librustc_data_structures/obligation_forest/mod.rs @@ -43,7 +43,16 @@ pub trait ObligationProcessor { obligation: &mut Self::Obligation) -> Result>, Self::Error>; - fn process_backedge<'c, I>(&mut self, cycle: I, + /// As we do the cycle check, we invoke this callback when we + /// encounter an actual cycle. `cycle` is an iterator that starts + /// at the start of the cycle in the stack and walks **toward the + /// top**. + /// + /// In other words, if we had O1 which required O2 which required + /// O3 which required O1, we would give an iterator yielding O1, + /// O2, O3 (O1 is not yielded twice). + fn process_backedge<'c, I>(&mut self, + cycle: I, _marker: PhantomData<&'c Self::Obligation>) where I: Clone + Iterator; } @@ -239,8 +248,8 @@ impl ObligationForest { } } Entry::Vacant(v) => { - debug!("register_obligation_at({:?}, {:?}) - ok", - obligation, parent); + debug!("register_obligation_at({:?}, {:?}) - ok, new index is {}", + obligation, parent, self.nodes.len()); v.insert(NodeIndex::new(self.nodes.len())); self.cache_list.push(obligation.as_predicate().clone()); self.nodes.push(Node::new(parent, obligation)); @@ -376,6 +385,9 @@ impl ObligationForest { where P: ObligationProcessor { let mut stack = self.scratch.take().unwrap(); + debug_assert!(stack.is_empty()); + + debug!("process_cycles()"); for index in 0..self.nodes.len() { // For rustc-benchmarks/inflate-0.1.0 this state test is extremely @@ -389,6 +401,9 @@ impl ObligationForest { } } + debug!("process_cycles: complete"); + + debug_assert!(stack.is_empty()); self.scratch = Some(stack); } @@ -402,21 +417,6 @@ impl ObligationForest { NodeState::OnDfsStack => { let index = stack.iter().rposition(|n| *n == index).unwrap(); - // I need a Clone closure - #[derive(Clone)] - struct GetObligation<'a, O: 'a>(&'a [Node]); - impl<'a, 'b, O> FnOnce<(&'b usize,)> for GetObligation<'a, O> { - type Output = &'a O; - extern "rust-call" fn call_once(self, args: (&'b usize,)) -> &'a O { - &self.0[*args.0].obligation - } - } - impl<'a, 'b, O> FnMut<(&'b usize,)> for GetObligation<'a, O> { - extern "rust-call" fn call_mut(&mut self, args: (&'b usize,)) -> &'a O { - &self.0[*args.0].obligation - } - } - processor.process_backedge(stack[index..].iter().map(GetObligation(&self.nodes)), PhantomData); } @@ -645,3 +645,20 @@ impl Node { } } } + +// I need a Clone closure +#[derive(Clone)] +struct GetObligation<'a, O: 'a>(&'a [Node]); + +impl<'a, 'b, O> FnOnce<(&'b usize,)> for GetObligation<'a, O> { + type Output = &'a O; + extern "rust-call" fn call_once(self, args: (&'b usize,)) -> &'a O { + &self.0[*args.0].obligation + } +} + +impl<'a, 'b, O> FnMut<(&'b usize,)> for GetObligation<'a, O> { + extern "rust-call" fn call_mut(&mut self, args: (&'b usize,)) -> &'a O { + &self.0[*args.0].obligation + } +} diff --git a/src/librustc_data_structures/stable_hasher.rs b/src/librustc_data_structures/stable_hasher.rs index 231c01c9ab78..95f063976d49 100644 --- a/src/librustc_data_structures/stable_hasher.rs +++ b/src/librustc_data_structures/stable_hasher.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::hash::Hasher; +use std::hash::{Hash, Hasher}; use std::marker::PhantomData; use std::mem; use blake2b::Blake2bHasher; @@ -40,13 +40,18 @@ fn write_signed_leb128_to_buf(buf: &mut [u8; 16], value: i64) -> usize { /// This hasher currently always uses the stable Blake2b algorithm /// and allows for variable output lengths through its type /// parameter. -#[derive(Debug)] pub struct StableHasher { state: Blake2bHasher, bytes_hashed: u64, width: PhantomData, } +impl ::std::fmt::Debug for StableHasher { + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + write!(f, "{:?}", self.state) + } +} + pub trait StableHasherResult: Sized { fn finish(hasher: StableHasher) -> Self; } @@ -174,3 +179,193 @@ impl Hasher for StableHasher { self.write_ileb128(i as i64); } } + + +/// Something that implements `HashStable` can be hashed in a way that is +/// stable across multiple compiliation sessions. +pub trait HashStable { + fn hash_stable(&self, + hcx: &mut CTX, + hasher: &mut StableHasher); +} + +// Implement HashStable by just calling `Hash::hash()`. This works fine for +// self-contained values that don't depend on the hashing context `CTX`. +macro_rules! impl_stable_hash_via_hash { + ($t:ty) => ( + impl HashStable for $t { + #[inline] + fn hash_stable(&self, + _: &mut CTX, + hasher: &mut StableHasher) { + ::std::hash::Hash::hash(self, hasher); + } + } + ); +} + +impl_stable_hash_via_hash!(i8); +impl_stable_hash_via_hash!(i16); +impl_stable_hash_via_hash!(i32); +impl_stable_hash_via_hash!(i64); +impl_stable_hash_via_hash!(isize); + +impl_stable_hash_via_hash!(u8); +impl_stable_hash_via_hash!(u16); +impl_stable_hash_via_hash!(u32); +impl_stable_hash_via_hash!(u64); +impl_stable_hash_via_hash!(usize); + +impl_stable_hash_via_hash!(u128); +impl_stable_hash_via_hash!(i128); + +impl_stable_hash_via_hash!(char); +impl_stable_hash_via_hash!(()); + +impl HashStable for f32 { + fn hash_stable(&self, + ctx: &mut CTX, + hasher: &mut StableHasher) { + let val: u32 = unsafe { + ::std::mem::transmute(*self) + }; + val.hash_stable(ctx, hasher); + } +} + +impl HashStable for f64 { + fn hash_stable(&self, + ctx: &mut CTX, + hasher: &mut StableHasher) { + let val: u64 = unsafe { + ::std::mem::transmute(*self) + }; + val.hash_stable(ctx, hasher); + } +} + +impl, T2: HashStable, CTX> HashStable for (T1, T2) { + fn hash_stable(&self, + ctx: &mut CTX, + hasher: &mut StableHasher) { + self.0.hash_stable(ctx, hasher); + self.1.hash_stable(ctx, hasher); + } +} + +impl, CTX> HashStable for [T] { + default fn hash_stable(&self, + ctx: &mut CTX, + hasher: &mut StableHasher) { + self.len().hash_stable(ctx, hasher); + for item in self { + item.hash_stable(ctx, hasher); + } + } +} + +impl, CTX> HashStable for Vec { + #[inline] + fn hash_stable(&self, + ctx: &mut CTX, + hasher: &mut StableHasher) { + (&self[..]).hash_stable(ctx, hasher); + } +} + +impl HashStable for str { + #[inline] + fn hash_stable(&self, + _: &mut CTX, + hasher: &mut StableHasher) { + self.len().hash(hasher); + self.as_bytes().hash(hasher); + } +} + +impl HashStable for bool { + #[inline] + fn hash_stable(&self, + ctx: &mut CTX, + hasher: &mut StableHasher) { + (if *self { 1u8 } else { 0u8 }).hash_stable(ctx, hasher); + } +} + + +impl HashStable for Option + where T: HashStable +{ + #[inline] + fn hash_stable(&self, + ctx: &mut CTX, + hasher: &mut StableHasher) { + if let Some(ref value) = *self { + 1u8.hash_stable(ctx, hasher); + value.hash_stable(ctx, hasher); + } else { + 0u8.hash_stable(ctx, hasher); + } + } +} + +impl<'a, T, CTX> HashStable for &'a T + where T: HashStable +{ + #[inline] + fn hash_stable(&self, + ctx: &mut CTX, + hasher: &mut StableHasher) { + (**self).hash_stable(ctx, hasher); + } +} + +impl HashStable for ::std::mem::Discriminant { + #[inline] + fn hash_stable(&self, + _: &mut CTX, + hasher: &mut StableHasher) { + ::std::hash::Hash::hash(self, hasher); + } +} + +impl HashStable for ::std::collections::BTreeMap + where K: Ord + HashStable, + V: HashStable, +{ + fn hash_stable(&self, + ctx: &mut CTX, + hasher: &mut StableHasher) { + self.len().hash_stable(ctx, hasher); + for (k, v) in self { + k.hash_stable(ctx, hasher); + v.hash_stable(ctx, hasher); + } + } +} + +impl HashStable for ::std::collections::BTreeSet + where T: Ord + HashStable, +{ + fn hash_stable(&self, + ctx: &mut CTX, + hasher: &mut StableHasher) { + self.len().hash_stable(ctx, hasher); + for v in self { + v.hash_stable(ctx, hasher); + } + } +} + +impl HashStable for ::indexed_vec::IndexVec + where T: HashStable, +{ + fn hash_stable(&self, + ctx: &mut CTX, + hasher: &mut StableHasher) { + self.len().hash_stable(ctx, hasher); + for v in &self.raw { + v.hash_stable(ctx, hasher); + } + } +} diff --git a/src/librustc_data_structures/transitive_relation.rs b/src/librustc_data_structures/transitive_relation.rs index 2bce7faf08ce..b0fca5c0ff37 100644 --- a/src/librustc_data_structures/transitive_relation.rs +++ b/src/librustc_data_structures/transitive_relation.rs @@ -9,11 +9,14 @@ // except according to those terms. use bitvec::BitMatrix; +use stable_hasher::{HashStable, StableHasher, StableHasherResult}; use rustc_serialize::{Encodable, Encoder, Decodable, Decoder}; use std::cell::RefCell; use std::fmt::Debug; use std::mem; + + #[derive(Clone)] pub struct TransitiveRelation { // List of elements. This is used to map from a T to a usize. We @@ -77,6 +80,27 @@ impl TransitiveRelation { } } + /// Applies the (partial) function to each edge and returns a new + /// 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, + U: Debug + PartialEq, + { + let mut result = TransitiveRelation::new(); + for edge in &self.edges { + let r = f(&self.elements[edge.source.0]).and_then(|source| { + f(&self.elements[edge.target.0]).and_then(|target| { + Some(result.add(source, target)) + }) + }); + if r.is_none() { + return None; + } + } + Some(result) + } + /// Indicate that `a < b` (where `<` is this relation) pub fn add(&mut self, a: T, b: T) { let a = self.add_index(a); @@ -334,6 +358,49 @@ impl Decodable for TransitiveRelation } } +impl HashStable for TransitiveRelation + where T: HashStable + PartialEq + Debug +{ + fn hash_stable(&self, + hcx: &mut CTX, + hasher: &mut StableHasher) { + // We are assuming here that the relation graph has been built in a + // deterministic way and we can just hash it the way it is. + let TransitiveRelation { + ref elements, + ref edges, + // "closure" is just a copy of the data above + closure: _ + } = *self; + + elements.hash_stable(hcx, hasher); + edges.hash_stable(hcx, hasher); + } +} + +impl HashStable for Edge { + fn hash_stable(&self, + hcx: &mut CTX, + hasher: &mut StableHasher) { + let Edge { + ref source, + ref target, + } = *self; + + source.hash_stable(hcx, hasher); + target.hash_stable(hcx, hasher); + } +} + +impl HashStable for Index { + fn hash_stable(&self, + hcx: &mut CTX, + hasher: &mut StableHasher) { + let Index(idx) = *self; + idx.hash_stable(hcx, hasher); + } +} + #[test] fn test_one_step() { let mut relation = TransitiveRelation::new(); diff --git a/src/librustc_driver/Cargo.toml b/src/librustc_driver/Cargo.toml index caa5c8b7e005..5b5113caa8e8 100644 --- a/src/librustc_driver/Cargo.toml +++ b/src/librustc_driver/Cargo.toml @@ -11,7 +11,8 @@ crate-type = ["dylib"] [dependencies] arena = { path = "../libarena" } graphviz = { path = "../libgraphviz" } -log = { path = "../liblog" } +log = { version = "0.3", features = ["release_max_level_info"] } +env_logger = { version = "0.4", default-features = false } proc_macro_plugin = { path = "../libproc_macro_plugin" } rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } diff --git a/src/librustc_driver/derive_registrar.rs b/src/librustc_driver/derive_registrar.rs index 6a884bafce75..9983efce6af0 100644 --- a/src/librustc_driver/derive_registrar.rs +++ b/src/librustc_driver/derive_registrar.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use rustc::dep_graph::DepNode; use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir::map::Map; use rustc::hir; @@ -16,7 +15,6 @@ use syntax::ast; use syntax::attr; pub fn find(hir_map: &Map) -> Option { - let _task = hir_map.dep_graph.in_task(DepNode::PluginRegistrar); let krate = hir_map.krate(); let mut finder = Finder { registrar: None }; diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index d37553d7d660..9f0f567b6cee 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -20,6 +20,7 @@ use rustc::session::search_paths::PathKind; use rustc::lint; use rustc::middle::{self, dependency_format, stability, reachable}; use rustc::middle::privacy::AccessLevels; +use rustc::mir::transform::{MIR_CONST, MIR_VALIDATED, MIR_OPTIMIZED, Passes}; use rustc::ty::{self, TyCtxt, Resolutions, GlobalArenas}; use rustc::util::common::time; use rustc::util::nodemap::NodeSet; @@ -35,9 +36,8 @@ use rustc_typeck as typeck; use rustc_privacy; use rustc_plugin::registry::Registry; use rustc_plugin as plugin; -use rustc_passes::{ast_validation, no_asm, loops, consts, rvalues, - static_recursion, hir_stats, mir_stats}; -use rustc_const_eval::check_match; +use rustc_passes::{ast_validation, no_asm, loops, consts, static_recursion, hir_stats}; +use rustc_const_eval::{self, check_match}; use super::Compilation; use serialize::json; @@ -48,6 +48,7 @@ use std::fs; use std::io::{self, Write}; use std::iter; use std::path::{Path, PathBuf}; +use std::rc::Rc; use syntax::{ast, diagnostics, visit}; use syntax::attr; use syntax::ext::base::ExtCtxt; @@ -198,13 +199,13 @@ pub fn compile_input(sess: &Session, result?; - if log_enabled!(::log::INFO) { + if log_enabled!(::log::LogLevel::Info) { println!("Pre-trans"); tcx.print_debug_stats(); } let trans = phase_4_translate_to_llvm(tcx, analysis, &incremental_hashes_map); - if log_enabled!(::log::INFO) { + if log_enabled!(::log::LogLevel::Info) { println!("Post-trans"); tcx.print_debug_stats(); } @@ -257,10 +258,7 @@ fn keep_hygiene_data(sess: &Session) -> bool { } fn keep_ast(sess: &Session) -> bool { - sess.opts.debugging_opts.keep_ast || - sess.opts.debugging_opts.save_analysis || - sess.opts.debugging_opts.save_analysis_csv || - sess.opts.debugging_opts.save_analysis_api + sess.opts.debugging_opts.keep_ast || ::save_analysis(sess) } /// The name used for source code that doesn't originate in a file @@ -582,7 +580,7 @@ pub fn phase_2_configure_and_expand(sess: &Session, krate = time(time_passes, "crate injection", || { let alt_std_name = sess.opts.alt_std_name.clone(); - syntax::std_inject::maybe_inject_crates_ref(&sess.parse_sess, krate, alt_std_name) + syntax::std_inject::maybe_inject_crates_ref(krate, alt_std_name) }); let mut addl_plugins = Some(addl_plugins); @@ -649,8 +647,12 @@ pub fn phase_2_configure_and_expand(sess: &Session, let mut crate_loader = CrateLoader::new(sess, &cstore, crate_name); crate_loader.preprocess(&krate); let resolver_arenas = Resolver::arenas(); - let mut resolver = - Resolver::new(sess, &krate, make_glob_map, &mut crate_loader, &resolver_arenas); + let mut resolver = Resolver::new(sess, + &krate, + crate_name, + make_glob_map, + &mut crate_loader, + &resolver_arenas); resolver.whitelisted_legacy_custom_derives = whitelisted_legacy_custom_derives; syntax_ext::register_builtins(&mut resolver, syntax_exts, sess.features.borrow().quote); @@ -800,25 +802,25 @@ pub fn phase_2_configure_and_expand(sess: &Session, // Discard hygiene data, which isn't required after lowering to HIR. if !keep_hygiene_data(sess) { - syntax::ext::hygiene::reset_hygiene_data(); + syntax::ext::hygiene::clear_markings(); } Ok(ExpansionResult { expanded_crate: krate, defs: resolver.definitions, analysis: ty::CrateAnalysis { - export_map: resolver.export_map, - access_levels: AccessLevels::default(), - reachable: NodeSet(), + access_levels: Rc::new(AccessLevels::default()), + reachable: Rc::new(NodeSet()), name: crate_name.to_string(), glob_map: if resolver.make_glob_map { Some(resolver.glob_map) } else { None }, }, resolutions: Resolutions { freevars: resolver.freevars, + export_map: resolver.export_map, trait_map: resolver.trait_map, maybe_unused_trait_imports: resolver.maybe_unused_trait_imports, }, - hir_forest: hir_forest + hir_forest: hir_forest, }) } @@ -872,10 +874,6 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, })); sess.derive_registrar_fn.set(derive_registrar::find(&hir_map)); - let region_map = time(time_passes, - "region resolution", - || middle::region::resolve_crate(sess, &hir_map)); - time(time_passes, "loop checking", || loops::check_crate(sess, &hir_map)); @@ -887,22 +885,67 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, let index = stability::Index::new(&hir_map); let mut local_providers = ty::maps::Providers::default(); + borrowck::provide(&mut local_providers); mir::provide(&mut local_providers); + reachable::provide(&mut local_providers); + rustc_privacy::provide(&mut local_providers); + trans::provide(&mut local_providers); typeck::provide(&mut local_providers); ty::provide(&mut local_providers); + reachable::provide(&mut local_providers); + rustc_const_eval::provide(&mut local_providers); + middle::region::provide(&mut local_providers); let mut extern_providers = ty::maps::Providers::default(); cstore::provide(&mut extern_providers); + trans::provide(&mut extern_providers); + ty::provide_extern(&mut extern_providers); + // FIXME(eddyb) get rid of this once we replace const_eval with miri. + rustc_const_eval::provide(&mut extern_providers); + + // Setup the MIR passes that we want to run. + let mut passes = Passes::new(); + passes.push_hook(mir::transform::dump_mir::DumpMir); + + // What we need to do constant evaluation. + passes.push_pass(MIR_CONST, mir::transform::simplify::SimplifyCfg::new("initial")); + passes.push_pass(MIR_CONST, mir::transform::type_check::TypeckMir); + + // What we need to run borrowck etc. + passes.push_pass(MIR_VALIDATED, mir::transform::qualify_consts::QualifyAndPromoteConstants); + passes.push_pass(MIR_VALIDATED, + mir::transform::simplify_branches::SimplifyBranches::new("initial")); + passes.push_pass(MIR_VALIDATED, mir::transform::simplify::SimplifyCfg::new("qualify-consts")); + + // Optimizations begin. + passes.push_pass(MIR_OPTIMIZED, mir::transform::no_landing_pads::NoLandingPads); + passes.push_pass(MIR_OPTIMIZED, mir::transform::simplify::SimplifyCfg::new("no-landing-pads")); + + // From here on out, regions are gone. + passes.push_pass(MIR_OPTIMIZED, mir::transform::erase_regions::EraseRegions); + passes.push_pass(MIR_OPTIMIZED, mir::transform::add_call_guards::AddCallGuards); + passes.push_pass(MIR_OPTIMIZED, borrowck::ElaborateDrops); + passes.push_pass(MIR_OPTIMIZED, mir::transform::no_landing_pads::NoLandingPads); + passes.push_pass(MIR_OPTIMIZED, mir::transform::simplify::SimplifyCfg::new("elaborate-drops")); + + // No lifetime analysis based on borrowing can be done from here on out. + passes.push_pass(MIR_OPTIMIZED, mir::transform::inline::Inline); + passes.push_pass(MIR_OPTIMIZED, mir::transform::instcombine::InstCombine); + passes.push_pass(MIR_OPTIMIZED, mir::transform::deaggregator::Deaggregator); + passes.push_pass(MIR_OPTIMIZED, mir::transform::copy_prop::CopyPropagation); + passes.push_pass(MIR_OPTIMIZED, mir::transform::simplify::SimplifyLocals); + passes.push_pass(MIR_OPTIMIZED, mir::transform::add_call_guards::AddCallGuards); + passes.push_pass(MIR_OPTIMIZED, mir::transform::dump_mir::Marker("PreTrans")); TyCtxt::create_and_enter(sess, local_providers, extern_providers, + Rc::new(passes), arenas, arena, resolutions, named_region_map, hir_map, - region_map, lang_items, index, name, @@ -911,6 +954,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, time(time_passes, "compute_incremental_hashes_map", || rustc_incremental::compute_incremental_hashes_map(tcx)); + time(time_passes, "load_dep_graph", || rustc_incremental::load_dep_graph(tcx, &incremental_hashes_map)); @@ -931,9 +975,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, || consts::check_crate(tcx)); analysis.access_levels = - time(time_passes, "privacy checking", || { - rustc_privacy::check_crate(tcx, &analysis.export_map) - }); + time(time_passes, "privacy checking", || rustc_privacy::check_crate(tcx)); time(time_passes, "intrinsic checking", @@ -955,34 +997,6 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, "liveness checking", || middle::liveness::check_crate(tcx)); - time(time_passes, - "rvalue checking", - || rvalues::check_crate(tcx)); - - time(time_passes, - "MIR dump", - || mir::mir_map::build_mir_for_crate(tcx)); - - if sess.opts.debugging_opts.mir_stats { - mir_stats::print_mir_stats(tcx, "PRE CLEANUP MIR STATS"); - } - - time(time_passes, "MIR cleanup and validation", || { - let mut passes = sess.mir_passes.borrow_mut(); - // Push all the built-in validation passes. - // NB: if you’re adding an *optimisation* it ought to go to another set of passes - // in stage 4 below. - passes.push_hook(box mir::transform::dump_mir::DumpMir); - passes.push_pass(box mir::transform::simplify::SimplifyCfg::new("initial")); - passes.push_pass(box mir::transform::qualify_consts::QualifyAndPromoteConstants); - passes.push_pass(box mir::transform::type_check::TypeckMir); - passes.push_pass( - box mir::transform::simplify_branches::SimplifyBranches::new("initial")); - passes.push_pass(box mir::transform::simplify::SimplifyCfg::new("qualify-consts")); - // And run everything. - passes.run_passes(tcx); - }); - time(time_passes, "borrow checking", || borrowck::check_crate(tcx)); @@ -1000,19 +1014,15 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, analysis.reachable = time(time_passes, "reachability checking", - || reachable::find_reachable(tcx, &analysis.access_levels)); + || reachable::find_reachable(tcx)); - time(time_passes, "death checking", || { - middle::dead::check_crate(tcx, &analysis.access_levels); - }); + time(time_passes, "death checking", || middle::dead::check_crate(tcx)); time(time_passes, "unused lib feature checking", || { - stability::check_unused_or_stable_features(tcx, &analysis.access_levels) + stability::check_unused_or_stable_features(tcx) }); - time(time_passes, - "lint checking", - || lint::check_crate(tcx, &analysis.access_levels)); + time(time_passes, "lint checking", || lint::check_crate(tcx)); // The above three passes generate errors w/o aborting if sess.err_count() > 0 { @@ -1035,43 +1045,6 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, "resolving dependency formats", || dependency_format::calculate(&tcx.sess)); - if tcx.sess.opts.debugging_opts.mir_stats { - mir_stats::print_mir_stats(tcx, "PRE OPTIMISATION MIR STATS"); - } - - // Run the passes that transform the MIR into a more suitable form for translation to LLVM - // code. - time(time_passes, "MIR optimisations", || { - let mut passes = ::rustc::mir::transform::Passes::new(); - passes.push_hook(box mir::transform::dump_mir::DumpMir); - passes.push_pass(box mir::transform::no_landing_pads::NoLandingPads); - passes.push_pass(box mir::transform::simplify::SimplifyCfg::new("no-landing-pads")); - - // From here on out, regions are gone. - passes.push_pass(box mir::transform::erase_regions::EraseRegions); - - passes.push_pass(box mir::transform::add_call_guards::AddCallGuards); - passes.push_pass(box borrowck::ElaborateDrops); - passes.push_pass(box mir::transform::no_landing_pads::NoLandingPads); - passes.push_pass(box mir::transform::simplify::SimplifyCfg::new("elaborate-drops")); - - // No lifetime analysis based on borrowing can be done from here on out. - passes.push_pass(box mir::transform::inline::Inline); - passes.push_pass(box mir::transform::instcombine::InstCombine::new()); - passes.push_pass(box mir::transform::deaggregator::Deaggregator); - passes.push_pass(box mir::transform::copy_prop::CopyPropagation); - - passes.push_pass(box mir::transform::simplify::SimplifyLocals); - passes.push_pass(box mir::transform::add_call_guards::AddCallGuards); - passes.push_pass(box mir::transform::dump_mir::Marker("PreTrans")); - - passes.run_passes(tcx); - }); - - if tcx.sess.opts.debugging_opts.mir_stats { - mir_stats::print_mir_stats(tcx, "POST OPTIMISATION MIR STATS"); - } - let translation = time(time_passes, "translation", @@ -1085,6 +1058,7 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, "serialize dep graph", || rustc_incremental::save_dep_graph(tcx, &incremental_hashes_map, + &translation.metadata.hashes, translation.link.crate_hash)); translation } @@ -1144,7 +1118,7 @@ pub fn phase_6_link_output(sess: &Session, outputs: &OutputFilenames) { time(sess.time_passes(), "linking", - || link::link_binary(sess, trans, outputs, &trans.link.crate_name.as_str())); + || link::link_binary(sess, trans, outputs, &trans.crate_name.as_str())); } fn escape_dep_filename(filename: &str) -> String { @@ -1365,10 +1339,9 @@ pub fn build_output_filenames(input: &Input, .values() .filter(|a| a.is_none()) .count(); - let ofile = if unnamed_output_types > 1 && - sess.opts.output_types.contains_key(&OutputType::Exe) { - sess.warn("ignoring specified output filename for 'link' output because multiple \ - outputs were requested"); + let ofile = if unnamed_output_types > 1 { + sess.warn("due to multiple output types requested, the explicitly specified \ + output file name will be adapted for each output type"); None } else { Some(out_file.clone()) diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 62d751265572..889f4dd4b9aa 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -35,6 +35,7 @@ extern crate arena; extern crate getopts; extern crate graphviz; +extern crate env_logger; extern crate libc; extern crate rustc; extern crate rustc_back; @@ -66,6 +67,7 @@ use pretty::{PpMode, UserIdentifiedItem}; use rustc_resolve as resolve; use rustc_save_analysis as save; +use rustc_save_analysis::DumpHandler; use rustc_trans::back::link; use rustc_trans::back::write::{create_target_machine, RELOC_MODEL_ARGS, CODE_GEN_MODEL_ARGS}; use rustc::dep_graph::DepGraph; @@ -204,7 +206,7 @@ pub fn run_compiler<'a>(args: &[String], let cstore = Rc::new(CStore::new(&dep_graph)); let loader = file_loader.unwrap_or(box RealFileLoader); - let codemap = Rc::new(CodeMap::with_file_loader(loader)); + let codemap = Rc::new(CodeMap::with_file_loader(loader, sopts.file_path_mapping())); let mut sess = session::build_session_with_codemap( sopts, &dep_graph, input_file_path, descriptions, cstore.clone(), codemap, emitter_dest, ); @@ -232,7 +234,7 @@ fn make_output(matches: &getopts::Matches) -> (Option, Option) // Extract input (string or file and optional path) from matches. fn make_input(free_matches: &[String]) -> Option<(Input, Option)> { if free_matches.len() == 1 { - let ifile = &free_matches[0][..]; + let ifile = &free_matches[0]; if ifile == "-" { let mut src = String::new(); io::stdin().read_to_string(&mut src).unwrap(); @@ -341,7 +343,7 @@ pub trait CompilerCalls<'a> { // Create a CompilController struct for controlling the behaviour of // compilation. - fn build_controller(&mut self, &Session, &getopts::Matches) -> CompileController<'a>; + fn build_controller(&mut self, _: &Session, _: &getopts::Matches) -> CompileController<'a>; } // CompilerCalls instance for a regular rustc build. @@ -506,14 +508,25 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { state.expanded_crate.unwrap(), state.analysis.unwrap(), state.crate_name.unwrap(), - state.out_dir, - save_analysis_format(state.session)) + DumpHandler::new(save_analysis_format(state.session), + state.out_dir, + state.crate_name.unwrap())) }); }; control.after_analysis.run_callback_on_error = true; control.make_glob_map = resolve::MakeGlobMap::Yes; } + if sess.print_fuel_crate.is_some() { + let old_callback = control.compilation_done.callback; + control.compilation_done.callback = box move |state| { + old_callback(state); + let sess = state.session; + println!("Fuel used by {}: {}", + sess.print_fuel_crate.as_ref().unwrap(), + sess.print_fuel.get()); + } + } control } } @@ -799,7 +812,7 @@ Available lint options: for lint in lints { let name = lint.name_lower().replace("_", "-"); println!(" {} {:7.7} {}", - padded(&name[..]), + padded(&name), lint.default_level.as_str(), lint.desc); } @@ -837,7 +850,7 @@ Available lint options: .map(|x| x.to_string().replace("_", "-")) .collect::>() .join(", "); - println!(" {} {}", padded(&name[..]), desc); + println!(" {} {}", padded(&name), desc); } println!("\n"); }; @@ -944,7 +957,7 @@ pub fn handle_options(args: &[String]) -> Option { .into_iter() .map(|x| x.opt_group) .collect(); - let matches = match getopts::getopts(&args[..], &all_groups) { + let matches = match getopts::getopts(&args, &all_groups) { Ok(m) => m, Err(f) => early_error(ErrorOutputType::default(), &f.to_string()), }; @@ -1083,7 +1096,7 @@ pub fn monitor(f: F) { format!("we would appreciate a bug report: {}", BUG_REPORT_URL)]; for note in &xs { handler.emit(&MultiSpan::new(), - ¬e[..], + ¬e, errors::Level::Note); } if match env::var_os("RUST_BACKTRACE") { @@ -1127,6 +1140,7 @@ pub fn diagnostics_registry() -> errors::registry::Registry { } pub fn main() { + env_logger::init().unwrap(); let result = run(|| run_compiler(&env::args().collect::>(), &mut RustcDefaultCalls, None, diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index 6cd97e955988..d40a2ab0b530 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -41,7 +41,6 @@ use graphviz as dot; use std::cell::Cell; use std::fs::File; use std::io::{self, Write}; -use std::iter; use std::option; use std::path::Path; use std::str::FromStr; @@ -589,7 +588,7 @@ impl UserIdentifiedItem { -> NodesMatchingUII<'a, 'hir> { match *self { ItemViaNode(node_id) => NodesMatchingDirect(Some(node_id).into_iter()), - ItemViaPath(ref parts) => NodesMatchingSuffix(map.nodes_matching_suffix(&parts[..])), + ItemViaPath(ref parts) => NodesMatchingSuffix(map.nodes_matching_suffix(&parts)), } } @@ -600,7 +599,7 @@ impl UserIdentifiedItem { user_option, self.reconstructed_input(), is_wrong_because); - sess.fatal(&message[..]) + sess.fatal(&message) }; let mut saw_node = ast::DUMMY_NODE_ID; @@ -771,7 +770,7 @@ fn print_flowgraph<'a, 'tcx, W: Write>(variants: Vec, fn expand_err_details(r: io::Result<()>) -> io::Result<()> { r.map_err(|ioerr| { io::Error::new(io::ErrorKind::Other, - &format!("graphviz::render failed: {}", ioerr)[..]) + format!("graphviz::render failed: {}", ioerr)) }) } } @@ -999,22 +998,14 @@ fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session, if let Some(nodeid) = nodeid { let def_id = tcx.hir.local_def_id(nodeid); match ppm { - PpmMir => write_mir_pretty(tcx, iter::once(def_id), &mut out), - PpmMirCFG => write_mir_graphviz(tcx, iter::once(def_id), &mut out), + PpmMir => write_mir_pretty(tcx, Some(def_id), &mut out), + PpmMirCFG => write_mir_graphviz(tcx, Some(def_id), &mut out), _ => unreachable!(), }?; } else { match ppm { - PpmMir => { - write_mir_pretty(tcx, - tcx.maps.mir.borrow().keys().into_iter(), - &mut out) - } - PpmMirCFG => { - write_mir_graphviz(tcx, - tcx.maps.mir.borrow().keys().into_iter(), - &mut out) - } + PpmMir => write_mir_pretty(tcx, None, &mut out), + PpmMirCFG => write_mir_graphviz(tcx, None, &mut out), _ => unreachable!(), }?; } diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 9568cc3d6de0..8b95be00fa75 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -16,7 +16,7 @@ use rustc_lint; use rustc_resolve::MakeGlobMap; use rustc::middle::lang_items; use rustc::middle::free_region::FreeRegionMap; -use rustc::middle::region::{self, CodeExtent}; +use rustc::middle::region::{CodeExtent, RegionMaps}; use rustc::middle::region::CodeExtentData; use rustc::middle::resolve_lifetime; use rustc::middle::stability; @@ -27,11 +27,12 @@ use rustc::infer::{self, InferOk, InferResult}; use rustc::infer::type_variable::TypeVariableOrigin; use rustc_metadata::cstore::CStore; use rustc::hir::map as hir_map; +use rustc::mir::transform::Passes; use rustc::session::{self, config}; use std::rc::Rc; use syntax::ast; use syntax::abi::Abi; -use syntax::codemap::CodeMap; +use syntax::codemap::{CodeMap, FilePathMapping}; use errors; use errors::emitter::Emitter; use errors::{Level, DiagnosticBuilder}; @@ -44,6 +45,7 @@ use rustc::hir; struct Env<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { infcx: &'a infer::InferCtxt<'a, 'gcx, 'tcx>, + region_maps: &'a mut RegionMaps<'tcx>, } struct RH<'a> { @@ -108,7 +110,7 @@ fn test_env(source_string: &str, &dep_graph, None, diagnostic_handler, - Rc::new(CodeMap::new()), + Rc::new(CodeMap::new(FilePathMapping::empty())), cstore.clone()); rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); let input = config::Input::Str { @@ -136,26 +138,26 @@ fn test_env(source_string: &str, // run just enough stuff to build a tcx: let lang_items = lang_items::collect_language_items(&sess, &hir_map); let named_region_map = resolve_lifetime::krate(&sess, &hir_map); - let region_map = region::resolve_crate(&sess, &hir_map); let index = stability::Index::new(&hir_map); TyCtxt::create_and_enter(&sess, ty::maps::Providers::default(), ty::maps::Providers::default(), + Rc::new(Passes::new()), &arenas, &arena, resolutions, named_region_map.unwrap(), hir_map, - region_map, lang_items, index, "test_crate", |tcx| { tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| { - - body(Env { infcx: &infcx }); + let mut region_maps = RegionMaps::new(); + body(Env { infcx: &infcx, region_maps: &mut region_maps }); let free_regions = FreeRegionMap::new(); - infcx.resolve_regions_and_report_errors(&free_regions, ast::CRATE_NODE_ID); + let def_id = tcx.hir.local_def_id(ast::CRATE_NODE_ID); + infcx.resolve_regions_and_report_errors(def_id, ®ion_maps, &free_regions); assert_eq!(tcx.sess.err_count(), expected_err_count); }); }); @@ -166,23 +168,21 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { self.infcx.tcx } - pub fn create_region_hierarchy(&self, rh: &RH, parent: CodeExtent) { - let me = self.infcx.tcx.region_maps.intern_node(rh.id, parent); + pub fn create_region_hierarchy(&mut self, rh: &RH, parent: CodeExtent<'tcx>) { + let me = self.tcx().intern_code_extent(CodeExtentData::Misc(rh.id)); + self.region_maps.record_code_extent(me, Some(parent)); for child_rh in rh.sub { self.create_region_hierarchy(child_rh, me); } } - pub fn create_simple_region_hierarchy(&self) { + pub fn create_simple_region_hierarchy(&mut self) { // creates a region hierarchy where 1 is root, 10 and 11 are // children of 1, etc let node = ast::NodeId::from_u32; - let dscope = self.infcx - .tcx - .region_maps - .intern_code_extent(CodeExtentData::DestructionScope(node(1)), - region::ROOT_CODE_EXTENT); + let dscope = self.tcx().intern_code_extent(CodeExtentData::DestructionScope(node(1))); + self.region_maps.record_code_extent(dscope, None); self.create_region_hierarchy(&RH { id: node(1), sub: &[RH { @@ -233,6 +233,7 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { hir::ItemStatic(..) | hir::ItemFn(..) | hir::ItemForeignMod(..) | + hir::ItemGlobalAsm(..) | hir::ItemTy(..) => None, hir::ItemEnum(..) | @@ -289,10 +290,10 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { pub fn t_param(&self, index: u32) -> Ty<'tcx> { let name = format!("T{}", index); - self.infcx.tcx.mk_param(index, Symbol::intern(&name[..])) + self.infcx.tcx.mk_param(index, Symbol::intern(&name)) } - pub fn re_early_bound(&self, index: u32, name: &'static str) -> &'tcx ty::Region { + pub fn re_early_bound(&self, index: u32, name: &'static str) -> ty::Region<'tcx> { let name = Symbol::intern(name); self.infcx.tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion { index: index, @@ -303,11 +304,11 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { pub fn re_late_bound_with_debruijn(&self, id: u32, debruijn: ty::DebruijnIndex) - -> &'tcx ty::Region { + -> ty::Region<'tcx> { self.infcx.tcx.mk_region(ty::ReLateBound(debruijn, ty::BrAnon(id))) } - pub fn t_rptr(&self, r: &'tcx ty::Region) -> Ty<'tcx> { + pub fn t_rptr(&self, r: ty::Region<'tcx>) -> Ty<'tcx> { self.infcx.tcx.mk_imm_ref(r, self.tcx().types.isize) } @@ -325,13 +326,13 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { } pub fn t_rptr_scope(&self, id: u32) -> Ty<'tcx> { - let r = ty::ReScope(self.tcx().region_maps.node_extent(ast::NodeId::from_u32(id))); + let r = ty::ReScope(self.tcx().node_extent(ast::NodeId::from_u32(id))); self.infcx.tcx.mk_imm_ref(self.infcx.tcx.mk_region(r), self.tcx().types.isize) } - pub fn re_free(&self, nid: ast::NodeId, id: u32) -> &'tcx ty::Region { + pub fn re_free(&self, nid: ast::NodeId, id: u32) -> ty::Region<'tcx> { self.infcx.tcx.mk_region(ty::ReFree(ty::FreeRegion { - scope: self.tcx().region_maps.item_extent(nid), + scope: Some(self.tcx().node_extent(nid)), bound_region: ty::BrAnon(id), })) } @@ -342,12 +343,12 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { } pub fn t_rptr_static(&self) -> Ty<'tcx> { - self.infcx.tcx.mk_imm_ref(self.infcx.tcx.mk_region(ty::ReStatic), + self.infcx.tcx.mk_imm_ref(self.infcx.tcx.types.re_static, self.tcx().types.isize) } pub fn t_rptr_empty(&self) -> Ty<'tcx> { - self.infcx.tcx.mk_imm_ref(self.infcx.tcx.mk_region(ty::ReEmpty), + self.infcx.tcx.mk_imm_ref(self.infcx.tcx.types.re_empty, self.tcx().types.isize) } @@ -375,7 +376,7 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { pub fn check_sub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) { match self.sub(t1, t2) { Ok(InferOk { obligations, .. }) => { - // FIXME(#32730) once obligations are being propagated, assert the right thing. + // None of these tests should require nested obligations: assert!(obligations.is_empty()); } Err(ref e) => { @@ -399,7 +400,7 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { pub fn check_lub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>, t_lub: Ty<'tcx>) { match self.lub(t1, t2) { Ok(InferOk { obligations, value: t }) => { - // FIXME(#32730) once obligations are being propagated, assert the right thing. + // None of these tests should require nested obligations: assert!(obligations.is_empty()); self.assert_eq(t, t_lub); @@ -414,7 +415,7 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { match self.glb(t1, t2) { Err(e) => panic!("unexpected error computing LUB: {:?}", e), Ok(InferOk { obligations, value: t }) => { - // FIXME(#32730) once obligations are being propagated, assert the right thing. + // None of these tests should require nested obligations: assert!(obligations.is_empty()); self.assert_eq(t, t_glb); @@ -429,7 +430,7 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { #[test] fn contravariant_region_ptr_ok() { - test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { + test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| { env.create_simple_region_hierarchy(); let t_rptr1 = env.t_rptr_scope(1); let t_rptr10 = env.t_rptr_scope(10); @@ -441,7 +442,7 @@ fn contravariant_region_ptr_ok() { #[test] fn contravariant_region_ptr_err() { - test_env(EMPTY_SOURCE_STR, errors(&["mismatched types"]), |env| { + test_env(EMPTY_SOURCE_STR, errors(&["mismatched types"]), |mut env| { env.create_simple_region_hierarchy(); let t_rptr1 = env.t_rptr_scope(1); let t_rptr10 = env.t_rptr_scope(10); @@ -461,7 +462,7 @@ fn sub_free_bound_false() { //! //! does NOT hold. - test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { + test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| { env.create_simple_region_hierarchy(); let t_rptr_free1 = env.t_rptr_free(1, 1); let t_rptr_bound1 = env.t_rptr_late_bound(1); @@ -478,7 +479,7 @@ fn sub_bound_free_true() { //! //! DOES hold. - test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { + test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| { env.create_simple_region_hierarchy(); let t_rptr_bound1 = env.t_rptr_late_bound(1); let t_rptr_free1 = env.t_rptr_free(1, 1); @@ -513,7 +514,7 @@ fn lub_free_bound_infer() { //! that it yields `fn(&'x isize)` for some free `'x`, //! anyhow. - test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { + test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| { env.create_simple_region_hierarchy(); let t_infer1 = env.infcx.next_ty_var(TypeVariableOrigin::MiscVariable(DUMMY_SP)); let t_rptr_bound1 = env.t_rptr_late_bound(1); @@ -537,7 +538,7 @@ fn lub_bound_bound() { #[test] fn lub_bound_free() { - test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { + test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| { env.create_simple_region_hierarchy(); let t_rptr_bound1 = env.t_rptr_late_bound(1); let t_rptr_free1 = env.t_rptr_free(1, 1); @@ -571,7 +572,7 @@ fn lub_bound_bound_inverse_order() { #[test] fn lub_free_free() { - test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { + test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| { env.create_simple_region_hierarchy(); let t_rptr_free1 = env.t_rptr_free(1, 1); let t_rptr_free2 = env.t_rptr_free(1, 2); @@ -584,7 +585,7 @@ fn lub_free_free() { #[test] fn lub_returning_scope() { - test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { + test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| { env.create_simple_region_hierarchy(); let t_rptr_scope10 = env.t_rptr_scope(10); let t_rptr_scope11 = env.t_rptr_scope(11); @@ -597,7 +598,7 @@ fn lub_returning_scope() { #[test] fn glb_free_free_with_common_scope() { - test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { + test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| { env.create_simple_region_hierarchy(); let t_rptr_free1 = env.t_rptr_free(1, 1); let t_rptr_free2 = env.t_rptr_free(1, 2); @@ -621,7 +622,7 @@ fn glb_bound_bound() { #[test] fn glb_bound_free() { - test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { + test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| { env.create_simple_region_hierarchy(); let t_rptr_bound1 = env.t_rptr_late_bound(1); let t_rptr_free1 = env.t_rptr_free(1, 1); @@ -743,7 +744,7 @@ fn subst_ty_renumber_some_bounds() { #[test] fn escaping() { - test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { + test_env(EMPTY_SOURCE_STR, errors(&[]), |mut env| { // Situation: // Theta = [A -> &'a foo] env.create_simple_region_hierarchy(); diff --git a/src/librustc_errors/diagnostic.rs b/src/librustc_errors/diagnostic.rs index 1b77ead92deb..38fa35ecb126 100644 --- a/src/librustc_errors/diagnostic.rs +++ b/src/librustc_errors/diagnostic.rs @@ -11,7 +11,6 @@ use CodeSuggestion; use Level; use RenderSpan; -use RenderSpan::Suggestion; use std::fmt; use syntax_pos::{MultiSpan, Span}; use snippet::Style; @@ -24,6 +23,7 @@ pub struct Diagnostic { pub code: Option, pub span: MultiSpan, pub children: Vec, + pub suggestion: Option, } /// For example a note attached to an error. @@ -35,6 +35,46 @@ pub struct SubDiagnostic { pub render_span: Option, } +#[derive(PartialEq, Eq)] +pub struct DiagnosticStyledString(pub Vec); + +impl DiagnosticStyledString { + pub fn new() -> DiagnosticStyledString { + DiagnosticStyledString(vec![]) + } + pub fn push_normal>(&mut self, t: S) { + self.0.push(StringPart::Normal(t.into())); + } + pub fn push_highlighted>(&mut self, t: S) { + self.0.push(StringPart::Highlighted(t.into())); + } + pub fn normal>(t: S) -> DiagnosticStyledString { + DiagnosticStyledString(vec![StringPart::Normal(t.into())]) + } + + pub fn highlighted>(t: S) -> DiagnosticStyledString { + DiagnosticStyledString(vec![StringPart::Highlighted(t.into())]) + } + + pub fn content(&self) -> String { + self.0.iter().map(|x| x.content()).collect::() + } +} + +#[derive(PartialEq, Eq)] +pub enum StringPart { + Normal(String), + Highlighted(String), +} + +impl StringPart { + pub fn content(&self) -> String { + match self { + &StringPart::Normal(ref s) | & StringPart::Highlighted(ref s) => s.to_owned() + } + } +} + impl Diagnostic { pub fn new(level: Level, message: &str) -> Self { Diagnostic::new_with_code(level, None, message) @@ -47,6 +87,7 @@ impl Diagnostic { code: code, span: MultiSpan::new(), children: vec![], + suggestion: None, } } @@ -81,8 +122,8 @@ impl Diagnostic { pub fn note_expected_found(&mut self, label: &fmt::Display, - expected: &fmt::Display, - found: &fmt::Display) + expected: DiagnosticStyledString, + found: DiagnosticStyledString) -> &mut Self { self.note_expected_found_extra(label, expected, found, &"", &"") @@ -90,21 +131,29 @@ impl Diagnostic { pub fn note_expected_found_extra(&mut self, label: &fmt::Display, - expected: &fmt::Display, - found: &fmt::Display, + expected: DiagnosticStyledString, + found: DiagnosticStyledString, expected_extra: &fmt::Display, found_extra: &fmt::Display) -> &mut Self { + let mut msg: Vec<_> = vec![(format!("expected {} `", label), Style::NoStyle)]; + msg.extend(expected.0.iter() + .map(|x| match *x { + StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle), + StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight), + })); + msg.push((format!("`{}\n", expected_extra), Style::NoStyle)); + msg.push((format!(" found {} `", label), Style::NoStyle)); + msg.extend(found.0.iter() + .map(|x| match *x { + StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle), + StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight), + })); + msg.push((format!("`{}", found_extra), Style::NoStyle)); + // For now, just attach these as notes - self.highlighted_note(vec![ - (format!("expected {} `", label), Style::NoStyle), - (format!("{}", expected), Style::Highlight), - (format!("`{}\n", expected_extra), Style::NoStyle), - (format!(" found {} `", label), Style::NoStyle), - (format!("{}", found), Style::Highlight), - (format!("`{}", found_extra), Style::NoStyle), - ]); + self.highlighted_note(msg); self } @@ -154,19 +203,14 @@ impl Diagnostic { /// Prints out a message with a suggested edit of the code. /// - /// See `diagnostic::RenderSpan::Suggestion` for more information. - pub fn span_suggestion>(&mut self, - sp: S, - msg: &str, - suggestion: String) - -> &mut Self { - self.sub(Level::Help, - msg, - MultiSpan::new(), - Some(Suggestion(CodeSuggestion { - msp: sp.into(), - substitutes: vec![suggestion], - }))); + /// See `diagnostic::CodeSuggestion` for more information. + pub fn span_suggestion(&mut self, sp: Span, msg: &str, suggestion: String) -> &mut Self { + assert!(self.suggestion.is_none()); + self.suggestion = Some(CodeSuggestion { + msp: sp.into(), + substitutes: vec![suggestion], + msg: msg.to_owned(), + }); self } diff --git a/src/librustc_errors/diagnostic_builder.rs b/src/librustc_errors/diagnostic_builder.rs index 7dfea6b8951b..9dfd47b8464d 100644 --- a/src/librustc_errors/diagnostic_builder.rs +++ b/src/librustc_errors/diagnostic_builder.rs @@ -9,6 +9,8 @@ // except according to those terms. use Diagnostic; +use DiagnosticStyledString; + use Level; use Handler; use std::fmt::{self, Debug}; @@ -115,14 +117,14 @@ impl<'a> DiagnosticBuilder<'a> { forward!(pub fn note_expected_found(&mut self, label: &fmt::Display, - expected: &fmt::Display, - found: &fmt::Display) + expected: DiagnosticStyledString, + found: DiagnosticStyledString) -> &mut Self); forward!(pub fn note_expected_found_extra(&mut self, label: &fmt::Display, - expected: &fmt::Display, - found: &fmt::Display, + expected: DiagnosticStyledString, + found: DiagnosticStyledString, expected_extra: &fmt::Display, found_extra: &fmt::Display) -> &mut Self); @@ -139,11 +141,11 @@ impl<'a> DiagnosticBuilder<'a> { sp: S, msg: &str) -> &mut Self); - forward!(pub fn span_suggestion>(&mut self, - sp: S, - msg: &str, - suggestion: String) - -> &mut Self); + forward!(pub fn span_suggestion(&mut self, + sp: Span, + msg: &str, + suggestion: String) + -> &mut Self); forward!(pub fn set_span>(&mut self, sp: S) -> &mut Self); forward!(pub fn code(&mut self, s: String) -> &mut Self); diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index 431edb3c9bc4..1a38018e1b37 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -10,7 +10,7 @@ use self::Destination::*; -use syntax_pos::{COMMAND_LINE_SP, DUMMY_SP, FileMap, Span, MultiSpan, CharPos}; +use syntax_pos::{DUMMY_SP, FileMap, Span, MultiSpan, CharPos}; use {Level, CodeSuggestion, DiagnosticBuilder, SubDiagnostic, CodeMapper}; use RenderSpan::*; @@ -21,6 +21,8 @@ use std::io::prelude::*; use std::io; use std::rc::Rc; use term; +use std::collections::HashMap; +use std::cmp::min; /// Emitter trait for emitting errors. pub trait Emitter { @@ -32,6 +34,27 @@ impl Emitter for EmitterWriter { fn emit(&mut self, db: &DiagnosticBuilder) { let mut primary_span = db.span.clone(); let mut children = db.children.clone(); + + if let Some(sugg) = db.suggestion.clone() { + assert_eq!(sugg.msp.primary_spans().len(), sugg.substitutes.len()); + // don't display multispans as labels + if sugg.substitutes.len() == 1 && + // don't display long messages as labels + sugg.msg.split_whitespace().count() < 10 && + // don't display multiline suggestions as labels + sugg.substitutes[0].find('\n').is_none() { + let msg = format!("help: {} `{}`", sugg.msg, sugg.substitutes[0]); + primary_span.push_span_label(sugg.msp.primary_spans()[0], msg); + } else { + children.push(SubDiagnostic { + level: Level::Help, + message: Vec::new(), + span: MultiSpan::new(), + render_span: Some(Suggestion(sugg)), + }); + } + } + self.fix_multispans_in_std_macros(&mut primary_span, &mut children); self.emit_messages_default(&db.level, &db.styled_message(), @@ -151,20 +174,11 @@ impl EmitterWriter { if let Some(ref cm) = self.cm { for span_label in msp.span_labels() { - if span_label.span == DUMMY_SP || span_label.span == COMMAND_LINE_SP { + if span_label.span == DUMMY_SP { continue; } let lo = cm.lookup_char_pos(span_label.span.lo); let mut hi = cm.lookup_char_pos(span_label.span.hi); - let mut is_minimized = false; - - // If the span is long multi-line, simplify down to the span of one character - let max_multiline_span_length = 8; - if lo.line != hi.line && (hi.line - lo.line) > max_multiline_span_length { - hi.line = lo.line; - hi.col = CharPos(lo.col.0 + 1); - is_minimized = true; - } // Watch out for "empty spans". If we get a span like 6..6, we // want to just display a `^` at 6, so convert that to @@ -175,16 +189,7 @@ impl EmitterWriter { hi.col = CharPos(lo.col.0 + 1); } - let mut ann = Annotation { - start_col: lo.col.0, - end_col: hi.col.0, - is_primary: span_label.is_primary, - label: span_label.label.clone(), - annotation_type: AnnotationType::Singleline, - }; - if is_minimized { - ann.annotation_type = AnnotationType::Minimized; - } else if lo.line != hi.line { + let ann_type = if lo.line != hi.line { let ml = MultilineAnnotation { depth: 1, line_start: lo.line, @@ -194,8 +199,17 @@ impl EmitterWriter { is_primary: span_label.is_primary, label: span_label.label.clone(), }; - ann.annotation_type = AnnotationType::Multiline(ml.clone()); - multiline_annotations.push((lo.file.clone(), ml)); + multiline_annotations.push((lo.file.clone(), ml.clone())); + AnnotationType::Multiline(ml) + } else { + AnnotationType::Singleline + }; + let ann = Annotation { + start_col: lo.col.0, + end_col: hi.col.0, + is_primary: span_label.is_primary, + label: span_label.label.clone(), + annotation_type: ann_type, }; if !ann.is_multiline() { @@ -233,9 +247,15 @@ impl EmitterWriter { max_depth = ann.depth; } add_annotation_to_file(&mut output, file.clone(), ann.line_start, ann.as_start()); - for line in ann.line_start + 1..ann.line_end { + let middle = min(ann.line_start + 4, ann.line_end); + for line in ann.line_start + 1..middle { add_annotation_to_file(&mut output, file.clone(), line, ann.as_line()); } + if middle < ann.line_end - 1 { + for line in ann.line_end - 1..ann.line_end { + add_annotation_to_file(&mut output, file.clone(), line, ann.as_line()); + } + } add_annotation_to_file(&mut output, file, ann.line_end, ann.as_end()); } for file_vec in output.iter_mut() { @@ -249,16 +269,11 @@ impl EmitterWriter { file: Rc, line: &Line, width_offset: usize, - multiline_depth: usize) { + code_offset: usize) -> Vec<(usize, Style)> { let source_string = file.get_line(line.line_index - 1) .unwrap_or(""); let line_offset = buffer.num_lines(); - let code_offset = if multiline_depth == 0 { - width_offset - } else { - width_offset + multiline_depth + 1 - }; // First create the source line we will highlight. buffer.puts(line_offset, code_offset, &source_string, Style::Quotation); @@ -269,6 +284,41 @@ impl EmitterWriter { draw_col_separator(buffer, line_offset, width_offset - 2); + // Special case when there's only one annotation involved, it is the start of a multiline + // span and there's no text at the beginning of the code line. Instead of doing the whole + // graph: + // + // 2 | fn foo() { + // | _^ + // 3 | | + // 4 | | } + // | |_^ test + // + // we simplify the output to: + // + // 2 | / fn foo() { + // 3 | | + // 4 | | } + // | |_^ test + if line.annotations.len() == 1 { + if let Some(ref ann) = line.annotations.get(0) { + if let AnnotationType::MultilineStart(depth) = ann.annotation_type { + if source_string[0..ann.start_col].trim() == "" { + let style = if ann.is_primary { + Style::UnderlinePrimary + } else { + Style::UnderlineSecondary + }; + buffer.putc(line_offset, + width_offset + depth - 1, + '/', + style); + return vec![(depth, style)]; + } + } + } + } + // We want to display like this: // // vec.push(vec.pop().unwrap()); @@ -286,7 +336,7 @@ impl EmitterWriter { // previous borrow of `vec` occurs here // // For this reason, we group the lines into "highlight lines" - // and "annotations lines", where the highlight lines have the `~`. + // and "annotations lines", where the highlight lines have the `^`. // Sort the annotations by (start, end col) let mut annotations = line.annotations.clone(); @@ -361,10 +411,8 @@ impl EmitterWriter { for (i, annotation) in annotations.iter().enumerate() { for (j, next) in annotations.iter().enumerate() { if overlaps(next, annotation, 0) // This label overlaps with another one and both - && !annotation.is_line() // take space (they have text and are not - && !next.is_line() // multiline lines). - && annotation.has_label() - && j > i + && annotation.has_label() // take space (they have text and are not + && j > i // multiline lines). && p == 0 // We're currently on the first line, move the label one line down { // This annotation needs a new line in the output. @@ -380,7 +428,7 @@ impl EmitterWriter { } else { 0 }; - if overlaps(next, annotation, l) // Do not allow two labels to be in the same + if (overlaps(next, annotation, l) // Do not allow two labels to be in the same // line if they overlap including padding, to // avoid situations like: // @@ -389,11 +437,18 @@ impl EmitterWriter { // | | // fn_spanx_span // - && !annotation.is_line() // Do not add a new line if this annotation - && !next.is_line() // or the next are vertical line placeholders. && annotation.has_label() // Both labels must have some text, otherwise - && next.has_label() // they are not overlapping. + && next.has_label()) // they are not overlapping. + // Do not add a new line if this annotation + // or the next are vertical line placeholders. + || (annotation.takes_space() // If either this or the next annotation is + && next.has_label()) // multiline start/end, move it to a new line + || (annotation.has_label() // so as not to overlap the orizontal lines. + && next.takes_space()) + || (annotation.takes_space() + && next.takes_space()) { + // This annotation needs a new line in the output. p += 1; break; } @@ -403,6 +458,7 @@ impl EmitterWriter { line_len = p; } } + if line_len != 0 { line_len += 1; } @@ -410,25 +466,9 @@ impl EmitterWriter { // If there are no annotations or the only annotations on this line are // MultilineLine, then there's only code being shown, stop processing. if line.annotations.is_empty() || line.annotations.iter() - .filter(|a| { - // Set the multiline annotation vertical lines to the left of - // the code in this line. - if let AnnotationType::MultilineLine(depth) = a.annotation_type { - buffer.putc(line_offset, - width_offset + depth - 1, - '|', - if a.is_primary { - Style::UnderlinePrimary - } else { - Style::UnderlineSecondary - }); - false - } else { - true - } - }).collect::>().len() == 0 + .filter(|a| !a.is_line()).collect::>().len() == 0 { - return; + return vec![]; } // Write the colunmn separator. @@ -483,8 +523,7 @@ impl EmitterWriter { } } - // Write the vertical lines for multiline spans and for labels that are - // on a different line as the underline. + // Write the vertical lines for labels that are on a different line as the underline. // // After this we will have: // @@ -492,7 +531,7 @@ impl EmitterWriter { // | __________ // | | | // | | - // 3 | | + // 3 | // 4 | | } // | |_ for &(pos, annotation) in &annotations_position { @@ -503,7 +542,7 @@ impl EmitterWriter { }; let pos = pos + 1; - if pos > 1 && annotation.has_label() { + if pos > 1 && (annotation.has_label() || annotation.takes_space()) { for p in line_offset + 1..line_offset + pos + 1 { buffer.putc(p, code_offset + annotation.start_col, @@ -528,16 +567,6 @@ impl EmitterWriter { style); } } - AnnotationType::MultilineLine(depth) => { - // the first line will have already be filled when we checked - // wether there were any annotations for this line. - for p in line_offset + 1..line_offset + line_len + 2 { - buffer.putc(p, - width_offset + depth - 1, - '|', - style); - } - } _ => (), } } @@ -547,12 +576,12 @@ impl EmitterWriter { // After this we will have: // // 2 | fn foo() { - // | __________ starting here... - // | | | - // | | something about `foo` - // 3 | | - // 4 | | } - // | |_ ...ending here: test + // | __________ + // | | + // | something about `foo` + // 3 | + // 4 | } + // | _ test for &(pos, annotation) in &annotations_position { let style = if annotation.is_primary { Style::LabelPrimary @@ -590,12 +619,12 @@ impl EmitterWriter { // After this we will have: // // 2 | fn foo() { - // | ____-_____^ starting here... - // | | | - // | | something about `foo` - // 3 | | - // 4 | | } - // | |_^ ...ending here: test + // | ____-_____^ + // | | + // | something about `foo` + // 3 | + // 4 | } + // | _^ test for &(_, annotation) in &annotations_position { let (underline, style) = if annotation.is_primary { ('^', Style::UnderlinePrimary) @@ -609,13 +638,27 @@ impl EmitterWriter { style); } } + annotations_position.iter().filter_map(|&(_, annotation)| { + match annotation.annotation_type { + AnnotationType::MultilineStart(p) | AnnotationType::MultilineEnd(p) => { + let style = if annotation.is_primary { + Style::LabelPrimary + } else { + Style::LabelSecondary + }; + Some((p, style)) + }, + _ => None + } + + }).collect::>() } fn get_multispan_max_line_num(&mut self, msp: &MultiSpan) -> usize { let mut max = 0; if let Some(ref cm) = self.cm { for primary_span in msp.primary_spans() { - if primary_span != &DUMMY_SP && primary_span != &COMMAND_LINE_SP { + if primary_span != &DUMMY_SP { let hi = cm.lookup_char_pos(primary_span.hi); if hi.line > max { max = hi.line; @@ -623,7 +666,7 @@ impl EmitterWriter { } } for span_label in msp.span_labels() { - if span_label.span != DUMMY_SP && span_label.span != COMMAND_LINE_SP { + if span_label.span != DUMMY_SP { let hi = cm.lookup_char_pos(span_label.span.hi); if hi.line > max { max = hi.line; @@ -659,20 +702,20 @@ impl EmitterWriter { // First, find all the spans in <*macros> and point instead at their use site for sp in span.primary_spans() { - if (*sp == COMMAND_LINE_SP) || (*sp == DUMMY_SP) { + if *sp == DUMMY_SP { continue; } if cm.span_to_filename(sp.clone()).contains("macros>") { - let v = cm.macro_backtrace(sp.clone()); + let v = sp.macro_backtrace(); if let Some(use_site) = v.last() { before_after.push((sp.clone(), use_site.call_site.clone())); } } - for trace in cm.macro_backtrace(sp.clone()).iter().rev() { + for trace in sp.macro_backtrace().iter().rev() { // Only show macro locations that are local // and display them like a span_note if let Some(def_site) = trace.def_site_span { - if (def_site == COMMAND_LINE_SP) || (def_site == DUMMY_SP) { + if def_site == DUMMY_SP { continue; } // Check to make sure we're not in any <*macros> @@ -689,11 +732,11 @@ impl EmitterWriter { span.push_span_label(label_span, label_text); } for sp_label in span.span_labels() { - if (sp_label.span == COMMAND_LINE_SP) || (sp_label.span == DUMMY_SP) { + if sp_label.span == DUMMY_SP { continue; } if cm.span_to_filename(sp_label.span.clone()).contains("macros>") { - let v = cm.macro_backtrace(sp_label.span.clone()); + let v = sp_label.span.macro_backtrace(); if let Some(use_site) = v.last() { before_after.push((sp_label.span.clone(), use_site.call_site.clone())); } @@ -734,7 +777,7 @@ impl EmitterWriter { /// displayed, keeping the provided highlighting. fn msg_to_buffer(&self, buffer: &mut StyledBuffer, - msg: &Vec<(String, Style)>, + msg: &[(String, Style)], padding: usize, label: &str, override_style: Option