diff --git a/.travis.yml b/.travis.yml index 40fecb3ee5ea..b95196da356c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -36,9 +36,10 @@ matrix: - env: IMAGE=dist-x86_64-linux DEPLOY=1 ALLOW_TRY=1 - env: IMAGE=dist-x86_64-musl DEPLOY=1 - env: IMAGE=dist-x86_64-netbsd DEPLOY=1 - - env: IMAGE=emscripten + - env: IMAGE=asmjs - env: IMAGE=i686-gnu - env: IMAGE=i686-gnu-nopt + # - env: IMAGE=wasm32 issue 42646 - env: IMAGE=x86_64-gnu - env: IMAGE=x86_64-gnu-full-bootstrap - env: IMAGE=x86_64-gnu-aux @@ -54,7 +55,7 @@ matrix: # version that we're using, 8.2, cannot compile LLVM for OSX 10.7. - env: > RUST_CHECK_TARGET=check - RUST_CONFIGURE_ARGS="--build=x86_64-apple-darwin --enable-sanitizers" + RUST_CONFIGURE_ARGS="--build=x86_64-apple-darwin --enable-sanitizers --enable-profiler" SRC=. RUSTC_RETRY_LINKER_ON_SEGFAULT=1 SCCACHE_ERROR_LOG=/tmp/sccache.log @@ -87,7 +88,7 @@ matrix: # 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" + RUST_CONFIGURE_ARGS="--build=i686-apple-darwin --enable-extended --enable-profiler" SRC=. DEPLOY=1 RUSTC_RETRY_LINKER_ON_SEGFAULT=1 @@ -101,7 +102,7 @@ matrix: - *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 --enable-sanitizers" + RUST_CONFIGURE_ARGS="--target=aarch64-apple-ios,armv7-apple-ios,armv7s-apple-ios,i386-apple-ios,x86_64-apple-ios --enable-extended --enable-sanitizers --enable-profiler" SRC=. DEPLOY=1 RUSTC_RETRY_LINKER_ON_SEGFAULT=1 diff --git a/README.md b/README.md index dbb5bf9ce38d..0b209fd3e949 100644 --- a/README.md +++ b/README.md @@ -7,9 +7,9 @@ standard library, and documentation. ## Quick Start -Read ["Installing Rust"] from [The Book]. +Read ["Installation"] from [The Book]. -["Installing Rust"]: https://doc.rust-lang.org/book/getting-started.html#installing-rust +["Installation"]: https://doc.rust-lang.org/book/second-edition/ch01-01-installation.html [The Book]: https://doc.rust-lang.org/book/index.html ## Building from Source diff --git a/appveyor.yml b/appveyor.yml index 96de1d90f25e..4711f34f830e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -7,7 +7,7 @@ environment: matrix: # 32/64 bit MSVC tests - MSYS_BITS: 64 - RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc + RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-profiler SCRIPT: python x.py test - MSYS_BITS: 32 RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc --target=i586-pc-windows-msvc @@ -48,12 +48,14 @@ environment: - RUST_CONFIGURE_ARGS: > --build=x86_64-pc-windows-msvc --enable-extended + --enable-profiler SCRIPT: python x.py dist DEPLOY: 1 - RUST_CONFIGURE_ARGS: > --build=i686-pc-windows-msvc --target=i586-pc-windows-msvc --enable-extended + --enable-profiler SCRIPT: python x.py dist DEPLOY: 1 - MSYS_BITS: 32 diff --git a/configure b/configure index af59d5b0bb88..2b493ee91b50 100755 --- a/configure +++ b/configure @@ -452,6 +452,7 @@ opt vendor 0 "enable usage of vendored Rust crates" opt sanitizers 0 "build the sanitizer runtimes (asan, lsan, msan, tsan)" opt dist-src 1 "when building tarballs enables building a source tarball" opt cargo-openssl-static 0 "static openssl in cargo" +opt profiler 0 "build the profiler runtime" # Optimization and debugging options. These may be overridden by the release channel, etc. opt_nosave optimize 1 "build optimized rust code" diff --git a/src/Cargo.lock b/src/Cargo.lock index cc2da1a02dc9..f99ffc6472d2 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -36,6 +36,7 @@ name = "alloc" version = "0.0.0" dependencies = [ "core 0.0.0", + "std_unicode 0.0.0", ] [[package]] @@ -44,7 +45,7 @@ version = "0.0.0" dependencies = [ "build_helper 0.1.0", "core 0.0.0", - "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.0.0", ] @@ -66,26 +67,36 @@ name = "arena" version = "0.0.0" [[package]] -name = "backtrace" -version = "0.3.0" +name = "atty" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "backtrace" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "backtrace-sys 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-demangle 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "backtrace-sys" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -103,17 +114,22 @@ name = "bitflags" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "bitflags" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "bootstrap" version = "0.0.0" dependencies = [ "build_helper 0.1.0", - "cmake 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", + "cmake 0.1.24 (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.50 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.51 (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.22 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -140,49 +156,53 @@ dependencies = [ [[package]] name = "cargo" -version = "0.20.0" -source = "git+https://github.com/rust-lang/cargo#2b32084293d8da63b48de56363a0f2e986ec3367" -replace = "cargo 0.20.0" +version = "0.21.0" +source = "git+https://github.com/rust-lang/cargo#50b1c24d146fa072db71f12005deed319ac5ba9a" +replace = "cargo 0.21.0" [[package]] name = "cargo" -version = "0.20.0" +version = "0.21.0" dependencies = [ "advapi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "bufstream 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "cargotest 0.1.0", - "crates-io 0.9.0", + "crates-io 0.10.0", "crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", "curl 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "docopt 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "docopt 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "flate2 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)", - "fs2 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "git2 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "fs2 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "git2 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "git2-curl 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "hamcrest 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jobserver 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)", - "libgit2-sys 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)", + "libgit2-sys 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl 0.9.12 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl 0.9.14 (registry+https://github.com/rust-lang/crates.io-index)", "psapi-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", + "scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "serde_ignored 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "shell-escape 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "tar 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "term 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "termcolor 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -191,21 +211,20 @@ name = "cargotest" version = "0.1.0" dependencies = [ "bufstream 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "cargo 0.20.0", + "cargo 0.21.0", "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "flate2 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)", - "git2 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "git2 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "hamcrest 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.22 (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.24 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "tar 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "term 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -215,31 +234,31 @@ version = "0.1.0" [[package]] name = "cfg-if" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "clap" -version = "2.19.3" +version = "2.24.2" 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)", - "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)", - "strsim 0.5.2 (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 0.1.3 (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.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.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-segmentation 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "vec_map 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "yaml-rust 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cmake" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -248,7 +267,6 @@ version = "0.0.0" dependencies = [ "alloc 0.0.0", "core 0.0.0", - "std_unicode 0.0.0", ] [[package]] @@ -257,7 +275,7 @@ version = "0.0.0" dependencies = [ "build_helper 0.1.0", "core 0.0.0", - "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -265,9 +283,9 @@ name = "compiletest" version = "0.0.0" dependencies = [ "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)", + "env_logger 0.4.3 (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)", + "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -277,13 +295,14 @@ version = "0.0.0" [[package]] name = "crates-io" -version = "0.9.0" +version = "0.10.0" dependencies = [ "curl 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -296,23 +315,24 @@ name = "curl" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "curl-sys 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)", + "curl-sys 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)", "openssl-probe 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.12 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.14 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "curl-sys" -version = "0.3.11" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)", - "libz-sys 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.12 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)", + "libz-sys 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.14 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -341,12 +361,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "docopt" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -355,17 +376,12 @@ name = "dtoa" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "either" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "enum_primitive" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -373,17 +389,17 @@ name = "env_logger" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "env_logger" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -391,7 +407,7 @@ name = "error-chain" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -403,7 +419,7 @@ name = "filetime" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -411,7 +427,7 @@ name = "flate" version = "0.0.0" dependencies = [ "build_helper 0.1.0", - "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -419,7 +435,7 @@ name = "flate2" version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)", "miniz-sys 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -434,28 +450,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "fs2" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "gcc" -version = "0.3.50" +version = "0.3.51" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "gdi32-sys" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "getopts" version = "0.0.0" @@ -467,15 +474,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "git2" -version = "0.6.5" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)", - "libgit2-sys 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)", + "libgit2-sys 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", "openssl-probe 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.12 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.14 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -484,9 +491,9 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "curl 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "git2 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "git2 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -503,7 +510,7 @@ name = "hamcrest" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "num 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -513,29 +520,34 @@ version = "0.25.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.8 (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.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "hex" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "idna" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-bidi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-normalization 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-bidi 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "installer" version = "0.0.0" dependencies = [ - "clap 2.19.3 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.24.2 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "flate2 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -546,19 +558,20 @@ dependencies = [ "xz2 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "itertools" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "either 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "itoa" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "jobserver" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "kernel32-sys" version = "0.2.2" @@ -574,10 +587,10 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "url_serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -595,21 +608,21 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.22" +version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libgit2-sys" -version = "0.6.11" +version = "0.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cmake 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", - "curl-sys 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)", - "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)", + "cmake 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", + "curl-sys 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)", "libssh2-sys 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libz-sys 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.12 (registry+https://github.com/rust-lang/crates.io-index)", + "libz-sys 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.14 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -618,21 +631,22 @@ name = "libssh2-sys" version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cmake 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)", - "libz-sys 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.12 (registry+https://github.com/rust-lang/crates.io-index)", + "cmake 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)", + "libz-sys 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.14 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "libz-sys" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -641,22 +655,22 @@ version = "0.1.0" [[package]] name = "log" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "lzma-sys" -version = "0.1.4" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "matches" -version = "0.1.4" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -664,13 +678,13 @@ name = "mdbook" version = "0.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "clap 2.19.3 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.24.2 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "handlebars 0.25.3 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.8 (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)", - "regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -681,7 +695,7 @@ name = "memchr" version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -689,7 +703,7 @@ name = "memchr" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -697,8 +711,8 @@ name = "miniz-sys" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -712,53 +726,48 @@ dependencies = [ "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "multimap" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "net2" version = "0.2.29" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num" -version = "0.1.37" +version = "0.1.39" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-bigint 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", - "num-complex 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "num-bigint 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", + "num-complex 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", "num-integer 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", "num-iter 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", - "num-rational 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "num-rational 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-bigint" -version = "0.1.37" +version = "0.1.39" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "num-integer 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-complex" -version = "0.1.37" +version = "0.1.38" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -767,7 +776,7 @@ name = "num-integer" version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -776,31 +785,31 @@ version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "num-integer 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-rational" -version = "0.1.36" +version = "0.1.38" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-bigint 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "num-bigint 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", "num-integer 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-traits" -version = "0.1.37" +version = "0.1.39" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "num_cpus" -version = "1.4.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -810,14 +819,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "openssl" -version = "0.9.12" +version = "0.9.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)", + "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", "foreign-types 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.12 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.14 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -827,14 +836,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "openssl-sys" -version = "0.9.12" +version = "0.9.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)", - "gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "user32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -863,6 +870,11 @@ dependencies = [ "unwind 0.0.0", ] +[[package]] +name = "percent-encoding" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "pest" version = "0.3.3" @@ -889,6 +901,14 @@ dependencies = [ "syntax_pos 0.0.0", ] +[[package]] +name = "profiler_builtins" +version = "0.0.0" +dependencies = [ + "core 0.0.0", + "gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "psapi-sys" version = "0.1.0" @@ -932,16 +952,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "racer" -version = "2.0.6" +version = "2.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "clap 2.19.3 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.24.2 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "syntex_errors 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)", "syntex_syntax 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "typed-arena 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "typed-arena 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -956,7 +977,7 @@ name = "rand" version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -973,12 +994,12 @@ dependencies = [ [[package]] name = "regex" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "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)", + "regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "thread_local 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -990,7 +1011,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "regex-syntax" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1005,40 +1026,49 @@ version = "0.1.0" name = "rls" version = "0.1.0" dependencies = [ - "cargo 0.20.0 (git+https://github.com/rust-lang/cargo)", + "cargo 0.21.0 (git+https://github.com/rust-lang/cargo)", "derive-new 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "languageserver-types 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "racer 2.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-analysis 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-data 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "racer 2.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-analysis 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-data 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-vfs 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustfmt 0.8.4 (git+https://github.com/rust-lang-nursery/rustfmt)", - "serde 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-vfs 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rustfmt-nightly 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "url_serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rls-analysis" -version = "0.2.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "derive-new 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-data 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-data 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rls-data" -version = "0.3.1" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rls-data" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1051,16 +1081,16 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rls-vfs" -version = "0.3.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "racer 2.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "racer 2.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1068,7 +1098,7 @@ dependencies = [ name = "rustbook" version = "0.1.0" dependencies = [ - "clap 2.19.3 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.24.2 (registry+https://github.com/rust-lang/crates.io-index)", "mdbook 0.0.21 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1079,7 +1109,7 @@ dependencies = [ "arena 0.0.0", "fmt_macros 0.0.0", "graphviz 0.0.0", - "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_back 0.0.0", "rustc_bitflags 0.0.0", @@ -1116,7 +1146,7 @@ version = "0.0.0" dependencies = [ "alloc_system 0.0.0", "build_helper 0.1.0", - "cmake 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", + "cmake 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", ] @@ -1124,7 +1154,7 @@ dependencies = [ name = "rustc_back" version = "0.0.0" dependencies = [ - "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "serialize 0.0.0", "syntax 0.0.0", ] @@ -1138,7 +1168,7 @@ name = "rustc_borrowck" version = "0.0.0" dependencies = [ "graphviz 0.0.0", - "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", @@ -1152,7 +1182,7 @@ name = "rustc_const_eval" version = "0.0.0" dependencies = [ "arena 0.0.0", - "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_back 0.0.0", "rustc_const_math 0.0.0", @@ -1174,7 +1204,7 @@ dependencies = [ name = "rustc_data_structures" version = "0.0.0" dependencies = [ - "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "serialize 0.0.0", ] @@ -1183,9 +1213,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)", + "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "graphviz 0.0.0", - "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "proc_macro_plugin 0.0.0", "rustc 0.0.0", "rustc_back 0.0.0", @@ -1223,7 +1253,7 @@ name = "rustc_incremental" version = "0.0.0" dependencies = [ "graphviz 0.0.0", - "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_data_structures 0.0.0", "serialize 0.0.0", @@ -1235,7 +1265,7 @@ dependencies = [ name = "rustc_lint" version = "0.0.0" dependencies = [ - "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_back 0.0.0", "rustc_const_eval 0.0.0", @@ -1248,7 +1278,7 @@ name = "rustc_llvm" version = "0.0.0" dependencies = [ "build_helper 0.1.0", - "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_bitflags 0.0.0", ] @@ -1258,7 +1288,7 @@ version = "0.0.0" dependencies = [ "alloc_system 0.0.0", "build_helper 0.1.0", - "cmake 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", + "cmake 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", ] @@ -1267,7 +1297,7 @@ name = "rustc_metadata" version = "0.0.0" dependencies = [ "flate 0.0.0", - "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "proc_macro 0.0.0", "rustc 0.0.0", @@ -1286,7 +1316,7 @@ name = "rustc_mir" version = "0.0.0" dependencies = [ "graphviz 0.0.0", - "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_bitflags 0.0.0", "rustc_const_eval 0.0.0", @@ -1302,7 +1332,7 @@ version = "0.0.0" dependencies = [ "alloc_system 0.0.0", "build_helper 0.1.0", - "cmake 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", + "cmake 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", ] @@ -1310,7 +1340,7 @@ dependencies = [ name = "rustc_passes" version = "0.0.0" dependencies = [ - "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.8 (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", @@ -1349,7 +1379,7 @@ name = "rustc_resolve" version = "0.0.0" dependencies = [ "arena 0.0.0", - "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_errors 0.0.0", "syntax 0.0.0", @@ -1360,8 +1390,8 @@ dependencies = [ name = "rustc_save_analysis" version = "0.0.0" dependencies = [ - "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-data 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-data 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1375,8 +1405,8 @@ name = "rustc_trans" version = "0.0.0" dependencies = [ "flate 0.0.0", - "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_back 0.0.0", @@ -1398,7 +1428,7 @@ version = "0.0.0" dependencies = [ "alloc_system 0.0.0", "build_helper 0.1.0", - "cmake 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", + "cmake 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", ] @@ -1408,7 +1438,7 @@ version = "0.0.0" dependencies = [ "arena 0.0.0", "fmt_macros 0.0.0", - "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_back 0.0.0", "rustc_const_math 0.0.0", @@ -1425,9 +1455,9 @@ version = "0.0.0" dependencies = [ "arena 0.0.0", "build_helper 0.1.0", - "env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.8 (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", @@ -1445,29 +1475,24 @@ dependencies = [ ] [[package]] -name = "rustfmt" -version = "0.8.4" -source = "git+https://github.com/rust-lang-nursery/rustfmt#bf9b3fa1d7cab2f7bd541539d397a92b4954ec96" +name = "rustfmt-nightly" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "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)", + "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", - "itertools 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "multimap 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "strings 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex_errors 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex_syntax 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", + "strings 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "term 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-segmentation 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1480,13 +1505,18 @@ dependencies = [ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "scoped-tls" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "semver" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1501,22 +1531,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.6" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde_derive" -version = "1.0.6" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive_internals 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive_internals 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_derive_internals" -version = "0.15.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1528,7 +1558,7 @@ name = "serde_ignored" version = "0.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1538,7 +1568,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "dtoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1549,8 +1579,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "dtoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1578,10 +1608,11 @@ dependencies = [ "collections 0.0.0", "compiler_builtins 0.0.0", "core 0.0.0", - "gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.0.0", "panic_abort 0.0.0", "panic_unwind 0.0.0", + "profiler_builtins 0.0.0", "rand 0.0.0", "rustc_asan 0.0.0", "rustc_lsan 0.0.0", @@ -1600,17 +1631,12 @@ dependencies = [ [[package]] name = "strings" -version = "0.0.1" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "strsim" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "strsim" version = "0.6.0" @@ -1648,7 +1674,7 @@ name = "syntax" version = "0.0.0" dependencies = [ "bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", "serialize 0.0.0", @@ -1660,7 +1686,7 @@ name = "syntax_ext" version = "0.0.0" dependencies = [ "fmt_macros 0.0.0", - "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "proc_macro 0.0.0", "rustc_errors 0.0.0", "syntax 0.0.0", @@ -1671,6 +1697,7 @@ dependencies = [ name = "syntax_pos" version = "0.0.0" dependencies = [ + "rustc_data_structures 0.0.0", "serialize 0.0.0", ] @@ -1679,26 +1706,14 @@ name = "syntex_errors" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", "syntex_pos 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)", "term 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "syntex_errors" -version = "0.58.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex_pos 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", - "term 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "syntex_pos" version = "0.52.0" @@ -1707,22 +1722,14 @@ dependencies = [ "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "syntex_pos" -version = "0.58.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "syntex_syntax" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", "syntex_errors 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)", "syntex_pos 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1730,26 +1737,13 @@ dependencies = [ "unicode-xid 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "syntex_syntax" -version = "0.58.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 0.8.2 (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.24 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex_errors 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex_pos 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "tar" version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)", "xattr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1776,14 +1770,22 @@ dependencies = [ [[package]] name = "term_size" -version = "0.2.3" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "termcolor" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "wincolor 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "test" version = "0.0.0" @@ -1798,7 +1800,7 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1807,7 +1809,7 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1860,30 +1862,25 @@ name = "toml" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "typed-arena" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "unicode-bidi" -version = "0.2.5" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "unicode-normalization" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "unicode-segmentation" -version = "0.1.3" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1914,13 +1911,21 @@ dependencies = [ "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "unstable-book-gen" +version = "0.1.0" +dependencies = [ + "tidy 0.1.0", +] + [[package]] name = "url" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "idna 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "idna 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "percent-encoding 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1928,17 +1933,8 @@ name = "url_serde" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "user32-sys" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1951,9 +1947,14 @@ name = "utf8-ranges" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "vcpkg" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "vec_map" -version = "0.6.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1981,6 +1982,15 @@ name = "winapi-build" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "wincolor" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ws2_32-sys" version = "0.2.1" @@ -1995,7 +2005,7 @@ name = "xattr" version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2003,7 +2013,7 @@ name = "xz2" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lzma-sys 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "lzma-sys 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2016,74 +2026,75 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ca972c2ea5f742bfce5687b9aef75506a764f61d37f8f649047846a9686ddb66" "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 backtrace 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f551bc2ddd53aea015d453ef0b635af89444afa5ed2405dd0b2062ad5d600d80" -"checksum backtrace-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d192fd129132fbc97497c1f2ec2c2c5174e376b95f535199ef4fe0a293d33842" +"checksum atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d912da0db7fa85514874458ca3651fe2cddace8d0b0505571dbdcd41ab490159" +"checksum backtrace 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "72f9b4182546f4b04ebc4ab7f84948953a118bd6021a1b6a6c909e3e94f6be76" +"checksum backtrace-sys 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3a0d842ea781ce92be2bf78a9b38883948542749640b8378b3b2f03d1fd9f1ff" "checksum bitflags 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4f67931368edf3a9a51d29886d245f1c3db2f1ef0dcc9e35ff70341b78c10d23" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" "checksum bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1370e9fc2a6ae53aea8b7a5110edbd08836ed87c88736dfabccade1c2b44bff4" +"checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" "checksum bufstream 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f2f382711e76b9de6c744cc00d0497baba02fb00a787f088c879f01d09468e32" -"checksum cargo 0.20.0 (git+https://github.com/rust-lang/cargo)" = "" -"checksum cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de1e760d7b6535af4241fca8bd8adf68e2e7edacc6b29f5d399050c5e48cf88c" -"checksum clap 2.19.3 (registry+https://github.com/rust-lang/crates.io-index)" = "95b78f3fe0fc94c13c731714363260e04b557a637166f33a4570d3189d642374" -"checksum cmake 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)" = "92278eb79412c8f75cfc89e707a1bb3a6490b68f7f2e78d15c774f30fe701122" +"checksum cargo 0.21.0 (git+https://github.com/rust-lang/cargo)" = "" +"checksum cfg-if 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d0c47d456a36ebf0536a6705c83c1cbbcb9255fbc1d905a6ded104f479268a29" +"checksum clap 2.24.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6b8f69e518f967224e628896b54e41ff6acfb4dcfefc5076325c36525dac900f" +"checksum cmake 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)" = "b8ebbb35d3dc9cd09497168f33de1acb79b265d350ab0ac34133b98f8509af1f" "checksum crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0c5ea215664ca264da8a9d9c3be80d2eaf30923c259d03e870388eb927508f97" "checksum curl 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c90e1240ef340dd4027ade439e5c7c2064dd9dc652682117bd50d1486a3add7b" -"checksum curl-sys 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "23e7e544dc5e1ba42c4a4a678bd47985e84b9c3f4d3404c29700622a029db9c3" +"checksum curl-sys 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)" = "f00c8ba847fb0730c293069b4d1203dc01bf3c2e1f90b4e55f426ed8f4a1eeac" "checksum dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97590ba53bcb8ac28279161ca943a924d1fd4a8fb3fa63302591647c4fc5b850" "checksum derive-new 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "41be6ca3b99e0c0483fb2389685448f650459c3ecbe4e18d7705d8010ec4ab8e" "checksum diff 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0a515461b6c8c08419850ced27bc29e86166dcdcde8fbe76f8b1f0589bb49472" -"checksum docopt 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab32ea6e284d87987066f21a9e809a73c14720571ef34516f0890b3d355ccfd8" +"checksum docopt 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "63e408eee8a772c5c61f62353992e3ebf51ef5c832dd04d986b3dc7d48c5b440" "checksum dtoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "80c8b71fd71146990a9742fc06dcbbde19161a267e0ad4e572c35162f4578c90" -"checksum either 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18785c1ba806c258137c937e44ada9ee7e69a37e3c72077542cd2f069d78562a" "checksum enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "be4551092f4d519593039259a9ed8daedf0da12e5109c5280338073eaeb81180" "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 env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3ddf21e73e016298f5cb37d6ef8e8da8e39f91f9ec8b0df44b7deb16a9f8cd5b" "checksum error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9435d864e017c3c6afeac1654189b06cdb491cf2ff73dbf0d73b0f292f42ff8" "checksum filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922" "checksum flate2 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)" = "36df0166e856739905cd3d7e0b210fe818592211a008862599845e012d8d304c" "checksum foreign-types 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e4056b9bd47f8ac5ba12be771f77a0dae796d1bbaaf5fd0b9c2d38b69b8a29d" -"checksum fs2 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "34edaee07555859dc13ca387e6ae05686bb4d0364c95d649b6dab959511f4baf" -"checksum gcc 0.3.50 (registry+https://github.com/rust-lang/crates.io-index)" = "5f837c392f2ea61cb1576eac188653df828c861b7137d74ea4a5caa89621f9e6" -"checksum gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0912515a8ff24ba900422ecda800b52f4016a56251922d397c576bf92c690518" +"checksum fs2 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9ab76cfd2aaa59b7bf6688ad9ba15bbae64bff97f04ea02144cfd3443e5c2866" +"checksum gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)" = "120d07f202dcc3f72859422563522b66fe6463a4c513df062874daad05f85f0a" "checksum getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9047cfbd08a437050b363d35ef160452c5fe8ea5187ae0a624708c91581d685" -"checksum git2 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "9de9df4358c17e448a778d90cd0272e1dab5eae30244502333fa2001c4e24357" +"checksum git2 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "aa01936ac96555c083c0e8553f672616274408d9d3fc5b8696603fbf63ff43ee" "checksum git2-curl 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "68676bc784bf0bef83278898929bf64a251e87c0340723d0b93fa096c9c5bf8e" "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" "checksum hamcrest 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bf088f042a467089e9baa4972f57f9247e42a0cc549ba264c7a04fbb8ecb89d4" "checksum handlebars 0.25.3 (registry+https://github.com/rust-lang/crates.io-index)" = "15bdf598fc3c2de40c6b340213028301c0d225eea55a2294e6cc148074e557a1" -"checksum idna 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6ac85ec3f80c8e4e99d9325521337e14ec7555c458a14e377d189659a427f375" -"checksum itertools 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4833d6978da405305126af4ac88569b5d71ff758581ce5a987dbfa3755f694fc" +"checksum hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d6a22814455d41612f41161581c2883c0c6a1c41852729b17d5ed88f01e153aa" +"checksum idna 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2233d4940b1f19f0418c158509cd7396b8d70a5db5705ce410914dc8fa603b37" "checksum itoa 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eb2f404fbc66fd9aac13e998248505e7ecb2ad8e44ab6388684c5fb11c6c251c" +"checksum jobserver 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "4e28adc987f6d0521ef66ad60b055968107b164b3bb3cf3dc8474e0a380474a6" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum languageserver-types 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97c2985bfcbbcb0189cfa25e1c10c1ac7111df2b6214b652c690127aefdf4e5b" "checksum lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3b37545ab726dd833ec6420aaba8231c5b320814b9029ad585555d2a03e94fbf" -"checksum libc 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)" = "babb8281da88cba992fa1f4ddec7d63ed96280a1a53ec9b919fd37b53d71e502" -"checksum libgit2-sys 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d9dc31ee90fb179b706d35fb672e91d0b74e950d7fb4ea7eae3c0f5ecbf2d3d3" +"checksum libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)" = "38f5c2b18a287cf78b4097db62e20f43cace381dc76ae5c0a3073067f78b7ddc" +"checksum libgit2-sys 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "df18a822100352d9863b302faf6f8f25c0e77f0e60feb40e5dbe1238b7f13b1d" "checksum libssh2-sys 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0db4ec23611747ef772db1c4d650f8bd762f07b461727ec998f953c614024b75" -"checksum libz-sys 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e5ee912a45d686d393d5ac87fac15ba0ba18daae14e8e7543c63ebf7fb7e970c" -"checksum log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "5141eca02775a762cc6cd564d8d2c50f67c0ea3a372cbf1c51592b3e029e10ad" -"checksum lzma-sys 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "fedff6a5cbb24494ec6ee4784e9ac5c187161fede04c7767d49bf87544013afa" -"checksum matches 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "efd7622e3022e1a6eaa602c4cea8912254e5582c9c692e9167714182244801b1" +"checksum libz-sys 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "e70195f655a44af531ad7135b1ec2a0a82522b451fe09730fbb25674a85996e7" +"checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b" +"checksum lzma-sys 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "013fa6506eb7d26040c46dab9ecb7ccb4e2896b5bf24a9d65932501ea9f67af8" +"checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376" "checksum mdbook 0.0.21 (registry+https://github.com/rust-lang/crates.io-index)" = "f1e2e9d848514dcfad4195788d0d42ae5153a477c191d75d5b84fab10f222fbd" "checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20" "checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4" "checksum miniz-sys 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "28eaee17666671fa872e567547e8428e83308ebe5808cdf6a0e28397dbe2c726" "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" -"checksum multimap 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9223f4774d08e06185e44e555b9a7561243d387bac49c78a6205c42d6975fbf2" "checksum net2 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)" = "bc01404e7568680f1259aa5729539f221cb1e6d047a0d9053cab4be8a73b5d67" -"checksum num 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "98b15ba84e910ea7a1973bccd3df7b31ae282bf9d8bd2897779950c9b8303d40" -"checksum num-bigint 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "ba6d838b16e56da1b6c383d065ff1ec3c7d7797f65a3e8f6ba7092fd87820bac" -"checksum num-complex 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "148eb324ca772230853418731ffdf13531738b50f89b30692a01fcdcb0a64677" +"checksum num 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "2c3a3dc9f30bf824141521b30c908a859ab190b76e20435fcd89f35eb6583887" +"checksum num-bigint 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "6361748d02e5291c72a422dc8ed4d8464a80cb1e618971f6fffe6d52d97e3286" +"checksum num-complex 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "412dfc143c56579aa6a22c574e38ddbf724522f1280ae2b257498cccff3fb6af" "checksum num-integer 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)" = "ef1a4bf6f9174aa5783a9b4cc892cacd11aebad6c69ad027a0b65c6ca5f8aa37" "checksum num-iter 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)" = "f7d1891bd7b936f12349b7d1403761c8a0b85a18b148e9da4429d5d102c1a41e" -"checksum num-rational 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "c2dc5ea04020a8f18318ae485c751f8cfa1c0e69dcf465c29ddaaa64a313cc44" -"checksum num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "e1cbfa3781f3fe73dc05321bed52a06d2d491eaa764c52335cf4399f046ece99" -"checksum num_cpus 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca313f1862c7ec3e0dfe8ace9fa91b1d9cb5c84ace3d00f5ec4216238e93c167" +"checksum num-rational 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "33c881e104a26e1accc09449374c095ff2312c8e0c27fab7bbefe16eac7c776d" +"checksum num-traits 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "1708c0628602a98b52fad936cf3edb9a107af06e52e49fdf0707e884456a6af6" +"checksum num_cpus 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6e416ba127a4bb3ff398cb19546a8d0414f73352efe2857f4060d36f5fe5983a" "checksum open 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3478ed1686bd1300c8a981a940abc92b06fac9cbef747f4c668d4e032ff7b842" -"checksum openssl 0.9.12 (registry+https://github.com/rust-lang/crates.io-index)" = "bb5d1663b73d10c6a3eda53e2e9d0346f822394e7b858d7257718f65f61dfbe2" +"checksum openssl 0.9.14 (registry+https://github.com/rust-lang/crates.io-index)" = "11ba043cb65fc9af71a431b8a36ffe8686cd4751cdf70a473ec1d01066ac7e41" "checksum openssl-probe 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d98df0270d404ccd3c050a41d579c52d1db15375168bb3471e04ec0f5f378daf" -"checksum openssl-sys 0.9.12 (registry+https://github.com/rust-lang/crates.io-index)" = "3a5886d87d3e2a0d890bf62dc8944f5e3769a405f7e1e9ef6e517e47fd7a0897" +"checksum openssl-sys 0.9.14 (registry+https://github.com/rust-lang/crates.io-index)" = "236c718c2e2c2b58a546d86ffea5194400bb15dbe01ca85325ffd357b03cf66c" "checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37" +"checksum percent-encoding 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de154f638187706bde41d9b4738748933d64e6b37bdbffc0b47a97d16a6ae356" "checksum pest 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0a6dda33d67c26f0aac90d324ab2eb7239c819fc7b2552fe9faa4fe88441edc8" "checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903" "checksum psapi-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "abcd5d1a07d360e29727f757a9decb3ce8bc6e0efa8969cfaad669a8317a2478" @@ -2092,47 +2103,46 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum quick-error 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c36987d4978eb1be2e422b1e0423a557923a5c3e7e6f31d5699e9aafaefa469" "checksum quote 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4c5cf478fe1006dbcc72567121d23dbdae5f1632386068c5c86ff4f645628504" "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" -"checksum racer 2.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b0d72b3afd67882adfca61d609fafb8d7aa5f9e814f12c32fcc6e171995920e8" +"checksum racer 2.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "edf2dfc188373ef96168bec3646a0415c5c21111c6144c0c36104fc720587ecd" "checksum rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "022e0636ec2519ddae48154b028864bdce4eaf7d35226ab8e65c611be97b189d" "checksum regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)" = "4fd4ace6a8cf7860714a2c2280d6c1f7e6a413486c13298bbc86fd3da019402f" -"checksum regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4278c17d0f6d62dfef0ab00028feb45bd7d2102843f80763474eeb1be8a10c01" +"checksum regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1731164734096285ec2a5ec7fea5248ae2f5485b3feeb0115af4fda2183b2d1b" "checksum regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ec002c35e86791825ed294b50008eea9ddfc8def4420124fbc6b08db834957" -"checksum regex-syntax 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9191b1f57603095f105d317e375d19b1c9c5c3185ea9633a99a6dcbed04457" -"checksum rls-analysis 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a62d88c341375c6f3f8b2e18b9b364896e7d3e7aa916907de717d0267e116506" -"checksum rls-data 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fc4277ce3c57f456b11fe3145b181a844a25201bab5cbaa1978457e6e2f27d47" +"checksum regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad890a5eef7953f55427c50575c680c42841653abd2b028b68cd223d157f62db" +"checksum rls-analysis 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8d77d58e8933752142b5b92e3f8ba6d6f1630be6da5627c492268a43f79ffbda" +"checksum rls-data 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "374a8fad31cc0681a7bfd8a04079dd4afd0e981d34e18a171b1a467445bdf51e" +"checksum rls-data 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9e2087477364c34faca86c2476765deb1185dbae3c598cfb1eb040f3a74d22b5" "checksum rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d7c7046dc6a92f2ae02ed302746db4382e75131b9ce20ce967259f6b5867a6a" -"checksum rls-vfs 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "986eada111517bcb5a7a75205b3f2b70c82e7766653cca61a23f5afce79bdb94" +"checksum rls-vfs 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ace07060dd154731b39254864245cbdd33c8f5f64fe1f630a089c72e2468f854" "checksum rustc-demangle 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3058a43ada2c2d0b92b3ae38007a2d0fa5e9db971be260e0171408a4ff471c95" "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" -"checksum rustfmt 0.8.4 (git+https://github.com/rust-lang-nursery/rustfmt)" = "" +"checksum rustfmt-nightly 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "277deb9c0ee9c4788ee94faef5988fa334179cd7363bf281a2cae027edbbc8bf" "checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7" +"checksum scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f417c22df063e9450888a7561788e9bd46d3bb3c1466435b4eccb903807f147d" "checksum semver 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3fdd61b85a0fa777f7fb7c454b9189b2941b110d1385ce84d7f76efdf1606a85" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" "checksum serde 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)" = "34b623917345a631dc9608d5194cc206b3fe6c3554cd1c75b937e55e285254af" -"checksum serde 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "38a3db3a5757f68069aba764b793823ea9fb9717c42c016f8903f8add50f508a" -"checksum serde_derive 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "e46ef71ee001a4279a4513e79a6ebbb59da3a4987bf77a6df2e5534cd6f21d82" -"checksum serde_derive_internals 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "021c338d22c7e30f957a6ab7e388cb6098499dda9fd4ba1661ee074ca7a180d1" +"checksum serde 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "c2f530d36fb84ec48fb7146936881f026cdbf4892028835fd9398475f82c1bb4" +"checksum serde_derive 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "10552fad5500771f3902d0c5ba187c5881942b811b7ba0d8fbbfbf84d80806d3" +"checksum serde_derive_internals 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)" = "37aee4e0da52d801acfbc0cc219eb1eda7142112339726e427926a6f6ee65d3a" "checksum serde_ignored 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c10e798e4405d7dcec3658989e35ee6706f730a9ed7c1184d5ebd84317e82f46" "checksum serde_json 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ad8bcf487be7d2e15d3d543f04312de991d631cfe1b43ea0ade69e6a8a5b16a1" "checksum serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "48b04779552e92037212c3615370f6bd57a40ebba7f20e554ff9f55e41a69a7b" "checksum shell-escape 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "dd5cc96481d54583947bfe88bf30c23d53f883c6cd0145368b69989d97b84ef8" "checksum stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "15132e0e364248108c5e2c02e3ab539be8d6f5d52a01ca9bbf27ed657316f02b" -"checksum strings 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "54f86446ab480b4f60782188f4f78886465c5793aee248cbb48b7fdc0d022420" -"checksum strsim 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "67f84c44fbb2f91db7fef94554e6b2ac05909c9c0b0bc23bb98d3a1aebfe7f7c" +"checksum strings 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "da75d8bf2c4d210d63dd09581a041b036001f9f6e03d9b151dbff810fb7ba26a" "checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694" "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" "checksum syn 0.8.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6ae6fb0dcc9bd85f89a1a4adc0df2fd90c90c98849d61433983dd7a9df6363f7" "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" "checksum syntex_errors 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9e52bffe6202cfb67587784cf23e0ec5bf26d331eef4922a16d5c42e12aa1e9b" -"checksum syntex_errors 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)" = "867cc5c2d7140ae7eaad2ae9e8bf39cb18a67ca651b7834f88d46ca98faadb9c" "checksum syntex_pos 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)" = "955ef4b16af4c468e4680d1497f873ff288f557d338180649e18f915af5e15ac" -"checksum syntex_pos 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)" = "13ad4762fe52abc9f4008e85c4fb1b1fe3aa91ccb99ff4826a439c7c598e1047" "checksum syntex_syntax 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)" = "76a302e717e348aa372ff577791c3832395650073b8d8432f8b3cb170b34afde" -"checksum syntex_syntax 0.58.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6e0e4dbae163dd98989464c23dd503161b338790640e11537686f2ef0f25c791" "checksum tar 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)" = "281285b717926caa919ad905ef89c63d75805c7d89437fb873100925a53f2b1b" "checksum tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "87974a6f5c1dfb344d733055601650059a3363de2a6104819293baff662132d6" "checksum term 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d168af3930b369cfe245132550579d47dfd873d69470755a19c2c6568dbbd989" -"checksum term_size 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "07b6c1ac5b3fffd75073276bca1ceed01f67a28537097a2a9539e116e50fb21a" +"checksum term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2b6b55df3198cc93372e85dd2ed817f0e38ce8cc0f22eb32391bfad9c4bf209" +"checksum termcolor 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9a5193a56b8d82014662c4b933dea6bec851daf018a2b01722e007daaf5f9dca" "checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03" "checksum thread-id 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8df7875b676fddfadffd96deea3b1124e5ede707d4884248931077518cf1f773" "checksum thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8576dbbfcaef9641452d5cf0df9b0e7eeab7694956dd33bb61515fb8f18cfdd5" @@ -2141,25 +2151,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum toml 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "736b60249cb25337bc196faa43ee12c705e426f3d55c214d73a4e7be06f92cb4" "checksum toml 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bd86ad9ebee246fdedd610e0f6d0587b754a3d81438db930a244d0480ed7878f" "checksum toml 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4cc5dbfb20a481e64b99eb7ae280859ec76730c7191570ba5edaa962394edb0a" -"checksum typed-arena 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8e2f9dc90da4f9d66ffc9ad3ead2c7d57582a26f4a3292d2ce7011bd29965100" -"checksum unicode-bidi 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d3a078ebdd62c0e71a709c3d53d2af693fe09fe93fbff8344aebe289b78f9032" -"checksum unicode-normalization 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e28fa37426fceeb5cf8f41ee273faa7c82c47dc8fba5853402841e665fcd86ff" -"checksum unicode-segmentation 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c3bc443ded17b11305ffffe6b37e2076f328a5a8cb6aa877b1b98f77699e98b5" +"checksum typed-arena 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5934776c3ac1bea4a9d56620d6bf2d483b20d394e49581db40f187e1118ff667" +"checksum unicode-bidi 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a6a2c4e3710edd365cd7e78383153ed739fa31af19f9172f72d3575060f5a43a" +"checksum unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "51ccda9ef9efa3f7ef5d91e8f9b83bbe6955f9bf86aec89d5cce2c874625920f" "checksum unicode-segmentation 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a8083c594e02b8ae1654ae26f0ade5158b119bd88ad0e8227a5d8fcd72407946" "checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f" "checksum unicode-xid 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "36dff09cafb4ec7c8cf0023eb0b686cb6ce65499116a12201c9e11840ca01beb" "checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" "checksum unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1f2ae5ddb18e1c92664717616dd9549dde73f539f01bd7b77c2edb2446bdff91" -"checksum url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f5ba8a749fb4479b043733416c244fa9d1d3af3d7c23804944651c8a448cb87e" +"checksum url 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a69a2e36a5e5ed3f3063c8c64a3b028c4d50d689fa6c862abd7cfe65f882595c" "checksum url_serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "74e7d099f1ee52f823d4bdd60c93c3602043c728f5db3b97bdb548467f7bddea" -"checksum user32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ef4711d107b21b410a3a974b1204d9accc8b10dad75d8324b5d755de1617d47" "checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f" "checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122" -"checksum vec_map 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cac5efe5cb0fa14ec2f84f83c701c562ee63f6dcc680861b21d65c682adfb05f" +"checksum vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9e0a7d8bed3178a8fb112199d466eeca9ed09a14ba8ad67718179b4fd5487d0b" +"checksum vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "887b5b631c2ad01628bbbaa7dd4c869f80d3186688f8d0b6f58774fbe324988c" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" "checksum walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "bb08f9e670fab86099470b97cd2b252d6527f0b3cc1401acdb595ffc9dd288ff" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" +"checksum wincolor 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "99c2af1426e2166e6f66d88b09b2a4d63afce06875f149174e386f2f1ee9779b" "checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" "checksum xattr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "5f04de8a1346489a2f9e9bd8526b73d135ec554227b17568456e86aa35b6f3fc" "checksum xz2 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e9510bdf100731599107c61f77daf46713a69a568f75458999c1f9dbf6ba25b0" diff --git a/src/Cargo.toml b/src/Cargo.toml index 85a6df3573ae..9cf6297d463b 100644 --- a/src/Cargo.toml +++ b/src/Cargo.toml @@ -9,6 +9,7 @@ members = [ "tools/error_index_generator", "tools/linkchecker", "tools/rustbook", + "tools/unstable-book-gen", "tools/tidy", "tools/build-manifest", "tools/remote-test-client", @@ -36,4 +37,4 @@ debug = false debug-assertions = false [replace] -"https://github.com/rust-lang/cargo#0.20.0" = { path = "tools/cargo" } +"https://github.com/rust-lang/cargo#0.21.0" = { path = "tools/cargo" } diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index 385376333c1d..0d3cc2e0b1b7 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -245,6 +245,9 @@ pub fn compiletest(build: &Build, let llvm_config = build.llvm_config(target); let llvm_version = output(Command::new(&llvm_config).arg("--version")); cmd.arg("--llvm-version").arg(llvm_version); + if !build.is_rust_llvm(target) { + cmd.arg("--system-llvm"); + } cmd.args(&build.flags.cmd.test_args()); @@ -299,6 +302,10 @@ pub fn compiletest(build: &Build, cmd.env("SANITIZER_SUPPORT", "1"); } + if build.config.profiler { + cmd.env("PROFILER_SUPPORT", "1"); + } + cmd.arg("--adb-path").arg("adb"); cmd.arg("--adb-test-dir").arg(ADB_TEST_DIR); if target.contains("android") { @@ -563,7 +570,9 @@ fn find_tests(dir: &Path, let filename = e.file_name().into_string().unwrap(); if (target.contains("windows") && filename.ends_with(".exe")) || (!target.contains("windows") && !filename.contains(".")) || - (target.contains("emscripten") && filename.ends_with(".js")) { + (target.contains("emscripten") && + filename.ends_with(".js") && + !filename.ends_with(".asm.js")) { dst.push(e.path()); } } diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index abad216d89be..64b2a665e257 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -50,6 +50,7 @@ pub struct Config { pub full_bootstrap: bool, pub extended: bool, pub sanitizers: bool, + pub profiler: bool, // llvm codegen options pub llvm_assertions: bool, @@ -162,6 +163,7 @@ struct Build { extended: Option, verbose: Option, sanitizers: Option, + profiler: Option, openssl_static: Option, } @@ -318,6 +320,7 @@ impl Config { set(&mut config.extended, build.extended); set(&mut config.verbose, build.verbose); set(&mut config.sanitizers, build.sanitizers); + set(&mut config.profiler, build.profiler); set(&mut config.openssl_static, build.openssl_static); if let Some(ref install) = toml.install { @@ -471,6 +474,7 @@ impl Config { ("FULL_BOOTSTRAP", self.full_bootstrap), ("EXTENDED", self.extended), ("SANITIZERS", self.sanitizers), + ("PROFILER", self.profiler), ("DIST_SRC", self.rust_dist_src), ("CARGO_OPENSSL_STATIC", self.openssl_static), } diff --git a/src/bootstrap/config.toml.example b/src/bootstrap/config.toml.example index 0eb6c4c82c4d..3a467dafbfb8 100644 --- a/src/bootstrap/config.toml.example +++ b/src/bootstrap/config.toml.example @@ -147,6 +147,9 @@ # Build the sanitizer runtimes #sanitizers = false +# Build the profiler runtime +#profiler = false + # Indicates whether the OpenSSL linked into Cargo will be statically linked or # not. If static linkage is specified then the build system will download a # known-good version of OpenSSL, compile it, and link it to Cargo. diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 26d44ae7693a..f92e6f50eb3e 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -376,8 +376,8 @@ pub fn debugger_scripts(build: &Build, install(&build.src.join("src/etc/rust-windbg.cmd"), &sysroot.join("bin"), 0o755); + cp_debugger_script("natvis/liballoc.natvis"); cp_debugger_script("natvis/libcore.natvis"); - cp_debugger_script("natvis/libcollections.natvis"); } else { cp_debugger_script("debugger_pretty_printers_common.py"); @@ -570,6 +570,7 @@ pub fn rust_src(build: &Build) { "src/libgetopts", "src/compiler-rt", "src/jemalloc", + "src/libprofiler_builtins", ]; let std_src_dirs_exclude = [ "src/compiler-rt/test", diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index baee1ada508f..30f631ca2df6 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -27,18 +27,26 @@ use {Build, Compiler, Mode}; use util::{cp_r, symlink_dir}; use build_helper::up_to_date; -/// Invoke `rustbook` as compiled in `stage` for `target` for the doc book -/// `name` into the `out` path. +/// Invoke `rustbook` for `target` for the doc book `name`. /// /// This will not actually generate any documentation if the documentation has /// already been generated. pub fn rustbook(build: &Build, target: &str, name: &str) { + let src = build.src.join("src/doc"); + rustbook_src(build, target, name, &src); +} + +/// Invoke `rustbook` for `target` for the doc book `name` from the `src` path. +/// +/// This will not actually generate any documentation if the documentation has +/// already been generated. +pub fn rustbook_src(build: &Build, target: &str, name: &str, src: &Path) { let out = build.doc_out(target); t!(fs::create_dir_all(&out)); let out = out.join(name); let compiler = Compiler::new(0, &build.config.build); - let src = build.src.join("src/doc").join(name); + let src = src.join(name); let index = out.join("index.html"); let rustbook = build.tool(&compiler, "rustbook"); if up_to_date(&src, &index) && up_to_date(&rustbook, &index) { @@ -354,6 +362,19 @@ pub fn error_index(build: &Build, target: &str) { build.run(&mut index); } +pub fn unstable_book_gen(build: &Build, target: &str) { + println!("Generating unstable book md files ({})", target); + let out = build.md_doc_out(target).join("unstable-book"); + t!(fs::create_dir_all(&out)); + t!(fs::remove_dir_all(&out)); + let compiler = Compiler::new(0, &build.config.build); + let mut cmd = build.tool_cmd(&compiler, "unstable-book-gen"); + cmd.arg(build.src.join("src")); + cmd.arg(out); + + build.run(&mut cmd); +} + fn symlink_dir_force(src: &Path, dst: &Path) -> io::Result<()> { if let Ok(m) = fs::symlink_metadata(dst) { if m.file_type().is_dir() { diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index f100baa5d2ca..dc9dac736278 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -196,9 +196,14 @@ Arguments: ./x.py build ./x.py build --stage 1 - For a quick build with a usable compile, you can pass: + For a quick build of a usable compiler, you can pass: - ./x.py build --stage 1 src/libtest"); + ./x.py build --stage 1 src/libtest + + This will first build everything once (like --stage 0 without further + arguments would), and then use the compiler built in stage 0 to build + src/libtest and its dependencies. + Once this is done, build/$ARCH/stage1 contains a usable compiler."); } "test" => { subcommand_help.push_str("\n @@ -237,11 +242,18 @@ Arguments: let cwd = t!(env::current_dir()); let paths = matches.free[1..].iter().map(|p| cwd.join(p)).collect::>(); + 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 { + None + } + }); // 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(); + let mut config = Config::parse(&flags.build, cfg_file.clone()); config.build = flags.build.clone(); let mut build = Build::new(flags, config); metadata::build(&mut build); @@ -302,14 +314,6 @@ Arguments: }; - 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 { - None - } - }); - let mut stage = matches.opt_str("stage").map(|j| j.parse().unwrap()); if matches.opt_present("incremental") { diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 2fe6a2a3ae89..e0e6583b9359 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -594,6 +594,9 @@ impl Build { if self.config.backtrace { features.push_str(" backtrace"); } + if self.config.profiler { + features.push_str(" profiler"); + } return features } @@ -677,6 +680,11 @@ impl Build { self.out.join(target).join("doc") } + /// Output directory for some generated md crate documentation for a target (temporary) + fn md_doc_out(&self, target: &str) -> PathBuf { + self.out.join(target).join("md-doc") + } + /// Output directory for all crate documentation for a target (temporary) /// /// The artifacts here are then copied into `doc_out` above. diff --git a/src/bootstrap/step.rs b/src/bootstrap/step.rs index 9e8b08a23b7e..5f0724c65775 100644 --- a/src/bootstrap/step.rs +++ b/src/bootstrap/step.rs @@ -463,7 +463,7 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { rules.test("check-linkchecker", "src/tools/linkchecker") .dep(|s| s.name("tool-linkchecker").stage(0)) .dep(|s| s.name("default:doc")) - .default(true) + .default(build.config.docs) .host(true) .run(move |s| check::linkcheck(build, s.target)); rules.test("check-cargotest", "src/tools/cargotest") @@ -548,6 +548,10 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { .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-unstable-book-gen", "src/tools/unstable-book-gen") + .dep(|s| s.name("maybe-clean-tools")) + .dep(|s| s.name("libstd-tool")) + .run(move |s| compile::tool(build, s.stage, s.target, "unstable-book-gen")); rules.build("tool-tidy", "src/tools/tidy") .dep(|s| s.name("maybe-clean-tools")) .dep(|s| s.name("libstd-tool")) @@ -662,8 +666,12 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { .target(&build.config.build) .stage(0) }) + .dep(move |s| s.name("doc-unstable-book-gen")) .default(build.config.docs) - .run(move |s| doc::rustbook(build, s.target, "unstable-book")); + .run(move |s| doc::rustbook_src(build, + s.target, + "unstable-book", + &build.md_doc_out(s.target))); rules.doc("doc-standalone", "src/doc") .dep(move |s| { s.name("rustc") @@ -679,6 +687,17 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules { .default(build.config.docs) .host(true) .run(move |s| doc::error_index(build, s.target)); + rules.doc("doc-unstable-book-gen", "src/tools/unstable-book-gen") + .dep(move |s| { + s.name("tool-unstable-book-gen") + .host(&build.config.build) + .target(&build.config.build) + .stage(0) + }) + .dep(move |s| s.name("libstd-link")) + .default(build.config.docs) + .host(true) + .run(move |s| doc::unstable_book_gen(build, s.target)); for (krate, path, default) in krates("std") { rules.doc(&krate.doc_step, path) .dep(|s| s.name("libstd-link")) @@ -1407,13 +1426,20 @@ mod tests { fn build(args: &[&str], extra_host: &[&str], extra_target: &[&str]) -> Build { + build_(args, extra_host, extra_target, true) + } + + fn build_(args: &[&str], + extra_host: &[&str], + extra_target: &[&str], + docs: bool) -> Build { let mut args = args.iter().map(|s| s.to_string()).collect::>(); args.push("--build".to_string()); args.push("A".to_string()); let flags = Flags::parse(&args); let mut config = Config::default(); - config.docs = true; + config.docs = docs; config.build = "A".to_string(); config.host = vec![config.build.clone()]; config.host.extend(extra_host.iter().map(|s| s.to_string())); @@ -1768,4 +1794,22 @@ mod tests { assert!(!plan.iter().any(|s| s.name.contains("tidy"))); assert!(plan.iter().any(|s| s.name.contains("valgrind"))); } + + #[test] + fn test_disable_docs() { + let build = build_(&["test"], &[], &[], false); + let rules = super::build_rules(&build); + let plan = rules.plan(); + println!("rules: {:#?}", plan); + assert!(!plan.iter().any(|s| { + s.name.contains("doc-") || s.name.contains("default:doc") + })); + // none of the dependencies should be a doc rule either + assert!(!plan.iter().any(|s| { + rules.rules[s.name].deps.iter().any(|dep| { + let dep = dep(&rules.sbuild.name(s.name)); + dep.name.contains("doc-") || dep.name.contains("default:doc") + }) + })); + } } diff --git a/src/ci/docker/asmjs/Dockerfile b/src/ci/docker/asmjs/Dockerfile new file mode 100644 index 000000000000..899ce1e4569d --- /dev/null +++ b/src/ci/docker/asmjs/Dockerfile @@ -0,0 +1,44 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++ \ + make \ + file \ + curl \ + ca-certificates \ + python \ + git \ + cmake \ + sudo \ + gdb \ + xz-utils + +# dumb-init +COPY scripts/dumb-init.sh /scripts/ +RUN sh /scripts/dumb-init.sh + +# emscripten +COPY scripts/emscripten.sh /scripts/ +RUN bash /scripts/emscripten.sh + +# env +ENV PATH=$PATH:/emsdk-portable +ENV PATH=$PATH:/emsdk-portable/clang/e1.37.13_64bit/ +ENV PATH=$PATH:/emsdk-portable/emscripten/1.37.13/ +ENV PATH=$PATH:/emsdk-portable/node/4.1.1_64bit/bin/ +ENV EMSCRIPTEN=/emsdk-portable/emscripten/1.37.13/ +ENV BINARYEN_ROOT=/emsdk-portable/clang/e1.37.13_64bit/binaryen/ +ENV EM_CONFIG=/emsdk-portable/.emscripten + +ENV TARGETS=asmjs-unknown-emscripten + +ENV RUST_CONFIGURE_ARGS --target=$TARGETS + +ENV SCRIPT python2.7 ../x.py test --target $TARGETS + +# cache +COPY scripts/sccache.sh /scripts/ +RUN sh /scripts/sccache.sh + +# init +ENTRYPOINT ["/usr/bin/dumb-init", "--"] diff --git a/src/ci/docker/disabled/wasm32/Dockerfile b/src/ci/docker/disabled/wasm32/Dockerfile new file mode 100644 index 000000000000..daf398ac0962 --- /dev/null +++ b/src/ci/docker/disabled/wasm32/Dockerfile @@ -0,0 +1,44 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++ \ + make \ + file \ + curl \ + ca-certificates \ + python \ + git \ + cmake \ + sudo \ + gdb \ + xz-utils + +# dumb-init +COPY scripts/dumb-init.sh /scripts/ +RUN sh /scripts/dumb-init.sh + +# emscripten +COPY scripts/emscripten.sh /scripts/ +RUN bash /scripts/emscripten.sh +COPY wasm32/node.sh /usr/local/bin/node + +# env +ENV PATH=$PATH:/emsdk-portable +ENV PATH=$PATH:/emsdk-portable/clang/e1.37.13_64bit/ +ENV PATH=$PATH:/emsdk-portable/emscripten/1.37.13/ +ENV EMSCRIPTEN=/emsdk-portable/emscripten/1.37.13/ +ENV BINARYEN_ROOT=/emsdk-portable/clang/e1.37.13_64bit/binaryen/ +ENV EM_CONFIG=/emsdk-portable/.emscripten + +ENV TARGETS=wasm32-unknown-emscripten + +ENV RUST_CONFIGURE_ARGS --target=$TARGETS + +ENV SCRIPT python2.7 ../x.py test --target $TARGETS + +# cache +COPY scripts/sccache.sh /scripts/ +RUN sh /scripts/sccache.sh + +# init +ENTRYPOINT ["/usr/bin/dumb-init", "--"] diff --git a/src/ci/docker/disabled/wasm32/node.sh b/src/ci/docker/disabled/wasm32/node.sh new file mode 100755 index 000000000000..dfa7f221ffa2 --- /dev/null +++ b/src/ci/docker/disabled/wasm32/node.sh @@ -0,0 +1,18 @@ +#!/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. + +path="$(dirname $1)" +file="$(basename $1)" + +shift + +cd "$path" +exec /node-v8.0.0-linux-x64/bin/node "$file" "$@" diff --git a/src/ci/docker/dist-i686-linux/Dockerfile b/src/ci/docker/dist-i686-linux/Dockerfile index a3c08e93ed15..9145e9dfc8d1 100644 --- a/src/ci/docker/dist-i686-linux/Dockerfile +++ b/src/ci/docker/dist-i686-linux/Dockerfile @@ -90,7 +90,8 @@ ENV HOSTS=i686-unknown-linux-gnu ENV RUST_CONFIGURE_ARGS \ --host=$HOSTS \ --enable-extended \ - --enable-sanitizers + --enable-sanitizers \ + --enable-profiler ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS # This is the only builder which will create source tarballs diff --git a/src/ci/docker/dist-x86_64-linux/Dockerfile b/src/ci/docker/dist-x86_64-linux/Dockerfile index e2e42836dcda..78b62839a35d 100644 --- a/src/ci/docker/dist-x86_64-linux/Dockerfile +++ b/src/ci/docker/dist-x86_64-linux/Dockerfile @@ -90,7 +90,8 @@ ENV HOSTS=x86_64-unknown-linux-gnu ENV RUST_CONFIGURE_ARGS \ --host=$HOSTS \ --enable-extended \ - --enable-sanitizers + --enable-sanitizers \ + --enable-profiler ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS # This is the only builder which will create source tarballs diff --git a/src/ci/docker/emscripten/Dockerfile b/src/ci/docker/emscripten/Dockerfile deleted file mode 100644 index 0f0e5b69c32c..000000000000 --- a/src/ci/docker/emscripten/Dockerfile +++ /dev/null @@ -1,41 +0,0 @@ -FROM ubuntu:16.04 - -RUN apt-get update && apt-get install -y --no-install-recommends \ - g++ \ - make \ - file \ - curl \ - ca-certificates \ - python \ - git \ - cmake \ - sudo \ - gdb \ - xz-utils \ - lib32stdc++6 - -RUN curl -o /usr/local/bin/sccache \ - https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-05-12-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", "--"] - -WORKDIR /tmp -COPY emscripten/build-emscripten.sh /tmp/ -RUN ./build-emscripten.sh -ENV PATH=$PATH:/tmp/emsdk_portable -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.10 -ENV EMSCRIPTEN=/tmp/emsdk_portable/emscripten/tag-1.37.10 - -ENV RUST_CONFIGURE_ARGS --target=asmjs-unknown-emscripten - -# Run `emcc` first as it's got a prompt and doesn't actually do anything, after -# that's done with do the real build. -ENV SCRIPT emcc && \ - python2.7 ../x.py test --target asmjs-unknown-emscripten - diff --git a/src/ci/docker/emscripten/build-emscripten.sh b/src/ci/docker/emscripten/build-emscripten.sh deleted file mode 100755 index 8d6a28f418bf..000000000000 --- a/src/ci/docker/emscripten/build-emscripten.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/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 - trap - ERR - kill $PING_LOOP_PID - rm /tmp/build.log - set -x -} - -curl https://s3.amazonaws.com/mozilla-games/emscripten/releases/emsdk-portable.tar.gz | \ - 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.10-32bit -hide_output emsdk activate --build=Release sdk-tag-1.37.10-32bit diff --git a/src/ci/docker/scripts/emscripten.sh b/src/ci/docker/scripts/emscripten.sh new file mode 100644 index 000000000000..8aa5a98d7fc5 --- /dev/null +++ b/src/ci/docker/scripts/emscripten.sh @@ -0,0 +1,53 @@ +# 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 + trap - ERR + kill $PING_LOOP_PID + rm -f /tmp/build.log + set -x +} + +cd / +curl -L https://s3.amazonaws.com/mozilla-games/emscripten/releases/emsdk-portable.tar.gz | \ + tar -xz + +cd /emsdk-portable +./emsdk update +hide_output ./emsdk install sdk-1.37.13-64bit +./emsdk activate sdk-1.37.13-64bit + +# Compile and cache libc +source ./emsdk_env.sh +echo "main(){}" > a.c +HOME=/emsdk-portable/ emcc a.c +HOME=/emsdk-portable/ emcc -s BINARYEN=1 a.c +rm -f a.* + +# Make emsdk usable by any user +cp /root/.emscripten /emsdk-portable +chmod a+rxw -R /emsdk-portable + +# node 8 is required to run wasm +cd / +curl -L https://nodejs.org/dist/v8.0.0/node-v8.0.0-linux-x64.tar.xz | \ + tar -xJ diff --git a/src/ci/docker/x86_64-gnu/Dockerfile b/src/ci/docker/x86_64-gnu/Dockerfile index de85e1ff36af..0bbbded57f27 100644 --- a/src/ci/docker/x86_64-gnu/Dockerfile +++ b/src/ci/docker/x86_64-gnu/Dockerfile @@ -22,5 +22,5 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini rm dumb-init_*.deb ENTRYPOINT ["/usr/bin/dumb-init", "--"] -ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu --enable-sanitizers +ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu --enable-sanitizers --enable-profiler ENV SCRIPT python2.7 ../x.py test diff --git a/src/ci/init_repo.sh b/src/ci/init_repo.sh index 282da009eac3..817ed8dd5543 100755 --- a/src/ci/init_repo.sh +++ b/src/ci/init_repo.sh @@ -22,9 +22,6 @@ 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" @@ -36,47 +33,19 @@ if [ ! -d "$CACHE_DIR" ]; then 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 - echo "Invalid cache, wiping ($cache_valid_file missing)" - 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 - echo "Valid cache ($cache_valid_file exists)" - rm "$cache_valid_file" - fi -fi +rm -rf "$CACHE_DIR" +mkdir "$CACHE_DIR" travis_fold start update_cache travis_time_start # 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 "rm -rf $cache_src_dir && mkdir -p $cache_src_dir && \ + git clone --depth 1 https://github.com/rust-lang/rust.git $cache_src_dir" (cd $cache_src_dir && git rm src/llvm) 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 -echo "Refreshed cache (touch $cache_valid_file)" -touch "$cache_valid_file" - travis_fold end update_cache travis_time_finish diff --git a/src/doc/book b/src/doc/book index f746084b0990..325c3da0814f 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit f746084b099060f55ac5e7d8050797593fcedd6e +Subproject commit 325c3da0814f44916bef00ff225f934f2d613203 diff --git a/src/doc/grammar.md b/src/doc/grammar.md index 12daa24e857f..78432b6a9659 100644 --- a/src/doc/grammar.md +++ b/src/doc/grammar.md @@ -154,19 +154,19 @@ token : simple_token | ident | literal | symbol | whitespace token ;

-| | | | | | -|----------|----------|----------|----------|---------| -| abstract | alignof | as | become | box | -| break | const | continue | crate | do | -| else | enum | extern | false | final | -| fn | for | if | impl | in | -| let | loop | macro | match | mod | -| move | mut | offsetof | override | priv | -| proc | pub | pure | ref | return | -| Self | self | sizeof | static | struct | -| super | trait | true | type | typeof | -| unsafe | unsized | use | virtual | where | -| while | yield | | | | +| | | | | | +|----------|----------|----------|----------|----------| +| _ | abstract | alignof | as | become | +| box | break | const | continue | crate | +| do | else | enum | extern | false | +| final | fn | for | if | impl | +| in | let | loop | macro | match | +| mod | move | mut | offsetof | override | +| priv | proc | pub | pure | ref | +| return | Self | self | sizeof | static | +| struct | super | trait | true | type | +| typeof | unsafe | unsized | use | virtual | +| where | while | yield | | | Each of these keywords has special meaning in its grammar, and all of them are diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md deleted file mode 100644 index 2b3ef338fad5..000000000000 --- a/src/doc/unstable-book/src/SUMMARY.md +++ /dev/null @@ -1,222 +0,0 @@ -[The Unstable Book](the-unstable-book.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_thiscall](language-features/abi-thiscall.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) - - [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) - - [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) - - [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) - - [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) - - [iterator_step_by](library-features/iterator-step-by.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) - - [placement_in](library-features/placement-in.md) - - [placement_new_protocol](library-features/placement-new-protocol.md) - - [print_internals](library-features/print-internals.md) - - [proc_macro_internals](library-features/proc-macro-internals.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) - - [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_rotate](library-features/slice-rotate.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) - - [try_trait](library-features/try-trait.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_resize_default](library-features/vec-resize-default.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/compiler-flags/profile.md b/src/doc/unstable-book/src/compiler-flags/profile.md new file mode 100644 index 000000000000..66d14fd09978 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/profile.md @@ -0,0 +1,21 @@ +# `profile` + +The tracking issue for this feature is: [#42524](https://github.com/rust-lang/rust/issues/42524). + +------------------------ + +This feature allows the generation of code coverage reports. + +Set the `-Zprofile` compiler flag in order to enable gcov profiling. + +For example: +```Bash +cargo new testgcov --bin +cd testgcov +export RUSTFLAGS="-Zprofile" +cargo build +cargo run +``` + +Once you've built and run your program, files with the `gcno` (after build) and `gcda` (after execution) extensions will be created. +You can parse them with [llvm-cov gcov](http://llvm.org/docs/CommandGuide/llvm-cov.html#llvm-cov-gcov) or [grcov](https://github.com/marco-c/grcov). diff --git a/src/doc/unstable-book/src/language-features/abi-sysv64.md b/src/doc/unstable-book/src/language-features/abi-sysv64.md deleted file mode 100644 index 27f61d56342c..000000000000 --- a/src/doc/unstable-book/src/language-features/abi-sysv64.md +++ /dev/null @@ -1,7 +0,0 @@ -# `abi_sysv64` - -The tracking issue for this feature is: [#36167] - -[#36167]: https://github.com/rust-lang/rust/issues/36167 - ------------------------- diff --git a/src/doc/unstable-book/src/language-features/abi-unadjusted.md b/src/doc/unstable-book/src/language-features/abi-unadjusted.md deleted file mode 100644 index 2e3113abdbf2..000000000000 --- a/src/doc/unstable-book/src/language-features/abi-unadjusted.md +++ /dev/null @@ -1,6 +0,0 @@ -# `abi_unadjusted` - -The tracking issue for this feature is: none. - ------------------------- - diff --git a/src/doc/unstable-book/src/language-features/abi-vectorcall.md b/src/doc/unstable-book/src/language-features/abi-vectorcall.md deleted file mode 100644 index 3e36b1569fd4..000000000000 --- a/src/doc/unstable-book/src/language-features/abi-vectorcall.md +++ /dev/null @@ -1,7 +0,0 @@ -# `abi_vectorcall` - -The tracking issue for this feature is: none. - ------------------------- - - diff --git a/src/doc/unstable-book/src/language-features/abi-x86-interrupt.md b/src/doc/unstable-book/src/language-features/abi-x86-interrupt.md deleted file mode 100644 index c89d2ee2106c..000000000000 --- a/src/doc/unstable-book/src/language-features/abi-x86-interrupt.md +++ /dev/null @@ -1,7 +0,0 @@ -# `abi_x86_interrupt` - -The tracking issue for this feature is: [#40180] - -[#40180]: https://github.com/rust-lang/rust/issues/40180 - ------------------------- diff --git a/src/doc/unstable-book/src/language-features/allow-internal-unstable.md b/src/doc/unstable-book/src/language-features/allow-internal-unstable.md deleted file mode 100644 index 74709ad5aeb4..000000000000 --- a/src/doc/unstable-book/src/language-features/allow-internal-unstable.md +++ /dev/null @@ -1,6 +0,0 @@ -# `allow_internal_unstable` - -The tracking issue for this feature is: None. - ------------------------- - diff --git a/src/doc/unstable-book/src/language-features/asm.md b/src/doc/unstable-book/src/language-features/asm.md index 8deb8f462562..f22095fe5de2 100644 --- a/src/doc/unstable-book/src/language-features/asm.md +++ b/src/doc/unstable-book/src/language-features/asm.md @@ -190,4 +190,4 @@ constraints, etc. [llvm-docs]: http://llvm.org/docs/LangRef.html#inline-assembler-expressions If you need more power and don't mind losing some of the niceties of -`asm!`, check out [global_asm](language-features/global_asm.html). +`asm!`, check out [global_asm](language-features/global-asm.html). diff --git a/src/doc/unstable-book/src/language-features/associated-type-defaults.md b/src/doc/unstable-book/src/language-features/associated-type-defaults.md deleted file mode 100644 index 56cc8a5b3060..000000000000 --- a/src/doc/unstable-book/src/language-features/associated-type-defaults.md +++ /dev/null @@ -1,10 +0,0 @@ -# `associated_type_defaults` - -The tracking issue for this feature is: [#29661] - -[#29661]: https://github.com/rust-lang/rust/issues/29661 - ------------------------- - - - diff --git a/src/doc/unstable-book/src/language-features/cfg-target-feature.md b/src/doc/unstable-book/src/language-features/cfg-target-feature.md deleted file mode 100644 index ddd88bdc2cb1..000000000000 --- a/src/doc/unstable-book/src/language-features/cfg-target-feature.md +++ /dev/null @@ -1,10 +0,0 @@ -# `cfg_target_feature` - -The tracking issue for this feature is: [#29717] - -[#29717]: https://github.com/rust-lang/rust/issues/29717 - ------------------------- - - - diff --git a/src/doc/unstable-book/src/language-features/cfg-target-has-atomic.md b/src/doc/unstable-book/src/language-features/cfg-target-has-atomic.md deleted file mode 100644 index 7496e42e1cd8..000000000000 --- a/src/doc/unstable-book/src/language-features/cfg-target-has-atomic.md +++ /dev/null @@ -1,10 +0,0 @@ -# `cfg_target_has_atomic` - -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/language-features/cfg-target-thread-local.md b/src/doc/unstable-book/src/language-features/cfg-target-thread-local.md deleted file mode 100644 index a5adb38db3df..000000000000 --- a/src/doc/unstable-book/src/language-features/cfg-target-thread-local.md +++ /dev/null @@ -1,10 +0,0 @@ -# `cfg_target_thread_local` - -The tracking issue for this feature is: [#29594] - -[#29594]: https://github.com/rust-lang/rust/issues/29594 - ------------------------- - - - diff --git a/src/doc/unstable-book/src/language-features/cfg-target-vendor.md b/src/doc/unstable-book/src/language-features/cfg-target-vendor.md deleted file mode 100644 index ddd88bdc2cb1..000000000000 --- a/src/doc/unstable-book/src/language-features/cfg-target-vendor.md +++ /dev/null @@ -1,10 +0,0 @@ -# `cfg_target_feature` - -The tracking issue for this feature is: [#29717] - -[#29717]: https://github.com/rust-lang/rust/issues/29717 - ------------------------- - - - diff --git a/src/doc/unstable-book/src/language-features/custom-attribute.md b/src/doc/unstable-book/src/language-features/custom-attribute.md deleted file mode 100644 index 838f09670d2c..000000000000 --- a/src/doc/unstable-book/src/language-features/custom-attribute.md +++ /dev/null @@ -1,10 +0,0 @@ -# `custom_attribute` - -The tracking issue for this feature is: [#29642] - -[#29642]: https://github.com/rust-lang/rust/issues/29642 - ------------------------- - - - diff --git a/src/doc/unstable-book/src/language-features/custom-derive.md b/src/doc/unstable-book/src/language-features/custom-derive.md deleted file mode 100644 index d5fdd2b708bb..000000000000 --- a/src/doc/unstable-book/src/language-features/custom-derive.md +++ /dev/null @@ -1,10 +0,0 @@ -# `custom_derive` - -The tracking issue for this feature is: [#29644] - -[#29644]: https://github.com/rust-lang/rust/issues/29644 - ------------------------- - - - diff --git a/src/doc/unstable-book/src/language-features/decl-macro.md b/src/doc/unstable-book/src/language-features/decl-macro.md deleted file mode 100644 index 4700b252e2d1..000000000000 --- a/src/doc/unstable-book/src/language-features/decl-macro.md +++ /dev/null @@ -1,10 +0,0 @@ -# `decl_macro` - -The tracking issue for this feature is: [#39412] - -[#39412]: https://github.com/rust-lang/rust/issues/39412 - ------------------------- - - - diff --git a/src/doc/unstable-book/src/language-features/default-type-parameter-fallback.md b/src/doc/unstable-book/src/language-features/default-type-parameter-fallback.md deleted file mode 100644 index fd16dbf89853..000000000000 --- a/src/doc/unstable-book/src/language-features/default-type-parameter-fallback.md +++ /dev/null @@ -1,10 +0,0 @@ -# `default_type_parameter_fallback` - -The tracking issue for this feature is: [#27336] - -[#27336]: https://github.com/rust-lang/rust/issues/27336 - ------------------------- - - - diff --git a/src/doc/unstable-book/src/language-features/drop-types-in-const.md b/src/doc/unstable-book/src/language-features/drop-types-in-const.md deleted file mode 100644 index b3367d0df445..000000000000 --- a/src/doc/unstable-book/src/language-features/drop-types-in-const.md +++ /dev/null @@ -1,10 +0,0 @@ -# `drop_types_in_const` - -The tracking issue for this feature is: [#33156] - -[#33156]: https://github.com/rust-lang/rust/issues/33156 - ------------------------- - - - diff --git a/src/doc/unstable-book/src/language-features/dropck-eyepatch.md b/src/doc/unstable-book/src/language-features/dropck-eyepatch.md deleted file mode 100644 index 2f189e9b6454..000000000000 --- a/src/doc/unstable-book/src/language-features/dropck-eyepatch.md +++ /dev/null @@ -1,10 +0,0 @@ -# `dropck_eyepatch` - -The tracking issue for this feature is: [#34761] - -[#34761]: https://github.com/rust-lang/rust/issues/34761 - ------------------------- - - - diff --git a/src/doc/unstable-book/src/language-features/dropck-parametricity.md b/src/doc/unstable-book/src/language-features/dropck-parametricity.md deleted file mode 100644 index c5ae721954b8..000000000000 --- a/src/doc/unstable-book/src/language-features/dropck-parametricity.md +++ /dev/null @@ -1,10 +0,0 @@ -# `dropck_parametricity` - -The tracking issue for this feature is: [#28498] - -[#28498]: https://github.com/rust-lang/rust/issues/28498 - ------------------------- - - - diff --git a/src/doc/unstable-book/src/language-features/exclusive-range-pattern.md b/src/doc/unstable-book/src/language-features/exclusive-range-pattern.md deleted file mode 100644 index b669ce83132d..000000000000 --- a/src/doc/unstable-book/src/language-features/exclusive-range-pattern.md +++ /dev/null @@ -1,10 +0,0 @@ -# `exclusive_range_pattern` - -The tracking issue for this feature is: [#37854] - -[#37854]: https://github.com/rust-lang/rust/issues/37854 - ------------------------- - - - diff --git a/src/doc/unstable-book/src/language-features/fundamental.md b/src/doc/unstable-book/src/language-features/fundamental.md deleted file mode 100644 index a068dadf95d1..000000000000 --- a/src/doc/unstable-book/src/language-features/fundamental.md +++ /dev/null @@ -1,10 +0,0 @@ -# `fundamental` - -The tracking issue for this feature is: [#29635] - -[#29635]: https://github.com/rust-lang/rust/issues/29635 - ------------------------- - - - diff --git a/src/doc/unstable-book/src/language-features/generic-param-attrs.md b/src/doc/unstable-book/src/language-features/generic-param-attrs.md deleted file mode 100644 index ba49c850e4d6..000000000000 --- a/src/doc/unstable-book/src/language-features/generic-param-attrs.md +++ /dev/null @@ -1,10 +0,0 @@ -# `generic_param_attrs` - -The tracking issue for this feature is: [#34761] - -[#34761]: https://github.com/rust-lang/rust/issues/34761 - ------------------------- - - - diff --git a/src/doc/unstable-book/src/language-features/global_asm.md b/src/doc/unstable-book/src/language-features/global-asm.md similarity index 100% rename from src/doc/unstable-book/src/language-features/global_asm.md rename to src/doc/unstable-book/src/language-features/global-asm.md diff --git a/src/doc/unstable-book/src/language-features/link-cfg.md b/src/doc/unstable-book/src/language-features/link-cfg.md deleted file mode 100644 index 7393d0628e4f..000000000000 --- a/src/doc/unstable-book/src/language-features/link-cfg.md +++ /dev/null @@ -1,10 +0,0 @@ -# `link_cfg` - -The tracking issue for this feature is: [#37406] - -[#37406]: https://github.com/rust-lang/rust/issues/37406 - ------------------------- - - - diff --git a/src/doc/unstable-book/src/language-features/link-llvm-intrinsics.md b/src/doc/unstable-book/src/language-features/link-llvm-intrinsics.md deleted file mode 100644 index ba639cb57fc6..000000000000 --- a/src/doc/unstable-book/src/language-features/link-llvm-intrinsics.md +++ /dev/null @@ -1,10 +0,0 @@ -# `link_llvm_intrinsics` - -The tracking issue for this feature is: [#29602] - -[#29602]: https://github.com/rust-lang/rust/issues/29602 - ------------------------- - - - diff --git a/src/doc/unstable-book/src/language-features/linkage.md b/src/doc/unstable-book/src/language-features/linkage.md deleted file mode 100644 index 5773d28a00ec..000000000000 --- a/src/doc/unstable-book/src/language-features/linkage.md +++ /dev/null @@ -1,10 +0,0 @@ -# `linkage` - -The tracking issue for this feature is: [#29603] - -[#29603]: https://github.com/rust-lang/rust/issues/29603 - ------------------------- - - - diff --git a/src/doc/unstable-book/src/language-features/log-syntax.md b/src/doc/unstable-book/src/language-features/log-syntax.md deleted file mode 100644 index b13f5ccfd917..000000000000 --- a/src/doc/unstable-book/src/language-features/log-syntax.md +++ /dev/null @@ -1,10 +0,0 @@ -# `log_syntax` - -The tracking issue for this feature is: [#29598] - -[#29598]: https://github.com/rust-lang/rust/issues/29598 - ------------------------- - - - diff --git a/src/doc/unstable-book/src/language-features/macro-reexport.md b/src/doc/unstable-book/src/language-features/macro-reexport.md deleted file mode 100644 index 32ffa3b4c31e..000000000000 --- a/src/doc/unstable-book/src/language-features/macro-reexport.md +++ /dev/null @@ -1,10 +0,0 @@ -# `macro_reexport` - -The tracking issue for this feature is: [#29638] - -[#29638]: https://github.com/rust-lang/rust/issues/29638 - ------------------------- - - - diff --git a/src/doc/unstable-book/src/language-features/main.md b/src/doc/unstable-book/src/language-features/main.md deleted file mode 100644 index 579aabfff88b..000000000000 --- a/src/doc/unstable-book/src/language-features/main.md +++ /dev/null @@ -1,10 +0,0 @@ -# `main` - -The tracking issue for this feature is: [#29634] - -[#29634]: https://github.com/rust-lang/rust/issues/29634 - ------------------------- - - - diff --git a/src/doc/unstable-book/src/language-features/naked-functions.md b/src/doc/unstable-book/src/language-features/naked-functions.md deleted file mode 100644 index e56ce4770aab..000000000000 --- a/src/doc/unstable-book/src/language-features/naked-functions.md +++ /dev/null @@ -1,10 +0,0 @@ -# `naked_functions` - -The tracking issue for this feature is: [#32408] - -[#32408]: https://github.com/rust-lang/rust/issues/32408 - ------------------------- - - - diff --git a/src/doc/unstable-book/src/language-features/needs-allocator.md b/src/doc/unstable-book/src/language-features/needs-allocator.md deleted file mode 100644 index 22aa10b2183c..000000000000 --- a/src/doc/unstable-book/src/language-features/needs-allocator.md +++ /dev/null @@ -1,10 +0,0 @@ -# `needs_allocator` - -The tracking issue for this feature is: [#27389] - -[#27389]: https://github.com/rust-lang/rust/issues/27389 - ------------------------- - - - diff --git a/src/doc/unstable-book/src/language-features/needs-panic-runtime.md b/src/doc/unstable-book/src/language-features/needs-panic-runtime.md deleted file mode 100644 index 627c946c1bb2..000000000000 --- a/src/doc/unstable-book/src/language-features/needs-panic-runtime.md +++ /dev/null @@ -1,10 +0,0 @@ -# `needs_panic_runtime` - -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/language-features/never-type.md b/src/doc/unstable-book/src/language-features/never-type.md deleted file mode 100644 index 3b3729a4b21d..000000000000 --- a/src/doc/unstable-book/src/language-features/never-type.md +++ /dev/null @@ -1,10 +0,0 @@ -# `never_type` - -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/language-features/no-core.md b/src/doc/unstable-book/src/language-features/no-core.md deleted file mode 100644 index 6238753447c9..000000000000 --- a/src/doc/unstable-book/src/language-features/no-core.md +++ /dev/null @@ -1,10 +0,0 @@ -# `no_core` - -The tracking issue for this feature is: [#29639] - -[#29639]: https://github.com/rust-lang/rust/issues/29639 - ------------------------- - - - diff --git a/src/doc/unstable-book/src/language-features/no-debug.md b/src/doc/unstable-book/src/language-features/no-debug.md deleted file mode 100644 index 7536ed9d4e10..000000000000 --- a/src/doc/unstable-book/src/language-features/no-debug.md +++ /dev/null @@ -1,10 +0,0 @@ -# `no_debug` - -The tracking issue for this feature is: [#29721] - -[#29721]: https://github.com/rust-lang/rust/issues/29721 - ------------------------- - - - diff --git a/src/doc/unstable-book/src/language-features/omit-gdb-pretty-printer-section.md b/src/doc/unstable-book/src/language-features/omit-gdb-pretty-printer-section.md deleted file mode 100644 index d8ac520fcb5e..000000000000 --- a/src/doc/unstable-book/src/language-features/omit-gdb-pretty-printer-section.md +++ /dev/null @@ -1,6 +0,0 @@ -# `omit_gdb_pretty_printer_section` - -The tracking issue for this feature is: None. - ------------------------- - diff --git a/src/doc/unstable-book/src/language-features/optin-builtin-traits.md b/src/doc/unstable-book/src/language-features/optin-builtin-traits.md deleted file mode 100644 index 0b2d60accd59..000000000000 --- a/src/doc/unstable-book/src/language-features/optin-builtin-traits.md +++ /dev/null @@ -1,9 +0,0 @@ -# `optin_builtin_traits` - -The tracking issue for this feature is: [#13231] - -[#13231]: https://github.com/rust-lang/rust/issues/13231 - ------------------------- - - 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 deleted file mode 100644 index a4920839c6ca..000000000000 --- a/src/doc/unstable-book/src/language-features/overlapping-marker-traits.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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/language-features/panic-runtime.md b/src/doc/unstable-book/src/language-features/panic-runtime.md deleted file mode 100644 index 65b067e82961..000000000000 --- a/src/doc/unstable-book/src/language-features/panic-runtime.md +++ /dev/null @@ -1,10 +0,0 @@ -# `panic_runtime` - -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/language-features/placement-in-syntax.md b/src/doc/unstable-book/src/language-features/placement-in-syntax.md deleted file mode 100644 index da12559a01b8..000000000000 --- a/src/doc/unstable-book/src/language-features/placement-in-syntax.md +++ /dev/null @@ -1,10 +0,0 @@ -# `placement_in_syntax` - -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/language-features/platform-intrinsics.md b/src/doc/unstable-book/src/language-features/platform-intrinsics.md deleted file mode 100644 index 377ac8f7342e..000000000000 --- a/src/doc/unstable-book/src/language-features/platform-intrinsics.md +++ /dev/null @@ -1,10 +0,0 @@ -# `platform_intrinsics` - -The tracking issue for this feature is: [#27731] - -[#27731]: https://github.com/rust-lang/rust/issues/27731 - ------------------------- - - - diff --git a/src/doc/unstable-book/src/language-features/prelude-import.md b/src/doc/unstable-book/src/language-features/prelude-import.md deleted file mode 100644 index 75dae5cfb740..000000000000 --- a/src/doc/unstable-book/src/language-features/prelude-import.md +++ /dev/null @@ -1,6 +0,0 @@ -# `prelude_import` - -The tracking issue for this feature is: None. - ------------------------- - diff --git a/src/doc/unstable-book/src/language-features/profiler-runtime.md b/src/doc/unstable-book/src/language-features/profiler-runtime.md new file mode 100644 index 000000000000..aee86f63952a --- /dev/null +++ b/src/doc/unstable-book/src/language-features/profiler-runtime.md @@ -0,0 +1,5 @@ +# `profiler_runtime` + +The tracking issue for this feature is: [#42524](https://github.com/rust-lang/rust/issues/42524). + +------------------------ diff --git a/src/doc/unstable-book/src/language-features/quote.md b/src/doc/unstable-book/src/language-features/quote.md deleted file mode 100644 index b4e078d920c4..000000000000 --- a/src/doc/unstable-book/src/language-features/quote.md +++ /dev/null @@ -1,10 +0,0 @@ -# `quote` - -The tracking issue for this feature is: [#29601] - -[#29601]: https://github.com/rust-lang/rust/issues/29601 - ------------------------- - - - diff --git a/src/doc/unstable-book/src/language-features/repr-align.md b/src/doc/unstable-book/src/language-features/repr-align.md deleted file mode 100644 index deea04f4c51c..000000000000 --- a/src/doc/unstable-book/src/language-features/repr-align.md +++ /dev/null @@ -1,11 +0,0 @@ -# `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/language-features/repr-simd.md b/src/doc/unstable-book/src/language-features/repr-simd.md deleted file mode 100644 index c6f051e4fffc..000000000000 --- a/src/doc/unstable-book/src/language-features/repr-simd.md +++ /dev/null @@ -1,10 +0,0 @@ -# `repr_simd` - -The tracking issue for this feature is: [#27731] - -[#27731]: https://github.com/rust-lang/rust/issues/27731 - ------------------------- - - - diff --git a/src/doc/unstable-book/src/language-features/rustc-attrs.md b/src/doc/unstable-book/src/language-features/rustc-attrs.md deleted file mode 100644 index d1f18cead068..000000000000 --- a/src/doc/unstable-book/src/language-features/rustc-attrs.md +++ /dev/null @@ -1,10 +0,0 @@ -# `rustc_attrs` - -The tracking issue for this feature is: [#29642] - -[#29642]: https://github.com/rust-lang/rust/issues/29642 - ------------------------- - - - diff --git a/src/doc/unstable-book/src/language-features/rustc-diagnostic-macros.md b/src/doc/unstable-book/src/language-features/rustc-diagnostic-macros.md deleted file mode 100644 index 0df6ca12089e..000000000000 --- a/src/doc/unstable-book/src/language-features/rustc-diagnostic-macros.md +++ /dev/null @@ -1,6 +0,0 @@ -# `rustc_diagnostic_macros` - -The tracking issue for this feature is: None. - ------------------------- - diff --git a/src/doc/unstable-book/src/language-features/sanitizer-runtime.md b/src/doc/unstable-book/src/language-features/sanitizer-runtime.md deleted file mode 100644 index f19504de58e1..000000000000 --- a/src/doc/unstable-book/src/language-features/sanitizer-runtime.md +++ /dev/null @@ -1,6 +0,0 @@ -# `sanitizer_runtime` - -The tracking issue for this feature is: None. - ------------------------- - diff --git a/src/doc/unstable-book/src/language-features/simd-ffi.md b/src/doc/unstable-book/src/language-features/simd-ffi.md deleted file mode 100644 index d85779c3d3dc..000000000000 --- a/src/doc/unstable-book/src/language-features/simd-ffi.md +++ /dev/null @@ -1,10 +0,0 @@ -# `simd_ffi` - -The tracking issue for this feature is: [#27731] - -[#27731]: https://github.com/rust-lang/rust/issues/27731 - ------------------------- - - - diff --git a/src/doc/unstable-book/src/language-features/simd.md b/src/doc/unstable-book/src/language-features/simd.md deleted file mode 100644 index 13c9722c5243..000000000000 --- a/src/doc/unstable-book/src/language-features/simd.md +++ /dev/null @@ -1,10 +0,0 @@ -# `simd` - -The tracking issue for this feature is: [#27731] - -[#27731]: https://github.com/rust-lang/rust/issues/27731 - ------------------------- - - - diff --git a/src/doc/unstable-book/src/language-features/specialization.md b/src/doc/unstable-book/src/language-features/specialization.md deleted file mode 100644 index efc380df6e11..000000000000 --- a/src/doc/unstable-book/src/language-features/specialization.md +++ /dev/null @@ -1,10 +0,0 @@ -# `specialization` - -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/language-features/staged-api.md b/src/doc/unstable-book/src/language-features/staged-api.md deleted file mode 100644 index 1409e570e887..000000000000 --- a/src/doc/unstable-book/src/language-features/staged-api.md +++ /dev/null @@ -1,6 +0,0 @@ -# `staged_api` - -The tracking issue for this feature is: None. - ------------------------- - diff --git a/src/doc/unstable-book/src/language-features/start.md b/src/doc/unstable-book/src/language-features/start.md deleted file mode 100644 index 1ea6d59c78d5..000000000000 --- a/src/doc/unstable-book/src/language-features/start.md +++ /dev/null @@ -1,10 +0,0 @@ -# `start` - -The tracking issue for this feature is: [#29633] - -[#29633]: https://github.com/rust-lang/rust/issues/29633 - ------------------------- - - - diff --git a/src/doc/unstable-book/src/language-features/static-nobundle.md b/src/doc/unstable-book/src/language-features/static-nobundle.md deleted file mode 100644 index 97b9d71d433a..000000000000 --- a/src/doc/unstable-book/src/language-features/static-nobundle.md +++ /dev/null @@ -1,10 +0,0 @@ -# `static_nobundle` - -The tracking issue for this feature is: [#37403] - -[#37403]: https://github.com/rust-lang/rust/issues/37403 - ------------------------- - - - diff --git a/src/doc/unstable-book/src/language-features/stmt-expr-attributes.md b/src/doc/unstable-book/src/language-features/stmt-expr-attributes.md deleted file mode 100644 index 71092fcf2904..000000000000 --- a/src/doc/unstable-book/src/language-features/stmt-expr-attributes.md +++ /dev/null @@ -1,10 +0,0 @@ -# `stmt_expr_attributes` - -The tracking issue for this feature is: [#15701] - -[#15701]: https://github.com/rust-lang/rust/issues/15701 - ------------------------- - - - diff --git a/src/doc/unstable-book/src/language-features/struct-field-attributes.md b/src/doc/unstable-book/src/language-features/struct-field-attributes.md deleted file mode 100644 index 1a94562968d1..000000000000 --- a/src/doc/unstable-book/src/language-features/struct-field-attributes.md +++ /dev/null @@ -1,10 +0,0 @@ -# `struct_field_attributes` - -The tracking issue for this feature is: [#38814] - -[#38814]: https://github.com/rust-lang/rust/issues/38814 - ------------------------- - - - diff --git a/src/doc/unstable-book/src/language-features/structural-match.md b/src/doc/unstable-book/src/language-features/structural-match.md deleted file mode 100644 index b3ca26e6474d..000000000000 --- a/src/doc/unstable-book/src/language-features/structural-match.md +++ /dev/null @@ -1,10 +0,0 @@ -# `structural_match` - -The tracking issue for this feature is: [#31434] - -[#31434]: https://github.com/rust-lang/rust/issues/31434 - ------------------------- - - - diff --git a/src/doc/unstable-book/src/language-features/target-feature.md b/src/doc/unstable-book/src/language-features/target-feature.md deleted file mode 100644 index 85ab1ab39efe..000000000000 --- a/src/doc/unstable-book/src/language-features/target-feature.md +++ /dev/null @@ -1,6 +0,0 @@ -# `target_feature` - -The tracking issue for this feature is: None. - ------------------------- - diff --git a/src/doc/unstable-book/src/language-features/thread-local.md b/src/doc/unstable-book/src/language-features/thread-local.md deleted file mode 100644 index 83de2f9cd4b5..000000000000 --- a/src/doc/unstable-book/src/language-features/thread-local.md +++ /dev/null @@ -1,10 +0,0 @@ -# `thread_local` - -The tracking issue for this feature is: [#29594] - -[#29594]: https://github.com/rust-lang/rust/issues/29594 - ------------------------- - - - diff --git a/src/doc/unstable-book/src/language-features/trace-macros.md b/src/doc/unstable-book/src/language-features/trace-macros.md deleted file mode 100644 index 856f1b0a7bbb..000000000000 --- a/src/doc/unstable-book/src/language-features/trace-macros.md +++ /dev/null @@ -1,10 +0,0 @@ -# `trace_macros` - -The tracking issue for this feature is: [#29598] - -[#29598]: https://github.com/rust-lang/rust/issues/29598 - ------------------------- - - - diff --git a/src/doc/unstable-book/src/language-features/type-ascription.md b/src/doc/unstable-book/src/language-features/type-ascription.md deleted file mode 100644 index 3ebd0d87ccff..000000000000 --- a/src/doc/unstable-book/src/language-features/type-ascription.md +++ /dev/null @@ -1,10 +0,0 @@ -# `type_ascription` - -The tracking issue for this feature is: [#23416] - -[#23416]: https://github.com/rust-lang/rust/issues/23416 - ------------------------- - - - diff --git a/src/doc/unstable-book/src/language-features/unboxed-closures.md b/src/doc/unstable-book/src/language-features/unboxed-closures.md deleted file mode 100644 index 2cbb436ce0bb..000000000000 --- a/src/doc/unstable-book/src/language-features/unboxed-closures.md +++ /dev/null @@ -1,10 +0,0 @@ -# `unboxed_closures` - -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/language-features/untagged-unions.md b/src/doc/unstable-book/src/language-features/untagged-unions.md deleted file mode 100644 index 6fe4f088ac23..000000000000 --- a/src/doc/unstable-book/src/language-features/untagged-unions.md +++ /dev/null @@ -1,10 +0,0 @@ -# `untagged_unions` - -The tracking issue for this feature is: [#32836] - -[#32836]: https://github.com/rust-lang/rust/issues/32836 - ------------------------- - - - diff --git a/src/doc/unstable-book/src/language-features/unwind-attributes.md b/src/doc/unstable-book/src/language-features/unwind-attributes.md deleted file mode 100644 index 0167a33b081a..000000000000 --- a/src/doc/unstable-book/src/language-features/unwind-attributes.md +++ /dev/null @@ -1,6 +0,0 @@ -# `unwind_attributes` - -The tracking issue for this feature is: None. - ------------------------- - diff --git a/src/doc/unstable-book/src/language-features/use-extern-macros.md b/src/doc/unstable-book/src/language-features/use-extern-macros.md deleted file mode 100644 index bc6149115028..000000000000 --- a/src/doc/unstable-book/src/language-features/use-extern-macros.md +++ /dev/null @@ -1,10 +0,0 @@ -# `use_extern_macros` - -The tracking issue for this feature is: [#35896] - -[#35896]: https://github.com/rust-lang/rust/issues/35896 - ------------------------- - - - diff --git a/src/doc/unstable-book/src/library-features/alloc.md b/src/doc/unstable-book/src/library-features/alloc.md deleted file mode 100644 index 47eeb0874fba..000000000000 --- a/src/doc/unstable-book/src/library-features/alloc.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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 deleted file mode 100644 index ed32eedb3481..000000000000 --- a/src/doc/unstable-book/src/library-features/as-c-str.md +++ /dev/null @@ -1,8 +0,0 @@ -# `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 deleted file mode 100644 index e253b4dcd9b5..000000000000 --- a/src/doc/unstable-book/src/library-features/ascii-ctype.md +++ /dev/null @@ -1,5 +0,0 @@ -# `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/box-heap.md b/src/doc/unstable-book/src/library-features/box-heap.md deleted file mode 100644 index 0f3f01ba0e16..000000000000 --- a/src/doc/unstable-book/src/library-features/box-heap.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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/char-escape-debug.md b/src/doc/unstable-book/src/library-features/char-escape-debug.md deleted file mode 100644 index 21aa486219e0..000000000000 --- a/src/doc/unstable-book/src/library-features/char-escape-debug.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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 deleted file mode 100644 index 078d3faf42a7..000000000000 --- a/src/doc/unstable-book/src/library-features/coerce-unsized.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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 deleted file mode 100644 index 268ca6ea590d..000000000000 --- a/src/doc/unstable-book/src/library-features/collection-placement.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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 deleted file mode 100644 index ea4f999ba0f9..000000000000 --- a/src/doc/unstable-book/src/library-features/collections-range.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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/command-envs.md b/src/doc/unstable-book/src/library-features/command-envs.md deleted file mode 100644 index 0ab89e278cdf..000000000000 --- a/src/doc/unstable-book/src/library-features/command-envs.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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/concat-idents-macro.md b/src/doc/unstable-book/src/library-features/concat-idents-macro.md deleted file mode 100644 index ac2fdd4fceb6..000000000000 --- a/src/doc/unstable-book/src/library-features/concat-idents-macro.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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 deleted file mode 100644 index d37d6b5c6d0b..000000000000 --- a/src/doc/unstable-book/src/library-features/core-char-ext.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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 deleted file mode 100644 index 194b2608dd02..000000000000 --- a/src/doc/unstable-book/src/library-features/core-float.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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-slice-ext.md b/src/doc/unstable-book/src/library-features/core-slice-ext.md deleted file mode 100644 index c50d44ac0ce3..000000000000 --- a/src/doc/unstable-book/src/library-features/core-slice-ext.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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 deleted file mode 100644 index 08c68f11c6ec..000000000000 --- a/src/doc/unstable-book/src/library-features/core-str-ext.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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/decode-utf8.md b/src/doc/unstable-book/src/library-features/decode-utf8.md deleted file mode 100644 index b96854ebcd46..000000000000 --- a/src/doc/unstable-book/src/library-features/decode-utf8.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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/discriminant-value.md b/src/doc/unstable-book/src/library-features/discriminant-value.md deleted file mode 100644 index 2f99f5ecab39..000000000000 --- a/src/doc/unstable-book/src/library-features/discriminant-value.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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 deleted file mode 100644 index be7a3ffd4dc4..000000000000 --- a/src/doc/unstable-book/src/library-features/error-type-id.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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 deleted file mode 100644 index 200ec3872517..000000000000 --- a/src/doc/unstable-book/src/library-features/exact-size-is-empty.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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/fixed-size-array.md b/src/doc/unstable-book/src/library-features/fixed-size-array.md deleted file mode 100644 index 9e24e6a0850d..000000000000 --- a/src/doc/unstable-book/src/library-features/fixed-size-array.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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 deleted file mode 100644 index f519545ac78b..000000000000 --- a/src/doc/unstable-book/src/library-features/float-bits-conv.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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/fmt-flags-align.md b/src/doc/unstable-book/src/library-features/fmt-flags-align.md deleted file mode 100644 index 755263bd9a61..000000000000 --- a/src/doc/unstable-book/src/library-features/fmt-flags-align.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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/fn-traits.md b/src/doc/unstable-book/src/library-features/fn-traits.md deleted file mode 100644 index 3942cda55388..000000000000 --- a/src/doc/unstable-book/src/library-features/fn-traits.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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 deleted file mode 100644 index a9b74d4f0047..000000000000 --- a/src/doc/unstable-book/src/library-features/fnbox.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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 deleted file mode 100644 index 570f779417f0..000000000000 --- a/src/doc/unstable-book/src/library-features/from_utf8_error_as_bytes.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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 deleted file mode 100644 index 460555bf1b0d..000000000000 --- a/src/doc/unstable-book/src/library-features/fused.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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/get-type-id.md b/src/doc/unstable-book/src/library-features/get-type-id.md deleted file mode 100644 index afdb030c406d..000000000000 --- a/src/doc/unstable-book/src/library-features/get-type-id.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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 deleted file mode 100644 index 01404e49dbda..000000000000 --- a/src/doc/unstable-book/src/library-features/heap-api.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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/i128.md b/src/doc/unstable-book/src/library-features/i128.md deleted file mode 100644 index a1a7ce8e63f4..000000000000 --- a/src/doc/unstable-book/src/library-features/i128.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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/library-features/inclusive-range.md b/src/doc/unstable-book/src/library-features/inclusive-range.md deleted file mode 100644 index 2e88e2047868..000000000000 --- a/src/doc/unstable-book/src/library-features/inclusive-range.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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/integer-atomics.md b/src/doc/unstable-book/src/library-features/integer-atomics.md deleted file mode 100644 index 50db9fd4ca45..000000000000 --- a/src/doc/unstable-book/src/library-features/integer-atomics.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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 deleted file mode 100644 index 0d94b4fc5605..000000000000 --- a/src/doc/unstable-book/src/library-features/into-boxed-c-str.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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 deleted file mode 100644 index 7636e20b14d8..000000000000 --- a/src/doc/unstable-book/src/library-features/into-boxed-os-str.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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 deleted file mode 100644 index 754c6042f07f..000000000000 --- a/src/doc/unstable-book/src/library-features/into-boxed-path.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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.md b/src/doc/unstable-book/src/library-features/io.md deleted file mode 100644 index ed6cae24e32d..000000000000 --- a/src/doc/unstable-book/src/library-features/io.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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 deleted file mode 100644 index 7e7d52adbdb0..000000000000 --- a/src/doc/unstable-book/src/library-features/ip.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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 deleted file mode 100644 index 444714490345..000000000000 --- a/src/doc/unstable-book/src/library-features/iter-rfind.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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/iterator-step-by.md b/src/doc/unstable-book/src/library-features/iterator-step-by.md deleted file mode 100644 index 8467cb68862f..000000000000 --- a/src/doc/unstable-book/src/library-features/iterator-step-by.md +++ /dev/null @@ -1,7 +0,0 @@ -# `iterator_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/linked-list-extras.md b/src/doc/unstable-book/src/library-features/linked-list-extras.md deleted file mode 100644 index be3b96aea70d..000000000000 --- a/src/doc/unstable-book/src/library-features/linked-list-extras.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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 deleted file mode 100644 index b60e7a010945..000000000000 --- a/src/doc/unstable-book/src/library-features/lookup-host.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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 deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/src/doc/unstable-book/src/library-features/mpsc-select.md b/src/doc/unstable-book/src/library-features/mpsc-select.md deleted file mode 100644 index 1405b6c5cb24..000000000000 --- a/src/doc/unstable-book/src/library-features/mpsc-select.md +++ /dev/null @@ -1,5 +0,0 @@ -# `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/needs-drop.md b/src/doc/unstable-book/src/library-features/needs-drop.md deleted file mode 100644 index 10ae95695a2d..000000000000 --- a/src/doc/unstable-book/src/library-features/needs-drop.md +++ /dev/null @@ -1,7 +0,0 @@ -# `needs_drop` - -The tracking issue for this feature is: [#41890] - -[#41890]: https://github.com/rust-lang/rust/issues/41890 - ------------------------- 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 deleted file mode 100644 index 4063cd0db01d..000000000000 --- a/src/doc/unstable-book/src/library-features/never-type-impls.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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 deleted file mode 100644 index f200f8e2786f..000000000000 --- a/src/doc/unstable-book/src/library-features/nonzero.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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 deleted file mode 100644 index 03d990eb4ae9..000000000000 --- a/src/doc/unstable-book/src/library-features/offset-to.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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 deleted file mode 100644 index 3c16cafae501..000000000000 --- a/src/doc/unstable-book/src/library-features/once-poison.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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 deleted file mode 100644 index 908caeb75c60..000000000000 --- a/src/doc/unstable-book/src/library-features/oom.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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 deleted file mode 100644 index edb4efc09e58..000000000000 --- a/src/doc/unstable-book/src/library-features/option-entry.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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 deleted file mode 100644 index 21dc7d095c80..000000000000 --- a/src/doc/unstable-book/src/library-features/osstring-shrink-to-fit.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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 deleted file mode 100644 index 07a957626905..000000000000 --- a/src/doc/unstable-book/src/library-features/panic-abort.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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 deleted file mode 100644 index 840e492597b5..000000000000 --- a/src/doc/unstable-book/src/library-features/panic-unwind.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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 deleted file mode 100644 index e76ee6beb675..000000000000 --- a/src/doc/unstable-book/src/library-features/pattern.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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/placement-in.md b/src/doc/unstable-book/src/library-features/placement-in.md deleted file mode 100644 index 6ff010b7e385..000000000000 --- a/src/doc/unstable-book/src/library-features/placement-in.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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 deleted file mode 100644 index d53225f0a352..000000000000 --- a/src/doc/unstable-book/src/library-features/placement-new-protocol.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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/proc-macro-internals.md b/src/doc/unstable-book/src/library-features/proc-macro-internals.md deleted file mode 100644 index ea087c0a4f7b..000000000000 --- a/src/doc/unstable-book/src/library-features/proc-macro-internals.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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/profiler-runtime-lib.md b/src/doc/unstable-book/src/library-features/profiler-runtime-lib.md new file mode 100644 index 000000000000..a01f1e73ab40 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/profiler-runtime-lib.md @@ -0,0 +1,5 @@ +# `profiler_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/range-contains.md b/src/doc/unstable-book/src/library-features/range-contains.md deleted file mode 100644 index ac4581faf2ae..000000000000 --- a/src/doc/unstable-book/src/library-features/range-contains.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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 deleted file mode 100644 index d7caf22813dc..000000000000 --- a/src/doc/unstable-book/src/library-features/raw.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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/reverse-cmp-key.md b/src/doc/unstable-book/src/library-features/reverse-cmp-key.md deleted file mode 100644 index a1a851d6ed63..000000000000 --- a/src/doc/unstable-book/src/library-features/reverse-cmp-key.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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/rustc-private.md b/src/doc/unstable-book/src/library-features/rustc-private.md deleted file mode 100644 index 2453475efe59..000000000000 --- a/src/doc/unstable-book/src/library-features/rustc-private.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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/shared.md b/src/doc/unstable-book/src/library-features/shared.md deleted file mode 100644 index b79d1212c62f..000000000000 --- a/src/doc/unstable-book/src/library-features/shared.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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 deleted file mode 100644 index 8f69c3ab2def..000000000000 --- a/src/doc/unstable-book/src/library-features/sip-hash-13.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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 deleted file mode 100644 index 9ba2de5adc72..000000000000 --- a/src/doc/unstable-book/src/library-features/slice-concat-ext.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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 deleted file mode 100644 index 57e2c148e796..000000000000 --- a/src/doc/unstable-book/src/library-features/slice-get-slice.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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-rotate.md b/src/doc/unstable-book/src/library-features/slice-rotate.md deleted file mode 100644 index 77fd598f1ea9..000000000000 --- a/src/doc/unstable-book/src/library-features/slice-rotate.md +++ /dev/null @@ -1,7 +0,0 @@ -# `slice_rotate` - -The tracking issue for this feature is: [#41891] - -[#41891]: https://github.com/rust-lang/rust/issues/41891 - ------------------------- diff --git a/src/doc/unstable-book/src/library-features/step-by.md b/src/doc/unstable-book/src/library-features/step-by.md deleted file mode 100644 index b649496cdd80..000000000000 --- a/src/doc/unstable-book/src/library-features/step-by.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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 deleted file mode 100644 index 56050c20c691..000000000000 --- a/src/doc/unstable-book/src/library-features/step-trait.md +++ /dev/null @@ -1,7 +0,0 @@ -# `step_trait` - -The tracking issue for this feature is: [#42168] - -[#42168]: https://github.com/rust-lang/rust/issues/42168 - ------------------------- 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 deleted file mode 100644 index d05dcafa84da..000000000000 --- a/src/doc/unstable-book/src/library-features/str-box-extras.md +++ /dev/null @@ -1,9 +0,0 @@ -# `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 deleted file mode 100644 index d390139a6bef..000000000000 --- a/src/doc/unstable-book/src/library-features/str-checked-slicing.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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 deleted file mode 100644 index 61e31c894432..000000000000 --- a/src/doc/unstable-book/src/library-features/str-escape.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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-mut-extras.md b/src/doc/unstable-book/src/library-features/str-mut-extras.md deleted file mode 100644 index df4f35832cdc..000000000000 --- a/src/doc/unstable-book/src/library-features/str-mut-extras.md +++ /dev/null @@ -1,8 +0,0 @@ -# `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/library-features/thread-id.md b/src/doc/unstable-book/src/library-features/thread-id.md deleted file mode 100644 index af3ea991025f..000000000000 --- a/src/doc/unstable-book/src/library-features/thread-id.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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-state.md b/src/doc/unstable-book/src/library-features/thread-local-state.md deleted file mode 100644 index 113c1e910dca..000000000000 --- a/src/doc/unstable-book/src/library-features/thread-local-state.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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 deleted file mode 100644 index eccc7e0e4dda..000000000000 --- a/src/doc/unstable-book/src/library-features/toowned-clone-into.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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 deleted file mode 100644 index 80213cf1fdbb..000000000000 --- a/src/doc/unstable-book/src/library-features/trusted-len.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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 deleted file mode 100644 index d763caff5aac..000000000000 --- a/src/doc/unstable-book/src/library-features/try-from.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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 deleted file mode 100644 index 9fecec2ac36d..000000000000 --- a/src/doc/unstable-book/src/library-features/unicode.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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 deleted file mode 100644 index 99a3490d106b..000000000000 --- a/src/doc/unstable-book/src/library-features/unique.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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 deleted file mode 100644 index 92807e2858ff..000000000000 --- a/src/doc/unstable-book/src/library-features/unsize.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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/utf8-error-error-len.md b/src/doc/unstable-book/src/library-features/utf8-error-error-len.md deleted file mode 100644 index 1c14a5a9fa08..000000000000 --- a/src/doc/unstable-book/src/library-features/utf8-error-error-len.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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 deleted file mode 100644 index 2b8c9f046eef..000000000000 --- a/src/doc/unstable-book/src/library-features/vec-remove-item.md +++ /dev/null @@ -1,7 +0,0 @@ -# `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/vec-resize-default.md b/src/doc/unstable-book/src/library-features/vec-resize-default.md deleted file mode 100644 index 5803d3215a54..000000000000 --- a/src/doc/unstable-book/src/library-features/vec-resize-default.md +++ /dev/null @@ -1,7 +0,0 @@ -# `vec_resize_default` - -The tracking issue for this feature is: [#41758] - -[#41758]: https://github.com/rust-lang/rust/issues/41758 - ------------------------- diff --git a/src/etc/debugger_pretty_printers_common.py b/src/etc/debugger_pretty_printers_common.py index 5e3ff5246a92..4a38d4be083f 100644 --- a/src/etc/debugger_pretty_printers_common.py +++ b/src/etc/debugger_pretty_printers_common.py @@ -46,6 +46,7 @@ TYPE_KIND_CSTYLE_ENUM = 14 TYPE_KIND_PTR = 15 TYPE_KIND_FIXED_SIZE_VEC = 16 TYPE_KIND_REGULAR_UNION = 17 +TYPE_KIND_OS_STRING = 18 ENCODED_ENUM_PREFIX = "RUST$ENCODED$ENUM$" ENUM_DISR_FIELD_NAME = "RUST$ENUM$DISR" @@ -64,6 +65,9 @@ STD_VEC_FIELD_NAMES = [STD_VEC_FIELD_NAME_BUF, # std::String related constants STD_STRING_FIELD_NAMES = ["vec"] +# std::ffi::OsString related constants +OS_STRING_FIELD_NAMES = ["inner"] + class Type(object): """ @@ -162,6 +166,11 @@ class Type(object): self.__conforms_to_field_layout(STD_STRING_FIELD_NAMES)): return TYPE_KIND_STD_STRING + # OS STRING + if (unqualified_type_name == "OsString" and + self.__conforms_to_field_layout(OS_STRING_FIELD_NAMES)): + return TYPE_KIND_OS_STRING + # ENUM VARIANTS if fields[0].name == ENUM_DISR_FIELD_NAME: if field_count == 1: @@ -345,3 +354,8 @@ def extract_type_name(qualified_type_name): return qualified_type_name else: return qualified_type_name[index + 2:] + +try: + compat_str = unicode # Python 2 +except NameError: + compat_str = str diff --git a/src/etc/gdb_rust_pretty_printing.py b/src/etc/gdb_rust_pretty_printing.py index afac8d6bbaef..822dc5814047 100755 --- a/src/etc/gdb_rust_pretty_printing.py +++ b/src/etc/gdb_rust_pretty_printing.py @@ -78,7 +78,8 @@ class GdbValue(rustpp.Value): def as_integer(self): if self.gdb_val.type.code == gdb.TYPE_CODE_PTR: - return int(str(self.gdb_val), 0) + as_str = rustpp.compat_str(self.gdb_val).split()[0] + return int(as_str, 0) return int(self.gdb_val) def get_wrapped_value(self): @@ -99,8 +100,10 @@ def rust_pretty_printer_lookup_function(gdb_val): val = GdbValue(gdb_val) type_kind = val.type.get_type_kind() - if (type_kind == rustpp.TYPE_KIND_REGULAR_STRUCT or - type_kind == rustpp.TYPE_KIND_EMPTY): + if type_kind == rustpp.TYPE_KIND_EMPTY: + return RustEmptyPrinter(val) + + if type_kind == rustpp.TYPE_KIND_REGULAR_STRUCT: return RustStructPrinter(val, omit_first_field = False, omit_type_name = False, @@ -124,6 +127,9 @@ def rust_pretty_printer_lookup_function(gdb_val): if type_kind == rustpp.TYPE_KIND_STD_STRING: return RustStdStringPrinter(val) + if type_kind == rustpp.TYPE_KIND_OS_STRING: + return RustOsStringPrinter(val) + if type_kind == rustpp.TYPE_KIND_TUPLE: return RustStructPrinter(val, omit_first_field = False, @@ -170,6 +176,14 @@ def rust_pretty_printer_lookup_function(gdb_val): #=------------------------------------------------------------------------------ # Pretty Printer Classes #=------------------------------------------------------------------------------ +class RustEmptyPrinter(object): + def __init__(self, val): + self.__val = val + + def to_string(self): + return self.__val.type.get_unqualified_type_name() + + class RustStructPrinter(object): def __init__(self, val, omit_first_field, omit_type_name, is_tuple_like): self.__val = val @@ -186,10 +200,10 @@ class RustStructPrinter(object): cs = [] wrapped_value = self.__val.get_wrapped_value() - for field in self.__val.type.get_fields(): + for number, field in enumerate(self.__val.type.get_fields()): field_value = wrapped_value[field.name] if self.__is_tuple_like: - cs.append(("", field_value)) + cs.append((str(number), field_value)) else: cs.append((field.name, field_value)) @@ -268,6 +282,21 @@ class RustStdStringPrinter(object): length=length) +class RustOsStringPrinter(object): + def __init__(self, val): + self.__val = val + + def to_string(self): + buf = self.__val.get_child_at_index(0) + vec = buf.get_child_at_index(0) + if vec.type.get_unqualified_type_name() == "Wtf8Buf": + vec = vec.get_child_at_index(0) + + (length, data_ptr, cap) = rustpp.extract_length_ptr_and_cap_from_std_vec( + vec) + return '"%s"' % data_ptr.get_wrapped_value().string(length=length) + + class RustCStyleVariantPrinter(object): def __init__(self, val): assert val.type.get_dwarf_type_kind() == rustpp.DWARF_TYPE_CODE_ENUM diff --git a/src/etc/natvis/libcollections.natvis b/src/etc/natvis/liballoc.natvis similarity index 81% rename from src/etc/natvis/libcollections.natvis rename to src/etc/natvis/liballoc.natvis index e7e93be98695..1f6d17748ab0 100644 --- a/src/etc/natvis/libcollections.natvis +++ b/src/etc/natvis/liballoc.natvis @@ -1,6 +1,6 @@ - + {{ size={len} }} len @@ -11,7 +11,7 @@ - + {{ size={tail <= head ? head - tail : buf.cap - tail + head} }} tail <= head ? head - tail : buf.cap - tail + head @@ -30,18 +30,18 @@ - + {{ size={len} }} len - *(collections::linked_list::Node<$T1> **)&head - *(collections::linked_list::Node<$T1> **)&next + *(alloc::linked_list::Node<$T1> **)&head + *(alloc::linked_list::Node<$T1> **)&next element - + {*(char**)this,[vec.len]} *(char**)this,[vec.len] @@ -53,4 +53,4 @@ - \ No newline at end of file + diff --git a/src/etc/platform-intrinsics/arm.json b/src/etc/platform-intrinsics/arm.json index 39e49e239f34..d008320713c3 100644 --- a/src/etc/platform-intrinsics/arm.json +++ b/src/etc/platform-intrinsics/arm.json @@ -1,7 +1,7 @@ { "platform": "arm_v", "intrinsic_prefix": "", - "llvm_prefix": "llvm.neon.v", + "llvm_prefix": "llvm.arm.neon.v", "number_info": { "signed": { "kind": "s", diff --git a/src/etc/rust-windbg.cmd b/src/etc/rust-windbg.cmd index 4cdd6b986099..b09b37c1db42 100644 --- a/src/etc/rust-windbg.cmd +++ b/src/etc/rust-windbg.cmd @@ -15,4 +15,4 @@ 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 +windbg -c ".nvload %rust_etc%\liballoc.natvis; .nvload %rust_etc%\libcore.natvis;" %* diff --git a/src/grammar/lexer.l b/src/grammar/lexer.l index 77737c99496f..91652bfdf246 100644 --- a/src/grammar/lexer.l +++ b/src/grammar/lexer.l @@ -126,7 +126,7 @@ while { return WHILE; } {ident} { return IDENT; } 0x[0-9a-fA-F_]+ { BEGIN(suffix); return LIT_INTEGER; } -0o[0-8_]+ { BEGIN(suffix); return LIT_INTEGER; } +0o[0-7_]+ { 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; } diff --git a/src/jemalloc b/src/jemalloc index 3288e0659c08..11bfb0dcf85f 160000 --- a/src/jemalloc +++ b/src/jemalloc @@ -1 +1 @@ -Subproject commit 3288e0659c08fb5006f6d6dd4b5675ed0c2c432a +Subproject commit 11bfb0dcf85f7aa92abd30524bb1e42e18d108c6 diff --git a/src/liballoc/Cargo.toml b/src/liballoc/Cargo.toml index 0889ca9fc84d..686e5681d12b 100644 --- a/src/liballoc/Cargo.toml +++ b/src/liballoc/Cargo.toml @@ -9,3 +9,12 @@ path = "lib.rs" [dependencies] core = { path = "../libcore" } +std_unicode = { path = "../libstd_unicode" } + +[[test]] +name = "collectionstests" +path = "../liballoc/tests/lib.rs" + +[[bench]] +name = "collectionsbenches" +path = "../liballoc/benches/lib.rs" diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 5faf4dcccaf9..7c51c4b161ca 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -42,7 +42,8 @@ use heap::deallocate; /// necessarily) at _exactly_ `MAX_REFCOUNT + 1` references. const MAX_REFCOUNT: usize = (isize::MAX) as usize; -/// A thread-safe reference-counting pointer. +/// A thread-safe reference-counting pointer. 'Arc' stands for 'Atomically +/// Reference Counted'. /// /// The type `Arc` provides shared ownership of a value of type `T`, /// allocated in the heap. Invoking [`clone`][clone] on `Arc` produces @@ -1221,11 +1222,12 @@ mod tests { use std::sync::atomic; use std::sync::atomic::Ordering::{Acquire, SeqCst}; use std::thread; - use std::vec::Vec; - use super::{Arc, Weak}; use std::sync::Mutex; use std::convert::From; + use super::{Arc, Weak}; + use vec::Vec; + struct Canary(*mut atomic::AtomicUsize); impl Drop for Canary { diff --git a/src/libcollections/benches/btree/map.rs b/src/liballoc/benches/btree/map.rs similarity index 100% rename from src/libcollections/benches/btree/map.rs rename to src/liballoc/benches/btree/map.rs diff --git a/src/libcollections/benches/btree/mod.rs b/src/liballoc/benches/btree/mod.rs similarity index 100% rename from src/libcollections/benches/btree/mod.rs rename to src/liballoc/benches/btree/mod.rs diff --git a/src/libcollections/benches/lib.rs b/src/liballoc/benches/lib.rs similarity index 100% rename from src/libcollections/benches/lib.rs rename to src/liballoc/benches/lib.rs diff --git a/src/libcollections/benches/linked_list.rs b/src/liballoc/benches/linked_list.rs similarity index 100% rename from src/libcollections/benches/linked_list.rs rename to src/liballoc/benches/linked_list.rs diff --git a/src/libcollections/benches/slice.rs b/src/liballoc/benches/slice.rs similarity index 100% rename from src/libcollections/benches/slice.rs rename to src/liballoc/benches/slice.rs diff --git a/src/libcollections/benches/str.rs b/src/liballoc/benches/str.rs similarity index 100% rename from src/libcollections/benches/str.rs rename to src/liballoc/benches/str.rs diff --git a/src/libcollections/benches/string.rs b/src/liballoc/benches/string.rs similarity index 100% rename from src/libcollections/benches/string.rs rename to src/liballoc/benches/string.rs diff --git a/src/libcollections/benches/vec.rs b/src/liballoc/benches/vec.rs similarity index 100% rename from src/libcollections/benches/vec.rs rename to src/liballoc/benches/vec.rs diff --git a/src/libcollections/benches/vec_deque.rs b/src/liballoc/benches/vec_deque.rs similarity index 100% rename from src/libcollections/benches/vec_deque.rs rename to src/liballoc/benches/vec_deque.rs diff --git a/src/libcollections/binary_heap.rs b/src/liballoc/binary_heap.rs similarity index 100% rename from src/libcollections/binary_heap.rs rename to src/liballoc/binary_heap.rs diff --git a/src/libcollections/borrow.rs b/src/liballoc/borrow.rs similarity index 100% rename from src/libcollections/borrow.rs rename to src/liballoc/borrow.rs diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 8a39be8fae8a..2f867912f582 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -95,6 +95,7 @@ pub const HEAP: ExchangeHeapSingleton = ExchangeHeapSingleton { _force_singleton #[unstable(feature = "box_heap", reason = "may be renamed; uncertain about custom allocator design", issue = "27779")] +#[allow(missing_debug_implementations)] #[derive(Copy, Clone)] pub struct ExchangeHeapSingleton { _force_singleton: (), @@ -129,6 +130,7 @@ pub struct Box(Unique); #[unstable(feature = "placement_in", reason = "placement box design is still being worked out.", issue = "27779")] +#[allow(missing_debug_implementations)] pub struct IntermediateBox { ptr: *mut u8, size: usize, diff --git a/src/libcollections/btree/map.rs b/src/liballoc/btree/map.rs similarity index 100% rename from src/libcollections/btree/map.rs rename to src/liballoc/btree/map.rs diff --git a/src/libcollections/btree/mod.rs b/src/liballoc/btree/mod.rs similarity index 100% rename from src/libcollections/btree/mod.rs rename to src/liballoc/btree/mod.rs diff --git a/src/libcollections/btree/node.rs b/src/liballoc/btree/node.rs similarity index 99% rename from src/libcollections/btree/node.rs rename to src/liballoc/btree/node.rs index 52cdd39d8f96..811174b331e2 100644 --- a/src/libcollections/btree/node.rs +++ b/src/liballoc/btree/node.rs @@ -41,7 +41,6 @@ // - A node of length `n` has `n` keys, `n` values, and (in an internal node) `n + 1` edges. // This implies that even an empty internal node has at least one edge. -use alloc::heap; use core::marker::PhantomData; use core::mem; use core::nonzero::NonZero; @@ -49,6 +48,7 @@ use core::ptr::{self, Unique}; use core::slice; use boxed::Box; +use heap; const B: usize = 6; pub const MIN_LEN: usize = B - 1; diff --git a/src/libcollections/btree/search.rs b/src/liballoc/btree/search.rs similarity index 100% rename from src/libcollections/btree/search.rs rename to src/liballoc/btree/search.rs diff --git a/src/libcollections/btree/set.rs b/src/liballoc/btree/set.rs similarity index 100% rename from src/libcollections/btree/set.rs rename to src/liballoc/btree/set.rs diff --git a/src/libcollections/fmt.rs b/src/liballoc/fmt.rs similarity index 100% rename from src/libcollections/fmt.rs rename to src/liballoc/fmt.rs diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 418a084da678..5252dabc1279 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// Copyright 2014-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,18 +8,16 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! # The Rust core allocation library +//! # The Rust core allocation and collections library //! -//! This is the lowest level library through which allocation in Rust can be -//! performed. +//! This library provides smart pointers and collections for managing +//! heap-allocated values. //! //! This library, like libcore, is not intended for general usage, but rather as //! a building block of other libraries. The types and interfaces in this //! library are reexported through the [standard library](../std/index.html), //! and should not be used through this library. //! -//! Currently, there are four major definitions in this library. -//! //! ## Boxed values //! //! The [`Box`](boxed/index.html) type is a smart pointer type. There can @@ -51,6 +49,12 @@ //! paired with synchronization primitives such as mutexes to allow mutation of //! shared resources. //! +//! ## Collections +//! +//! Implementations of the most common general purpose data structures are +//! defined in this library. They are reexported through the +//! [standard collections library](../std/collections/index.html). +//! //! ## Heap interfaces //! //! The [`heap`](heap/index.html) module defines the low-level interface to the @@ -71,8 +75,20 @@ #![no_std] #![needs_allocator] #![deny(warnings)] +#![deny(missing_debug_implementations)] +#![cfg_attr(test, allow(deprecated))] // rand +#![cfg_attr(test, feature(placement_in))] +#![cfg_attr(not(test), feature(char_escape_debug))] +#![cfg_attr(not(test), feature(core_float))] +#![cfg_attr(not(test), feature(exact_size_is_empty))] +#![cfg_attr(not(test), feature(slice_rotate))] +#![cfg_attr(not(test), feature(sort_unstable))] +#![cfg_attr(not(test), feature(str_checked_slicing))] +#![cfg_attr(test, feature(rand, test))] #![feature(allocator)] +#![feature(allow_internal_unstable)] +#![feature(box_patterns)] #![feature(box_syntax)] #![feature(cfg_target_has_atomic)] #![feature(coerce_unsized)] @@ -80,16 +96,33 @@ #![feature(core_intrinsics)] #![feature(custom_attribute)] #![feature(dropck_eyepatch)] -#![cfg_attr(not(test), feature(exact_size_is_empty))] +#![feature(exact_size_is_empty)] +#![feature(fmt_internals)] #![feature(fundamental)] +#![feature(fused)] #![feature(generic_param_attrs)] +#![feature(i128_type)] +#![feature(inclusive_range)] #![feature(lang_items)] +#![feature(manually_drop)] #![feature(needs_allocator)] +#![feature(nonzero)] +#![feature(offset_to)] #![feature(optin_builtin_traits)] +#![feature(pattern)] #![feature(placement_in_syntax)] +#![feature(placement_new_protocol)] #![feature(shared)] +#![feature(slice_get_slice)] +#![feature(slice_patterns)] +#![feature(slice_rsplit)] +#![feature(specialization)] #![feature(staged_api)] +#![feature(str_internals)] +#![feature(str_mut_extras)] +#![feature(trusted_len)] #![feature(unboxed_closures)] +#![feature(unicode)] #![feature(unique)] #![feature(unsize)] @@ -101,6 +134,10 @@ #[cfg(test)] #[macro_use] extern crate std; +#[cfg(test)] +extern crate test; + +extern crate std_unicode; // Module with internal macros used by other modules (needs to be included before other modules). #[macro_use] @@ -120,7 +157,7 @@ pub mod heap; pub mod boxed; #[cfg(test)] mod boxed { - pub use std::boxed::{Box, HEAP}; + pub use std::boxed::{Box, IntermediateBox, HEAP}; } #[cfg(test)] mod boxed_test; @@ -128,8 +165,111 @@ 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; +// collections modules +pub mod binary_heap; +mod btree; +pub mod borrow; +pub mod fmt; +pub mod linked_list; +pub mod range; +pub mod slice; +pub mod str; +pub mod string; +pub mod vec; +pub mod vec_deque; + +#[stable(feature = "rust1", since = "1.0.0")] +pub mod btree_map { + //! A map based on a B-Tree. + #[stable(feature = "rust1", since = "1.0.0")] + pub use btree::map::*; +} + +#[stable(feature = "rust1", since = "1.0.0")] +pub mod btree_set { + //! A set based on a B-Tree. + #[stable(feature = "rust1", since = "1.0.0")] + pub use btree::set::*; +} + +#[cfg(not(test))] +mod std { + pub use core::ops; // RangeFull +} + +/// 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 { + /// An inclusive bound. + #[stable(feature = "collections_bound", since = "1.17.0")] + Included(T), + /// An exclusive bound. + #[stable(feature = "collections_bound", since = "1.17.0")] + Excluded(T), + /// An infinite endpoint. Indicates that there is no bound in this direction. + #[stable(feature = "collections_bound", since = "1.17.0")] + Unbounded, +} + +/// An intermediate trait for specialization of `Extend`. +#[doc(hidden)] +trait SpecExtend { + /// Extends `self` with the contents of the given iterator. + fn spec_extend(&mut self, iter: I); +} + pub use oom::oom; + +#[doc(no_inline)] +pub use binary_heap::BinaryHeap; +#[doc(no_inline)] +pub use btree_map::BTreeMap; +#[doc(no_inline)] +pub use btree_set::BTreeSet; +#[doc(no_inline)] +pub use linked_list::LinkedList; +#[doc(no_inline)] +pub use vec_deque::VecDeque; +#[doc(no_inline)] +pub use string::String; +#[doc(no_inline)] +pub use vec::Vec; diff --git a/src/libcollections/linked_list.rs b/src/liballoc/linked_list.rs similarity index 99% rename from src/libcollections/linked_list.rs rename to src/liballoc/linked_list.rs index ae258083546f..e8973b7d2853 100644 --- a/src/libcollections/linked_list.rs +++ b/src/liballoc/linked_list.rs @@ -22,7 +22,6 @@ #![stable(feature = "rust1", since = "1.0.0")] -use alloc::boxed::{Box, IntermediateBox}; use core::cmp::Ordering; use core::fmt; use core::hash::{Hasher, Hash}; @@ -32,6 +31,7 @@ use core::mem; use core::ops::{BoxPlace, InPlace, Place, Placer}; use core::ptr::{self, Shared}; +use boxed::{Box, IntermediateBox}; use super::SpecExtend; /// A doubly-linked list with owned nodes. diff --git a/src/liballoc/macros.rs b/src/liballoc/macros.rs index 7da91c87e967..763f04fcd0dc 100644 --- a/src/liballoc/macros.rs +++ b/src/liballoc/macros.rs @@ -8,6 +8,89 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +/// Creates a `Vec` containing the arguments. +/// +/// `vec!` allows `Vec`s to be defined with the same syntax as array expressions. +/// There are two forms of this macro: +/// +/// - Create a `Vec` containing a given list of elements: +/// +/// ``` +/// let v = vec![1, 2, 3]; +/// assert_eq!(v[0], 1); +/// assert_eq!(v[1], 2); +/// assert_eq!(v[2], 3); +/// ``` +/// +/// - Create a `Vec` from a given element and size: +/// +/// ``` +/// let v = vec![1; 3]; +/// assert_eq!(v, [1, 1, 1]); +/// ``` +/// +/// Note that unlike array expressions this syntax supports all elements +/// which implement `Clone` and the number of elements doesn't have to be +/// a constant. +/// +/// This will use `clone()` to duplicate an expression, so one should be careful +/// using this with types having a nonstandard `Clone` implementation. For +/// example, `vec![Rc::new(1); 5]` will create a vector of five references +/// to the same boxed integer value, not five references pointing to independently +/// boxed integers. +#[cfg(not(test))] +#[macro_export] +#[stable(feature = "rust1", since = "1.0.0")] +#[allow_internal_unstable] +macro_rules! vec { + ($elem:expr; $n:expr) => ( + $crate::vec::from_elem($elem, $n) + ); + ($($x:expr),*) => ( + <[_]>::into_vec(box [$($x),*]) + ); + ($($x:expr,)*) => (vec![$($x),*]) +} + +// HACK(japaric): with cfg(test) the inherent `[T]::into_vec` method, which is +// required for this macro definition, is not available. Instead use the +// `slice::into_vec` function which is only available with cfg(test) +// NB see the slice::hack module in slice.rs for more information +#[cfg(test)] +macro_rules! vec { + ($elem:expr; $n:expr) => ( + $crate::vec::from_elem($elem, $n) + ); + ($($x:expr),*) => ( + $crate::slice::into_vec(box [$($x),*]) + ); + ($($x:expr,)*) => (vec![$($x),*]) +} + +/// Use the syntax described in `std::fmt` to create a value of type `String`. +/// See [`std::fmt`][fmt] for more information. +/// +/// [fmt]: ../std/fmt/index.html +/// +/// # Panics +/// +/// `format!` panics if a formatting trait implementation returns an error. +/// This indicates an incorrect implementation +/// since `fmt::Write for String` never returns an error itself. +/// +/// # Examples +/// +/// ``` +/// format!("test"); +/// format!("hello {}", "world!"); +/// format!("x = {}, y = {y}", 10, y = 30); +/// ``` +#[macro_export] +#[stable(feature = "rust1", since = "1.0.0")] +macro_rules! format { + ($($arg:tt)*) => ($crate::fmt::format(format_args!($($arg)*))) +} + // Private macro to get the offset of a struct field in bytes from the address of the struct. macro_rules! offset_of { ($container:path, $field:ident) => {{ diff --git a/src/libcollections/range.rs b/src/liballoc/range.rs similarity index 92% rename from src/libcollections/range.rs rename to src/liballoc/range.rs index bc8566e8cbeb..f862da0d61e0 100644 --- a/src/libcollections/range.rs +++ b/src/liballoc/range.rs @@ -27,14 +27,14 @@ pub trait RangeArgument { /// # Examples /// /// ``` - /// #![feature(collections)] + /// #![feature(alloc)] /// #![feature(collections_range)] /// - /// extern crate collections; + /// extern crate alloc; /// /// # fn main() { - /// use collections::range::RangeArgument; - /// use collections::Bound::*; + /// use alloc::range::RangeArgument; + /// use alloc::Bound::*; /// /// assert_eq!((..10).start(), Unbounded); /// assert_eq!((3..10).start(), Included(&3)); @@ -49,14 +49,14 @@ pub trait RangeArgument { /// # Examples /// /// ``` - /// #![feature(collections)] + /// #![feature(alloc)] /// #![feature(collections_range)] /// - /// extern crate collections; + /// extern crate alloc; /// /// # fn main() { - /// use collections::range::RangeArgument; - /// use collections::Bound::*; + /// use alloc::range::RangeArgument; + /// use alloc::Bound::*; /// /// assert_eq!((3..).end(), Unbounded); /// assert_eq!((3..10).end(), Excluded(&10)); diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index 7edf07944ec5..34ab0a19d4e0 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -44,6 +44,7 @@ use core::cmp; /// `shrink_to_fit`, and `from_box` will actually set RawVec's private capacity /// field. This allows zero-sized types to not be special-cased by consumers of /// this type. +#[allow(missing_debug_implementations)] pub struct RawVec { ptr: Unique, cap: usize, diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 33951b911dd5..21a56ff9899e 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -10,7 +10,8 @@ #![allow(deprecated)] -//! Single-threaded reference-counting pointers. +//! Single-threaded reference-counting pointers. 'Rc' stands for 'Reference +//! Counted'. //! //! The type [`Rc`][`Rc`] provides shared ownership of a value of type `T`, //! allocated in the heap. Invoking [`clone`][clone] on [`Rc`] produces a new @@ -266,7 +267,8 @@ struct RcBox { value: T, } -/// A single-threaded reference-counting pointer. +/// A single-threaded reference-counting pointer. 'Rc' stands for 'Reference +/// Counted'. /// /// See the [module-level documentation](./index.html) for more details. /// @@ -426,7 +428,7 @@ impl Rc { #[doc(hidden)] #[unstable(feature = "rustc_private", reason = "for internal use in rustc", - issue = "0")] + issue = "27812")] pub fn __from_str(value: &str) -> Rc { unsafe { // Allocate enough space for `RcBox`. @@ -451,7 +453,7 @@ impl Rc<[T]> { #[doc(hidden)] #[unstable(feature = "rustc_private", reason = "for internal use in rustc", - issue = "0")] + issue = "27812")] pub fn __from_array(value: Box<[T]>) -> Rc<[T]> { unsafe { let ptr: *mut RcBox<[T]> = diff --git a/src/libcollections/slice.rs b/src/liballoc/slice.rs similarity index 99% rename from src/libcollections/slice.rs rename to src/liballoc/slice.rs index 97d6687c79b5..88876999d765 100644 --- a/src/libcollections/slice.rs +++ b/src/liballoc/slice.rs @@ -97,7 +97,6 @@ // It's cleaner to just turn off the unused_imports warning than to fix them. #![cfg_attr(test, allow(unused_imports, dead_code))] -use alloc::boxed::Box; use core::cmp::Ordering::{self, Less}; use core::mem::size_of; use core::mem; @@ -105,6 +104,7 @@ use core::ptr; use core::slice as core_slice; use borrow::{Borrow, BorrowMut, ToOwned}; +use boxed::Box; use vec::Vec; #[stable(feature = "rust1", since = "1.0.0")] @@ -141,7 +141,7 @@ pub use self::hack::to_vec; // `core::slice::SliceExt` - we need to supply these functions for the // `test_permutations` test mod hack { - use alloc::boxed::Box; + use boxed::Box; use core::mem; #[cfg(test)] diff --git a/src/liballoc/str.rs b/src/liballoc/str.rs index c87db16a0f41..f56288c30132 100644 --- a/src/liballoc/str.rs +++ b/src/liballoc/str.rs @@ -8,11 +8,1992 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Methods for dealing with boxed strings. -use core::mem; +//! 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. +// It's cleaner to just turn off the unused_imports warning than to fix them. +#![allow(unused_imports)] + +use core::fmt; +use core::str as core_str; +use core::str::pattern::Pattern; +use core::str::pattern::{Searcher, ReverseSearcher, DoubleEndedSearcher}; +use core::mem; +use core::iter::FusedIterator; +use std_unicode::str::{UnicodeStr, Utf16Encoder}; + +use vec_deque::VecDeque; +use borrow::{Borrow, ToOwned}; +use string::String; +use std_unicode; +use vec::Vec; +use slice::{SliceConcatExt, SliceIndex}; use boxed::Box; +#[stable(feature = "rust1", since = "1.0.0")] +pub use core::str::{FromStr, Utf8Error}; +#[allow(deprecated)] +#[stable(feature = "rust1", since = "1.0.0")] +pub use core::str::{Lines, LinesAny}; +#[stable(feature = "rust1", since = "1.0.0")] +pub use core::str::{Split, RSplit}; +#[stable(feature = "rust1", since = "1.0.0")] +pub use core::str::{SplitN, RSplitN}; +#[stable(feature = "rust1", since = "1.0.0")] +pub use core::str::{SplitTerminator, RSplitTerminator}; +#[stable(feature = "rust1", since = "1.0.0")] +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, from_utf8_mut, Chars, CharIndices, Bytes}; +#[stable(feature = "rust1", since = "1.0.0")] +pub use core::str::{from_utf8_unchecked, from_utf8_unchecked_mut, ParseBoolError}; +#[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")] +impl> SliceConcatExt for [S] { + type Output = String; + + fn concat(&self) -> String { + if self.is_empty() { + return String::new(); + } + + // `len` calculation may overflow but push_str will check boundaries + let len = self.iter().map(|s| s.borrow().len()).sum(); + let mut result = String::with_capacity(len); + + for s in self { + result.push_str(s.borrow()) + } + + result + } + + fn join(&self, sep: &str) -> String { + if self.is_empty() { + return String::new(); + } + + // concat is faster + if sep.is_empty() { + return self.concat(); + } + + // this is wrong without the guarantee that `self` is non-empty + // `len` calculation may overflow but push_str but will check boundaries + let len = sep.len() * (self.len() - 1) + + self.iter().map(|s| s.borrow().len()).sum::(); + let mut result = String::with_capacity(len); + let mut first = true; + + for s in self { + if first { + first = false; + } else { + result.push_str(sep); + } + result.push_str(s.borrow()); + } + result + } + + fn connect(&self, sep: &str) -> String { + self.join(sep) + } +} + +/// An iterator of [`u16`] over the string encoded as UTF-16. +/// +/// [`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> { + encoder: Utf16Encoder>, +} + +#[stable(feature = "collection_debug", since = "1.17.0")] +impl<'a> fmt::Debug for EncodeUtf16<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("EncodeUtf16 { .. }") + } +} + +#[stable(feature = "encode_utf16", since = "1.8.0")] +impl<'a> Iterator for EncodeUtf16<'a> { + type Item = u16; + + #[inline] + fn next(&mut self) -> Option { + self.encoder.next() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.encoder.size_hint() + } +} + +#[unstable(feature = "fused", issue = "35602")] +impl<'a> FusedIterator for EncodeUtf16<'a> {} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Borrow for String { + #[inline] + fn borrow(&self) -> &str { + &self[..] + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ToOwned for str { + type Owned = String; + 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. +#[lang = "str"] +#[cfg(not(test))] +impl str { + /// Returns the length of `self`. + /// + /// This length is in bytes, not [`char`]s or graphemes. In other words, + /// it may not be what a human considers the length of the string. + /// + /// [`char`]: primitive.char.html + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let len = "foo".len(); + /// assert_eq!(3, len); + /// + /// let len = "ƒoo".len(); // fancy f! + /// assert_eq!(4, len); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn len(&self) -> usize { + core_str::StrExt::len(self) + } + + /// Returns `true` if `self` has a length of zero bytes. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let s = ""; + /// assert!(s.is_empty()); + /// + /// let s = "not empty"; + /// assert!(!s.is_empty()); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn is_empty(&self) -> bool { + core_str::StrExt::is_empty(self) + } + + /// Checks that `index`-th byte lies at the start and/or end of a + /// UTF-8 code point sequence. + /// + /// The start and end of the string (when `index == self.len()`) are + /// considered to be + /// boundaries. + /// + /// Returns `false` if `index` is greater than `self.len()`. + /// + /// # Examples + /// + /// ``` + /// let s = "Löwe 老虎 Léopard"; + /// assert!(s.is_char_boundary(0)); + /// // start of `老` + /// assert!(s.is_char_boundary(6)); + /// assert!(s.is_char_boundary(s.len())); + /// + /// // second byte of `ö` + /// assert!(!s.is_char_boundary(2)); + /// + /// // third byte of `老` + /// assert!(!s.is_char_boundary(8)); + /// ``` + #[stable(feature = "is_char_boundary", since = "1.9.0")] + #[inline] + pub fn is_char_boundary(&self, index: usize) -> bool { + core_str::StrExt::is_char_boundary(self, index) + } + + /// Converts a string slice to a byte slice. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let bytes = "bors".as_bytes(); + /// assert_eq!(b"bors", bytes); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline(always)] + pub fn as_bytes(&self) -> &[u8] { + 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 + /// [`u8`]. This pointer will be pointing to the first byte of the string + /// slice. + /// + /// [`u8`]: primitive.u8.html + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let s = "Hello"; + /// let ptr = s.as_ptr(); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn as_ptr(&self) -> *const u8 { + 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. + /// + /// This is generally not recommended, use with caution! For a safe + /// alternative see [`str`] and [`Index`]. + /// + /// [`str`]: primitive.str.html + /// [`Index`]: ops/trait.Index.html + /// + /// This new slice goes from `begin` to `end`, including `begin` but + /// excluding `end`. + /// + /// To get a mutable string slice instead, see the + /// [`slice_mut_unchecked`] method. + /// + /// [`slice_mut_unchecked`]: #method.slice_mut_unchecked + /// + /// # Safety + /// + /// Callers of this function are responsible that three preconditions are + /// satisfied: + /// + /// * `begin` must come before `end`. + /// * `begin` and `end` must be byte positions within the string slice. + /// * `begin` and `end` must lie on UTF-8 sequence boundaries. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let s = "Löwe 老虎 Léopard"; + /// + /// unsafe { + /// assert_eq!("Löwe 老虎 Léopard", s.slice_unchecked(0, 21)); + /// } + /// + /// let s = "Hello, world!"; + /// + /// unsafe { + /// assert_eq!("world", s.slice_unchecked(7, 12)); + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str { + core_str::StrExt::slice_unchecked(self, begin, end) + } + + /// Creates a string slice from another string slice, bypassing safety + /// checks. + /// This is generally not recommended, use with caution! For a safe + /// alternative see [`str`] and [`IndexMut`]. + /// + /// [`str`]: primitive.str.html + /// [`IndexMut`]: ops/trait.IndexMut.html + /// + /// This new slice goes from `begin` to `end`, including `begin` but + /// excluding `end`. + /// + /// To get an immutable string slice instead, see the + /// [`slice_unchecked`] method. + /// + /// [`slice_unchecked`]: #method.slice_unchecked + /// + /// # Safety + /// + /// Callers of this function are responsible that three preconditions are + /// satisfied: + /// + /// * `begin` must come before `end`. + /// * `begin` and `end` must be byte positions within the string slice. + /// * `begin` and `end` must lie on UTF-8 sequence boundaries. + #[stable(feature = "str_slice_mut", since = "1.5.0")] + #[inline] + pub unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut str { + core_str::StrExt::slice_mut_unchecked(self, begin, end) + } + + /// Divide one string slice into two at an index. + /// + /// The argument, `mid`, should be a byte offset from the start of the + /// string. It must also be on the boundary of a UTF-8 code point. + /// + /// The two slices returned go from the start of the string slice to `mid`, + /// and from `mid` to the end of the string slice. + /// + /// To get mutable string slices instead, see the [`split_at_mut`] + /// method. + /// + /// [`split_at_mut`]: #method.split_at_mut + /// + /// # Panics + /// + /// Panics if `mid` is not on a UTF-8 code point boundary, or if it is + /// beyond the last code point of the string slice. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let s = "Per Martin-Löf"; + /// + /// let (first, last) = s.split_at(3); + /// + /// assert_eq!("Per", first); + /// assert_eq!(" Martin-Löf", last); + /// ``` + #[inline] + #[stable(feature = "str_split_at", since = "1.4.0")] + pub fn split_at(&self, mid: usize) -> (&str, &str) { + core_str::StrExt::split_at(self, mid) + } + + /// Divide one mutable string slice into two at an index. + /// + /// The argument, `mid`, should be a byte offset from the start of the + /// string. It must also be on the boundary of a UTF-8 code point. + /// + /// The two slices returned go from the start of the string slice to `mid`, + /// and from `mid` to the end of the string slice. + /// + /// To get immutable string slices instead, see the [`split_at`] method. + /// + /// [`split_at`]: #method.split_at + /// + /// # Panics + /// + /// Panics if `mid` is not on a UTF-8 code point boundary, or if it is + /// beyond the last code point of the string slice. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let mut s = "Per Martin-Löf".to_string(); + /// + /// let (first, last) = s.split_at_mut(3); + /// + /// assert_eq!("Per", first); + /// assert_eq!(" Martin-Löf", last); + /// ``` + #[inline] + #[stable(feature = "str_split_at", since = "1.4.0")] + pub fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str) { + core_str::StrExt::split_at_mut(self, mid) + } + + /// 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. + /// + /// It's important to remember that [`char`] represents a Unicode Scalar + /// Value, and may not match your idea of what a 'character' is. Iteration + /// over grapheme clusters may be what you actually want. + /// + /// [`char`]: primitive.char.html + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let word = "goodbye"; + /// + /// let count = word.chars().count(); + /// assert_eq!(7, count); + /// + /// let mut chars = word.chars(); + /// + /// assert_eq!(Some('g'), chars.next()); + /// assert_eq!(Some('o'), chars.next()); + /// assert_eq!(Some('o'), chars.next()); + /// assert_eq!(Some('d'), chars.next()); + /// assert_eq!(Some('b'), chars.next()); + /// assert_eq!(Some('y'), chars.next()); + /// assert_eq!(Some('e'), chars.next()); + /// + /// assert_eq!(None, chars.next()); + /// ``` + /// + /// Remember, [`char`]s may not match your human intuition about characters: + /// + /// ``` + /// let y = "y̆"; + /// + /// let mut chars = y.chars(); + /// + /// assert_eq!(Some('y'), chars.next()); // not 'y̆' + /// assert_eq!(Some('\u{0306}'), chars.next()); + /// + /// assert_eq!(None, chars.next()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn chars(&self) -> Chars { + core_str::StrExt::chars(self) + } + /// Returns an iterator over the [`char`]s of a string slice, and their + /// positions. + /// + /// As a string slice consists of valid UTF-8, we can iterate through a + /// string slice by [`char`]. This method returns an iterator of both + /// these [`char`]s, as well as their byte positions. + /// + /// The iterator yields tuples. The position is first, the [`char`] is + /// second. + /// + /// [`char`]: primitive.char.html + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let word = "goodbye"; + /// + /// let count = word.char_indices().count(); + /// assert_eq!(7, count); + /// + /// let mut char_indices = word.char_indices(); + /// + /// assert_eq!(Some((0, 'g')), char_indices.next()); + /// assert_eq!(Some((1, 'o')), char_indices.next()); + /// assert_eq!(Some((2, 'o')), char_indices.next()); + /// assert_eq!(Some((3, 'd')), char_indices.next()); + /// assert_eq!(Some((4, 'b')), char_indices.next()); + /// assert_eq!(Some((5, 'y')), char_indices.next()); + /// assert_eq!(Some((6, 'e')), char_indices.next()); + /// + /// assert_eq!(None, char_indices.next()); + /// ``` + /// + /// Remember, [`char`]s may not match your human intuition about characters: + /// + /// ``` + /// let y = "y̆"; + /// + /// let mut char_indices = y.char_indices(); + /// + /// assert_eq!(Some((0, 'y')), char_indices.next()); // not (0, 'y̆') + /// assert_eq!(Some((1, '\u{0306}')), char_indices.next()); + /// + /// assert_eq!(None, char_indices.next()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn char_indices(&self) -> CharIndices { + core_str::StrExt::char_indices(self) + } + + /// An iterator over the bytes of a string slice. + /// + /// As a string slice consists of a sequence of bytes, we can iterate + /// through a string slice by byte. This method returns such an iterator. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let mut bytes = "bors".bytes(); + /// + /// assert_eq!(Some(b'b'), bytes.next()); + /// assert_eq!(Some(b'o'), bytes.next()); + /// assert_eq!(Some(b'r'), bytes.next()); + /// assert_eq!(Some(b's'), bytes.next()); + /// + /// assert_eq!(None, bytes.next()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn bytes(&self) -> Bytes { + core_str::StrExt::bytes(self) + } + + /// Split a string slice by whitespace. + /// + /// The iterator returned will return string slices that are sub-slices of + /// the original string slice, separated by any amount of whitespace. + /// + /// 'Whitespace' is defined according to the terms of the Unicode Derived + /// Core Property `White_Space`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let mut iter = "A few words".split_whitespace(); + /// + /// assert_eq!(Some("A"), iter.next()); + /// assert_eq!(Some("few"), iter.next()); + /// assert_eq!(Some("words"), iter.next()); + /// + /// assert_eq!(None, iter.next()); + /// ``` + /// + /// All kinds of whitespace are considered: + /// + /// ``` + /// let mut iter = " Mary had\ta\u{2009}little \n\t lamb".split_whitespace(); + /// assert_eq!(Some("Mary"), iter.next()); + /// assert_eq!(Some("had"), iter.next()); + /// assert_eq!(Some("a"), iter.next()); + /// assert_eq!(Some("little"), iter.next()); + /// assert_eq!(Some("lamb"), iter.next()); + /// + /// assert_eq!(None, iter.next()); + /// ``` + #[stable(feature = "split_whitespace", since = "1.1.0")] + #[inline] + pub fn split_whitespace(&self) -> SplitWhitespace { + UnicodeStr::split_whitespace(self) + } + + /// An iterator over the lines of a string, as string slices. + /// + /// Lines are ended with either a newline (`\n`) or a carriage return with + /// a line feed (`\r\n`). + /// + /// The final line ending is optional. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let text = "foo\r\nbar\n\nbaz\n"; + /// let mut lines = text.lines(); + /// + /// assert_eq!(Some("foo"), lines.next()); + /// assert_eq!(Some("bar"), lines.next()); + /// assert_eq!(Some(""), lines.next()); + /// assert_eq!(Some("baz"), lines.next()); + /// + /// assert_eq!(None, lines.next()); + /// ``` + /// + /// The final line ending isn't required: + /// + /// ``` + /// let text = "foo\nbar\n\r\nbaz"; + /// let mut lines = text.lines(); + /// + /// assert_eq!(Some("foo"), lines.next()); + /// assert_eq!(Some("bar"), lines.next()); + /// assert_eq!(Some(""), lines.next()); + /// assert_eq!(Some("baz"), lines.next()); + /// + /// assert_eq!(None, lines.next()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn lines(&self) -> Lines { + core_str::StrExt::lines(self) + } + + /// An iterator over the lines of a string. + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_deprecated(since = "1.4.0", reason = "use lines() instead now")] + #[inline] + #[allow(deprecated)] + pub fn lines_any(&self) -> LinesAny { + core_str::StrExt::lines_any(self) + } + + /// Returns an iterator of `u16` over the string encoded as UTF-16. + #[stable(feature = "encode_utf16", since = "1.8.0")] + pub fn encode_utf16(&self) -> EncodeUtf16 { + EncodeUtf16 { encoder: Utf16Encoder::new(self[..].chars()) } + } + + /// Returns `true` if the given pattern matches a sub-slice of + /// this string slice. + /// + /// Returns `false` if it does not. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let bananas = "bananas"; + /// + /// assert!(bananas.contains("nana")); + /// assert!(!bananas.contains("apples")); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn contains<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool { + core_str::StrExt::contains(self, pat) + } + + /// Returns `true` if the given pattern matches a prefix of this + /// string slice. + /// + /// Returns `false` if it does not. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let bananas = "bananas"; + /// + /// assert!(bananas.starts_with("bana")); + /// assert!(!bananas.starts_with("nana")); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn starts_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool { + core_str::StrExt::starts_with(self, pat) + } + + /// Returns `true` if the given pattern matches a suffix of this + /// string slice. + /// + /// Returns `false` if it does not. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let bananas = "bananas"; + /// + /// assert!(bananas.ends_with("anas")); + /// assert!(!bananas.ends_with("nana")); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn ends_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool + where P::Searcher: ReverseSearcher<'a> + { + core_str::StrExt::ends_with(self, pat) + } + + /// Returns the byte index of the first character of this string slice that + /// matches the pattern. + /// + /// Returns [`None`] if the pattern doesn't match. + /// + /// The pattern can be a `&str`, [`char`], or a closure that determines if + /// a character matches. + /// + /// [`char`]: primitive.char.html + /// [`None`]: option/enum.Option.html#variant.None + /// + /// # Examples + /// + /// Simple patterns: + /// + /// ``` + /// let s = "Löwe 老虎 Léopard"; + /// + /// assert_eq!(s.find('L'), Some(0)); + /// assert_eq!(s.find('é'), Some(14)); + /// assert_eq!(s.find("Léopard"), Some(13)); + /// ``` + /// + /// More complex patterns with closures: + /// + /// ``` + /// let s = "Löwe 老虎 Léopard"; + /// + /// assert_eq!(s.find(char::is_whitespace), Some(5)); + /// assert_eq!(s.find(char::is_lowercase), Some(1)); + /// ``` + /// + /// Not finding the pattern: + /// + /// ``` + /// let s = "Löwe 老虎 Léopard"; + /// let x: &[_] = &['1', '2']; + /// + /// assert_eq!(s.find(x), None); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option { + core_str::StrExt::find(self, pat) + } + + /// Returns the byte index of the last character of this string slice that + /// matches the pattern. + /// + /// Returns [`None`] if the pattern doesn't match. + /// + /// The pattern can be a `&str`, [`char`], or a closure that determines if + /// a character matches. + /// + /// [`char`]: primitive.char.html + /// [`None`]: option/enum.Option.html#variant.None + /// + /// # Examples + /// + /// Simple patterns: + /// + /// ``` + /// let s = "Löwe 老虎 Léopard"; + /// + /// assert_eq!(s.rfind('L'), Some(13)); + /// assert_eq!(s.rfind('é'), Some(14)); + /// ``` + /// + /// More complex patterns with closures: + /// + /// ``` + /// let s = "Löwe 老虎 Léopard"; + /// + /// assert_eq!(s.rfind(char::is_whitespace), Some(12)); + /// assert_eq!(s.rfind(char::is_lowercase), Some(20)); + /// ``` + /// + /// Not finding the pattern: + /// + /// ``` + /// let s = "Löwe 老虎 Léopard"; + /// let x: &[_] = &['1', '2']; + /// + /// assert_eq!(s.rfind(x), None); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn rfind<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option + where P::Searcher: ReverseSearcher<'a> + { + core_str::StrExt::rfind(self, pat) + } + + /// An iterator over substrings of this string slice, separated by + /// characters matched by a pattern. + /// + /// The pattern can be a `&str`, [`char`], or a closure that determines the + /// split. + /// + /// # Iterator behavior + /// + /// The returned iterator will be a [`DoubleEndedIterator`] if the pattern + /// allows a reverse search and forward/reverse search yields the same + /// elements. This is true for, eg, [`char`] but not for `&str`. + /// + /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html + /// + /// If the pattern allows a reverse search but its results might differ + /// from a forward search, the [`rsplit`] method can be used. + /// + /// [`char`]: primitive.char.html + /// [`rsplit`]: #method.rsplit + /// + /// # Examples + /// + /// Simple patterns: + /// + /// ``` + /// let v: Vec<&str> = "Mary had a little lamb".split(' ').collect(); + /// assert_eq!(v, ["Mary", "had", "a", "little", "lamb"]); + /// + /// let v: Vec<&str> = "".split('X').collect(); + /// assert_eq!(v, [""]); + /// + /// let v: Vec<&str> = "lionXXtigerXleopard".split('X').collect(); + /// assert_eq!(v, ["lion", "", "tiger", "leopard"]); + /// + /// let v: Vec<&str> = "lion::tiger::leopard".split("::").collect(); + /// assert_eq!(v, ["lion", "tiger", "leopard"]); + /// + /// let v: Vec<&str> = "abc1def2ghi".split(char::is_numeric).collect(); + /// assert_eq!(v, ["abc", "def", "ghi"]); + /// + /// let v: Vec<&str> = "lionXtigerXleopard".split(char::is_uppercase).collect(); + /// assert_eq!(v, ["lion", "tiger", "leopard"]); + /// ``` + /// + /// A more complex pattern, using a closure: + /// + /// ``` + /// let v: Vec<&str> = "abc1defXghi".split(|c| c == '1' || c == 'X').collect(); + /// assert_eq!(v, ["abc", "def", "ghi"]); + /// ``` + /// + /// If a string contains multiple contiguous separators, you will end up + /// with empty strings in the output: + /// + /// ``` + /// let x = "||||a||b|c".to_string(); + /// let d: Vec<_> = x.split('|').collect(); + /// + /// assert_eq!(d, &["", "", "", "", "a", "", "b", "c"]); + /// ``` + /// + /// Contiguous separators are separated by the empty string. + /// + /// ``` + /// let x = "(///)".to_string(); + /// let d: Vec<_> = x.split('/').collect(); + /// + /// assert_eq!(d, &["(", "", "", ")"]); + /// ``` + /// + /// Separators at the start or end of a string are neighbored + /// by empty strings. + /// + /// ``` + /// let d: Vec<_> = "010".split("0").collect(); + /// assert_eq!(d, &["", "1", ""]); + /// ``` + /// + /// When the empty string is used as a separator, it separates + /// every character in the string, along with the beginning + /// and end of the string. + /// + /// ``` + /// let f: Vec<_> = "rust".split("").collect(); + /// assert_eq!(f, &["", "r", "u", "s", "t", ""]); + /// ``` + /// + /// Contiguous separators can lead to possibly surprising behavior + /// when whitespace is used as the separator. This code is correct: + /// + /// ``` + /// let x = " a b c".to_string(); + /// let d: Vec<_> = x.split(' ').collect(); + /// + /// assert_eq!(d, &["", "", "", "", "a", "", "b", "c"]); + /// ``` + /// + /// It does _not_ give you: + /// + /// ```,ignore + /// assert_eq!(d, &["a", "b", "c"]); + /// ``` + /// + /// Use [`split_whitespace`] for this behavior. + /// + /// [`split_whitespace`]: #method.split_whitespace + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P> { + core_str::StrExt::split(self, pat) + } + + /// An iterator over substrings of the given string slice, separated by + /// characters matched by a pattern and yielded in reverse order. + /// + /// The pattern can be a `&str`, [`char`], or a closure that determines the + /// split. + /// + /// [`char`]: primitive.char.html + /// + /// # Iterator behavior + /// + /// The returned iterator requires that the pattern supports a reverse + /// search, and it will be a [`DoubleEndedIterator`] if a forward/reverse + /// search yields the same elements. + /// + /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html + /// + /// For iterating from the front, the [`split`] method can be used. + /// + /// [`split`]: #method.split + /// + /// # Examples + /// + /// Simple patterns: + /// + /// ``` + /// let v: Vec<&str> = "Mary had a little lamb".rsplit(' ').collect(); + /// assert_eq!(v, ["lamb", "little", "a", "had", "Mary"]); + /// + /// let v: Vec<&str> = "".rsplit('X').collect(); + /// assert_eq!(v, [""]); + /// + /// let v: Vec<&str> = "lionXXtigerXleopard".rsplit('X').collect(); + /// assert_eq!(v, ["leopard", "tiger", "", "lion"]); + /// + /// let v: Vec<&str> = "lion::tiger::leopard".rsplit("::").collect(); + /// assert_eq!(v, ["leopard", "tiger", "lion"]); + /// ``` + /// + /// A more complex pattern, using a closure: + /// + /// ``` + /// let v: Vec<&str> = "abc1defXghi".rsplit(|c| c == '1' || c == 'X').collect(); + /// assert_eq!(v, ["ghi", "def", "abc"]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn rsplit<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplit<'a, P> + where P::Searcher: ReverseSearcher<'a> + { + core_str::StrExt::rsplit(self, pat) + } + + /// An iterator over substrings of the given string slice, separated by + /// characters matched by a pattern. + /// + /// The pattern can be a `&str`, [`char`], or a closure that determines the + /// split. + /// + /// Equivalent to [`split`], except that the trailing substring + /// is skipped if empty. + /// + /// [`split`]: #method.split + /// + /// This method can be used for string data that is _terminated_, + /// rather than _separated_ by a pattern. + /// + /// # Iterator behavior + /// + /// The returned iterator will be a [`DoubleEndedIterator`] if the pattern + /// allows a reverse search and forward/reverse search yields the same + /// elements. This is true for, eg, [`char`] but not for `&str`. + /// + /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html + /// [`char`]: primitive.char.html + /// + /// If the pattern allows a reverse search but its results might differ + /// from a forward search, the [`rsplit_terminator`] method can be used. + /// + /// [`rsplit_terminator`]: #method.rsplit_terminator + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let v: Vec<&str> = "A.B.".split_terminator('.').collect(); + /// assert_eq!(v, ["A", "B"]); + /// + /// let v: Vec<&str> = "A..B..".split_terminator(".").collect(); + /// assert_eq!(v, ["A", "", "B", ""]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn split_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitTerminator<'a, P> { + core_str::StrExt::split_terminator(self, pat) + } + + /// An iterator over substrings of `self`, separated by characters + /// matched by a pattern and yielded in reverse order. + /// + /// The pattern can be a simple `&str`, [`char`], or a closure that + /// determines the split. + /// Additional libraries might provide more complex patterns like + /// regular expressions. + /// + /// [`char`]: primitive.char.html + /// + /// Equivalent to [`split`], except that the trailing substring is + /// skipped if empty. + /// + /// [`split`]: #method.split + /// + /// This method can be used for string data that is _terminated_, + /// rather than _separated_ by a pattern. + /// + /// # Iterator behavior + /// + /// The returned iterator requires that the pattern supports a + /// reverse search, and it will be double ended if a forward/reverse + /// search yields the same elements. + /// + /// For iterating from the front, the [`split_terminator`] method can be + /// used. + /// + /// [`split_terminator`]: #method.split_terminator + /// + /// # Examples + /// + /// ``` + /// let v: Vec<&str> = "A.B.".rsplit_terminator('.').collect(); + /// assert_eq!(v, ["B", "A"]); + /// + /// let v: Vec<&str> = "A..B..".rsplit_terminator(".").collect(); + /// assert_eq!(v, ["", "B", "", "A"]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn rsplit_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplitTerminator<'a, P> + where P::Searcher: ReverseSearcher<'a> + { + core_str::StrExt::rsplit_terminator(self, pat) + } + + /// An iterator over substrings of the given string slice, separated by a + /// pattern, restricted to returning at most `n` items. + /// + /// If `n` substrings are returned, the last substring (the `n`th substring) + /// will contain the remainder of the string. + /// + /// The pattern can be a `&str`, [`char`], or a closure that determines the + /// split. + /// + /// [`char`]: primitive.char.html + /// + /// # Iterator behavior + /// + /// The returned iterator will not be double ended, because it is + /// not efficient to support. + /// + /// If the pattern allows a reverse search, the [`rsplitn`] method can be + /// used. + /// + /// [`rsplitn`]: #method.rsplitn + /// + /// # Examples + /// + /// Simple patterns: + /// + /// ``` + /// let v: Vec<&str> = "Mary had a little lambda".splitn(3, ' ').collect(); + /// assert_eq!(v, ["Mary", "had", "a little lambda"]); + /// + /// let v: Vec<&str> = "lionXXtigerXleopard".splitn(3, "X").collect(); + /// assert_eq!(v, ["lion", "", "tigerXleopard"]); + /// + /// let v: Vec<&str> = "abcXdef".splitn(1, 'X').collect(); + /// assert_eq!(v, ["abcXdef"]); + /// + /// let v: Vec<&str> = "".splitn(1, 'X').collect(); + /// assert_eq!(v, [""]); + /// ``` + /// + /// A more complex pattern, using a closure: + /// + /// ``` + /// let v: Vec<&str> = "abc1defXghi".splitn(2, |c| c == '1' || c == 'X').collect(); + /// assert_eq!(v, ["abc", "defXghi"]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn splitn<'a, P: Pattern<'a>>(&'a self, n: usize, pat: P) -> SplitN<'a, P> { + core_str::StrExt::splitn(self, n, pat) + } + + /// An iterator over substrings of this string slice, separated by a + /// pattern, starting from the end of the string, restricted to returning + /// at most `n` items. + /// + /// If `n` substrings are returned, the last substring (the `n`th substring) + /// will contain the remainder of the string. + /// + /// The pattern can be a `&str`, [`char`], or a closure that + /// determines the split. + /// + /// [`char`]: primitive.char.html + /// + /// # Iterator behavior + /// + /// The returned iterator will not be double ended, because it is not + /// efficient to support. + /// + /// For splitting from the front, the [`splitn`] method can be used. + /// + /// [`splitn`]: #method.splitn + /// + /// # Examples + /// + /// Simple patterns: + /// + /// ``` + /// let v: Vec<&str> = "Mary had a little lamb".rsplitn(3, ' ').collect(); + /// assert_eq!(v, ["lamb", "little", "Mary had a"]); + /// + /// let v: Vec<&str> = "lionXXtigerXleopard".rsplitn(3, 'X').collect(); + /// assert_eq!(v, ["leopard", "tiger", "lionX"]); + /// + /// let v: Vec<&str> = "lion::tiger::leopard".rsplitn(2, "::").collect(); + /// assert_eq!(v, ["leopard", "lion::tiger"]); + /// ``` + /// + /// A more complex pattern, using a closure: + /// + /// ``` + /// let v: Vec<&str> = "abc1defXghi".rsplitn(2, |c| c == '1' || c == 'X').collect(); + /// assert_eq!(v, ["ghi", "abc1def"]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn rsplitn<'a, P: Pattern<'a>>(&'a self, n: usize, pat: P) -> RSplitN<'a, P> + where P::Searcher: ReverseSearcher<'a> + { + core_str::StrExt::rsplitn(self, n, pat) + } + + /// An iterator over the disjoint matches of a pattern within the given string + /// slice. + /// + /// The pattern can be a `&str`, [`char`], or a closure that + /// determines if a character matches. + /// + /// [`char`]: primitive.char.html + /// + /// # Iterator behavior + /// + /// The returned iterator will be a [`DoubleEndedIterator`] if the pattern + /// allows a reverse search and forward/reverse search yields the same + /// elements. This is true for, eg, [`char`] but not for `&str`. + /// + /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html + /// [`char`]: primitive.char.html + /// + /// If the pattern allows a reverse search but its results might differ + /// from a forward search, the [`rmatches`] method can be used. + /// + /// [`rmatches`]: #method.rmatches + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let v: Vec<&str> = "abcXXXabcYYYabc".matches("abc").collect(); + /// assert_eq!(v, ["abc", "abc", "abc"]); + /// + /// let v: Vec<&str> = "1abc2abc3".matches(char::is_numeric).collect(); + /// assert_eq!(v, ["1", "2", "3"]); + /// ``` + #[stable(feature = "str_matches", since = "1.2.0")] + #[inline] + pub fn matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> Matches<'a, P> { + core_str::StrExt::matches(self, pat) + } + + /// An iterator over the disjoint matches of a pattern within this string slice, + /// yielded in reverse order. + /// + /// The pattern can be a `&str`, [`char`], or a closure that determines if + /// a character matches. + /// + /// [`char`]: primitive.char.html + /// + /// # Iterator behavior + /// + /// The returned iterator requires that the pattern supports a reverse + /// search, and it will be a [`DoubleEndedIterator`] if a forward/reverse + /// search yields the same elements. + /// + /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html + /// + /// For iterating from the front, the [`matches`] method can be used. + /// + /// [`matches`]: #method.matches + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let v: Vec<&str> = "abcXXXabcYYYabc".rmatches("abc").collect(); + /// assert_eq!(v, ["abc", "abc", "abc"]); + /// + /// let v: Vec<&str> = "1abc2abc3".rmatches(char::is_numeric).collect(); + /// assert_eq!(v, ["3", "2", "1"]); + /// ``` + #[stable(feature = "str_matches", since = "1.2.0")] + #[inline] + pub fn rmatches<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatches<'a, P> + where P::Searcher: ReverseSearcher<'a> + { + core_str::StrExt::rmatches(self, pat) + } + + /// An iterator over the disjoint matches of a pattern within this string + /// slice as well as the index that the match starts at. + /// + /// For matches of `pat` within `self` that overlap, only the indices + /// corresponding to the first match are returned. + /// + /// The pattern can be a `&str`, [`char`], or a closure that determines + /// if a character matches. + /// + /// [`char`]: primitive.char.html + /// + /// # Iterator behavior + /// + /// The returned iterator will be a [`DoubleEndedIterator`] if the pattern + /// allows a reverse search and forward/reverse search yields the same + /// elements. This is true for, eg, [`char`] but not for `&str`. + /// + /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html + /// + /// If the pattern allows a reverse search but its results might differ + /// from a forward search, the [`rmatch_indices`] method can be used. + /// + /// [`rmatch_indices`]: #method.rmatch_indices + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let v: Vec<_> = "abcXXXabcYYYabc".match_indices("abc").collect(); + /// assert_eq!(v, [(0, "abc"), (6, "abc"), (12, "abc")]); + /// + /// let v: Vec<_> = "1abcabc2".match_indices("abc").collect(); + /// assert_eq!(v, [(1, "abc"), (4, "abc")]); + /// + /// let v: Vec<_> = "ababa".match_indices("aba").collect(); + /// assert_eq!(v, [(0, "aba")]); // only the first `aba` + /// ``` + #[stable(feature = "str_match_indices", since = "1.5.0")] + #[inline] + pub fn match_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> MatchIndices<'a, P> { + core_str::StrExt::match_indices(self, pat) + } + + /// An iterator over the disjoint matches of a pattern within `self`, + /// yielded in reverse order along with the index of the match. + /// + /// For matches of `pat` within `self` that overlap, only the indices + /// corresponding to the last match are returned. + /// + /// The pattern can be a `&str`, [`char`], or a closure that determines if a + /// character matches. + /// + /// [`char`]: primitive.char.html + /// + /// # Iterator behavior + /// + /// The returned iterator requires that the pattern supports a reverse + /// search, and it will be a [`DoubleEndedIterator`] if a forward/reverse + /// search yields the same elements. + /// + /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html + /// + /// For iterating from the front, the [`match_indices`] method can be used. + /// + /// [`match_indices`]: #method.match_indices + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let v: Vec<_> = "abcXXXabcYYYabc".rmatch_indices("abc").collect(); + /// assert_eq!(v, [(12, "abc"), (6, "abc"), (0, "abc")]); + /// + /// let v: Vec<_> = "1abcabc2".rmatch_indices("abc").collect(); + /// assert_eq!(v, [(4, "abc"), (1, "abc")]); + /// + /// let v: Vec<_> = "ababa".rmatch_indices("aba").collect(); + /// assert_eq!(v, [(2, "aba")]); // only the last `aba` + /// ``` + #[stable(feature = "str_match_indices", since = "1.5.0")] + #[inline] + pub fn rmatch_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatchIndices<'a, P> + where P::Searcher: ReverseSearcher<'a> + { + core_str::StrExt::rmatch_indices(self, pat) + } + + /// Returns a string slice with leading and trailing whitespace removed. + /// + /// 'Whitespace' is defined according to the terms of the Unicode Derived + /// Core Property `White_Space`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let s = " Hello\tworld\t"; + /// + /// assert_eq!("Hello\tworld", s.trim()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn trim(&self) -> &str { + UnicodeStr::trim(self) + } + + /// Returns a string slice with leading whitespace removed. + /// + /// 'Whitespace' is defined according to the terms of the Unicode Derived + /// Core Property `White_Space`. + /// + /// # Text directionality + /// + /// A string is a sequence of bytes. 'Left' in this context means the first + /// position of that byte string; for a language like Arabic or Hebrew + /// which are 'right to left' rather than 'left to right', this will be + /// the _right_ side, not the left. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let s = " Hello\tworld\t"; + /// + /// assert_eq!("Hello\tworld\t", s.trim_left()); + /// ``` + /// + /// Directionality: + /// + /// ``` + /// let s = " English"; + /// assert!(Some('E') == s.trim_left().chars().next()); + /// + /// let s = " עברית"; + /// assert!(Some('ע') == s.trim_left().chars().next()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn trim_left(&self) -> &str { + UnicodeStr::trim_left(self) + } + + /// Returns a string slice with trailing whitespace removed. + /// + /// 'Whitespace' is defined according to the terms of the Unicode Derived + /// Core Property `White_Space`. + /// + /// # Text directionality + /// + /// A string is a sequence of bytes. 'Right' in this context means the last + /// position of that byte string; for a language like Arabic or Hebrew + /// which are 'right to left' rather than 'left to right', this will be + /// the _left_ side, not the right. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let s = " Hello\tworld\t"; + /// + /// assert_eq!(" Hello\tworld", s.trim_right()); + /// ``` + /// + /// Directionality: + /// + /// ``` + /// let s = "English "; + /// assert!(Some('h') == s.trim_right().chars().rev().next()); + /// + /// let s = "עברית "; + /// assert!(Some('ת') == s.trim_right().chars().rev().next()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn trim_right(&self) -> &str { + UnicodeStr::trim_right(self) + } + + /// Returns a string slice with all prefixes and suffixes that match a + /// pattern repeatedly removed. + /// + /// The pattern can be a [`char`] or a closure that determines if a + /// character matches. + /// + /// [`char`]: primitive.char.html + /// + /// # Examples + /// + /// Simple patterns: + /// + /// ``` + /// assert_eq!("11foo1bar11".trim_matches('1'), "foo1bar"); + /// assert_eq!("123foo1bar123".trim_matches(char::is_numeric), "foo1bar"); + /// + /// let x: &[_] = &['1', '2']; + /// assert_eq!("12foo1bar12".trim_matches(x), "foo1bar"); + /// ``` + /// + /// A more complex pattern, using a closure: + /// + /// ``` + /// assert_eq!("1foo1barXX".trim_matches(|c| c == '1' || c == 'X'), "foo1bar"); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn trim_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str + where P::Searcher: DoubleEndedSearcher<'a> + { + core_str::StrExt::trim_matches(self, pat) + } + + /// Returns a string slice with all prefixes that match a pattern + /// repeatedly removed. + /// + /// The pattern can be a `&str`, [`char`], or a closure that determines if + /// a character matches. + /// + /// [`char`]: primitive.char.html + /// + /// # Text directionality + /// + /// A string is a sequence of bytes. 'Left' in this context means the first + /// position of that byte string; for a language like Arabic or Hebrew + /// which are 'right to left' rather than 'left to right', this will be + /// the _right_ side, not the left. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// assert_eq!("11foo1bar11".trim_left_matches('1'), "foo1bar11"); + /// assert_eq!("123foo1bar123".trim_left_matches(char::is_numeric), "foo1bar123"); + /// + /// let x: &[_] = &['1', '2']; + /// assert_eq!("12foo1bar12".trim_left_matches(x), "foo1bar12"); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn trim_left_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str { + core_str::StrExt::trim_left_matches(self, pat) + } + + /// Returns a string slice with all suffixes that match a pattern + /// repeatedly removed. + /// + /// The pattern can be a `&str`, [`char`], or a closure that + /// determines if a character matches. + /// + /// [`char`]: primitive.char.html + /// + /// # Text directionality + /// + /// A string is a sequence of bytes. 'Right' in this context means the last + /// position of that byte string; for a language like Arabic or Hebrew + /// which are 'right to left' rather than 'left to right', this will be + /// the _left_ side, not the right. + /// + /// # Examples + /// + /// Simple patterns: + /// + /// ``` + /// assert_eq!("11foo1bar11".trim_right_matches('1'), "11foo1bar"); + /// assert_eq!("123foo1bar123".trim_right_matches(char::is_numeric), "123foo1bar"); + /// + /// let x: &[_] = &['1', '2']; + /// assert_eq!("12foo1bar12".trim_right_matches(x), "12foo1bar"); + /// ``` + /// + /// A more complex pattern, using a closure: + /// + /// ``` + /// assert_eq!("1fooX".trim_left_matches(|c| c == '1' || c == 'X'), "fooX"); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn trim_right_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str + where P::Searcher: ReverseSearcher<'a> + { + core_str::StrExt::trim_right_matches(self, pat) + } + + /// 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 + /// 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. + /// + /// [`FromStr`]: str/trait.FromStr.html + /// + /// # Errors + /// + /// Will return [`Err`] if it's not possible to parse this string slice into + /// the desired type. + /// + /// [`Err`]: str/trait.FromStr.html#associatedtype.Err + /// + /// # Example + /// + /// Basic usage + /// + /// ``` + /// let four: u32 = "4".parse().unwrap(); + /// + /// assert_eq!(4, four); + /// ``` + /// + /// Using the 'turbofish' instead of annotating `four`: + /// + /// ``` + /// let four = "4".parse::(); + /// + /// assert_eq!(Ok(4), four); + /// ``` + /// + /// Failing to parse: + /// + /// ``` + /// let nope = "j".parse::(); + /// + /// assert!(nope.is_err()); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn parse(&self) -> Result { + 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. + /// While doing so, it attempts to find matches of a pattern. If it finds any, it + /// replaces them with the replacement string slice. + /// + /// [`String`]: string/struct.String.html + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let s = "this is old"; + /// + /// assert_eq!("this is new", s.replace("old", "new")); + /// ``` + /// + /// When the pattern doesn't match: + /// + /// ``` + /// let s = "this is old"; + /// assert_eq!(s, s.replace("cookie monster", "little lamb")); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn replace<'a, P: Pattern<'a>>(&'a self, from: P, to: &str) -> String { + let mut result = String::new(); + let mut last_end = 0; + for (start, part) in self.match_indices(from) { + result.push_str(unsafe { self.slice_unchecked(last_end, start) }); + result.push_str(to); + last_end = start + part.len(); + } + result.push_str(unsafe { self.slice_unchecked(last_end, self.len()) }); + result + } + + /// Replaces first N matches of a pattern with another string. + /// + /// `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 `count` times. + /// + /// [`String`]: string/struct.String.html + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let s = "foo foo 123 foo"; + /// assert_eq!("new new 123 foo", s.replacen("foo", "new", 2)); + /// assert_eq!("faa fao 123 foo", s.replacen('o', "a", 3)); + /// assert_eq!("foo foo new23 foo", s.replacen(char::is_numeric, "new", 1)); + /// ``` + /// + /// When the pattern doesn't match: + /// + /// ``` + /// let s = "this is old"; + /// assert_eq!(s, s.replacen("cookie monster", "little lamb", 10)); + /// ``` + #[stable(feature = "str_replacen", since = "1.16.0")] + pub fn replacen<'a, P: Pattern<'a>>(&'a self, pat: P, to: &str, count: usize) -> String { + // Hope to reduce the times of re-allocation + let mut result = String::with_capacity(32); + let mut last_end = 0; + for (start, part) in self.match_indices(pat).take(count) { + result.push_str(unsafe { self.slice_unchecked(last_end, start) }); + result.push_str(to); + last_end = start + part.len(); + } + result.push_str(unsafe { self.slice_unchecked(last_end, self.len()) }); + result + } + + /// Returns the lowercase equivalent of this string slice, as a new [`String`]. + /// + /// 'Lowercase' is defined according to the terms of the Unicode Derived Core Property + /// `Lowercase`. + /// + /// Since some characters can expand into multiple characters when changing + /// the case, this function returns a [`String`] instead of modifying the + /// parameter in-place. + /// + /// [`String`]: string/struct.String.html + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let s = "HELLO"; + /// + /// assert_eq!("hello", s.to_lowercase()); + /// ``` + /// + /// A tricky example, with sigma: + /// + /// ``` + /// let sigma = "Σ"; + /// + /// assert_eq!("σ", sigma.to_lowercase()); + /// + /// // but at the end of a word, it's ς, not σ: + /// let odysseus = "ὈΔΥΣΣΕΎΣ"; + /// + /// assert_eq!("ὀδυσσεύς", odysseus.to_lowercase()); + /// ``` + /// + /// Languages without case are not changed: + /// + /// ``` + /// let new_year = "农历新年"; + /// + /// assert_eq!(new_year, new_year.to_lowercase()); + /// ``` + #[stable(feature = "unicode_case_mapping", since = "1.2.0")] + pub fn to_lowercase(&self) -> String { + let mut s = String::with_capacity(self.len()); + for (i, c) in self[..].char_indices() { + if c == 'Σ' { + // Σ maps to σ, except at the end of a word where it maps to ς. + // This is the only conditional (contextual) but language-independent mapping + // in `SpecialCasing.txt`, + // so hard-code it rather than have a generic "condition" mechanism. + // See https://github.com/rust-lang/rust/issues/26035 + map_uppercase_sigma(self, i, &mut s) + } else { + s.extend(c.to_lowercase()); + } + } + return s; + + fn map_uppercase_sigma(from: &str, i: usize, to: &mut String) { + // See http://www.unicode.org/versions/Unicode7.0.0/ch03.pdf#G33992 + // for the definition of `Final_Sigma`. + debug_assert!('Σ'.len_utf8() == 2); + let is_word_final = case_ignoreable_then_cased(from[..i].chars().rev()) && + !case_ignoreable_then_cased(from[i + 2..].chars()); + to.push_str(if is_word_final { "ς" } else { "σ" }); + } + + fn case_ignoreable_then_cased>(iter: I) -> bool { + use std_unicode::derived_property::{Cased, Case_Ignorable}; + match iter.skip_while(|&c| Case_Ignorable(c)).next() { + Some(c) => Cased(c), + None => false, + } + } + } + + /// Returns the uppercase equivalent of this string slice, as a new [`String`]. + /// + /// 'Uppercase' is defined according to the terms of the Unicode Derived Core Property + /// `Uppercase`. + /// + /// Since some characters can expand into multiple characters when changing + /// the case, this function returns a [`String`] instead of modifying the + /// parameter in-place. + /// + /// [`String`]: string/struct.String.html + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let s = "hello"; + /// + /// assert_eq!("HELLO", s.to_uppercase()); + /// ``` + /// + /// Scripts without case are not changed: + /// + /// ``` + /// let new_year = "农历新年"; + /// + /// assert_eq!(new_year, new_year.to_uppercase()); + /// ``` + #[stable(feature = "unicode_case_mapping", since = "1.2.0")] + pub fn to_uppercase(&self) -> String { + let mut s = String::with_capacity(self.len()); + s.extend(self.chars().flat_map(|c| c.to_uppercase())); + return s; + } + + /// 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")] + pub fn escape_debug(&self) -> String { + self.chars().flat_map(|c| c.escape_debug()).collect() + } + + /// Escapes each char in `s` with [`char::escape_default`]. + /// + /// [`char::escape_default`]: primitive.char.html#method.escape_default + #[unstable(feature = "str_escape", + reason = "return type may change to be an iterator", + issue = "27791")] + pub fn escape_default(&self) -> String { + self.chars().flat_map(|c| c.escape_default()).collect() + } + + /// Escapes each char in `s` with [`char::escape_unicode`]. + /// + /// [`char::escape_unicode`]: primitive.char.html#method.escape_unicode + #[unstable(feature = "str_escape", + reason = "return type may change to be an iterator", + issue = "27791")] + pub fn escape_unicode(&self) -> String { + self.chars().flat_map(|c| c.escape_unicode()).collect() + } + + /// Converts a [`Box`] into a [`String`] without copying or allocating. + /// + /// [`String`]: string/struct.String.html + /// [`Box`]: boxed/struct.Box.html + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let string = String::from("birthday gift"); + /// let boxed_str = string.clone().into_boxed_str(); + /// + /// assert_eq!(boxed_str.into_string(), string); + /// ``` + #[stable(feature = "box_str", since = "1.4.0")] + pub fn into_string(self: Box) -> String { + unsafe { + let slice = mem::transmute::, Box<[u8]>>(self); + String::from_utf8_unchecked(slice.into_vec()) + } + } + + /// Create a [`String`] by repeating a string `n` times. + /// + /// [`String`]: string/struct.String.html + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// assert_eq!("abc".repeat(4), String::from("abcabcabcabc")); + /// ``` + #[stable(feature = "repeat_str", since = "1.16.0")] + pub fn repeat(&self, n: usize) -> String { + let mut s = String::with_capacity(self.len() * n); + s.extend((0..n).map(|_| self)); + s + } +} + /// 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")] diff --git a/src/libcollections/string.rs b/src/liballoc/string.rs similarity index 94% rename from src/libcollections/string.rs rename to src/liballoc/string.rs index 55f0e01548fe..2cb81029f95e 100644 --- a/src/libcollections/string.rs +++ b/src/liballoc/string.rs @@ -56,21 +56,19 @@ #![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::ops::{self, Add, AddAssign, Index, IndexMut}; use core::ptr; -use core::str as core_str; use core::str::pattern::Pattern; +use std_unicode::lossy; use std_unicode::char::{decode_utf16, REPLACEMENT_CHARACTER}; use borrow::{Cow, ToOwned}; use range::RangeArgument; use Bound::{Excluded, Included, Unbounded}; -use str::{self, FromStr, Utf8Error, Chars}; +use str::{self, from_boxed_utf8_unchecked, FromStr, Utf8Error, Chars}; use vec::Vec; use boxed::Box; @@ -535,111 +533,34 @@ impl String { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn from_utf8_lossy<'a>(v: &'a [u8]) -> Cow<'a, str> { - let mut i; - match str::from_utf8(v) { - Ok(s) => return Cow::Borrowed(s), - Err(e) => i = e.valid_up_to(), + let mut iter = lossy::Utf8Lossy::from_bytes(v).chunks(); + + let (first_valid, first_broken) = if let Some(chunk) = iter.next() { + let lossy::Utf8LossyChunk { valid, broken } = chunk; + if valid.len() == v.len() { + debug_assert!(broken.is_empty()); + return Cow::Borrowed(valid); + } + (valid, broken) + } else { + return Cow::Borrowed(""); + }; + + const REPLACEMENT: &'static str = "\u{FFFD}"; + + let mut res = String::with_capacity(v.len()); + res.push_str(first_valid); + if !first_broken.is_empty() { + res.push_str(REPLACEMENT); } - const TAG_CONT_U8: u8 = 128; - const REPLACEMENT: &'static [u8] = b"\xEF\xBF\xBD"; // U+FFFD in UTF-8 - let total = v.len(); - fn unsafe_get(xs: &[u8], i: usize) -> u8 { - unsafe { *xs.get_unchecked(i) } - } - fn safe_get(xs: &[u8], i: usize, total: usize) -> u8 { - if i >= total { 0 } else { unsafe_get(xs, i) } - } - - let mut res = String::with_capacity(total); - - if i > 0 { - unsafe { res.as_mut_vec().extend_from_slice(&v[..i]) }; - } - - // subseqidx is the index of the first byte of the subsequence we're - // looking at. It's used to copy a bunch of contiguous good codepoints - // at once instead of copying them one by one. - let mut subseqidx = i; - - while i < total { - let i_ = i; - let byte = unsafe_get(v, i); - i += 1; - - macro_rules! error { () => ({ - unsafe { - if subseqidx != i_ { - res.as_mut_vec().extend_from_slice(&v[subseqidx..i_]); - } - subseqidx = i; - res.as_mut_vec().extend_from_slice(REPLACEMENT); - } - })} - - if byte < 128 { - // subseqidx handles this - } else { - let w = core_str::utf8_char_width(byte); - - match w { - 2 => { - if safe_get(v, i, total) & 192 != TAG_CONT_U8 { - error!(); - continue; - } - i += 1; - } - 3 => { - match (byte, safe_get(v, i, total)) { - (0xE0, 0xA0...0xBF) => (), - (0xE1...0xEC, 0x80...0xBF) => (), - (0xED, 0x80...0x9F) => (), - (0xEE...0xEF, 0x80...0xBF) => (), - _ => { - error!(); - continue; - } - } - i += 1; - if safe_get(v, i, total) & 192 != TAG_CONT_U8 { - error!(); - continue; - } - i += 1; - } - 4 => { - match (byte, safe_get(v, i, total)) { - (0xF0, 0x90...0xBF) => (), - (0xF1...0xF3, 0x80...0xBF) => (), - (0xF4, 0x80...0x8F) => (), - _ => { - error!(); - continue; - } - } - i += 1; - if safe_get(v, i, total) & 192 != TAG_CONT_U8 { - error!(); - continue; - } - i += 1; - if safe_get(v, i, total) & 192 != TAG_CONT_U8 { - error!(); - continue; - } - i += 1; - } - _ => { - error!(); - continue; - } - } + for lossy::Utf8LossyChunk { valid, broken } in iter { + res.push_str(valid); + if !broken.is_empty() { + res.push_str(REPLACEMENT); } } - if subseqidx < total { - unsafe { res.as_mut_vec().extend_from_slice(&v[subseqidx..total]) }; - } + Cow::Owned(res) } @@ -1464,7 +1385,7 @@ 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 { alloc_str::from_boxed_utf8_unchecked(slice) } + unsafe { from_boxed_utf8_unchecked(slice) } } } diff --git a/src/libcollections/tests/binary_heap.rs b/src/liballoc/tests/binary_heap.rs similarity index 100% rename from src/libcollections/tests/binary_heap.rs rename to src/liballoc/tests/binary_heap.rs diff --git a/src/libcollections/tests/btree/map.rs b/src/liballoc/tests/btree/map.rs similarity index 100% rename from src/libcollections/tests/btree/map.rs rename to src/liballoc/tests/btree/map.rs diff --git a/src/libcollections/tests/btree/mod.rs b/src/liballoc/tests/btree/mod.rs similarity index 100% rename from src/libcollections/tests/btree/mod.rs rename to src/liballoc/tests/btree/mod.rs diff --git a/src/libcollections/tests/btree/set.rs b/src/liballoc/tests/btree/set.rs similarity index 100% rename from src/libcollections/tests/btree/set.rs rename to src/liballoc/tests/btree/set.rs diff --git a/src/libcollections/tests/cow_str.rs b/src/liballoc/tests/cow_str.rs similarity index 100% rename from src/libcollections/tests/cow_str.rs rename to src/liballoc/tests/cow_str.rs diff --git a/src/libcollections/tests/fmt.rs b/src/liballoc/tests/fmt.rs similarity index 100% rename from src/libcollections/tests/fmt.rs rename to src/liballoc/tests/fmt.rs diff --git a/src/libcollections/tests/lib.rs b/src/liballoc/tests/lib.rs similarity index 94% rename from src/libcollections/tests/lib.rs rename to src/liballoc/tests/lib.rs index 5f5217b73c25..c6d70ee7575f 100644 --- a/src/libcollections/tests/lib.rs +++ b/src/liballoc/tests/lib.rs @@ -10,11 +10,11 @@ #![deny(warnings)] +#![feature(alloc)] #![feature(attr_literals)] #![feature(box_syntax)] #![feature(inclusive_range_syntax)] #![feature(collection_placement)] -#![feature(collections)] #![feature(const_fn)] #![feature(exact_size_is_empty)] #![feature(iterator_step_by)] @@ -24,13 +24,14 @@ #![feature(repr_align)] #![feature(slice_rotate)] #![feature(splice)] +#![feature(str_checked_slicing)] #![feature(str_escape)] #![feature(test)] #![feature(unboxed_closures)] #![feature(unicode)] #![feature(utf8_error_error_len)] -extern crate collections; +extern crate alloc; extern crate test; extern crate std_unicode; extern crate core; diff --git a/src/libcollections/tests/linked_list.rs b/src/liballoc/tests/linked_list.rs similarity index 100% rename from src/libcollections/tests/linked_list.rs rename to src/liballoc/tests/linked_list.rs diff --git a/src/libcollections/tests/slice.rs b/src/liballoc/tests/slice.rs similarity index 100% rename from src/libcollections/tests/slice.rs rename to src/liballoc/tests/slice.rs diff --git a/src/libcollections/tests/str.rs b/src/liballoc/tests/str.rs similarity index 97% rename from src/libcollections/tests/str.rs rename to src/liballoc/tests/str.rs index c9b7104fec4f..9d8ca38b20e4 100644 --- a/src/libcollections/tests/str.rs +++ b/src/liballoc/tests/str.rs @@ -358,6 +358,48 @@ fn test_slice_fail() { &"中华Việt Nam"[0..2]; } +#[test] +#[should_panic] +fn test_str_slice_rangetoinclusive_max_panics() { + &"hello"[...usize::max_value()]; +} + +#[test] +#[should_panic] +fn test_str_slice_rangeinclusive_max_panics() { + &"hello"[1...usize::max_value()]; +} + +#[test] +#[should_panic] +fn test_str_slicemut_rangetoinclusive_max_panics() { + let mut s = "hello".to_owned(); + let s: &mut str = &mut s; + &mut s[...usize::max_value()]; +} + +#[test] +#[should_panic] +fn test_str_slicemut_rangeinclusive_max_panics() { + let mut s = "hello".to_owned(); + let s: &mut str = &mut s; + &mut s[1...usize::max_value()]; +} + +#[test] +fn test_str_get_maxinclusive() { + let mut s = "hello".to_owned(); + { + let s: &str = &s; + assert_eq!(s.get(...usize::max_value()), None); + assert_eq!(s.get(1...usize::max_value()), None); + } + { + let s: &mut str = &mut s; + assert_eq!(s.get(...usize::max_value()), None); + assert_eq!(s.get(1...usize::max_value()), None); + } +} #[test] fn test_is_char_boundary() { diff --git a/src/libcollections/tests/string.rs b/src/liballoc/tests/string.rs similarity index 100% rename from src/libcollections/tests/string.rs rename to src/liballoc/tests/string.rs diff --git a/src/libcollections/tests/vec.rs b/src/liballoc/tests/vec.rs similarity index 100% rename from src/libcollections/tests/vec.rs rename to src/liballoc/tests/vec.rs diff --git a/src/libcollections/tests/vec_deque.rs b/src/liballoc/tests/vec_deque.rs similarity index 100% rename from src/libcollections/tests/vec_deque.rs rename to src/liballoc/tests/vec_deque.rs diff --git a/src/libcollections/vec.rs b/src/liballoc/vec.rs similarity index 99% rename from src/libcollections/vec.rs rename to src/liballoc/vec.rs index 3ef8438bc0bd..8bb16febb048 100644 --- a/src/libcollections/vec.rs +++ b/src/liballoc/vec.rs @@ -9,7 +9,7 @@ // except according to those terms. //! A contiguous growable array type with heap-allocated contents, written -//! `Vec` but pronounced 'vector.' +//! `Vec`. //! //! Vectors have `O(1)` indexing, amortized `O(1)` push (to the end) and //! `O(1)` pop (from the end). @@ -66,10 +66,6 @@ #![stable(feature = "rust1", since = "1.0.0")] -use alloc::boxed::Box; -use alloc::raw_vec::RawVec; -use borrow::ToOwned; -use borrow::Cow; use core::cmp::Ordering; use core::fmt; use core::hash::{self, Hash}; @@ -84,6 +80,10 @@ use core::ptr; use core::ptr::Shared; use core::slice; +use borrow::ToOwned; +use borrow::Cow; +use boxed::Box; +use raw_vec::RawVec; use super::range::RangeArgument; use Bound::{Excluded, Included, Unbounded}; diff --git a/src/libcollections/vec_deque.rs b/src/liballoc/vec_deque.rs similarity index 99% rename from src/libcollections/vec_deque.rs rename to src/liballoc/vec_deque.rs index e826c9432b51..18175a5d01bd 100644 --- a/src/libcollections/vec_deque.rs +++ b/src/liballoc/vec_deque.rs @@ -29,7 +29,7 @@ use core::slice; use core::hash::{Hash, Hasher}; use core::cmp; -use alloc::raw_vec::RawVec; +use raw_vec::RawVec; use super::range::RangeArgument; use Bound::{Excluded, Included, Unbounded}; diff --git a/src/liballoc_jemalloc/build.rs b/src/liballoc_jemalloc/build.rs index 859e414a6fe7..f3a0eebe6984 100644 --- a/src/liballoc_jemalloc/build.rs +++ b/src/liballoc_jemalloc/build.rs @@ -93,7 +93,29 @@ fn main() { .env("AR", &ar) .env("RANLIB", format!("{} s", ar.display())); - if target.contains("ios") { + if target.contains("windows") { + // A bit of history here, this used to be --enable-lazy-lock added in + // #14006 which was filed with jemalloc in jemalloc/jemalloc#83 which + // was also reported to MinGW: + // + // http://sourceforge.net/p/mingw-w64/bugs/395/ + // + // When updating jemalloc to 4.0, however, it was found that binaries + // would exit with the status code STATUS_RESOURCE_NOT_OWNED indicating + // that a thread was unlocking a mutex it never locked. Disabling this + // "lazy lock" option seems to fix the issue, but it was enabled by + // default for MinGW targets in 13473c7 for jemalloc. + // + // As a result of all that, force disabling lazy lock on Windows, and + // after reading some code it at least *appears* that the initialization + // of mutexes is otherwise ok in jemalloc, so shouldn't cause problems + // hopefully... + // + // tl;dr: make windows behave like other platforms by disabling lazy + // locking, but requires passing an option due to a historical + // default with jemalloc. + cmd.arg("--disable-lazy-lock"); + } else if target.contains("ios") { cmd.arg("--disable-tls"); } else if target.contains("android") { // We force android to have prefixed symbols because apparently diff --git a/src/libcollections/Cargo.toml b/src/libcollections/Cargo.toml index 7e92404bc0d6..800e36161d24 100644 --- a/src/libcollections/Cargo.toml +++ b/src/libcollections/Cargo.toml @@ -10,12 +10,3 @@ path = "lib.rs" [dependencies] alloc = { path = "../liballoc" } core = { path = "../libcore" } -std_unicode = { path = "../libstd_unicode" } - -[[test]] -name = "collectionstests" -path = "../libcollections/tests/lib.rs" - -[[bench]] -name = "collectionsbenches" -path = "../libcollections/benches/lib.rs" diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 34626326c221..de5d6df328cb 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -8,185 +8,65 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Collection types. +#![crate_name = "collections"] +#![crate_type = "rlib"] +#![allow(unused_attributes)] +#![unstable(feature = "collections", + reason = "this library is unlikely to be stabilized in its current \ + form or name", + issue = "27783")] +#![rustc_deprecated(since = "1.20.0", + reason = "collections moved to `alloc`")] +#![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/", + issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/", + test(no_crate_inject, attr(allow(unused_variables), deny(warnings))))] +#![no_std] +#![needs_allocator] +#![deny(warnings)] + +#![feature(alloc)] +#![feature(collections_range)] +#![feature(macro_reexport)] +#![feature(needs_allocator)] +#![feature(staged_api)] + +//! Collection types //! //! See [`std::collections`](../std/collections/index.html) for a detailed //! discussion of collections in Rust. -#![crate_name = "collections"] -#![crate_type = "rlib"] -#![unstable(feature = "collections", - reason = "library is unlikely to be stabilized with the current \ - layout and name, use std::collections instead", - issue = "27783")] -#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", - html_favicon_url = "https://doc.rust-lang.org/favicon.ico", - html_root_url = "https://doc.rust-lang.org/nightly/", - html_playground_url = "https://play.rust-lang.org/", - issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/", - test(no_crate_inject, attr(allow(unused_variables), deny(warnings))))] - -#![cfg_attr(test, allow(deprecated))] // rand -#![deny(warnings)] -#![deny(missing_debug_implementations)] - -#![feature(alloc)] -#![feature(allow_internal_unstable)] -#![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)] -#![feature(fmt_internals)] -#![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)] -#![feature(placement_in_syntax)] -#![feature(placement_new_protocol)] -#![feature(shared)] -#![feature(slice_get_slice)] -#![feature(slice_patterns)] -#![cfg_attr(not(test), feature(slice_rotate))] -#![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)] -#![cfg_attr(not(test), feature(str_checked_slicing))] -#![cfg_attr(test, feature(rand, test))] -#![feature(offset_to)] - -#![no_std] - -extern crate std_unicode; +#[macro_reexport(vec, format)] extern crate alloc; -#[cfg(test)] -#[macro_use] -extern crate std; -#[cfg(test)] -extern crate test; +pub use alloc::Bound; + +pub use alloc::binary_heap; +pub use alloc::borrow; +pub use alloc::fmt; +pub use alloc::linked_list; +pub use alloc::range; +pub use alloc::slice; +pub use alloc::str; +pub use alloc::string; +pub use alloc::vec; +pub use alloc::vec_deque; + +pub use alloc::btree_map; +pub use alloc::btree_set; #[doc(no_inline)] -pub use binary_heap::BinaryHeap; +pub use alloc::binary_heap::BinaryHeap; #[doc(no_inline)] -pub use btree_map::BTreeMap; +pub use alloc::btree_map::BTreeMap; #[doc(no_inline)] -pub use btree_set::BTreeSet; +pub use alloc::btree_set::BTreeSet; #[doc(no_inline)] -pub use linked_list::LinkedList; +pub use alloc::linked_list::LinkedList; #[doc(no_inline)] -pub use vec_deque::VecDeque; +pub use alloc::vec_deque::VecDeque; #[doc(no_inline)] -pub use string::String; +pub use alloc::string::String; #[doc(no_inline)] -pub use vec::Vec; - -// Needed for the vec! macro -pub use alloc::boxed; - -#[macro_use] -mod macros; - -pub mod binary_heap; -mod btree; -pub mod borrow; -pub mod fmt; -pub mod linked_list; -pub mod range; -pub mod slice; -pub mod str; -pub mod string; -pub mod vec; -pub mod vec_deque; - -#[stable(feature = "rust1", since = "1.0.0")] -pub mod btree_map { - //! A map based on a B-Tree. - #[stable(feature = "rust1", since = "1.0.0")] - pub use btree::map::*; -} - -#[stable(feature = "rust1", since = "1.0.0")] -pub mod btree_set { - //! A set based on a B-Tree. - #[stable(feature = "rust1", since = "1.0.0")] - pub use btree::set::*; -} - -#[cfg(not(test))] -mod std { - pub use core::ops; // RangeFull -} - -/// 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 { - /// An inclusive bound. - #[stable(feature = "collections_bound", since = "1.17.0")] - Included(T), - /// An exclusive bound. - #[stable(feature = "collections_bound", since = "1.17.0")] - Excluded(T), - /// An infinite endpoint. Indicates that there is no bound in this direction. - #[stable(feature = "collections_bound", since = "1.17.0")] - Unbounded, -} - -/// An intermediate trait for specialization of `Extend`. -#[doc(hidden)] -trait SpecExtend { - /// Extends `self` with the contents of the given iterator. - fn spec_extend(&mut self, iter: I); -} +pub use alloc::vec::Vec; diff --git a/src/libcollections/macros.rs b/src/libcollections/macros.rs deleted file mode 100644 index 396a917dfde2..000000000000 --- a/src/libcollections/macros.rs +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright 2014-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. - -/// Creates a `Vec` containing the arguments. -/// -/// `vec!` allows `Vec`s to be defined with the same syntax as array expressions. -/// There are two forms of this macro: -/// -/// - Create a `Vec` containing a given list of elements: -/// -/// ``` -/// let v = vec![1, 2, 3]; -/// assert_eq!(v[0], 1); -/// assert_eq!(v[1], 2); -/// assert_eq!(v[2], 3); -/// ``` -/// -/// - Create a `Vec` from a given element and size: -/// -/// ``` -/// let v = vec![1; 3]; -/// assert_eq!(v, [1, 1, 1]); -/// ``` -/// -/// Note that unlike array expressions this syntax supports all elements -/// which implement `Clone` and the number of elements doesn't have to be -/// a constant. -/// -/// This will use `clone()` to duplicate an expression, so one should be careful -/// using this with types having a nonstandard `Clone` implementation. For -/// example, `vec![Rc::new(1); 5]` will create a vector of five references -/// to the same boxed integer value, not five references pointing to independently -/// boxed integers. -#[cfg(not(test))] -#[macro_export] -#[stable(feature = "rust1", since = "1.0.0")] -#[allow_internal_unstable] -macro_rules! vec { - ($elem:expr; $n:expr) => ( - $crate::vec::from_elem($elem, $n) - ); - ($($x:expr),*) => ( - <[_]>::into_vec(box [$($x),*]) - ); - ($($x:expr,)*) => (vec![$($x),*]) -} - -// HACK(japaric): with cfg(test) the inherent `[T]::into_vec` method, which is -// required for this macro definition, is not available. Instead use the -// `slice::into_vec` function which is only available with cfg(test) -// NB see the slice::hack module in slice.rs for more information -#[cfg(test)] -macro_rules! vec { - ($elem:expr; $n:expr) => ( - $crate::vec::from_elem($elem, $n) - ); - ($($x:expr),*) => ( - $crate::slice::into_vec(box [$($x),*]) - ); - ($($x:expr,)*) => (vec![$($x),*]) -} - -/// Use the syntax described in `std::fmt` to create a value of type `String`. -/// See [`std::fmt`][fmt] for more information. -/// -/// [fmt]: ../std/fmt/index.html -/// -/// # Panics -/// -/// `format!` panics if a formatting trait implementation returns an error. -/// This indicates an incorrect implementation -/// since `fmt::Write for String` never returns an error itself. -/// -/// # Examples -/// -/// ``` -/// format!("test"); -/// format!("hello {}", "world!"); -/// format!("x = {}, y = {y}", 10, y = 30); -/// ``` -#[macro_export] -#[stable(feature = "rust1", since = "1.0.0")] -macro_rules! format { - ($($arg:tt)*) => ($crate::fmt::format(format_args!($($arg)*))) -} diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs deleted file mode 100644 index eb32f4781948..000000000000 --- a/src/libcollections/str.rs +++ /dev/null @@ -1,1997 +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. - -//! 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. -// It's cleaner to just turn off the unused_imports warning than to fix them. -#![allow(unused_imports)] - -use core::fmt; -use core::str as core_str; -use core::str::pattern::Pattern; -use core::str::pattern::{Searcher, ReverseSearcher, DoubleEndedSearcher}; -use core::mem; -use core::iter::FusedIterator; -use std_unicode::str::{UnicodeStr, Utf16Encoder}; - -use vec_deque::VecDeque; -use borrow::{Borrow, ToOwned}; -use string::String; -use std_unicode; -use vec::Vec; -use slice::{SliceConcatExt, SliceIndex}; -use boxed::Box; - -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::str::{FromStr, Utf8Error}; -#[allow(deprecated)] -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::str::{Lines, LinesAny}; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::str::{Split, RSplit}; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::str::{SplitN, RSplitN}; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core::str::{SplitTerminator, RSplitTerminator}; -#[stable(feature = "rust1", since = "1.0.0")] -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, from_utf8_mut, Chars, CharIndices, Bytes}; -#[stable(feature = "rust1", since = "1.0.0")] -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")] -impl> SliceConcatExt for [S] { - type Output = String; - - fn concat(&self) -> String { - if self.is_empty() { - return String::new(); - } - - // `len` calculation may overflow but push_str will check boundaries - let len = self.iter().map(|s| s.borrow().len()).sum(); - let mut result = String::with_capacity(len); - - for s in self { - result.push_str(s.borrow()) - } - - result - } - - fn join(&self, sep: &str) -> String { - if self.is_empty() { - return String::new(); - } - - // concat is faster - if sep.is_empty() { - return self.concat(); - } - - // this is wrong without the guarantee that `self` is non-empty - // `len` calculation may overflow but push_str but will check boundaries - let len = sep.len() * (self.len() - 1) + - self.iter().map(|s| s.borrow().len()).sum::(); - let mut result = String::with_capacity(len); - let mut first = true; - - for s in self { - if first { - first = false; - } else { - result.push_str(sep); - } - result.push_str(s.borrow()); - } - result - } - - fn connect(&self, sep: &str) -> String { - self.join(sep) - } -} - -/// An iterator of [`u16`] over the string encoded as UTF-16. -/// -/// [`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> { - encoder: Utf16Encoder>, -} - -#[stable(feature = "collection_debug", since = "1.17.0")] -impl<'a> fmt::Debug for EncodeUtf16<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.pad("EncodeUtf16 { .. }") - } -} - -#[stable(feature = "encode_utf16", since = "1.8.0")] -impl<'a> Iterator for EncodeUtf16<'a> { - type Item = u16; - - #[inline] - fn next(&mut self) -> Option { - self.encoder.next() - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.encoder.size_hint() - } -} - -#[unstable(feature = "fused", issue = "35602")] -impl<'a> FusedIterator for EncodeUtf16<'a> {} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Borrow for String { - #[inline] - fn borrow(&self) -> &str { - &self[..] - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ToOwned for str { - type Owned = String; - 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. -#[lang = "str"] -#[cfg(not(test))] -impl str { - /// Returns the length of `self`. - /// - /// This length is in bytes, not [`char`]s or graphemes. In other words, - /// it may not be what a human considers the length of the string. - /// - /// [`char`]: primitive.char.html - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let len = "foo".len(); - /// assert_eq!(3, len); - /// - /// let len = "ƒoo".len(); // fancy f! - /// assert_eq!(4, len); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn len(&self) -> usize { - core_str::StrExt::len(self) - } - - /// Returns `true` if `self` has a length of zero bytes. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let s = ""; - /// assert!(s.is_empty()); - /// - /// let s = "not empty"; - /// assert!(!s.is_empty()); - /// ``` - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn is_empty(&self) -> bool { - core_str::StrExt::is_empty(self) - } - - /// Checks that `index`-th byte lies at the start and/or end of a - /// UTF-8 code point sequence. - /// - /// The start and end of the string (when `index == self.len()`) are - /// considered to be - /// boundaries. - /// - /// Returns `false` if `index` is greater than `self.len()`. - /// - /// # Examples - /// - /// ``` - /// let s = "Löwe 老虎 Léopard"; - /// assert!(s.is_char_boundary(0)); - /// // start of `老` - /// assert!(s.is_char_boundary(6)); - /// assert!(s.is_char_boundary(s.len())); - /// - /// // second byte of `ö` - /// assert!(!s.is_char_boundary(2)); - /// - /// // third byte of `老` - /// assert!(!s.is_char_boundary(8)); - /// ``` - #[stable(feature = "is_char_boundary", since = "1.9.0")] - #[inline] - pub fn is_char_boundary(&self, index: usize) -> bool { - core_str::StrExt::is_char_boundary(self, index) - } - - /// Converts a string slice to a byte slice. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let bytes = "bors".as_bytes(); - /// assert_eq!(b"bors", bytes); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline(always)] - pub fn as_bytes(&self) -> &[u8] { - 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 - /// [`u8`]. This pointer will be pointing to the first byte of the string - /// slice. - /// - /// [`u8`]: primitive.u8.html - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let s = "Hello"; - /// let ptr = s.as_ptr(); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn as_ptr(&self) -> *const u8 { - 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. - /// - /// This is generally not recommended, use with caution! For a safe - /// alternative see [`str`] and [`Index`]. - /// - /// [`str`]: primitive.str.html - /// [`Index`]: ops/trait.Index.html - /// - /// This new slice goes from `begin` to `end`, including `begin` but - /// excluding `end`. - /// - /// To get a mutable string slice instead, see the - /// [`slice_mut_unchecked`] method. - /// - /// [`slice_mut_unchecked`]: #method.slice_mut_unchecked - /// - /// # Safety - /// - /// Callers of this function are responsible that three preconditions are - /// satisfied: - /// - /// * `begin` must come before `end`. - /// * `begin` and `end` must be byte positions within the string slice. - /// * `begin` and `end` must lie on UTF-8 sequence boundaries. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let s = "Löwe 老虎 Léopard"; - /// - /// unsafe { - /// assert_eq!("Löwe 老虎 Léopard", s.slice_unchecked(0, 21)); - /// } - /// - /// let s = "Hello, world!"; - /// - /// unsafe { - /// assert_eq!("world", s.slice_unchecked(7, 12)); - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str { - core_str::StrExt::slice_unchecked(self, begin, end) - } - - /// Creates a string slice from another string slice, bypassing safety - /// checks. - /// This is generally not recommended, use with caution! For a safe - /// alternative see [`str`] and [`IndexMut`]. - /// - /// [`str`]: primitive.str.html - /// [`IndexMut`]: ops/trait.IndexMut.html - /// - /// This new slice goes from `begin` to `end`, including `begin` but - /// excluding `end`. - /// - /// To get an immutable string slice instead, see the - /// [`slice_unchecked`] method. - /// - /// [`slice_unchecked`]: #method.slice_unchecked - /// - /// # Safety - /// - /// Callers of this function are responsible that three preconditions are - /// satisfied: - /// - /// * `begin` must come before `end`. - /// * `begin` and `end` must be byte positions within the string slice. - /// * `begin` and `end` must lie on UTF-8 sequence boundaries. - #[stable(feature = "str_slice_mut", since = "1.5.0")] - #[inline] - pub unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut str { - core_str::StrExt::slice_mut_unchecked(self, begin, end) - } - - /// Divide one string slice into two at an index. - /// - /// The argument, `mid`, should be a byte offset from the start of the - /// string. It must also be on the boundary of a UTF-8 code point. - /// - /// The two slices returned go from the start of the string slice to `mid`, - /// and from `mid` to the end of the string slice. - /// - /// To get mutable string slices instead, see the [`split_at_mut`] - /// method. - /// - /// [`split_at_mut`]: #method.split_at_mut - /// - /// # Panics - /// - /// Panics if `mid` is not on a UTF-8 code point boundary, or if it is - /// beyond the last code point of the string slice. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let s = "Per Martin-Löf"; - /// - /// let (first, last) = s.split_at(3); - /// - /// assert_eq!("Per", first); - /// assert_eq!(" Martin-Löf", last); - /// ``` - #[inline] - #[stable(feature = "str_split_at", since = "1.4.0")] - pub fn split_at(&self, mid: usize) -> (&str, &str) { - core_str::StrExt::split_at(self, mid) - } - - /// Divide one mutable string slice into two at an index. - /// - /// The argument, `mid`, should be a byte offset from the start of the - /// string. It must also be on the boundary of a UTF-8 code point. - /// - /// The two slices returned go from the start of the string slice to `mid`, - /// and from `mid` to the end of the string slice. - /// - /// To get immutable string slices instead, see the [`split_at`] method. - /// - /// [`split_at`]: #method.split_at - /// - /// # Panics - /// - /// Panics if `mid` is not on a UTF-8 code point boundary, or if it is - /// beyond the last code point of the string slice. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let mut s = "Per Martin-Löf".to_string(); - /// - /// let (first, last) = s.split_at_mut(3); - /// - /// assert_eq!("Per", first); - /// assert_eq!(" Martin-Löf", last); - /// ``` - #[inline] - #[stable(feature = "str_split_at", since = "1.4.0")] - pub fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str) { - core_str::StrExt::split_at_mut(self, mid) - } - - /// 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. - /// - /// It's important to remember that [`char`] represents a Unicode Scalar - /// Value, and may not match your idea of what a 'character' is. Iteration - /// over grapheme clusters may be what you actually want. - /// - /// [`char`]: primitive.char.html - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let word = "goodbye"; - /// - /// let count = word.chars().count(); - /// assert_eq!(7, count); - /// - /// let mut chars = word.chars(); - /// - /// assert_eq!(Some('g'), chars.next()); - /// assert_eq!(Some('o'), chars.next()); - /// assert_eq!(Some('o'), chars.next()); - /// assert_eq!(Some('d'), chars.next()); - /// assert_eq!(Some('b'), chars.next()); - /// assert_eq!(Some('y'), chars.next()); - /// assert_eq!(Some('e'), chars.next()); - /// - /// assert_eq!(None, chars.next()); - /// ``` - /// - /// Remember, [`char`]s may not match your human intuition about characters: - /// - /// ``` - /// let y = "y̆"; - /// - /// let mut chars = y.chars(); - /// - /// assert_eq!(Some('y'), chars.next()); // not 'y̆' - /// assert_eq!(Some('\u{0306}'), chars.next()); - /// - /// assert_eq!(None, chars.next()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn chars(&self) -> Chars { - core_str::StrExt::chars(self) - } - /// Returns an iterator over the [`char`]s of a string slice, and their - /// positions. - /// - /// As a string slice consists of valid UTF-8, we can iterate through a - /// string slice by [`char`]. This method returns an iterator of both - /// these [`char`]s, as well as their byte positions. - /// - /// The iterator yields tuples. The position is first, the [`char`] is - /// second. - /// - /// [`char`]: primitive.char.html - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let word = "goodbye"; - /// - /// let count = word.char_indices().count(); - /// assert_eq!(7, count); - /// - /// let mut char_indices = word.char_indices(); - /// - /// assert_eq!(Some((0, 'g')), char_indices.next()); - /// assert_eq!(Some((1, 'o')), char_indices.next()); - /// assert_eq!(Some((2, 'o')), char_indices.next()); - /// assert_eq!(Some((3, 'd')), char_indices.next()); - /// assert_eq!(Some((4, 'b')), char_indices.next()); - /// assert_eq!(Some((5, 'y')), char_indices.next()); - /// assert_eq!(Some((6, 'e')), char_indices.next()); - /// - /// assert_eq!(None, char_indices.next()); - /// ``` - /// - /// Remember, [`char`]s may not match your human intuition about characters: - /// - /// ``` - /// let y = "y̆"; - /// - /// let mut char_indices = y.char_indices(); - /// - /// assert_eq!(Some((0, 'y')), char_indices.next()); // not (0, 'y̆') - /// assert_eq!(Some((1, '\u{0306}')), char_indices.next()); - /// - /// assert_eq!(None, char_indices.next()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn char_indices(&self) -> CharIndices { - core_str::StrExt::char_indices(self) - } - - /// An iterator over the bytes of a string slice. - /// - /// As a string slice consists of a sequence of bytes, we can iterate - /// through a string slice by byte. This method returns such an iterator. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let mut bytes = "bors".bytes(); - /// - /// assert_eq!(Some(b'b'), bytes.next()); - /// assert_eq!(Some(b'o'), bytes.next()); - /// assert_eq!(Some(b'r'), bytes.next()); - /// assert_eq!(Some(b's'), bytes.next()); - /// - /// assert_eq!(None, bytes.next()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn bytes(&self) -> Bytes { - core_str::StrExt::bytes(self) - } - - /// Split a string slice by whitespace. - /// - /// The iterator returned will return string slices that are sub-slices of - /// the original string slice, separated by any amount of whitespace. - /// - /// 'Whitespace' is defined according to the terms of the Unicode Derived - /// Core Property `White_Space`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let mut iter = "A few words".split_whitespace(); - /// - /// assert_eq!(Some("A"), iter.next()); - /// assert_eq!(Some("few"), iter.next()); - /// assert_eq!(Some("words"), iter.next()); - /// - /// assert_eq!(None, iter.next()); - /// ``` - /// - /// All kinds of whitespace are considered: - /// - /// ``` - /// let mut iter = " Mary had\ta\u{2009}little \n\t lamb".split_whitespace(); - /// assert_eq!(Some("Mary"), iter.next()); - /// assert_eq!(Some("had"), iter.next()); - /// assert_eq!(Some("a"), iter.next()); - /// assert_eq!(Some("little"), iter.next()); - /// assert_eq!(Some("lamb"), iter.next()); - /// - /// assert_eq!(None, iter.next()); - /// ``` - #[stable(feature = "split_whitespace", since = "1.1.0")] - #[inline] - pub fn split_whitespace(&self) -> SplitWhitespace { - UnicodeStr::split_whitespace(self) - } - - /// An iterator over the lines of a string, as string slices. - /// - /// Lines are ended with either a newline (`\n`) or a carriage return with - /// a line feed (`\r\n`). - /// - /// The final line ending is optional. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let text = "foo\r\nbar\n\nbaz\n"; - /// let mut lines = text.lines(); - /// - /// assert_eq!(Some("foo"), lines.next()); - /// assert_eq!(Some("bar"), lines.next()); - /// assert_eq!(Some(""), lines.next()); - /// assert_eq!(Some("baz"), lines.next()); - /// - /// assert_eq!(None, lines.next()); - /// ``` - /// - /// The final line ending isn't required: - /// - /// ``` - /// let text = "foo\nbar\n\r\nbaz"; - /// let mut lines = text.lines(); - /// - /// assert_eq!(Some("foo"), lines.next()); - /// assert_eq!(Some("bar"), lines.next()); - /// assert_eq!(Some(""), lines.next()); - /// assert_eq!(Some("baz"), lines.next()); - /// - /// assert_eq!(None, lines.next()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn lines(&self) -> Lines { - core_str::StrExt::lines(self) - } - - /// An iterator over the lines of a string. - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_deprecated(since = "1.4.0", reason = "use lines() instead now")] - #[inline] - #[allow(deprecated)] - pub fn lines_any(&self) -> LinesAny { - core_str::StrExt::lines_any(self) - } - - /// Returns an iterator of `u16` over the string encoded as UTF-16. - #[stable(feature = "encode_utf16", since = "1.8.0")] - pub fn encode_utf16(&self) -> EncodeUtf16 { - EncodeUtf16 { encoder: Utf16Encoder::new(self[..].chars()) } - } - - /// Returns `true` if the given pattern matches a sub-slice of - /// this string slice. - /// - /// Returns `false` if it does not. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let bananas = "bananas"; - /// - /// assert!(bananas.contains("nana")); - /// assert!(!bananas.contains("apples")); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn contains<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool { - core_str::StrExt::contains(self, pat) - } - - /// Returns `true` if the given pattern matches a prefix of this - /// string slice. - /// - /// Returns `false` if it does not. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let bananas = "bananas"; - /// - /// assert!(bananas.starts_with("bana")); - /// assert!(!bananas.starts_with("nana")); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn starts_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool { - core_str::StrExt::starts_with(self, pat) - } - - /// Returns `true` if the given pattern matches a suffix of this - /// string slice. - /// - /// Returns `false` if it does not. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let bananas = "bananas"; - /// - /// assert!(bananas.ends_with("anas")); - /// assert!(!bananas.ends_with("nana")); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn ends_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool - where P::Searcher: ReverseSearcher<'a> - { - core_str::StrExt::ends_with(self, pat) - } - - /// Returns the byte index of the first character of this string slice that - /// matches the pattern. - /// - /// Returns [`None`] if the pattern doesn't match. - /// - /// The pattern can be a `&str`, [`char`], or a closure that determines if - /// a character matches. - /// - /// [`char`]: primitive.char.html - /// [`None`]: option/enum.Option.html#variant.None - /// - /// # Examples - /// - /// Simple patterns: - /// - /// ``` - /// let s = "Löwe 老虎 Léopard"; - /// - /// assert_eq!(s.find('L'), Some(0)); - /// assert_eq!(s.find('é'), Some(14)); - /// assert_eq!(s.find("Léopard"), Some(13)); - /// ``` - /// - /// More complex patterns with closures: - /// - /// ``` - /// let s = "Löwe 老虎 Léopard"; - /// - /// assert_eq!(s.find(char::is_whitespace), Some(5)); - /// assert_eq!(s.find(char::is_lowercase), Some(1)); - /// ``` - /// - /// Not finding the pattern: - /// - /// ``` - /// let s = "Löwe 老虎 Léopard"; - /// let x: &[_] = &['1', '2']; - /// - /// assert_eq!(s.find(x), None); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option { - core_str::StrExt::find(self, pat) - } - - /// Returns the byte index of the last character of this string slice that - /// matches the pattern. - /// - /// Returns [`None`] if the pattern doesn't match. - /// - /// The pattern can be a `&str`, [`char`], or a closure that determines if - /// a character matches. - /// - /// [`char`]: primitive.char.html - /// [`None`]: option/enum.Option.html#variant.None - /// - /// # Examples - /// - /// Simple patterns: - /// - /// ``` - /// let s = "Löwe 老虎 Léopard"; - /// - /// assert_eq!(s.rfind('L'), Some(13)); - /// assert_eq!(s.rfind('é'), Some(14)); - /// ``` - /// - /// More complex patterns with closures: - /// - /// ``` - /// let s = "Löwe 老虎 Léopard"; - /// - /// assert_eq!(s.rfind(char::is_whitespace), Some(12)); - /// assert_eq!(s.rfind(char::is_lowercase), Some(20)); - /// ``` - /// - /// Not finding the pattern: - /// - /// ``` - /// let s = "Löwe 老虎 Léopard"; - /// let x: &[_] = &['1', '2']; - /// - /// assert_eq!(s.rfind(x), None); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn rfind<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option - where P::Searcher: ReverseSearcher<'a> - { - core_str::StrExt::rfind(self, pat) - } - - /// An iterator over substrings of this string slice, separated by - /// characters matched by a pattern. - /// - /// The pattern can be a `&str`, [`char`], or a closure that determines the - /// split. - /// - /// # Iterator behavior - /// - /// The returned iterator will be a [`DoubleEndedIterator`] if the pattern - /// allows a reverse search and forward/reverse search yields the same - /// elements. This is true for, eg, [`char`] but not for `&str`. - /// - /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html - /// - /// If the pattern allows a reverse search but its results might differ - /// from a forward search, the [`rsplit`] method can be used. - /// - /// [`char`]: primitive.char.html - /// [`rsplit`]: #method.rsplit - /// - /// # Examples - /// - /// Simple patterns: - /// - /// ``` - /// let v: Vec<&str> = "Mary had a little lamb".split(' ').collect(); - /// assert_eq!(v, ["Mary", "had", "a", "little", "lamb"]); - /// - /// let v: Vec<&str> = "".split('X').collect(); - /// assert_eq!(v, [""]); - /// - /// let v: Vec<&str> = "lionXXtigerXleopard".split('X').collect(); - /// assert_eq!(v, ["lion", "", "tiger", "leopard"]); - /// - /// let v: Vec<&str> = "lion::tiger::leopard".split("::").collect(); - /// assert_eq!(v, ["lion", "tiger", "leopard"]); - /// - /// let v: Vec<&str> = "abc1def2ghi".split(char::is_numeric).collect(); - /// assert_eq!(v, ["abc", "def", "ghi"]); - /// - /// let v: Vec<&str> = "lionXtigerXleopard".split(char::is_uppercase).collect(); - /// assert_eq!(v, ["lion", "tiger", "leopard"]); - /// ``` - /// - /// A more complex pattern, using a closure: - /// - /// ``` - /// let v: Vec<&str> = "abc1defXghi".split(|c| c == '1' || c == 'X').collect(); - /// assert_eq!(v, ["abc", "def", "ghi"]); - /// ``` - /// - /// If a string contains multiple contiguous separators, you will end up - /// with empty strings in the output: - /// - /// ``` - /// let x = "||||a||b|c".to_string(); - /// let d: Vec<_> = x.split('|').collect(); - /// - /// assert_eq!(d, &["", "", "", "", "a", "", "b", "c"]); - /// ``` - /// - /// Contiguous separators are separated by the empty string. - /// - /// ``` - /// let x = "(///)".to_string(); - /// let d: Vec<_> = x.split('/').collect(); - /// - /// assert_eq!(d, &["(", "", "", ")"]); - /// ``` - /// - /// Separators at the start or end of a string are neighbored - /// by empty strings. - /// - /// ``` - /// let d: Vec<_> = "010".split("0").collect(); - /// assert_eq!(d, &["", "1", ""]); - /// ``` - /// - /// When the empty string is used as a separator, it separates - /// every character in the string, along with the beginning - /// and end of the string. - /// - /// ``` - /// let f: Vec<_> = "rust".split("").collect(); - /// assert_eq!(f, &["", "r", "u", "s", "t", ""]); - /// ``` - /// - /// Contiguous separators can lead to possibly surprising behavior - /// when whitespace is used as the separator. This code is correct: - /// - /// ``` - /// let x = " a b c".to_string(); - /// let d: Vec<_> = x.split(' ').collect(); - /// - /// assert_eq!(d, &["", "", "", "", "a", "", "b", "c"]); - /// ``` - /// - /// It does _not_ give you: - /// - /// ```,ignore - /// assert_eq!(d, &["a", "b", "c"]); - /// ``` - /// - /// Use [`split_whitespace`] for this behavior. - /// - /// [`split_whitespace`]: #method.split_whitespace - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P> { - core_str::StrExt::split(self, pat) - } - - /// An iterator over substrings of the given string slice, separated by - /// characters matched by a pattern and yielded in reverse order. - /// - /// The pattern can be a `&str`, [`char`], or a closure that determines the - /// split. - /// - /// [`char`]: primitive.char.html - /// - /// # Iterator behavior - /// - /// The returned iterator requires that the pattern supports a reverse - /// search, and it will be a [`DoubleEndedIterator`] if a forward/reverse - /// search yields the same elements. - /// - /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html - /// - /// For iterating from the front, the [`split`] method can be used. - /// - /// [`split`]: #method.split - /// - /// # Examples - /// - /// Simple patterns: - /// - /// ``` - /// let v: Vec<&str> = "Mary had a little lamb".rsplit(' ').collect(); - /// assert_eq!(v, ["lamb", "little", "a", "had", "Mary"]); - /// - /// let v: Vec<&str> = "".rsplit('X').collect(); - /// assert_eq!(v, [""]); - /// - /// let v: Vec<&str> = "lionXXtigerXleopard".rsplit('X').collect(); - /// assert_eq!(v, ["leopard", "tiger", "", "lion"]); - /// - /// let v: Vec<&str> = "lion::tiger::leopard".rsplit("::").collect(); - /// assert_eq!(v, ["leopard", "tiger", "lion"]); - /// ``` - /// - /// A more complex pattern, using a closure: - /// - /// ``` - /// let v: Vec<&str> = "abc1defXghi".rsplit(|c| c == '1' || c == 'X').collect(); - /// assert_eq!(v, ["ghi", "def", "abc"]); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn rsplit<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplit<'a, P> - where P::Searcher: ReverseSearcher<'a> - { - core_str::StrExt::rsplit(self, pat) - } - - /// An iterator over substrings of the given string slice, separated by - /// characters matched by a pattern. - /// - /// The pattern can be a `&str`, [`char`], or a closure that determines the - /// split. - /// - /// Equivalent to [`split`], except that the trailing substring - /// is skipped if empty. - /// - /// [`split`]: #method.split - /// - /// This method can be used for string data that is _terminated_, - /// rather than _separated_ by a pattern. - /// - /// # Iterator behavior - /// - /// The returned iterator will be a [`DoubleEndedIterator`] if the pattern - /// allows a reverse search and forward/reverse search yields the same - /// elements. This is true for, eg, [`char`] but not for `&str`. - /// - /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html - /// [`char`]: primitive.char.html - /// - /// If the pattern allows a reverse search but its results might differ - /// from a forward search, the [`rsplit_terminator`] method can be used. - /// - /// [`rsplit_terminator`]: #method.rsplit_terminator - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let v: Vec<&str> = "A.B.".split_terminator('.').collect(); - /// assert_eq!(v, ["A", "B"]); - /// - /// let v: Vec<&str> = "A..B..".split_terminator(".").collect(); - /// assert_eq!(v, ["A", "", "B", ""]); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn split_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitTerminator<'a, P> { - core_str::StrExt::split_terminator(self, pat) - } - - /// An iterator over substrings of `self`, separated by characters - /// matched by a pattern and yielded in reverse order. - /// - /// The pattern can be a simple `&str`, [`char`], or a closure that - /// determines the split. - /// Additional libraries might provide more complex patterns like - /// regular expressions. - /// - /// [`char`]: primitive.char.html - /// - /// Equivalent to [`split`], except that the trailing substring is - /// skipped if empty. - /// - /// [`split`]: #method.split - /// - /// This method can be used for string data that is _terminated_, - /// rather than _separated_ by a pattern. - /// - /// # Iterator behavior - /// - /// The returned iterator requires that the pattern supports a - /// reverse search, and it will be double ended if a forward/reverse - /// search yields the same elements. - /// - /// For iterating from the front, the [`split_terminator`] method can be - /// used. - /// - /// [`split_terminator`]: #method.split_terminator - /// - /// # Examples - /// - /// ``` - /// let v: Vec<&str> = "A.B.".rsplit_terminator('.').collect(); - /// assert_eq!(v, ["B", "A"]); - /// - /// let v: Vec<&str> = "A..B..".rsplit_terminator(".").collect(); - /// assert_eq!(v, ["", "B", "", "A"]); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn rsplit_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplitTerminator<'a, P> - where P::Searcher: ReverseSearcher<'a> - { - core_str::StrExt::rsplit_terminator(self, pat) - } - - /// An iterator over substrings of the given string slice, separated by a - /// pattern, restricted to returning at most `n` items. - /// - /// If `n` substrings are returned, the last substring (the `n`th substring) - /// will contain the remainder of the string. - /// - /// The pattern can be a `&str`, [`char`], or a closure that determines the - /// split. - /// - /// [`char`]: primitive.char.html - /// - /// # Iterator behavior - /// - /// The returned iterator will not be double ended, because it is - /// not efficient to support. - /// - /// If the pattern allows a reverse search, the [`rsplitn`] method can be - /// used. - /// - /// [`rsplitn`]: #method.rsplitn - /// - /// # Examples - /// - /// Simple patterns: - /// - /// ``` - /// let v: Vec<&str> = "Mary had a little lambda".splitn(3, ' ').collect(); - /// assert_eq!(v, ["Mary", "had", "a little lambda"]); - /// - /// let v: Vec<&str> = "lionXXtigerXleopard".splitn(3, "X").collect(); - /// assert_eq!(v, ["lion", "", "tigerXleopard"]); - /// - /// let v: Vec<&str> = "abcXdef".splitn(1, 'X').collect(); - /// assert_eq!(v, ["abcXdef"]); - /// - /// let v: Vec<&str> = "".splitn(1, 'X').collect(); - /// assert_eq!(v, [""]); - /// ``` - /// - /// A more complex pattern, using a closure: - /// - /// ``` - /// let v: Vec<&str> = "abc1defXghi".splitn(2, |c| c == '1' || c == 'X').collect(); - /// assert_eq!(v, ["abc", "defXghi"]); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn splitn<'a, P: Pattern<'a>>(&'a self, n: usize, pat: P) -> SplitN<'a, P> { - core_str::StrExt::splitn(self, n, pat) - } - - /// An iterator over substrings of this string slice, separated by a - /// pattern, starting from the end of the string, restricted to returning - /// at most `n` items. - /// - /// If `n` substrings are returned, the last substring (the `n`th substring) - /// will contain the remainder of the string. - /// - /// The pattern can be a `&str`, [`char`], or a closure that - /// determines the split. - /// - /// [`char`]: primitive.char.html - /// - /// # Iterator behavior - /// - /// The returned iterator will not be double ended, because it is not - /// efficient to support. - /// - /// For splitting from the front, the [`splitn`] method can be used. - /// - /// [`splitn`]: #method.splitn - /// - /// # Examples - /// - /// Simple patterns: - /// - /// ``` - /// let v: Vec<&str> = "Mary had a little lamb".rsplitn(3, ' ').collect(); - /// assert_eq!(v, ["lamb", "little", "Mary had a"]); - /// - /// let v: Vec<&str> = "lionXXtigerXleopard".rsplitn(3, 'X').collect(); - /// assert_eq!(v, ["leopard", "tiger", "lionX"]); - /// - /// let v: Vec<&str> = "lion::tiger::leopard".rsplitn(2, "::").collect(); - /// assert_eq!(v, ["leopard", "lion::tiger"]); - /// ``` - /// - /// A more complex pattern, using a closure: - /// - /// ``` - /// let v: Vec<&str> = "abc1defXghi".rsplitn(2, |c| c == '1' || c == 'X').collect(); - /// assert_eq!(v, ["ghi", "abc1def"]); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn rsplitn<'a, P: Pattern<'a>>(&'a self, n: usize, pat: P) -> RSplitN<'a, P> - where P::Searcher: ReverseSearcher<'a> - { - core_str::StrExt::rsplitn(self, n, pat) - } - - /// An iterator over the matches of a pattern within the given string - /// slice. - /// - /// The pattern can be a `&str`, [`char`], or a closure that - /// determines if a character matches. - /// - /// [`char`]: primitive.char.html - /// - /// # Iterator behavior - /// - /// The returned iterator will be a [`DoubleEndedIterator`] if the pattern - /// allows a reverse search and forward/reverse search yields the same - /// elements. This is true for, eg, [`char`] but not for `&str`. - /// - /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html - /// [`char`]: primitive.char.html - /// - /// If the pattern allows a reverse search but its results might differ - /// from a forward search, the [`rmatches`] method can be used. - /// - /// [`rmatches`]: #method.rmatches - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let v: Vec<&str> = "abcXXXabcYYYabc".matches("abc").collect(); - /// assert_eq!(v, ["abc", "abc", "abc"]); - /// - /// let v: Vec<&str> = "1abc2abc3".matches(char::is_numeric).collect(); - /// assert_eq!(v, ["1", "2", "3"]); - /// ``` - #[stable(feature = "str_matches", since = "1.2.0")] - #[inline] - pub fn matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> Matches<'a, P> { - core_str::StrExt::matches(self, pat) - } - - /// An iterator over the matches of a pattern within this string slice, - /// yielded in reverse order. - /// - /// The pattern can be a `&str`, [`char`], or a closure that determines if - /// a character matches. - /// - /// [`char`]: primitive.char.html - /// - /// # Iterator behavior - /// - /// The returned iterator requires that the pattern supports a reverse - /// search, and it will be a [`DoubleEndedIterator`] if a forward/reverse - /// search yields the same elements. - /// - /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html - /// - /// For iterating from the front, the [`matches`] method can be used. - /// - /// [`matches`]: #method.matches - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let v: Vec<&str> = "abcXXXabcYYYabc".rmatches("abc").collect(); - /// assert_eq!(v, ["abc", "abc", "abc"]); - /// - /// let v: Vec<&str> = "1abc2abc3".rmatches(char::is_numeric).collect(); - /// assert_eq!(v, ["3", "2", "1"]); - /// ``` - #[stable(feature = "str_matches", since = "1.2.0")] - #[inline] - pub fn rmatches<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatches<'a, P> - where P::Searcher: ReverseSearcher<'a> - { - core_str::StrExt::rmatches(self, pat) - } - - /// An iterator over the disjoint matches of a pattern within this string - /// slice as well as the index that the match starts at. - /// - /// For matches of `pat` within `self` that overlap, only the indices - /// corresponding to the first match are returned. - /// - /// The pattern can be a `&str`, [`char`], or a closure that determines - /// if a character matches. - /// - /// [`char`]: primitive.char.html - /// - /// # Iterator behavior - /// - /// The returned iterator will be a [`DoubleEndedIterator`] if the pattern - /// allows a reverse search and forward/reverse search yields the same - /// elements. This is true for, eg, [`char`] but not for `&str`. - /// - /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html - /// - /// If the pattern allows a reverse search but its results might differ - /// from a forward search, the [`rmatch_indices`] method can be used. - /// - /// [`rmatch_indices`]: #method.rmatch_indices - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let v: Vec<_> = "abcXXXabcYYYabc".match_indices("abc").collect(); - /// assert_eq!(v, [(0, "abc"), (6, "abc"), (12, "abc")]); - /// - /// let v: Vec<_> = "1abcabc2".match_indices("abc").collect(); - /// assert_eq!(v, [(1, "abc"), (4, "abc")]); - /// - /// let v: Vec<_> = "ababa".match_indices("aba").collect(); - /// assert_eq!(v, [(0, "aba")]); // only the first `aba` - /// ``` - #[stable(feature = "str_match_indices", since = "1.5.0")] - #[inline] - pub fn match_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> MatchIndices<'a, P> { - core_str::StrExt::match_indices(self, pat) - } - - /// An iterator over the disjoint matches of a pattern within `self`, - /// yielded in reverse order along with the index of the match. - /// - /// For matches of `pat` within `self` that overlap, only the indices - /// corresponding to the last match are returned. - /// - /// The pattern can be a `&str`, [`char`], or a closure that determines if a - /// character matches. - /// - /// [`char`]: primitive.char.html - /// - /// # Iterator behavior - /// - /// The returned iterator requires that the pattern supports a reverse - /// search, and it will be a [`DoubleEndedIterator`] if a forward/reverse - /// search yields the same elements. - /// - /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html - /// - /// For iterating from the front, the [`match_indices`] method can be used. - /// - /// [`match_indices`]: #method.match_indices - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let v: Vec<_> = "abcXXXabcYYYabc".rmatch_indices("abc").collect(); - /// assert_eq!(v, [(12, "abc"), (6, "abc"), (0, "abc")]); - /// - /// let v: Vec<_> = "1abcabc2".rmatch_indices("abc").collect(); - /// assert_eq!(v, [(4, "abc"), (1, "abc")]); - /// - /// let v: Vec<_> = "ababa".rmatch_indices("aba").collect(); - /// assert_eq!(v, [(2, "aba")]); // only the last `aba` - /// ``` - #[stable(feature = "str_match_indices", since = "1.5.0")] - #[inline] - pub fn rmatch_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatchIndices<'a, P> - where P::Searcher: ReverseSearcher<'a> - { - core_str::StrExt::rmatch_indices(self, pat) - } - - /// Returns a string slice with leading and trailing whitespace removed. - /// - /// 'Whitespace' is defined according to the terms of the Unicode Derived - /// Core Property `White_Space`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let s = " Hello\tworld\t"; - /// - /// assert_eq!("Hello\tworld", s.trim()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn trim(&self) -> &str { - UnicodeStr::trim(self) - } - - /// Returns a string slice with leading whitespace removed. - /// - /// 'Whitespace' is defined according to the terms of the Unicode Derived - /// Core Property `White_Space`. - /// - /// # Text directionality - /// - /// A string is a sequence of bytes. 'Left' in this context means the first - /// position of that byte string; for a language like Arabic or Hebrew - /// which are 'right to left' rather than 'left to right', this will be - /// the _right_ side, not the left. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let s = " Hello\tworld\t"; - /// - /// assert_eq!("Hello\tworld\t", s.trim_left()); - /// ``` - /// - /// Directionality: - /// - /// ``` - /// let s = " English"; - /// assert!(Some('E') == s.trim_left().chars().next()); - /// - /// let s = " עברית"; - /// assert!(Some('ע') == s.trim_left().chars().next()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn trim_left(&self) -> &str { - UnicodeStr::trim_left(self) - } - - /// Returns a string slice with trailing whitespace removed. - /// - /// 'Whitespace' is defined according to the terms of the Unicode Derived - /// Core Property `White_Space`. - /// - /// # Text directionality - /// - /// A string is a sequence of bytes. 'Right' in this context means the last - /// position of that byte string; for a language like Arabic or Hebrew - /// which are 'right to left' rather than 'left to right', this will be - /// the _left_ side, not the right. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let s = " Hello\tworld\t"; - /// - /// assert_eq!(" Hello\tworld", s.trim_right()); - /// ``` - /// - /// Directionality: - /// - /// ``` - /// let s = "English "; - /// assert!(Some('h') == s.trim_right().chars().rev().next()); - /// - /// let s = "עברית "; - /// assert!(Some('ת') == s.trim_right().chars().rev().next()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn trim_right(&self) -> &str { - UnicodeStr::trim_right(self) - } - - /// Returns a string slice with all prefixes and suffixes that match a - /// pattern repeatedly removed. - /// - /// The pattern can be a [`char`] or a closure that determines if a - /// character matches. - /// - /// [`char`]: primitive.char.html - /// - /// # Examples - /// - /// Simple patterns: - /// - /// ``` - /// assert_eq!("11foo1bar11".trim_matches('1'), "foo1bar"); - /// assert_eq!("123foo1bar123".trim_matches(char::is_numeric), "foo1bar"); - /// - /// let x: &[_] = &['1', '2']; - /// assert_eq!("12foo1bar12".trim_matches(x), "foo1bar"); - /// ``` - /// - /// A more complex pattern, using a closure: - /// - /// ``` - /// assert_eq!("1foo1barXX".trim_matches(|c| c == '1' || c == 'X'), "foo1bar"); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn trim_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str - where P::Searcher: DoubleEndedSearcher<'a> - { - core_str::StrExt::trim_matches(self, pat) - } - - /// Returns a string slice with all prefixes that match a pattern - /// repeatedly removed. - /// - /// The pattern can be a `&str`, [`char`], or a closure that determines if - /// a character matches. - /// - /// [`char`]: primitive.char.html - /// - /// # Text directionality - /// - /// A string is a sequence of bytes. 'Left' in this context means the first - /// position of that byte string; for a language like Arabic or Hebrew - /// which are 'right to left' rather than 'left to right', this will be - /// the _right_ side, not the left. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!("11foo1bar11".trim_left_matches('1'), "foo1bar11"); - /// assert_eq!("123foo1bar123".trim_left_matches(char::is_numeric), "foo1bar123"); - /// - /// let x: &[_] = &['1', '2']; - /// assert_eq!("12foo1bar12".trim_left_matches(x), "foo1bar12"); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn trim_left_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str { - core_str::StrExt::trim_left_matches(self, pat) - } - - /// Returns a string slice with all suffixes that match a pattern - /// repeatedly removed. - /// - /// The pattern can be a `&str`, [`char`], or a closure that - /// determines if a character matches. - /// - /// [`char`]: primitive.char.html - /// - /// # Text directionality - /// - /// A string is a sequence of bytes. 'Right' in this context means the last - /// position of that byte string; for a language like Arabic or Hebrew - /// which are 'right to left' rather than 'left to right', this will be - /// the _left_ side, not the right. - /// - /// # Examples - /// - /// Simple patterns: - /// - /// ``` - /// assert_eq!("11foo1bar11".trim_right_matches('1'), "11foo1bar"); - /// assert_eq!("123foo1bar123".trim_right_matches(char::is_numeric), "123foo1bar"); - /// - /// let x: &[_] = &['1', '2']; - /// assert_eq!("12foo1bar12".trim_right_matches(x), "12foo1bar"); - /// ``` - /// - /// A more complex pattern, using a closure: - /// - /// ``` - /// assert_eq!("1fooX".trim_left_matches(|c| c == '1' || c == 'X'), "fooX"); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn trim_right_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str - where P::Searcher: ReverseSearcher<'a> - { - core_str::StrExt::trim_right_matches(self, pat) - } - - /// 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 - /// 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. - /// - /// [`FromStr`]: str/trait.FromStr.html - /// - /// # Errors - /// - /// Will return [`Err`] if it's not possible to parse this string slice into - /// the desired type. - /// - /// [`Err`]: str/trait.FromStr.html#associatedtype.Err - /// - /// # Example - /// - /// Basic usage - /// - /// ``` - /// let four: u32 = "4".parse().unwrap(); - /// - /// assert_eq!(4, four); - /// ``` - /// - /// Using the 'turbofish' instead of annotating `four`: - /// - /// ``` - /// let four = "4".parse::(); - /// - /// assert_eq!(Ok(4), four); - /// ``` - /// - /// Failing to parse: - /// - /// ``` - /// let nope = "j".parse::(); - /// - /// assert!(nope.is_err()); - /// ``` - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn parse(&self) -> Result { - 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. - /// While doing so, it attempts to find matches of a pattern. If it finds any, it - /// replaces them with the replacement string slice. - /// - /// [`String`]: string/struct.String.html - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let s = "this is old"; - /// - /// assert_eq!("this is new", s.replace("old", "new")); - /// ``` - /// - /// When the pattern doesn't match: - /// - /// ``` - /// let s = "this is old"; - /// assert_eq!(s, s.replace("cookie monster", "little lamb")); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn replace<'a, P: Pattern<'a>>(&'a self, from: P, to: &str) -> String { - let mut result = String::new(); - let mut last_end = 0; - for (start, part) in self.match_indices(from) { - result.push_str(unsafe { self.slice_unchecked(last_end, start) }); - result.push_str(to); - last_end = start + part.len(); - } - result.push_str(unsafe { self.slice_unchecked(last_end, self.len()) }); - result - } - - /// Replaces first N matches of a pattern with another string. - /// - /// `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 `count` times. - /// - /// [`String`]: string/struct.String.html - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let s = "foo foo 123 foo"; - /// assert_eq!("new new 123 foo", s.replacen("foo", "new", 2)); - /// assert_eq!("faa fao 123 foo", s.replacen('o', "a", 3)); - /// assert_eq!("foo foo new23 foo", s.replacen(char::is_numeric, "new", 1)); - /// ``` - /// - /// When the pattern doesn't match: - /// - /// ``` - /// let s = "this is old"; - /// assert_eq!(s, s.replacen("cookie monster", "little lamb", 10)); - /// ``` - #[stable(feature = "str_replacen", since = "1.16.0")] - pub fn replacen<'a, P: Pattern<'a>>(&'a self, pat: P, to: &str, count: usize) -> String { - // Hope to reduce the times of re-allocation - let mut result = String::with_capacity(32); - let mut last_end = 0; - for (start, part) in self.match_indices(pat).take(count) { - result.push_str(unsafe { self.slice_unchecked(last_end, start) }); - result.push_str(to); - last_end = start + part.len(); - } - result.push_str(unsafe { self.slice_unchecked(last_end, self.len()) }); - result - } - - /// Returns the lowercase equivalent of this string slice, as a new [`String`]. - /// - /// 'Lowercase' is defined according to the terms of the Unicode Derived Core Property - /// `Lowercase`. - /// - /// Since some characters can expand into multiple characters when changing - /// the case, this function returns a [`String`] instead of modifying the - /// parameter in-place. - /// - /// [`String`]: string/struct.String.html - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let s = "HELLO"; - /// - /// assert_eq!("hello", s.to_lowercase()); - /// ``` - /// - /// A tricky example, with sigma: - /// - /// ``` - /// let sigma = "Σ"; - /// - /// assert_eq!("σ", sigma.to_lowercase()); - /// - /// // but at the end of a word, it's ς, not σ: - /// let odysseus = "ὈΔΥΣΣΕΎΣ"; - /// - /// assert_eq!("ὀδυσσεύς", odysseus.to_lowercase()); - /// ``` - /// - /// Languages without case are not changed: - /// - /// ``` - /// let new_year = "农历新年"; - /// - /// assert_eq!(new_year, new_year.to_lowercase()); - /// ``` - #[stable(feature = "unicode_case_mapping", since = "1.2.0")] - pub fn to_lowercase(&self) -> String { - let mut s = String::with_capacity(self.len()); - for (i, c) in self[..].char_indices() { - if c == 'Σ' { - // Σ maps to σ, except at the end of a word where it maps to ς. - // This is the only conditional (contextual) but language-independent mapping - // in `SpecialCasing.txt`, - // so hard-code it rather than have a generic "condition" mechanism. - // See https://github.com/rust-lang/rust/issues/26035 - map_uppercase_sigma(self, i, &mut s) - } else { - s.extend(c.to_lowercase()); - } - } - return s; - - fn map_uppercase_sigma(from: &str, i: usize, to: &mut String) { - // See http://www.unicode.org/versions/Unicode7.0.0/ch03.pdf#G33992 - // for the definition of `Final_Sigma`. - debug_assert!('Σ'.len_utf8() == 2); - let is_word_final = case_ignoreable_then_cased(from[..i].chars().rev()) && - !case_ignoreable_then_cased(from[i + 2..].chars()); - to.push_str(if is_word_final { "ς" } else { "σ" }); - } - - fn case_ignoreable_then_cased>(iter: I) -> bool { - use std_unicode::derived_property::{Cased, Case_Ignorable}; - match iter.skip_while(|&c| Case_Ignorable(c)).next() { - Some(c) => Cased(c), - None => false, - } - } - } - - /// Returns the uppercase equivalent of this string slice, as a new [`String`]. - /// - /// 'Uppercase' is defined according to the terms of the Unicode Derived Core Property - /// `Uppercase`. - /// - /// Since some characters can expand into multiple characters when changing - /// the case, this function returns a [`String`] instead of modifying the - /// parameter in-place. - /// - /// [`String`]: string/struct.String.html - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let s = "hello"; - /// - /// assert_eq!("HELLO", s.to_uppercase()); - /// ``` - /// - /// Scripts without case are not changed: - /// - /// ``` - /// let new_year = "农历新年"; - /// - /// assert_eq!(new_year, new_year.to_uppercase()); - /// ``` - #[stable(feature = "unicode_case_mapping", since = "1.2.0")] - pub fn to_uppercase(&self) -> String { - let mut s = String::with_capacity(self.len()); - s.extend(self.chars().flat_map(|c| c.to_uppercase())); - return s; - } - - /// 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")] - pub fn escape_debug(&self) -> String { - self.chars().flat_map(|c| c.escape_debug()).collect() - } - - /// Escapes each char in `s` with [`char::escape_default`]. - /// - /// [`char::escape_default`]: primitive.char.html#method.escape_default - #[unstable(feature = "str_escape", - reason = "return type may change to be an iterator", - issue = "27791")] - pub fn escape_default(&self) -> String { - self.chars().flat_map(|c| c.escape_default()).collect() - } - - /// Escapes each char in `s` with [`char::escape_unicode`]. - /// - /// [`char::escape_unicode`]: primitive.char.html#method.escape_unicode - #[unstable(feature = "str_escape", - reason = "return type may change to be an iterator", - issue = "27791")] - pub fn escape_unicode(&self) -> String { - self.chars().flat_map(|c| c.escape_unicode()).collect() - } - - /// Converts a [`Box`] into a [`String`] without copying or allocating. - /// - /// [`String`]: string/struct.String.html - /// [`Box`]: boxed/struct.Box.html - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let string = String::from("birthday gift"); - /// let boxed_str = string.clone().into_boxed_str(); - /// - /// assert_eq!(boxed_str.into_string(), string); - /// ``` - #[stable(feature = "box_str", since = "1.4.0")] - pub fn into_string(self: Box) -> String { - unsafe { - let slice = mem::transmute::, Box<[u8]>>(self); - String::from_utf8_unchecked(slice.into_vec()) - } - } - - /// Create a [`String`] by repeating a string `n` times. - /// - /// [`String`]: string/struct.String.html - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!("abc".repeat(4), String::from("abcabcabcabc")); - /// ``` - #[stable(feature = "repeat_str", since = "1.16.0")] - pub fn repeat(&self, n: usize) -> String { - let mut s = String::with_capacity(self.len() * n); - s.extend((0..n).map(|_| self)); - s - } -} diff --git a/src/libcore/borrow.rs b/src/libcore/borrow.rs index 3d223465c88a..61558034e63e 100644 --- a/src/libcore/borrow.rs +++ b/src/libcore/borrow.rs @@ -31,7 +31,7 @@ /// `Borrow` is very similar to, but different than, `AsRef`. See /// [the book][book] for more. /// -/// [book]: ../../book/borrow-and-asref.html +/// [book]: ../../book/first-edition/borrow-and-asref.html #[stable(feature = "rust1", since = "1.0.0")] pub trait Borrow { /// Immutably borrows from an owned value. diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index ea480f38947f..e75401f6ce03 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -391,17 +391,17 @@ impl Cell { } } - /// Replaces the contained value. + /// Replaces the contained value, and returns it. /// /// # Examples /// /// ``` /// use std::cell::Cell; /// - /// let c = Cell::new(5); - /// let old = c.replace(10); - /// - /// assert_eq!(5, old); + /// let cell = Cell::new(5); + /// assert_eq!(cell.get(), 5); + /// assert_eq!(cell.replace(10), 5); + /// assert_eq!(cell.get(), 10); /// ``` #[stable(feature = "move_cell", since = "1.17.0")] pub fn replace(&self, val: T) -> T { diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index 661cf73c7f30..6f35d0417f18 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -443,6 +443,42 @@ pub trait Ord: Eq + PartialOrd { /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn cmp(&self, other: &Self) -> Ordering; + + /// Compares and returns the maximum of two values. + /// + /// Returns the second argument if the comparison determines them to be equal. + /// + /// # Examples + /// + /// ``` + /// #![feature(ord_max_min)] + /// + /// assert_eq!(2, 1.max(2)); + /// assert_eq!(2, 2.max(2)); + /// ``` + #[unstable(feature = "ord_max_min", issue = "25663")] + fn max(self, other: Self) -> Self + where Self: Sized { + if other >= self { other } else { self } + } + + /// Compares and returns the minimum of two values. + /// + /// Returns the first argument if the comparison determines them to be equal. + /// + /// # Examples + /// + /// ``` + /// #![feature(ord_max_min)] + /// + /// assert_eq!(1, 1.min(2)); + /// assert_eq!(2, 2.min(2)); + /// ``` + #[unstable(feature = "ord_max_min", issue = "25663")] + fn min(self, other: Self) -> Self + where Self: Sized { + if self <= other { self } else { other } + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -678,6 +714,8 @@ pub trait PartialOrd: PartialEq { /// /// Returns the first argument if the comparison determines them to be equal. /// +/// Internally uses an alias to `Ord::min`. +/// /// # Examples /// /// ``` @@ -689,13 +727,15 @@ pub trait PartialOrd: PartialEq { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn min(v1: T, v2: T) -> T { - if v1 <= v2 { v1 } else { v2 } + v1.min(v2) } /// Compares and returns the maximum of two values. /// /// Returns the second argument if the comparison determines them to be equal. /// +/// Internally uses an alias to `Ord::max`. +/// /// # Examples /// /// ``` @@ -707,7 +747,7 @@ pub fn min(v1: T, v2: T) -> T { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn max(v1: T, v2: T) -> T { - if v2 >= v1 { v2 } else { v1 } + v1.max(v2) } // Implementation of PartialEq, Eq, PartialOrd and Ord for primitive types diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs index 11a360ff900f..6f3c3863fae1 100644 --- a/src/libcore/convert.rs +++ b/src/libcore/convert.rs @@ -71,7 +71,7 @@ use str::FromStr; /// /// See [the book][book] for a more detailed comparison. /// -/// [book]: ../../book/borrow-and-asref.html +/// [book]: ../../book/first-edition/borrow-and-asref.html /// [`Borrow`]: ../../std/borrow/trait.Borrow.html /// /// **Note: this trait must not fail**. If the conversion can fail, use a @@ -305,7 +305,7 @@ 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 +/// [book]: ../../book/first-edition/error-handling.html #[stable(feature = "rust1", since = "1.0.0")] pub trait From: Sized { /// Performs the conversion. diff --git a/src/libcore/hash/mod.rs b/src/libcore/hash/mod.rs index f68361e85227..3b304f4c479a 100644 --- a/src/libcore/hash/mod.rs +++ b/src/libcore/hash/mod.rs @@ -99,7 +99,7 @@ use mem; #[allow(deprecated)] pub use self::sip::SipHasher; -#[unstable(feature = "sip_hash_13", issue = "29754")] +#[unstable(feature = "sip_hash_13", issue = "34767")] #[allow(deprecated)] pub use self::sip::{SipHasher13, SipHasher24}; diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 3566bbdebc2b..8188c15a2829 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1229,6 +1229,23 @@ extern "rust-intrinsic" { /// ``` pub fn ctlz(x: T) -> T; + /// Like `ctlz`, but extra-unsafe as it returns `undef` when + /// given an `x` with value `0`. + /// + /// # Examples + /// + /// ``` + /// #![feature(core_intrinsics)] + /// + /// use std::intrinsics::ctlz_nonzero; + /// + /// let x = 0b0001_1100_u8; + /// let num_leading = unsafe { ctlz_nonzero(x) }; + /// assert_eq!(num_leading, 3); + /// ``` + #[cfg(not(stage0))] + pub fn ctlz_nonzero(x: T) -> T; + /// Returns the number of trailing unset bits (zeroes) in an integer type `T`. /// /// # Examples @@ -1256,6 +1273,23 @@ extern "rust-intrinsic" { /// ``` pub fn cttz(x: T) -> T; + /// Like `cttz`, but extra-unsafe as it returns `undef` when + /// given an `x` with value `0`. + /// + /// # Examples + /// + /// ``` + /// #![feature(core_intrinsics)] + /// + /// use std::intrinsics::cttz_nonzero; + /// + /// let x = 0b0011_1000_u8; + /// let num_trailing = unsafe { cttz_nonzero(x) }; + /// assert_eq!(num_trailing, 3); + /// ``` + #[cfg(not(stage0))] + pub fn cttz_nonzero(x: T) -> T; + /// Reverses the bytes in an integer type `T`. pub fn bswap(x: T) -> T; diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index 85149a0f5707..30d09e5453b3 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -262,7 +262,7 @@ pub trait Iterator { /// Creates an iterator starting at the same point, but stepping by /// the given amount at each iteration. /// - /// Note that it will always return the first element of the range, + /// Note that it will always return the first element of the iterator, /// regardless of the step given. /// /// # Panics diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs index 015cc150dc27..679cf3a9b23e 100644 --- a/src/libcore/iter/traits.rs +++ b/src/libcore/iter/traits.rs @@ -798,6 +798,23 @@ impl Iterator for ResultShunt impl Sum> for Result where T: Sum, { + /// Takes each element in the `Iterator`: if it is an `Err`, no further + /// elements are taken, and the `Err` is returned. Should no `Err` occur, + /// the sum of all elements is returned. + /// + /// # Examples + /// + /// This sums up every integer in a vector, rejecting the sum if a negative + /// element is encountered: + /// + /// ``` + /// let v = vec![1, 2]; + /// let res: Result = v.iter().map(|&x: &i32| + /// if x < 0 { Err("Negative element found") } + /// else { Ok(x) } + /// ).sum(); + /// assert_eq!(res, Ok(3)); + /// ``` fn sum(iter: I) -> Result where I: Iterator>, { @@ -809,6 +826,9 @@ impl Sum> for Result impl Product> for Result where T: Product, { + /// Takes each element in the `Iterator`: if it is an `Err`, no further + /// elements are taken, and the `Err` is returned. Should no `Err` occur, + /// the product of all elements is returned. fn product(iter: I) -> Result where I: Iterator>, { @@ -819,7 +839,7 @@ impl Product> for Result /// An iterator that always continues to yield `None` when exhausted. /// /// Calling next on a fused iterator that has returned `None` once is guaranteed -/// to return [`None`] again. This trait is should be implemented by all iterators +/// to return [`None`] again. This trait should be implemented by all iterators /// that behave this way because it allows for some significant optimizations. /// /// Note: In general, you should not use `FusedIterator` in generic bounds if diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index f8316d685788..dfe95d3a4d6b 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -54,7 +54,7 @@ macro_rules! panic { /// /// [`panic!`]: macro.panic.html /// [`debug_assert!`]: macro.debug_assert.html -/// [testing]: ../book/testing.html +/// [testing]: ../book/first-edition/testing.html /// /// # Examples /// @@ -554,7 +554,8 @@ macro_rules! unreachable { #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] macro_rules! unimplemented { - () => (panic!("not yet implemented")) + () => (panic!("not yet implemented")); + ($($arg:tt)+) => (panic!("not yet implemented: {}", format_args!($($arg)*))); } /// Built-in macros to the compiler itself. diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 05df84708e05..3bed425943f7 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -85,7 +85,7 @@ impl !Send for *mut T { } /// // be made into an object /// ``` /// -/// [trait object]: ../../book/trait-objects.html +/// [trait object]: ../../book/first-edition/trait-objects.html #[stable(feature = "rust1", since = "1.0.0")] #[lang = "sized"] #[rustc_on_unimplemented = "`{Self}` does not have a constant size known at compile-time"] @@ -493,7 +493,7 @@ macro_rules! impls{ /// types. We track the Rust type using a phantom type parameter on /// the struct `ExternalResource` which wraps a handle. /// -/// [FFI]: ../../book/ffi.html +/// [FFI]: ../../book/first-edition/ffi.html /// /// ``` /// # #![allow(dead_code)] diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index d11ad76d65df..3924034fea22 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -109,7 +109,7 @@ pub use intrinsics::transmute; /// [`Clone`][clone]. You need the value's destructor to run only once, /// because a double `free` is undefined behavior. /// -/// An example is the definition of [`mem::swap`][swap] in this module: +/// An example is a possible implementation of [`mem::swap`][swap]: /// /// ``` /// use std::mem; @@ -499,18 +499,59 @@ pub unsafe fn uninitialized() -> T { #[stable(feature = "rust1", since = "1.0.0")] pub fn swap(x: &mut T, y: &mut T) { unsafe { - // Give ourselves some scratch space to work with - let mut t: T = uninitialized(); + // The approach here is to utilize simd to swap x & y efficiently. Testing reveals + // that swapping either 32 bytes or 64 bytes at a time is most efficient for intel + // Haswell E processors. LLVM is more able to optimize if we give a struct a + // #[repr(simd)], even if we don't actually use this struct directly. + // + // FIXME repr(simd) broken on emscripten + #[cfg_attr(not(target_os = "emscripten"), repr(simd))] + struct Block(u64, u64, u64, u64); + struct UnalignedBlock(u64, u64, u64, u64); - // Perform the swap, `&mut` pointers never alias - ptr::copy_nonoverlapping(&*x, &mut t, 1); - ptr::copy_nonoverlapping(&*y, x, 1); - ptr::copy_nonoverlapping(&t, y, 1); + let block_size = size_of::(); - // y and t now point to the same thing, but we need to completely - // forget `t` because we do not want to run the destructor for `T` - // on its value, which is still owned somewhere outside this function. - forget(t); + // Get raw pointers to the bytes of x & y for easier manipulation + let x = x as *mut T as *mut u8; + let y = y as *mut T as *mut u8; + + // Loop through x & y, copying them `Block` at a time + // The optimizer should unroll the loop fully for most types + // N.B. We can't use a for loop as the `range` impl calls `mem::swap` recursively + let len = size_of::(); + let mut i = 0; + while i + block_size <= len { + // Create some uninitialized memory as scratch space + // Declaring `t` here avoids aligning the stack when this loop is unused + let mut t: Block = uninitialized(); + let t = &mut t as *mut _ as *mut u8; + let x = x.offset(i as isize); + let y = y.offset(i as isize); + + // Swap a block of bytes of x & y, using t as a temporary buffer + // This should be optimized into efficient SIMD operations where available + ptr::copy_nonoverlapping(x, t, block_size); + ptr::copy_nonoverlapping(y, x, block_size); + ptr::copy_nonoverlapping(t, y, block_size); + i += block_size; + } + + + if i < len { + // Swap any remaining bytes, using aligned types to copy + // where appropriate (this information is lost by conversion + // to *mut u8, so restore it manually here) + let mut t: UnalignedBlock = uninitialized(); + let rem = len - i; + + let t = &mut t as *mut _ as *mut u8; + let x = x.offset(i as isize); + let y = y.offset(i as isize); + + ptr::copy_nonoverlapping(x, t, rem); + ptr::copy_nonoverlapping(y, x, rem); + ptr::copy_nonoverlapping(t, y, rem); + } } } diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 91ca213e96e0..cb28035682d6 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -242,4 +242,32 @@ impl Float for f32 { let value: f32 = consts::PI; self * (value / 180.0f32) } + + /// Returns the maximum of the two numbers. + #[inline] + fn max(self, other: f32) -> f32 { + // IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the + // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it + // is either x or y, canonicalized (this means results might differ among implementations). + // When either x or y is a signalingNaN, then the result is according to 6.2. + // + // Since we do not support sNaN in Rust yet, we do not need to handle them. + // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by + // multiplying by 1.0. Should switch to the `canonicalize` when it works. + (if self < other || self.is_nan() { other } else { self }) * 1.0 + } + + /// Returns the minimum of the two numbers. + #[inline] + fn min(self, other: f32) -> f32 { + // IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the + // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it + // is either x or y, canonicalized (this means results might differ among implementations). + // When either x or y is a signalingNaN, then the result is according to 6.2. + // + // Since we do not support sNaN in Rust yet, we do not need to handle them. + // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by + // multiplying by 1.0. Should switch to the `canonicalize` when it works. + (if self < other || other.is_nan() { self } else { other }) * 1.0 + } } diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index 7d6d6cef0497..ac6b1e67cd27 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -242,4 +242,32 @@ impl Float for f64 { let value: f64 = consts::PI; self * (value / 180.0) } + + /// Returns the maximum of the two numbers. + #[inline] + fn max(self, other: f64) -> f64 { + // IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the + // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it + // is either x or y, canonicalized (this means results might differ among implementations). + // When either x or y is a signalingNaN, then the result is according to 6.2. + // + // Since we do not support sNaN in Rust yet, we do not need to handle them. + // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by + // multiplying by 1.0. Should switch to the `canonicalize` when it works. + (if self < other || self.is_nan() { other } else { self }) * 1.0 + } + + /// Returns the minimum of the two numbers. + #[inline] + fn min(self, other: f64) -> f64 { + // IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the + // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it + // is either x or y, canonicalized (this means results might differ among implementations). + // When either x or y is a signalingNaN, then the result is according to 6.2. + // + // Since we do not support sNaN in Rust yet, we do not need to handle them. + // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by + // multiplying by 1.0. Should switch to the `canonicalize` when it works. + (if self < other || other.is_nan() { self } else { other }) * 1.0 + } } diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index be093cca6a1b..cbd59ed37137 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -15,7 +15,6 @@ use convert::TryFrom; use fmt; use intrinsics; -use mem::size_of; use str::FromStr; /// Provides intentionally-wrapped arithmetic on `T`. @@ -1263,6 +1262,7 @@ macro_rules! uint_impl { ($SelfT:ty, $ActualT:ty, $BITS:expr, $ctpop:path, $ctlz:path, + $ctlz_nonzero:path, $cttz:path, $bswap:path, $add_with_overflow:path, @@ -2176,8 +2176,33 @@ macro_rules! uint_impl { (self.wrapping_sub(1)) & self == 0 && !(self == 0) } + // Returns one less than next power of two. + // (For 8u8 next power of two is 8u8 and for 6u8 it is 8u8) + // + // 8u8.one_less_than_next_power_of_two() == 7 + // 6u8.one_less_than_next_power_of_two() == 7 + // + // This method cannot overflow, as in the `next_power_of_two` + // overflow cases it instead ends up returning the maximum value + // of the type, and can return 0 for 0. + #[inline] + fn one_less_than_next_power_of_two(self) -> Self { + if self <= 1 { return 0; } + + // Because `p > 0`, it cannot consist entirely of leading zeros. + // That means the shift is always in-bounds, and some processors + // (such as intel pre-haswell) have more efficient ctlz + // intrinsics when the argument is non-zero. + let p = self - 1; + let z = unsafe { $ctlz_nonzero(p) }; + <$SelfT>::max_value() >> z + } + /// Returns the smallest power of two greater than or equal to `self`. - /// Unspecified behavior on overflow. + /// + /// When return value overflows (i.e. `self > (1 << (N-1))` for type + /// `uN`), it panics in debug mode and return value is wrapped to 0 in + /// release mode (the only situation in which method can return 0). /// /// # Examples /// @@ -2190,9 +2215,7 @@ macro_rules! uint_impl { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn next_power_of_two(self) -> Self { - let bits = size_of::() * 8; - let one: Self = 1; - one << ((bits - self.wrapping_sub(one).leading_zeros() as usize) % bits) + self.one_less_than_next_power_of_two() + 1 } /// Returns the smallest power of two greater than or equal to `n`. If @@ -2210,21 +2233,22 @@ macro_rules! uint_impl { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn checked_next_power_of_two(self) -> Option { - let npot = self.next_power_of_two(); - if npot >= self { - Some(npot) - } else { - None - } + self.one_less_than_next_power_of_two().checked_add(1) } } } +#[cfg(stage0)] +unsafe fn ctlz_nonzero(x: T) -> T { intrinsics::ctlz(x) } +#[cfg(not(stage0))] +unsafe fn ctlz_nonzero(x: T) -> T { intrinsics::ctlz_nonzero(x) } + #[lang = "u8"] impl u8 { uint_impl! { u8, u8, 8, intrinsics::ctpop, intrinsics::ctlz, + ctlz_nonzero, intrinsics::cttz, intrinsics::bswap, intrinsics::add_with_overflow, @@ -2237,6 +2261,7 @@ impl u16 { uint_impl! { u16, u16, 16, intrinsics::ctpop, intrinsics::ctlz, + ctlz_nonzero, intrinsics::cttz, intrinsics::bswap, intrinsics::add_with_overflow, @@ -2249,6 +2274,7 @@ impl u32 { uint_impl! { u32, u32, 32, intrinsics::ctpop, intrinsics::ctlz, + ctlz_nonzero, intrinsics::cttz, intrinsics::bswap, intrinsics::add_with_overflow, @@ -2261,6 +2287,7 @@ impl u64 { uint_impl! { u64, u64, 64, intrinsics::ctpop, intrinsics::ctlz, + ctlz_nonzero, intrinsics::cttz, intrinsics::bswap, intrinsics::add_with_overflow, @@ -2273,6 +2300,7 @@ impl u128 { uint_impl! { u128, u128, 128, intrinsics::ctpop, intrinsics::ctlz, + ctlz_nonzero, intrinsics::cttz, intrinsics::bswap, intrinsics::add_with_overflow, @@ -2286,6 +2314,7 @@ impl usize { uint_impl! { usize, u16, 16, intrinsics::ctpop, intrinsics::ctlz, + ctlz_nonzero, intrinsics::cttz, intrinsics::bswap, intrinsics::add_with_overflow, @@ -2298,6 +2327,7 @@ impl usize { uint_impl! { usize, u32, 32, intrinsics::ctpop, intrinsics::ctlz, + ctlz_nonzero, intrinsics::cttz, intrinsics::bswap, intrinsics::add_with_overflow, @@ -2311,6 +2341,7 @@ impl usize { uint_impl! { usize, u64, 64, intrinsics::ctpop, intrinsics::ctlz, + ctlz_nonzero, intrinsics::cttz, intrinsics::bswap, intrinsics::add_with_overflow, @@ -2428,6 +2459,13 @@ pub trait Float: Sized { /// Convert degrees to radians. #[stable(feature = "deg_rad_conversions", since="1.7.0")] fn to_radians(self) -> Self; + + /// Returns the maximum of the two numbers. + #[stable(feature = "core_float_min_max", since="1.20.0")] + fn max(self, other: Self) -> Self; + /// Returns the minimum of the two numbers. + #[stable(feature = "core_float_min_max", since="1.20.0")] + fn min(self, other: Self) -> Self; } macro_rules! from_str_radix_int_impl { diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs deleted file mode 100644 index a1de8fe76e25..000000000000 --- a/src/libcore/ops.rs +++ /dev/null @@ -1,3021 +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. - -//! Overloadable operators. -//! -//! Implementing these traits allows you to overload certain operators. -//! -//! Some of these traits are imported by the prelude, so they are available in -//! every Rust program. Only operators backed by traits can be overloaded. For -//! example, the addition operator (`+`) can be overloaded through the [`Add`] -//! trait, but since the assignment operator (`=`) has no backing trait, there -//! is no way of overloading its semantics. Additionally, this module does not -//! provide any mechanism to create new operators. If traitless overloading or -//! custom operators are required, you should look toward macros or compiler -//! plugins to extend Rust's syntax. -//! -//! Note that the `&&` and `||` operators short-circuit, i.e. they only -//! evaluate their second operand if it contributes to the result. Since this -//! behavior is not enforceable by traits, `&&` and `||` are not supported as -//! overloadable operators. -//! -//! Many of the operators take their operands by value. In non-generic -//! contexts involving built-in types, this is usually not a problem. -//! However, using these operators in generic code, requires some -//! attention if values have to be reused as opposed to letting the operators -//! consume them. One option is to occasionally use [`clone`]. -//! Another option is to rely on the types involved providing additional -//! operator implementations for references. For example, for a user-defined -//! type `T` which is supposed to support addition, it is probably a good -//! idea to have both `T` and `&T` implement the traits [`Add`][`Add`] and -//! [`Add<&T>`][`Add`] so that generic code can be written without unnecessary -//! cloning. -//! -//! # Examples -//! -//! This example creates a `Point` struct that implements [`Add`] and [`Sub`], -//! and then demonstrates adding and subtracting two `Point`s. -//! -//! ```rust -//! use std::ops::{Add, Sub}; -//! -//! #[derive(Debug)] -//! struct Point { -//! x: i32, -//! y: i32, -//! } -//! -//! impl Add for Point { -//! type Output = Point; -//! -//! fn add(self, other: Point) -> Point { -//! Point {x: self.x + other.x, y: self.y + other.y} -//! } -//! } -//! -//! impl Sub for Point { -//! type Output = Point; -//! -//! fn sub(self, other: Point) -> Point { -//! Point {x: self.x - other.x, y: self.y - other.y} -//! } -//! } -//! fn main() { -//! println!("{:?}", Point {x: 1, y: 0} + Point {x: 2, y: 3}); -//! println!("{:?}", Point {x: 1, y: 0} - Point {x: 2, y: 3}); -//! } -//! ``` -//! -//! See the documentation for each trait for an example implementation. -//! -//! The [`Fn`], [`FnMut`], and [`FnOnce`] traits are implemented by types that can be -//! invoked like functions. Note that [`Fn`] takes `&self`, [`FnMut`] takes `&mut -//! self` and [`FnOnce`] takes `self`. These correspond to the three kinds of -//! methods that can be invoked on an instance: call-by-reference, -//! call-by-mutable-reference, and call-by-value. The most common use of these -//! traits is to act as bounds to higher-level functions that take functions or -//! closures as arguments. -//! -//! Taking a [`Fn`] as a parameter: -//! -//! ```rust -//! fn call_with_one(func: F) -> usize -//! where F: Fn(usize) -> usize -//! { -//! func(1) -//! } -//! -//! let double = |x| x * 2; -//! assert_eq!(call_with_one(double), 2); -//! ``` -//! -//! Taking a [`FnMut`] as a parameter: -//! -//! ```rust -//! fn do_twice(mut func: F) -//! where F: FnMut() -//! { -//! func(); -//! func(); -//! } -//! -//! let mut x: usize = 1; -//! { -//! let add_two_to_x = || x += 2; -//! do_twice(add_two_to_x); -//! } -//! -//! assert_eq!(x, 5); -//! ``` -//! -//! Taking a [`FnOnce`] as a parameter: -//! -//! ```rust -//! fn consume_with_relish(func: F) -//! where F: FnOnce() -> String -//! { -//! // `func` consumes its captured variables, so it cannot be run more -//! // than once -//! println!("Consumed: {}", func()); -//! -//! println!("Delicious!"); -//! -//! // Attempting to invoke `func()` again will throw a `use of moved -//! // value` error for `func` -//! } -//! -//! let x = String::from("x"); -//! let consume_and_return_x = move || x; -//! consume_with_relish(consume_and_return_x); -//! -//! // `consume_and_return_x` can no longer be invoked at this point -//! ``` -//! -//! [`Fn`]: trait.Fn.html -//! [`FnMut`]: trait.FnMut.html -//! [`FnOnce`]: trait.FnOnce.html -//! [`Add`]: trait.Add.html -//! [`Sub`]: trait.Sub.html -//! [`clone`]: ../clone/trait.Clone.html#tymethod.clone - -#![stable(feature = "rust1", since = "1.0.0")] - -use fmt; -use marker::Unsize; - -/// The `Drop` trait is used to run some code when a value goes out of scope. -/// This is sometimes called a 'destructor'. -/// -/// When a value goes out of scope, if it implements this trait, it will have -/// its `drop` method called. Then any fields the value contains will also -/// be dropped recursively. -/// -/// Because of the recursive dropping, you do not need to implement this trait -/// unless your type needs its own destructor logic. -/// -/// # Examples -/// -/// A trivial implementation of `Drop`. The `drop` method is called when `_x` -/// goes out of scope, and therefore `main` prints `Dropping!`. -/// -/// ``` -/// struct HasDrop; -/// -/// impl Drop for HasDrop { -/// fn drop(&mut self) { -/// println!("Dropping!"); -/// } -/// } -/// -/// fn main() { -/// let _x = HasDrop; -/// } -/// ``` -/// -/// Showing the recursive nature of `Drop`. When `outer` goes out of scope, the -/// `drop` method will be called first for `Outer`, then for `Inner`. Therefore -/// `main` prints `Dropping Outer!` and then `Dropping Inner!`. -/// -/// ``` -/// struct Inner; -/// struct Outer(Inner); -/// -/// impl Drop for Inner { -/// fn drop(&mut self) { -/// println!("Dropping Inner!"); -/// } -/// } -/// -/// impl Drop for Outer { -/// fn drop(&mut self) { -/// println!("Dropping Outer!"); -/// } -/// } -/// -/// fn main() { -/// let _x = Outer(Inner); -/// } -/// ``` -/// -/// Because variables are dropped in the reverse order they are declared, -/// `main` will print `Declared second!` and then `Declared first!`. -/// -/// ``` -/// struct PrintOnDrop(&'static str); -/// -/// fn main() { -/// let _first = PrintOnDrop("Declared first!"); -/// let _second = PrintOnDrop("Declared second!"); -/// } -/// ``` -#[lang = "drop"] -#[stable(feature = "rust1", since = "1.0.0")] -pub trait Drop { - /// A method called when the value goes out of scope. - /// - /// When this method has been called, `self` has not yet been deallocated. - /// If it were, `self` would be a dangling reference. - /// - /// After this function is over, the memory of `self` will be deallocated. - /// - /// This function cannot be called explicitly. This is compiler error - /// [E0040]. However, the [`std::mem::drop`] function in the prelude can be - /// used to call the argument's `Drop` implementation. - /// - /// [E0040]: ../../error-index.html#E0040 - /// [`std::mem::drop`]: ../../std/mem/fn.drop.html - /// - /// # Panics - /// - /// Given that a `panic!` will call `drop()` as it unwinds, any `panic!` in - /// a `drop()` implementation will likely abort. - #[stable(feature = "rust1", since = "1.0.0")] - fn drop(&mut self); -} - -/// The addition operator `+`. -/// -/// # Examples -/// -/// This example creates a `Point` struct that implements the `Add` trait, and -/// then demonstrates adding two `Point`s. -/// -/// ``` -/// use std::ops::Add; -/// -/// #[derive(Debug)] -/// struct Point { -/// x: i32, -/// y: i32, -/// } -/// -/// impl Add for Point { -/// type Output = Point; -/// -/// fn add(self, other: Point) -> Point { -/// Point { -/// x: self.x + other.x, -/// y: self.y + other.y, -/// } -/// } -/// } -/// -/// impl PartialEq for Point { -/// fn eq(&self, other: &Self) -> bool { -/// self.x == other.x && self.y == other.y -/// } -/// } -/// -/// fn main() { -/// assert_eq!(Point { x: 1, y: 0 } + Point { x: 2, y: 3 }, -/// Point { x: 3, y: 3 }); -/// } -/// ``` -/// -/// Here is an example of the same `Point` struct implementing the `Add` trait -/// using generics. -/// -/// ``` -/// use std::ops::Add; -/// -/// #[derive(Debug)] -/// struct Point { -/// x: T, -/// y: T, -/// } -/// -/// // Notice that the implementation uses the `Output` associated type -/// impl> Add for Point { -/// type Output = Point; -/// -/// fn add(self, other: Point) -> Point { -/// Point { -/// x: self.x + other.x, -/// y: self.y + other.y, -/// } -/// } -/// } -/// -/// impl PartialEq for Point { -/// fn eq(&self, other: &Self) -> bool { -/// self.x == other.x && self.y == other.y -/// } -/// } -/// -/// fn main() { -/// assert_eq!(Point { x: 1, y: 0 } + Point { x: 2, y: 3 }, -/// Point { x: 3, y: 3 }); -/// } -/// ``` -/// -/// Note that `RHS = Self` by default, but this is not mandatory. For example, -/// [std::time::SystemTime] implements `Add`, which permits -/// operations of the form `SystemTime = SystemTime + Duration`. -/// -/// [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")] - type Output; - - /// The method for the `+` operator - #[stable(feature = "rust1", since = "1.0.0")] - fn add(self, rhs: RHS) -> Self::Output; -} - -macro_rules! add_impl { - ($($t:ty)*) => ($( - #[stable(feature = "rust1", since = "1.0.0")] - impl Add for $t { - type Output = $t; - - #[inline] - #[rustc_inherit_overflow_checks] - fn add(self, other: $t) -> $t { self + other } - } - - forward_ref_binop! { impl Add, add for $t, $t } - )*) -} - -add_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } - -/// The subtraction operator `-`. -/// -/// # Examples -/// -/// This example creates a `Point` struct that implements the `Sub` trait, and -/// then demonstrates subtracting two `Point`s. -/// -/// ``` -/// use std::ops::Sub; -/// -/// #[derive(Debug)] -/// struct Point { -/// x: i32, -/// y: i32, -/// } -/// -/// impl Sub for Point { -/// type Output = Point; -/// -/// fn sub(self, other: Point) -> Point { -/// Point { -/// x: self.x - other.x, -/// y: self.y - other.y, -/// } -/// } -/// } -/// -/// impl PartialEq for Point { -/// fn eq(&self, other: &Self) -> bool { -/// self.x == other.x && self.y == other.y -/// } -/// } -/// -/// fn main() { -/// assert_eq!(Point { x: 3, y: 3 } - Point { x: 2, y: 3 }, -/// Point { x: 1, y: 0 }); -/// } -/// ``` -/// -/// Note that `RHS = Self` by default, but this is not mandatory. For example, -/// [std::time::SystemTime] implements `Sub`, which permits -/// operations of the form `SystemTime = SystemTime - Duration`. -/// -/// [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")] - type Output; - - /// The method for the `-` operator - #[stable(feature = "rust1", since = "1.0.0")] - fn sub(self, rhs: RHS) -> Self::Output; -} - -macro_rules! sub_impl { - ($($t:ty)*) => ($( - #[stable(feature = "rust1", since = "1.0.0")] - impl Sub for $t { - type Output = $t; - - #[inline] - #[rustc_inherit_overflow_checks] - fn sub(self, other: $t) -> $t { self - other } - } - - forward_ref_binop! { impl Sub, sub for $t, $t } - )*) -} - -sub_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } - -/// The multiplication operator `*`. -/// -/// # Examples -/// -/// Implementing a `Mul`tipliable rational number struct: -/// -/// ``` -/// use std::ops::Mul; -/// -/// // The uniqueness of rational numbers in lowest terms is a consequence of -/// // the fundamental theorem of arithmetic. -/// #[derive(Eq)] -/// #[derive(PartialEq, Debug)] -/// struct Rational { -/// nominator: usize, -/// denominator: usize, -/// } -/// -/// impl Rational { -/// fn new(nominator: usize, denominator: usize) -> Self { -/// if denominator == 0 { -/// panic!("Zero is an invalid denominator!"); -/// } -/// -/// // Reduce to lowest terms by dividing by the greatest common -/// // divisor. -/// let gcd = gcd(nominator, denominator); -/// Rational { -/// nominator: nominator / gcd, -/// denominator: denominator / gcd, -/// } -/// } -/// } -/// -/// impl Mul for Rational { -/// // The multiplication of rational numbers is a closed operation. -/// type Output = Self; -/// -/// fn mul(self, rhs: Self) -> Self { -/// let nominator = self.nominator * rhs.nominator; -/// let denominator = self.denominator * rhs.denominator; -/// Rational::new(nominator, denominator) -/// } -/// } -/// -/// // Euclid's two-thousand-year-old algorithm for finding the greatest common -/// // divisor. -/// fn gcd(x: usize, y: usize) -> usize { -/// let mut x = x; -/// let mut y = y; -/// while y != 0 { -/// let t = y; -/// y = x % y; -/// x = t; -/// } -/// x -/// } -/// -/// assert_eq!(Rational::new(1, 2), Rational::new(2, 4)); -/// assert_eq!(Rational::new(2, 3) * Rational::new(3, 4), -/// Rational::new(1, 2)); -/// ``` -/// -/// Note that `RHS = Self` by default, but this is not mandatory. Here is an -/// implementation which enables multiplication of vectors by scalars, as is -/// done in linear algebra. -/// -/// ``` -/// use std::ops::Mul; -/// -/// struct Scalar {value: usize}; -/// -/// #[derive(Debug)] -/// struct Vector {value: Vec}; -/// -/// impl Mul for Scalar { -/// type Output = Vector; -/// -/// fn mul(self, rhs: Vector) -> Vector { -/// Vector {value: rhs.value.iter().map(|v| self.value * v).collect()} -/// } -/// } -/// -/// impl PartialEq for Vector { -/// fn eq(&self, other: &Self) -> bool { -/// self.value == other.value -/// } -/// } -/// -/// let scalar = Scalar{value: 3}; -/// let vector = Vector{value: vec![2, 4, 6]}; -/// assert_eq!(scalar * vector, Vector{value: vec![6, 12, 18]}); -/// ``` -#[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")] - type Output; - - /// The method for the `*` operator - #[stable(feature = "rust1", since = "1.0.0")] - fn mul(self, rhs: RHS) -> Self::Output; -} - -macro_rules! mul_impl { - ($($t:ty)*) => ($( - #[stable(feature = "rust1", since = "1.0.0")] - impl Mul for $t { - type Output = $t; - - #[inline] - #[rustc_inherit_overflow_checks] - fn mul(self, other: $t) -> $t { self * other } - } - - forward_ref_binop! { impl Mul, mul for $t, $t } - )*) -} - -mul_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } - -/// The division operator `/`. -/// -/// # Examples -/// -/// Implementing a `Div`idable rational number struct: -/// -/// ``` -/// use std::ops::Div; -/// -/// // The uniqueness of rational numbers in lowest terms is a consequence of -/// // the fundamental theorem of arithmetic. -/// #[derive(Eq)] -/// #[derive(PartialEq, Debug)] -/// struct Rational { -/// nominator: usize, -/// denominator: usize, -/// } -/// -/// impl Rational { -/// fn new(nominator: usize, denominator: usize) -> Self { -/// if denominator == 0 { -/// panic!("Zero is an invalid denominator!"); -/// } -/// -/// // Reduce to lowest terms by dividing by the greatest common -/// // divisor. -/// let gcd = gcd(nominator, denominator); -/// Rational { -/// nominator: nominator / gcd, -/// denominator: denominator / gcd, -/// } -/// } -/// } -/// -/// impl Div for Rational { -/// // The division of rational numbers is a closed operation. -/// type Output = Self; -/// -/// fn div(self, rhs: Self) -> Self { -/// if rhs.nominator == 0 { -/// panic!("Cannot divide by zero-valued `Rational`!"); -/// } -/// -/// let nominator = self.nominator * rhs.denominator; -/// let denominator = self.denominator * rhs.nominator; -/// Rational::new(nominator, denominator) -/// } -/// } -/// -/// // Euclid's two-thousand-year-old algorithm for finding the greatest common -/// // divisor. -/// fn gcd(x: usize, y: usize) -> usize { -/// let mut x = x; -/// let mut y = y; -/// while y != 0 { -/// let t = y; -/// y = x % y; -/// x = t; -/// } -/// x -/// } -/// -/// fn main() { -/// assert_eq!(Rational::new(1, 2), Rational::new(2, 4)); -/// assert_eq!(Rational::new(1, 2) / Rational::new(3, 4), -/// Rational::new(2, 3)); -/// } -/// ``` -/// -/// Note that `RHS = Self` by default, but this is not mandatory. Here is an -/// implementation which enables division of vectors by scalars, as is done in -/// linear algebra. -/// -/// ``` -/// use std::ops::Div; -/// -/// struct Scalar {value: f32}; -/// -/// #[derive(Debug)] -/// struct Vector {value: Vec}; -/// -/// impl Div for Vector { -/// type Output = Vector; -/// -/// fn div(self, rhs: Scalar) -> Vector { -/// Vector {value: self.value.iter().map(|v| v / rhs.value).collect()} -/// } -/// } -/// -/// impl PartialEq for Vector { -/// fn eq(&self, other: &Self) -> bool { -/// self.value == other.value -/// } -/// } -/// -/// let scalar = Scalar{value: 2f32}; -/// let vector = Vector{value: vec![2f32, 4f32, 6f32]}; -/// assert_eq!(vector / scalar, Vector{value: vec![1f32, 2f32, 3f32]}); -/// ``` -#[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")] - type Output; - - /// The method for the `/` operator - #[stable(feature = "rust1", since = "1.0.0")] - fn div(self, rhs: RHS) -> Self::Output; -} - -macro_rules! div_impl_integer { - ($($t:ty)*) => ($( - /// This operation rounds towards zero, truncating any - /// fractional part of the exact result. - #[stable(feature = "rust1", since = "1.0.0")] - impl Div for $t { - type Output = $t; - - #[inline] - fn div(self, other: $t) -> $t { self / other } - } - - forward_ref_binop! { impl Div, div for $t, $t } - )*) -} - -div_impl_integer! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } - -macro_rules! div_impl_float { - ($($t:ty)*) => ($( - #[stable(feature = "rust1", since = "1.0.0")] - impl Div for $t { - type Output = $t; - - #[inline] - fn div(self, other: $t) -> $t { self / other } - } - - forward_ref_binop! { impl Div, div for $t, $t } - )*) -} - -div_impl_float! { f32 f64 } - -/// The remainder operator `%`. -/// -/// # Examples -/// -/// This example implements `Rem` on a `SplitSlice` object. After `Rem` is -/// implemented, one can use the `%` operator to find out what the remaining -/// elements of the slice would be after splitting it into equal slices of a -/// given length. -/// -/// ``` -/// use std::ops::Rem; -/// -/// #[derive(PartialEq, Debug)] -/// struct SplitSlice<'a, T: 'a> { -/// slice: &'a [T], -/// } -/// -/// impl<'a, T> Rem for SplitSlice<'a, T> { -/// type Output = SplitSlice<'a, T>; -/// -/// fn rem(self, modulus: usize) -> Self { -/// let len = self.slice.len(); -/// let rem = len % modulus; -/// let start = len - rem; -/// SplitSlice {slice: &self.slice[start..]} -/// } -/// } -/// -/// // If we were to divide &[0, 1, 2, 3, 4, 5, 6, 7] into slices of size 3, -/// // the remainder would be &[6, 7] -/// assert_eq!(SplitSlice { slice: &[0, 1, 2, 3, 4, 5, 6, 7] } % 3, -/// SplitSlice { slice: &[6, 7] }); -/// ``` -#[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")] - type Output = Self; - - /// The method for the `%` operator - #[stable(feature = "rust1", since = "1.0.0")] - fn rem(self, rhs: RHS) -> Self::Output; -} - -macro_rules! rem_impl_integer { - ($($t:ty)*) => ($( - /// This operation satisfies `n % d == n - (n / d) * d`. The - /// result has the same sign as the left operand. - #[stable(feature = "rust1", since = "1.0.0")] - impl Rem for $t { - type Output = $t; - - #[inline] - fn rem(self, other: $t) -> $t { self % other } - } - - forward_ref_binop! { impl Rem, rem for $t, $t } - )*) -} - -rem_impl_integer! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } - - -macro_rules! rem_impl_float { - ($($t:ty)*) => ($( - #[stable(feature = "rust1", since = "1.0.0")] - impl Rem for $t { - type Output = $t; - - #[inline] - fn rem(self, other: $t) -> $t { self % other } - } - - forward_ref_binop! { impl Rem, rem for $t, $t } - )*) -} - -rem_impl_float! { f32 f64 } - -/// The unary negation operator `-`. -/// -/// # Examples -/// -/// An implementation of `Neg` for `Sign`, which allows the use of `-` to -/// negate its value. -/// -/// ``` -/// use std::ops::Neg; -/// -/// #[derive(Debug, PartialEq)] -/// enum Sign { -/// Negative, -/// Zero, -/// Positive, -/// } -/// -/// impl Neg for Sign { -/// type Output = Sign; -/// -/// fn neg(self) -> Sign { -/// match self { -/// Sign::Negative => Sign::Positive, -/// Sign::Zero => Sign::Zero, -/// Sign::Positive => Sign::Negative, -/// } -/// } -/// } -/// -/// // a negative positive is a negative -/// assert_eq!(-Sign::Positive, Sign::Negative); -/// // a double negative is a positive -/// assert_eq!(-Sign::Negative, Sign::Positive); -/// // zero is its own negation -/// assert_eq!(-Sign::Zero, Sign::Zero); -/// ``` -#[lang = "neg"] -#[stable(feature = "rust1", since = "1.0.0")] -pub trait Neg { - /// The resulting type after applying the `-` operator - #[stable(feature = "rust1", since = "1.0.0")] - type Output; - - /// The method for the unary `-` operator - #[stable(feature = "rust1", since = "1.0.0")] - fn neg(self) -> Self::Output; -} - - - -macro_rules! neg_impl_core { - ($id:ident => $body:expr, $($t:ty)*) => ($( - #[stable(feature = "rust1", since = "1.0.0")] - impl Neg for $t { - type Output = $t; - - #[inline] - #[rustc_inherit_overflow_checks] - fn neg(self) -> $t { let $id = self; $body } - } - - forward_ref_unop! { impl Neg, neg for $t } - )*) -} - -macro_rules! neg_impl_numeric { - ($($t:ty)*) => { neg_impl_core!{ x => -x, $($t)*} } -} - -#[allow(unused_macros)] -macro_rules! neg_impl_unsigned { - ($($t:ty)*) => { - neg_impl_core!{ x => { - !x.wrapping_add(1) - }, $($t)*} } -} - -// neg_impl_unsigned! { usize u8 u16 u32 u64 } -neg_impl_numeric! { isize i8 i16 i32 i64 i128 f32 f64 } - -/// The unary logical negation operator `!`. -/// -/// # Examples -/// -/// An implementation of `Not` for `Answer`, which enables the use of `!` to -/// invert its value. -/// -/// ``` -/// use std::ops::Not; -/// -/// #[derive(Debug, PartialEq)] -/// enum Answer { -/// Yes, -/// No, -/// } -/// -/// impl Not for Answer { -/// type Output = Answer; -/// -/// fn not(self) -> Answer { -/// match self { -/// Answer::Yes => Answer::No, -/// Answer::No => Answer::Yes -/// } -/// } -/// } -/// -/// assert_eq!(!Answer::Yes, Answer::No); -/// assert_eq!(!Answer::No, Answer::Yes); -/// ``` -#[lang = "not"] -#[stable(feature = "rust1", since = "1.0.0")] -pub trait Not { - /// The resulting type after applying the `!` operator - #[stable(feature = "rust1", since = "1.0.0")] - type Output; - - /// The method for the unary `!` operator - #[stable(feature = "rust1", since = "1.0.0")] - fn not(self) -> Self::Output; -} - -macro_rules! not_impl { - ($($t:ty)*) => ($( - #[stable(feature = "rust1", since = "1.0.0")] - impl Not for $t { - type Output = $t; - - #[inline] - fn not(self) -> $t { !self } - } - - forward_ref_unop! { impl Not, not for $t } - )*) -} - -not_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } - -/// The bitwise AND operator `&`. -/// -/// # Examples -/// -/// In this example, the `&` operator is lifted to a trivial `Scalar` type. -/// -/// ``` -/// use std::ops::BitAnd; -/// -/// #[derive(Debug, PartialEq)] -/// struct Scalar(bool); -/// -/// impl BitAnd for Scalar { -/// type Output = Self; -/// -/// // rhs is the "right-hand side" of the expression `a & b` -/// fn bitand(self, rhs: Self) -> Self { -/// Scalar(self.0 & rhs.0) -/// } -/// } -/// -/// fn main() { -/// assert_eq!(Scalar(true) & Scalar(true), Scalar(true)); -/// assert_eq!(Scalar(true) & Scalar(false), Scalar(false)); -/// assert_eq!(Scalar(false) & Scalar(true), Scalar(false)); -/// assert_eq!(Scalar(false) & Scalar(false), Scalar(false)); -/// } -/// ``` -/// -/// In this example, the `BitAnd` trait is implemented for a `BooleanVector` -/// struct. -/// -/// ``` -/// use std::ops::BitAnd; -/// -/// #[derive(Debug, PartialEq)] -/// struct BooleanVector(Vec); -/// -/// impl BitAnd for BooleanVector { -/// type Output = Self; -/// -/// fn bitand(self, BooleanVector(rhs): Self) -> Self { -/// let BooleanVector(lhs) = self; -/// assert_eq!(lhs.len(), rhs.len()); -/// BooleanVector(lhs.iter().zip(rhs.iter()).map(|(x, y)| *x && *y).collect()) -/// } -/// } -/// -/// fn main() { -/// let bv1 = BooleanVector(vec![true, true, false, false]); -/// let bv2 = BooleanVector(vec![true, false, true, false]); -/// let expected = BooleanVector(vec![true, false, false, false]); -/// assert_eq!(bv1 & bv2, expected); -/// } -/// ``` -#[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")] - type Output; - - /// The method for the `&` operator - #[stable(feature = "rust1", since = "1.0.0")] - fn bitand(self, rhs: RHS) -> Self::Output; -} - -macro_rules! bitand_impl { - ($($t:ty)*) => ($( - #[stable(feature = "rust1", since = "1.0.0")] - impl BitAnd for $t { - type Output = $t; - - #[inline] - fn bitand(self, rhs: $t) -> $t { self & rhs } - } - - forward_ref_binop! { impl BitAnd, bitand for $t, $t } - )*) -} - -bitand_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } - -/// The bitwise OR operator `|`. -/// -/// # Examples -/// -/// In this example, the `|` operator is lifted to a trivial `Scalar` type. -/// -/// ``` -/// use std::ops::BitOr; -/// -/// #[derive(Debug, PartialEq)] -/// struct Scalar(bool); -/// -/// impl BitOr for Scalar { -/// type Output = Self; -/// -/// // rhs is the "right-hand side" of the expression `a | b` -/// fn bitor(self, rhs: Self) -> Self { -/// Scalar(self.0 | rhs.0) -/// } -/// } -/// -/// fn main() { -/// assert_eq!(Scalar(true) | Scalar(true), Scalar(true)); -/// assert_eq!(Scalar(true) | Scalar(false), Scalar(true)); -/// assert_eq!(Scalar(false) | Scalar(true), Scalar(true)); -/// assert_eq!(Scalar(false) | Scalar(false), Scalar(false)); -/// } -/// ``` -/// -/// In this example, the `BitOr` trait is implemented for a `BooleanVector` -/// struct. -/// -/// ``` -/// use std::ops::BitOr; -/// -/// #[derive(Debug, PartialEq)] -/// struct BooleanVector(Vec); -/// -/// impl BitOr for BooleanVector { -/// type Output = Self; -/// -/// fn bitor(self, BooleanVector(rhs): Self) -> Self { -/// let BooleanVector(lhs) = self; -/// assert_eq!(lhs.len(), rhs.len()); -/// BooleanVector(lhs.iter().zip(rhs.iter()).map(|(x, y)| *x || *y).collect()) -/// } -/// } -/// -/// fn main() { -/// let bv1 = BooleanVector(vec![true, true, false, false]); -/// let bv2 = BooleanVector(vec![true, false, true, false]); -/// let expected = BooleanVector(vec![true, true, true, false]); -/// assert_eq!(bv1 | bv2, expected); -/// } -/// ``` -#[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")] - type Output; - - /// The method for the `|` operator - #[stable(feature = "rust1", since = "1.0.0")] - fn bitor(self, rhs: RHS) -> Self::Output; -} - -macro_rules! bitor_impl { - ($($t:ty)*) => ($( - #[stable(feature = "rust1", since = "1.0.0")] - impl BitOr for $t { - type Output = $t; - - #[inline] - fn bitor(self, rhs: $t) -> $t { self | rhs } - } - - forward_ref_binop! { impl BitOr, bitor for $t, $t } - )*) -} - -bitor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } - -/// The bitwise XOR operator `^`. -/// -/// # Examples -/// -/// In this example, the `^` operator is lifted to a trivial `Scalar` type. -/// -/// ``` -/// use std::ops::BitXor; -/// -/// #[derive(Debug, PartialEq)] -/// struct Scalar(bool); -/// -/// impl BitXor for Scalar { -/// type Output = Self; -/// -/// // rhs is the "right-hand side" of the expression `a ^ b` -/// fn bitxor(self, rhs: Self) -> Self { -/// Scalar(self.0 ^ rhs.0) -/// } -/// } -/// -/// fn main() { -/// assert_eq!(Scalar(true) ^ Scalar(true), Scalar(false)); -/// assert_eq!(Scalar(true) ^ Scalar(false), Scalar(true)); -/// assert_eq!(Scalar(false) ^ Scalar(true), Scalar(true)); -/// assert_eq!(Scalar(false) ^ Scalar(false), Scalar(false)); -/// } -/// ``` -/// -/// In this example, the `BitXor` trait is implemented for a `BooleanVector` -/// struct. -/// -/// ``` -/// use std::ops::BitXor; -/// -/// #[derive(Debug, PartialEq)] -/// struct BooleanVector(Vec); -/// -/// impl BitXor for BooleanVector { -/// type Output = Self; -/// -/// fn bitxor(self, BooleanVector(rhs): Self) -> Self { -/// let BooleanVector(lhs) = self; -/// assert_eq!(lhs.len(), rhs.len()); -/// BooleanVector(lhs.iter() -/// .zip(rhs.iter()) -/// .map(|(x, y)| (*x || *y) && !(*x && *y)) -/// .collect()) -/// } -/// } -/// -/// fn main() { -/// let bv1 = BooleanVector(vec![true, true, false, false]); -/// let bv2 = BooleanVector(vec![true, false, true, false]); -/// let expected = BooleanVector(vec![false, true, true, false]); -/// assert_eq!(bv1 ^ bv2, expected); -/// } -/// ``` -#[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")] - type Output; - - /// The method for the `^` operator - #[stable(feature = "rust1", since = "1.0.0")] - fn bitxor(self, rhs: RHS) -> Self::Output; -} - -macro_rules! bitxor_impl { - ($($t:ty)*) => ($( - #[stable(feature = "rust1", since = "1.0.0")] - impl BitXor for $t { - type Output = $t; - - #[inline] - fn bitxor(self, other: $t) -> $t { self ^ other } - } - - forward_ref_binop! { impl BitXor, bitxor for $t, $t } - )*) -} - -bitxor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } - -/// The left shift operator `<<`. -/// -/// # Examples -/// -/// An implementation of `Shl` that lifts the `<<` operation on integers to a -/// `Scalar` struct. -/// -/// ``` -/// use std::ops::Shl; -/// -/// #[derive(PartialEq, Debug)] -/// struct Scalar(usize); -/// -/// impl Shl for Scalar { -/// type Output = Self; -/// -/// fn shl(self, Scalar(rhs): Self) -> Scalar { -/// let Scalar(lhs) = self; -/// Scalar(lhs << rhs) -/// } -/// } -/// fn main() { -/// assert_eq!(Scalar(4) << Scalar(2), Scalar(16)); -/// } -/// ``` -/// -/// An implementation of `Shl` that spins a vector leftward by a given amount. -/// -/// ``` -/// use std::ops::Shl; -/// -/// #[derive(PartialEq, Debug)] -/// struct SpinVector { -/// vec: Vec, -/// } -/// -/// impl Shl for SpinVector { -/// type Output = Self; -/// -/// fn shl(self, rhs: usize) -> SpinVector { -/// // rotate the vector by `rhs` places -/// let (a, b) = self.vec.split_at(rhs); -/// let mut spun_vector: Vec = vec![]; -/// spun_vector.extend_from_slice(b); -/// spun_vector.extend_from_slice(a); -/// SpinVector { vec: spun_vector } -/// } -/// } -/// -/// fn main() { -/// assert_eq!(SpinVector { vec: vec![0, 1, 2, 3, 4] } << 2, -/// SpinVector { vec: vec![2, 3, 4, 0, 1] }); -/// } -/// ``` -#[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")] - type Output; - - /// The method for the `<<` operator - #[stable(feature = "rust1", since = "1.0.0")] - fn shl(self, rhs: RHS) -> Self::Output; -} - -macro_rules! shl_impl { - ($t:ty, $f:ty) => ( - #[stable(feature = "rust1", since = "1.0.0")] - impl Shl<$f> for $t { - type Output = $t; - - #[inline] - #[rustc_inherit_overflow_checks] - fn shl(self, other: $f) -> $t { - self << other - } - } - - forward_ref_binop! { impl Shl, shl for $t, $f } - ) -} - -macro_rules! shl_impl_all { - ($($t:ty)*) => ($( - shl_impl! { $t, u8 } - shl_impl! { $t, u16 } - shl_impl! { $t, u32 } - shl_impl! { $t, u64 } - shl_impl! { $t, u128 } - shl_impl! { $t, usize } - - shl_impl! { $t, i8 } - shl_impl! { $t, i16 } - shl_impl! { $t, i32 } - shl_impl! { $t, i64 } - shl_impl! { $t, i128 } - shl_impl! { $t, isize } - )*) -} - -shl_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 isize i128 } - -/// The right shift operator `>>`. -/// -/// # Examples -/// -/// An implementation of `Shr` that lifts the `>>` operation on integers to a -/// `Scalar` struct. -/// -/// ``` -/// use std::ops::Shr; -/// -/// #[derive(PartialEq, Debug)] -/// struct Scalar(usize); -/// -/// impl Shr for Scalar { -/// type Output = Self; -/// -/// fn shr(self, Scalar(rhs): Self) -> Scalar { -/// let Scalar(lhs) = self; -/// Scalar(lhs >> rhs) -/// } -/// } -/// fn main() { -/// assert_eq!(Scalar(16) >> Scalar(2), Scalar(4)); -/// } -/// ``` -/// -/// An implementation of `Shr` that spins a vector rightward by a given amount. -/// -/// ``` -/// use std::ops::Shr; -/// -/// #[derive(PartialEq, Debug)] -/// struct SpinVector { -/// vec: Vec, -/// } -/// -/// impl Shr for SpinVector { -/// type Output = Self; -/// -/// fn shr(self, rhs: usize) -> SpinVector { -/// // rotate the vector by `rhs` places -/// let (a, b) = self.vec.split_at(self.vec.len() - rhs); -/// let mut spun_vector: Vec = vec![]; -/// spun_vector.extend_from_slice(b); -/// spun_vector.extend_from_slice(a); -/// SpinVector { vec: spun_vector } -/// } -/// } -/// -/// fn main() { -/// assert_eq!(SpinVector { vec: vec![0, 1, 2, 3, 4] } >> 2, -/// SpinVector { vec: vec![3, 4, 0, 1, 2] }); -/// } -/// ``` -#[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")] - type Output; - - /// The method for the `>>` operator - #[stable(feature = "rust1", since = "1.0.0")] - fn shr(self, rhs: RHS) -> Self::Output; -} - -macro_rules! shr_impl { - ($t:ty, $f:ty) => ( - #[stable(feature = "rust1", since = "1.0.0")] - impl Shr<$f> for $t { - type Output = $t; - - #[inline] - #[rustc_inherit_overflow_checks] - fn shr(self, other: $f) -> $t { - self >> other - } - } - - forward_ref_binop! { impl Shr, shr for $t, $f } - ) -} - -macro_rules! shr_impl_all { - ($($t:ty)*) => ($( - shr_impl! { $t, u8 } - shr_impl! { $t, u16 } - shr_impl! { $t, u32 } - shr_impl! { $t, u64 } - shr_impl! { $t, u128 } - shr_impl! { $t, usize } - - shr_impl! { $t, i8 } - shr_impl! { $t, i16 } - shr_impl! { $t, i32 } - shr_impl! { $t, i64 } - shr_impl! { $t, i128 } - shr_impl! { $t, isize } - )*) -} - -shr_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize } - -/// The addition assignment operator `+=`. -/// -/// # Examples -/// -/// This example creates a `Point` struct that implements the `AddAssign` -/// trait, and then demonstrates add-assigning to a mutable `Point`. -/// -/// ``` -/// use std::ops::AddAssign; -/// -/// #[derive(Debug)] -/// struct Point { -/// x: i32, -/// y: i32, -/// } -/// -/// impl AddAssign for Point { -/// fn add_assign(&mut self, other: Point) { -/// *self = Point { -/// x: self.x + other.x, -/// y: self.y + other.y, -/// }; -/// } -/// } -/// -/// impl PartialEq for Point { -/// fn eq(&self, other: &Self) -> bool { -/// self.x == other.x && self.y == other.y -/// } -/// } -/// -/// let mut point = Point { x: 1, y: 0 }; -/// point += Point { x: 2, y: 3 }; -/// assert_eq!(point, Point { x: 3, y: 3 }); -/// ``` -#[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")] - fn add_assign(&mut self, rhs: Rhs); -} - -macro_rules! add_assign_impl { - ($($t:ty)+) => ($( - #[stable(feature = "op_assign_traits", since = "1.8.0")] - impl AddAssign for $t { - #[inline] - #[rustc_inherit_overflow_checks] - fn add_assign(&mut self, other: $t) { *self += other } - } - )+) -} - -add_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } - -/// The subtraction assignment operator `-=`. -/// -/// # Examples -/// -/// This example creates a `Point` struct that implements the `SubAssign` -/// trait, and then demonstrates sub-assigning to a mutable `Point`. -/// -/// ``` -/// use std::ops::SubAssign; -/// -/// #[derive(Debug)] -/// struct Point { -/// x: i32, -/// y: i32, -/// } -/// -/// impl SubAssign for Point { -/// fn sub_assign(&mut self, other: Point) { -/// *self = Point { -/// x: self.x - other.x, -/// y: self.y - other.y, -/// }; -/// } -/// } -/// -/// impl PartialEq for Point { -/// fn eq(&self, other: &Self) -> bool { -/// self.x == other.x && self.y == other.y -/// } -/// } -/// -/// let mut point = Point { x: 3, y: 3 }; -/// point -= Point { x: 2, y: 3 }; -/// assert_eq!(point, Point {x: 1, y: 0}); -/// ``` -#[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")] - fn sub_assign(&mut self, rhs: Rhs); -} - -macro_rules! sub_assign_impl { - ($($t:ty)+) => ($( - #[stable(feature = "op_assign_traits", since = "1.8.0")] - impl SubAssign for $t { - #[inline] - #[rustc_inherit_overflow_checks] - fn sub_assign(&mut self, other: $t) { *self -= other } - } - )+) -} - -sub_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } - -/// The multiplication assignment operator `*=`. -/// -/// # Examples -/// -/// A trivial implementation of `MulAssign`. When `Foo *= Foo` happens, it ends up -/// calling `mul_assign`, and therefore, `main` prints `Multiplying!`. -/// -/// ``` -/// use std::ops::MulAssign; -/// -/// struct Foo; -/// -/// impl MulAssign for Foo { -/// fn mul_assign(&mut self, _rhs: Foo) { -/// println!("Multiplying!"); -/// } -/// } -/// -/// # #[allow(unused_assignments)] -/// fn main() { -/// let mut foo = Foo; -/// foo *= Foo; -/// } -/// ``` -#[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")] - fn mul_assign(&mut self, rhs: Rhs); -} - -macro_rules! mul_assign_impl { - ($($t:ty)+) => ($( - #[stable(feature = "op_assign_traits", since = "1.8.0")] - impl MulAssign for $t { - #[inline] - #[rustc_inherit_overflow_checks] - fn mul_assign(&mut self, other: $t) { *self *= other } - } - )+) -} - -mul_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } - -/// The division assignment operator `/=`. -/// -/// # Examples -/// -/// A trivial implementation of `DivAssign`. When `Foo /= Foo` happens, it ends up -/// calling `div_assign`, and therefore, `main` prints `Dividing!`. -/// -/// ``` -/// use std::ops::DivAssign; -/// -/// struct Foo; -/// -/// impl DivAssign for Foo { -/// fn div_assign(&mut self, _rhs: Foo) { -/// println!("Dividing!"); -/// } -/// } -/// -/// # #[allow(unused_assignments)] -/// fn main() { -/// let mut foo = Foo; -/// foo /= Foo; -/// } -/// ``` -#[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")] - fn div_assign(&mut self, rhs: Rhs); -} - -macro_rules! div_assign_impl { - ($($t:ty)+) => ($( - #[stable(feature = "op_assign_traits", since = "1.8.0")] - impl DivAssign for $t { - #[inline] - fn div_assign(&mut self, other: $t) { *self /= other } - } - )+) -} - -div_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } - -/// The remainder assignment operator `%=`. -/// -/// # Examples -/// -/// A trivial implementation of `RemAssign`. When `Foo %= Foo` happens, it ends up -/// calling `rem_assign`, and therefore, `main` prints `Remainder-ing!`. -/// -/// ``` -/// use std::ops::RemAssign; -/// -/// struct Foo; -/// -/// impl RemAssign for Foo { -/// fn rem_assign(&mut self, _rhs: Foo) { -/// println!("Remainder-ing!"); -/// } -/// } -/// -/// # #[allow(unused_assignments)] -/// fn main() { -/// let mut foo = Foo; -/// foo %= Foo; -/// } -/// ``` -#[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")] - fn rem_assign(&mut self, rhs: Rhs); -} - -macro_rules! rem_assign_impl { - ($($t:ty)+) => ($( - #[stable(feature = "op_assign_traits", since = "1.8.0")] - impl RemAssign for $t { - #[inline] - fn rem_assign(&mut self, other: $t) { *self %= other } - } - )+) -} - -rem_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } - -/// The bitwise AND assignment operator `&=`. -/// -/// # Examples -/// -/// In this example, the `&=` operator is lifted to a trivial `Scalar` type. -/// -/// ``` -/// use std::ops::BitAndAssign; -/// -/// #[derive(Debug, PartialEq)] -/// struct Scalar(bool); -/// -/// impl BitAndAssign for Scalar { -/// // rhs is the "right-hand side" of the expression `a &= b` -/// fn bitand_assign(&mut self, rhs: Self) { -/// *self = Scalar(self.0 & rhs.0) -/// } -/// } -/// -/// fn main() { -/// let mut scalar = Scalar(true); -/// scalar &= Scalar(true); -/// assert_eq!(scalar, Scalar(true)); -/// -/// let mut scalar = Scalar(true); -/// scalar &= Scalar(false); -/// assert_eq!(scalar, Scalar(false)); -/// -/// let mut scalar = Scalar(false); -/// scalar &= Scalar(true); -/// assert_eq!(scalar, Scalar(false)); -/// -/// let mut scalar = Scalar(false); -/// scalar &= Scalar(false); -/// assert_eq!(scalar, Scalar(false)); -/// } -/// ``` -/// -/// In this example, the `BitAndAssign` trait is implemented for a -/// `BooleanVector` struct. -/// -/// ``` -/// use std::ops::BitAndAssign; -/// -/// #[derive(Debug, PartialEq)] -/// struct BooleanVector(Vec); -/// -/// impl BitAndAssign for BooleanVector { -/// // rhs is the "right-hand side" of the expression `a &= b` -/// fn bitand_assign(&mut self, rhs: Self) { -/// assert_eq!(self.0.len(), rhs.0.len()); -/// *self = BooleanVector(self.0 -/// .iter() -/// .zip(rhs.0.iter()) -/// .map(|(x, y)| *x && *y) -/// .collect()); -/// } -/// } -/// -/// fn main() { -/// let mut bv = BooleanVector(vec![true, true, false, false]); -/// bv &= BooleanVector(vec![true, false, true, false]); -/// let expected = BooleanVector(vec![true, false, false, false]); -/// assert_eq!(bv, expected); -/// } -/// ``` -#[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")] - fn bitand_assign(&mut self, rhs: Rhs); -} - -macro_rules! bitand_assign_impl { - ($($t:ty)+) => ($( - #[stable(feature = "op_assign_traits", since = "1.8.0")] - impl BitAndAssign for $t { - #[inline] - fn bitand_assign(&mut self, other: $t) { *self &= other } - } - )+) -} - -bitand_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } - -/// The bitwise OR assignment operator `|=`. -/// -/// # Examples -/// -/// A trivial implementation of `BitOrAssign`. When `Foo |= Foo` happens, it ends up -/// calling `bitor_assign`, and therefore, `main` prints `Bitwise Or-ing!`. -/// -/// ``` -/// use std::ops::BitOrAssign; -/// -/// struct Foo; -/// -/// impl BitOrAssign for Foo { -/// fn bitor_assign(&mut self, _rhs: Foo) { -/// println!("Bitwise Or-ing!"); -/// } -/// } -/// -/// # #[allow(unused_assignments)] -/// fn main() { -/// let mut foo = Foo; -/// foo |= Foo; -/// } -/// ``` -#[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")] - fn bitor_assign(&mut self, rhs: Rhs); -} - -macro_rules! bitor_assign_impl { - ($($t:ty)+) => ($( - #[stable(feature = "op_assign_traits", since = "1.8.0")] - impl BitOrAssign for $t { - #[inline] - fn bitor_assign(&mut self, other: $t) { *self |= other } - } - )+) -} - -bitor_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } - -/// The bitwise XOR assignment operator `^=`. -/// -/// # Examples -/// -/// A trivial implementation of `BitXorAssign`. When `Foo ^= Foo` happens, it ends up -/// calling `bitxor_assign`, and therefore, `main` prints `Bitwise Xor-ing!`. -/// -/// ``` -/// use std::ops::BitXorAssign; -/// -/// struct Foo; -/// -/// impl BitXorAssign for Foo { -/// fn bitxor_assign(&mut self, _rhs: Foo) { -/// println!("Bitwise Xor-ing!"); -/// } -/// } -/// -/// # #[allow(unused_assignments)] -/// fn main() { -/// let mut foo = Foo; -/// foo ^= Foo; -/// } -/// ``` -#[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")] - fn bitxor_assign(&mut self, rhs: Rhs); -} - -macro_rules! bitxor_assign_impl { - ($($t:ty)+) => ($( - #[stable(feature = "op_assign_traits", since = "1.8.0")] - impl BitXorAssign for $t { - #[inline] - fn bitxor_assign(&mut self, other: $t) { *self ^= other } - } - )+) -} - -bitxor_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } - -/// The left shift assignment operator `<<=`. -/// -/// # Examples -/// -/// A trivial implementation of `ShlAssign`. When `Foo <<= Foo` happens, it ends up -/// calling `shl_assign`, and therefore, `main` prints `Shifting left!`. -/// -/// ``` -/// use std::ops::ShlAssign; -/// -/// struct Foo; -/// -/// impl ShlAssign for Foo { -/// fn shl_assign(&mut self, _rhs: Foo) { -/// println!("Shifting left!"); -/// } -/// } -/// -/// # #[allow(unused_assignments)] -/// fn main() { -/// let mut foo = Foo; -/// foo <<= Foo; -/// } -/// ``` -#[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")] - fn shl_assign(&mut self, rhs: Rhs); -} - -macro_rules! shl_assign_impl { - ($t:ty, $f:ty) => ( - #[stable(feature = "op_assign_traits", since = "1.8.0")] - impl ShlAssign<$f> for $t { - #[inline] - #[rustc_inherit_overflow_checks] - fn shl_assign(&mut self, other: $f) { - *self <<= other - } - } - ) -} - -macro_rules! shl_assign_impl_all { - ($($t:ty)*) => ($( - shl_assign_impl! { $t, u8 } - shl_assign_impl! { $t, u16 } - shl_assign_impl! { $t, u32 } - shl_assign_impl! { $t, u64 } - shl_assign_impl! { $t, u128 } - shl_assign_impl! { $t, usize } - - shl_assign_impl! { $t, i8 } - shl_assign_impl! { $t, i16 } - shl_assign_impl! { $t, i32 } - shl_assign_impl! { $t, i64 } - shl_assign_impl! { $t, i128 } - shl_assign_impl! { $t, isize } - )*) -} - -shl_assign_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize } - -/// The right shift assignment operator `>>=`. -/// -/// # Examples -/// -/// A trivial implementation of `ShrAssign`. When `Foo >>= Foo` happens, it ends up -/// calling `shr_assign`, and therefore, `main` prints `Shifting right!`. -/// -/// ``` -/// use std::ops::ShrAssign; -/// -/// struct Foo; -/// -/// impl ShrAssign for Foo { -/// fn shr_assign(&mut self, _rhs: Foo) { -/// println!("Shifting right!"); -/// } -/// } -/// -/// # #[allow(unused_assignments)] -/// fn main() { -/// let mut foo = Foo; -/// foo >>= Foo; -/// } -/// ``` -#[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")] - fn shr_assign(&mut self, rhs: Rhs); -} - -macro_rules! shr_assign_impl { - ($t:ty, $f:ty) => ( - #[stable(feature = "op_assign_traits", since = "1.8.0")] - impl ShrAssign<$f> for $t { - #[inline] - #[rustc_inherit_overflow_checks] - fn shr_assign(&mut self, other: $f) { - *self >>= other - } - } - ) -} - -macro_rules! shr_assign_impl_all { - ($($t:ty)*) => ($( - shr_assign_impl! { $t, u8 } - shr_assign_impl! { $t, u16 } - shr_assign_impl! { $t, u32 } - shr_assign_impl! { $t, u64 } - shr_assign_impl! { $t, u128 } - shr_assign_impl! { $t, usize } - - shr_assign_impl! { $t, i8 } - shr_assign_impl! { $t, i16 } - shr_assign_impl! { $t, i32 } - shr_assign_impl! { $t, i64 } - shr_assign_impl! { $t, i128 } - shr_assign_impl! { $t, isize } - )*) -} - -shr_assign_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize } - -/// The `Index` trait is used to specify the functionality of indexing operations -/// like `container[index]` when used in an immutable context. -/// -/// `container[index]` is actually syntactic sugar for `*container.index(index)`, -/// but only when used as an immutable value. If a mutable value is requested, -/// [`IndexMut`] is used instead. This allows nice things such as -/// `let value = v[index]` if `value` implements [`Copy`]. -/// -/// [`IndexMut`]: ../../std/ops/trait.IndexMut.html -/// [`Copy`]: ../../std/marker/trait.Copy.html -/// -/// # Examples -/// -/// The following example implements `Index` on a read-only `NucleotideCount` -/// container, enabling individual counts to be retrieved with index syntax. -/// -/// ``` -/// use std::ops::Index; -/// -/// enum Nucleotide { -/// A, -/// C, -/// G, -/// T, -/// } -/// -/// struct NucleotideCount { -/// a: usize, -/// c: usize, -/// g: usize, -/// t: usize, -/// } -/// -/// impl Index for NucleotideCount { -/// type Output = usize; -/// -/// fn index(&self, nucleotide: Nucleotide) -> &usize { -/// match nucleotide { -/// Nucleotide::A => &self.a, -/// Nucleotide::C => &self.c, -/// Nucleotide::G => &self.g, -/// Nucleotide::T => &self.t, -/// } -/// } -/// } -/// -/// let nucleotide_count = NucleotideCount {a: 14, c: 9, g: 10, t: 12}; -/// assert_eq!(nucleotide_count[Nucleotide::A], 14); -/// assert_eq!(nucleotide_count[Nucleotide::C], 9); -/// assert_eq!(nucleotide_count[Nucleotide::G], 10); -/// assert_eq!(nucleotide_count[Nucleotide::T], 12); -/// ``` -#[lang = "index"] -#[rustc_on_unimplemented = "the type `{Self}` cannot be indexed by `{Idx}`"] -#[stable(feature = "rust1", since = "1.0.0")] -pub trait Index { - /// The returned type after indexing - #[stable(feature = "rust1", since = "1.0.0")] - type Output: ?Sized; - - /// The method for the indexing (`container[index]`) operation - #[stable(feature = "rust1", since = "1.0.0")] - fn index(&self, index: Idx) -> &Self::Output; -} - -/// The `IndexMut` trait is used to specify the functionality of indexing -/// operations like `container[index]` when used in a mutable context. -/// -/// `container[index]` is actually syntactic sugar for -/// `*container.index_mut(index)`, but only when used as a mutable value. If -/// an immutable value is requested, the [`Index`] trait is used instead. This -/// allows nice things such as `v[index] = value` if `value` implements [`Copy`]. -/// -/// [`Index`]: ../../std/ops/trait.Index.html -/// [`Copy`]: ../../std/marker/trait.Copy.html -/// -/// # Examples -/// -/// A very simple implementation of a `Balance` struct that has two sides, where -/// each can be indexed mutably and immutably. -/// -/// ``` -/// use std::ops::{Index,IndexMut}; -/// -/// #[derive(Debug)] -/// enum Side { -/// Left, -/// Right, -/// } -/// -/// #[derive(Debug, PartialEq)] -/// enum Weight { -/// Kilogram(f32), -/// Pound(f32), -/// } -/// -/// struct Balance { -/// pub left: Weight, -/// pub right:Weight, -/// } -/// -/// impl Index for Balance { -/// type Output = Weight; -/// -/// fn index<'a>(&'a self, index: Side) -> &'a Weight { -/// println!("Accessing {:?}-side of balance immutably", index); -/// match index { -/// Side::Left => &self.left, -/// Side::Right => &self.right, -/// } -/// } -/// } -/// -/// impl IndexMut for Balance { -/// fn index_mut<'a>(&'a mut self, index: Side) -> &'a mut Weight { -/// println!("Accessing {:?}-side of balance mutably", index); -/// match index { -/// Side::Left => &mut self.left, -/// Side::Right => &mut self.right, -/// } -/// } -/// } -/// -/// fn main() { -/// let mut balance = Balance { -/// right: Weight::Kilogram(2.5), -/// left: Weight::Pound(1.5), -/// }; -/// -/// // In this case balance[Side::Right] is sugar for -/// // *balance.index(Side::Right), since we are only reading -/// // balance[Side::Right], not writing it. -/// assert_eq!(balance[Side::Right],Weight::Kilogram(2.5)); -/// -/// // However in this case balance[Side::Left] is sugar for -/// // *balance.index_mut(Side::Left), since we are writing -/// // balance[Side::Left]. -/// balance[Side::Left] = Weight::Kilogram(3.0); -/// } -/// ``` -#[lang = "index_mut"] -#[rustc_on_unimplemented = "the type `{Self}` cannot be mutably indexed by `{Idx}`"] -#[stable(feature = "rust1", since = "1.0.0")] -pub trait IndexMut: Index { - /// The method for the mutable indexing (`container[index]`) operation - #[stable(feature = "rust1", since = "1.0.0")] - fn index_mut(&mut self, index: Idx) -> &mut Self::Output; -} - -/// An unbounded range. Use `..` (two dots) for its shorthand. -/// -/// Its primary use case is slicing index. It cannot serve as an iterator -/// because it doesn't have a starting point. -/// -/// # Examples -/// -/// The `..` syntax is a `RangeFull`: -/// -/// ``` -/// assert_eq!((..), std::ops::RangeFull); -/// ``` -/// -/// It does not have an `IntoIterator` implementation, so you can't use it in a -/// `for` loop directly. This won't compile: -/// -/// ```ignore -/// for i in .. { -/// // ... -/// } -/// ``` -/// -/// Used as a slicing index, `RangeFull` produces the full array as a slice. -/// -/// ``` -/// let arr = [0, 1, 2, 3]; -/// assert_eq!(arr[ .. ], [0,1,2,3]); // RangeFull -/// assert_eq!(arr[ ..3], [0,1,2 ]); -/// assert_eq!(arr[1.. ], [ 1,2,3]); -/// assert_eq!(arr[1..3], [ 1,2 ]); -/// ``` -#[derive(Copy, Clone, PartialEq, Eq, Hash)] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct RangeFull; - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for RangeFull { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "..") - } -} - -/// A (half-open) range which is bounded at both ends: { x | start <= x < end }. -/// Use `start..end` (two dots) for its shorthand. -/// -/// See the [`contains`](#method.contains) method for its characterization. -/// -/// # Examples -/// -/// ``` -/// fn main() { -/// assert_eq!((3..5), std::ops::Range{ start: 3, end: 5 }); -/// assert_eq!(3+4+5, (3..6).sum()); -/// -/// let arr = [0, 1, 2, 3]; -/// assert_eq!(arr[ .. ], [0,1,2,3]); -/// assert_eq!(arr[ ..3], [0,1,2 ]); -/// assert_eq!(arr[1.. ], [ 1,2,3]); -/// assert_eq!(arr[1..3], [ 1,2 ]); // Range -/// } -/// ``` -#[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186 -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Range { - /// The lower bound of the range (inclusive). - #[stable(feature = "rust1", since = "1.0.0")] - pub start: Idx, - /// The upper bound of the range (exclusive). - #[stable(feature = "rust1", since = "1.0.0")] - pub end: Idx, -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for Range { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "{:?}..{:?}", self.start, self.end) - } -} - -#[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] -impl> Range { - /// # Examples - /// - /// ``` - /// #![feature(range_contains)] - /// fn main() { - /// assert!( ! (3..5).contains(2)); - /// assert!( (3..5).contains(3)); - /// assert!( (3..5).contains(4)); - /// assert!( ! (3..5).contains(5)); - /// - /// assert!( ! (3..3).contains(3)); - /// assert!( ! (3..2).contains(3)); - /// } - /// ``` - pub fn contains(&self, item: Idx) -> bool { - (self.start <= item) && (item < self.end) - } -} - -/// A range which is only bounded below: { x | start <= x }. -/// Use `start..` for its shorthand. -/// -/// See the [`contains`](#method.contains) method for its characterization. -/// -/// Note: Currently, no overflow checking is done for the iterator -/// implementation; if you use an integer range and the integer overflows, it -/// might panic in debug mode or create an endless loop in release mode. This -/// overflow behavior might change in the future. -/// -/// # Examples -/// -/// ``` -/// fn main() { -/// assert_eq!((2..), std::ops::RangeFrom{ start: 2 }); -/// assert_eq!(2+3+4, (2..).take(3).sum()); -/// -/// let arr = [0, 1, 2, 3]; -/// assert_eq!(arr[ .. ], [0,1,2,3]); -/// assert_eq!(arr[ ..3], [0,1,2 ]); -/// assert_eq!(arr[1.. ], [ 1,2,3]); // RangeFrom -/// assert_eq!(arr[1..3], [ 1,2 ]); -/// } -/// ``` -#[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186 -#[stable(feature = "rust1", since = "1.0.0")] -pub struct RangeFrom { - /// The lower bound of the range (inclusive). - #[stable(feature = "rust1", since = "1.0.0")] - pub start: Idx, -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for RangeFrom { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "{:?}..", self.start) - } -} - -#[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] -impl> RangeFrom { - /// # Examples - /// - /// ``` - /// #![feature(range_contains)] - /// fn main() { - /// assert!( ! (3..).contains(2)); - /// assert!( (3..).contains(3)); - /// assert!( (3..).contains(1_000_000_000)); - /// } - /// ``` - pub fn contains(&self, item: Idx) -> bool { - (self.start <= item) - } -} - -/// A range which is only bounded above: { x | x < end }. -/// Use `..end` (two dots) for its shorthand. -/// -/// See the [`contains`](#method.contains) method for its characterization. -/// -/// It cannot serve as an iterator because it doesn't have a starting point. -/// -/// # Examples -/// -/// The `..{integer}` syntax is a `RangeTo`: -/// -/// ``` -/// assert_eq!((..5), std::ops::RangeTo{ end: 5 }); -/// ``` -/// -/// It does not have an `IntoIterator` implementation, so you can't use it in a -/// `for` loop directly. This won't compile: -/// -/// ```ignore -/// for i in ..5 { -/// // ... -/// } -/// ``` -/// -/// When used as a slicing index, `RangeTo` produces a slice of all array -/// elements before the index indicated by `end`. -/// -/// ``` -/// let arr = [0, 1, 2, 3]; -/// assert_eq!(arr[ .. ], [0,1,2,3]); -/// assert_eq!(arr[ ..3], [0,1,2 ]); // RangeTo -/// assert_eq!(arr[1.. ], [ 1,2,3]); -/// assert_eq!(arr[1..3], [ 1,2 ]); -/// ``` -#[derive(Copy, Clone, PartialEq, Eq, Hash)] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct RangeTo { - /// The upper bound of the range (exclusive). - #[stable(feature = "rust1", since = "1.0.0")] - pub end: Idx, -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for RangeTo { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "..{:?}", self.end) - } -} - -#[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] -impl> RangeTo { - /// # Examples - /// - /// ``` - /// #![feature(range_contains)] - /// fn main() { - /// assert!( (..5).contains(-1_000_000_000)); - /// assert!( (..5).contains(4)); - /// assert!( ! (..5).contains(5)); - /// } - /// ``` - pub fn contains(&self, item: Idx) -> bool { - (item < self.end) - } -} - -/// An inclusive range which is bounded at both ends: { x | start <= x <= end }. -/// Use `start...end` (three dots) for its shorthand. -/// -/// See the [`contains`](#method.contains) method for its characterization. -/// -/// # Examples -/// -/// ``` -/// #![feature(inclusive_range,inclusive_range_syntax)] -/// fn main() { -/// assert_eq!((3...5), std::ops::RangeInclusive{ start: 3, end: 5 }); -/// assert_eq!(3+4+5, (3...5).sum()); -/// -/// let arr = [0, 1, 2, 3]; -/// assert_eq!(arr[ ...2], [0,1,2 ]); -/// assert_eq!(arr[1...2], [ 1,2 ]); // RangeInclusive -/// } -/// ``` -#[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186 -#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] -pub struct RangeInclusive { - /// The lower bound of the range (inclusive). - #[unstable(feature = "inclusive_range", - reason = "recently added, follows RFC", - issue = "28237")] - pub start: Idx, - /// The upper bound of the range (inclusive). - #[unstable(feature = "inclusive_range", - reason = "recently added, follows RFC", - issue = "28237")] - pub end: Idx, -} - -#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] -impl fmt::Debug for RangeInclusive { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "{:?}...{:?}", self.start, self.end) - } -} - -#[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] -impl> RangeInclusive { - /// # Examples - /// - /// ``` - /// #![feature(range_contains,inclusive_range_syntax)] - /// fn main() { - /// assert!( ! (3...5).contains(2)); - /// assert!( (3...5).contains(3)); - /// assert!( (3...5).contains(4)); - /// assert!( (3...5).contains(5)); - /// assert!( ! (3...5).contains(6)); - /// - /// assert!( (3...3).contains(3)); - /// assert!( ! (3...2).contains(3)); - /// } - /// ``` - pub fn contains(&self, item: Idx) -> bool { - self.start <= item && item <= self.end - } -} - -/// An inclusive range which is only bounded above: { x | x <= end }. -/// Use `...end` (three dots) for its shorthand. -/// -/// See the [`contains`](#method.contains) method for its characterization. -/// -/// It cannot serve as an iterator because it doesn't have a starting point. -/// -/// # Examples -/// -/// The `...{integer}` syntax is a `RangeToInclusive`: -/// -/// ``` -/// #![feature(inclusive_range,inclusive_range_syntax)] -/// assert_eq!((...5), std::ops::RangeToInclusive{ end: 5 }); -/// ``` -/// -/// It does not have an `IntoIterator` implementation, so you can't use it in a -/// `for` loop directly. This won't compile: -/// -/// ```ignore -/// for i in ...5 { -/// // ... -/// } -/// ``` -/// -/// When used as a slicing index, `RangeToInclusive` produces a slice of all -/// array elements up to and including the index indicated by `end`. -/// -/// ``` -/// #![feature(inclusive_range_syntax)] -/// let arr = [0, 1, 2, 3]; -/// assert_eq!(arr[ ...2], [0,1,2 ]); // RangeToInclusive -/// assert_eq!(arr[1...2], [ 1,2 ]); -/// ``` -#[derive(Copy, Clone, PartialEq, Eq, Hash)] -#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] -pub struct RangeToInclusive { - /// The upper bound of the range (inclusive) - #[unstable(feature = "inclusive_range", - reason = "recently added, follows RFC", - issue = "28237")] - pub end: Idx, -} - -#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] -impl fmt::Debug for RangeToInclusive { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "...{:?}", self.end) - } -} - -#[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] -impl> RangeToInclusive { - /// # Examples - /// - /// ``` - /// #![feature(range_contains,inclusive_range_syntax)] - /// fn main() { - /// assert!( (...5).contains(-1_000_000_000)); - /// assert!( (...5).contains(5)); - /// assert!( ! (...5).contains(6)); - /// } - /// ``` - pub fn contains(&self, item: Idx) -> bool { - (item <= self.end) - } -} - -// RangeToInclusive cannot impl From> -// because underflow would be possible with (..0).into() - -/// The `Deref` trait is used to specify the functionality of dereferencing -/// operations, like `*v`. -/// -/// `Deref` also enables ['`Deref` coercions'][coercions]. -/// -/// [coercions]: ../../book/deref-coercions.html -/// -/// # Examples -/// -/// A struct with a single field which is accessible via dereferencing the -/// struct. -/// -/// ``` -/// use std::ops::Deref; -/// -/// struct DerefExample { -/// value: T -/// } -/// -/// impl Deref for DerefExample { -/// type Target = T; -/// -/// fn deref(&self) -> &T { -/// &self.value -/// } -/// } -/// -/// fn main() { -/// let x = DerefExample { value: 'a' }; -/// assert_eq!('a', *x); -/// } -/// ``` -#[lang = "deref"] -#[stable(feature = "rust1", since = "1.0.0")] -pub trait Deref { - /// The resulting type after dereferencing - #[stable(feature = "rust1", since = "1.0.0")] - type Target: ?Sized; - - /// The method called to dereference a value - #[stable(feature = "rust1", since = "1.0.0")] - fn deref(&self) -> &Self::Target; -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T: ?Sized> Deref for &'a T { - type Target = T; - - fn deref(&self) -> &T { *self } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T: ?Sized> Deref for &'a mut T { - type Target = T; - - fn deref(&self) -> &T { *self } -} - -/// The `DerefMut` trait is used to specify the functionality of dereferencing -/// mutably like `*v = 1;` -/// -/// `DerefMut` also enables ['`Deref` coercions'][coercions]. -/// -/// [coercions]: ../../book/deref-coercions.html -/// -/// # Examples -/// -/// A struct with a single field which is modifiable via dereferencing the -/// struct. -/// -/// ``` -/// use std::ops::{Deref, DerefMut}; -/// -/// struct DerefMutExample { -/// value: T -/// } -/// -/// impl Deref for DerefMutExample { -/// type Target = T; -/// -/// fn deref(&self) -> &T { -/// &self.value -/// } -/// } -/// -/// impl DerefMut for DerefMutExample { -/// fn deref_mut(&mut self) -> &mut T { -/// &mut self.value -/// } -/// } -/// -/// fn main() { -/// let mut x = DerefMutExample { value: 'a' }; -/// *x = 'b'; -/// assert_eq!('b', *x); -/// } -/// ``` -#[lang = "deref_mut"] -#[stable(feature = "rust1", since = "1.0.0")] -pub trait DerefMut: Deref { - /// The method called to mutably dereference a value - #[stable(feature = "rust1", since = "1.0.0")] - fn deref_mut(&mut self) -> &mut Self::Target; -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T: ?Sized> DerefMut for &'a mut T { - fn deref_mut(&mut self) -> &mut T { *self } -} - -/// A version of the call operator that takes an immutable receiver. -/// -/// # Examples -/// -/// Closures automatically implement this trait, which allows them to be -/// invoked. Note, however, that `Fn` takes an immutable reference to any -/// captured variables. To take a mutable capture, implement [`FnMut`], and to -/// consume the capture, implement [`FnOnce`]. -/// -/// [`FnMut`]: trait.FnMut.html -/// [`FnOnce`]: trait.FnOnce.html -/// -/// ``` -/// let square = |x| x * x; -/// assert_eq!(square(5), 25); -/// ``` -/// -/// Closures can also be passed to higher-level functions through a `Fn` -/// parameter (or a `FnMut` or `FnOnce` parameter, which are supertraits of -/// `Fn`). -/// -/// ``` -/// fn call_with_one(func: F) -> usize -/// where F: Fn(usize) -> usize { -/// func(1) -/// } -/// -/// let double = |x| x * 2; -/// assert_eq!(call_with_one(double), 2); -/// ``` -#[lang = "fn"] -#[stable(feature = "rust1", since = "1.0.0")] -#[rustc_paren_sugar] -#[fundamental] // so that regex can rely that `&str: !FnMut` -pub trait Fn : FnMut { - /// This is called when the call operator is used. - #[unstable(feature = "fn_traits", issue = "29625")] - extern "rust-call" fn call(&self, args: Args) -> Self::Output; -} - -/// A version of the call operator that takes a mutable receiver. -/// -/// # Examples -/// -/// Closures that mutably capture variables automatically implement this trait, -/// which allows them to be invoked. -/// -/// ``` -/// let mut x = 5; -/// { -/// let mut square_x = || x *= x; -/// square_x(); -/// } -/// assert_eq!(x, 25); -/// ``` -/// -/// Closures can also be passed to higher-level functions through a `FnMut` -/// parameter (or a `FnOnce` parameter, which is a supertrait of `FnMut`). -/// -/// ``` -/// fn do_twice(mut func: F) -/// where F: FnMut() -/// { -/// func(); -/// func(); -/// } -/// -/// let mut x: usize = 1; -/// { -/// let add_two_to_x = || x += 2; -/// do_twice(add_two_to_x); -/// } -/// -/// assert_eq!(x, 5); -/// ``` -#[lang = "fn_mut"] -#[stable(feature = "rust1", since = "1.0.0")] -#[rustc_paren_sugar] -#[fundamental] // so that regex can rely that `&str: !FnMut` -pub trait FnMut : FnOnce { - /// This is called when the call operator is used. - #[unstable(feature = "fn_traits", issue = "29625")] - extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output; -} - -/// A version of the call operator that takes a by-value receiver. -/// -/// # Examples -/// -/// By-value closures automatically implement this trait, which allows them to -/// be invoked. -/// -/// ``` -/// let x = 5; -/// let square_x = move || x * x; -/// assert_eq!(square_x(), 25); -/// ``` -/// -/// By-value Closures can also be passed to higher-level functions through a -/// `FnOnce` parameter. -/// -/// ``` -/// fn consume_with_relish(func: F) -/// where F: FnOnce() -> String -/// { -/// // `func` consumes its captured variables, so it cannot be run more -/// // than once -/// println!("Consumed: {}", func()); -/// -/// println!("Delicious!"); -/// -/// // Attempting to invoke `func()` again will throw a `use of moved -/// // value` error for `func` -/// } -/// -/// let x = String::from("x"); -/// let consume_and_return_x = move || x; -/// consume_with_relish(consume_and_return_x); -/// -/// // `consume_and_return_x` can no longer be invoked at this point -/// ``` -#[lang = "fn_once"] -#[stable(feature = "rust1", since = "1.0.0")] -#[rustc_paren_sugar] -#[fundamental] // so that regex can rely that `&str: !FnMut` -pub trait FnOnce { - /// The returned type after the call operator is used. - #[stable(feature = "fn_once_output", since = "1.12.0")] - type Output; - - /// This is called when the call operator is used. - #[unstable(feature = "fn_traits", issue = "29625")] - extern "rust-call" fn call_once(self, args: Args) -> Self::Output; -} - -mod impls { - #[stable(feature = "rust1", since = "1.0.0")] - impl<'a,A,F:?Sized> Fn for &'a F - where F : Fn - { - extern "rust-call" fn call(&self, args: A) -> F::Output { - (**self).call(args) - } - } - - #[stable(feature = "rust1", since = "1.0.0")] - impl<'a,A,F:?Sized> FnMut for &'a F - where F : Fn - { - extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output { - (**self).call(args) - } - } - - #[stable(feature = "rust1", since = "1.0.0")] - impl<'a,A,F:?Sized> FnOnce for &'a F - where F : Fn - { - type Output = F::Output; - - extern "rust-call" fn call_once(self, args: A) -> F::Output { - (*self).call(args) - } - } - - #[stable(feature = "rust1", since = "1.0.0")] - impl<'a,A,F:?Sized> FnMut for &'a mut F - where F : FnMut - { - extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output { - (*self).call_mut(args) - } - } - - #[stable(feature = "rust1", since = "1.0.0")] - impl<'a,A,F:?Sized> FnOnce for &'a mut F - where F : FnMut - { - type Output = F::Output; - extern "rust-call" fn call_once(mut self, args: A) -> F::Output { - (*self).call_mut(args) - } - } -} - -/// Trait that indicates that this is a pointer or a wrapper for one, -/// where unsizing can be performed on the pointee. -/// -/// See the [DST coercion RfC][dst-coerce] and [the nomicon entry on coercion][nomicon-coerce] -/// for more details. -/// -/// For builtin pointer types, pointers to `T` will coerce to pointers to `U` if `T: Unsize` -/// by converting from a thin pointer to a fat pointer. -/// -/// For custom types, the coercion here works by coercing `Foo` to `Foo` -/// provided an impl of `CoerceUnsized> for Foo` exists. -/// Such an impl can only be written if `Foo` has only a single non-phantomdata -/// field involving `T`. If the type of that field is `Bar`, an implementation -/// of `CoerceUnsized> for Bar` must exist. The coercion will work by -/// by coercing the `Bar` field into `Bar` and filling in the rest of the fields -/// from `Foo` to create a `Foo`. This will effectively drill down to a pointer -/// field and coerce that. -/// -/// Generally, for smart pointers you will implement -/// `CoerceUnsized> for Ptr where T: Unsize, U: ?Sized`, with an -/// optional `?Sized` bound on `T` itself. For wrapper types that directly embed `T` -/// like `Cell` and `RefCell`, you -/// can directly implement `CoerceUnsized> for Wrap where T: CoerceUnsized`. -/// This will let coercions of types like `Cell>` work. -/// -/// [`Unsize`][unsize] is used to mark types which can be coerced to DSTs if behind -/// pointers. It is implemented automatically by the compiler. -/// -/// [dst-coerce]: https://github.com/rust-lang/rfcs/blob/master/text/0982-dst-coercion.md -/// [unsize]: ../marker/trait.Unsize.html -/// [nomicon-coerce]: ../../nomicon/coercions.html -#[unstable(feature = "coerce_unsized", issue = "27732")] -#[lang="coerce_unsized"] -pub trait CoerceUnsized { - // Empty. -} - -// &mut T -> &mut U -#[unstable(feature = "coerce_unsized", issue = "27732")] -impl<'a, T: ?Sized+Unsize, U: ?Sized> CoerceUnsized<&'a mut U> for &'a mut T {} -// &mut T -> &U -#[unstable(feature = "coerce_unsized", issue = "27732")] -impl<'a, 'b: 'a, T: ?Sized+Unsize, U: ?Sized> CoerceUnsized<&'a U> for &'b mut T {} -// &mut T -> *mut U -#[unstable(feature = "coerce_unsized", issue = "27732")] -impl<'a, T: ?Sized+Unsize, U: ?Sized> CoerceUnsized<*mut U> for &'a mut T {} -// &mut T -> *const U -#[unstable(feature = "coerce_unsized", issue = "27732")] -impl<'a, T: ?Sized+Unsize, U: ?Sized> CoerceUnsized<*const U> for &'a mut T {} - -// &T -> &U -#[unstable(feature = "coerce_unsized", issue = "27732")] -impl<'a, 'b: 'a, T: ?Sized+Unsize, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} -// &T -> *const U -#[unstable(feature = "coerce_unsized", issue = "27732")] -impl<'a, T: ?Sized+Unsize, U: ?Sized> CoerceUnsized<*const U> for &'a T {} - -// *mut T -> *mut U -#[unstable(feature = "coerce_unsized", issue = "27732")] -impl, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} -// *mut T -> *const U -#[unstable(feature = "coerce_unsized", issue = "27732")] -impl, U: ?Sized> CoerceUnsized<*const U> for *mut T {} - -// *const T -> *const U -#[unstable(feature = "coerce_unsized", issue = "27732")] -impl, U: ?Sized> CoerceUnsized<*const U> for *const T {} - -/// Both `PLACE <- EXPR` and `box EXPR` desugar into expressions -/// that allocate an intermediate "place" that holds uninitialized -/// state. The desugaring evaluates EXPR, and writes the result at -/// the address returned by the `pointer` method of this trait. -/// -/// A `Place` can be thought of as a special representation for a -/// hypothetical `&uninit` reference (which Rust cannot currently -/// express directly). That is, it represents a pointer to -/// uninitialized storage. -/// -/// The client is responsible for two steps: First, initializing the -/// payload (it can access its address via `pointer`). Second, -/// converting the agent to an instance of the owning pointer, via the -/// appropriate `finalize` method (see the `InPlace`. -/// -/// If evaluating EXPR fails, then it is up to the destructor for the -/// implementation of Place to clean up any intermediate state -/// (e.g. deallocate box storage, pop a stack, etc). -#[unstable(feature = "placement_new_protocol", issue = "27779")] -pub trait Place { - /// Returns the address where the input value will be written. - /// Note that the data at this address is generally uninitialized, - /// and thus one should use `ptr::write` for initializing it. - fn pointer(&mut self) -> *mut Data; -} - -/// Interface to implementations of `PLACE <- EXPR`. -/// -/// `PLACE <- EXPR` effectively desugars into: -/// -/// ```rust,ignore -/// let p = PLACE; -/// let mut place = Placer::make_place(p); -/// let raw_place = Place::pointer(&mut place); -/// let value = EXPR; -/// unsafe { -/// std::ptr::write(raw_place, value); -/// InPlace::finalize(place) -/// } -/// ``` -/// -/// The type of `PLACE <- EXPR` is derived from the type of `PLACE`; -/// if the type of `PLACE` is `P`, then the final type of the whole -/// expression is `P::Place::Owner` (see the `InPlace` and `Boxed` -/// traits). -/// -/// Values for types implementing this trait usually are transient -/// intermediate values (e.g. the return value of `Vec::emplace_back`) -/// or `Copy`, since the `make_place` method takes `self` by value. -#[unstable(feature = "placement_new_protocol", issue = "27779")] -pub trait Placer { - /// `Place` is the intermedate agent guarding the - /// uninitialized state for `Data`. - type Place: InPlace; - - /// Creates a fresh place from `self`. - fn make_place(self) -> Self::Place; -} - -/// Specialization of `Place` trait supporting `PLACE <- EXPR`. -#[unstable(feature = "placement_new_protocol", issue = "27779")] -pub trait InPlace: Place { - /// `Owner` is the type of the end value of `PLACE <- EXPR` - /// - /// Note that when `PLACE <- EXPR` is solely used for - /// side-effecting an existing data-structure, - /// e.g. `Vec::emplace_back`, then `Owner` need not carry any - /// information at all (e.g. it can be the unit type `()` in that - /// case). - type Owner; - - /// Converts self into the final value, shifting - /// deallocation/cleanup responsibilities (if any remain), over to - /// the returned instance of `Owner` and forgetting self. - unsafe fn finalize(self) -> Self::Owner; -} - -/// Core trait for the `box EXPR` form. -/// -/// `box EXPR` effectively desugars into: -/// -/// ```rust,ignore -/// let mut place = BoxPlace::make_place(); -/// let raw_place = Place::pointer(&mut place); -/// let value = EXPR; -/// unsafe { -/// ::std::ptr::write(raw_place, value); -/// Boxed::finalize(place) -/// } -/// ``` -/// -/// The type of `box EXPR` is supplied from its surrounding -/// context; in the above expansion, the result type `T` is used -/// to determine which implementation of `Boxed` to use, and that -/// `` in turn dictates determines which -/// implementation of `BoxPlace` to use, namely: -/// `<::Place as BoxPlace>`. -#[unstable(feature = "placement_new_protocol", issue = "27779")] -pub trait Boxed { - /// The kind of data that is stored in this kind of box. - type Data; /* (`Data` unused b/c cannot yet express below bound.) */ - /// The place that will negotiate the storage of the data. - type Place: BoxPlace; - - /// Converts filled place into final owning value, shifting - /// deallocation/cleanup responsibilities (if any remain), over to - /// returned instance of `Self` and forgetting `filled`. - unsafe fn finalize(filled: Self::Place) -> Self; -} - -/// Specialization of `Place` trait supporting `box EXPR`. -#[unstable(feature = "placement_new_protocol", issue = "27779")] -pub trait BoxPlace : Place { - /// Creates a globally fresh place. - fn make_place() -> Self; -} - -/// This trait has been superseded by the `Try` trait, but must remain -/// here as `?` is still lowered to it in stage0 . -#[cfg(stage0)] -#[unstable(feature = "question_mark_carrier", issue = "31436")] -pub trait Carrier { - /// The type of the value when computation succeeds. - type Success; - /// The type of the value when computation errors out. - type Error; - - /// Create a `Carrier` from a success value. - fn from_success(_: Self::Success) -> Self; - - /// Create a `Carrier` from an error value. - fn from_error(_: Self::Error) -> Self; - - /// Translate this `Carrier` to another implementation of `Carrier` with the - /// same associated types. - fn translate(self) -> T where T: Carrier; -} - -#[cfg(stage0)] -#[unstable(feature = "question_mark_carrier", issue = "31436")] -impl Carrier for Result { - type Success = U; - type Error = V; - - fn from_success(u: U) -> Result { - Ok(u) - } - - fn from_error(e: V) -> Result { - Err(e) - } - - fn translate(self) -> T - where T: Carrier - { - match self { - Ok(u) => T::from_success(u), - Err(e) => T::from_error(e), - } - } -} - -struct _DummyErrorType; - -impl Try for _DummyErrorType { - type Ok = (); - type Error = (); - - fn into_result(self) -> Result { - Ok(()) - } - - fn from_ok(_: ()) -> _DummyErrorType { - _DummyErrorType - } - - fn from_error(_: ()) -> _DummyErrorType { - _DummyErrorType - } -} - -/// A trait for customizing the behaviour of the `?` operator. -/// -/// A type implementing `Try` is one that has a canonical way to view it -/// in terms of a success/failure dichotomy. This trait allows both -/// extracting those success or failure values from an existing instance and -/// creating a new instance from a success or failure value. -#[unstable(feature = "try_trait", issue = "42327")] -pub trait Try { - /// The type of this value when viewed as successful. - #[unstable(feature = "try_trait", issue = "42327")] - type Ok; - /// The type of this value when viewed as failed. - #[unstable(feature = "try_trait", issue = "42327")] - type Error; - - /// Applies the "?" operator. A return of `Ok(t)` means that the - /// execution should continue normally, and the result of `?` is the - /// value `t`. A return of `Err(e)` means that execution should branch - /// to the innermost enclosing `catch`, or return from the function. - /// - /// If an `Err(e)` result is returned, the value `e` will be "wrapped" - /// in the return type of the enclosing scope (which must itself implement - /// `Try`). Specifically, the value `X::from_error(From::from(e))` - /// is returned, where `X` is the return type of the enclosing function. - #[unstable(feature = "try_trait", issue = "42327")] - fn into_result(self) -> Result; - - /// Wrap an error value to construct the composite result. For example, - /// `Result::Err(x)` and `Result::from_error(x)` are equivalent. - #[unstable(feature = "try_trait", issue = "42327")] - fn from_error(v: Self::Error) -> Self; - - /// Wrap an OK value to construct the composite result. For example, - /// `Result::Ok(x)` and `Result::from_ok(x)` are equivalent. - #[unstable(feature = "try_trait", issue = "42327")] - fn from_ok(v: Self::Ok) -> Self; -} diff --git a/src/libcore/ops/arith.rs b/src/libcore/ops/arith.rs new file mode 100644 index 000000000000..c6fb75f6acef --- /dev/null +++ b/src/libcore/ops/arith.rs @@ -0,0 +1,873 @@ +// 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. + +/// The addition operator `+`. +/// +/// # Examples +/// +/// This example creates a `Point` struct that implements the `Add` trait, and +/// then demonstrates adding two `Point`s. +/// +/// ``` +/// use std::ops::Add; +/// +/// #[derive(Debug)] +/// struct Point { +/// x: i32, +/// y: i32, +/// } +/// +/// impl Add for Point { +/// type Output = Point; +/// +/// fn add(self, other: Point) -> Point { +/// Point { +/// x: self.x + other.x, +/// y: self.y + other.y, +/// } +/// } +/// } +/// +/// impl PartialEq for Point { +/// fn eq(&self, other: &Self) -> bool { +/// self.x == other.x && self.y == other.y +/// } +/// } +/// +/// fn main() { +/// assert_eq!(Point { x: 1, y: 0 } + Point { x: 2, y: 3 }, +/// Point { x: 3, y: 3 }); +/// } +/// ``` +/// +/// Here is an example of the same `Point` struct implementing the `Add` trait +/// using generics. +/// +/// ``` +/// use std::ops::Add; +/// +/// #[derive(Debug)] +/// struct Point { +/// x: T, +/// y: T, +/// } +/// +/// // Notice that the implementation uses the `Output` associated type +/// impl> Add for Point { +/// type Output = Point; +/// +/// fn add(self, other: Point) -> Point { +/// Point { +/// x: self.x + other.x, +/// y: self.y + other.y, +/// } +/// } +/// } +/// +/// impl PartialEq for Point { +/// fn eq(&self, other: &Self) -> bool { +/// self.x == other.x && self.y == other.y +/// } +/// } +/// +/// fn main() { +/// assert_eq!(Point { x: 1, y: 0 } + Point { x: 2, y: 3 }, +/// Point { x: 3, y: 3 }); +/// } +/// ``` +/// +/// Note that `RHS = Self` by default, but this is not mandatory. For example, +/// [std::time::SystemTime] implements `Add`, which permits +/// operations of the form `SystemTime = SystemTime + Duration`. +/// +/// [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")] + type Output; + + /// The method for the `+` operator + #[stable(feature = "rust1", since = "1.0.0")] + fn add(self, rhs: RHS) -> Self::Output; +} + +macro_rules! add_impl { + ($($t:ty)*) => ($( + #[stable(feature = "rust1", since = "1.0.0")] + impl Add for $t { + type Output = $t; + + #[inline] + #[rustc_inherit_overflow_checks] + fn add(self, other: $t) -> $t { self + other } + } + + forward_ref_binop! { impl Add, add for $t, $t } + )*) +} + +add_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } + +/// The subtraction operator `-`. +/// +/// # Examples +/// +/// This example creates a `Point` struct that implements the `Sub` trait, and +/// then demonstrates subtracting two `Point`s. +/// +/// ``` +/// use std::ops::Sub; +/// +/// #[derive(Debug)] +/// struct Point { +/// x: i32, +/// y: i32, +/// } +/// +/// impl Sub for Point { +/// type Output = Point; +/// +/// fn sub(self, other: Point) -> Point { +/// Point { +/// x: self.x - other.x, +/// y: self.y - other.y, +/// } +/// } +/// } +/// +/// impl PartialEq for Point { +/// fn eq(&self, other: &Self) -> bool { +/// self.x == other.x && self.y == other.y +/// } +/// } +/// +/// fn main() { +/// assert_eq!(Point { x: 3, y: 3 } - Point { x: 2, y: 3 }, +/// Point { x: 1, y: 0 }); +/// } +/// ``` +/// +/// Note that `RHS = Self` by default, but this is not mandatory. For example, +/// [std::time::SystemTime] implements `Sub`, which permits +/// operations of the form `SystemTime = SystemTime - Duration`. +/// +/// [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")] + type Output; + + /// The method for the `-` operator + #[stable(feature = "rust1", since = "1.0.0")] + fn sub(self, rhs: RHS) -> Self::Output; +} + +macro_rules! sub_impl { + ($($t:ty)*) => ($( + #[stable(feature = "rust1", since = "1.0.0")] + impl Sub for $t { + type Output = $t; + + #[inline] + #[rustc_inherit_overflow_checks] + fn sub(self, other: $t) -> $t { self - other } + } + + forward_ref_binop! { impl Sub, sub for $t, $t } + )*) +} + +sub_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } + +/// The multiplication operator `*`. +/// +/// # Examples +/// +/// Implementing a `Mul`tipliable rational number struct: +/// +/// ``` +/// use std::ops::Mul; +/// +/// // The uniqueness of rational numbers in lowest terms is a consequence of +/// // the fundamental theorem of arithmetic. +/// #[derive(Eq)] +/// #[derive(PartialEq, Debug)] +/// struct Rational { +/// nominator: usize, +/// denominator: usize, +/// } +/// +/// impl Rational { +/// fn new(nominator: usize, denominator: usize) -> Self { +/// if denominator == 0 { +/// panic!("Zero is an invalid denominator!"); +/// } +/// +/// // Reduce to lowest terms by dividing by the greatest common +/// // divisor. +/// let gcd = gcd(nominator, denominator); +/// Rational { +/// nominator: nominator / gcd, +/// denominator: denominator / gcd, +/// } +/// } +/// } +/// +/// impl Mul for Rational { +/// // The multiplication of rational numbers is a closed operation. +/// type Output = Self; +/// +/// fn mul(self, rhs: Self) -> Self { +/// let nominator = self.nominator * rhs.nominator; +/// let denominator = self.denominator * rhs.denominator; +/// Rational::new(nominator, denominator) +/// } +/// } +/// +/// // Euclid's two-thousand-year-old algorithm for finding the greatest common +/// // divisor. +/// fn gcd(x: usize, y: usize) -> usize { +/// let mut x = x; +/// let mut y = y; +/// while y != 0 { +/// let t = y; +/// y = x % y; +/// x = t; +/// } +/// x +/// } +/// +/// assert_eq!(Rational::new(1, 2), Rational::new(2, 4)); +/// assert_eq!(Rational::new(2, 3) * Rational::new(3, 4), +/// Rational::new(1, 2)); +/// ``` +/// +/// Note that `RHS = Self` by default, but this is not mandatory. Here is an +/// implementation which enables multiplication of vectors by scalars, as is +/// done in linear algebra. +/// +/// ``` +/// use std::ops::Mul; +/// +/// struct Scalar {value: usize}; +/// +/// #[derive(Debug)] +/// struct Vector {value: Vec}; +/// +/// impl Mul for Scalar { +/// type Output = Vector; +/// +/// fn mul(self, rhs: Vector) -> Vector { +/// Vector {value: rhs.value.iter().map(|v| self.value * v).collect()} +/// } +/// } +/// +/// impl PartialEq for Vector { +/// fn eq(&self, other: &Self) -> bool { +/// self.value == other.value +/// } +/// } +/// +/// let scalar = Scalar{value: 3}; +/// let vector = Vector{value: vec![2, 4, 6]}; +/// assert_eq!(scalar * vector, Vector{value: vec![6, 12, 18]}); +/// ``` +#[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")] + type Output; + + /// The method for the `*` operator + #[stable(feature = "rust1", since = "1.0.0")] + fn mul(self, rhs: RHS) -> Self::Output; +} + +macro_rules! mul_impl { + ($($t:ty)*) => ($( + #[stable(feature = "rust1", since = "1.0.0")] + impl Mul for $t { + type Output = $t; + + #[inline] + #[rustc_inherit_overflow_checks] + fn mul(self, other: $t) -> $t { self * other } + } + + forward_ref_binop! { impl Mul, mul for $t, $t } + )*) +} + +mul_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } + +/// The division operator `/`. +/// +/// # Examples +/// +/// Implementing a `Div`idable rational number struct: +/// +/// ``` +/// use std::ops::Div; +/// +/// // The uniqueness of rational numbers in lowest terms is a consequence of +/// // the fundamental theorem of arithmetic. +/// #[derive(Eq)] +/// #[derive(PartialEq, Debug)] +/// struct Rational { +/// nominator: usize, +/// denominator: usize, +/// } +/// +/// impl Rational { +/// fn new(nominator: usize, denominator: usize) -> Self { +/// if denominator == 0 { +/// panic!("Zero is an invalid denominator!"); +/// } +/// +/// // Reduce to lowest terms by dividing by the greatest common +/// // divisor. +/// let gcd = gcd(nominator, denominator); +/// Rational { +/// nominator: nominator / gcd, +/// denominator: denominator / gcd, +/// } +/// } +/// } +/// +/// impl Div for Rational { +/// // The division of rational numbers is a closed operation. +/// type Output = Self; +/// +/// fn div(self, rhs: Self) -> Self { +/// if rhs.nominator == 0 { +/// panic!("Cannot divide by zero-valued `Rational`!"); +/// } +/// +/// let nominator = self.nominator * rhs.denominator; +/// let denominator = self.denominator * rhs.nominator; +/// Rational::new(nominator, denominator) +/// } +/// } +/// +/// // Euclid's two-thousand-year-old algorithm for finding the greatest common +/// // divisor. +/// fn gcd(x: usize, y: usize) -> usize { +/// let mut x = x; +/// let mut y = y; +/// while y != 0 { +/// let t = y; +/// y = x % y; +/// x = t; +/// } +/// x +/// } +/// +/// fn main() { +/// assert_eq!(Rational::new(1, 2), Rational::new(2, 4)); +/// assert_eq!(Rational::new(1, 2) / Rational::new(3, 4), +/// Rational::new(2, 3)); +/// } +/// ``` +/// +/// Note that `RHS = Self` by default, but this is not mandatory. Here is an +/// implementation which enables division of vectors by scalars, as is done in +/// linear algebra. +/// +/// ``` +/// use std::ops::Div; +/// +/// struct Scalar {value: f32}; +/// +/// #[derive(Debug)] +/// struct Vector {value: Vec}; +/// +/// impl Div for Vector { +/// type Output = Vector; +/// +/// fn div(self, rhs: Scalar) -> Vector { +/// Vector {value: self.value.iter().map(|v| v / rhs.value).collect()} +/// } +/// } +/// +/// impl PartialEq for Vector { +/// fn eq(&self, other: &Self) -> bool { +/// self.value == other.value +/// } +/// } +/// +/// let scalar = Scalar{value: 2f32}; +/// let vector = Vector{value: vec![2f32, 4f32, 6f32]}; +/// assert_eq!(vector / scalar, Vector{value: vec![1f32, 2f32, 3f32]}); +/// ``` +#[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")] + type Output; + + /// The method for the `/` operator + #[stable(feature = "rust1", since = "1.0.0")] + fn div(self, rhs: RHS) -> Self::Output; +} + +macro_rules! div_impl_integer { + ($($t:ty)*) => ($( + /// This operation rounds towards zero, truncating any + /// fractional part of the exact result. + #[stable(feature = "rust1", since = "1.0.0")] + impl Div for $t { + type Output = $t; + + #[inline] + fn div(self, other: $t) -> $t { self / other } + } + + forward_ref_binop! { impl Div, div for $t, $t } + )*) +} + +div_impl_integer! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } + +macro_rules! div_impl_float { + ($($t:ty)*) => ($( + #[stable(feature = "rust1", since = "1.0.0")] + impl Div for $t { + type Output = $t; + + #[inline] + fn div(self, other: $t) -> $t { self / other } + } + + forward_ref_binop! { impl Div, div for $t, $t } + )*) +} + +div_impl_float! { f32 f64 } + +/// The remainder operator `%`. +/// +/// # Examples +/// +/// This example implements `Rem` on a `SplitSlice` object. After `Rem` is +/// implemented, one can use the `%` operator to find out what the remaining +/// elements of the slice would be after splitting it into equal slices of a +/// given length. +/// +/// ``` +/// use std::ops::Rem; +/// +/// #[derive(PartialEq, Debug)] +/// struct SplitSlice<'a, T: 'a> { +/// slice: &'a [T], +/// } +/// +/// impl<'a, T> Rem for SplitSlice<'a, T> { +/// type Output = SplitSlice<'a, T>; +/// +/// fn rem(self, modulus: usize) -> Self { +/// let len = self.slice.len(); +/// let rem = len % modulus; +/// let start = len - rem; +/// SplitSlice {slice: &self.slice[start..]} +/// } +/// } +/// +/// // If we were to divide &[0, 1, 2, 3, 4, 5, 6, 7] into slices of size 3, +/// // the remainder would be &[6, 7] +/// assert_eq!(SplitSlice { slice: &[0, 1, 2, 3, 4, 5, 6, 7] } % 3, +/// SplitSlice { slice: &[6, 7] }); +/// ``` +#[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")] + type Output = Self; + + /// The method for the `%` operator + #[stable(feature = "rust1", since = "1.0.0")] + fn rem(self, rhs: RHS) -> Self::Output; +} + +macro_rules! rem_impl_integer { + ($($t:ty)*) => ($( + /// This operation satisfies `n % d == n - (n / d) * d`. The + /// result has the same sign as the left operand. + #[stable(feature = "rust1", since = "1.0.0")] + impl Rem for $t { + type Output = $t; + + #[inline] + fn rem(self, other: $t) -> $t { self % other } + } + + forward_ref_binop! { impl Rem, rem for $t, $t } + )*) +} + +rem_impl_integer! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } + + +macro_rules! rem_impl_float { + ($($t:ty)*) => ($( + #[stable(feature = "rust1", since = "1.0.0")] + impl Rem for $t { + type Output = $t; + + #[inline] + fn rem(self, other: $t) -> $t { self % other } + } + + forward_ref_binop! { impl Rem, rem for $t, $t } + )*) +} + +rem_impl_float! { f32 f64 } + +/// The unary negation operator `-`. +/// +/// # Examples +/// +/// An implementation of `Neg` for `Sign`, which allows the use of `-` to +/// negate its value. +/// +/// ``` +/// use std::ops::Neg; +/// +/// #[derive(Debug, PartialEq)] +/// enum Sign { +/// Negative, +/// Zero, +/// Positive, +/// } +/// +/// impl Neg for Sign { +/// type Output = Sign; +/// +/// fn neg(self) -> Sign { +/// match self { +/// Sign::Negative => Sign::Positive, +/// Sign::Zero => Sign::Zero, +/// Sign::Positive => Sign::Negative, +/// } +/// } +/// } +/// +/// // a negative positive is a negative +/// assert_eq!(-Sign::Positive, Sign::Negative); +/// // a double negative is a positive +/// assert_eq!(-Sign::Negative, Sign::Positive); +/// // zero is its own negation +/// assert_eq!(-Sign::Zero, Sign::Zero); +/// ``` +#[lang = "neg"] +#[stable(feature = "rust1", since = "1.0.0")] +pub trait Neg { + /// The resulting type after applying the `-` operator + #[stable(feature = "rust1", since = "1.0.0")] + type Output; + + /// The method for the unary `-` operator + #[stable(feature = "rust1", since = "1.0.0")] + fn neg(self) -> Self::Output; +} + + + +macro_rules! neg_impl_core { + ($id:ident => $body:expr, $($t:ty)*) => ($( + #[stable(feature = "rust1", since = "1.0.0")] + impl Neg for $t { + type Output = $t; + + #[inline] + #[rustc_inherit_overflow_checks] + fn neg(self) -> $t { let $id = self; $body } + } + + forward_ref_unop! { impl Neg, neg for $t } + )*) +} + +macro_rules! neg_impl_numeric { + ($($t:ty)*) => { neg_impl_core!{ x => -x, $($t)*} } +} + +#[allow(unused_macros)] +macro_rules! neg_impl_unsigned { + ($($t:ty)*) => { + neg_impl_core!{ x => { + !x.wrapping_add(1) + }, $($t)*} } +} + +// neg_impl_unsigned! { usize u8 u16 u32 u64 } +neg_impl_numeric! { isize i8 i16 i32 i64 i128 f32 f64 } + +/// The addition assignment operator `+=`. +/// +/// # Examples +/// +/// This example creates a `Point` struct that implements the `AddAssign` +/// trait, and then demonstrates add-assigning to a mutable `Point`. +/// +/// ``` +/// use std::ops::AddAssign; +/// +/// #[derive(Debug)] +/// struct Point { +/// x: i32, +/// y: i32, +/// } +/// +/// impl AddAssign for Point { +/// fn add_assign(&mut self, other: Point) { +/// *self = Point { +/// x: self.x + other.x, +/// y: self.y + other.y, +/// }; +/// } +/// } +/// +/// impl PartialEq for Point { +/// fn eq(&self, other: &Self) -> bool { +/// self.x == other.x && self.y == other.y +/// } +/// } +/// +/// let mut point = Point { x: 1, y: 0 }; +/// point += Point { x: 2, y: 3 }; +/// assert_eq!(point, Point { x: 3, y: 3 }); +/// ``` +#[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")] + fn add_assign(&mut self, rhs: Rhs); +} + +macro_rules! add_assign_impl { + ($($t:ty)+) => ($( + #[stable(feature = "op_assign_traits", since = "1.8.0")] + impl AddAssign for $t { + #[inline] + #[rustc_inherit_overflow_checks] + fn add_assign(&mut self, other: $t) { *self += other } + } + )+) +} + +add_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } + +/// The subtraction assignment operator `-=`. +/// +/// # Examples +/// +/// This example creates a `Point` struct that implements the `SubAssign` +/// trait, and then demonstrates sub-assigning to a mutable `Point`. +/// +/// ``` +/// use std::ops::SubAssign; +/// +/// #[derive(Debug)] +/// struct Point { +/// x: i32, +/// y: i32, +/// } +/// +/// impl SubAssign for Point { +/// fn sub_assign(&mut self, other: Point) { +/// *self = Point { +/// x: self.x - other.x, +/// y: self.y - other.y, +/// }; +/// } +/// } +/// +/// impl PartialEq for Point { +/// fn eq(&self, other: &Self) -> bool { +/// self.x == other.x && self.y == other.y +/// } +/// } +/// +/// let mut point = Point { x: 3, y: 3 }; +/// point -= Point { x: 2, y: 3 }; +/// assert_eq!(point, Point {x: 1, y: 0}); +/// ``` +#[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")] + fn sub_assign(&mut self, rhs: Rhs); +} + +macro_rules! sub_assign_impl { + ($($t:ty)+) => ($( + #[stable(feature = "op_assign_traits", since = "1.8.0")] + impl SubAssign for $t { + #[inline] + #[rustc_inherit_overflow_checks] + fn sub_assign(&mut self, other: $t) { *self -= other } + } + )+) +} + +sub_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } + +/// The multiplication assignment operator `*=`. +/// +/// # Examples +/// +/// A trivial implementation of `MulAssign`. When `Foo *= Foo` happens, it ends up +/// calling `mul_assign`, and therefore, `main` prints `Multiplying!`. +/// +/// ``` +/// use std::ops::MulAssign; +/// +/// struct Foo; +/// +/// impl MulAssign for Foo { +/// fn mul_assign(&mut self, _rhs: Foo) { +/// println!("Multiplying!"); +/// } +/// } +/// +/// # #[allow(unused_assignments)] +/// fn main() { +/// let mut foo = Foo; +/// foo *= Foo; +/// } +/// ``` +#[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")] + fn mul_assign(&mut self, rhs: Rhs); +} + +macro_rules! mul_assign_impl { + ($($t:ty)+) => ($( + #[stable(feature = "op_assign_traits", since = "1.8.0")] + impl MulAssign for $t { + #[inline] + #[rustc_inherit_overflow_checks] + fn mul_assign(&mut self, other: $t) { *self *= other } + } + )+) +} + +mul_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } + +/// The division assignment operator `/=`. +/// +/// # Examples +/// +/// A trivial implementation of `DivAssign`. When `Foo /= Foo` happens, it ends up +/// calling `div_assign`, and therefore, `main` prints `Dividing!`. +/// +/// ``` +/// use std::ops::DivAssign; +/// +/// struct Foo; +/// +/// impl DivAssign for Foo { +/// fn div_assign(&mut self, _rhs: Foo) { +/// println!("Dividing!"); +/// } +/// } +/// +/// # #[allow(unused_assignments)] +/// fn main() { +/// let mut foo = Foo; +/// foo /= Foo; +/// } +/// ``` +#[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")] + fn div_assign(&mut self, rhs: Rhs); +} + +macro_rules! div_assign_impl { + ($($t:ty)+) => ($( + #[stable(feature = "op_assign_traits", since = "1.8.0")] + impl DivAssign for $t { + #[inline] + fn div_assign(&mut self, other: $t) { *self /= other } + } + )+) +} + +div_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } + +/// The remainder assignment operator `%=`. +/// +/// # Examples +/// +/// A trivial implementation of `RemAssign`. When `Foo %= Foo` happens, it ends up +/// calling `rem_assign`, and therefore, `main` prints `Remainder-ing!`. +/// +/// ``` +/// use std::ops::RemAssign; +/// +/// struct Foo; +/// +/// impl RemAssign for Foo { +/// fn rem_assign(&mut self, _rhs: Foo) { +/// println!("Remainder-ing!"); +/// } +/// } +/// +/// # #[allow(unused_assignments)] +/// fn main() { +/// let mut foo = Foo; +/// foo %= Foo; +/// } +/// ``` +#[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")] + fn rem_assign(&mut self, rhs: Rhs); +} + +macro_rules! rem_assign_impl { + ($($t:ty)+) => ($( + #[stable(feature = "op_assign_traits", since = "1.8.0")] + impl RemAssign for $t { + #[inline] + fn rem_assign(&mut self, other: $t) { *self %= other } + } + )+) +} + +rem_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } diff --git a/src/libcore/ops/bit.rs b/src/libcore/ops/bit.rs new file mode 100644 index 000000000000..8743be3557cc --- /dev/null +++ b/src/libcore/ops/bit.rs @@ -0,0 +1,839 @@ +// 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. + +/// The unary logical negation operator `!`. +/// +/// # Examples +/// +/// An implementation of `Not` for `Answer`, which enables the use of `!` to +/// invert its value. +/// +/// ``` +/// use std::ops::Not; +/// +/// #[derive(Debug, PartialEq)] +/// enum Answer { +/// Yes, +/// No, +/// } +/// +/// impl Not for Answer { +/// type Output = Answer; +/// +/// fn not(self) -> Answer { +/// match self { +/// Answer::Yes => Answer::No, +/// Answer::No => Answer::Yes +/// } +/// } +/// } +/// +/// assert_eq!(!Answer::Yes, Answer::No); +/// assert_eq!(!Answer::No, Answer::Yes); +/// ``` +#[lang = "not"] +#[stable(feature = "rust1", since = "1.0.0")] +pub trait Not { + /// The resulting type after applying the `!` operator + #[stable(feature = "rust1", since = "1.0.0")] + type Output; + + /// The method for the unary `!` operator + #[stable(feature = "rust1", since = "1.0.0")] + fn not(self) -> Self::Output; +} + +macro_rules! not_impl { + ($($t:ty)*) => ($( + #[stable(feature = "rust1", since = "1.0.0")] + impl Not for $t { + type Output = $t; + + #[inline] + fn not(self) -> $t { !self } + } + + forward_ref_unop! { impl Not, not for $t } + )*) +} + +not_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } + +/// The bitwise AND operator `&`. +/// +/// # Examples +/// +/// In this example, the `&` operator is lifted to a trivial `Scalar` type. +/// +/// ``` +/// use std::ops::BitAnd; +/// +/// #[derive(Debug, PartialEq)] +/// struct Scalar(bool); +/// +/// impl BitAnd for Scalar { +/// type Output = Self; +/// +/// // rhs is the "right-hand side" of the expression `a & b` +/// fn bitand(self, rhs: Self) -> Self { +/// Scalar(self.0 & rhs.0) +/// } +/// } +/// +/// fn main() { +/// assert_eq!(Scalar(true) & Scalar(true), Scalar(true)); +/// assert_eq!(Scalar(true) & Scalar(false), Scalar(false)); +/// assert_eq!(Scalar(false) & Scalar(true), Scalar(false)); +/// assert_eq!(Scalar(false) & Scalar(false), Scalar(false)); +/// } +/// ``` +/// +/// In this example, the `BitAnd` trait is implemented for a `BooleanVector` +/// struct. +/// +/// ``` +/// use std::ops::BitAnd; +/// +/// #[derive(Debug, PartialEq)] +/// struct BooleanVector(Vec); +/// +/// impl BitAnd for BooleanVector { +/// type Output = Self; +/// +/// fn bitand(self, BooleanVector(rhs): Self) -> Self { +/// let BooleanVector(lhs) = self; +/// assert_eq!(lhs.len(), rhs.len()); +/// BooleanVector(lhs.iter().zip(rhs.iter()).map(|(x, y)| *x && *y).collect()) +/// } +/// } +/// +/// fn main() { +/// let bv1 = BooleanVector(vec![true, true, false, false]); +/// let bv2 = BooleanVector(vec![true, false, true, false]); +/// let expected = BooleanVector(vec![true, false, false, false]); +/// assert_eq!(bv1 & bv2, expected); +/// } +/// ``` +#[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")] + type Output; + + /// The method for the `&` operator + #[stable(feature = "rust1", since = "1.0.0")] + fn bitand(self, rhs: RHS) -> Self::Output; +} + +macro_rules! bitand_impl { + ($($t:ty)*) => ($( + #[stable(feature = "rust1", since = "1.0.0")] + impl BitAnd for $t { + type Output = $t; + + #[inline] + fn bitand(self, rhs: $t) -> $t { self & rhs } + } + + forward_ref_binop! { impl BitAnd, bitand for $t, $t } + )*) +} + +bitand_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } + +/// The bitwise OR operator `|`. +/// +/// # Examples +/// +/// In this example, the `|` operator is lifted to a trivial `Scalar` type. +/// +/// ``` +/// use std::ops::BitOr; +/// +/// #[derive(Debug, PartialEq)] +/// struct Scalar(bool); +/// +/// impl BitOr for Scalar { +/// type Output = Self; +/// +/// // rhs is the "right-hand side" of the expression `a | b` +/// fn bitor(self, rhs: Self) -> Self { +/// Scalar(self.0 | rhs.0) +/// } +/// } +/// +/// fn main() { +/// assert_eq!(Scalar(true) | Scalar(true), Scalar(true)); +/// assert_eq!(Scalar(true) | Scalar(false), Scalar(true)); +/// assert_eq!(Scalar(false) | Scalar(true), Scalar(true)); +/// assert_eq!(Scalar(false) | Scalar(false), Scalar(false)); +/// } +/// ``` +/// +/// In this example, the `BitOr` trait is implemented for a `BooleanVector` +/// struct. +/// +/// ``` +/// use std::ops::BitOr; +/// +/// #[derive(Debug, PartialEq)] +/// struct BooleanVector(Vec); +/// +/// impl BitOr for BooleanVector { +/// type Output = Self; +/// +/// fn bitor(self, BooleanVector(rhs): Self) -> Self { +/// let BooleanVector(lhs) = self; +/// assert_eq!(lhs.len(), rhs.len()); +/// BooleanVector(lhs.iter().zip(rhs.iter()).map(|(x, y)| *x || *y).collect()) +/// } +/// } +/// +/// fn main() { +/// let bv1 = BooleanVector(vec![true, true, false, false]); +/// let bv2 = BooleanVector(vec![true, false, true, false]); +/// let expected = BooleanVector(vec![true, true, true, false]); +/// assert_eq!(bv1 | bv2, expected); +/// } +/// ``` +#[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")] + type Output; + + /// The method for the `|` operator + #[stable(feature = "rust1", since = "1.0.0")] + fn bitor(self, rhs: RHS) -> Self::Output; +} + +macro_rules! bitor_impl { + ($($t:ty)*) => ($( + #[stable(feature = "rust1", since = "1.0.0")] + impl BitOr for $t { + type Output = $t; + + #[inline] + fn bitor(self, rhs: $t) -> $t { self | rhs } + } + + forward_ref_binop! { impl BitOr, bitor for $t, $t } + )*) +} + +bitor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } + +/// The bitwise XOR operator `^`. +/// +/// # Examples +/// +/// In this example, the `^` operator is lifted to a trivial `Scalar` type. +/// +/// ``` +/// use std::ops::BitXor; +/// +/// #[derive(Debug, PartialEq)] +/// struct Scalar(bool); +/// +/// impl BitXor for Scalar { +/// type Output = Self; +/// +/// // rhs is the "right-hand side" of the expression `a ^ b` +/// fn bitxor(self, rhs: Self) -> Self { +/// Scalar(self.0 ^ rhs.0) +/// } +/// } +/// +/// fn main() { +/// assert_eq!(Scalar(true) ^ Scalar(true), Scalar(false)); +/// assert_eq!(Scalar(true) ^ Scalar(false), Scalar(true)); +/// assert_eq!(Scalar(false) ^ Scalar(true), Scalar(true)); +/// assert_eq!(Scalar(false) ^ Scalar(false), Scalar(false)); +/// } +/// ``` +/// +/// In this example, the `BitXor` trait is implemented for a `BooleanVector` +/// struct. +/// +/// ``` +/// use std::ops::BitXor; +/// +/// #[derive(Debug, PartialEq)] +/// struct BooleanVector(Vec); +/// +/// impl BitXor for BooleanVector { +/// type Output = Self; +/// +/// fn bitxor(self, BooleanVector(rhs): Self) -> Self { +/// let BooleanVector(lhs) = self; +/// assert_eq!(lhs.len(), rhs.len()); +/// BooleanVector(lhs.iter() +/// .zip(rhs.iter()) +/// .map(|(x, y)| (*x || *y) && !(*x && *y)) +/// .collect()) +/// } +/// } +/// +/// fn main() { +/// let bv1 = BooleanVector(vec![true, true, false, false]); +/// let bv2 = BooleanVector(vec![true, false, true, false]); +/// let expected = BooleanVector(vec![false, true, true, false]); +/// assert_eq!(bv1 ^ bv2, expected); +/// } +/// ``` +#[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")] + type Output; + + /// The method for the `^` operator + #[stable(feature = "rust1", since = "1.0.0")] + fn bitxor(self, rhs: RHS) -> Self::Output; +} + +macro_rules! bitxor_impl { + ($($t:ty)*) => ($( + #[stable(feature = "rust1", since = "1.0.0")] + impl BitXor for $t { + type Output = $t; + + #[inline] + fn bitxor(self, other: $t) -> $t { self ^ other } + } + + forward_ref_binop! { impl BitXor, bitxor for $t, $t } + )*) +} + +bitxor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } + +/// The left shift operator `<<`. +/// +/// # Examples +/// +/// An implementation of `Shl` that lifts the `<<` operation on integers to a +/// `Scalar` struct. +/// +/// ``` +/// use std::ops::Shl; +/// +/// #[derive(PartialEq, Debug)] +/// struct Scalar(usize); +/// +/// impl Shl for Scalar { +/// type Output = Self; +/// +/// fn shl(self, Scalar(rhs): Self) -> Scalar { +/// let Scalar(lhs) = self; +/// Scalar(lhs << rhs) +/// } +/// } +/// fn main() { +/// assert_eq!(Scalar(4) << Scalar(2), Scalar(16)); +/// } +/// ``` +/// +/// An implementation of `Shl` that spins a vector leftward by a given amount. +/// +/// ``` +/// use std::ops::Shl; +/// +/// #[derive(PartialEq, Debug)] +/// struct SpinVector { +/// vec: Vec, +/// } +/// +/// impl Shl for SpinVector { +/// type Output = Self; +/// +/// fn shl(self, rhs: usize) -> SpinVector { +/// // rotate the vector by `rhs` places +/// let (a, b) = self.vec.split_at(rhs); +/// let mut spun_vector: Vec = vec![]; +/// spun_vector.extend_from_slice(b); +/// spun_vector.extend_from_slice(a); +/// SpinVector { vec: spun_vector } +/// } +/// } +/// +/// fn main() { +/// assert_eq!(SpinVector { vec: vec![0, 1, 2, 3, 4] } << 2, +/// SpinVector { vec: vec![2, 3, 4, 0, 1] }); +/// } +/// ``` +#[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")] + type Output; + + /// The method for the `<<` operator + #[stable(feature = "rust1", since = "1.0.0")] + fn shl(self, rhs: RHS) -> Self::Output; +} + +macro_rules! shl_impl { + ($t:ty, $f:ty) => ( + #[stable(feature = "rust1", since = "1.0.0")] + impl Shl<$f> for $t { + type Output = $t; + + #[inline] + #[rustc_inherit_overflow_checks] + fn shl(self, other: $f) -> $t { + self << other + } + } + + forward_ref_binop! { impl Shl, shl for $t, $f } + ) +} + +macro_rules! shl_impl_all { + ($($t:ty)*) => ($( + shl_impl! { $t, u8 } + shl_impl! { $t, u16 } + shl_impl! { $t, u32 } + shl_impl! { $t, u64 } + shl_impl! { $t, u128 } + shl_impl! { $t, usize } + + shl_impl! { $t, i8 } + shl_impl! { $t, i16 } + shl_impl! { $t, i32 } + shl_impl! { $t, i64 } + shl_impl! { $t, i128 } + shl_impl! { $t, isize } + )*) +} + +shl_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 isize i128 } + +/// The right shift operator `>>`. +/// +/// # Examples +/// +/// An implementation of `Shr` that lifts the `>>` operation on integers to a +/// `Scalar` struct. +/// +/// ``` +/// use std::ops::Shr; +/// +/// #[derive(PartialEq, Debug)] +/// struct Scalar(usize); +/// +/// impl Shr for Scalar { +/// type Output = Self; +/// +/// fn shr(self, Scalar(rhs): Self) -> Scalar { +/// let Scalar(lhs) = self; +/// Scalar(lhs >> rhs) +/// } +/// } +/// fn main() { +/// assert_eq!(Scalar(16) >> Scalar(2), Scalar(4)); +/// } +/// ``` +/// +/// An implementation of `Shr` that spins a vector rightward by a given amount. +/// +/// ``` +/// use std::ops::Shr; +/// +/// #[derive(PartialEq, Debug)] +/// struct SpinVector { +/// vec: Vec, +/// } +/// +/// impl Shr for SpinVector { +/// type Output = Self; +/// +/// fn shr(self, rhs: usize) -> SpinVector { +/// // rotate the vector by `rhs` places +/// let (a, b) = self.vec.split_at(self.vec.len() - rhs); +/// let mut spun_vector: Vec = vec![]; +/// spun_vector.extend_from_slice(b); +/// spun_vector.extend_from_slice(a); +/// SpinVector { vec: spun_vector } +/// } +/// } +/// +/// fn main() { +/// assert_eq!(SpinVector { vec: vec![0, 1, 2, 3, 4] } >> 2, +/// SpinVector { vec: vec![3, 4, 0, 1, 2] }); +/// } +/// ``` +#[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")] + type Output; + + /// The method for the `>>` operator + #[stable(feature = "rust1", since = "1.0.0")] + fn shr(self, rhs: RHS) -> Self::Output; +} + +macro_rules! shr_impl { + ($t:ty, $f:ty) => ( + #[stable(feature = "rust1", since = "1.0.0")] + impl Shr<$f> for $t { + type Output = $t; + + #[inline] + #[rustc_inherit_overflow_checks] + fn shr(self, other: $f) -> $t { + self >> other + } + } + + forward_ref_binop! { impl Shr, shr for $t, $f } + ) +} + +macro_rules! shr_impl_all { + ($($t:ty)*) => ($( + shr_impl! { $t, u8 } + shr_impl! { $t, u16 } + shr_impl! { $t, u32 } + shr_impl! { $t, u64 } + shr_impl! { $t, u128 } + shr_impl! { $t, usize } + + shr_impl! { $t, i8 } + shr_impl! { $t, i16 } + shr_impl! { $t, i32 } + shr_impl! { $t, i64 } + shr_impl! { $t, i128 } + shr_impl! { $t, isize } + )*) +} + +shr_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize } + +/// The bitwise AND assignment operator `&=`. +/// +/// # Examples +/// +/// In this example, the `&=` operator is lifted to a trivial `Scalar` type. +/// +/// ``` +/// use std::ops::BitAndAssign; +/// +/// #[derive(Debug, PartialEq)] +/// struct Scalar(bool); +/// +/// impl BitAndAssign for Scalar { +/// // rhs is the "right-hand side" of the expression `a &= b` +/// fn bitand_assign(&mut self, rhs: Self) { +/// *self = Scalar(self.0 & rhs.0) +/// } +/// } +/// +/// fn main() { +/// let mut scalar = Scalar(true); +/// scalar &= Scalar(true); +/// assert_eq!(scalar, Scalar(true)); +/// +/// let mut scalar = Scalar(true); +/// scalar &= Scalar(false); +/// assert_eq!(scalar, Scalar(false)); +/// +/// let mut scalar = Scalar(false); +/// scalar &= Scalar(true); +/// assert_eq!(scalar, Scalar(false)); +/// +/// let mut scalar = Scalar(false); +/// scalar &= Scalar(false); +/// assert_eq!(scalar, Scalar(false)); +/// } +/// ``` +/// +/// In this example, the `BitAndAssign` trait is implemented for a +/// `BooleanVector` struct. +/// +/// ``` +/// use std::ops::BitAndAssign; +/// +/// #[derive(Debug, PartialEq)] +/// struct BooleanVector(Vec); +/// +/// impl BitAndAssign for BooleanVector { +/// // rhs is the "right-hand side" of the expression `a &= b` +/// fn bitand_assign(&mut self, rhs: Self) { +/// assert_eq!(self.0.len(), rhs.0.len()); +/// *self = BooleanVector(self.0 +/// .iter() +/// .zip(rhs.0.iter()) +/// .map(|(x, y)| *x && *y) +/// .collect()); +/// } +/// } +/// +/// fn main() { +/// let mut bv = BooleanVector(vec![true, true, false, false]); +/// bv &= BooleanVector(vec![true, false, true, false]); +/// let expected = BooleanVector(vec![true, false, false, false]); +/// assert_eq!(bv, expected); +/// } +/// ``` +#[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")] + fn bitand_assign(&mut self, rhs: Rhs); +} + +macro_rules! bitand_assign_impl { + ($($t:ty)+) => ($( + #[stable(feature = "op_assign_traits", since = "1.8.0")] + impl BitAndAssign for $t { + #[inline] + fn bitand_assign(&mut self, other: $t) { *self &= other } + } + )+) +} + +bitand_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } + +/// The bitwise OR assignment operator `|=`. +/// +/// # Examples +/// +/// A trivial implementation of `BitOrAssign`. When `Foo |= Foo` happens, it ends up +/// calling `bitor_assign`, and therefore, `main` prints `Bitwise Or-ing!`. +/// +/// ``` +/// use std::ops::BitOrAssign; +/// +/// struct Foo; +/// +/// impl BitOrAssign for Foo { +/// fn bitor_assign(&mut self, _rhs: Foo) { +/// println!("Bitwise Or-ing!"); +/// } +/// } +/// +/// # #[allow(unused_assignments)] +/// fn main() { +/// let mut foo = Foo; +/// foo |= Foo; +/// } +/// ``` +#[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")] + fn bitor_assign(&mut self, rhs: Rhs); +} + +macro_rules! bitor_assign_impl { + ($($t:ty)+) => ($( + #[stable(feature = "op_assign_traits", since = "1.8.0")] + impl BitOrAssign for $t { + #[inline] + fn bitor_assign(&mut self, other: $t) { *self |= other } + } + )+) +} + +bitor_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } + +/// The bitwise XOR assignment operator `^=`. +/// +/// # Examples +/// +/// A trivial implementation of `BitXorAssign`. When `Foo ^= Foo` happens, it ends up +/// calling `bitxor_assign`, and therefore, `main` prints `Bitwise Xor-ing!`. +/// +/// ``` +/// use std::ops::BitXorAssign; +/// +/// struct Foo; +/// +/// impl BitXorAssign for Foo { +/// fn bitxor_assign(&mut self, _rhs: Foo) { +/// println!("Bitwise Xor-ing!"); +/// } +/// } +/// +/// # #[allow(unused_assignments)] +/// fn main() { +/// let mut foo = Foo; +/// foo ^= Foo; +/// } +/// ``` +#[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")] + fn bitxor_assign(&mut self, rhs: Rhs); +} + +macro_rules! bitxor_assign_impl { + ($($t:ty)+) => ($( + #[stable(feature = "op_assign_traits", since = "1.8.0")] + impl BitXorAssign for $t { + #[inline] + fn bitxor_assign(&mut self, other: $t) { *self ^= other } + } + )+) +} + +bitxor_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } + +/// The left shift assignment operator `<<=`. +/// +/// # Examples +/// +/// A trivial implementation of `ShlAssign`. When `Foo <<= Foo` happens, it ends up +/// calling `shl_assign`, and therefore, `main` prints `Shifting left!`. +/// +/// ``` +/// use std::ops::ShlAssign; +/// +/// struct Foo; +/// +/// impl ShlAssign for Foo { +/// fn shl_assign(&mut self, _rhs: Foo) { +/// println!("Shifting left!"); +/// } +/// } +/// +/// # #[allow(unused_assignments)] +/// fn main() { +/// let mut foo = Foo; +/// foo <<= Foo; +/// } +/// ``` +#[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")] + fn shl_assign(&mut self, rhs: Rhs); +} + +macro_rules! shl_assign_impl { + ($t:ty, $f:ty) => ( + #[stable(feature = "op_assign_traits", since = "1.8.0")] + impl ShlAssign<$f> for $t { + #[inline] + #[rustc_inherit_overflow_checks] + fn shl_assign(&mut self, other: $f) { + *self <<= other + } + } + ) +} + +macro_rules! shl_assign_impl_all { + ($($t:ty)*) => ($( + shl_assign_impl! { $t, u8 } + shl_assign_impl! { $t, u16 } + shl_assign_impl! { $t, u32 } + shl_assign_impl! { $t, u64 } + shl_assign_impl! { $t, u128 } + shl_assign_impl! { $t, usize } + + shl_assign_impl! { $t, i8 } + shl_assign_impl! { $t, i16 } + shl_assign_impl! { $t, i32 } + shl_assign_impl! { $t, i64 } + shl_assign_impl! { $t, i128 } + shl_assign_impl! { $t, isize } + )*) +} + +shl_assign_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize } + +/// The right shift assignment operator `>>=`. +/// +/// # Examples +/// +/// A trivial implementation of `ShrAssign`. When `Foo >>= Foo` happens, it ends up +/// calling `shr_assign`, and therefore, `main` prints `Shifting right!`. +/// +/// ``` +/// use std::ops::ShrAssign; +/// +/// struct Foo; +/// +/// impl ShrAssign for Foo { +/// fn shr_assign(&mut self, _rhs: Foo) { +/// println!("Shifting right!"); +/// } +/// } +/// +/// # #[allow(unused_assignments)] +/// fn main() { +/// let mut foo = Foo; +/// foo >>= Foo; +/// } +/// ``` +#[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")] + fn shr_assign(&mut self, rhs: Rhs); +} + +macro_rules! shr_assign_impl { + ($t:ty, $f:ty) => ( + #[stable(feature = "op_assign_traits", since = "1.8.0")] + impl ShrAssign<$f> for $t { + #[inline] + #[rustc_inherit_overflow_checks] + fn shr_assign(&mut self, other: $f) { + *self >>= other + } + } + ) +} + +macro_rules! shr_assign_impl_all { + ($($t:ty)*) => ($( + shr_assign_impl! { $t, u8 } + shr_assign_impl! { $t, u16 } + shr_assign_impl! { $t, u32 } + shr_assign_impl! { $t, u64 } + shr_assign_impl! { $t, u128 } + shr_assign_impl! { $t, usize } + + shr_assign_impl! { $t, i8 } + shr_assign_impl! { $t, i16 } + shr_assign_impl! { $t, i32 } + shr_assign_impl! { $t, i64 } + shr_assign_impl! { $t, i128 } + shr_assign_impl! { $t, isize } + )*) +} + +shr_assign_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize } diff --git a/src/libcore/ops/deref.rs b/src/libcore/ops/deref.rs new file mode 100644 index 000000000000..18cf20ac411d --- /dev/null +++ b/src/libcore/ops/deref.rs @@ -0,0 +1,119 @@ +// 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. + +/// The `Deref` trait is used to specify the functionality of dereferencing +/// operations, like `*v`. +/// +/// `Deref` also enables ['`Deref` coercions'][coercions]. +/// +/// [coercions]: ../../book/first-edition/deref-coercions.html +/// +/// # Examples +/// +/// A struct with a single field which is accessible via dereferencing the +/// struct. +/// +/// ``` +/// use std::ops::Deref; +/// +/// struct DerefExample { +/// value: T +/// } +/// +/// impl Deref for DerefExample { +/// type Target = T; +/// +/// fn deref(&self) -> &T { +/// &self.value +/// } +/// } +/// +/// fn main() { +/// let x = DerefExample { value: 'a' }; +/// assert_eq!('a', *x); +/// } +/// ``` +#[lang = "deref"] +#[stable(feature = "rust1", since = "1.0.0")] +pub trait Deref { + /// The resulting type after dereferencing + #[stable(feature = "rust1", since = "1.0.0")] + type Target: ?Sized; + + /// The method called to dereference a value + #[stable(feature = "rust1", since = "1.0.0")] + fn deref(&self) -> &Self::Target; +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T: ?Sized> Deref for &'a T { + type Target = T; + + fn deref(&self) -> &T { *self } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T: ?Sized> Deref for &'a mut T { + type Target = T; + + fn deref(&self) -> &T { *self } +} + +/// The `DerefMut` trait is used to specify the functionality of dereferencing +/// mutably like `*v = 1;` +/// +/// `DerefMut` also enables ['`Deref` coercions'][coercions]. +/// +/// [coercions]: ../../book/first-edition/deref-coercions.html +/// +/// # Examples +/// +/// A struct with a single field which is modifiable via dereferencing the +/// struct. +/// +/// ``` +/// use std::ops::{Deref, DerefMut}; +/// +/// struct DerefMutExample { +/// value: T +/// } +/// +/// impl Deref for DerefMutExample { +/// type Target = T; +/// +/// fn deref(&self) -> &T { +/// &self.value +/// } +/// } +/// +/// impl DerefMut for DerefMutExample { +/// fn deref_mut(&mut self) -> &mut T { +/// &mut self.value +/// } +/// } +/// +/// fn main() { +/// let mut x = DerefMutExample { value: 'a' }; +/// *x = 'b'; +/// assert_eq!('b', *x); +/// } +/// ``` +#[lang = "deref_mut"] +#[stable(feature = "rust1", since = "1.0.0")] +pub trait DerefMut: Deref { + /// The method called to mutably dereference a value + #[stable(feature = "rust1", since = "1.0.0")] + fn deref_mut(&mut self) -> &mut Self::Target; +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T: ?Sized> DerefMut for &'a mut T { + fn deref_mut(&mut self) -> &mut T { *self } +} diff --git a/src/libcore/ops/drop.rs b/src/libcore/ops/drop.rs new file mode 100644 index 000000000000..92f3cb256c83 --- /dev/null +++ b/src/libcore/ops/drop.rs @@ -0,0 +1,99 @@ +// 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. + +/// The `Drop` trait is used to run some code when a value goes out of scope. +/// This is sometimes called a 'destructor'. +/// +/// When a value goes out of scope, if it implements this trait, it will have +/// its `drop` method called. Then any fields the value contains will also +/// be dropped recursively. +/// +/// Because of the recursive dropping, you do not need to implement this trait +/// unless your type needs its own destructor logic. +/// +/// # Examples +/// +/// A trivial implementation of `Drop`. The `drop` method is called when `_x` +/// goes out of scope, and therefore `main` prints `Dropping!`. +/// +/// ``` +/// struct HasDrop; +/// +/// impl Drop for HasDrop { +/// fn drop(&mut self) { +/// println!("Dropping!"); +/// } +/// } +/// +/// fn main() { +/// let _x = HasDrop; +/// } +/// ``` +/// +/// Showing the recursive nature of `Drop`. When `outer` goes out of scope, the +/// `drop` method will be called first for `Outer`, then for `Inner`. Therefore +/// `main` prints `Dropping Outer!` and then `Dropping Inner!`. +/// +/// ``` +/// struct Inner; +/// struct Outer(Inner); +/// +/// impl Drop for Inner { +/// fn drop(&mut self) { +/// println!("Dropping Inner!"); +/// } +/// } +/// +/// impl Drop for Outer { +/// fn drop(&mut self) { +/// println!("Dropping Outer!"); +/// } +/// } +/// +/// fn main() { +/// let _x = Outer(Inner); +/// } +/// ``` +/// +/// Because variables are dropped in the reverse order they are declared, +/// `main` will print `Declared second!` and then `Declared first!`. +/// +/// ``` +/// struct PrintOnDrop(&'static str); +/// +/// fn main() { +/// let _first = PrintOnDrop("Declared first!"); +/// let _second = PrintOnDrop("Declared second!"); +/// } +/// ``` +#[lang = "drop"] +#[stable(feature = "rust1", since = "1.0.0")] +pub trait Drop { + /// A method called when the value goes out of scope. + /// + /// When this method has been called, `self` has not yet been deallocated. + /// If it were, `self` would be a dangling reference. + /// + /// After this function is over, the memory of `self` will be deallocated. + /// + /// This function cannot be called explicitly. This is compiler error + /// [E0040]. However, the [`std::mem::drop`] function in the prelude can be + /// used to call the argument's `Drop` implementation. + /// + /// [E0040]: ../../error-index.html#E0040 + /// [`std::mem::drop`]: ../../std/mem/fn.drop.html + /// + /// # Panics + /// + /// Given that a `panic!` will call `drop()` as it unwinds, any `panic!` in + /// a `drop()` implementation will likely abort. + #[stable(feature = "rust1", since = "1.0.0")] + fn drop(&mut self); +} diff --git a/src/libcore/ops/function.rs b/src/libcore/ops/function.rs new file mode 100644 index 000000000000..62bf69336a39 --- /dev/null +++ b/src/libcore/ops/function.rs @@ -0,0 +1,194 @@ +// 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 version of the call operator that takes an immutable receiver. +/// +/// # Examples +/// +/// Closures automatically implement this trait, which allows them to be +/// invoked. Note, however, that `Fn` takes an immutable reference to any +/// captured variables. To take a mutable capture, implement [`FnMut`], and to +/// consume the capture, implement [`FnOnce`]. +/// +/// [`FnMut`]: trait.FnMut.html +/// [`FnOnce`]: trait.FnOnce.html +/// +/// ``` +/// let square = |x| x * x; +/// assert_eq!(square(5), 25); +/// ``` +/// +/// Closures can also be passed to higher-level functions through a `Fn` +/// parameter (or a `FnMut` or `FnOnce` parameter, which are supertraits of +/// `Fn`). +/// +/// ``` +/// fn call_with_one(func: F) -> usize +/// where F: Fn(usize) -> usize { +/// func(1) +/// } +/// +/// let double = |x| x * 2; +/// assert_eq!(call_with_one(double), 2); +/// ``` +#[lang = "fn"] +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_paren_sugar] +#[fundamental] // so that regex can rely that `&str: !FnMut` +pub trait Fn : FnMut { + /// This is called when the call operator is used. + #[unstable(feature = "fn_traits", issue = "29625")] + extern "rust-call" fn call(&self, args: Args) -> Self::Output; +} + +/// A version of the call operator that takes a mutable receiver. +/// +/// # Examples +/// +/// Closures that mutably capture variables automatically implement this trait, +/// which allows them to be invoked. +/// +/// ``` +/// let mut x = 5; +/// { +/// let mut square_x = || x *= x; +/// square_x(); +/// } +/// assert_eq!(x, 25); +/// ``` +/// +/// Closures can also be passed to higher-level functions through a `FnMut` +/// parameter (or a `FnOnce` parameter, which is a supertrait of `FnMut`). +/// +/// ``` +/// fn do_twice(mut func: F) +/// where F: FnMut() +/// { +/// func(); +/// func(); +/// } +/// +/// let mut x: usize = 1; +/// { +/// let add_two_to_x = || x += 2; +/// do_twice(add_two_to_x); +/// } +/// +/// assert_eq!(x, 5); +/// ``` +#[lang = "fn_mut"] +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_paren_sugar] +#[fundamental] // so that regex can rely that `&str: !FnMut` +pub trait FnMut : FnOnce { + /// This is called when the call operator is used. + #[unstable(feature = "fn_traits", issue = "29625")] + extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output; +} + +/// A version of the call operator that takes a by-value receiver. +/// +/// # Examples +/// +/// By-value closures automatically implement this trait, which allows them to +/// be invoked. +/// +/// ``` +/// let x = 5; +/// let square_x = move || x * x; +/// assert_eq!(square_x(), 25); +/// ``` +/// +/// By-value Closures can also be passed to higher-level functions through a +/// `FnOnce` parameter. +/// +/// ``` +/// fn consume_with_relish(func: F) +/// where F: FnOnce() -> String +/// { +/// // `func` consumes its captured variables, so it cannot be run more +/// // than once +/// println!("Consumed: {}", func()); +/// +/// println!("Delicious!"); +/// +/// // Attempting to invoke `func()` again will throw a `use of moved +/// // value` error for `func` +/// } +/// +/// let x = String::from("x"); +/// let consume_and_return_x = move || x; +/// consume_with_relish(consume_and_return_x); +/// +/// // `consume_and_return_x` can no longer be invoked at this point +/// ``` +#[lang = "fn_once"] +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_paren_sugar] +#[fundamental] // so that regex can rely that `&str: !FnMut` +pub trait FnOnce { + /// The returned type after the call operator is used. + #[stable(feature = "fn_once_output", since = "1.12.0")] + type Output; + + /// This is called when the call operator is used. + #[unstable(feature = "fn_traits", issue = "29625")] + extern "rust-call" fn call_once(self, args: Args) -> Self::Output; +} + +mod impls { + #[stable(feature = "rust1", since = "1.0.0")] + impl<'a,A,F:?Sized> Fn for &'a F + where F : Fn + { + extern "rust-call" fn call(&self, args: A) -> F::Output { + (**self).call(args) + } + } + + #[stable(feature = "rust1", since = "1.0.0")] + impl<'a,A,F:?Sized> FnMut for &'a F + where F : Fn + { + extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output { + (**self).call(args) + } + } + + #[stable(feature = "rust1", since = "1.0.0")] + impl<'a,A,F:?Sized> FnOnce for &'a F + where F : Fn + { + type Output = F::Output; + + extern "rust-call" fn call_once(self, args: A) -> F::Output { + (*self).call(args) + } + } + + #[stable(feature = "rust1", since = "1.0.0")] + impl<'a,A,F:?Sized> FnMut for &'a mut F + where F : FnMut + { + extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output { + (*self).call_mut(args) + } + } + + #[stable(feature = "rust1", since = "1.0.0")] + impl<'a,A,F:?Sized> FnOnce for &'a mut F + where F : FnMut + { + type Output = F::Output; + extern "rust-call" fn call_once(mut self, args: A) -> F::Output { + (*self).call_mut(args) + } + } +} diff --git a/src/libcore/ops/index.rs b/src/libcore/ops/index.rs new file mode 100644 index 000000000000..b16b95677874 --- /dev/null +++ b/src/libcore/ops/index.rs @@ -0,0 +1,158 @@ +// 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. + +/// The `Index` trait is used to specify the functionality of indexing operations +/// like `container[index]` when used in an immutable context. +/// +/// `container[index]` is actually syntactic sugar for `*container.index(index)`, +/// but only when used as an immutable value. If a mutable value is requested, +/// [`IndexMut`] is used instead. This allows nice things such as +/// `let value = v[index]` if `value` implements [`Copy`]. +/// +/// [`IndexMut`]: ../../std/ops/trait.IndexMut.html +/// [`Copy`]: ../../std/marker/trait.Copy.html +/// +/// # Examples +/// +/// The following example implements `Index` on a read-only `NucleotideCount` +/// container, enabling individual counts to be retrieved with index syntax. +/// +/// ``` +/// use std::ops::Index; +/// +/// enum Nucleotide { +/// A, +/// C, +/// G, +/// T, +/// } +/// +/// struct NucleotideCount { +/// a: usize, +/// c: usize, +/// g: usize, +/// t: usize, +/// } +/// +/// impl Index for NucleotideCount { +/// type Output = usize; +/// +/// fn index(&self, nucleotide: Nucleotide) -> &usize { +/// match nucleotide { +/// Nucleotide::A => &self.a, +/// Nucleotide::C => &self.c, +/// Nucleotide::G => &self.g, +/// Nucleotide::T => &self.t, +/// } +/// } +/// } +/// +/// let nucleotide_count = NucleotideCount {a: 14, c: 9, g: 10, t: 12}; +/// assert_eq!(nucleotide_count[Nucleotide::A], 14); +/// assert_eq!(nucleotide_count[Nucleotide::C], 9); +/// assert_eq!(nucleotide_count[Nucleotide::G], 10); +/// assert_eq!(nucleotide_count[Nucleotide::T], 12); +/// ``` +#[lang = "index"] +#[rustc_on_unimplemented = "the type `{Self}` cannot be indexed by `{Idx}`"] +#[stable(feature = "rust1", since = "1.0.0")] +pub trait Index { + /// The returned type after indexing + #[stable(feature = "rust1", since = "1.0.0")] + type Output: ?Sized; + + /// The method for the indexing (`container[index]`) operation + #[stable(feature = "rust1", since = "1.0.0")] + fn index(&self, index: Idx) -> &Self::Output; +} + +/// The `IndexMut` trait is used to specify the functionality of indexing +/// operations like `container[index]` when used in a mutable context. +/// +/// `container[index]` is actually syntactic sugar for +/// `*container.index_mut(index)`, but only when used as a mutable value. If +/// an immutable value is requested, the [`Index`] trait is used instead. This +/// allows nice things such as `v[index] = value` if `value` implements [`Copy`]. +/// +/// [`Index`]: ../../std/ops/trait.Index.html +/// [`Copy`]: ../../std/marker/trait.Copy.html +/// +/// # Examples +/// +/// A very simple implementation of a `Balance` struct that has two sides, where +/// each can be indexed mutably and immutably. +/// +/// ``` +/// use std::ops::{Index,IndexMut}; +/// +/// #[derive(Debug)] +/// enum Side { +/// Left, +/// Right, +/// } +/// +/// #[derive(Debug, PartialEq)] +/// enum Weight { +/// Kilogram(f32), +/// Pound(f32), +/// } +/// +/// struct Balance { +/// pub left: Weight, +/// pub right:Weight, +/// } +/// +/// impl Index for Balance { +/// type Output = Weight; +/// +/// fn index<'a>(&'a self, index: Side) -> &'a Weight { +/// println!("Accessing {:?}-side of balance immutably", index); +/// match index { +/// Side::Left => &self.left, +/// Side::Right => &self.right, +/// } +/// } +/// } +/// +/// impl IndexMut for Balance { +/// fn index_mut<'a>(&'a mut self, index: Side) -> &'a mut Weight { +/// println!("Accessing {:?}-side of balance mutably", index); +/// match index { +/// Side::Left => &mut self.left, +/// Side::Right => &mut self.right, +/// } +/// } +/// } +/// +/// fn main() { +/// let mut balance = Balance { +/// right: Weight::Kilogram(2.5), +/// left: Weight::Pound(1.5), +/// }; +/// +/// // In this case balance[Side::Right] is sugar for +/// // *balance.index(Side::Right), since we are only reading +/// // balance[Side::Right], not writing it. +/// assert_eq!(balance[Side::Right],Weight::Kilogram(2.5)); +/// +/// // However in this case balance[Side::Left] is sugar for +/// // *balance.index_mut(Side::Left), since we are writing +/// // balance[Side::Left]. +/// balance[Side::Left] = Weight::Kilogram(3.0); +/// } +/// ``` +#[lang = "index_mut"] +#[rustc_on_unimplemented = "the type `{Self}` cannot be mutably indexed by `{Idx}`"] +#[stable(feature = "rust1", since = "1.0.0")] +pub trait IndexMut: Index { + /// The method for the mutable indexing (`container[index]`) operation + #[stable(feature = "rust1", since = "1.0.0")] + fn index_mut(&mut self, index: Idx) -> &mut Self::Output; +} diff --git a/src/libcore/ops/mod.rs b/src/libcore/ops/mod.rs new file mode 100644 index 000000000000..4e0389e5de4e --- /dev/null +++ b/src/libcore/ops/mod.rs @@ -0,0 +1,199 @@ +// 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. + +//! Overloadable operators. +//! +//! Implementing these traits allows you to overload certain operators. +//! +//! Some of these traits are imported by the prelude, so they are available in +//! every Rust program. Only operators backed by traits can be overloaded. For +//! example, the addition operator (`+`) can be overloaded through the [`Add`] +//! trait, but since the assignment operator (`=`) has no backing trait, there +//! is no way of overloading its semantics. Additionally, this module does not +//! provide any mechanism to create new operators. If traitless overloading or +//! custom operators are required, you should look toward macros or compiler +//! plugins to extend Rust's syntax. +//! +//! Note that the `&&` and `||` operators short-circuit, i.e. they only +//! evaluate their second operand if it contributes to the result. Since this +//! behavior is not enforceable by traits, `&&` and `||` are not supported as +//! overloadable operators. +//! +//! Many of the operators take their operands by value. In non-generic +//! contexts involving built-in types, this is usually not a problem. +//! However, using these operators in generic code, requires some +//! attention if values have to be reused as opposed to letting the operators +//! consume them. One option is to occasionally use [`clone`]. +//! Another option is to rely on the types involved providing additional +//! operator implementations for references. For example, for a user-defined +//! type `T` which is supposed to support addition, it is probably a good +//! idea to have both `T` and `&T` implement the traits [`Add`][`Add`] and +//! [`Add<&T>`][`Add`] so that generic code can be written without unnecessary +//! cloning. +//! +//! # Examples +//! +//! This example creates a `Point` struct that implements [`Add`] and [`Sub`], +//! and then demonstrates adding and subtracting two `Point`s. +//! +//! ```rust +//! use std::ops::{Add, Sub}; +//! +//! #[derive(Debug)] +//! struct Point { +//! x: i32, +//! y: i32, +//! } +//! +//! impl Add for Point { +//! type Output = Point; +//! +//! fn add(self, other: Point) -> Point { +//! Point {x: self.x + other.x, y: self.y + other.y} +//! } +//! } +//! +//! impl Sub for Point { +//! type Output = Point; +//! +//! fn sub(self, other: Point) -> Point { +//! Point {x: self.x - other.x, y: self.y - other.y} +//! } +//! } +//! fn main() { +//! println!("{:?}", Point {x: 1, y: 0} + Point {x: 2, y: 3}); +//! println!("{:?}", Point {x: 1, y: 0} - Point {x: 2, y: 3}); +//! } +//! ``` +//! +//! See the documentation for each trait for an example implementation. +//! +//! The [`Fn`], [`FnMut`], and [`FnOnce`] traits are implemented by types that can be +//! invoked like functions. Note that [`Fn`] takes `&self`, [`FnMut`] takes `&mut +//! self` and [`FnOnce`] takes `self`. These correspond to the three kinds of +//! methods that can be invoked on an instance: call-by-reference, +//! call-by-mutable-reference, and call-by-value. The most common use of these +//! traits is to act as bounds to higher-level functions that take functions or +//! closures as arguments. +//! +//! Taking a [`Fn`] as a parameter: +//! +//! ```rust +//! fn call_with_one(func: F) -> usize +//! where F: Fn(usize) -> usize +//! { +//! func(1) +//! } +//! +//! let double = |x| x * 2; +//! assert_eq!(call_with_one(double), 2); +//! ``` +//! +//! Taking a [`FnMut`] as a parameter: +//! +//! ```rust +//! fn do_twice(mut func: F) +//! where F: FnMut() +//! { +//! func(); +//! func(); +//! } +//! +//! let mut x: usize = 1; +//! { +//! let add_two_to_x = || x += 2; +//! do_twice(add_two_to_x); +//! } +//! +//! assert_eq!(x, 5); +//! ``` +//! +//! Taking a [`FnOnce`] as a parameter: +//! +//! ```rust +//! fn consume_with_relish(func: F) +//! where F: FnOnce() -> String +//! { +//! // `func` consumes its captured variables, so it cannot be run more +//! // than once +//! println!("Consumed: {}", func()); +//! +//! println!("Delicious!"); +//! +//! // Attempting to invoke `func()` again will throw a `use of moved +//! // value` error for `func` +//! } +//! +//! let x = String::from("x"); +//! let consume_and_return_x = move || x; +//! consume_with_relish(consume_and_return_x); +//! +//! // `consume_and_return_x` can no longer be invoked at this point +//! ``` +//! +//! [`Fn`]: trait.Fn.html +//! [`FnMut`]: trait.FnMut.html +//! [`FnOnce`]: trait.FnOnce.html +//! [`Add`]: trait.Add.html +//! [`Sub`]: trait.Sub.html +//! [`clone`]: ../clone/trait.Clone.html#tymethod.clone + +#![stable(feature = "rust1", since = "1.0.0")] + +mod arith; +mod bit; +mod deref; +mod drop; +mod function; +mod index; +mod place; +mod range; +mod try; +mod unsize; + +#[stable(feature = "rust1", since = "1.0.0")] +pub use self::arith::{Add, Sub, Mul, Div, Rem, Neg}; +#[stable(feature = "op_assign_traits", since = "1.8.0")] +pub use self::arith::{AddAssign, SubAssign, MulAssign, DivAssign, RemAssign}; + +#[stable(feature = "rust1", since = "1.0.0")] +pub use self::bit::{Not, BitAnd, BitOr, BitXor, Shl, Shr}; +#[stable(feature = "op_assign_traits", since = "1.8.0")] +pub use self::bit::{BitAndAssign, BitOrAssign, BitXorAssign, ShlAssign, ShrAssign}; + +#[stable(feature = "rust1", since = "1.0.0")] +pub use self::deref::{Deref, DerefMut}; + +#[stable(feature = "rust1", since = "1.0.0")] +pub use self::drop::Drop; + +#[stable(feature = "rust1", since = "1.0.0")] +pub use self::function::{Fn, FnMut, FnOnce}; + +#[stable(feature = "rust1", since = "1.0.0")] +pub use self::index::{Index, IndexMut}; + +#[stable(feature = "rust1", since = "1.0.0")] +pub use self::range::{Range, RangeFrom, RangeFull, RangeTo}; + +#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +pub use self::range::{RangeInclusive, RangeToInclusive}; + +#[unstable(feature = "question_mark_carrier", issue = "31436")] +#[cfg(stage0)] +pub use self::try::Carrier; +#[unstable(feature = "try_trait", issue = "42327")] +pub use self::try::Try; + +#[unstable(feature = "placement_new_protocol", issue = "27779")] +pub use self::place::{Place, Placer, InPlace, Boxed, BoxPlace}; + +#[unstable(feature = "coerce_unsized", issue = "27732")] +pub use self::unsize::CoerceUnsized; diff --git a/src/libcore/ops/place.rs b/src/libcore/ops/place.rs new file mode 100644 index 000000000000..996a741c96f9 --- /dev/null +++ b/src/libcore/ops/place.rs @@ -0,0 +1,126 @@ +// 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. + +/// Both `PLACE <- EXPR` and `box EXPR` desugar into expressions +/// that allocate an intermediate "place" that holds uninitialized +/// state. The desugaring evaluates EXPR, and writes the result at +/// the address returned by the `pointer` method of this trait. +/// +/// A `Place` can be thought of as a special representation for a +/// hypothetical `&uninit` reference (which Rust cannot currently +/// express directly). That is, it represents a pointer to +/// uninitialized storage. +/// +/// The client is responsible for two steps: First, initializing the +/// payload (it can access its address via `pointer`). Second, +/// converting the agent to an instance of the owning pointer, via the +/// appropriate `finalize` method (see the `InPlace`. +/// +/// If evaluating EXPR fails, then it is up to the destructor for the +/// implementation of Place to clean up any intermediate state +/// (e.g. deallocate box storage, pop a stack, etc). +#[unstable(feature = "placement_new_protocol", issue = "27779")] +pub trait Place { + /// Returns the address where the input value will be written. + /// Note that the data at this address is generally uninitialized, + /// and thus one should use `ptr::write` for initializing it. + fn pointer(&mut self) -> *mut Data; +} + +/// Interface to implementations of `PLACE <- EXPR`. +/// +/// `PLACE <- EXPR` effectively desugars into: +/// +/// ```rust,ignore +/// let p = PLACE; +/// let mut place = Placer::make_place(p); +/// let raw_place = Place::pointer(&mut place); +/// let value = EXPR; +/// unsafe { +/// std::ptr::write(raw_place, value); +/// InPlace::finalize(place) +/// } +/// ``` +/// +/// The type of `PLACE <- EXPR` is derived from the type of `PLACE`; +/// if the type of `PLACE` is `P`, then the final type of the whole +/// expression is `P::Place::Owner` (see the `InPlace` and `Boxed` +/// traits). +/// +/// Values for types implementing this trait usually are transient +/// intermediate values (e.g. the return value of `Vec::emplace_back`) +/// or `Copy`, since the `make_place` method takes `self` by value. +#[unstable(feature = "placement_new_protocol", issue = "27779")] +pub trait Placer { + /// `Place` is the intermedate agent guarding the + /// uninitialized state for `Data`. + type Place: InPlace; + + /// Creates a fresh place from `self`. + fn make_place(self) -> Self::Place; +} + +/// Specialization of `Place` trait supporting `PLACE <- EXPR`. +#[unstable(feature = "placement_new_protocol", issue = "27779")] +pub trait InPlace: Place { + /// `Owner` is the type of the end value of `PLACE <- EXPR` + /// + /// Note that when `PLACE <- EXPR` is solely used for + /// side-effecting an existing data-structure, + /// e.g. `Vec::emplace_back`, then `Owner` need not carry any + /// information at all (e.g. it can be the unit type `()` in that + /// case). + type Owner; + + /// Converts self into the final value, shifting + /// deallocation/cleanup responsibilities (if any remain), over to + /// the returned instance of `Owner` and forgetting self. + unsafe fn finalize(self) -> Self::Owner; +} + +/// Core trait for the `box EXPR` form. +/// +/// `box EXPR` effectively desugars into: +/// +/// ```rust,ignore +/// let mut place = BoxPlace::make_place(); +/// let raw_place = Place::pointer(&mut place); +/// let value = EXPR; +/// unsafe { +/// ::std::ptr::write(raw_place, value); +/// Boxed::finalize(place) +/// } +/// ``` +/// +/// The type of `box EXPR` is supplied from its surrounding +/// context; in the above expansion, the result type `T` is used +/// to determine which implementation of `Boxed` to use, and that +/// `` in turn dictates determines which +/// implementation of `BoxPlace` to use, namely: +/// `<::Place as BoxPlace>`. +#[unstable(feature = "placement_new_protocol", issue = "27779")] +pub trait Boxed { + /// The kind of data that is stored in this kind of box. + type Data; /* (`Data` unused b/c cannot yet express below bound.) */ + /// The place that will negotiate the storage of the data. + type Place: BoxPlace; + + /// Converts filled place into final owning value, shifting + /// deallocation/cleanup responsibilities (if any remain), over to + /// returned instance of `Self` and forgetting `filled`. + unsafe fn finalize(filled: Self::Place) -> Self; +} + +/// Specialization of `Place` trait supporting `box EXPR`. +#[unstable(feature = "placement_new_protocol", issue = "27779")] +pub trait BoxPlace : Place { + /// Creates a globally fresh place. + fn make_place() -> Self; +} diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs new file mode 100644 index 000000000000..70c35df87dda --- /dev/null +++ b/src/libcore/ops/range.rs @@ -0,0 +1,366 @@ +// 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. + +use fmt; + +/// An unbounded range. Use `..` (two dots) for its shorthand. +/// +/// Its primary use case is slicing index. It cannot serve as an iterator +/// because it doesn't have a starting point. +/// +/// # Examples +/// +/// The `..` syntax is a `RangeFull`: +/// +/// ``` +/// assert_eq!((..), std::ops::RangeFull); +/// ``` +/// +/// It does not have an `IntoIterator` implementation, so you can't use it in a +/// `for` loop directly. This won't compile: +/// +/// ```ignore +/// for i in .. { +/// // ... +/// } +/// ``` +/// +/// Used as a slicing index, `RangeFull` produces the full array as a slice. +/// +/// ``` +/// let arr = [0, 1, 2, 3]; +/// assert_eq!(arr[ .. ], [0,1,2,3]); // RangeFull +/// assert_eq!(arr[ ..3], [0,1,2 ]); +/// assert_eq!(arr[1.. ], [ 1,2,3]); +/// assert_eq!(arr[1..3], [ 1,2 ]); +/// ``` +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct RangeFull; + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Debug for RangeFull { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "..") + } +} + +/// A (half-open) range which is bounded at both ends: { x | start <= x < end }. +/// Use `start..end` (two dots) for its shorthand. +/// +/// See the [`contains`](#method.contains) method for its characterization. +/// +/// # Examples +/// +/// ``` +/// fn main() { +/// assert_eq!((3..5), std::ops::Range{ start: 3, end: 5 }); +/// assert_eq!(3+4+5, (3..6).sum()); +/// +/// let arr = [0, 1, 2, 3]; +/// assert_eq!(arr[ .. ], [0,1,2,3]); +/// assert_eq!(arr[ ..3], [0,1,2 ]); +/// assert_eq!(arr[1.. ], [ 1,2,3]); +/// assert_eq!(arr[1..3], [ 1,2 ]); // Range +/// } +/// ``` +#[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186 +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Range { + /// The lower bound of the range (inclusive). + #[stable(feature = "rust1", since = "1.0.0")] + pub start: Idx, + /// The upper bound of the range (exclusive). + #[stable(feature = "rust1", since = "1.0.0")] + pub end: Idx, +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Debug for Range { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "{:?}..{:?}", self.start, self.end) + } +} + +#[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] +impl> Range { + /// # Examples + /// + /// ``` + /// #![feature(range_contains)] + /// fn main() { + /// assert!( ! (3..5).contains(2)); + /// assert!( (3..5).contains(3)); + /// assert!( (3..5).contains(4)); + /// assert!( ! (3..5).contains(5)); + /// + /// assert!( ! (3..3).contains(3)); + /// assert!( ! (3..2).contains(3)); + /// } + /// ``` + pub fn contains(&self, item: Idx) -> bool { + (self.start <= item) && (item < self.end) + } +} + +/// A range which is only bounded below: { x | start <= x }. +/// Use `start..` for its shorthand. +/// +/// See the [`contains`](#method.contains) method for its characterization. +/// +/// Note: Currently, no overflow checking is done for the iterator +/// implementation; if you use an integer range and the integer overflows, it +/// might panic in debug mode or create an endless loop in release mode. This +/// overflow behavior might change in the future. +/// +/// # Examples +/// +/// ``` +/// fn main() { +/// assert_eq!((2..), std::ops::RangeFrom{ start: 2 }); +/// assert_eq!(2+3+4, (2..).take(3).sum()); +/// +/// let arr = [0, 1, 2, 3]; +/// assert_eq!(arr[ .. ], [0,1,2,3]); +/// assert_eq!(arr[ ..3], [0,1,2 ]); +/// assert_eq!(arr[1.. ], [ 1,2,3]); // RangeFrom +/// assert_eq!(arr[1..3], [ 1,2 ]); +/// } +/// ``` +#[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186 +#[stable(feature = "rust1", since = "1.0.0")] +pub struct RangeFrom { + /// The lower bound of the range (inclusive). + #[stable(feature = "rust1", since = "1.0.0")] + pub start: Idx, +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Debug for RangeFrom { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "{:?}..", self.start) + } +} + +#[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] +impl> RangeFrom { + /// # Examples + /// + /// ``` + /// #![feature(range_contains)] + /// fn main() { + /// assert!( ! (3..).contains(2)); + /// assert!( (3..).contains(3)); + /// assert!( (3..).contains(1_000_000_000)); + /// } + /// ``` + pub fn contains(&self, item: Idx) -> bool { + (self.start <= item) + } +} + +/// A range which is only bounded above: { x | x < end }. +/// Use `..end` (two dots) for its shorthand. +/// +/// See the [`contains`](#method.contains) method for its characterization. +/// +/// It cannot serve as an iterator because it doesn't have a starting point. +/// +/// # Examples +/// +/// The `..{integer}` syntax is a `RangeTo`: +/// +/// ``` +/// assert_eq!((..5), std::ops::RangeTo{ end: 5 }); +/// ``` +/// +/// It does not have an `IntoIterator` implementation, so you can't use it in a +/// `for` loop directly. This won't compile: +/// +/// ```ignore +/// for i in ..5 { +/// // ... +/// } +/// ``` +/// +/// When used as a slicing index, `RangeTo` produces a slice of all array +/// elements before the index indicated by `end`. +/// +/// ``` +/// let arr = [0, 1, 2, 3]; +/// assert_eq!(arr[ .. ], [0,1,2,3]); +/// assert_eq!(arr[ ..3], [0,1,2 ]); // RangeTo +/// assert_eq!(arr[1.. ], [ 1,2,3]); +/// assert_eq!(arr[1..3], [ 1,2 ]); +/// ``` +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct RangeTo { + /// The upper bound of the range (exclusive). + #[stable(feature = "rust1", since = "1.0.0")] + pub end: Idx, +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Debug for RangeTo { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "..{:?}", self.end) + } +} + +#[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] +impl> RangeTo { + /// # Examples + /// + /// ``` + /// #![feature(range_contains)] + /// fn main() { + /// assert!( (..5).contains(-1_000_000_000)); + /// assert!( (..5).contains(4)); + /// assert!( ! (..5).contains(5)); + /// } + /// ``` + pub fn contains(&self, item: Idx) -> bool { + (item < self.end) + } +} + +/// An inclusive range which is bounded at both ends: { x | start <= x <= end }. +/// Use `start...end` (three dots) for its shorthand. +/// +/// See the [`contains`](#method.contains) method for its characterization. +/// +/// # Examples +/// +/// ``` +/// #![feature(inclusive_range,inclusive_range_syntax)] +/// fn main() { +/// assert_eq!((3...5), std::ops::RangeInclusive{ start: 3, end: 5 }); +/// assert_eq!(3+4+5, (3...5).sum()); +/// +/// let arr = [0, 1, 2, 3]; +/// assert_eq!(arr[ ...2], [0,1,2 ]); +/// assert_eq!(arr[1...2], [ 1,2 ]); // RangeInclusive +/// } +/// ``` +#[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186 +#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +pub struct RangeInclusive { + /// The lower bound of the range (inclusive). + #[unstable(feature = "inclusive_range", + reason = "recently added, follows RFC", + issue = "28237")] + pub start: Idx, + /// The upper bound of the range (inclusive). + #[unstable(feature = "inclusive_range", + reason = "recently added, follows RFC", + issue = "28237")] + pub end: Idx, +} + +#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +impl fmt::Debug for RangeInclusive { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "{:?}...{:?}", self.start, self.end) + } +} + +#[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] +impl> RangeInclusive { + /// # Examples + /// + /// ``` + /// #![feature(range_contains,inclusive_range_syntax)] + /// fn main() { + /// assert!( ! (3...5).contains(2)); + /// assert!( (3...5).contains(3)); + /// assert!( (3...5).contains(4)); + /// assert!( (3...5).contains(5)); + /// assert!( ! (3...5).contains(6)); + /// + /// assert!( (3...3).contains(3)); + /// assert!( ! (3...2).contains(3)); + /// } + /// ``` + pub fn contains(&self, item: Idx) -> bool { + self.start <= item && item <= self.end + } +} + +/// An inclusive range which is only bounded above: { x | x <= end }. +/// Use `...end` (three dots) for its shorthand. +/// +/// See the [`contains`](#method.contains) method for its characterization. +/// +/// It cannot serve as an iterator because it doesn't have a starting point. +/// +/// # Examples +/// +/// The `...{integer}` syntax is a `RangeToInclusive`: +/// +/// ``` +/// #![feature(inclusive_range,inclusive_range_syntax)] +/// assert_eq!((...5), std::ops::RangeToInclusive{ end: 5 }); +/// ``` +/// +/// It does not have an `IntoIterator` implementation, so you can't use it in a +/// `for` loop directly. This won't compile: +/// +/// ```ignore +/// for i in ...5 { +/// // ... +/// } +/// ``` +/// +/// When used as a slicing index, `RangeToInclusive` produces a slice of all +/// array elements up to and including the index indicated by `end`. +/// +/// ``` +/// #![feature(inclusive_range_syntax)] +/// let arr = [0, 1, 2, 3]; +/// assert_eq!(arr[ ...2], [0,1,2 ]); // RangeToInclusive +/// assert_eq!(arr[1...2], [ 1,2 ]); +/// ``` +#[derive(Copy, Clone, PartialEq, Eq, Hash)] +#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +pub struct RangeToInclusive { + /// The upper bound of the range (inclusive) + #[unstable(feature = "inclusive_range", + reason = "recently added, follows RFC", + issue = "28237")] + pub end: Idx, +} + +#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")] +impl fmt::Debug for RangeToInclusive { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "...{:?}", self.end) + } +} + +#[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")] +impl> RangeToInclusive { + /// # Examples + /// + /// ``` + /// #![feature(range_contains,inclusive_range_syntax)] + /// fn main() { + /// assert!( (...5).contains(-1_000_000_000)); + /// assert!( (...5).contains(5)); + /// assert!( ! (...5).contains(6)); + /// } + /// ``` + pub fn contains(&self, item: Idx) -> bool { + (item <= self.end) + } +} + +// RangeToInclusive cannot impl From> +// because underflow would be possible with (..0).into() diff --git a/src/libcore/ops/try.rs b/src/libcore/ops/try.rs new file mode 100644 index 000000000000..cf75cf79fae6 --- /dev/null +++ b/src/libcore/ops/try.rs @@ -0,0 +1,111 @@ +// 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. + +/// This trait has been superseded by the `Try` trait, but must remain +/// here as `?` is still lowered to it in stage0 . +#[cfg(stage0)] +#[unstable(feature = "question_mark_carrier", issue = "31436")] +pub trait Carrier { + /// The type of the value when computation succeeds. + type Success; + /// The type of the value when computation errors out. + type Error; + + /// Create a `Carrier` from a success value. + fn from_success(_: Self::Success) -> Self; + + /// Create a `Carrier` from an error value. + fn from_error(_: Self::Error) -> Self; + + /// Translate this `Carrier` to another implementation of `Carrier` with the + /// same associated types. + fn translate(self) -> T where T: Carrier; +} + +#[cfg(stage0)] +#[unstable(feature = "question_mark_carrier", issue = "31436")] +impl Carrier for Result { + type Success = U; + type Error = V; + + fn from_success(u: U) -> Result { + Ok(u) + } + + fn from_error(e: V) -> Result { + Err(e) + } + + fn translate(self) -> T + where T: Carrier + { + match self { + Ok(u) => T::from_success(u), + Err(e) => T::from_error(e), + } + } +} + +struct _DummyErrorType; + +impl Try for _DummyErrorType { + type Ok = (); + type Error = (); + + fn into_result(self) -> Result { + Ok(()) + } + + fn from_ok(_: ()) -> _DummyErrorType { + _DummyErrorType + } + + fn from_error(_: ()) -> _DummyErrorType { + _DummyErrorType + } +} + +/// A trait for customizing the behaviour of the `?` operator. +/// +/// A type implementing `Try` is one that has a canonical way to view it +/// in terms of a success/failure dichotomy. This trait allows both +/// extracting those success or failure values from an existing instance and +/// creating a new instance from a success or failure value. +#[unstable(feature = "try_trait", issue = "42327")] +pub trait Try { + /// The type of this value when viewed as successful. + #[unstable(feature = "try_trait", issue = "42327")] + type Ok; + /// The type of this value when viewed as failed. + #[unstable(feature = "try_trait", issue = "42327")] + type Error; + + /// Applies the "?" operator. A return of `Ok(t)` means that the + /// execution should continue normally, and the result of `?` is the + /// value `t`. A return of `Err(e)` means that execution should branch + /// to the innermost enclosing `catch`, or return from the function. + /// + /// If an `Err(e)` result is returned, the value `e` will be "wrapped" + /// in the return type of the enclosing scope (which must itself implement + /// `Try`). Specifically, the value `X::from_error(From::from(e))` + /// is returned, where `X` is the return type of the enclosing function. + #[unstable(feature = "try_trait", issue = "42327")] + fn into_result(self) -> Result; + + /// Wrap an error value to construct the composite result. For example, + /// `Result::Err(x)` and `Result::from_error(x)` are equivalent. + #[unstable(feature = "try_trait", issue = "42327")] + fn from_error(v: Self::Error) -> Self; + + /// Wrap an OK value to construct the composite result. For example, + /// `Result::Ok(x)` and `Result::from_ok(x)` are equivalent. + #[unstable(feature = "try_trait", issue = "42327")] + fn from_ok(v: Self::Ok) -> Self; +} diff --git a/src/libcore/ops/unsize.rs b/src/libcore/ops/unsize.rs new file mode 100644 index 000000000000..1914216e9f08 --- /dev/null +++ b/src/libcore/ops/unsize.rs @@ -0,0 +1,79 @@ +// 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. + +use marker::Unsize; + +/// Trait that indicates that this is a pointer or a wrapper for one, +/// where unsizing can be performed on the pointee. +/// +/// See the [DST coercion RfC][dst-coerce] and [the nomicon entry on coercion][nomicon-coerce] +/// for more details. +/// +/// For builtin pointer types, pointers to `T` will coerce to pointers to `U` if `T: Unsize` +/// by converting from a thin pointer to a fat pointer. +/// +/// For custom types, the coercion here works by coercing `Foo` to `Foo` +/// provided an impl of `CoerceUnsized> for Foo` exists. +/// Such an impl can only be written if `Foo` has only a single non-phantomdata +/// field involving `T`. If the type of that field is `Bar`, an implementation +/// of `CoerceUnsized> for Bar` must exist. The coercion will work by +/// by coercing the `Bar` field into `Bar` and filling in the rest of the fields +/// from `Foo` to create a `Foo`. This will effectively drill down to a pointer +/// field and coerce that. +/// +/// Generally, for smart pointers you will implement +/// `CoerceUnsized> for Ptr where T: Unsize, U: ?Sized`, with an +/// optional `?Sized` bound on `T` itself. For wrapper types that directly embed `T` +/// like `Cell` and `RefCell`, you +/// can directly implement `CoerceUnsized> for Wrap where T: CoerceUnsized`. +/// This will let coercions of types like `Cell>` work. +/// +/// [`Unsize`][unsize] is used to mark types which can be coerced to DSTs if behind +/// pointers. It is implemented automatically by the compiler. +/// +/// [dst-coerce]: https://github.com/rust-lang/rfcs/blob/master/text/0982-dst-coercion.md +/// [unsize]: ../marker/trait.Unsize.html +/// [nomicon-coerce]: ../../nomicon/coercions.html +#[unstable(feature = "coerce_unsized", issue = "27732")] +#[lang="coerce_unsized"] +pub trait CoerceUnsized { + // Empty. +} + +// &mut T -> &mut U +#[unstable(feature = "coerce_unsized", issue = "27732")] +impl<'a, T: ?Sized+Unsize, U: ?Sized> CoerceUnsized<&'a mut U> for &'a mut T {} +// &mut T -> &U +#[unstable(feature = "coerce_unsized", issue = "27732")] +impl<'a, 'b: 'a, T: ?Sized+Unsize, U: ?Sized> CoerceUnsized<&'a U> for &'b mut T {} +// &mut T -> *mut U +#[unstable(feature = "coerce_unsized", issue = "27732")] +impl<'a, T: ?Sized+Unsize, U: ?Sized> CoerceUnsized<*mut U> for &'a mut T {} +// &mut T -> *const U +#[unstable(feature = "coerce_unsized", issue = "27732")] +impl<'a, T: ?Sized+Unsize, U: ?Sized> CoerceUnsized<*const U> for &'a mut T {} + +// &T -> &U +#[unstable(feature = "coerce_unsized", issue = "27732")] +impl<'a, 'b: 'a, T: ?Sized+Unsize, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} +// &T -> *const U +#[unstable(feature = "coerce_unsized", issue = "27732")] +impl<'a, T: ?Sized+Unsize, U: ?Sized> CoerceUnsized<*const U> for &'a T {} + +// *mut T -> *mut U +#[unstable(feature = "coerce_unsized", issue = "27732")] +impl, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} +// *mut T -> *const U +#[unstable(feature = "coerce_unsized", issue = "27732")] +impl, U: ?Sized> CoerceUnsized<*const U> for *mut T {} + +// *const T -> *const U +#[unstable(feature = "coerce_unsized", issue = "27732")] +impl, U: ?Sized> CoerceUnsized<*const U> for *const T {} diff --git a/src/libcore/result.rs b/src/libcore/result.rs index df7fff0df927..88a93492de96 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -1060,12 +1060,9 @@ impl> FromIterator> for Result { /// checking for overflow: /// /// ``` - /// use std::u32; - /// /// let v = vec![1, 2]; - /// let res: Result, &'static str> = v.iter().map(|&x: &u32| - /// if x == u32::MAX { Err("Overflow!") } - /// else { Ok(x + 1) } + /// let res: Result, &'static str> = v.iter().map(|x: &u32| + /// x.checked_add(1).ok_or("Overflow!") /// ).collect(); /// assert!(res == Ok(vec![2, 3])); /// ``` @@ -1126,4 +1123,4 @@ impl ops::Try for Result { fn from_error(v: E) -> Self { Err(v) } -} \ No newline at end of file +} diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 547a4899c711..624c3638df5c 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -1617,12 +1617,7 @@ mod traits { #[inline] fn index(&self, index: ops::RangeTo) -> &str { - // is_char_boundary checks that the index is in [0, .len()] - if self.is_char_boundary(index.end) { - unsafe { self.slice_unchecked(0, index.end) } - } else { - super::slice_error_fail(self, 0, index.end) - } + index.index(self) } } @@ -1636,12 +1631,7 @@ mod traits { impl ops::IndexMut> for str { #[inline] fn index_mut(&mut self, index: ops::RangeTo) -> &mut str { - // is_char_boundary checks that the index is in [0, .len()] - if self.is_char_boundary(index.end) { - unsafe { self.slice_mut_unchecked(0, index.end) } - } else { - super::slice_error_fail(self, 0, index.end) - } + index.index_mut(self) } } @@ -1657,12 +1647,7 @@ mod traits { #[inline] fn index(&self, index: ops::RangeFrom) -> &str { - // is_char_boundary checks that the index is in [0, .len()] - if self.is_char_boundary(index.start) { - unsafe { self.slice_unchecked(index.start, self.len()) } - } else { - super::slice_error_fail(self, index.start, self.len()) - } + index.index(self) } } @@ -1676,13 +1661,7 @@ mod traits { impl ops::IndexMut> for str { #[inline] fn index_mut(&mut self, index: ops::RangeFrom) -> &mut str { - // is_char_boundary checks that the index is in [0, .len()] - if self.is_char_boundary(index.start) { - let len = self.len(); - unsafe { self.slice_mut_unchecked(index.start, len) } - } else { - super::slice_error_fail(self, index.start, self.len()) - } + index.index_mut(self) } } @@ -1724,9 +1703,7 @@ mod traits { #[inline] fn index(&self, index: ops::RangeInclusive) -> &str { - assert!(index.end != usize::max_value(), - "attempted to index str up to maximum usize"); - self.index(index.start .. index.end+1) + index.index(self) } } @@ -1738,9 +1715,7 @@ mod traits { #[inline] fn index(&self, index: ops::RangeToInclusive) -> &str { - assert!(index.end != usize::max_value(), - "attempted to index str up to maximum usize"); - self.index(.. index.end+1) + index.index(self) } } @@ -1750,9 +1725,7 @@ mod traits { impl ops::IndexMut> for str { #[inline] fn index_mut(&mut self, index: ops::RangeInclusive) -> &mut str { - assert!(index.end != usize::max_value(), - "attempted to index str up to maximum usize"); - self.index_mut(index.start .. index.end+1) + index.index_mut(self) } } #[unstable(feature = "inclusive_range", @@ -1761,9 +1734,7 @@ mod traits { impl ops::IndexMut> for str { #[inline] fn index_mut(&mut self, index: ops::RangeToInclusive) -> &mut str { - assert!(index.end != usize::max_value(), - "attempted to index str up to maximum usize"); - self.index_mut(.. index.end+1) + index.index_mut(self) } } @@ -1886,6 +1857,7 @@ mod traits { } #[inline] fn index_mut(self, slice: &mut str) -> &mut Self::Output { + // is_char_boundary checks that the index is in [0, .len()] if slice.is_char_boundary(self.end) { unsafe { self.get_unchecked_mut(slice) } } else { @@ -1932,6 +1904,7 @@ mod traits { } #[inline] fn index_mut(self, slice: &mut str) -> &mut Self::Output { + // is_char_boundary checks that the index is in [0, .len()] if slice.is_char_boundary(self.start) { unsafe { self.get_unchecked_mut(slice) } } else { @@ -1945,11 +1918,19 @@ mod traits { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { - (self.start..self.end+1).get(slice) + if let Some(end) = self.end.checked_add(1) { + (self.start..end).get(slice) + } else { + None + } } #[inline] fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { - (self.start..self.end+1).get_mut(slice) + if let Some(end) = self.end.checked_add(1) { + (self.start..end).get_mut(slice) + } else { + None + } } #[inline] unsafe fn get_unchecked(self, slice: &str) -> &Self::Output { @@ -1961,10 +1942,14 @@ mod traits { } #[inline] fn index(self, slice: &str) -> &Self::Output { + assert!(self.end != usize::max_value(), + "attempted to index str up to maximum usize"); (self.start..self.end+1).index(slice) } #[inline] fn index_mut(self, slice: &mut str) -> &mut Self::Output { + assert!(self.end != usize::max_value(), + "attempted to index str up to maximum usize"); (self.start..self.end+1).index_mut(slice) } } @@ -1976,7 +1961,7 @@ mod traits { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { - if slice.is_char_boundary(self.end + 1) { + if self.end < usize::max_value() && slice.is_char_boundary(self.end + 1) { Some(unsafe { self.get_unchecked(slice) }) } else { None @@ -1984,7 +1969,7 @@ mod traits { } #[inline] fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { - if slice.is_char_boundary(self.end + 1) { + if self.end < usize::max_value() && slice.is_char_boundary(self.end + 1) { Some(unsafe { self.get_unchecked_mut(slice) }) } else { None @@ -2002,11 +1987,15 @@ mod traits { } #[inline] fn index(self, slice: &str) -> &Self::Output { + assert!(self.end != usize::max_value(), + "attempted to index str up to maximum usize"); 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 { + assert!(self.end != usize::max_value(), + "attempted to index str up to maximum usize"); if slice.is_char_boundary(self.end) { unsafe { self.get_unchecked_mut(slice) } } else { @@ -2026,7 +2015,7 @@ mod traits { issue = "32110")] pub trait StrExt { // NB there are no docs here are they're all located on the StrExt trait in - // libcollections, not here. + // liballoc, not here. #[stable(feature = "core", since = "1.6.0")] fn contains<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool; @@ -2096,7 +2085,7 @@ 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")] + #[unstable(feature = "str_mut_extras", issue = "41119")] 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; diff --git a/src/libcore/str/pattern.rs b/src/libcore/str/pattern.rs index 4918e37eb35f..5a007285e487 100644 --- a/src/libcore/str/pattern.rs +++ b/src/libcore/str/pattern.rs @@ -618,7 +618,10 @@ impl<'a, 'b> StrSearcher<'a, 'b> { } unsafe impl<'a, 'b> Searcher<'a> for StrSearcher<'a, 'b> { - fn haystack(&self) -> &'a str { self.haystack } + #[inline] + fn haystack(&self) -> &'a str { + self.haystack + } #[inline] fn next(&mut self) -> SearchStep { diff --git a/src/libcore/tests/cmp.rs b/src/libcore/tests/cmp.rs index e3c65ad8b33c..8c5179f59932 100644 --- a/src/libcore/tests/cmp.rs +++ b/src/libcore/tests/cmp.rs @@ -28,6 +28,16 @@ fn test_mut_int_totalord() { assert_eq!((&mut 12).cmp(&&mut -5), Greater); } +#[test] +fn test_ord_max_min() { + assert_eq!(1.max(2), 2); + assert_eq!(2.max(1), 2); + assert_eq!(1.min(2), 1); + assert_eq!(2.min(1), 1); + assert_eq!(1.max(1), 1); + assert_eq!(1.min(1), 1); +} + #[test] fn test_ordering_reverse() { assert_eq!(Less.reverse(), Greater); diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 505e51fa80b3..337f8aa31dc4 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -13,6 +13,7 @@ #![feature(box_syntax)] #![feature(char_escape_debug)] #![feature(const_fn)] +#![feature(core_float)] #![feature(core_private_bignum)] #![feature(core_private_diy_float)] #![feature(dec2flt)] @@ -26,6 +27,7 @@ #![feature(iter_rfind)] #![feature(libc)] #![feature(nonzero)] +#![feature(ord_max_min)] #![feature(rand)] #![feature(raw)] #![feature(sip_hash_13)] diff --git a/src/libcore/tests/num/dec2flt/mod.rs b/src/libcore/tests/num/dec2flt/mod.rs index 5d546c643e7e..9934e1dab966 100644 --- a/src/libcore/tests/num/dec2flt/mod.rs +++ b/src/libcore/tests/num/dec2flt/mod.rs @@ -33,6 +33,7 @@ macro_rules! test_literal { }) } +#[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630 #[test] fn ordinary() { test_literal!(1.0); @@ -43,6 +44,7 @@ fn ordinary() { test_literal!(2.2250738585072014e-308); } +#[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630 #[test] fn special_code_paths() { test_literal!(36893488147419103229.0); // 2^65 - 3, triggers half-to-even with even significand diff --git a/src/libcore/tests/num/dec2flt/rawfp.rs b/src/libcore/tests/num/dec2flt/rawfp.rs index 2b0afc402027..c9cd2bf5a9ae 100644 --- a/src/libcore/tests/num/dec2flt/rawfp.rs +++ b/src/libcore/tests/num/dec2flt/rawfp.rs @@ -86,6 +86,7 @@ fn rounding_overflow() { assert_eq!(rounded.k, adjusted_k + 1); } +#[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630 #[test] fn prev_float_monotonic() { let mut x = 1.0; @@ -121,6 +122,7 @@ fn next_float_inf() { assert_eq!(next_float(f64::INFINITY), f64::INFINITY); } +#[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630 #[test] fn next_prev_identity() { for &x in &SOME_FLOATS { @@ -131,6 +133,7 @@ fn next_prev_identity() { } } +#[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630 #[test] fn next_float_monotonic() { let mut x = 0.49999999999999; diff --git a/src/libcore/tests/num/flt2dec/strategy/dragon.rs b/src/libcore/tests/num/flt2dec/strategy/dragon.rs index 4edb0f3df60c..03772a765cc6 100644 --- a/src/libcore/tests/num/flt2dec/strategy/dragon.rs +++ b/src/libcore/tests/num/flt2dec/strategy/dragon.rs @@ -24,6 +24,7 @@ fn test_mul_pow10() { } } +#[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630 #[test] fn shortest_sanity_test() { f64_shortest_sanity_test(format_shortest); diff --git a/src/libcore/tests/num/flt2dec/strategy/grisu.rs b/src/libcore/tests/num/flt2dec/strategy/grisu.rs index 79e66ee669e1..17fb99bcc922 100644 --- a/src/libcore/tests/num/flt2dec/strategy/grisu.rs +++ b/src/libcore/tests/num/flt2dec/strategy/grisu.rs @@ -38,6 +38,7 @@ fn test_max_pow10_no_more_than() { } +#[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630 #[test] fn shortest_sanity_test() { f64_shortest_sanity_test(format_shortest); diff --git a/src/libcore/tests/num/mod.rs b/src/libcore/tests/num/mod.rs index 51737c9c3b48..f233b649a8f3 100644 --- a/src/libcore/tests/num/mod.rs +++ b/src/libcore/tests/num/mod.rs @@ -169,6 +169,7 @@ test_impl_from! { test_u16f64, u16, f64 } test_impl_from! { test_u32f64, u32, f64 } // Float -> Float +#[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630 #[test] fn test_f32f64() { use core::f32; @@ -398,3 +399,57 @@ test_impl_try_from_signed_to_unsigned_err! { test_try_i32u16, i32, u16 } test_impl_try_from_signed_to_unsigned_err! { test_try_i64u8, i64, u8 } test_impl_try_from_signed_to_unsigned_err! { test_try_i64u16, i64, u16 } test_impl_try_from_signed_to_unsigned_err! { test_try_i64u32, i64, u32 } + +macro_rules! test_float { + ($modname: ident, $fty: ty, $inf: expr, $neginf: expr, $nan: expr) => { mod $modname { + use core::num::Float; + // FIXME(nagisa): these tests should test for sign of -0.0 + #[test] + fn min() { + assert_eq!(0.0.min(0.0), 0.0); + assert_eq!((-0.0).min(-0.0), -0.0); + assert_eq!(9.0.min(9.0), 9.0); + assert_eq!((-9.0).min(0.0), -9.0); + assert_eq!(0.0.min(9.0), 0.0); + assert_eq!((-0.0).min(-9.0), -9.0); + assert_eq!($inf.min(9.0), 9.0); + assert_eq!(9.0.min($inf), 9.0); + assert_eq!($inf.min(-9.0), -9.0); + assert_eq!((-9.0).min($inf), -9.0); + assert_eq!($neginf.min(9.0), $neginf); + assert_eq!(9.0.min($neginf), $neginf); + assert_eq!($neginf.min(-9.0), $neginf); + assert_eq!((-9.0).min($neginf), $neginf); + assert_eq!($nan.min(9.0), 9.0); + assert_eq!($nan.min(-9.0), -9.0); + assert_eq!(9.0.min($nan), 9.0); + assert_eq!((-9.0).min($nan), -9.0); + assert!($nan.min($nan).is_nan()); + } + #[test] + fn max() { + assert_eq!(0.0.max(0.0), 0.0); + assert_eq!((-0.0).max(-0.0), -0.0); + assert_eq!(9.0.max(9.0), 9.0); + assert_eq!((-9.0).max(0.0), 0.0); + assert_eq!(0.0.max(9.0), 9.0); + assert_eq!((-0.0).max(-9.0), -0.0); + assert_eq!($inf.max(9.0), $inf); + assert_eq!(9.0.max($inf), $inf); + assert_eq!($inf.max(-9.0), $inf); + assert_eq!((-9.0).max($inf), $inf); + assert_eq!($neginf.max(9.0), 9.0); + assert_eq!(9.0.max($neginf), 9.0); + assert_eq!($neginf.max(-9.0), -9.0); + assert_eq!((-9.0).max($neginf), -9.0); + assert_eq!($nan.max(9.0), 9.0); + assert_eq!($nan.max(-9.0), -9.0); + assert_eq!(9.0.max($nan), 9.0); + assert_eq!((-9.0).max($nan), -9.0); + assert!($nan.max($nan).is_nan()); + } + } } +} + +test_float!(f32, f32, ::core::f32::INFINITY, ::core::f32::NEG_INFINITY, ::core::f32::NAN); +test_float!(f64, f64, ::core::f64::INFINITY, ::core::f64::NEG_INFINITY, ::core::f64::NAN); diff --git a/src/libfmt_macros/lib.rs b/src/libfmt_macros/lib.rs index 641a42b08188..967bfb6c9905 100644 --- a/src/libfmt_macros/lib.rs +++ b/src/libfmt_macros/lib.rs @@ -26,7 +26,7 @@ #![deny(warnings)] #![cfg_attr(stage0, feature(staged_api))] -#![feature(unicode)] +#![feature(rustc_private)] pub use self::Piece::*; pub use self::Position::*; diff --git a/src/libpanic_unwind/dwarf/eh.rs b/src/libpanic_unwind/dwarf/eh.rs index e7994f4e0ef0..0c326ce37184 100644 --- a/src/libpanic_unwind/dwarf/eh.rs +++ b/src/libpanic_unwind/dwarf/eh.rs @@ -61,9 +61,11 @@ pub enum EHAction { pub const USING_SJLJ_EXCEPTIONS: bool = cfg!(all(target_os = "ios", target_arch = "arm")); -pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext) -> EHAction { +pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext) + -> Result +{ if lsda.is_null() { - return EHAction::None; + return Ok(EHAction::None) } let func_start = context.func_start; @@ -72,7 +74,7 @@ pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext) -> EHAction { let start_encoding = reader.read::(); // base address for landing pad offsets let lpad_base = if start_encoding != DW_EH_PE_omit { - read_encoded_pointer(&mut reader, context, start_encoding) + read_encoded_pointer(&mut reader, context, start_encoding)? } else { func_start }; @@ -90,9 +92,9 @@ pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext) -> EHAction { if !USING_SJLJ_EXCEPTIONS { while reader.ptr < action_table { - let cs_start = read_encoded_pointer(&mut reader, context, call_site_encoding); - let cs_len = read_encoded_pointer(&mut reader, context, call_site_encoding); - let cs_lpad = read_encoded_pointer(&mut reader, context, call_site_encoding); + let cs_start = read_encoded_pointer(&mut reader, context, call_site_encoding)?; + let cs_len = read_encoded_pointer(&mut reader, context, call_site_encoding)?; + let cs_lpad = read_encoded_pointer(&mut reader, context, call_site_encoding)?; let cs_action = reader.read_uleb128(); // Callsite table is sorted by cs_start, so if we've passed the ip, we // may stop searching. @@ -101,23 +103,23 @@ pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext) -> EHAction { } if ip < func_start + cs_start + cs_len { if cs_lpad == 0 { - return EHAction::None; + return Ok(EHAction::None) } else { let lpad = lpad_base + cs_lpad; - return interpret_cs_action(cs_action, lpad); + return Ok(interpret_cs_action(cs_action, lpad)) } } } // Ip is not present in the table. This should not happen... but it does: issue #35011. // So rather than returning EHAction::Terminate, we do this. - EHAction::None + Ok(EHAction::None) } else { // SjLj version: // The "IP" is an index into the call-site table, with two exceptions: // -1 means 'no-action', and 0 means 'terminate'. match ip as isize { - -1 => return EHAction::None, - 0 => return EHAction::Terminate, + -1 => return Ok(EHAction::None), + 0 => return Ok(EHAction::Terminate), _ => (), } let mut idx = ip; @@ -129,7 +131,7 @@ pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext) -> EHAction { // Can never have null landing pad for sjlj -- that would have // been indicated by a -1 call site index. let lpad = (cs_lpad + 1) as usize; - return interpret_cs_action(cs_action, lpad); + return Ok(interpret_cs_action(cs_action, lpad)) } } } @@ -144,21 +146,26 @@ fn interpret_cs_action(cs_action: u64, lpad: usize) -> EHAction { } #[inline] -fn round_up(unrounded: usize, align: usize) -> usize { - assert!(align.is_power_of_two()); - (unrounded + align - 1) & !(align - 1) +fn round_up(unrounded: usize, align: usize) -> Result { + if align.is_power_of_two() { + Ok((unrounded + align - 1) & !(align - 1)) + } else { + Err(()) + } } unsafe fn read_encoded_pointer(reader: &mut DwarfReader, context: &EHContext, encoding: u8) - -> usize { - assert!(encoding != DW_EH_PE_omit); + -> Result { + if encoding == DW_EH_PE_omit { + return Err(()) + } // DW_EH_PE_aligned implies it's an absolute pointer value if encoding == DW_EH_PE_aligned { - reader.ptr = round_up(reader.ptr as usize, mem::size_of::()) as *const u8; - return reader.read::(); + reader.ptr = round_up(reader.ptr as usize, mem::size_of::())? as *const u8; + return Ok(reader.read::()) } let mut result = match encoding & 0x0F { @@ -171,7 +178,7 @@ unsafe fn read_encoded_pointer(reader: &mut DwarfReader, DW_EH_PE_sdata2 => reader.read::() as usize, DW_EH_PE_sdata4 => reader.read::() as usize, DW_EH_PE_sdata8 => reader.read::() as usize, - _ => panic!(), + _ => return Err(()), }; result += match encoding & 0x70 { @@ -179,17 +186,19 @@ unsafe fn read_encoded_pointer(reader: &mut DwarfReader, // relative to address of the encoded value, despite the name DW_EH_PE_pcrel => reader.ptr as usize, DW_EH_PE_funcrel => { - assert!(context.func_start != 0); + if context.func_start == 0 { + return Err(()) + } context.func_start } DW_EH_PE_textrel => (*context.get_text_start)(), DW_EH_PE_datarel => (*context.get_data_start)(), - _ => panic!(), + _ => return Err(()), }; if encoding & DW_EH_PE_indirect != 0 { result = *(result as *const usize); } - result + Ok(result) } diff --git a/src/libpanic_unwind/gcc.rs b/src/libpanic_unwind/gcc.rs index 84abc6bc4a51..aadbeb96b2d2 100644 --- a/src/libpanic_unwind/gcc.rs +++ b/src/libpanic_unwind/gcc.rs @@ -156,7 +156,10 @@ unsafe extern "C" fn rust_eh_personality(version: c_int, if version != 1 { return uw::_URC_FATAL_PHASE1_ERROR; } - let eh_action = find_eh_action(context); + let eh_action = match find_eh_action(context) { + Ok(action) => action, + Err(_) => return uw::_URC_FATAL_PHASE1_ERROR, + }; if actions as i32 & uw::_UA_SEARCH_PHASE as i32 != 0 { match eh_action { EHAction::None | @@ -219,7 +222,10 @@ unsafe extern "C" fn rust_eh_personality(state: uw::_Unwind_State, // _Unwind_Context in our libunwind bindings and fetch the required data from there directly, // bypassing DWARF compatibility functions. - let eh_action = find_eh_action(context); + let eh_action = match find_eh_action(context) { + Ok(action) => action, + Err(_) => return uw::_URC_FAILURE, + }; if search_phase { match eh_action { EHAction::None | @@ -260,7 +266,9 @@ unsafe extern "C" fn rust_eh_personality(state: uw::_Unwind_State, } } -unsafe fn find_eh_action(context: *mut uw::_Unwind_Context) -> EHAction { +unsafe fn find_eh_action(context: *mut uw::_Unwind_Context) + -> Result +{ let lsda = uw::_Unwind_GetLanguageSpecificData(context) as *const u8; let mut ip_before_instr: c_int = 0; let ip = uw::_Unwind_GetIPInfo(context, &mut ip_before_instr); diff --git a/src/libpanic_unwind/seh64_gnu.rs b/src/libpanic_unwind/seh64_gnu.rs index d4906b556b31..0a9fa7d9a80b 100644 --- a/src/libpanic_unwind/seh64_gnu.rs +++ b/src/libpanic_unwind/seh64_gnu.rs @@ -128,9 +128,10 @@ unsafe fn find_landing_pad(dc: &c::DISPATCHER_CONTEXT) -> Option { get_data_start: &|| unimplemented!(), }; match find_eh_action(dc.HandlerData, &eh_ctx) { - EHAction::None => None, - EHAction::Cleanup(lpad) | - EHAction::Catch(lpad) => Some(lpad), - EHAction::Terminate => intrinsics::abort(), + Err(_) | + Ok(EHAction::None) => None, + Ok(EHAction::Cleanup(lpad)) | + Ok(EHAction::Catch(lpad)) => Some(lpad), + Ok(EHAction::Terminate) => intrinsics::abort(), } } diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs index 0ab0550469ba..f3d0521a2af6 100644 --- a/src/libproc_macro/lib.rs +++ b/src/libproc_macro/lib.rs @@ -21,7 +21,7 @@ //! This functionality is intended to be expanded over time as more surface //! area for macro authors is stabilized. //! -//! See [the book](../book/procedural-macros.html) for more. +//! See [the book](../book/first-edition/procedural-macros.html) for more. #![crate_name = "proc_macro"] #![stable(feature = "proc_macro_lib", since = "1.15.0")] diff --git a/src/libprofiler_builtins/Cargo.toml b/src/libprofiler_builtins/Cargo.toml new file mode 100644 index 000000000000..a60db3136797 --- /dev/null +++ b/src/libprofiler_builtins/Cargo.toml @@ -0,0 +1,18 @@ +[package] +authors = ["The Rust Project Developers"] +build = "build.rs" +name = "profiler_builtins" +version = "0.0.0" + +[lib] +name = "profiler_builtins" +path = "lib.rs" +test = false +bench = false +doc = false + +[dependencies] +core = { path = "../libcore" } + +[build-dependencies] +gcc = "0.3.50" diff --git a/src/libprofiler_builtins/build.rs b/src/libprofiler_builtins/build.rs new file mode 100644 index 000000000000..1ee284ff4dab --- /dev/null +++ b/src/libprofiler_builtins/build.rs @@ -0,0 +1,60 @@ +// 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. + +//! Compiles the profiler part of the `compiler-rt` library. +//! +//! See the build.rs for libcompiler_builtins crate for details. + +extern crate gcc; + +use std::env; +use std::path::Path; + +fn main() { + let target = env::var("TARGET").expect("TARGET was not set"); + let cfg = &mut gcc::Config::new(); + + let mut profile_sources = vec!["GCDAProfiling.c", + "InstrProfiling.c", + "InstrProfilingBuffer.c", + "InstrProfilingFile.c", + "InstrProfilingMerge.c", + "InstrProfilingMergeFile.c", + "InstrProfilingPlatformDarwin.c", + "InstrProfilingPlatformLinux.c", + "InstrProfilingPlatformOther.c", + "InstrProfilingRuntime.cc", + "InstrProfilingUtil.c", + "InstrProfilingValue.c", + "InstrProfilingWriter.c"]; + + if target.contains("msvc") { + // Don't pull in extra libraries on MSVC + cfg.flag("/Zl"); + profile_sources.push("WindowsMMap.c"); + cfg.define("strdup", Some("_strdup")); + cfg.define("open", Some("_open")); + cfg.define("fdopen", Some("_fdopen")); + } else { + // Turn off various features of gcc and such, mostly copying + // compiler-rt's build system already + cfg.flag("-fno-builtin"); + cfg.flag("-fvisibility=hidden"); + cfg.flag("-fomit-frame-pointer"); + cfg.flag("-ffreestanding"); + cfg.define("VISIBILITY_HIDDEN", None); + } + + for src in profile_sources { + cfg.file(Path::new("../compiler-rt/lib/profile").join(src)); + } + + cfg.compile("libprofiler-rt.a"); +} diff --git a/src/libprofiler_builtins/lib.rs b/src/libprofiler_builtins/lib.rs new file mode 100644 index 000000000000..087cc444185b --- /dev/null +++ b/src/libprofiler_builtins/lib.rs @@ -0,0 +1,20 @@ +// 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. + +#![no_std] +#![cfg_attr(not(stage0), feature(profiler_runtime))] +#![cfg_attr(not(stage0), profiler_runtime)] +#![unstable(feature = "profiler_runtime_lib", + reason = "internal implementation detail of rustc right now", + issue = "0")] +#![crate_name = "profiler_builtins"] +#![crate_type = "rlib"] +#![allow(unused_features)] +#![feature(staged_api)] diff --git a/src/librustc/dep_graph/README.md b/src/librustc/dep_graph/README.md index 72715cf6bc74..c747c443b3a4 100644 --- a/src/librustc/dep_graph/README.md +++ b/src/librustc/dep_graph/README.md @@ -18,7 +18,7 @@ one of three things: 1. HIR nodes (like `Hir(DefId)`) represent the HIR input itself. 2. Data nodes (like `ItemSignature(DefId)`) represent some computed information about a particular item. -3. Procedure notes (like `CoherenceCheckImpl(DefId)`) represent some +3. Procedure nodes (like `CoherenceCheckTrait(DefId)`) represent some procedure that is executing. Usually this procedure is performing some kind of check for errors. You can think of them as computed values where the value being computed is `()` (and the @@ -57,139 +57,10 @@ recompile that item for sure. But we need the dep tracking map to tell us what *else* we have to recompile. Shared state is anything that is used to communicate results from one item to another. -### Identifying the current task +### Identifying the current task, tracking reads/writes, etc -The dep graph always tracks a current task: this is basically the -`DepNode` that the compiler is computing right now. Typically it would -be a procedure node, but it can also be a data node (as noted above, -the two are kind of equivalent). - -You set the current task by calling `dep_graph.in_task(node)`. For example: - -```rust -let _task = tcx.dep_graph.in_task(DepNode::Privacy); -``` - -Now all the code until `_task` goes out of scope will be considered -part of the "privacy task". - -The tasks are maintained in a stack, so it is perfectly fine to nest -one task within another. Because pushing a task is considered to be -computing a value, when you nest a task `N2` inside of a task `N1`, we -automatically add an edge `N2 -> N1` (since `N1` presumably needed the -result of `N2` to complete): - -```rust -let _n1 = tcx.dep_graph.in_task(DepNode::N1); -let _n2 = tcx.dep_graph.in_task(DepNode::N2); -// this will result in an edge N1 -> n2 -``` - -### Ignore tasks - -Although it is rarely needed, you can also push a special "ignore" -task: - -```rust -let _ignore = tc.dep_graph.in_ignore(); -``` - -This will cause all read/write edges to be ignored until it goes out -of scope or until something else is pushed. For example, we could -suppress the edge between nested tasks like so: - -```rust -let _n1 = tcx.dep_graph.in_task(DepNode::N1); -let _ignore = tcx.dep_graph.in_ignore(); -let _n2 = tcx.dep_graph.in_task(DepNode::N2); -// now no edge is added -``` - -### Tracking reads and writes - -We need to identify what shared state is read/written by the current -task as it executes. The most fundamental way of doing that is to invoke -the `read` and `write` methods on `DepGraph`: - -```rust -// Adds an edge from DepNode::Hir(some_def_id) to the current task -tcx.dep_graph.read(DepNode::Hir(some_def_id)) - -// Adds an edge from the current task to DepNode::ItemSignature(some_def_id) -tcx.dep_graph.write(DepNode::ItemSignature(some_def_id)) -``` - -However, you should rarely need to invoke those methods directly. -Instead, the idea is to *encapsulate* shared state into some API that -will invoke `read` and `write` automatically. The most common way to -do this is to use a `DepTrackingMap`, described in the next section, -but any sort of abstraction barrier will do. In general, the strategy -is that getting access to information implicitly adds an appropriate -`read`. So, for example, when you use the -`dep_graph::visit_all_items_in_krate` helper method, it will visit -each item `X`, start a task `Foo(X)` for that item, and automatically -add an edge `Hir(X) -> Foo(X)`. This edge is added because the code is -being given access to the HIR node for `X`, and hence it is expected -to read from it. Similarly, reading from the `tcache` map for item `X` -(which is a `DepTrackingMap`, described below) automatically invokes -`dep_graph.read(ItemSignature(X))`. - -**Note:** adding `Hir` nodes requires a bit of caution due to the -"inlining" that old trans and constant evaluation still use. See the -section on inlining below. - -To make this strategy work, a certain amount of indirection is -required. For example, modules in the HIR do not have direct pointers -to the items that they contain. Rather, they contain node-ids -- one -can then ask the HIR map for the item with a given node-id. This gives -us an opportunity to add an appropriate read edge. - -#### Explicit calls to read and write when starting a new subtask - -One time when you *may* need to call `read` and `write` directly is -when you push a new task onto the stack, either by calling `in_task` -as shown above or indirectly, such as with the `memoize` pattern -described below. In that case, any data that the task has access to -from the surrounding environment must be explicitly "read". For -example, in `librustc_typeck`, the collection code visits all items -and, among other things, starts a subtask producing its signature -(what follows is simplified pseudocode, of course): - -```rust -fn visit_item(item: &hir::Item) { - // Here, current subtask is "Collect(X)", and an edge Hir(X) -> Collect(X) - // has automatically been added by `visit_all_items_in_krate`. - let sig = signature_of_item(item); -} - -fn signature_of_item(item: &hir::Item) { - let def_id = tcx.map.local_def_id(item.id); - let task = tcx.dep_graph.in_task(DepNode::ItemSignature(def_id)); - tcx.dep_graph.read(DepNode::Hir(def_id)); // <-- the interesting line - ... -} -``` - -Here you can see that, in `signature_of_item`, we started a subtask -corresponding to producing the `ItemSignature`. This subtask will read from -`item` -- but it gained access to `item` implicitly. This means that if it just -reads from `item`, there would be missing edges in the graph: - - Hir(X) --+ // added by the explicit call to `read` - | | - | +---> ItemSignature(X) -> Collect(X) - | ^ - | | - +---------------------------------+ // added by `visit_all_items_in_krate` - -In particular, the edge from `Hir(X)` to `ItemSignature(X)` is only -present because we called `read` ourselves when entering the `ItemSignature(X)` -task. - -So, the rule of thumb: when entering a new task yourself, register -reads on any shared state that you inherit. (This actually comes up -fairly infrequently though: the main place you need caution is around -memoization.) +FIXME(#42293). This text needs to be rewritten for the new red-green +system, which doesn't fully exist yet. #### Dependency tracking map diff --git a/src/librustc/dep_graph/debug.rs b/src/librustc/dep_graph/debug.rs index 5b15c5e67174..e22552008d5a 100644 --- a/src/librustc/dep_graph/debug.rs +++ b/src/librustc/dep_graph/debug.rs @@ -12,7 +12,6 @@ use super::dep_node::DepNode; use std::error::Error; -use std::fmt::Debug; /// A dep-node filter goes from a user-defined string to a query over /// nodes. Right now the format is like this: @@ -39,7 +38,7 @@ impl DepNodeFilter { } /// Tests whether `node` meets the filter, returning true if so. - pub fn test(&self, node: &DepNode) -> bool { + pub fn test(&self, node: &DepNode) -> bool { let debug_str = format!("{:?}", node); self.text.split("&") .map(|s| s.trim()) @@ -67,10 +66,10 @@ impl EdgeFilter { } } - pub fn test(&self, - source: &DepNode, - target: &DepNode) - -> bool { + pub fn test(&self, + source: &DepNode, + target: &DepNode) + -> bool { self.source.test(source) && self.target.test(target) } } diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 85a02953a910..92efeb7fd862 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -8,80 +8,380 @@ // 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; -macro_rules! try_opt { - ($e:expr) => ( - match $e { - Some(r) => r, - None => return None, - } - ) +//! This module defines the `DepNode` type which the compiler uses to represent +//! nodes in the dependency graph. A `DepNode` consists of a `DepKind` (which +//! specifies the kind of thing it represents, like a piece of HIR, MIR, etc) +//! and a `Fingerprint`, a 128 bit hash value the exact meaning of which +//! depends on the node's `DepKind`. Together, the kind and the fingerprint +//! fully identify a dependency node, even across multiple compilation sessions. +//! In other words, the value of the fingerprint does not depend on anything +//! that is specific to a given compilation session, like an unpredictable +//! interning key (e.g. NodeId, DefId, Symbol) or the numeric value of a +//! pointer. The concept behind this could be compared to how git commit hashes +//! uniquely identify a given commit and has a few advantages: +//! +//! * A `DepNode` can simply be serialized to disk and loaded in another session +//! without the need to do any "rebasing (like we have to do for Spans and +//! NodeIds) or "retracing" like we had to do for `DefId` in earlier +//! implementations of the dependency graph. +//! * A `Fingerprint` is just a bunch of bits, which allows `DepNode` to +//! implement `Copy`, `Sync`, `Send`, `Freeze`, etc. +//! * Since we just have a bit pattern, `DepNode` can be mapped from disk into +//! memory without any post-processing (e.g. "abomination-style" pointer +//! reconstruction). +//! * Because a `DepNode` is self-contained, we can instantiate `DepNodes` that +//! refer to things that do not exist anymore. In previous implementations +//! `DepNode` contained a `DefId`. A `DepNode` referring to something that +//! had been removed between the previous and the current compilation session +//! could not be instantiated because the current compilation session +//! contained no `DefId` for thing that had been removed. +//! +//! `DepNode` definition happens in the `define_dep_nodes!()` macro. This macro +//! defines the `DepKind` enum and a corresponding `DepConstructor` enum. The +//! `DepConstructor` enum links a `DepKind` to the parameters that are needed at +//! runtime in order to construct a valid `DepNode` fingerprint. +//! +//! Because the macro sees what parameters a given `DepKind` requires, it can +//! "infer" some properties for each kind of `DepNode`: +//! +//! * Whether a `DepNode` of a given kind has any parameters at all. Some +//! `DepNode`s, like `Krate`, represent global concepts with only one value. +//! * Whether it is possible, in principle, to reconstruct a query key from a +//! given `DepNode`. Many `DepKind`s only require a single `DefId` parameter, +//! in which case it is possible to map the node's fingerprint back to the +//! `DefId` it was computed from. In other cases, too much information gets +//! lost during fingerprint computation. +//! +//! The `DepConstructor` enum, together with `DepNode::new()` ensures that only +//! valid `DepNode` instances can be constructed. For example, the API does not +//! allow for constructing parameterless `DepNode`s with anything other +//! than a zeroed out fingerprint. More generally speaking, it relieves the +//! user of the `DepNode` API of having to know how to compute the expected +//! fingerprint for a given set of node parameters. + +use hir::def_id::{CrateNum, DefId}; +use hir::map::DefPathHash; + +use ich::Fingerprint; +use ty::TyCtxt; +use rustc_data_structures::stable_hasher::{StableHasher, HashStable}; +use ich::StableHashingContext; +use std::fmt; +use std::hash::Hash; + +// erase!() just makes tokens go away. It's used to specify which macro argument +// is repeated (i.e. which sub-expression of the macro we are in) but don't need +// to actually use any of the arguments. +macro_rules! erase { + ($x:tt) => ({}) } -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] -pub enum DepNode { - // The `D` type is "how definitions are identified". - // During compilation, it is always `DefId`, but when serializing - // it is mapped to `DefPath`. +macro_rules! define_dep_nodes { + ($( + $variant:ident $(( $($tuple_arg:tt),* ))* + $({ $($struct_arg_name:ident : $struct_arg_ty:ty),* })* + ,)* + ) => ( + #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, + RustcEncodable, RustcDecodable)] + pub enum DepKind { + $($variant),* + } - /// Represents the `Krate` as a whole (the `hir::Krate` value) (as - /// distinct from the krate module). This is basically a hash of - /// the entire krate, so if you read from `Krate` (e.g., by calling - /// `tcx.hir.krate()`), we will have to assume that any change - /// means that you need to be recompiled. This is because the - /// `Krate` value gives you access to all other items. To avoid - /// this fate, do not call `tcx.hir.krate()`; instead, prefer - /// wrappers like `tcx.visit_all_items_in_krate()`. If there is no - /// suitable wrapper, you can use `tcx.dep_graph.ignore()` to gain - /// access to the krate, but you must remember to add suitable - /// edges yourself for the individual items that you read. + impl DepKind { + #[allow(unreachable_code)] + #[inline] + pub fn can_reconstruct_query_key(&self) -> bool { + match *self { + $( + DepKind :: $variant => { + // tuple args + $({ + return <( $($tuple_arg,)* ) as DepNodeParams> + ::CAN_RECONSTRUCT_QUERY_KEY; + })* + + // struct args + $({ + return <( $($struct_arg_ty,)* ) as DepNodeParams> + ::CAN_RECONSTRUCT_QUERY_KEY; + })* + + true + } + )* + } + } + + #[allow(unreachable_code)] + #[inline] + pub fn has_params(&self) -> bool { + match *self { + $( + DepKind :: $variant => { + // tuple args + $({ + $(erase!($tuple_arg);)* + return true; + })* + + // struct args + $({ + $(erase!($struct_arg_name);)* + return true; + })* + + false + } + )* + } + } + } + + pub enum DepConstructor { + $( + $variant $(( $($tuple_arg),* ))* + $({ $($struct_arg_name : $struct_arg_ty),* })* + ),* + } + + #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, + RustcEncodable, RustcDecodable)] + pub struct DepNode { + pub kind: DepKind, + pub hash: Fingerprint, + } + + impl DepNode { + #[allow(unreachable_code, non_snake_case)] + pub fn new(tcx: TyCtxt, dep: DepConstructor) -> DepNode { + match dep { + $( + DepConstructor :: $variant $(( $($tuple_arg),* ))* + $({ $($struct_arg_name),* })* + => + { + // tuple args + $({ + let tupled_args = ( $($tuple_arg,)* ); + let hash = DepNodeParams::to_fingerprint(&tupled_args, + tcx); + let dep_node = DepNode { + kind: DepKind::$variant, + hash + }; + + if cfg!(debug_assertions) && + !dep_node.kind.can_reconstruct_query_key() && + (tcx.sess.opts.debugging_opts.incremental_info || + tcx.sess.opts.debugging_opts.query_dep_graph) + { + tcx.dep_graph.register_dep_node_debug_str(dep_node, || { + tupled_args.to_debug_str(tcx) + }); + } + + return dep_node; + })* + + // struct args + $({ + let tupled_args = ( $($struct_arg_name,)* ); + let hash = DepNodeParams::to_fingerprint(&tupled_args, + tcx); + let dep_node = DepNode { + kind: DepKind::$variant, + hash + }; + + if cfg!(debug_assertions) && + !dep_node.kind.can_reconstruct_query_key() && + (tcx.sess.opts.debugging_opts.incremental_info || + tcx.sess.opts.debugging_opts.query_dep_graph) + { + tcx.dep_graph.register_dep_node_debug_str(dep_node, || { + tupled_args.to_debug_str(tcx) + }); + } + + return dep_node; + })* + + DepNode { + kind: DepKind::$variant, + hash: Fingerprint::zero(), + } + } + )* + } + } + + /// Construct a DepNode from the given DepKind and DefPathHash. This + /// method will assert that the given DepKind actually requires a + /// single DefId/DefPathHash parameter. + #[inline] + pub fn from_def_path_hash(kind: DepKind, + def_path_hash: DefPathHash) + -> DepNode { + assert!(kind.can_reconstruct_query_key() && kind.has_params()); + DepNode { + kind, + hash: def_path_hash.0, + } + } + + /// Create a new, parameterless DepNode. This method will assert + /// that the DepNode corresponding to the given DepKind actually + /// does not require any parameters. + #[inline] + pub fn new_no_params(kind: DepKind) -> DepNode { + assert!(!kind.has_params()); + DepNode { + kind, + hash: Fingerprint::zero(), + } + } + + /// Extract the DefId corresponding to this DepNode. This will work + /// if two conditions are met: + /// + /// 1. The Fingerprint of the DepNode actually is a DefPathHash, and + /// 2. the item that the DefPath refers to exists in the current tcx. + /// + /// Condition (1) is determined by the DepKind variant of the + /// DepNode. Condition (2) might not be fulfilled if a DepNode + /// refers to something from the previous compilation session that + /// has been removed. + #[inline] + pub fn extract_def_id(&self, tcx: TyCtxt) -> Option { + if self.kind.can_reconstruct_query_key() { + let def_path_hash = DefPathHash(self.hash); + if let Some(ref def_path_map) = tcx.def_path_hash_to_def_id.as_ref() { + def_path_map.get(&def_path_hash).cloned() + } else { + None + } + } else { + None + } + } + + /// Used in testing + pub fn from_label_string(label: &str, + def_path_hash: DefPathHash) + -> Result { + let kind = match label { + $( + stringify!($variant) => DepKind::$variant, + )* + _ => return Err(()), + }; + + if !kind.can_reconstruct_query_key() { + return Err(()); + } + + if kind.has_params() { + Ok(def_path_hash.to_dep_node(kind)) + } else { + Ok(DepNode::new_no_params(kind)) + } + } + } + ); +} + +impl fmt::Debug for DepNode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:?}", self.kind)?; + + if !self.kind.has_params() { + return Ok(()); + } + + write!(f, "(")?; + + ::ty::tls::with_opt(|opt_tcx| { + if let Some(tcx) = opt_tcx { + if let Some(def_id) = self.extract_def_id(tcx) { + write!(f, "{}", tcx.item_path_str(def_id))?; + } else if let Some(ref s) = tcx.dep_graph.dep_node_debug_str(*self) { + write!(f, "{}", s)?; + } else { + write!(f, "{:?}", self.hash)?; + } + } else { + write!(f, "{:?}", self.hash)?; + } + Ok(()) + })?; + + write!(f, ")") + } +} + + +impl DefPathHash { + #[inline] + pub fn to_dep_node(self, kind: DepKind) -> DepNode { + DepNode::from_def_path_hash(kind, self) + } +} + +impl DefId { + #[inline] + pub fn to_dep_node(self, tcx: TyCtxt, kind: DepKind) -> DepNode { + DepNode::from_def_path_hash(kind, tcx.def_path_hash(self)) + } +} + +define_dep_nodes!( + // Represents the `Krate` as a whole (the `hir::Krate` value) (as + // distinct from the krate module). This is basically a hash of + // the entire krate, so if you read from `Krate` (e.g., by calling + // `tcx.hir.krate()`), we will have to assume that any change + // means that you need to be recompiled. This is because the + // `Krate` value gives you access to all other items. To avoid + // this fate, do not call `tcx.hir.krate()`; instead, prefer + // wrappers like `tcx.visit_all_items_in_krate()`. If there is no + // suitable wrapper, you can use `tcx.dep_graph.ignore()` to gain + // access to the krate, but you must remember to add suitable + // edges yourself for the individual items that you read. Krate, - /// Represents the HIR node with the given node-id - Hir(D), + // Represents the HIR node with the given node-id + Hir(DefId), - /// Represents the body of a function or method. The def-id is that of the - /// function/method. - HirBody(D), + // Represents the body of a function or method. The def-id is that of the + // function/method. + HirBody(DefId), - /// Represents the metadata for a given HIR node, typically found - /// in an extern crate. - MetaData(D), + // Represents the metadata for a given HIR node, typically found + // in an extern crate. + MetaData(DefId), - /// Represents some piece of metadata global to its crate. - GlobalMetaData(D, GlobalMetaDataKind), - - /// Represents some artifact that we save to disk. Note that these - /// do not have a def-id as part of their identifier. - WorkProduct(Arc), + // Represents some artifact that we save to disk. Note that these + // do not have a def-id as part of their identifier. + WorkProduct(WorkProductId), // Represents different phases in the compiler. - RegionMaps(D), + RegionMaps(DefId), Coherence, Resolve, - CoherenceCheckTrait(D), - CoherenceCheckImpl(D), - CoherenceOverlapCheck(D), - CoherenceOverlapCheckSpecial(D), - Variance, + CoherenceCheckTrait(DefId), PrivacyAccessLevels(CrateNum), // Represents the MIR for a fn; also used as the task node for // things read/modify that MIR. - MirKrate, - Mir(D), - MirShim(Vec), + Mir(DefId), + MirShim(DefIdList), BorrowCheckKrate, - BorrowCheck(D), - RvalueCheck(D), + BorrowCheck(DefId), + RvalueCheck(DefId), Reachability, MirKeys, - LateLintCheck, - TransCrateItem(D), TransWriteMetadata, CrateVariances, @@ -90,38 +390,38 @@ pub enum DepNode { // nodes. Often we map multiple tables to the same node if there // is no point in distinguishing them (e.g., both the type and // predicates for an item wind up in `ItemSignature`). - AssociatedItems(D), - ItemSignature(D), - ItemVarianceConstraints(D), - ItemVariances(D), - IsForeignItem(D), - TypeParamPredicates((D, D)), - SizedConstraint(D), - DtorckConstraint(D), - AdtDestructor(D), - AssociatedItemDefIds(D), - InherentImpls(D), + AssociatedItems(DefId), + ItemSignature(DefId), + ItemVarianceConstraints(DefId), + ItemVariances(DefId), + IsConstFn(DefId), + IsForeignItem(DefId), + TypeParamPredicates { item_id: DefId, param_id: DefId }, + SizedConstraint(DefId), + DtorckConstraint(DefId), + AdtDestructor(DefId), + AssociatedItemDefIds(DefId), + InherentImpls(DefId), TypeckBodiesKrate, - TypeckTables(D), - UsedTraitImports(D), - ConstEval(D), - SymbolName(D), - SpecializationGraph(D), - ObjectSafety(D), - IsCopy(D), - IsSized(D), - IsFreeze(D), - NeedsDrop(D), - Layout(D), + TypeckTables(DefId), + ConstEval(DefId), + SymbolName(DefId), + SpecializationGraph(DefId), + ObjectSafety(DefId), + IsCopy(DefId), + IsSized(DefId), + IsFreeze(DefId), + NeedsDrop(DefId), + Layout(DefId), - /// The set of impls for a given trait. Ultimately, it would be - /// nice to get more fine-grained here (e.g., to include a - /// simplified type), but we can't do that until we restructure the - /// HIR to distinguish the *header* of an impl from its body. This - /// is because changes to the header may change the self-type of - /// the impl and hence would require us to be more conservative - /// than changes in the impl body. - TraitImpls(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 + // simplified type), but we can't do that until we restructure the + // HIR to distinguish the *header* of an impl from its body. This + // is because changes to the header may change the self-type of + // the impl and hence would require us to be more conservative + // than changes in the impl body. + TraitImpls(DefId), AllLocalTraitImpls, @@ -130,185 +430,151 @@ pub enum DepNode { // Otherwise the write into the map would be incorrectly // attributed to the first task that happened to fill the cache, // which would yield an overly conservative dep-graph. - TraitItems(D), - ReprHints(D), + TraitItems(DefId), + ReprHints(DefId), - /// Trait selection cache is a little funny. Given a trait - /// reference like `Foo: SomeTrait`, there could be - /// arbitrarily many def-ids to map on in there (e.g., `Foo`, - /// `SomeTrait`, `Bar`). We could have a vector of them, but it - /// requires heap-allocation, and trait sel in general can be a - /// surprisingly hot path. So instead we pick two def-ids: the - /// trait def-id, and the first def-id in the input types. If there - /// is no def-id in the input types, then we use the trait def-id - /// again. So for example: - /// - /// - `i32: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: Clone }` - /// - `u32: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: Clone }` - /// - `Clone: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: Clone }` - /// - `Vec: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: Vec }` - /// - `String: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: String }` - /// - `Foo: Trait` -> `TraitSelect { trait_def_id: Trait, self_def_id: Foo }` - /// - `Foo: Trait` -> `TraitSelect { trait_def_id: Trait, self_def_id: Foo }` - /// - `(Foo, Bar): Trait` -> `TraitSelect { trait_def_id: Trait, self_def_id: Foo }` - /// - `i32: Trait` -> `TraitSelect { trait_def_id: Trait, self_def_id: Foo }` - /// - /// You can see that we map many trait refs to the same - /// trait-select node. This is not a problem, it just means - /// imprecision in our dep-graph tracking. The important thing is - /// that for any given trait-ref, we always map to the **same** - /// trait-select node. - TraitSelect { trait_def_id: D, input_def_id: D }, + // Trait selection cache is a little funny. Given a trait + // reference like `Foo: SomeTrait`, there could be + // arbitrarily many def-ids to map on in there (e.g., `Foo`, + // `SomeTrait`, `Bar`). We could have a vector of them, but it + // requires heap-allocation, and trait sel in general can be a + // surprisingly hot path. So instead we pick two def-ids: the + // trait def-id, and the first def-id in the input types. If there + // is no def-id in the input types, then we use the trait def-id + // again. So for example: + // + // - `i32: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: Clone }` + // - `u32: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: Clone }` + // - `Clone: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: Clone }` + // - `Vec: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: Vec }` + // - `String: Clone` -> `TraitSelect { trait_def_id: Clone, self_def_id: String }` + // - `Foo: Trait` -> `TraitSelect { trait_def_id: Trait, self_def_id: Foo }` + // - `Foo: Trait` -> `TraitSelect { trait_def_id: Trait, self_def_id: Foo }` + // - `(Foo, Bar): Trait` -> `TraitSelect { trait_def_id: Trait, self_def_id: Foo }` + // - `i32: Trait` -> `TraitSelect { trait_def_id: Trait, self_def_id: Foo }` + // + // You can see that we map many trait refs to the same + // trait-select node. This is not a problem, it just means + // imprecision in our dep-graph tracking. The important thing is + // that for any given trait-ref, we always map to the **same** + // trait-select node. + TraitSelect { trait_def_id: DefId, input_def_id: DefId }, - /// For proj. cache, we just keep a list of all def-ids, since it is - /// not a hotspot. - ProjectionCache { def_ids: Vec }, + // For proj. cache, we just keep a list of all def-ids, since it is + // not a hotspot. + ProjectionCache { def_ids: DefIdList }, - ParamEnv(D), - DescribeDef(D), - DefSpan(D), - Stability(D), - Deprecation(D), - ItemBodyNestedBodies(D), - ConstIsRvaluePromotableToStatic(D), - ImplParent(D), - TraitOfItem(D), - IsExportedSymbol(D), - IsMirAvailable(D), - ItemAttrs(D), - FnArgNames(D), + ParamEnv(DefId), + DescribeDef(DefId), + DefSpan(DefId), + Stability(DefId), + Deprecation(DefId), + ItemBodyNestedBodies(DefId), + ConstIsRvaluePromotableToStatic(DefId), + ImplParent(DefId), + TraitOfItem(DefId), + IsExportedSymbol(DefId), + IsMirAvailable(DefId), + ItemAttrs(DefId), + FnArgNames(DefId), + DylibDepFormats(DefId), + IsAllocator(DefId), + IsPanicRuntime(DefId), + ExternCrate(DefId), +); + +trait DepNodeParams<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> { + const CAN_RECONSTRUCT_QUERY_KEY: bool; + fn to_fingerprint(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Fingerprint; + fn to_debug_str(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> String; } -impl DepNode { - /// Used in testing - pub fn from_label_string(label: &str, data: D) -> Result, ()> { - macro_rules! check { - ($($name:ident,)*) => { - match label { - $(stringify!($name) => Ok(DepNode::$name(data)),)* - _ => Err(()) - } - } - } +impl<'a, 'gcx: 'tcx + 'a, 'tcx: 'a, T> DepNodeParams<'a, 'gcx, 'tcx> for T + where T: HashStable> + fmt::Debug +{ + default const CAN_RECONSTRUCT_QUERY_KEY: bool = false; - if label == "Krate" { - // special case - return Ok(DepNode::Krate); - } + default fn to_fingerprint(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Fingerprint { + let mut hcx = StableHashingContext::new(tcx); + let mut hasher = StableHasher::new(); - check! { - BorrowCheck, - Hir, - HirBody, - TransCrateItem, - AssociatedItems, - ItemSignature, - ItemVariances, - IsForeignItem, - AssociatedItemDefIds, - InherentImpls, - TypeckTables, - UsedTraitImports, - TraitImpls, - ReprHints, - } + self.hash_stable(&mut hcx, &mut hasher); + + hasher.finish() } - pub fn map_def(&self, mut op: OP) -> Option> - where OP: FnMut(&D) -> Option, E: Clone + Debug - { - use self::DepNode::*; + default fn to_debug_str(&self, _: TyCtxt<'a, 'gcx, 'tcx>) -> String { + format!("{:?}", *self) + } +} - match *self { - Krate => Some(Krate), - BorrowCheckKrate => Some(BorrowCheckKrate), - MirKrate => Some(MirKrate), - TypeckBodiesKrate => Some(TypeckBodiesKrate), - Coherence => Some(Coherence), - CrateVariances => Some(CrateVariances), - Resolve => Some(Resolve), - Variance => Some(Variance), - PrivacyAccessLevels(k) => Some(PrivacyAccessLevels(k)), - Reachability => Some(Reachability), - MirKeys => Some(MirKeys), - LateLintCheck => Some(LateLintCheck), - TransWriteMetadata => Some(TransWriteMetadata), +impl<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> DepNodeParams<'a, 'gcx, 'tcx> for (DefId,) { + const CAN_RECONSTRUCT_QUERY_KEY: bool = true; - // work product names do not need to be mapped, because - // they are always absolute. - WorkProduct(ref id) => Some(WorkProduct(id.clone())), + fn to_fingerprint(&self, tcx: TyCtxt) -> Fingerprint { + tcx.def_path_hash(self.0).0 + } - IsCopy(ref d) => op(d).map(IsCopy), - IsSized(ref d) => op(d).map(IsSized), - IsFreeze(ref d) => op(d).map(IsFreeze), - NeedsDrop(ref d) => op(d).map(NeedsDrop), - Layout(ref d) => op(d).map(Layout), - Hir(ref d) => op(d).map(Hir), - HirBody(ref d) => op(d).map(HirBody), - MetaData(ref d) => op(d).map(MetaData), - 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), - 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), - TransCrateItem(ref d) => op(d).map(TransCrateItem), - AssociatedItems(ref d) => op(d).map(AssociatedItems), - ItemSignature(ref d) => op(d).map(ItemSignature), - ItemVariances(ref d) => op(d).map(ItemVariances), - ItemVarianceConstraints(ref d) => op(d).map(ItemVarianceConstraints), - 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), - ConstEval(ref d) => op(d).map(ConstEval), - SymbolName(ref d) => op(d).map(SymbolName), - SpecializationGraph(ref d) => op(d).map(SpecializationGraph), - ObjectSafety(ref d) => op(d).map(ObjectSafety), - TraitImpls(ref d) => op(d).map(TraitImpls), - AllLocalTraitImpls => Some(AllLocalTraitImpls), - TraitItems(ref d) => op(d).map(TraitItems), - ReprHints(ref d) => op(d).map(ReprHints), - TraitSelect { ref trait_def_id, ref input_def_id } => { - op(trait_def_id).and_then(|trait_def_id| { - op(input_def_id).and_then(|input_def_id| { - Some(TraitSelect { trait_def_id: trait_def_id, - input_def_id: input_def_id }) - }) - }) - } - ProjectionCache { ref def_ids } => { - let def_ids: Option> = def_ids.iter().map(op).collect(); - def_ids.map(|d| ProjectionCache { def_ids: d }) - } - ParamEnv(ref d) => op(d).map(ParamEnv), - 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), - ItemAttrs(ref d) => op(d).map(ItemAttrs), - FnArgNames(ref d) => op(d).map(FnArgNames), - ImplParent(ref d) => op(d).map(ImplParent), - TraitOfItem(ref d) => op(d).map(TraitOfItem), - IsExportedSymbol(ref d) => op(d).map(IsExportedSymbol), - ItemBodyNestedBodies(ref d) => op(d).map(ItemBodyNestedBodies), - ConstIsRvaluePromotableToStatic(ref d) => op(d).map(ConstIsRvaluePromotableToStatic), - IsMirAvailable(ref d) => op(d).map(IsMirAvailable), - GlobalMetaData(ref d, kind) => op(d).map(|d| GlobalMetaData(d, kind)), + fn to_debug_str(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> String { + tcx.item_path_str(self.0) + } +} + +impl<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> DepNodeParams<'a, 'gcx, 'tcx> for (DefId, DefId) { + const CAN_RECONSTRUCT_QUERY_KEY: bool = false; + + // We actually would not need to specialize the implementation of this + // method but it's faster to combine the hashes than to instantiate a full + // hashing context and stable-hashing state. + fn to_fingerprint(&self, tcx: TyCtxt) -> Fingerprint { + let (def_id_0, def_id_1) = *self; + + let def_path_hash_0 = tcx.def_path_hash(def_id_0); + let def_path_hash_1 = tcx.def_path_hash(def_id_1); + + def_path_hash_0.0.combine(def_path_hash_1.0) + } + + fn to_debug_str(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> String { + let (def_id_0, def_id_1) = *self; + + format!("({}, {})", + tcx.def_path(def_id_0).to_string(tcx), + tcx.def_path(def_id_1).to_string(tcx)) + } +} + + +impl<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> DepNodeParams<'a, 'gcx, 'tcx> for (DefIdList,) { + const CAN_RECONSTRUCT_QUERY_KEY: bool = false; + + // We actually would not need to specialize the implementation of this + // method but it's faster to combine the hashes than to instantiate a full + // hashing context and stable-hashing state. + fn to_fingerprint(&self, tcx: TyCtxt) -> Fingerprint { + let mut fingerprint = Fingerprint::zero(); + + for &def_id in self.0.iter() { + let def_path_hash = tcx.def_path_hash(def_id); + fingerprint = fingerprint.combine(def_path_hash.0); } + + fingerprint + } + + fn to_debug_str(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> String { + use std::fmt::Write; + + let mut s = String::new(); + write!(&mut s, "[").unwrap(); + + for &def_id in self.0.iter() { + write!(&mut s, "{}", tcx.def_path(def_id).to_string(tcx)).unwrap(); + } + + write!(&mut s, "]").unwrap(); + + s } } @@ -317,18 +583,38 @@ impl DepNode { /// some independent path or string that persists between runs without /// the need to be mapped or unmapped. (This ensures we can serialize /// them even in the absence of a tcx.) -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] -pub struct WorkProductId(pub String); - -#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] -pub enum GlobalMetaDataKind { - Krate, - CrateDeps, - DylibDependencyFormats, - LangItems, - LangItemsMissing, - NativeLibraries, - CodeMap, - Impls, - ExportedSymbols, +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, + RustcEncodable, RustcDecodable)] +pub struct WorkProductId { + hash: Fingerprint } + +impl WorkProductId { + pub fn from_cgu_name(cgu_name: &str) -> WorkProductId { + let mut hasher = StableHasher::new(); + cgu_name.len().hash(&mut hasher); + cgu_name.hash(&mut hasher); + WorkProductId { + hash: hasher.finish() + } + } + + pub fn from_fingerprint(fingerprint: Fingerprint) -> WorkProductId { + WorkProductId { + hash: fingerprint + } + } + + pub fn to_dep_node(self) -> DepNode { + DepNode { + kind: DepKind::WorkProduct, + hash: self.hash, + } + } +} + +impl_stable_hash_for!(struct ::dep_graph::WorkProductId { + hash +}); + +type DefIdList = Vec; diff --git a/src/librustc/dep_graph/dep_tracking_map.rs b/src/librustc/dep_graph/dep_tracking_map.rs index 7a246c814d3e..43f8d6b938da 100644 --- a/src/librustc/dep_graph/dep_tracking_map.rs +++ b/src/librustc/dep_graph/dep_tracking_map.rs @@ -8,12 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use hir::def_id::DefId; use rustc_data_structures::fx::FxHashMap; use std::cell::RefCell; -use std::ops::Index; use std::hash::Hash; use std::marker::PhantomData; +use ty::TyCtxt; use util::common::MemoizationMap; use super::{DepNode, DepGraph}; @@ -30,7 +29,7 @@ pub struct DepTrackingMap { pub trait DepTrackingMapConfig { type Key: Eq + Hash + Clone; type Value: Clone; - fn to_dep_node(key: &Self::Key) -> DepNode; + fn to_dep_node(tcx: TyCtxt, key: &Self::Key) -> DepNode; } impl DepTrackingMap { @@ -44,18 +43,18 @@ impl DepTrackingMap { /// Registers a (synthetic) read from the key `k`. Usually this /// is invoked automatically by `get`. - fn read(&self, k: &M::Key) { - let dep_node = M::to_dep_node(k); + fn read(&self, tcx: TyCtxt, k: &M::Key) { + let dep_node = M::to_dep_node(tcx, k); self.graph.read(dep_node); } - pub fn get(&self, k: &M::Key) -> Option<&M::Value> { - self.read(k); + pub fn get(&self, tcx: TyCtxt, k: &M::Key) -> Option<&M::Value> { + self.read(tcx, k); self.map.get(k) } - pub fn contains_key(&self, k: &M::Key) -> bool { - self.read(k); + pub fn contains_key(&self, tcx: TyCtxt, k: &M::Key) -> bool { + self.read(tcx, k); self.map.contains_key(k) } @@ -99,32 +98,22 @@ impl MemoizationMap for RefCell> { /// The key is the line marked `(*)`: the closure implicitly /// accesses the body of the item `item`, so we register a read /// from `Hir(item_def_id)`. - fn memoize(&self, key: M::Key, op: OP) -> M::Value + fn memoize(&self, tcx: TyCtxt, key: M::Key, op: OP) -> M::Value where OP: FnOnce() -> M::Value { let graph; { let this = self.borrow(); if let Some(result) = this.map.get(&key) { - this.read(&key); + this.read(tcx, &key); return result.clone(); } graph = this.graph.clone(); } - let _task = graph.in_task(M::to_dep_node(&key)); + let _task = graph.in_task(M::to_dep_node(tcx, &key)); let result = op(); self.borrow_mut().map.insert(key, result.clone()); result } } - -impl<'k, M: DepTrackingMapConfig> Index<&'k M::Key> for DepTrackingMap { - type Output = M::Value; - - #[inline] - fn index(&self, k: &'k M::Key) -> &M::Value { - self.get(k).unwrap() - } -} - diff --git a/src/librustc/dep_graph/edges.rs b/src/librustc/dep_graph/edges.rs index 5dbabcc92304..a323e44d0d42 100644 --- a/src/librustc/dep_graph/edges.rs +++ b/src/librustc/dep_graph/edges.rs @@ -9,13 +9,11 @@ // except according to those terms. use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use std::fmt::Debug; -use std::hash::Hash; use super::{DepGraphQuery, DepNode}; -pub struct DepGraphEdges { - nodes: Vec>, - indices: FxHashMap, IdIndex>, +pub struct DepGraphEdges { + nodes: Vec, + indices: FxHashMap, edges: FxHashSet<(IdIndex, IdIndex)>, open_nodes: Vec, } @@ -42,8 +40,8 @@ enum OpenNode { Ignore, } -impl DepGraphEdges { - pub fn new() -> DepGraphEdges { +impl DepGraphEdges { + pub fn new() -> DepGraphEdges { DepGraphEdges { nodes: vec![], indices: FxHashMap(), @@ -52,12 +50,12 @@ impl DepGraphEdges { } } - fn id(&self, index: IdIndex) -> DepNode { + fn id(&self, index: IdIndex) -> DepNode { self.nodes[index.index()].clone() } /// Creates a node for `id` in the graph. - fn make_node(&mut self, id: DepNode) -> IdIndex { + fn make_node(&mut self, id: DepNode) -> IdIndex { if let Some(&i) = self.indices.get(&id) { return i; } @@ -82,7 +80,7 @@ impl DepGraphEdges { assert_eq!(popped_node, OpenNode::Ignore); } - pub fn push_task(&mut self, key: DepNode) { + pub fn push_task(&mut self, key: DepNode) { let top_node = self.current_node(); let new_node = self.make_node(key); @@ -95,7 +93,7 @@ impl DepGraphEdges { } } - pub fn pop_task(&mut self, key: DepNode) { + pub fn pop_task(&mut self, key: DepNode) { let popped_node = self.open_nodes.pop().unwrap(); assert_eq!(OpenNode::Node(self.indices[&key]), popped_node); } @@ -105,7 +103,7 @@ impl DepGraphEdges { /// 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) { + pub fn read(&mut self, v: DepNode) { if self.current_node().is_some() { let source = self.make_node(v); self.add_edge_from_current_node(|current| (source, current)) @@ -115,7 +113,7 @@ impl DepGraphEdges { /// Indicates that the current task `C` writes `v` by adding an /// edge from `C` to `v`. If there is no current task, panics. If /// you want to suppress this edge, use `ignore`. - pub fn write(&mut self, v: DepNode) { + pub fn write(&mut self, v: DepNode) { let target = self.make_node(v); self.add_edge_from_current_node(|current| (current, target)) } @@ -159,7 +157,7 @@ impl DepGraphEdges { } } - pub fn query(&self) -> DepGraphQuery { + pub fn query(&self) -> DepGraphQuery { let edges: Vec<_> = self.edges.iter() .map(|&(i, j)| (self.id(i), self.id(j))) .collect(); diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs index 18eb4e5d0ad7..e48e61d80351 100644 --- a/src/librustc/dep_graph/graph.rs +++ b/src/librustc/dep_graph/graph.rs @@ -8,12 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use hir::def_id::DefId; use rustc_data_structures::fx::FxHashMap; use session::config::OutputType; use std::cell::{Ref, RefCell}; use std::rc::Rc; -use std::sync::Arc; use super::dep_node::{DepNode, WorkProductId}; use super::query::DepGraphQuery; @@ -35,10 +33,12 @@ struct DepGraphData { /// things available to us. If we find that they are not dirty, we /// load the path to the file storing those work-products here into /// this map. We can later look for and extract that data. - previous_work_products: RefCell, WorkProduct>>, + previous_work_products: RefCell>, /// Work-products that we generate in this run. - work_products: RefCell, WorkProduct>>, + work_products: RefCell>, + + dep_node_debug: RefCell>, } impl DepGraph { @@ -48,6 +48,7 @@ impl DepGraph { thread: DepGraphThreadData::new(enabled), previous_work_products: RefCell::new(FxHashMap()), work_products: RefCell::new(FxHashMap()), + dep_node_debug: RefCell::new(FxHashMap()), }) } } @@ -58,7 +59,7 @@ impl DepGraph { self.data.thread.is_fully_enabled() } - pub fn query(&self) -> DepGraphQuery { + pub fn query(&self) -> DepGraphQuery { self.data.thread.query() } @@ -66,7 +67,7 @@ impl DepGraph { raii::IgnoreTask::new(&self.data.thread) } - pub fn in_task<'graph>(&'graph self, key: DepNode) -> Option> { + pub fn in_task<'graph>(&'graph self, key: DepNode) -> Option> { raii::DepTask::new(&self.data.thread, key) } @@ -104,14 +105,14 @@ impl DepGraph { /// `arg` parameter. /// /// [README]: README.md - pub fn with_task(&self, key: DepNode, cx: C, arg: A, task: fn(C, A) -> R) -> R + pub fn with_task(&self, key: DepNode, cx: C, arg: A, task: fn(C, A) -> R) -> R where C: DepGraphSafe, A: DepGraphSafe { let _task = self.in_task(key); task(cx, arg) } - pub fn read(&self, v: DepNode) { + pub fn read(&self, v: DepNode) { if self.data.thread.is_enqueue_enabled() { self.data.thread.enqueue(DepMessage::Read(v)); } @@ -120,7 +121,7 @@ impl DepGraph { /// Indicates that a previous work product exists for `v`. This is /// invoked during initial start-up based on what nodes are clean /// (and what files exist in the incr. directory). - pub fn insert_previous_work_product(&self, v: &Arc, data: WorkProduct) { + pub fn insert_previous_work_product(&self, v: &WorkProductId, data: WorkProduct) { debug!("insert_previous_work_product({:?}, {:?})", v, data); self.data.previous_work_products.borrow_mut() .insert(v.clone(), data); @@ -129,7 +130,7 @@ impl DepGraph { /// Indicates that we created the given work-product in this run /// for `v`. This record will be preserved and loaded in the next /// run. - pub fn insert_work_product(&self, v: &Arc, data: WorkProduct) { + pub fn insert_work_product(&self, v: &WorkProductId, data: WorkProduct) { debug!("insert_work_product({:?}, {:?})", v, data); self.data.work_products.borrow_mut() .insert(v.clone(), data); @@ -137,7 +138,7 @@ impl DepGraph { /// Check whether a previous work product exists for `v` and, if /// so, return the path that leads to it. Used to skip doing work. - pub fn previous_work_product(&self, v: &Arc) -> Option { + pub fn previous_work_product(&self, v: &WorkProductId) -> Option { self.data.previous_work_products.borrow() .get(v) .cloned() @@ -145,15 +146,31 @@ impl DepGraph { /// Access the map of work-products created during this run. Only /// used during saving of the dep-graph. - pub fn work_products(&self) -> Ref, WorkProduct>> { + pub fn work_products(&self) -> Ref> { self.data.work_products.borrow() } /// Access the map of work-products created during the cached run. Only /// used during saving of the dep-graph. - pub fn previous_work_products(&self) -> Ref, WorkProduct>> { + pub fn previous_work_products(&self) -> Ref> { self.data.previous_work_products.borrow() } + + #[inline(always)] + pub(super) fn register_dep_node_debug_str(&self, + dep_node: DepNode, + debug_str_gen: F) + where F: FnOnce() -> String + { + let mut dep_node_debug = self.data.dep_node_debug.borrow_mut(); + + dep_node_debug.entry(dep_node) + .or_insert_with(debug_str_gen); + } + + pub(super) fn dep_node_debug_str(&self, dep_node: DepNode) -> Option { + self.data.dep_node_debug.borrow().get(&dep_node).cloned() + } } /// A "work product" is an intermediate result that we save into the diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs index 822b61df7a48..92b05f6a6558 100644 --- a/src/librustc/dep_graph/mod.rs +++ b/src/librustc/dep_graph/mod.rs @@ -22,10 +22,11 @@ mod thread; pub use self::dep_tracking_map::{DepTrackingMap, DepTrackingMapConfig}; pub use self::dep_node::DepNode; pub use self::dep_node::WorkProductId; -pub use self::dep_node::GlobalMetaDataKind; pub use self::graph::DepGraph; pub use self::graph::WorkProduct; pub use self::query::DepGraphQuery; pub use self::safe::AssertDepGraphSafe; pub use self::safe::DepGraphSafe; pub use self::raii::DepTask; + +pub use self::dep_node::{DepKind, DepConstructor}; diff --git a/src/librustc/dep_graph/query.rs b/src/librustc/dep_graph/query.rs index 4c791f965534..116c527bf46d 100644 --- a/src/librustc/dep_graph/query.rs +++ b/src/librustc/dep_graph/query.rs @@ -10,20 +10,18 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::graph::{Direction, INCOMING, Graph, NodeIndex, OUTGOING}; -use std::fmt::Debug; -use std::hash::Hash; use super::DepNode; -pub struct DepGraphQuery { - pub graph: Graph, ()>, - pub indices: FxHashMap, NodeIndex>, +pub struct DepGraphQuery { + pub graph: Graph, + pub indices: FxHashMap, } -impl DepGraphQuery { - pub fn new(nodes: &[DepNode], - edges: &[(DepNode, DepNode)]) - -> DepGraphQuery { +impl DepGraphQuery { + pub fn new(nodes: &[DepNode], + edges: &[(DepNode, DepNode)]) + -> DepGraphQuery { let mut graph = Graph::new(); let mut indices = FxHashMap(); for node in nodes { @@ -43,18 +41,18 @@ impl DepGraphQuery { } } - pub fn contains_node(&self, node: &DepNode) -> bool { + pub fn contains_node(&self, node: &DepNode) -> bool { self.indices.contains_key(&node) } - pub fn nodes(&self) -> Vec<&DepNode> { + pub fn nodes(&self) -> Vec<&DepNode> { self.graph.all_nodes() .iter() .map(|n| &n.data) .collect() } - pub fn edges(&self) -> Vec<(&DepNode,&DepNode)> { + pub fn edges(&self) -> Vec<(&DepNode,&DepNode)> { self.graph.all_edges() .iter() .map(|edge| (edge.source(), edge.target())) @@ -63,7 +61,7 @@ impl DepGraphQuery { .collect() } - fn reachable_nodes(&self, node: &DepNode, direction: Direction) -> Vec<&DepNode> { + fn reachable_nodes(&self, node: &DepNode, direction: Direction) -> Vec<&DepNode> { if let Some(&index) = self.indices.get(node) { self.graph.depth_traverse(index, direction) .map(|s| self.graph.node_data(s)) @@ -75,17 +73,17 @@ impl DepGraphQuery { /// All nodes reachable from `node`. In other words, things that /// will have to be recomputed if `node` changes. - pub fn transitive_successors(&self, node: &DepNode) -> Vec<&DepNode> { + pub fn transitive_successors(&self, node: &DepNode) -> Vec<&DepNode> { self.reachable_nodes(node, OUTGOING) } /// All nodes that can reach `node`. - pub fn transitive_predecessors(&self, node: &DepNode) -> Vec<&DepNode> { + pub fn transitive_predecessors(&self, node: &DepNode) -> Vec<&DepNode> { self.reachable_nodes(node, INCOMING) } /// Just the outgoing edges from `node`. - pub fn immediate_successors(&self, node: &DepNode) -> Vec<&DepNode> { + pub fn immediate_successors(&self, node: &DepNode) -> Vec<&DepNode> { if let Some(&index) = self.indices.get(&node) { self.graph.successor_nodes(index) .map(|s| self.graph.node_data(s)) diff --git a/src/librustc/dep_graph/raii.rs b/src/librustc/dep_graph/raii.rs index e39797599acf..b45f5de80271 100644 --- a/src/librustc/dep_graph/raii.rs +++ b/src/librustc/dep_graph/raii.rs @@ -8,17 +8,16 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use hir::def_id::DefId; use super::DepNode; use super::thread::{DepGraphThreadData, DepMessage}; pub struct DepTask<'graph> { data: &'graph DepGraphThreadData, - key: Option>, + key: Option, } impl<'graph> DepTask<'graph> { - pub fn new(data: &'graph DepGraphThreadData, key: DepNode) + pub fn new(data: &'graph DepGraphThreadData, key: DepNode) -> Option> { if data.is_enqueue_enabled() { data.enqueue(DepMessage::PushTask(key.clone())); diff --git a/src/librustc/dep_graph/shadow.rs b/src/librustc/dep_graph/shadow.rs index bedb6ff2771f..8808ea5948da 100644 --- a/src/librustc/dep_graph/shadow.rs +++ b/src/librustc/dep_graph/shadow.rs @@ -26,7 +26,6 @@ //! specify an edge filter to be applied to each edge as it is //! created. See `./README.md` for details. -use hir::def_id::DefId; use std::cell::RefCell; use std::env; @@ -36,7 +35,7 @@ use super::debug::EdgeFilter; pub struct ShadowGraph { // if you push None onto the stack, that corresponds to an Ignore - stack: RefCell>>>, + stack: RefCell>>, forbidden_edge: Option, } @@ -114,8 +113,8 @@ impl ShadowGraph { } fn check_edge(&self, - source: Option>>, - target: Option>>) { + source: Option>, + target: Option>) { assert!(ENABLED); match (source, target) { // cannot happen, one side is always Some(Some(_)) @@ -141,9 +140,9 @@ impl ShadowGraph { // Do a little juggling: we get back a reference to an option at the // top of the stack, convert it to an optional reference. -fn top<'s>(stack: &'s Vec>>) -> Option>> { +fn top<'s>(stack: &'s Vec>) -> Option> { stack.last() - .map(|n: &'s Option>| -> Option<&'s DepNode> { + .map(|n: &'s Option| -> Option<&'s DepNode> { // (*) // (*) type annotation just there to clarify what would // otherwise be some *really* obscure code diff --git a/src/librustc/dep_graph/thread.rs b/src/librustc/dep_graph/thread.rs index d3a940c811b8..ad0abfe26f45 100644 --- a/src/librustc/dep_graph/thread.rs +++ b/src/librustc/dep_graph/thread.rs @@ -18,7 +18,6 @@ //! to accumulate more messages. This way we only ever have two vectors //! allocated (and both have a fairly large capacity). -use hir::def_id::DefId; use rustc_data_structures::veccell::VecCell; use std::sync::mpsc::{self, Sender, Receiver}; use std::thread; @@ -30,10 +29,10 @@ use super::shadow::ShadowGraph; #[derive(Debug)] pub enum DepMessage { - Read(DepNode), - Write(DepNode), - PushTask(DepNode), - PopTask(DepNode), + Read(DepNode), + Write(DepNode), + PushTask(DepNode), + PopTask(DepNode), PushIgnore, PopIgnore, Query, @@ -63,7 +62,7 @@ pub struct DepGraphThreadData { swap_out: Sender>, // where to receive query results - query_in: Receiver>, + query_in: Receiver, } const INITIAL_CAPACITY: usize = 2048; @@ -120,7 +119,7 @@ impl DepGraphThreadData { self.swap_out.send(old_messages).unwrap(); } - pub fn query(&self) -> DepGraphQuery { + pub fn query(&self) -> DepGraphQuery { assert!(self.is_fully_enabled(), "should never query if not fully enabled"); self.enqueue(DepMessage::Query); self.swap(); @@ -151,7 +150,7 @@ impl DepGraphThreadData { /// Definition of the depgraph thread. pub fn main(swap_in: Receiver>, swap_out: Sender>, - query_out: Sender>) { + query_out: Sender) { let mut edges = DepGraphEdges::new(); // the compiler thread always expects a fresh buffer to be diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 800e678405aa..28fb96aa2032 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -405,7 +405,7 @@ impl Quux for Foo { } Lifetime elision in implementation headers was part of the lifetime elision RFC. It is, however, [currently unimplemented][iss15872]. -[book-le]: https://doc.rust-lang.org/nightly/book/lifetimes.html#lifetime-elision +[book-le]: https://doc.rust-lang.org/nightly/book/first-edition/lifetimes.html#lifetime-elision [iss15872]: https://github.com/rust-lang/rust/issues/15872 "##, @@ -501,7 +501,7 @@ fn main() { } ``` -See also https://doc.rust-lang.org/book/unsafe.html +See also https://doc.rust-lang.org/book/first-edition/unsafe.html "##, // This shouldn't really ever trigger since the repeated value error comes first @@ -666,7 +666,7 @@ attributes: #![no_std] ``` -See also https://doc.rust-lang.org/book/no-stdlib.html +See also https://doc.rust-lang.org/book/first-edition/no-stdlib.html "##, E0261: r##" @@ -1779,7 +1779,7 @@ fn main() { ``` To understand better how closures work in Rust, read: -https://doc.rust-lang.org/book/closures.html +https://doc.rust-lang.org/book/first-edition/closures.html "##, E0580: r##" diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs index f553c03d09bd..3034242b5940 100644 --- a/src/librustc/hir/check_attr.rs +++ b/src/librustc/hir/check_attr.rs @@ -8,6 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +//! This module implements some validity checks for attributes. +//! In particular it verifies that `#[inline]` and `#[repr]` attributes are +//! attached to items that actually support them and if there are +//! conflicts between multiple such attributes attached to the same +//! item. + use session::Session; use syntax::ast; @@ -40,6 +46,18 @@ struct CheckAttrVisitor<'a> { } impl<'a> CheckAttrVisitor<'a> { + /// Check any attribute. + fn check_attribute(&self, attr: &ast::Attribute, target: Target) { + if let Some(name) = attr.name() { + match &*name.as_str() { + "inline" => self.check_inline(attr, target), + "repr" => self.check_repr(attr, target), + _ => (), + } + } + } + + /// Check if an `#[inline]` is applied to a function. fn check_inline(&self, attr: &ast::Attribute, target: Target) { if target != Target::Fn { struct_span_err!(self.sess, attr.span, E0518, "attribute should be applied to function") @@ -48,6 +66,7 @@ impl<'a> CheckAttrVisitor<'a> { } } + /// Check if an `#[repr]` attr is valid. fn check_repr(&self, attr: &ast::Attribute, target: Target) { let words = match attr.meta_item_list() { Some(words) => words, @@ -135,16 +154,6 @@ impl<'a> CheckAttrVisitor<'a> { "conflicting packed and align representation hints").emit(); } } - - fn check_attribute(&self, attr: &ast::Attribute, target: Target) { - if let Some(name) = attr.name() { - match &*name.as_str() { - "inline" => self.check_inline(attr, target), - "repr" => self.check_repr(attr, target), - _ => (), - } - } - } } impl<'a> Visitor<'a> for CheckAttrVisitor<'a> { diff --git a/src/librustc/hir/def_id.rs b/src/librustc/hir/def_id.rs index ce2baa738975..95a27f065999 100644 --- a/src/librustc/hir/def_id.rs +++ b/src/librustc/hir/def_id.rs @@ -58,6 +58,8 @@ impl CrateNum { pub fn as_u32(&self) -> u32 { self.0 } + + pub fn as_def_id(&self) -> DefId { DefId { krate: *self, index: CRATE_DEF_INDEX } } } impl fmt::Display for CrateNum { diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index a6ab67e04693..3d77381e2e93 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -2686,7 +2686,7 @@ impl<'a> LoweringContext<'a> { let parent_def = self.parent_def.unwrap(); let def_id = { let defs = self.resolver.definitions(); - let def_path_data = DefPathData::Binding(Ident::with_empty_ctxt(name)); + let def_path_data = DefPathData::Binding(name); let def_index = defs .create_def_with_parent(parent_def, id, def_path_data, REGULAR_SPACE, Mark::root()); DefId::local(def_index) diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index cb25b462b6e2..7fbefa5788b2 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -15,6 +15,7 @@ use syntax::ast::*; use syntax::ext::hygiene::Mark; use syntax::visit; use syntax::symbol::keywords; +use syntax::symbol::Symbol; use hir::map::{ITEM_LIKE_SPACE, REGULAR_SPACE}; @@ -103,14 +104,14 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { DefPathData::Impl, ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) | ItemKind::Trait(..) | ItemKind::ExternCrate(..) | ItemKind::ForeignMod(..) | ItemKind::Ty(..) => - DefPathData::TypeNs(i.ident.modern()), + DefPathData::TypeNs(i.ident.name), ItemKind::Mod(..) if i.ident == keywords::Invalid.ident() => { return visit::walk_item(self, i); } - ItemKind::Mod(..) => DefPathData::Module(i.ident.modern()), + ItemKind::Mod(..) => DefPathData::Module(i.ident.name), ItemKind::Static(..) | ItemKind::Const(..) | ItemKind::Fn(..) => - DefPathData::ValueNs(i.ident.modern()), - ItemKind::MacroDef(..) => DefPathData::MacroDef(i.ident.modern()), + DefPathData::ValueNs(i.ident.name), + ItemKind::MacroDef(..) => DefPathData::MacroDef(i.ident.name), ItemKind::Mac(..) => return self.visit_macro_invoc(i.id, false), ItemKind::GlobalAsm(..) => DefPathData::Misc, ItemKind::Use(ref view_path) => { @@ -138,13 +139,13 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { for v in &enum_definition.variants { let variant_def_index = this.create_def(v.node.data.id(), - DefPathData::EnumVariant(v.node.name.modern()), + DefPathData::EnumVariant(v.node.name.name), REGULAR_SPACE); this.with_parent(variant_def_index, |this| { for (index, field) in v.node.data.fields().iter().enumerate() { - let ident = field.ident.map(Ident::modern) - .unwrap_or_else(|| Ident::from_str(&index.to_string())); - this.create_def(field.id, DefPathData::Field(ident), REGULAR_SPACE); + let name = field.ident.map(|ident| ident.name) + .unwrap_or_else(|| Symbol::intern(&index.to_string())); + this.create_def(field.id, DefPathData::Field(name), REGULAR_SPACE); } if let Some(ref expr) = v.node.disr_expr { @@ -162,9 +163,9 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { } for (index, field) in struct_def.fields().iter().enumerate() { - let ident = field.ident.map(Ident::modern) - .unwrap_or_else(|| Ident::from_str(&index.to_string())); - this.create_def(field.id, DefPathData::Field(ident), REGULAR_SPACE); + let name = field.ident.map(|ident| ident.name) + .unwrap_or_else(|| Symbol::intern(&index.to_string())); + this.create_def(field.id, DefPathData::Field(name), REGULAR_SPACE); } } _ => {} @@ -175,7 +176,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { fn visit_foreign_item(&mut self, foreign_item: &'a ForeignItem) { let def = self.create_def(foreign_item.id, - DefPathData::ValueNs(foreign_item.ident.modern()), + DefPathData::ValueNs(foreign_item.ident.name), REGULAR_SPACE); self.with_parent(def, |this| { @@ -186,7 +187,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { fn visit_generics(&mut self, generics: &'a Generics) { for ty_param in generics.ty_params.iter() { self.create_def(ty_param.id, - DefPathData::TypeParam(ty_param.ident.modern()), + DefPathData::TypeParam(ty_param.ident.name), REGULAR_SPACE); } @@ -196,8 +197,8 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { fn visit_trait_item(&mut self, ti: &'a TraitItem) { let def_data = match ti.node { TraitItemKind::Method(..) | TraitItemKind::Const(..) => - DefPathData::ValueNs(ti.ident.modern()), - TraitItemKind::Type(..) => DefPathData::TypeNs(ti.ident.modern()), + DefPathData::ValueNs(ti.ident.name), + TraitItemKind::Type(..) => DefPathData::TypeNs(ti.ident.name), TraitItemKind::Macro(..) => return self.visit_macro_invoc(ti.id, false), }; @@ -214,8 +215,8 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { fn visit_impl_item(&mut self, ii: &'a ImplItem) { let def_data = match ii.node { ImplItemKind::Method(..) | ImplItemKind::Const(..) => - DefPathData::ValueNs(ii.ident.modern()), - ImplItemKind::Type(..) => DefPathData::TypeNs(ii.ident.modern()), + DefPathData::ValueNs(ii.ident.name), + ImplItemKind::Type(..) => DefPathData::TypeNs(ii.ident.name), ImplItemKind::Macro(..) => return self.visit_macro_invoc(ii.id, false), }; @@ -236,7 +237,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { PatKind::Mac(..) => return self.visit_macro_invoc(pat.id, false), PatKind::Ident(_, id, _) => { let def = self.create_def(pat.id, - DefPathData::Binding(id.node.modern()), + DefPathData::Binding(id.node.name), REGULAR_SPACE); self.parent_def = Some(def); } @@ -281,7 +282,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { fn visit_lifetime_def(&mut self, def: &'a LifetimeDef) { self.create_def(def.lifetime.id, - DefPathData::LifetimeDef(def.lifetime.ident.modern()), + DefPathData::LifetimeDef(def.lifetime.ident.name), REGULAR_SPACE); } diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs index ced0f351c9ee..c969aef675ff 100644 --- a/src/librustc/hir/map/definitions.rs +++ b/src/librustc/hir/map/definitions.rs @@ -15,7 +15,8 @@ //! expressions) that are mostly just leftovers. use hir; -use hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE, DefIndexAddressSpace}; +use hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE, DefIndexAddressSpace, + CRATE_DEF_INDEX}; use ich::Fingerprint; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::indexed_vec::IndexVec; @@ -23,8 +24,8 @@ use rustc_data_structures::stable_hasher::StableHasher; use serialize::{Encodable, Decodable, Encoder, Decoder}; use std::fmt::Write; use std::hash::Hash; -use syntax::ast::{self, Ident}; -use syntax::ext::hygiene::{Mark, SyntaxContext}; +use syntax::ast; +use syntax::ext::hygiene::Mark; use syntax::symbol::{Symbol, InternedString}; use ty::TyCtxt; use util::nodemap::NodeMap; @@ -247,7 +248,39 @@ impl DefKey { // and the special "root_parent" below. 0u8.hash(&mut hasher); parent_hash.hash(&mut hasher); - self.disambiguated_data.hash(&mut hasher); + + let DisambiguatedDefPathData { + ref data, + disambiguator, + } = self.disambiguated_data; + + ::std::mem::discriminant(data).hash(&mut hasher); + match *data { + DefPathData::TypeNs(name) | + DefPathData::ValueNs(name) | + DefPathData::Module(name) | + DefPathData::MacroDef(name) | + DefPathData::TypeParam(name) | + DefPathData::LifetimeDef(name) | + DefPathData::EnumVariant(name) | + DefPathData::Binding(name) | + DefPathData::Field(name) | + DefPathData::GlobalMetaData(name) => { + (*name.as_str()).hash(&mut hasher); + } + + DefPathData::Impl | + DefPathData::CrateRoot | + DefPathData::Misc | + DefPathData::ClosureExpr | + DefPathData::StructCtor | + DefPathData::Initializer | + DefPathData::ImplTrait | + DefPathData::Typeof => {} + }; + + disambiguator.hash(&mut hasher); + DefPathHash(hasher.finish()) } @@ -353,7 +386,7 @@ impl DefPath { } } -#[derive(Clone, Debug, RustcEncodable, RustcDecodable)] +#[derive(Clone, Debug, Eq, PartialEq, Hash, RustcEncodable, RustcDecodable)] pub enum DefPathData { // Root: these should only be used for the root nodes, because // they are treated specially by the `def_path` function. @@ -367,35 +400,40 @@ pub enum DefPathData { /// An impl Impl, /// Something in the type NS - TypeNs(Ident), + TypeNs(Symbol), /// Something in the value NS - ValueNs(Ident), + ValueNs(Symbol), /// A module declaration - Module(Ident), + Module(Symbol), /// A macro rule - MacroDef(Ident), + MacroDef(Symbol), /// A closure expression ClosureExpr, // Subportions of items /// A type parameter (generic parameter) - TypeParam(Ident), + TypeParam(Symbol), /// A lifetime definition - LifetimeDef(Ident), + LifetimeDef(Symbol), /// A variant of a enum - EnumVariant(Ident), + EnumVariant(Symbol), /// A struct field - Field(Ident), + Field(Symbol), /// Implicit ctor for a tuple-like struct StructCtor, /// Initializer for a const Initializer, /// Pattern binding - Binding(Ident), + Binding(Symbol), /// An `impl Trait` type node. ImplTrait, /// A `typeof` type node. Typeof, + + /// GlobalMetaData identifies a piece of crate metadata that is global to + /// a whole crate (as opposed to just one item). GlobalMetaData components + /// are only supposed to show up right below the crate root. + GlobalMetaData(Symbol) } #[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug, @@ -427,8 +465,8 @@ impl Definitions { /// Get the number of definitions. pub fn def_index_counts_lo_hi(&self) -> (usize, usize) { - (self.def_index_to_node[DefIndexAddressSpace::Low.index()].len(), - self.def_index_to_node[DefIndexAddressSpace::High.index()].len()) + (self.table.index_to_key[DefIndexAddressSpace::Low.index()].len(), + self.table.index_to_key[DefIndexAddressSpace::High.index()].len()) } pub fn def_key(&self, index: DefIndex) -> DefKey { @@ -469,7 +507,12 @@ impl Definitions { if def_id.krate == LOCAL_CRATE { let space_index = def_id.index.address_space().index(); let array_index = def_id.index.as_array_index(); - Some(self.def_index_to_node[space_index][array_index]) + let node_id = self.def_index_to_node[space_index][array_index]; + if node_id != ast::DUMMY_NODE_ID { + Some(node_id) + } else { + None + } } else { None } @@ -498,12 +541,16 @@ impl Definitions { // Create the definition. let address_space = super::ITEM_LIKE_SPACE; - let index = self.table.allocate(key, def_path_hash, address_space); + let root_index = self.table.allocate(key, def_path_hash, address_space); + assert_eq!(root_index, CRATE_DEF_INDEX); 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); + self.node_to_def_index.insert(ast::CRATE_NODE_ID, root_index); - index + // Allocate some other DefIndices that always must exist. + GlobalMetaDataKind::allocate_def_indices(self); + + root_index } /// Add a definition with a parent definition. @@ -550,13 +597,19 @@ impl Definitions { 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); + + // Some things for which we allocate DefIndices don't correspond to + // anything in the AST, so they don't have a NodeId. For these cases + // we don't need a mapping from NodeId to DefIndex. + if node_id != ast::DUMMY_NODE_ID { + debug!("create_def_with_parent: def_index_to_node[{:?} <-> {:?}", index, node_id); + self.node_to_def_index.insert(node_id, index); + } + if expansion.is_modern() { self.expansions.insert(index, expansion); } - debug!("create_def_with_parent: def_index_to_node[{:?} <-> {:?}", index, node_id); - self.node_to_def_index.insert(node_id, index); - index } @@ -583,18 +636,19 @@ impl Definitions { } impl DefPathData { - pub fn get_opt_ident(&self) -> Option { + pub fn get_opt_name(&self) -> Option { use self::DefPathData::*; match *self { - TypeNs(ident) | - ValueNs(ident) | - Module(ident) | - MacroDef(ident) | - TypeParam(ident) | - LifetimeDef(ident) | - EnumVariant(ident) | - Binding(ident) | - Field(ident) => Some(ident), + TypeNs(name) | + ValueNs(name) | + Module(name) | + MacroDef(name) | + TypeParam(name) | + LifetimeDef(name) | + EnumVariant(name) | + Binding(name) | + Field(name) | + GlobalMetaData(name) => Some(name), Impl | CrateRoot | @@ -607,23 +661,20 @@ impl DefPathData { } } - pub fn get_opt_name(&self) -> Option { - self.get_opt_ident().map(|ident| ident.name) - } - pub fn as_interned_str(&self) -> InternedString { use self::DefPathData::*; let s = match *self { - TypeNs(ident) | - ValueNs(ident) | - Module(ident) | - MacroDef(ident) | - TypeParam(ident) | - LifetimeDef(ident) | - EnumVariant(ident) | - Binding(ident) | - Field(ident) => { - return ident.name.as_str(); + TypeNs(name) | + ValueNs(name) | + Module(name) | + MacroDef(name) | + TypeParam(name) | + LifetimeDef(name) | + EnumVariant(name) | + Binding(name) | + Field(name) | + GlobalMetaData(name) => { + return name.as_str(); } // note that this does not show up in user printouts @@ -646,24 +697,72 @@ impl DefPathData { } } -impl Eq for DefPathData {} -impl PartialEq for DefPathData { - fn eq(&self, other: &DefPathData) -> bool { - ::std::mem::discriminant(self) == ::std::mem::discriminant(other) && - self.get_opt_ident() == other.get_opt_ident() - } -} +// We define the GlobalMetaDataKind enum with this macro because we want to +// make sure that we exhaustively iterate over all variants when registering +// the corresponding DefIndices in the DefTable. +macro_rules! define_global_metadata_kind { + (pub enum GlobalMetaDataKind { + $($variant:ident),* + }) => ( + #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, + RustcEncodable, RustcDecodable)] + pub enum GlobalMetaDataKind { + $($variant),* + } -impl ::std::hash::Hash for DefPathData { - fn hash(&self, hasher: &mut H) { - ::std::mem::discriminant(self).hash(hasher); - if let Some(ident) = self.get_opt_ident() { - if ident.ctxt == SyntaxContext::empty() && ident.name == ident.name.interned() { - ident.name.as_str().hash(hasher) - } else { - // FIXME(jseyfried) implement stable hashing for idents with macros 2.0 hygiene info - ident.hash(hasher) + impl GlobalMetaDataKind { + fn allocate_def_indices(definitions: &mut Definitions) { + $({ + let instance = GlobalMetaDataKind::$variant; + definitions.create_def_with_parent( + CRATE_DEF_INDEX, + ast::DUMMY_NODE_ID, + DefPathData::GlobalMetaData(instance.name()), + DefIndexAddressSpace::High, + Mark::root() + ); + + // Make sure calling def_index does not crash. + instance.def_index(&definitions.table); + })* + } + + pub fn def_index(&self, def_path_table: &DefPathTable) -> DefIndex { + let def_key = DefKey { + parent: Some(CRATE_DEF_INDEX), + disambiguated_data: DisambiguatedDefPathData { + data: DefPathData::GlobalMetaData(self.name()), + disambiguator: 0, + } + }; + + def_path_table.key_to_index[&def_key] + } + + fn name(&self) -> Symbol { + + let string = match *self { + $( + GlobalMetaDataKind::$variant => { + concat!("{{GlobalMetaData::", stringify!($variant), "}}") + } + )* + }; + + Symbol::intern(string) } } - } + ) } + +define_global_metadata_kind!(pub enum GlobalMetaDataKind { + Krate, + CrateDeps, + DylibDependencyFormats, + LangItems, + LangItemsMissing, + NativeLibraries, + CodeMap, + Impls, + ExportedSymbols +}); diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 176760c255c0..a1875cd46a0c 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -15,7 +15,7 @@ pub use self::def_collector::{DefCollector, MacroInvocationData}; pub use self::definitions::{Definitions, DefKey, DefPath, DefPathData, DisambiguatedDefPathData, DefPathHash}; -use dep_graph::{DepGraph, DepNode}; +use dep_graph::{DepGraph, DepNode, DepKind}; use hir::def_id::{CRATE_DEF_INDEX, DefId, DefIndex, DefIndexAddressSpace}; @@ -235,7 +235,7 @@ impl Forest { } pub fn krate<'hir>(&'hir self) -> &'hir Crate { - self.dep_graph.read(DepNode::Krate); + self.dep_graph.read(DepNode::new_no_params(DepKind::Krate)); &self.krate } } @@ -280,7 +280,7 @@ impl<'hir> Map<'hir> { self.dep_graph.read(self.dep_node(id)); } - fn dep_node(&self, id0: NodeId) -> DepNode { + fn dep_node(&self, id0: NodeId) -> DepNode { let mut id = id0; let mut last_expr = None; loop { @@ -289,14 +289,16 @@ impl<'hir> Map<'hir> { EntryItem(..) | EntryTraitItem(..) | EntryImplItem(..) => { + let def_index = self.definitions.opt_def_index(id).unwrap(); + let def_path_hash = self.definitions.def_path_hash(def_index); + if let Some(last_id) = last_expr { // The body may have a separate dep node if entry.is_body_owner(last_id) { - let def_id = self.local_def_id(id); - return DepNode::HirBody(def_id); + return def_path_hash.to_dep_node(DepKind::HirBody); } } - return DepNode::Hir(self.local_def_id(id)); + return def_path_hash.to_dep_node(DepKind::Hir); } EntryVariant(p, v) => { @@ -305,8 +307,9 @@ impl<'hir> Map<'hir> { if last_expr.is_some() { if v.node.disr_expr.map(|e| e.node_id) == last_expr { // The enum parent holds both Hir and HirBody nodes. - let def_id = self.local_def_id(id); - return DepNode::HirBody(def_id); + let def_index = self.definitions.opt_def_index(id).unwrap(); + let def_path_hash = self.definitions.def_path_hash(def_index); + return def_path_hash.to_dep_node(DepKind::HirBody); } } } @@ -331,7 +334,8 @@ impl<'hir> Map<'hir> { } RootCrate => { - return DepNode::Hir(DefId::local(CRATE_DEF_INDEX)); + let def_path_hash = self.definitions.def_path_hash(CRATE_DEF_INDEX); + return def_path_hash.to_dep_node(DepKind::Hir); } NotPresent => @@ -339,8 +343,11 @@ impl<'hir> Map<'hir> { // present in the map for whatever reason, but // they *do* have def-ids. So if we encounter an // empty hole, check for that case. - return self.opt_local_def_id(id) - .map(|def_id| DepNode::Hir(def_id)) + return self.definitions.opt_def_index(id) + .map(|def_index| { + let def_path_hash = self.definitions.def_path_hash(def_index); + def_path_hash.to_dep_node(DepKind::Hir) + }) .unwrap_or_else(|| { bug!("Walking parents from `{}` \ led to `NotPresent` at `{}`", @@ -497,7 +504,7 @@ impl<'hir> Map<'hir> { } pub fn trait_impls(&self, trait_did: DefId) -> &'hir [NodeId] { - self.dep_graph.read(DepNode::AllLocalTraitImpls); + self.dep_graph.read(DepNode::new_no_params(DepKind::AllLocalTraitImpls)); // NB: intentionally bypass `self.forest.krate()` so that we // do not trigger a read of the whole krate here @@ -505,7 +512,7 @@ impl<'hir> Map<'hir> { } pub fn trait_default_impl(&self, trait_did: DefId) -> Option { - self.dep_graph.read(DepNode::AllLocalTraitImpls); + self.dep_graph.read(DepNode::new_no_params(DepKind::AllLocalTraitImpls)); // NB: intentionally bypass `self.forest.krate()` so that we // do not trigger a read of the whole krate here @@ -520,8 +527,9 @@ impl<'hir> Map<'hir> { /// invoking `krate.attrs` because it registers a tighter /// dep-graph access. pub fn krate_attrs(&self) -> &'hir [ast::Attribute] { - let crate_root_def_id = DefId::local(CRATE_DEF_INDEX); - self.dep_graph.read(DepNode::Hir(crate_root_def_id)); + let def_path_hash = self.definitions.def_path_hash(CRATE_DEF_INDEX); + + self.dep_graph.read(def_path_hash.to_dep_node(DepKind::Hir)); &self.forest.krate.attrs } @@ -754,11 +762,8 @@ impl<'hir> Map<'hir> { } } - pub fn get_inlined_body(&self, def_id: DefId) -> Option<&'hir Body> { - self.inlined_bodies.borrow().get(&def_id).map(|&body| { - self.dep_graph.read(DepNode::MetaData(def_id)); - body - }) + pub fn get_inlined_body_untracked(&self, def_id: DefId) -> Option<&'hir Body> { + self.inlined_bodies.borrow().get(&def_id).cloned() } pub fn intern_inlined_body(&self, def_id: DefId, body: Body) -> &'hir Body { diff --git a/src/librustc/ich/caching_codemap_view.rs b/src/librustc/ich/caching_codemap_view.rs index 9aecd8ad8360..bf47b9bb9d43 100644 --- a/src/librustc/ich/caching_codemap_view.rs +++ b/src/librustc/ich/caching_codemap_view.rs @@ -29,8 +29,8 @@ pub struct CachingCodemapView<'tcx> { time_stamp: usize, } -impl<'tcx> CachingCodemapView<'tcx> { - pub fn new<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CachingCodemapView<'tcx> { +impl<'gcx> CachingCodemapView<'gcx> { + pub fn new<'a, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> CachingCodemapView<'gcx> { let codemap = tcx.sess.codemap(); let files = codemap.files(); let first_file = files[0].clone(); diff --git a/src/librustc/ich/fingerprint.rs b/src/librustc/ich/fingerprint.rs index 8308c756c053..2391b61253aa 100644 --- a/src/librustc/ich/fingerprint.rs +++ b/src/librustc/ich/fingerprint.rs @@ -31,9 +31,20 @@ impl Fingerprint { self.0 } + #[inline] + pub fn combine(self, other: Fingerprint) -> Fingerprint { + // See https://stackoverflow.com/a/27952689 on why this function is + // implemented this way. + Fingerprint( + self.0.wrapping_mul(3).wrapping_add(other.0), + self.1.wrapping_mul(3).wrapping_add(other.1) + ) + } + pub fn to_hex(&self) -> String { format!("{:x}{:x}", self.0, self.1) } + } impl ::std::fmt::Display for Fingerprint { diff --git a/src/librustc/ich/hcx.rs b/src/librustc/ich/hcx.rs index a83554889418..2784a7bd024f 100644 --- a/src/librustc/ich/hcx.rs +++ b/src/librustc/ich/hcx.rs @@ -33,9 +33,9 @@ use rustc_data_structures::accumulate_vec::AccumulateVec; /// 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>, +pub struct StableHashingContext<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { + tcx: ty::TyCtxt<'a, 'gcx, 'tcx>, + codemap: CachingCodemapView<'gcx>, hash_spans: bool, hash_bodies: bool, overflow_checks_enabled: bool, @@ -51,9 +51,9 @@ pub enum NodeIdHashingMode { HashTraitsInScope, } -impl<'a, 'tcx: 'a> StableHashingContext<'a, 'tcx> { +impl<'a, 'gcx, 'tcx> StableHashingContext<'a, 'gcx, 'tcx> { - pub fn new(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>) -> Self { + pub fn new(tcx: ty::TyCtxt<'a, 'gcx, 'tcx>) -> Self { let hash_spans_initial = tcx.sess.opts.debuginfo != NoDebugInfo; let check_overflow_initial = tcx.sess.overflow_checks(); @@ -111,7 +111,7 @@ impl<'a, 'tcx: 'a> StableHashingContext<'a, 'tcx> { } #[inline] - pub fn tcx(&self) -> ty::TyCtxt<'a, 'tcx, 'tcx> { + pub fn tcx(&self) -> ty::TyCtxt<'a, 'gcx, 'tcx> { self.tcx } @@ -131,7 +131,7 @@ impl<'a, 'tcx: 'a> StableHashingContext<'a, 'tcx> { } #[inline] - pub fn codemap(&mut self) -> &mut CachingCodemapView<'tcx> { + pub fn codemap(&mut self) -> &mut CachingCodemapView<'gcx> { &mut self.codemap } @@ -195,9 +195,9 @@ impl<'a, 'tcx: 'a> StableHashingContext<'a, 'tcx> { } -impl<'a, 'tcx> HashStable> for ast::NodeId { +impl<'a, 'gcx, 'tcx> HashStable> for ast::NodeId { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { match hcx.node_id_hashing_mode { NodeIdHashingMode::Ignore => { @@ -230,7 +230,7 @@ impl<'a, 'tcx> HashStable> for ast::NodeId { } } -impl<'a, 'tcx> HashStable> for Span { +impl<'a, 'gcx, '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 @@ -242,7 +242,7 @@ impl<'a, 'tcx> HashStable> for Span { // 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>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { use syntax_pos::Pos; @@ -305,15 +305,16 @@ impl<'a, 'tcx> HashStable> for Span { } } -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) +pub fn hash_stable_hashmap<'a, 'gcx, 'tcx, K, V, R, SK, F, W>( + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, + hasher: &mut StableHasher, + map: &HashMap, + extract_stable_key: F) where K: Eq + std_hash::Hash, - V: HashStable>, + V: HashStable>, R: std_hash::BuildHasher, - SK: HashStable> + Ord + Clone, - F: Fn(&mut StableHashingContext<'a, 'tcx>, &K) -> SK, + SK: HashStable> + Ord + Clone, + F: Fn(&mut StableHashingContext<'a, 'gcx, 'tcx>, &K) -> SK, W: StableHasherResult, { let mut keys: Vec<_> = map.keys() @@ -327,14 +328,15 @@ pub fn hash_stable_hashmap<'a, 'tcx, K, V, R, SK, F, W>(hcx: &mut StableHashingC } } -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) +pub fn hash_stable_hashset<'a, 'tcx, 'gcx, K, R, SK, F, W>( + hcx: &mut StableHashingContext<'a, 'gcx, '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, + SK: HashStable> + Ord + Clone, + F: Fn(&mut StableHashingContext<'a, 'gcx, 'tcx>, &K) -> SK, W: StableHasherResult, { let mut keys: Vec<_> = set.iter() @@ -344,10 +346,11 @@ pub fn hash_stable_hashset<'a, 'tcx, K, R, SK, F, W>(hcx: &mut StableHashingCont 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>, +pub fn hash_stable_nodemap<'a, 'tcx, 'gcx, V, W>( + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, + hasher: &mut StableHasher, + map: &NodeMap) + where V: HashStable>, W: StableHasherResult, { hash_stable_hashmap(hcx, hasher, map, |hcx, node_id| { @@ -356,14 +359,15 @@ pub fn hash_stable_nodemap<'a, 'tcx, V, W>(hcx: &mut StableHashingContext<'a, 't } -pub fn hash_stable_btreemap<'a, 'tcx, K, V, SK, F, W>(hcx: &mut StableHashingContext<'a, 'tcx>, - hasher: &mut StableHasher, - map: &BTreeMap, - extract_stable_key: F) +pub fn hash_stable_btreemap<'a, 'tcx, 'gcx, K, V, SK, F, W>( + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, + hasher: &mut StableHasher, + map: &BTreeMap, + extract_stable_key: F) where K: Eq + Ord, - V: HashStable>, - SK: HashStable> + Ord + Clone, - F: Fn(&mut StableHashingContext<'a, 'tcx>, &K) -> SK, + V: HashStable>, + SK: HashStable> + Ord + Clone, + F: Fn(&mut StableHashingContext<'a, 'gcx, 'tcx>, &K) -> SK, W: StableHasherResult, { let mut keys: Vec<_> = map.keys() diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index c582cac67e22..7f7a545df960 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -12,7 +12,7 @@ //! types in no particular order. use hir; -use hir::def_id::DefId; +use hir::def_id::{DefId, CrateNum, CRATE_DEF_INDEX}; use ich::{StableHashingContext, NodeIdHashingMode}; use std::mem; @@ -21,20 +21,20 @@ use syntax::ast; use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult}; -impl<'a, 'tcx> HashStable> for DefId { +impl<'a, 'gcx, 'tcx> HashStable> for DefId { #[inline] fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { hcx.def_path_hash(*self).hash_stable(hcx, hasher); } } -impl<'a, 'tcx> HashStable> for hir::HirId { +impl<'a, 'gcx, 'tcx> HashStable> for hir::HirId { #[inline] fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { let hir::HirId { owner, @@ -46,6 +46,19 @@ impl<'a, 'tcx> HashStable> for hir::HirId { } } + +impl<'a, 'gcx, 'tcx> HashStable> for CrateNum { + #[inline] + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, + hasher: &mut StableHasher) { + hcx.def_path_hash(DefId { + krate: *self, + index: CRATE_DEF_INDEX + }).hash_stable(hcx, hasher); + } +} + impl_stable_hash_for!(tuple_struct hir::ItemLocalId { index }); // The following implementations of HashStable for ItemId, TraitItemId, and @@ -55,9 +68,9 @@ impl_stable_hash_for!(tuple_struct hir::ItemLocalId { index }); // 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 { +impl<'a, 'gcx, 'tcx> HashStable> for hir::ItemId { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { let hir::ItemId { id @@ -69,9 +82,9 @@ impl<'a, 'tcx> HashStable> for hir::ItemId { } } -impl<'a, 'tcx> HashStable> for hir::TraitItemId { +impl<'a, 'gcx, 'tcx> HashStable> for hir::TraitItemId { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { let hir::TraitItemId { node_id @@ -83,9 +96,9 @@ impl<'a, 'tcx> HashStable> for hir::TraitItemId { } } -impl<'a, 'tcx> HashStable> for hir::ImplItemId { +impl<'a, 'gcx, 'tcx> HashStable> for hir::ImplItemId { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { let hir::ImplItemId { node_id @@ -215,9 +228,9 @@ impl_stable_hash_for!(struct hir::TypeBinding { span }); -impl<'a, 'tcx> HashStable> for hir::Ty { +impl<'a, 'gcx, 'tcx> HashStable> for hir::Ty { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { let node_id_hashing_mode = match self.node { hir::TySlice(..) | @@ -299,9 +312,9 @@ impl_stable_hash_for!(enum hir::FunctionRetTy { Return(t) }); -impl<'a, 'tcx> HashStable> for hir::TraitRef { +impl<'a, 'gcx, 'tcx> HashStable> for hir::TraitRef { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { let hir::TraitRef { ref path, @@ -338,9 +351,9 @@ impl_stable_hash_for!(struct hir::MacroDef { }); -impl<'a, 'tcx> HashStable> for hir::Block { +impl<'a, 'gcx, 'tcx> HashStable> for hir::Block { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { let hir::Block { ref stmts, @@ -386,9 +399,9 @@ impl<'a, 'tcx> HashStable> for hir::Block { } } -impl<'a, 'tcx> HashStable> for hir::Pat { +impl<'a, 'gcx, 'tcx> HashStable> for hir::Pat { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { let node_id_hashing_mode = match self.node { hir::PatKind::Wild | @@ -529,9 +542,9 @@ impl_stable_hash_for!(enum hir::UnsafeSource { UserProvided }); -impl<'a, 'tcx> HashStable> for hir::Expr { +impl<'a, 'gcx, 'tcx> HashStable> for hir::Expr { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { hcx.while_hashing_hir_bodies(true, |hcx| { let hir::Expr { @@ -652,9 +665,9 @@ impl_stable_hash_for!(enum hir::LoopSource { ForLoop }); -impl<'a, 'tcx> HashStable> for hir::MatchSource { +impl<'a, 'gcx, 'tcx> HashStable> for hir::MatchSource { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { use hir::MatchSource; @@ -703,9 +716,9 @@ impl_stable_hash_for!(enum hir::ScopeTarget { Loop(loop_id_result) }); -impl<'a, 'tcx> HashStable> for ast::Ident { +impl<'a, 'gcx, 'tcx> HashStable> for ast::Ident { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { let ast::Ident { ref name, @@ -716,9 +729,9 @@ impl<'a, 'tcx> HashStable> for ast::Ident { } } -impl<'a, 'tcx> HashStable> for hir::TraitItem { +impl<'a, 'gcx, 'tcx> HashStable> for hir::TraitItem { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { let hir::TraitItem { id, @@ -749,9 +762,9 @@ impl_stable_hash_for!(enum hir::TraitItemKind { Type(bounds, rhs) }); -impl<'a, 'tcx> HashStable> for hir::ImplItem { +impl<'a, 'gcx, 'tcx> HashStable> for hir::ImplItem { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { let hir::ImplItem { id, @@ -781,9 +794,9 @@ impl_stable_hash_for!(enum hir::ImplItemKind { Type(t) }); -impl<'a, 'tcx> HashStable> for hir::Visibility { +impl<'a, 'gcx, 'tcx> HashStable> for hir::Visibility { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { @@ -802,9 +815,9 @@ impl<'a, 'tcx> HashStable> for hir::Visibility { } } -impl<'a, 'tcx> HashStable> for hir::Defaultness { +impl<'a, 'gcx, 'tcx> HashStable> for hir::Defaultness { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { @@ -823,9 +836,9 @@ impl_stable_hash_for!(enum hir::ImplPolarity { Negative }); -impl<'a, 'tcx> HashStable> for hir::Mod { +impl<'a, 'gcx, 'tcx> HashStable> for hir::Mod { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { let hir::Mod { inner, @@ -878,9 +891,9 @@ impl_stable_hash_for!(enum hir::VariantData { Unit(id) }); -impl<'a, 'tcx> HashStable> for hir::Item { +impl<'a, 'gcx, 'tcx> HashStable> for hir::Item { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { let node_id_hashing_mode = match self.node { hir::ItemExternCrate(..) | @@ -961,9 +974,10 @@ impl_stable_hash_for!(struct hir::ImplItemRef { defaultness }); -impl<'a, 'tcx> HashStable> for hir::AssociatedItemKind { +impl<'a, 'gcx, 'tcx> HashStable> +for hir::AssociatedItemKind { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { @@ -1008,9 +1022,9 @@ impl_stable_hash_for!(struct hir::Body { value }); -impl<'a, 'tcx> HashStable> for hir::BodyId { +impl<'a, 'gcx, 'tcx> HashStable> for hir::BodyId { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { if hcx.hash_bodies() { hcx.tcx().hir.body(*self).hash_stable(hcx, hasher); @@ -1024,9 +1038,9 @@ impl_stable_hash_for!(struct hir::InlineAsmOutput { is_indirect }); -impl<'a, 'tcx> HashStable> for hir::GlobalAsm { +impl<'a, 'gcx, 'tcx> HashStable> for hir::GlobalAsm { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { let hir::GlobalAsm { asm, @@ -1037,9 +1051,9 @@ impl<'a, 'tcx> HashStable> for hir::GlobalAsm { } } -impl<'a, 'tcx> HashStable> for hir::InlineAsm { +impl<'a, 'gcx, 'tcx> HashStable> for hir::InlineAsm { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { let hir::InlineAsm { asm, @@ -1114,10 +1128,11 @@ impl_stable_hash_for!(enum hir::Constness { NotConst }); -impl<'a, 'tcx> HashStable> for hir::def_id::DefIndex { +impl<'a, 'gcx, 'tcx> HashStable> +for hir::def_id::DefIndex { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { DefId::local(*self).hash_stable(hcx, hasher); } @@ -1129,9 +1144,10 @@ impl_stable_hash_for!(struct hir::def::Export { span }); -impl<'a, 'tcx> HashStable> for ::middle::lang_items::LangItem { +impl<'a, 'gcx, 'tcx> HashStable> +for ::middle::lang_items::LangItem { fn hash_stable(&self, - _: &mut StableHashingContext<'a, 'tcx>, + _: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { ::std::hash::Hash::hash(self, hasher); } diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs index edaeb596fe58..cb017b7f8864 100644 --- a/src/librustc/ich/impls_mir.rs +++ b/src/librustc/ich/impls_mir.rs @@ -32,10 +32,11 @@ impl_stable_hash_for!(struct mir::LocalDecl<'tcx> { impl_stable_hash_for!(struct mir::UpvarDecl { debug_name, by_ref }); impl_stable_hash_for!(struct mir::BasicBlockData<'tcx> { statements, terminator, is_cleanup }); -impl<'a, 'tcx> HashStable> for mir::Terminator<'tcx> { +impl<'a, 'gcx, 'tcx> HashStable> +for mir::Terminator<'tcx> { #[inline] fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { let mir::Terminator { ref kind, @@ -72,59 +73,61 @@ impl<'a, 'tcx> HashStable> for mir::Terminator<'t } -impl<'a, 'tcx> HashStable> for mir::Local { +impl<'a, 'gcx, 'tcx> HashStable> for mir::Local { #[inline] fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { use rustc_data_structures::indexed_vec::Idx; self.index().hash_stable(hcx, hasher); } } -impl<'a, 'tcx> HashStable> for mir::BasicBlock { +impl<'a, 'gcx, 'tcx> HashStable> for mir::BasicBlock { #[inline] fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { use rustc_data_structures::indexed_vec::Idx; self.index().hash_stable(hcx, hasher); } } -impl<'a, 'tcx> HashStable> for mir::Field { +impl<'a, 'gcx, 'tcx> HashStable> for mir::Field { #[inline] fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { use rustc_data_structures::indexed_vec::Idx; self.index().hash_stable(hcx, hasher); } } -impl<'a, 'tcx> HashStable> for mir::VisibilityScope { +impl<'a, 'gcx, 'tcx> HashStable> +for mir::VisibilityScope { #[inline] fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { use rustc_data_structures::indexed_vec::Idx; self.index().hash_stable(hcx, hasher); } } -impl<'a, 'tcx> HashStable> for mir::Promoted { +impl<'a, 'gcx, 'tcx> HashStable> for mir::Promoted { #[inline] fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, '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> { +impl<'a, 'gcx, 'tcx> HashStable> +for mir::TerminatorKind<'tcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); @@ -182,9 +185,10 @@ impl<'a, 'tcx> HashStable> for mir::TerminatorKin } } -impl<'a, 'tcx> HashStable> for mir::AssertMessage<'tcx> { +impl<'a, 'gcx, 'tcx> HashStable> +for mir::AssertMessage<'tcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); @@ -202,9 +206,10 @@ impl<'a, 'tcx> HashStable> for mir::AssertMessage impl_stable_hash_for!(struct mir::Statement<'tcx> { source_info, kind }); -impl<'a, 'tcx> HashStable> for mir::StatementKind<'tcx> { +impl<'a, 'gcx, 'tcx> HashStable> +for mir::StatementKind<'tcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); @@ -221,6 +226,9 @@ impl<'a, 'tcx> HashStable> for mir::StatementKind mir::StatementKind::StorageDead(ref lvalue) => { lvalue.hash_stable(hcx, hasher); } + mir::StatementKind::EndRegion(ref extents) => { + extents.hash_stable(hcx, hasher); + } mir::StatementKind::Nop => {} mir::StatementKind::InlineAsm { ref asm, ref outputs, ref inputs } => { asm.hash_stable(hcx, hasher); @@ -231,9 +239,9 @@ impl<'a, 'tcx> HashStable> for mir::StatementKind } } -impl<'a, 'tcx> HashStable> for mir::Lvalue<'tcx> { +impl<'a, 'gcx, 'tcx> HashStable> for mir::Lvalue<'tcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { @@ -250,12 +258,13 @@ impl<'a, 'tcx> HashStable> for mir::Lvalue<'tcx> } } -impl<'a, 'tcx, B, V> HashStable> for mir::Projection<'tcx, B, V> - where B: HashStable>, - V: HashStable> +impl<'a, 'gcx, 'tcx, B, V> HashStable> +for mir::Projection<'tcx, B, V> + where B: HashStable>, + V: HashStable> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { let mir::Projection { ref base, @@ -267,11 +276,12 @@ impl<'a, 'tcx, B, V> HashStable> for mir::Project } } -impl<'a, 'tcx, V> HashStable> for mir::ProjectionElem<'tcx, V> - where V: HashStable> +impl<'a, 'gcx, 'tcx, V> HashStable> +for mir::ProjectionElem<'tcx, V> + where V: HashStable> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { @@ -302,9 +312,9 @@ impl<'a, 'tcx, V> HashStable> for mir::Projection impl_stable_hash_for!(struct mir::VisibilityScopeData { span, parent_scope }); -impl<'a, 'tcx> HashStable> for mir::Operand<'tcx> { +impl<'a, 'gcx, 'tcx> HashStable> for mir::Operand<'tcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); @@ -319,9 +329,9 @@ impl<'a, 'tcx> HashStable> for mir::Operand<'tcx> } } -impl<'a, 'tcx> HashStable> for mir::Rvalue<'tcx> { +impl<'a, 'gcx, 'tcx> HashStable> for mir::Rvalue<'tcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); @@ -379,9 +389,10 @@ impl_stable_hash_for!(enum mir::CastKind { Unsize }); -impl<'a, 'tcx> HashStable> for mir::AggregateKind<'tcx> { +impl<'a, 'gcx, 'tcx> HashStable> +for mir::AggregateKind<'tcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { @@ -435,9 +446,9 @@ impl_stable_hash_for!(enum mir::NullOp { impl_stable_hash_for!(struct mir::Constant<'tcx> { span, ty, literal }); -impl<'a, 'tcx> HashStable> for mir::Literal<'tcx> { +impl<'a, 'gcx, 'tcx> HashStable> for mir::Literal<'tcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index f6ad97445e8b..b9cc3b5fb937 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -27,20 +27,21 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult}; use rustc_data_structures::accumulate_vec::AccumulateVec; -impl<'a, 'tcx> HashStable> for ::syntax::symbol::InternedString { +impl<'a, 'gcx, 'tcx> HashStable> +for ::syntax::symbol::InternedString { #[inline] fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { let s: &str = &**self; s.hash_stable(hcx, hasher); } } -impl<'a, 'tcx> HashStable> for ast::Name { +impl<'a, 'gcx, 'tcx> HashStable> for ast::Name { #[inline] fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { self.as_str().hash_stable(hcx, hasher); } @@ -82,9 +83,10 @@ impl_stable_hash_for!(enum ::syntax::abi::Abi { 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 { +impl<'a, 'gcx, 'tcx> HashStable> +for ::syntax::attr::StabilityLevel { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { @@ -135,9 +137,9 @@ impl_stable_hash_for!(struct ::syntax::ast::Lifetime { id, span, ident }); 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] { +impl<'a, 'gcx, 'tcx> HashStable> for [ast::Attribute] { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { // Some attributes are always ignored during hashing. let filtered: AccumulateVec<[&ast::Attribute; 8]> = self @@ -155,9 +157,9 @@ impl<'a, 'tcx> HashStable> for [ast::Attribute] { } } -impl<'a, 'tcx> HashStable> for ast::Attribute { +impl<'a, 'gcx, 'tcx> HashStable> for ast::Attribute { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, '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)); @@ -184,9 +186,10 @@ impl<'a, 'tcx> HashStable> for ast::Attribute { } } -impl<'a, 'tcx> HashStable> for tokenstream::TokenTree { +impl<'a, 'gcx, 'tcx> HashStable> +for tokenstream::TokenTree { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { @@ -205,9 +208,10 @@ impl<'a, 'tcx> HashStable> for tokenstream::Token } } -impl<'a, 'tcx> HashStable> for tokenstream::TokenStream { +impl<'a, 'gcx, 'tcx> HashStable> +for tokenstream::TokenStream { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { for sub_tt in self.trees() { sub_tt.hash_stable(hcx, hasher); @@ -215,8 +219,8 @@ impl<'a, 'tcx> HashStable> for tokenstream::Token } } -fn hash_token<'a, 'tcx, W: StableHasherResult>(token: &token::Token, - hcx: &mut StableHashingContext<'a, 'tcx>, +fn hash_token<'a, 'gcx, 'tcx, W: StableHasherResult>(token: &token::Token, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher, error_reporting_span: Span) { mem::discriminant(token).hash_stable(hcx, hasher); @@ -322,9 +326,9 @@ impl_stable_hash_for!(enum ::syntax::ast::MetaItemKind { NameValue(lit) }); -impl<'a, 'tcx> HashStable> for FileMap { +impl<'a, 'gcx, 'tcx> HashStable> for FileMap { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { let FileMap { ref name, @@ -332,6 +336,8 @@ impl<'a, 'tcx> HashStable> for FileMap { crate_of_origin, // Do not hash the source as it is not encoded src: _, + src_hash, + external_src: _, start_pos, end_pos: _, ref lines, @@ -346,6 +352,8 @@ impl<'a, 'tcx> HashStable> for FileMap { index: CRATE_DEF_INDEX, }.hash_stable(hcx, hasher); + src_hash.hash_stable(hcx, hasher); + // We only hash the relative position within this filemap let lines = lines.borrow(); lines.len().hash_stable(hcx, hasher); diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index a362dc31ff18..4e78d79ef873 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -19,27 +19,30 @@ use std::mem; use syntax_pos::symbol::InternedString; use ty; -impl<'a, 'tcx, T> HashStable> for &'tcx ty::Slice - where T: HashStable> { +impl<'a, 'gcx, 'tcx, T> HashStable> +for &'tcx ty::Slice + where T: HashStable> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { (&self[..]).hash_stable(hcx, hasher); } } -impl<'a, 'tcx> HashStable> for ty::subst::Kind<'tcx> { +impl<'a, 'gcx, 'tcx> HashStable> +for ty::subst::Kind<'tcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, '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 { +impl<'a, 'gcx, 'tcx> HashStable> +for ty::RegionKind { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { @@ -72,9 +75,10 @@ impl<'a, 'tcx> HashStable> for ty::RegionKind { } } -impl<'a, 'tcx> HashStable> for ty::adjustment::AutoBorrow<'tcx> { +impl<'a, 'gcx, 'tcx> HashStable> +for ty::adjustment::AutoBorrow<'tcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { @@ -89,9 +93,10 @@ impl<'a, 'tcx> HashStable> for ty::adjustment::Au } } -impl<'a, 'tcx> HashStable> for ty::adjustment::Adjust<'tcx> { +impl<'a, 'gcx, 'tcx> HashStable> +for ty::adjustment::Adjust<'tcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { @@ -122,9 +127,10 @@ impl_stable_hash_for!(enum ty::BorrowKind { MutBorrow }); -impl<'a, 'tcx> HashStable> for ty::UpvarCapture<'tcx> { +impl<'a, 'gcx, 'tcx> HashStable> +for ty::UpvarCapture<'tcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { @@ -143,11 +149,11 @@ impl_stable_hash_for!(struct ty::FnSig<'tcx> { abi }); -impl<'a, 'tcx, T> HashStable> for ty::Binder - where T: HashStable> + ty::fold::TypeFoldable<'tcx> +impl<'a, 'gcx, 'tcx, T> HashStable> for ty::Binder + where T: HashStable> + ty::fold::TypeFoldable<'tcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { hcx.tcx().anonymize_late_bound_regions(self).0.hash_stable(hcx, hasher); } @@ -166,12 +172,13 @@ 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>, +impl<'a, 'gcx, 'tcx, A, B> HashStable> +for ty::OutlivesPredicate + where A: HashStable>, + B: HashStable>, { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { let ty::OutlivesPredicate(ref a, ref b) = *self; a.hash_stable(hcx, hasher); @@ -183,9 +190,9 @@ impl_stable_hash_for!(struct ty::ProjectionPredicate<'tcx> { projection_ty, ty } impl_stable_hash_for!(struct ty::ProjectionTy<'tcx> { trait_ref, item_def_id }); -impl<'a, 'tcx> HashStable> for ty::Predicate<'tcx> { +impl<'a, 'gcx, 'tcx> HashStable> for ty::Predicate<'tcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { @@ -221,9 +228,9 @@ impl<'a, 'tcx> HashStable> for ty::Predicate<'tcx } } -impl<'a, 'tcx> HashStable> for ty::AdtFlags { +impl<'a, 'gcx, 'tcx> HashStable> for ty::AdtFlags { fn hash_stable(&self, - _: &mut StableHashingContext<'a, 'tcx>, + _: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { std_hash::Hash::hash(self, hasher); } @@ -248,10 +255,10 @@ impl_stable_hash_for!(struct ty::FieldDef { vis }); -impl<'a, 'tcx> HashStable> +impl<'a, 'gcx, 'tcx> HashStable> for ::middle::const_val::ConstVal<'tcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { use middle::const_val::ConstVal; @@ -324,9 +331,9 @@ impl_stable_hash_for!(enum ty::adjustment::CustomCoerceUnsized { Struct(index) }); -impl<'a, 'tcx> HashStable> for ty::Generics { +impl<'a, 'gcx, 'tcx> HashStable> for ty::Generics { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { let ty::Generics { parent, @@ -350,9 +357,10 @@ impl<'a, 'tcx> HashStable> for ty::Generics { } } -impl<'a, 'tcx> HashStable> for ty::RegionParameterDef { +impl<'a, 'gcx, 'tcx> HashStable> +for ty::RegionParameterDef { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { let ty::RegionParameterDef { name, @@ -379,12 +387,12 @@ impl_stable_hash_for!(struct ty::TypeParameterDef { }); -impl<'a, 'tcx, T> HashStable> +impl<'a, 'gcx, 'tcx, T> HashStable> for ::middle::resolve_lifetime::Set1 - where T: HashStable> + where T: HashStable> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { use middle::resolve_lifetime::Set1; @@ -427,10 +435,11 @@ impl_stable_hash_for!(enum ty::cast::CastKind { FnPtrAddrCast }); -impl<'a, 'tcx> HashStable> for ::middle::region::CodeExtent +impl<'a, 'gcx, 'tcx> HashStable> +for ::middle::region::CodeExtent { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { use middle::region::CodeExtent; @@ -472,10 +481,11 @@ impl_stable_hash_for!(enum ty::BoundRegion { BrEnv }); -impl<'a, 'tcx> HashStable> for ty::TypeVariants<'tcx> +impl<'a, 'gcx, 'tcx> HashStable> +for ty::TypeVariants<'tcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { use ty::TypeVariants::*; @@ -563,10 +573,11 @@ impl_stable_hash_for!(struct ty::TypeAndMut<'tcx> { mutbl }); -impl<'a, 'tcx> HashStable> for ty::ExistentialPredicate<'tcx> +impl<'a, 'gcx, 'tcx> HashStable> +for ty::ExistentialPredicate<'tcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { @@ -595,9 +606,10 @@ impl_stable_hash_for!(struct ty::ExistentialProjection<'tcx> { }); -impl<'a, 'tcx> HashStable> for ty::TypeckTables<'tcx> { +impl<'a, 'gcx, 'tcx> HashStable> +for ty::TypeckTables<'tcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { let ty::TypeckTables { ref type_dependent_defs, diff --git a/src/librustc/infer/README.md b/src/librustc/infer/README.md index 68e64b8b7bfc..b4075f697309 100644 --- a/src/librustc/infer/README.md +++ b/src/librustc/infer/README.md @@ -236,4 +236,4 @@ yet, that's what we're trying to find! In our code, we opt to unify We make use of a trait-like implementation strategy to consolidate duplicated code between subtypes, GLB, and LUB computations. See the -section on "Type Combining" below for details. +section on "Type Combining" in combine.rs for more details. diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 0515e1cc3043..11bac21bc429 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -74,6 +74,7 @@ use syntax_pos::{Pos, Span}; use errors::{DiagnosticBuilder, DiagnosticStyledString}; mod note; +mod need_type_info; impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn note_and_explain_region(self, diff --git a/src/librustc/infer/error_reporting/need_type_info.rs b/src/librustc/infer/error_reporting/need_type_info.rs new file mode 100644 index 000000000000..7361d66428f6 --- /dev/null +++ b/src/librustc/infer/error_reporting/need_type_info.rs @@ -0,0 +1,153 @@ +// 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::{self, map, Local, Pat, Body}; +use hir::intravisit::{self, Visitor, NestedVisitorMap}; +use infer::InferCtxt; +use infer::type_variable::TypeVariableOrigin; +use ty::{self, Ty, TyInfer, TyVar}; + +use syntax::ast::NodeId; +use syntax_pos::Span; + +struct FindLocalByTypeVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { + infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, + target_ty: &'a Ty<'tcx>, + hir_map: &'a hir::map::Map<'gcx>, + found_local_pattern: Option<&'gcx Pat>, + found_arg_pattern: Option<&'gcx Pat>, +} + +impl<'a, 'gcx, 'tcx> FindLocalByTypeVisitor<'a, 'gcx, 'tcx> { + fn node_matches_type(&mut self, node_id: NodeId) -> bool { + let ty_opt = self.infcx.in_progress_tables.and_then(|tables| { + tables.borrow().node_id_to_type_opt(node_id) + }); + match ty_opt { + 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, + } + }) + } + None => 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: &'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> { + fn extract_type_name(&self, ty: &'a Ty<'tcx>) -> String { + if let ty::TyInfer(ty::TyVar(ty_vid)) = (*ty).sty { + let ty_vars = self.type_variables.borrow(); + if let TypeVariableOrigin::TypeParameterDefinition(_, name) = + *ty_vars.var_origin(ty_vid) { + name.to_string() + } else { + ty.to_string() + } + } else { + ty.to_string() + } + } + + 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 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, + 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(body_id.node_id) { + Some(map::NodeExpr(expr)) => local_visitor.visit_expr(expr), + _ => () + } + + 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() { + labels.push((pattern.span, format!("consider giving `{}` a type", simple_name))); + } else { + 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(); + } +} diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index f5869b8a20fa..f96e8c389d68 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -19,11 +19,8 @@ pub use self::freshen::TypeFreshener; pub use self::region_inference::{GenericKind, VerifyBound}; use hir::def_id::DefId; -use hir; 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; use mir::tcx::LvalueTy; use ty::subst::{Kind, Subst, Substs}; @@ -34,13 +31,12 @@ use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use ty::relate::RelateResult; use traits::{self, ObligationCause, PredicateObligations, Reveal}; use rustc_data_structures::unify::{self, UnificationTable}; -use std::cell::{Cell, RefCell, Ref, RefMut}; +use std::cell::{Cell, RefCell, Ref}; use std::fmt; -use std::ops::Deref; use syntax::ast; use errors::DiagnosticBuilder; use syntax_pos::{self, Span, DUMMY_SP}; -use util::nodemap::{FxHashMap, FxHashSet}; +use util::nodemap::FxHashMap; use arena::DroplessArena; use self::combine::CombineFields; @@ -76,71 +72,14 @@ pub type Bound = Option; pub type UnitResult<'tcx> = RelateResult<'tcx, ()>; // "unify result" pub type FixupResult = Result; // "fixup result" -/// A version of &ty::TypeckTables which can be `Missing` (not needed), -/// `InProgress` (during typeck) or `Interned` (result of typeck). -/// Only the `InProgress` version supports `borrow_mut`. -#[derive(Copy, Clone)] -pub enum InferTables<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { - Interned(&'a ty::TypeckTables<'gcx>), - InProgress(&'a RefCell>), - Missing -} - -pub enum InferTablesRef<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { - Interned(&'a ty::TypeckTables<'gcx>), - InProgress(Ref<'a, ty::TypeckTables<'tcx>>) -} - -impl<'a, 'gcx, 'tcx> Deref for InferTablesRef<'a, 'gcx, 'tcx> { - type Target = ty::TypeckTables<'tcx>; - fn deref(&self) -> &Self::Target { - match *self { - InferTablesRef::Interned(tables) => tables, - InferTablesRef::InProgress(ref tables) => tables - } - } -} - -impl<'a, 'gcx, 'tcx> InferTables<'a, 'gcx, 'tcx> { - pub fn borrow(self) -> InferTablesRef<'a, 'gcx, 'tcx> { - match self { - InferTables::Interned(tables) => InferTablesRef::Interned(tables), - InferTables::InProgress(tables) => InferTablesRef::InProgress(tables.borrow()), - InferTables::Missing => { - bug!("InferTables: infcx.tables.borrow() with no tables") - } - } - } - - pub fn expect_interned(self) -> &'a ty::TypeckTables<'gcx> { - match self { - InferTables::Interned(tables) => tables, - InferTables::InProgress(_) => { - bug!("InferTables: infcx.tables.expect_interned() during type-checking"); - } - InferTables::Missing => { - bug!("InferTables: infcx.tables.expect_interned() with no tables") - } - } - } - - pub fn borrow_mut(self) -> RefMut<'a, ty::TypeckTables<'tcx>> { - match self { - InferTables::Interned(_) => { - bug!("InferTables: infcx.tables.borrow_mut() outside of type-checking"); - } - InferTables::InProgress(tables) => tables.borrow_mut(), - InferTables::Missing => { - bug!("InferTables: infcx.tables.borrow_mut() with no tables") - } - } - } -} - pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { pub tcx: TyCtxt<'a, 'gcx, 'tcx>, - pub tables: InferTables<'a, 'gcx, 'tcx>, + /// During type-checking/inference of a body, `in_progress_tables` + /// contains a reference to the tables being built up, which are + /// used for reading closure kinds/signatures as they are inferred, + /// and for error reporting logic to read arbitrary node types. + pub in_progress_tables: Option<&'a RefCell>>, // Cache for projections. This cache is snapshotted along with the // infcx. @@ -171,7 +110,7 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { // the set of predicates on which errors have been reported, to // avoid reporting the same error twice. - pub reported_trait_errors: RefCell>>, + pub reported_trait_errors: RefCell>>>, // When an error occurs, we want to avoid reporting "derived" // errors that are due to this original failure. Normally, we @@ -396,91 +335,34 @@ impl fmt::Display for FixupError { } } -pub trait InferEnv<'a, 'tcx> { - fn to_parts(self, tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> (Option<&'a ty::TypeckTables<'tcx>>, - Option>); -} - -impl<'a, 'tcx> InferEnv<'a, 'tcx> for () { - fn to_parts(self, _: TyCtxt<'a, 'tcx, 'tcx>) - -> (Option<&'a ty::TypeckTables<'tcx>>, - Option>) { - (None, None) - } -} - -impl<'a, 'tcx> InferEnv<'a, 'tcx> for &'a ty::TypeckTables<'tcx> { - fn to_parts(self, _: TyCtxt<'a, 'tcx, 'tcx>) - -> (Option<&'a ty::TypeckTables<'tcx>>, - Option>) { - (Some(self), None) - } -} - -impl<'a, 'tcx> InferEnv<'a, 'tcx> for ty::TypeckTables<'tcx> { - fn to_parts(self, _: TyCtxt<'a, 'tcx, 'tcx>) - -> (Option<&'a ty::TypeckTables<'tcx>>, - Option>) { - (None, Some(self)) - } -} - -impl<'a, 'tcx> InferEnv<'a, 'tcx> for hir::BodyId { - fn to_parts(self, tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> (Option<&'a ty::TypeckTables<'tcx>>, - Option>) { - let def_id = tcx.hir.body_owner_def_id(self); - (Some(tcx.typeck_tables_of(def_id)), None) - } -} - -/// Helper type of a temporary returned by tcx.infer_ctxt(...). +/// Helper type of a temporary returned by tcx.infer_ctxt(). /// Necessary because we can't write the following bound: /// F: for<'b, 'tcx> where 'gcx: 'tcx FnOnce(InferCtxt<'b, 'gcx, 'tcx>). pub struct InferCtxtBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { global_tcx: TyCtxt<'a, 'gcx, 'gcx>, arena: DroplessArena, fresh_tables: Option>>, - tables: Option<&'a ty::TypeckTables<'gcx>>, } impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> { - pub fn infer_ctxt>(self, env: E) -> InferCtxtBuilder<'a, 'gcx, 'tcx> { - let (tables, fresh_tables) = env.to_parts(self); + pub fn infer_ctxt(self) -> InferCtxtBuilder<'a, 'gcx, 'tcx> { InferCtxtBuilder { global_tcx: self, arena: DroplessArena::new(), - fresh_tables: fresh_tables.map(RefCell::new), - tables: tables, - } - } + fresh_tables: None, - /// Fake InferCtxt with the global tcx. Used by pre-MIR borrowck - /// for MemCategorizationContext/ExprUseVisitor. - /// If any inference functionality is used, ICEs will occur. - pub fn borrowck_fake_infer_ctxt(self, body: hir::BodyId) - -> InferCtxt<'a, 'gcx, 'gcx> { - let (tables, _) = body.to_parts(self); - InferCtxt { - tcx: self, - tables: InferTables::Interned(tables.unwrap()), - type_variables: RefCell::new(type_variable::TypeVariableTable::new()), - int_unification_table: RefCell::new(UnificationTable::new()), - float_unification_table: RefCell::new(UnificationTable::new()), - region_vars: RegionVarBindings::new(self), - selection_cache: traits::SelectionCache::new(), - evaluation_cache: traits::EvaluationCache::new(), - projection_cache: RefCell::new(traits::ProjectionCache::new()), - reported_trait_errors: RefCell::new(FxHashSet()), - tainted_by_errors_flag: Cell::new(false), - err_count_on_creation: self.sess.err_count(), - in_snapshot: Cell::new(false), } } } impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> { + /// Used only by `rustc_typeck` during body type-checking/inference, + /// will initialize `in_progress_tables` with fresh `TypeckTables`. + pub fn with_fresh_in_progress_tables(mut self) -> Self { + self.fresh_tables = Some(RefCell::new(ty::TypeckTables::empty())); + self + } + pub fn enter(&'tcx mut self, f: F) -> R where F: for<'b> FnOnce(InferCtxt<'b, 'gcx, 'tcx>) -> R { @@ -488,14 +370,11 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> { global_tcx, ref arena, ref fresh_tables, - tables, } = *self; - let tables = tables.map(InferTables::Interned).unwrap_or_else(|| { - fresh_tables.as_ref().map_or(InferTables::Missing, InferTables::InProgress) - }); + let in_progress_tables = fresh_tables.as_ref(); global_tcx.enter_local(arena, |tcx| f(InferCtxt { - tcx: tcx, - tables: tables, + tcx, + in_progress_tables, projection_cache: RefCell::new(traits::ProjectionCache::new()), type_variables: RefCell::new(type_variable::TypeVariableTable::new()), int_unification_table: RefCell::new(UnificationTable::new()), @@ -503,7 +382,7 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> { region_vars: RegionVarBindings::new(tcx), selection_cache: traits::SelectionCache::new(), evaluation_cache: traits::EvaluationCache::new(), - reported_trait_errors: RefCell::new(FxHashSet()), + reported_trait_errors: RefCell::new(FxHashMap()), tainted_by_errors_flag: Cell::new(false), err_count_on_creation: tcx.sess.err_count(), in_snapshot: Cell::new(false), @@ -618,7 +497,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { return value; } - self.infer_ctxt(()).enter(|infcx| { + self.infer_ctxt().enter(|infcx| { value.trans_normalize(&infcx, param_env) }) } @@ -640,7 +519,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { return value; } - self.infer_ctxt(()).enter(|infcx| { + self.infer_ctxt().enter(|infcx| { value.trans_normalize(&infcx, env.reveal_all()) }) } @@ -844,10 +723,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { was_in_snapshot: in_snapshot, // Borrow tables "in progress" (i.e. during typeck) // to ban writes from within a snapshot to them. - _in_progress_tables: match self.tables { - InferTables::InProgress(ref tables) => tables.try_borrow().ok(), - _ => None - } + _in_progress_tables: self.in_progress_tables.map(|tables| { + tables.borrow() + }) } } @@ -1190,28 +1068,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.tainted_by_errors_flag.set(true) } - pub fn node_type(&self, id: ast::NodeId) -> Ty<'tcx> { - match self.tables.borrow().node_types.get(&id) { - Some(&t) => t, - // FIXME - None if self.is_tainted_by_errors() => - self.tcx.types.err, - None => { - bug!("no type for node {}: {} in fcx", - id, self.tcx.hir.node_to_string(id)); - } - } - } - - pub fn expr_ty(&self, ex: &hir::Expr) -> Ty<'tcx> { - match self.tables.borrow().node_types.get(&ex.id) { - Some(&t) => t, - None => { - bug!("no type for expr in fcx"); - } - } - } - pub fn resolve_regions_and_report_errors(&self, region_context: DefId, region_map: &RegionMaps, @@ -1310,21 +1166,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { value.fold_with(&mut r) } - /// Resolves all type variables in `t` and then, if any were left - /// unresolved, substitutes an error type. This is used after the - /// main checking when doing a second pass before writeback. The - /// justification is that writeback will produce an error for - /// these unconstrained type variables. - fn resolve_type_vars_or_error(&self, t: &Ty<'tcx>) -> mc::McResult> { - let ty = self.resolve_type_vars_if_possible(t); - if ty.references_error() || ty.is_ty_var() { - debug!("resolve_type_vars_or_error: error from {:?}", ty); - Err(()) - } else { - Ok(ty) - } - } - pub fn fully_resolve>(&self, value: &T) -> FixupResult { /*! * Attempts to resolve all type/region variables in @@ -1484,30 +1325,16 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.region_vars.verify_generic_bound(origin, kind, a, bound); } - pub fn node_ty(&self, id: ast::NodeId) -> McResult> { - let ty = self.node_type(id); - self.resolve_type_vars_or_error(&ty) - } - - pub fn expr_ty_adjusted(&self, expr: &hir::Expr) -> McResult> { - let ty = self.tables.borrow().expr_ty_adjusted(expr); - self.resolve_type_vars_or_error(&ty) - } - pub fn type_moves_by_default(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>, span: Span) -> bool { let ty = self.resolve_type_vars_if_possible(&ty); - if let Some((param_env, ty)) = self.tcx.lift_to_global(&(param_env, ty)) { - // Even if the type may have no inference variables, during - // type-checking closure types are in local tables only. - let local_closures = match self.tables { - InferTables::InProgress(_) => ty.has_closure_types(), - _ => false - }; - if !local_closures { + // Even if the type may have no inference variables, during + // type-checking closure types are in local tables only. + if !self.in_progress_tables.is_some() || !ty.has_closure_types() { + if let Some((param_env, ty)) = self.tcx.lift_to_global(&(param_env, ty)) { return ty.moves_by_default(self.tcx.global_tcx(), param_env, span); } } @@ -1521,15 +1348,11 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { !traits::type_known_to_meet_bound(self, param_env, ty, copy_def_id, span) } - pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option> { - self.tables.borrow().upvar_capture_map.get(&upvar_id).cloned() - } - pub fn closure_kind(&self, def_id: DefId) -> Option { - if let InferTables::InProgress(tables) = self.tables { + if let Some(tables) = self.in_progress_tables { if let Some(id) = self.tcx.hir.as_local_node_id(def_id) { return tables.borrow() .closure_kinds @@ -1547,7 +1370,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } pub fn closure_type(&self, def_id: DefId) -> ty::PolyFnSig<'tcx> { - if let InferTables::InProgress(tables) = self.tables { + if let Some(tables) = self.in_progress_tables { if let Some(id) = self.tcx.hir.as_local_node_id(def_id) { if let Some(&ty) = tables.borrow().closure_tys.get(&id) { return ty; diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 2022565d533b..a9e0ef511024 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -25,8 +25,8 @@ //! for all lint attributes. use self::TargetLint::*; -use dep_graph::DepNode; use middle::privacy::AccessLevels; +use traits::Reveal; use ty::{self, TyCtxt}; use session::{config, early_error, Session}; use lint::{Level, LevelSource, Lint, LintId, LintPass, LintSource}; @@ -411,8 +411,8 @@ pub struct LateContext<'a, 'tcx: 'a> { /// Side-tables for the body we are in. pub tables: &'a ty::TypeckTables<'tcx>, - /// The crate being checked. - pub krate: &'a hir::Crate, + /// Parameter environment for the item we are in. + pub param_env: ty::ParamEnv<'tcx>, /// Items accessible from the crate being checked. pub access_levels: &'a AccessLevels, @@ -869,6 +869,17 @@ impl<'a> LintContext<'a> for EarlyContext<'a> { } } +impl<'a, 'tcx> LateContext<'a, 'tcx> { + fn with_param_env(&mut self, id: ast::NodeId, f: F) + where F: FnOnce(&mut Self), + { + let old_param_env = self.param_env; + self.param_env = self.tcx.param_env(self.tcx.hir.local_def_id(id)); + f(self); + self.param_env = old_param_env; + } +} + impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> { /// Because lints are scoped lexically, we want to walk nested /// items in the context of the outer item, so enable @@ -902,17 +913,21 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> { fn visit_item(&mut self, it: &'tcx hir::Item) { self.with_lint_attrs(&it.attrs, |cx| { - run_lints!(cx, check_item, late_passes, it); - hir_visit::walk_item(cx, it); - run_lints!(cx, check_item_post, late_passes, it); + cx.with_param_env(it.id, |cx| { + run_lints!(cx, check_item, late_passes, it); + hir_visit::walk_item(cx, it); + run_lints!(cx, check_item_post, late_passes, it); + }); }) } fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem) { self.with_lint_attrs(&it.attrs, |cx| { - run_lints!(cx, check_foreign_item, late_passes, it); - hir_visit::walk_foreign_item(cx, it); - run_lints!(cx, check_foreign_item_post, late_passes, it); + cx.with_param_env(it.id, |cx| { + run_lints!(cx, check_foreign_item, late_passes, it); + hir_visit::walk_foreign_item(cx, it); + run_lints!(cx, check_foreign_item_post, late_passes, it); + }); }) } @@ -1026,17 +1041,21 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> { fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) { self.with_lint_attrs(&trait_item.attrs, |cx| { - run_lints!(cx, check_trait_item, late_passes, trait_item); - hir_visit::walk_trait_item(cx, trait_item); - run_lints!(cx, check_trait_item_post, late_passes, trait_item); + cx.with_param_env(trait_item.id, |cx| { + run_lints!(cx, check_trait_item, late_passes, trait_item); + hir_visit::walk_trait_item(cx, trait_item); + run_lints!(cx, check_trait_item_post, late_passes, trait_item); + }); }); } fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) { self.with_lint_attrs(&impl_item.attrs, |cx| { - run_lints!(cx, check_impl_item, late_passes, impl_item); - hir_visit::walk_impl_item(cx, impl_item); - run_lints!(cx, check_impl_item_post, late_passes, impl_item); + cx.with_param_env(impl_item.id, |cx| { + run_lints!(cx, check_impl_item, late_passes, impl_item); + hir_visit::walk_impl_item(cx, impl_item); + run_lints!(cx, check_impl_item_post, late_passes, impl_item); + }); }); } @@ -1321,8 +1340,6 @@ fn check_lint_name_cmdline(sess: &Session, lint_cx: &LintStore, /// /// Consumes the `lint_store` field of the `Session`. 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(); @@ -1330,7 +1347,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let mut cx = LateContext { tcx: tcx, tables: &ty::TypeckTables::empty(), - krate: krate, + param_env: ty::ParamEnv::empty(Reveal::UserFacing), access_levels: access_levels, lint_sess: LintSession::new(&tcx.sess.lint_store), }; diff --git a/src/librustc/macros.rs b/src/librustc/macros.rs index c18e585f7955..f814f941b06f 100644 --- a/src/librustc/macros.rs +++ b/src/librustc/macros.rs @@ -73,10 +73,10 @@ macro_rules! __impl_stable_hash_field { #[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 { + impl<'a, 'gcx, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a, 'gcx, 'tcx>> for $enum_name { #[inline] fn hash_stable(&self, - __ctx: &mut $crate::ich::StableHashingContext<'a, 'tcx>, + __ctx: &mut $crate::ich::StableHashingContext<'a, 'gcx, 'tcx>, __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) { use $enum_name::*; ::std::mem::discriminant(self).hash_stable(__ctx, __hasher); @@ -92,10 +92,10 @@ macro_rules! impl_stable_hash_for { } }; (struct $struct_name:path { $($field:ident),* }) => { - impl<'a, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a, 'tcx>> for $struct_name { + impl<'a, 'gcx, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a, 'gcx, 'tcx>> for $struct_name { #[inline] fn hash_stable(&self, - __ctx: &mut $crate::ich::StableHashingContext<'a, 'tcx>, + __ctx: &mut $crate::ich::StableHashingContext<'a, 'gcx, 'tcx>, __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) { let $struct_name { $(ref $field),* @@ -106,10 +106,10 @@ macro_rules! impl_stable_hash_for { } }; (tuple_struct $struct_name:path { $($field:ident),* }) => { - impl<'a, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a, 'tcx>> for $struct_name { + impl<'a, 'gcx, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a, 'gcx, 'tcx>> for $struct_name { #[inline] fn hash_stable(&self, - __ctx: &mut $crate::ich::StableHashingContext<'a, 'tcx>, + __ctx: &mut $crate::ich::StableHashingContext<'a, 'gcx, 'tcx>, __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) { let $struct_name ( $(ref $field),* @@ -125,11 +125,11 @@ macro_rules! impl_stable_hash_for { macro_rules! impl_stable_hash_for_spanned { ($T:path) => ( - impl<'a, 'tcx> HashStable> for ::syntax::codemap::Spanned<$T> + impl<'a, 'gcx, 'tcx> HashStable> for ::syntax::codemap::Spanned<$T> { #[inline] fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { self.node.hash_stable(hcx, hasher); self.span.hash_stable(hcx, hasher); diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 71b066c6688b..960d616cd4ca 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -23,7 +23,6 @@ // probably get a better home if someone can find one. use hir::def; -use dep_graph::DepNode; use hir::def_id::{CrateNum, DefId, DefIndex}; use hir::map as hir_map; use hir::map::definitions::{Definitions, DefKey, DisambiguatedDefPathData, @@ -190,15 +189,14 @@ pub struct EncodedMetadataHash { /// upstream crate. #[derive(Debug, RustcEncodable, RustcDecodable, Clone)] pub struct EncodedMetadataHashes { - pub entry_hashes: Vec, - pub global_hashes: Vec<(DepNode<()>, ich::Fingerprint)>, + // Stable content hashes for things in crate metadata, indexed by DefIndex. + pub hashes: Vec, } impl EncodedMetadataHashes { pub fn new() -> EncodedMetadataHashes { EncodedMetadataHashes { - entry_hashes: Vec::new(), - global_hashes: Vec::new(), + hashes: Vec::new(), } } } @@ -232,7 +230,7 @@ pub trait CrateStore { // item info fn visibility(&self, def: DefId) -> ty::Visibility; - fn visible_parent_map<'a>(&'a self) -> ::std::cell::Ref<'a, DefIdMap>; + fn visible_parent_map<'a>(&'a self, sess: &Session) -> ::std::cell::Ref<'a, DefIdMap>; fn item_generics_cloned(&self, def: DefId) -> ty::Generics; // trait info @@ -245,23 +243,18 @@ pub trait CrateStore { fn associated_item_cloned(&self, def: DefId) -> ty::AssociatedItem; // flags - fn is_const_fn(&self, did: DefId) -> bool; fn is_dllimport_foreign_item(&self, def: DefId) -> bool; fn is_statically_included_foreign_item(&self, def_id: DefId) -> bool; // crate metadata - fn dylib_dependency_formats(&self, cnum: CrateNum) - -> Vec<(CrateNum, LinkagePreference)>; fn dep_kind(&self, cnum: CrateNum) -> DepKind; fn export_macros(&self, cnum: CrateNum); fn lang_items(&self, cnum: CrateNum) -> Vec<(DefIndex, usize)>; fn missing_lang_items(&self, cnum: CrateNum) -> Vec; - fn is_allocator(&self, cnum: CrateNum) -> bool; - fn is_panic_runtime(&self, cnum: CrateNum) -> bool; fn is_compiler_builtins(&self, cnum: CrateNum) -> bool; fn is_sanitizer_runtime(&self, cnum: CrateNum) -> bool; + fn is_profiler_runtime(&self, cnum: CrateNum) -> bool; fn panic_strategy(&self, cnum: CrateNum) -> PanicStrategy; - fn extern_crate(&self, cnum: CrateNum) -> Option; /// The name of the crate as it is referred to in source code of the current /// crate. fn crate_name(&self, cnum: CrateNum) -> Symbol; @@ -285,7 +278,7 @@ pub trait CrateStore { fn def_path_hash(&self, def: DefId) -> hir_map::DefPathHash; fn def_path_table(&self, cnum: CrateNum) -> Rc; fn struct_field_names(&self, def: DefId) -> Vec; - fn item_children(&self, did: DefId) -> Vec; + fn item_children(&self, did: DefId, sess: &Session) -> Vec; fn load_macro(&self, did: DefId, sess: &Session) -> LoadedMacro; // misc. metadata @@ -347,7 +340,9 @@ impl CrateStore for DummyCrateStore { { bug!("crate_data_as_rc_any") } // item info fn visibility(&self, def: DefId) -> ty::Visibility { bug!("visibility") } - fn visible_parent_map<'a>(&'a self) -> ::std::cell::Ref<'a, DefIdMap> { + fn visible_parent_map<'a>(&'a self, session: &Session) + -> ::std::cell::Ref<'a, DefIdMap> + { bug!("visible_parent_map") } fn item_generics_cloned(&self, def: DefId) -> ty::Generics @@ -364,28 +359,22 @@ impl CrateStore for DummyCrateStore { { bug!("associated_item_cloned") } // flags - fn is_const_fn(&self, did: DefId) -> bool { bug!("is_const_fn") } fn is_dllimport_foreign_item(&self, id: DefId) -> bool { false } fn is_statically_included_foreign_item(&self, def_id: DefId) -> bool { false } // crate metadata - fn dylib_dependency_formats(&self, cnum: CrateNum) - -> Vec<(CrateNum, LinkagePreference)> - { bug!("dylib_dependency_formats") } fn lang_items(&self, cnum: CrateNum) -> Vec<(DefIndex, usize)> { bug!("lang_items") } fn missing_lang_items(&self, cnum: CrateNum) -> Vec { bug!("missing_lang_items") } fn dep_kind(&self, cnum: CrateNum) -> DepKind { bug!("is_explicitly_linked") } fn export_macros(&self, cnum: CrateNum) { bug!("export_macros") } - fn is_allocator(&self, cnum: CrateNum) -> bool { bug!("is_allocator") } - fn is_panic_runtime(&self, cnum: CrateNum) -> bool { bug!("is_panic_runtime") } fn is_compiler_builtins(&self, cnum: CrateNum) -> bool { bug!("is_compiler_builtins") } + fn is_profiler_runtime(&self, cnum: CrateNum) -> bool { bug!("is_profiler_runtime") } fn is_sanitizer_runtime(&self, cnum: CrateNum) -> bool { bug!("is_sanitizer_runtime") } fn panic_strategy(&self, cnum: CrateNum) -> PanicStrategy { bug!("panic_strategy") } - fn extern_crate(&self, cnum: CrateNum) -> Option { bug!("extern_crate") } fn crate_name(&self, cnum: CrateNum) -> Symbol { bug!("crate_name") } fn original_crate_name(&self, cnum: CrateNum) -> Symbol { bug!("original_crate_name") @@ -421,7 +410,9 @@ impl CrateStore for DummyCrateStore { bug!("def_path_table") } fn struct_field_names(&self, def: DefId) -> Vec { bug!("struct_field_names") } - fn item_children(&self, did: DefId) -> Vec { bug!("item_children") } + fn item_children(&self, did: DefId, sess: &Session) -> Vec { + bug!("item_children") + } fn load_macro(&self, did: DefId, sess: &Session) -> LoadedMacro { bug!("load_macro") } // misc. metadata diff --git a/src/librustc/middle/dependency_format.rs b/src/librustc/middle/dependency_format.rs index e60d0533c9f8..4e1f06cca06c 100644 --- a/src/librustc/middle/dependency_format.rs +++ b/src/librustc/middle/dependency_format.rs @@ -65,6 +65,7 @@ use hir::def_id::CrateNum; use session; use session::config; +use ty::TyCtxt; use middle::cstore::DepKind; use middle::cstore::LinkagePreference::{self, RequireStatic, RequireDynamic}; use util::nodemap::FxHashMap; @@ -91,18 +92,22 @@ pub enum Linkage { Dynamic, } -pub fn calculate(sess: &session::Session) { +pub fn calculate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { + let sess = &tcx.sess; let mut fmts = sess.dependency_formats.borrow_mut(); for &ty in sess.crate_types.borrow().iter() { - let linkage = calculate_type(sess, ty); - verify_ok(sess, &linkage); + let linkage = calculate_type(tcx, ty); + verify_ok(tcx, &linkage); fmts.insert(ty, linkage); } sess.abort_if_errors(); } -fn calculate_type(sess: &session::Session, - ty: config::CrateType) -> DependencyList { +fn calculate_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + ty: config::CrateType) -> DependencyList { + + let sess = &tcx.sess; + if !sess.opts.output_types.should_trans() { return Vec::new(); } @@ -111,7 +116,7 @@ fn calculate_type(sess: &session::Session, // If the global prefer_dynamic switch is turned off, first attempt // static linkage (this can fail). config::CrateTypeExecutable if !sess.opts.cg.prefer_dynamic => { - if let Some(v) = attempt_static(sess) { + if let Some(v) = attempt_static(tcx) { return v; } } @@ -124,7 +129,7 @@ fn calculate_type(sess: &session::Session, // to be found, we generate some nice pretty errors. config::CrateTypeStaticlib | config::CrateTypeCdylib => { - if let Some(v) = attempt_static(sess) { + if let Some(v) = attempt_static(tcx) { return v; } for cnum in sess.cstore.crates() { @@ -141,7 +146,7 @@ fn calculate_type(sess: &session::Session, // to try to eagerly statically link all dependencies. This is normally // done for end-product dylibs, not intermediate products. config::CrateTypeDylib if !sess.opts.cg.prefer_dynamic => { - if let Some(v) = attempt_static(sess) { + if let Some(v) = attempt_static(tcx) { return v; } } @@ -167,8 +172,8 @@ fn calculate_type(sess: &session::Session, if src.dylib.is_some() { info!("adding dylib: {}", name); add_library(sess, cnum, RequireDynamic, &mut formats); - let deps = sess.cstore.dylib_dependency_formats(cnum); - for &(depnum, style) in &deps { + let deps = tcx.dylib_dependency_formats(cnum.as_def_id()); + for &(depnum, style) in deps.iter() { info!("adding {:?}: {}", style, sess.cstore.crate_name(depnum)); add_library(sess, depnum, style, &mut formats); @@ -210,9 +215,9 @@ fn calculate_type(sess: &session::Session, // Things like allocators and panic runtimes may not have been activated // quite yet, so do so here. activate_injected_dep(sess.injected_allocator.get(), &mut ret, - &|cnum| sess.cstore.is_allocator(cnum)); + &|cnum| tcx.is_allocator(cnum.as_def_id())); activate_injected_dep(sess.injected_panic_runtime.get(), &mut ret, - &|cnum| sess.cstore.is_panic_runtime(cnum)); + &|cnum| tcx.is_panic_runtime(cnum.as_def_id())); // When dylib B links to dylib A, then when using B we must also link to A. // It could be the case, however, that the rlib for A is present (hence we @@ -269,7 +274,8 @@ fn add_library(sess: &session::Session, } } -fn attempt_static(sess: &session::Session) -> Option { +fn attempt_static<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option { + let sess = &tcx.sess; let crates = sess.cstore.used_crates(RequireStatic); if !crates.iter().by_ref().all(|&(_, ref p)| p.is_some()) { return None @@ -290,9 +296,9 @@ fn attempt_static(sess: &session::Session) -> Option { // explicitly linked, which is the case for any injected dependency. Handle // that here and activate them. activate_injected_dep(sess.injected_allocator.get(), &mut ret, - &|cnum| sess.cstore.is_allocator(cnum)); + &|cnum| tcx.is_allocator(cnum.as_def_id())); activate_injected_dep(sess.injected_panic_runtime.get(), &mut ret, - &|cnum| sess.cstore.is_panic_runtime(cnum)); + &|cnum| tcx.is_panic_runtime(cnum.as_def_id())); Some(ret) } @@ -327,7 +333,8 @@ fn activate_injected_dep(injected: Option, // After the linkage for a crate has been determined we need to verify that // there's only going to be one allocator in the output. -fn verify_ok(sess: &session::Session, list: &[Linkage]) { +fn verify_ok<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, list: &[Linkage]) { + let sess = &tcx.sess; if list.len() == 0 { return } @@ -338,7 +345,7 @@ fn verify_ok(sess: &session::Session, list: &[Linkage]) { continue } let cnum = CrateNum::new(i + 1); - if sess.cstore.is_allocator(cnum) { + if tcx.is_allocator(cnum.as_def_id()) { if let Some(prev) = allocator { let prev_name = sess.cstore.crate_name(prev); let cur_name = sess.cstore.crate_name(cnum); @@ -349,7 +356,7 @@ fn verify_ok(sess: &session::Session, list: &[Linkage]) { allocator = Some(cnum); } - if sess.cstore.is_panic_runtime(cnum) { + if tcx.is_panic_runtime(cnum.as_def_id()) { if let Some((prev, _)) = panic_runtime { let prev_name = sess.cstore.crate_name(prev); let cur_name = sess.cstore.crate_name(cnum); diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 0b2652c74881..58e77f40d981 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -235,17 +235,14 @@ impl OverloadedCallType { /////////////////////////////////////////////////////////////////////////// // The ExprUseVisitor type // -// This is the code that actually walks the tree. Like -// mem_categorization, it requires a TYPER, which is a type that -// supplies types from the tree. After type checking is complete, you -// can just use the tcx as the typer. +// This is the code that actually walks the tree. pub struct ExprUseVisitor<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { mc: mc::MemCategorizationContext<'a, 'gcx, 'tcx>, delegate: &'a mut Delegate<'tcx>, param_env: ty::ParamEnv<'tcx>, } -// If the TYPER results in an error, it's because the type check +// If the MC results in an error, it's because the type check // failed (or will fail, when the error is uncovered and reported // during writeback). In this case, we just ignore this part of the // code. @@ -264,29 +261,32 @@ macro_rules! return_if_err { ) } -impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { +impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx, 'tcx> { pub fn new(delegate: &'a mut (Delegate<'tcx>+'a), + tcx: TyCtxt<'a, 'tcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, region_maps: &'a RegionMaps, - infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, - param_env: ty::ParamEnv<'tcx>) - -> Self - { - ExprUseVisitor::with_options(delegate, - infcx, - param_env, - region_maps, - mc::MemCategorizationOptions::default()) - } - - pub fn with_options(delegate: &'a mut (Delegate<'tcx>+'a), - infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - region_maps: &'a RegionMaps, - options: mc::MemCategorizationOptions) + tables: &'a ty::TypeckTables<'tcx>) -> Self { ExprUseVisitor { - mc: mc::MemCategorizationContext::with_options(infcx, region_maps, options), + mc: mc::MemCategorizationContext::new(tcx, region_maps, tables), + delegate, + param_env, + } + } +} + +impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { + pub fn with_infer(delegate: &'a mut (Delegate<'tcx>+'a), + infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + region_maps: &'a RegionMaps, + tables: &'a ty::TypeckTables<'tcx>) + -> Self + { + ExprUseVisitor { + mc: mc::MemCategorizationContext::with_infer(infcx, region_maps, tables), delegate, param_env, } @@ -296,7 +296,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { debug!("consume_body(body={:?})", body); for arg in &body.arguments { - let arg_ty = return_if_err!(self.mc.infcx.node_ty(arg.pat.id)); + let arg_ty = return_if_err!(self.mc.node_ty(arg.pat.id)); let fn_body_scope_r = self.tcx().node_scope_region(body.value.id); let arg_cmt = self.mc.cat_rvalue( @@ -312,7 +312,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { } fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { - self.mc.infcx.tcx + self.mc.tcx } fn delegate_consume(&mut self, @@ -322,7 +322,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { debug!("delegate_consume(consume_id={}, cmt={:?})", consume_id, cmt); - let mode = copy_or_move(self.mc.infcx, self.param_env, &cmt, DirectRefMove); + let mode = copy_or_move(&self.mc, self.param_env, &cmt, DirectRefMove); self.delegate.consume(consume_id, consume_span, cmt, mode); } @@ -441,7 +441,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { hir::ExprAddrOf(m, ref base) => { // &base // make sure that the thing we are pointing out stays valid // for the lifetime `scope_r` of the resulting ptr: - let expr_ty = return_if_err!(self.mc.infcx.node_ty(expr.id)); + let expr_ty = return_if_err!(self.mc.expr_ty(expr)); if let ty::TyRef(r, _) = expr_ty.sty { let bk = ty::BorrowKind::from_mutbl(m); self.borrow_expr(&base, r, bk, AddrOf); @@ -505,7 +505,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { } hir::ExprAssignOp(_, ref lhs, ref rhs) => { - if self.mc.infcx.tables.borrow().is_method_call(expr) { + if self.mc.tables.is_method_call(expr) { self.consume_expr(lhs); } else { self.mutate_expr(expr, &lhs, MutateMode::WriteAndRead); @@ -528,7 +528,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { } fn walk_callee(&mut self, call: &hir::Expr, callee: &hir::Expr) { - let callee_ty = return_if_err!(self.mc.infcx.expr_ty_adjusted(callee)); + let callee_ty = return_if_err!(self.mc.expr_ty_adjusted(callee)); debug!("walk_callee: callee={:?} callee_ty={:?}", callee, callee_ty); match callee_ty.sty { @@ -537,7 +537,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { } ty::TyError => { } _ => { - let def_id = self.mc.infcx.tables.borrow().type_dependent_defs[&call.id].def_id(); + let def_id = self.mc.tables.type_dependent_defs[&call.id].def_id(); match OverloadedCallType::from_method_id(self.tcx(), def_id) { FnMutOverloadedCall => { let call_scope_r = self.tcx().node_scope_region(call.id); @@ -678,8 +678,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { // consumed or borrowed as part of the automatic adjustment // process. fn walk_adjustment(&mut self, expr: &hir::Expr) { - //NOTE(@jroesch): mixed RefCell borrow causes crash - let adjustments = self.mc.infcx.tables.borrow().expr_adjustments(expr).to_vec(); + let adjustments = self.mc.tables.expr_adjustments(expr); let mut cmt = return_if_err!(self.mc.cat_expr_unadjusted(expr)); for adjustment in adjustments { debug!("walk_adjustment expr={:?} adj={:?}", expr, adjustment); @@ -796,12 +795,12 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { mode: &mut TrackMatchMode) { debug!("determine_pat_move_mode cmt_discr={:?} pat={:?}", cmt_discr, pat); - return_if_err!(self.mc.cat_pattern(cmt_discr, pat, |_mc, cmt_pat, pat| { + return_if_err!(self.mc.cat_pattern(cmt_discr, pat, |cmt_pat, pat| { match pat.node { PatKind::Binding(hir::BindByRef(..), ..) => mode.lub(BorrowingMatch), PatKind::Binding(hir::BindByValue(..), ..) => { - match copy_or_move(self.mc.infcx, self.param_env, &cmt_pat, PatBindingMove) { + match copy_or_move(&self.mc, self.param_env, &cmt_pat, PatBindingMove) { Copy => mode.lub(CopyingMatch), Move(..) => mode.lub(MovingMatch), } @@ -818,14 +817,13 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { debug!("walk_pat cmt_discr={:?} pat={:?}", cmt_discr, pat); let tcx = self.tcx(); - let infcx = self.mc.infcx; let ExprUseVisitor { ref mc, ref mut delegate, param_env } = *self; - return_if_err!(mc.cat_pattern(cmt_discr.clone(), pat, |mc, cmt_pat, pat| { + return_if_err!(mc.cat_pattern(cmt_discr.clone(), pat, |cmt_pat, pat| { if let PatKind::Binding(bmode, def_id, ..) = pat.node { debug!("binding cmt_pat={:?} pat={:?} match_mode={:?}", cmt_pat, pat, match_mode); // pat_ty: the type of the binding being produced. - let pat_ty = return_if_err!(infcx.node_ty(pat.id)); + let pat_ty = return_if_err!(mc.node_ty(pat.id)); // Each match binding is effectively an assignment to the // binding being produced. @@ -843,7 +841,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { } } hir::BindByValue(..) => { - let mode = copy_or_move(infcx, param_env, &cmt_pat, PatBindingMove); + let mode = copy_or_move(mc, param_env, &cmt_pat, PatBindingMove); debug!("walk_pat binding consuming pat"); delegate.consume_pat(pat, cmt_pat, mode); } @@ -855,14 +853,14 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { // the interior nodes (enum variants and structs), as opposed // to the above loop's visit of than the bindings that form // the leaves of the pattern tree structure. - return_if_err!(mc.cat_pattern(cmt_discr, pat, |mc, cmt_pat, pat| { + return_if_err!(mc.cat_pattern(cmt_discr, pat, |cmt_pat, pat| { let qpath = match pat.node { PatKind::Path(ref qpath) | PatKind::TupleStruct(ref qpath, ..) | PatKind::Struct(ref qpath, ..) => qpath, _ => return }; - let def = infcx.tables.borrow().qpath_def(qpath, pat.id); + let def = mc.tables.qpath_def(qpath, pat.id); match def { Def::Variant(variant_did) | Def::VariantCtor(variant_did, ..) => { @@ -896,13 +894,13 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { let id_var = self.tcx().hir.as_local_node_id(def_id).unwrap(); let upvar_id = ty::UpvarId { var_id: id_var, closure_expr_id: closure_expr.id }; - let upvar_capture = self.mc.infcx.upvar_capture(upvar_id).unwrap(); + let upvar_capture = self.mc.tables.upvar_capture(upvar_id); let cmt_var = return_if_err!(self.cat_captured_var(closure_expr.id, fn_decl_span, freevar.def)); match upvar_capture { ty::UpvarCapture::ByValue => { - let mode = copy_or_move(self.mc.infcx, + let mode = copy_or_move(&self.mc, self.param_env, &cmt_var, CaptureMove); @@ -929,18 +927,18 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { // Create the cmt for the variable being borrowed, from the // caller's perspective let var_id = self.tcx().hir.as_local_node_id(upvar_def.def_id()).unwrap(); - let var_ty = self.mc.infcx.node_ty(var_id)?; + let var_ty = self.mc.node_ty(var_id)?; self.mc.cat_def(closure_id, closure_span, var_ty, upvar_def) } } -fn copy_or_move<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, +fn copy_or_move<'a, 'gcx, 'tcx>(mc: &mc::MemCategorizationContext<'a, 'gcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, cmt: &mc::cmt<'tcx>, move_reason: MoveReason) -> ConsumeMode { - if infcx.type_moves_by_default(param_env, cmt.ty, cmt.span) { + if mc.type_moves_by_default(param_env, cmt.ty, cmt.span) { Move(move_reason) } else { Copy diff --git a/src/librustc/middle/free_region.rs b/src/librustc/middle/free_region.rs index 6a21bdc19e09..de738fba30e9 100644 --- a/src/librustc/middle/free_region.rs +++ b/src/librustc/middle/free_region.rs @@ -18,7 +18,6 @@ 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; /// Combines a `RegionMaps` (which governs relationships between @@ -136,23 +135,6 @@ impl<'tcx> FreeRegionMap<'tcx> { self.relation.is_empty() } - 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(a, b) => { - self.relate_regions(a, b); - } - ImpliedBound::RegionSubParam(..) | - ImpliedBound::RegionSubProjection(..) => { - } - } - } - } - pub fn relate_free_regions_from_predicates(&mut self, predicates: &[ty::Predicate<'tcx>]) { debug!("relate_free_regions_from_predicates(predicates={:?})", predicates); @@ -177,7 +159,7 @@ impl<'tcx> FreeRegionMap<'tcx> { // Record that `'sup:'sub`. Or, put another way, `'sub <= 'sup`. // (with the exception that `'static: 'x` is not notable) - fn relate_regions(&mut self, sub: Region<'tcx>, sup: Region<'tcx>) { + pub fn relate_regions(&mut self, sub: Region<'tcx>, sup: Region<'tcx>) { if (is_free(sub) || *sub == ty::ReStatic) && is_free(sup) { self.relation.add(sub, sup) } diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index c114aa1d7a88..259079cf1604 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -76,6 +76,7 @@ use infer::InferCtxt; use hir::def::{Def, CtorKind}; use ty::adjustment; use ty::{self, Ty, TyCtxt}; +use ty::fold::TypeFoldable; use hir::{MutImmutable, MutMutable, PatKind}; use hir::pat_util::EnumerateAndAdjustIterator; @@ -281,20 +282,10 @@ impl ast_node for hir::Pat { #[derive(Clone)] pub struct MemCategorizationContext<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { - pub infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, + pub tcx: TyCtxt<'a, 'gcx, 'tcx>, pub region_maps: &'a RegionMaps, - options: MemCategorizationOptions, -} - -#[derive(Copy, Clone, Default)] -pub struct MemCategorizationOptions { - // If true, then when analyzing a closure upvar, if the closure - // has a missing kind, we treat it like a Fn closure. When false, - // we ICE if the closure has a missing kind. Should be false - // except during closure kind inference. It is used by the - // mem-categorization code to be able to have stricter assertions - // (which are always true except during upvar inference). - pub during_closure_kind_inference: bool, + pub tables: &'a ty::TypeckTables<'tcx>, + infcx: Option<&'a InferCtxt<'a, 'gcx, 'tcx>>, } pub type McResult = Result; @@ -395,51 +386,90 @@ impl MutabilityCategory { } } -impl<'a, 'gcx, 'tcx> MemCategorizationContext<'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) - -> MemCategorizationContext<'a, 'gcx, 'tcx> { - MemCategorizationContext::with_options(infcx, - region_maps, - MemCategorizationOptions::default()) +impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx, 'tcx> { + pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, + region_maps: &'a RegionMaps, + tables: &'a ty::TypeckTables<'tcx>) + -> MemCategorizationContext<'a, 'tcx, 'tcx> { + MemCategorizationContext { tcx, region_maps, tables, infcx: None } } +} - pub fn with_options(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, - region_maps: &'a RegionMaps, - options: MemCategorizationOptions) - -> MemCategorizationContext<'a, 'gcx, 'tcx> { +impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { + pub fn with_infer(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, + region_maps: &'a RegionMaps, + tables: &'a ty::TypeckTables<'tcx>) + -> MemCategorizationContext<'a, 'gcx, 'tcx> { MemCategorizationContext { - infcx: infcx, - region_maps: region_maps, - options: options, + tcx: infcx.tcx, + region_maps, + tables, + infcx: Some(infcx), } } - fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { - self.infcx.tcx + pub fn type_moves_by_default(&self, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>, + span: Span) + -> bool { + self.infcx.map(|infcx| infcx.type_moves_by_default(param_env, ty, span)) + .or_else(|| { + self.tcx.lift_to_global(&(param_env, ty)).map(|(param_env, ty)| { + ty.moves_by_default(self.tcx.global_tcx(), param_env, span) + }) + }) + .unwrap_or(true) } - fn expr_ty(&self, expr: &hir::Expr) -> McResult> { - match self.infcx.node_ty(expr.id) { - Ok(t) => Ok(t), - Err(()) => { - debug!("expr_ty({:?}) yielded Err", expr); - Err(()) + fn resolve_type_vars_if_possible(&self, value: &T) -> T + where T: TypeFoldable<'tcx> + { + self.infcx.map(|infcx| infcx.resolve_type_vars_if_possible(value)) + .unwrap_or_else(|| value.clone()) + } + + fn is_tainted_by_errors(&self) -> bool { + self.infcx.map_or(false, |infcx| infcx.is_tainted_by_errors()) + } + + fn resolve_type_vars_or_error(&self, + id: ast::NodeId, + ty: Option>) + -> McResult> { + match ty { + Some(ty) => { + let ty = self.resolve_type_vars_if_possible(&ty); + if ty.references_error() || ty.is_ty_var() { + debug!("resolve_type_vars_or_error: error from {:?}", ty); + Err(()) + } else { + Ok(ty) + } + } + // FIXME + None if self.is_tainted_by_errors() => Err(()), + None => { + bug!("no type for node {}: {} in mem_categorization", + id, self.tcx.hir.node_to_string(id)); } } } - fn expr_ty_adjusted(&self, expr: &hir::Expr) -> McResult> { - self.infcx.expr_ty_adjusted(expr) + pub fn node_ty(&self, id: ast::NodeId) -> McResult> { + self.resolve_type_vars_or_error(id, self.tables.node_id_to_type_opt(id)) } - fn node_ty(&self, id: ast::NodeId) -> McResult> { - self.infcx.node_ty(id) + pub fn expr_ty(&self, expr: &hir::Expr) -> McResult> { + self.resolve_type_vars_or_error(expr.id, self.tables.expr_ty_opt(expr)) + } + + pub fn expr_ty_adjusted(&self, expr: &hir::Expr) -> McResult> { + self.resolve_type_vars_or_error(expr.id, self.tables.expr_ty_adjusted_opt(expr)) } fn pat_ty(&self, pat: &hir::Pat) -> McResult> { - let base_ty = self.infcx.node_ty(pat.id)?; + let base_ty = self.node_ty(pat.id)?; // FIXME (Issue #18207): This code detects whether we are // looking at a `ref x`, and if so, figures out what the type // *being borrowed* is. But ideally we would put in a more @@ -479,7 +509,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } } - helper(self, expr, self.infcx.tables.borrow().expr_adjustments(expr)) + helper(self, expr, self.tables.expr_adjustments(expr)) } pub fn cat_expr_adjusted(&self, expr: &hir::Expr, @@ -496,12 +526,12 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { where F: FnOnce() -> McResult> { debug!("cat_expr_adjusted_with({:?}): {:?}", adjustment, expr); - let target = self.infcx.resolve_type_vars_if_possible(&adjustment.target); + let target = self.resolve_type_vars_if_possible(&adjustment.target); match adjustment.kind { adjustment::Adjust::Deref(overloaded) => { // Equivalent to *expr or something similar. let base = if let Some(deref) = overloaded { - let ref_ty = self.tcx().mk_ref(deref.region, ty::TypeAndMut { + let ref_ty = self.tcx.mk_ref(deref.region, ty::TypeAndMut { ty: target, mutbl: deref.mutbl, }); @@ -531,7 +561,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { let expr_ty = self.expr_ty(expr)?; match expr.node { hir::ExprUnary(hir::UnDeref, ref e_base) => { - if self.infcx.tables.borrow().is_method_call(expr) { + if self.tables.is_method_call(expr) { self.cat_overloaded_lvalue(expr, e_base, false) } else { let base_cmt = self.cat_expr(&e_base)?; @@ -554,7 +584,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } hir::ExprIndex(ref base, _) => { - if self.infcx.tables.borrow().is_method_call(expr) { + if self.tables.is_method_call(expr) { // If this is an index implemented by a method call, then it // will include an implicit deref of the result. // The call to index() returns a `&T` value, which @@ -568,7 +598,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } hir::ExprPath(ref qpath) => { - let def = self.infcx.tables.borrow().qpath_def(qpath, expr.id); + let def = self.tables.qpath_def(qpath, expr.id); self.cat_def(expr.id, expr.span, expr_ty, def) } @@ -619,49 +649,17 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } Def::Upvar(def_id, _, fn_node_id) => { - let var_id = self.tcx().hir.as_local_node_id(def_id).unwrap(); - let ty = self.node_ty(fn_node_id)?; - match ty.sty { - ty::TyClosure(closure_id, _) => { - match self.infcx.closure_kind(closure_id) { - Some(kind) => { - self.cat_upvar(id, span, var_id, fn_node_id, kind) - } - None => { - if !self.options.during_closure_kind_inference { - span_bug!( - span, - "No closure kind for {:?}", - closure_id); - } - - // during closure kind inference, we - // don't know the closure kind yet, but - // it's ok because we detect that we are - // accessing an upvar and handle that - // case specially anyhow. Use Fn - // arbitrarily. - self.cat_upvar(id, span, var_id, fn_node_id, ty::ClosureKind::Fn) - } - } - } - _ => { - span_bug!( - span, - "Upvar of non-closure {} - {:?}", - fn_node_id, - ty); - } - } + let var_id = self.tcx.hir.as_local_node_id(def_id).unwrap(); + self.cat_upvar(id, span, var_id, fn_node_id) } Def::Local(def_id) => { - let vid = self.tcx().hir.as_local_node_id(def_id).unwrap(); + let vid = self.tcx.hir.as_local_node_id(def_id).unwrap(); Ok(Rc::new(cmt_ { id: id, span: span, cat: Categorization::Local(vid), - mutbl: MutabilityCategory::from_local(self.tcx(), vid), + mutbl: MutabilityCategory::from_local(self.tcx, vid), ty: expr_ty, note: NoteNone })) @@ -677,8 +675,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { id: ast::NodeId, span: Span, var_id: ast::NodeId, - fn_node_id: ast::NodeId, - kind: ty::ClosureKind) + fn_node_id: ast::NodeId) -> McResult> { // An upvar can have up to 3 components. We translate first to a @@ -704,12 +701,17 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // FnMut | copied -> &'env mut | upvar -> &'env mut -> &'up bk // FnOnce | copied | upvar -> &'up bk + let kind = match self.tables.closure_kinds.get(&fn_node_id) { + Some(&(kind, _)) => kind, + None => span_bug!(span, "missing closure kind") + }; + let upvar_id = ty::UpvarId { var_id: var_id, closure_expr_id: fn_node_id }; let var_ty = self.node_ty(var_id)?; // Mutability of original variable itself - let var_mutbl = MutabilityCategory::from_local(self.tcx(), var_id); + let var_mutbl = MutabilityCategory::from_local(self.tcx, var_id); // Construct the upvar. This represents access to the field // from the environment (perhaps we should eventually desugar @@ -743,7 +745,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // for that. let upvar_id = ty::UpvarId { var_id: var_id, closure_expr_id: fn_node_id }; - let upvar_capture = self.infcx.upvar_capture(upvar_id).unwrap(); + let upvar_capture = self.tables.upvar_capture(upvar_id); let cmt_result = match upvar_capture { ty::UpvarCapture::ByValue => { cmt_result @@ -776,11 +778,11 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { -> cmt_<'tcx> { // Region of environment pointer - let env_region = self.tcx().mk_region(ty::ReFree(ty::FreeRegion { + let env_region = self.tcx.mk_region(ty::ReFree(ty::FreeRegion { // The environment of a closure is guaranteed to // outlive any bindings introduced in the body of the // closure itself. - scope: self.tcx().hir.local_def_id(upvar_id.closure_expr_id), + scope: self.tcx.hir.local_def_id(upvar_id.closure_expr_id), bound_region: ty::BrEnv })); @@ -797,7 +799,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // one. let cmt_result = cmt_ { mutbl: McImmutable, - ty: self.tcx().types.err, + ty: self.tcx.types.err, ..cmt_result }; @@ -829,7 +831,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { pub fn temporary_scope(&self, id: ast::NodeId) -> ty::Region<'tcx> { let scope = self.region_maps.temporary_scope(id); - self.tcx().mk_region(match scope { + self.tcx.mk_region(match scope { Some(scope) => ty::ReScope(scope), None => ty::ReStatic }) @@ -840,20 +842,20 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { span: Span, expr_ty: Ty<'tcx>) -> cmt<'tcx> { - let promotable = self.tcx().rvalue_promotable_to_static.borrow().get(&id).cloned() + let promotable = self.tcx.rvalue_promotable_to_static.borrow().get(&id).cloned() .unwrap_or(false); // When the corresponding feature isn't toggled, only promote `[T; 0]`. let promotable = match expr_ty.sty { ty::TyArray(_, 0) => true, - _ => promotable && self.tcx().sess.features.borrow().rvalue_static_promotion, + _ => promotable && self.tcx.sess.features.borrow().rvalue_static_promotion, }; // Compute maximum lifetime of this rvalue. This is 'static if // we can promote to a constant, otherwise equal to enclosing temp // lifetime. let re = if promotable { - self.tcx().types.re_static + self.tcx.types.re_static } else { self.temporary_scope(id) }; @@ -934,7 +936,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { span_bug!(expr.span, "cat_overloaded_lvalue: base is not a reference") } }; - let ref_ty = self.tcx().mk_ref(region, ty::TypeAndMut { + let ref_ty = self.tcx.mk_ref(region, ty::TypeAndMut { ty: lvalue_ty, mutbl, }); @@ -1049,14 +1051,14 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } pub fn cat_pattern(&self, cmt: cmt<'tcx>, pat: &hir::Pat, mut op: F) -> McResult<()> - where F: FnMut(&MemCategorizationContext<'a, 'gcx, 'tcx>, cmt<'tcx>, &hir::Pat), + where F: FnMut(cmt<'tcx>, &hir::Pat), { self.cat_pattern_(cmt, pat, &mut op) } // FIXME(#19596) This is a workaround, but there should be a better way to do this fn cat_pattern_(&self, cmt: cmt<'tcx>, pat: &hir::Pat, op: &mut F) -> McResult<()> - where F : FnMut(&MemCategorizationContext<'a, 'gcx, 'tcx>, cmt<'tcx>, &hir::Pat) + where F : FnMut(cmt<'tcx>, &hir::Pat) { // Here, `cmt` is the categorization for the value being // matched and pat is the pattern it is being matched against. @@ -1105,7 +1107,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { debug!("cat_pattern: {:?} cmt={:?}", pat, cmt); - op(self, cmt.clone(), pat); + op(cmt.clone(), pat); // Note: This goes up here (rather than within the PatKind::TupleStruct arm // alone) because PatKind::Struct can also refer to variants. @@ -1121,8 +1123,8 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { 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().adt_def(enum_did).is_univariant() { + let enum_did = self.tcx.parent_def_id(variant_did).unwrap(); + if !self.tcx.adt_def(enum_did).is_univariant() { self.cat_downcast(pat, cmt.clone(), cmt.ty, variant_did) } else { cmt @@ -1136,11 +1138,11 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { match pat.node { PatKind::TupleStruct(ref qpath, ref subpats, ddpos) => { - let def = self.infcx.tables.borrow().qpath_def(qpath, pat.id); + let def = self.tables.qpath_def(qpath, pat.id); let expected_len = match def { Def::VariantCtor(def_id, CtorKind::Fn) => { - let enum_def = self.tcx().parent_def_id(def_id).unwrap(); - self.tcx().adt_def(enum_def).variant_with_id(def_id).fields.len() + let enum_def = self.tcx.parent_def_id(def_id).unwrap(); + self.tcx.adt_def(enum_def).variant_with_id(def_id).fields.len() } Def::StructCtor(_, CtorKind::Fn) => { match self.pat_ty(&pat)?.sty { diff --git a/src/librustc/mir/cache.rs b/src/librustc/mir/cache.rs index 799686ceca4a..73c702fedb81 100644 --- a/src/librustc/mir/cache.rs +++ b/src/librustc/mir/cache.rs @@ -35,9 +35,9 @@ impl serialize::Decodable for Cache { } } -impl<'a, 'tcx> HashStable> for Cache { +impl<'a, 'gcx, 'tcx> HashStable> for Cache { fn hash_stable(&self, - _: &mut StableHashingContext<'a, 'tcx>, + _: &mut StableHashingContext<'a, 'gcx, 'tcx>, _: &mut StableHasher) { // do nothing } diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 80c42917196d..c8d03e7b3058 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -12,6 +12,7 @@ use graphviz::IntoCow; use middle::const_val::ConstVal; +use middle::region::CodeExtent; use rustc_const_math::{ConstUsize, ConstInt, ConstMathErr}; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; use rustc_data_structures::control_flow_graph::dominators::{Dominators, dominators}; @@ -804,6 +805,10 @@ pub enum StatementKind<'tcx> { inputs: Vec> }, + /// Mark one terminating point of an extent (i.e. static region). + /// (The starting point(s) arise implicitly from borrows.) + EndRegion(CodeExtent), + /// No-op. Useful for deleting instructions without affecting statement indices. Nop, } @@ -813,6 +818,8 @@ impl<'tcx> Debug for Statement<'tcx> { use self::StatementKind::*; match self.kind { Assign(ref lv, ref rv) => write!(fmt, "{:?} = {:?}", lv, rv), + // (reuse lifetime rendering policy from ppaux.) + EndRegion(ref ce) => write!(fmt, "EndRegion({})", ty::ReScope(*ce)), StorageLive(ref lv) => write!(fmt, "StorageLive({:?})", lv), StorageDead(ref lv) => write!(fmt, "StorageDead({:?})", lv), SetDiscriminant{lvalue: ref lv, variant_index: index} => { @@ -1176,12 +1183,22 @@ impl<'tcx> Debug for Rvalue<'tcx> { UnaryOp(ref op, ref a) => write!(fmt, "{:?}({:?})", op, a), Discriminant(ref lval) => write!(fmt, "discriminant({:?})", lval), NullaryOp(ref op, ref t) => write!(fmt, "{:?}({:?})", op, t), - Ref(_, borrow_kind, ref lv) => { + Ref(region, borrow_kind, ref lv) => { let kind_str = match borrow_kind { BorrowKind::Shared => "", BorrowKind::Mut | BorrowKind::Unique => "mut ", }; - write!(fmt, "&{}{:?}", kind_str, lv) + + // When identifying regions, add trailing space if + // necessary. + let region = if ppaux::identify_regions() { + let mut region = format!("{}", region); + if region.len() > 0 { region.push(' '); } + region + } else { + "".to_owned() + }; + write!(fmt, "&{}{}{:?}", region, kind_str, lv) } Aggregate(ref kind, ref lvs) => { @@ -1224,7 +1241,11 @@ impl<'tcx> Debug for Rvalue<'tcx> { AggregateKind::Closure(def_id, _) => ty::tls::with(|tcx| { if let Some(node_id) = tcx.hir.as_local_node_id(def_id) { - let name = format!("[closure@{:?}]", tcx.hir.span(node_id)); + let name = if tcx.sess.opts.debugging_opts.span_free_formats { + format!("[closure@{:?}]", node_id) + } else { + format!("[closure@{:?}]", tcx.hir.span(node_id)) + }; let mut struct_fmt = fmt.debug_struct(&name); tcx.with_freevars(node_id, |freevars| { @@ -1458,6 +1479,13 @@ impl<'tcx> TypeFoldable<'tcx> for Statement<'tcx> { outputs: outputs.fold_with(folder), inputs: inputs.fold_with(folder) }, + + // Note for future: If we want to expose the extents + // during the fold, we need to either generalize EndRegion + // to carry `[ty::Region]`, or extend the `TypeFolder` + // trait with a `fn fold_extent`. + EndRegion(ref extent) => EndRegion(extent.clone()), + Nop => Nop, }; Statement { @@ -1476,6 +1504,13 @@ impl<'tcx> TypeFoldable<'tcx> for Statement<'tcx> { StorageDead(ref lvalue) => lvalue.visit_with(visitor), InlineAsm { ref outputs, ref inputs, .. } => outputs.visit_with(visitor) || inputs.visit_with(visitor), + + // Note for future: If we want to expose the extents + // during the visit, we need to either generalize EndRegion + // to carry `[ty::Region]`, or extend the `TypeVisitor` + // trait with a `fn visit_extent`. + EndRegion(ref _extent) => false, + Nop => false, } } diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 780ce736bfd3..ac1c0306f701 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -325,6 +325,7 @@ macro_rules! make_mir_visitor { ref $($mutability)* rvalue) => { self.visit_assign(block, lvalue, rvalue, location); } + StatementKind::EndRegion(_) => {} StatementKind::SetDiscriminant{ ref $($mutability)* lvalue, .. } => { self.visit_lvalue(lvalue, LvalueContext::Store, location); } diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 589489b49b4f..7b4394f2ac9f 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -893,6 +893,10 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, DB_OPTIONS, db_type_desc, dbsetters, verbose: bool = (false, parse_bool, [UNTRACKED], "in general, enable more debug printouts"), + span_free_formats: bool = (false, parse_bool, [UNTRACKED], + "when debug-printing compiler state, do not include spans"), // o/w tests have closure@path + identify_regions: bool = (false, parse_bool, [UNTRACKED], + "make unnamed regions display as '# (where # is some non-ident unique id)"), time_passes: bool = (false, parse_bool, [UNTRACKED], "measure time of each rustc pass"), count_llvm_insns: bool = (false, parse_bool, @@ -935,8 +939,6 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, save_analysis: bool = (false, parse_bool, [UNTRACKED], "write syntax and type analysis (in JSON format) information, in \ addition to normal output"), - save_analysis_csv: bool = (false, parse_bool, [UNTRACKED], - "write syntax and type analysis (in CSV format) information, in addition to normal output"), save_analysis_api: bool = (false, parse_bool, [UNTRACKED], "write syntax and type analysis information for opaque libraries (in JSON format), \ in addition to normal output"), @@ -1033,6 +1035,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "a single extra argument to prepend the linker invocation (can be used several times)"), pre_link_args: Option> = (None, parse_opt_list, [UNTRACKED], "extra arguments to prepend to the linker invocation (space separated)"), + profile: bool = (false, parse_bool, [TRACKED], + "insert profiling code"), } pub fn default_lib_output() -> CrateType { @@ -2469,8 +2473,6 @@ mod tests { assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash()); opts.debugging_opts.save_analysis = true; assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash()); - opts.debugging_opts.save_analysis_csv = true; - assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash()); opts.debugging_opts.save_analysis_api = true; assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash()); opts.debugging_opts.print_move_fragments = true; diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 049d5e488c94..247fb079fe7e 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -18,6 +18,7 @@ use super::{ OutputTypeParameterMismatch, TraitNotObjectSafe, PredicateObligation, + Reveal, SelectionContext, SelectionError, ObjectSafetyViolation, @@ -25,16 +26,14 @@ use super::{ use errors::DiagnosticBuilder; use fmt_macros::{Parser, Piece, Position}; -use hir::{self, intravisit, Local, Pat, Body}; -use hir::intravisit::{Visitor, NestedVisitorMap}; -use hir::map::NodeExpr; +use hir; use hir::def_id::DefId; use infer::{self, InferCtxt}; use infer::type_variable::TypeVariableOrigin; use rustc::lint::builtin::EXTRA_REQUIREMENT_IN_IMPL; use std::fmt; -use syntax::ast::{self, NodeId}; -use ty::{self, AdtKind, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable, TyInfer, TyVar}; +use syntax::ast; +use ty::{self, AdtKind, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; use ty::error::{ExpectedFound, TypeError}; use ty::fast_reject; use ty::fold::TypeFolder; @@ -44,93 +43,113 @@ use util::nodemap::{FxHashMap, FxHashSet}; use syntax_pos::{DUMMY_SP, Span}; - -#[derive(Debug, PartialEq, Eq, Hash)] -pub struct TraitErrorKey<'tcx> { - span: Span, - predicate: ty::Predicate<'tcx> -} - -impl<'a, 'gcx, 'tcx> TraitErrorKey<'tcx> { - fn from_error(infcx: &InferCtxt<'a, 'gcx, 'tcx>, - e: &FulfillmentError<'tcx>) -> Self { - let predicate = - infcx.resolve_type_vars_if_possible(&e.obligation.predicate); - TraitErrorKey { - span: e.obligation.cause.span, - predicate: infcx.tcx.erase_regions(&predicate) - } - } -} - -struct FindLocalByTypeVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { - infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, - target_ty: &'a Ty<'tcx>, - hir_map: &'a hir::map::Map<'gcx>, - found_local_pattern: Option<&'gcx Pat>, - found_arg_pattern: Option<&'gcx Pat>, -} - -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: &'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> { - pub fn report_fulfillment_errors(&self, errors: &Vec>) { - for error in errors { - self.report_fulfillment_error(error); + pub fn report_fulfillment_errors(&self, + errors: &Vec>) { + #[derive(Debug)] + struct ErrorDescriptor<'tcx> { + predicate: ty::Predicate<'tcx>, + index: Option, // None if this is an old error + } + + let mut error_map : FxHashMap<_, _> = + self.reported_trait_errors.borrow().iter().map(|(&span, predicates)| { + (span, predicates.iter().map(|predicate| ErrorDescriptor { + predicate: predicate.clone(), + index: None + }).collect()) + }).collect(); + + for (index, error) in errors.iter().enumerate() { + error_map.entry(error.obligation.cause.span).or_insert(Vec::new()).push( + ErrorDescriptor { + predicate: error.obligation.predicate.clone(), + index: Some(index) + }); + + self.reported_trait_errors.borrow_mut() + .entry(error.obligation.cause.span).or_insert(Vec::new()) + .push(error.obligation.predicate.clone()); + } + + // We do this in 2 passes because we want to display errors in order, tho + // maybe it *is* better to sort errors by span or something. + let mut is_suppressed: Vec = errors.iter().map(|_| false).collect(); + for (_, error_set) in error_map.iter() { + // We want to suppress "duplicate" errors with the same span. + for error in error_set { + if let Some(index) = error.index { + // Suppress errors that are either: + // 1) strictly implied by another error. + // 2) implied by an error with a smaller index. + for error2 in error_set { + if error2.index.map_or(false, |index2| is_suppressed[index2]) { + // Avoid errors being suppressed by already-suppressed + // errors, to prevent all errors from being suppressed + // at once. + continue + } + + if self.error_implies(&error2.predicate, &error.predicate) && + !(error2.index >= error.index && + self.error_implies(&error.predicate, &error2.predicate)) + { + info!("skipping {:?} (implied by {:?})", error, error2); + is_suppressed[index] = true; + break + } + } + } + } + } + + for (error, suppressed) in errors.iter().zip(is_suppressed) { + if !suppressed { + self.report_fulfillment_error(error); + } } } - fn report_fulfillment_error(&self, - error: &FulfillmentError<'tcx>) { - let error_key = TraitErrorKey::from_error(self, error); - debug!("report_fulfillment_errors({:?}) - key={:?}", - error, error_key); - if !self.reported_trait_errors.borrow_mut().insert(error_key) { - debug!("report_fulfillment_errors: skipping duplicate"); - return; + // returns if `cond` not occuring implies that `error` does not occur - i.e. that + // `error` occuring implies that `cond` occurs. + fn error_implies(&self, + cond: &ty::Predicate<'tcx>, + error: &ty::Predicate<'tcx>) + -> bool + { + if cond == error { + return true } + + let (cond, error) = match (cond, error) { + (&ty::Predicate::Trait(..), &ty::Predicate::Trait(ref error)) + => (cond, error), + _ => { + // FIXME: make this work in other cases too. + return false + } + }; + + for implication in super::elaborate_predicates(self.tcx, vec![cond.clone()]) { + if let ty::Predicate::Trait(implication) = implication { + let error = error.to_poly_trait_ref(); + let implication = implication.to_poly_trait_ref(); + // FIXME: I'm just not taking associated types at all here. + // Eventually I'll need to implement param-env-aware + // `Γ₁ ⊦ φ₁ => Γ₂ ⊦ φ₂` logic. + let param_env = ty::ParamEnv::empty(Reveal::UserFacing); + if let Ok(_) = self.can_sub(param_env, error, implication) { + debug!("error_implies: {:?} -> {:?} -> {:?}", cond, error, implication); + return true + } + } + } + + false + } + + fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>) { + debug!("report_fulfillment_errors({:?})", error); match error.code { FulfillmentErrorCode::CodeSelectionError(ref e) => { self.report_selection_error(&error.obligation, e); @@ -640,16 +659,36 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ty::Predicate::ClosureKind(closure_def_id, kind) => { let found_kind = self.closure_kind(closure_def_id).unwrap(); let closure_span = self.tcx.hir.span_if_local(closure_def_id).unwrap(); + let node_id = self.tcx.hir.as_local_node_id(closure_def_id).unwrap(); let mut err = struct_span_err!( self.tcx.sess, closure_span, E0525, "expected a closure that implements the `{}` trait, \ but this closure only implements `{}`", kind, found_kind); - err.span_note( + + err.span_label( obligation.cause.span, - &format!("the requirement to implement \ - `{}` derives from here", kind)); + format!("the requirement to implement `{}` derives from here", kind)); + + // Additional context information explaining why the closure only implements + // a particular trait. + if let Some(tables) = self.in_progress_tables { + match tables.borrow().closure_kinds.get(&node_id) { + Some(&(ty::ClosureKind::FnOnce, Some((span, name)))) => { + err.span_note(span, &format!( + "closure is `FnOnce` because it moves the \ + variable `{}` out of its environment", name)); + }, + Some(&(ty::ClosureKind::FnMut, Some((span, name)))) => { + err.span_note(span, &format!( + "closure is `FnMut` because it mutates the \ + variable `{}` here", name)); + }, + _ => {} + } + } + err.emit(); return; } @@ -985,83 +1024,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { }) } - fn extract_type_name(&self, ty: &'a Ty<'tcx>) -> String { - if let ty::TyInfer(ty::TyVar(ty_vid)) = (*ty).sty { - let ty_vars = self.type_variables.borrow(); - if let TypeVariableOrigin::TypeParameterDefinition(_, name) = - *ty_vars.var_origin(ty_vid) { - name.to_string() - } else { - ty.to_string() - } - } else { - ty.to_string() - } - } - - 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 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, - 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(body_id.node_id) { - Some(NodeExpr(expr)) => local_visitor.visit_expr(expr), - _ => () - } - - 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() { - labels.push((pattern.span, format!("consider giving `{}` a type", simple_name))); - } else { - 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(); - } - fn note_obligation_cause(&self, err: &mut DiagnosticBuilder, obligation: &Obligation<'tcx, T>) @@ -1182,4 +1144,3 @@ 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 c2fe04534375..16ecc94b9476 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -183,7 +183,9 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> { assert!(!infcx.is_in_snapshot()); - if infcx.tcx.fulfilled_predicates.borrow().check_duplicate(&obligation.predicate) { + let tcx = infcx.tcx; + + if tcx.fulfilled_predicates.borrow().check_duplicate(tcx, &obligation.predicate) { debug!("register_predicate_obligation: duplicate"); return } @@ -373,7 +375,8 @@ fn process_predicate<'a, 'gcx, 'tcx>( match obligation.predicate { ty::Predicate::Trait(ref data) => { - if selcx.tcx().fulfilled_predicates.borrow().check_duplicate_trait(data) { + let tcx = selcx.tcx(); + if tcx.fulfilled_predicates.borrow().check_duplicate_trait(tcx, data) { return Ok(Some(vec![])); } @@ -607,22 +610,22 @@ impl<'a, 'gcx, 'tcx> GlobalFulfilledPredicates<'gcx> { } } - pub fn check_duplicate(&self, key: &ty::Predicate<'tcx>) -> bool { + pub fn check_duplicate(&self, tcx: TyCtxt, key: &ty::Predicate<'tcx>) -> bool { if let ty::Predicate::Trait(ref data) = *key { - self.check_duplicate_trait(data) + self.check_duplicate_trait(tcx, data) } else { false } } - pub fn check_duplicate_trait(&self, data: &ty::PolyTraitPredicate<'tcx>) -> bool { + pub fn check_duplicate_trait(&self, tcx: TyCtxt, data: &ty::PolyTraitPredicate<'tcx>) -> bool { // For the global predicate registry, when we find a match, it // may have been computed by some other task, so we want to // add a read from the node corresponding to the predicate // processing to make sure we get the transitive dependencies. if self.set.contains(data) { debug_assert!(data.is_global()); - self.dep_graph.read(data.dep_node()); + self.dep_graph.read(data.dep_node(tcx)); debug!("check_duplicate: global predicate `{:?}` already proved elsewhere", data); true diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index c51974e6e670..e9196cd12431 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -28,7 +28,6 @@ use std::rc::Rc; use syntax::ast; use syntax_pos::{Span, DUMMY_SP}; -pub use self::error_reporting::TraitErrorKey; pub use self::coherence::orphan_check; pub use self::coherence::overlapping_impls; pub use self::coherence::OrphanCheckErr; @@ -484,7 +483,7 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let elaborated_env = ty::ParamEnv::new(tcx.intern_predicates(&predicates), unnormalized_env.reveal); - tcx.infer_ctxt(()).enter(|infcx| { + tcx.infer_ctxt().enter(|infcx| { let predicates = match fully_normalize( &infcx, cause, @@ -598,7 +597,7 @@ pub fn normalize_and_test_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, debug!("normalize_and_test_predicates(predicates={:?})", predicates); - tcx.infer_ctxt(()).enter(|infcx| { + tcx.infer_ctxt().enter(|infcx| { let param_env = ty::ParamEnv::empty(Reveal::All); let mut selcx = SelectionContext::new(&infcx); let mut fulfill_cx = FulfillmentContext::new(); diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 998201ad8d9f..10710d963a01 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -381,7 +381,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { assert!(!obligation.predicate.has_escaping_regions()); let tcx = self.tcx(); - let dep_node = obligation.predicate.dep_node(); + let dep_node = obligation.predicate.dep_node(tcx); let _task = tcx.dep_graph.in_task(dep_node); let stack = self.push_stack(TraitObligationStackList::empty(), obligation); @@ -514,11 +514,13 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { debug!("evaluate_predicate_recursively({:?})", obligation); + let tcx = self.tcx(); + // Check the cache from the tcx of predicates that we know // have been proven elsewhere. This cache only contains // predicates that are global in scope and hence unaffected by // the current environment. - if self.tcx().fulfilled_predicates.borrow().check_duplicate(&obligation.predicate) { + if tcx.fulfilled_predicates.borrow().check_duplicate(tcx, &obligation.predicate) { return EvaluatedToOk; } diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index 689f06a35973..18734e2dbc3f 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -125,7 +125,7 @@ pub fn find_associated_item<'a, 'tcx>( let ancestors = trait_def.ancestors(tcx, impl_data.impl_def_id); match ancestors.defs(tcx, item.name, item.kind).next() { Some(node_item) => { - let substs = tcx.infer_ctxt(()).enter(|infcx| { + let substs = tcx.infer_ctxt().enter(|infcx| { let param_env = ty::ParamEnv::empty(Reveal::All); let substs = substs.rebase_onto(tcx, trait_def_id, impl_data.substs); let substs = translate_substs(&infcx, param_env, impl_data.impl_def_id, @@ -188,7 +188,7 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let impl1_trait_ref = tcx.impl_trait_ref(impl1_def_id).unwrap(); // Create a infcx, taking the predicates of impl1 as assumptions: - let result = tcx.infer_ctxt(()).enter(|infcx| { + let result = tcx.infer_ctxt().enter(|infcx| { // Normalize the trait reference. The WF rules ought to ensure // that this always succeeds. let impl1_trait_ref = diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc/traits/specialize/specialization_graph.rs index 702c5035a18b..f80caeec460f 100644 --- a/src/librustc/traits/specialize/specialization_graph.rs +++ b/src/librustc/traits/specialize/specialization_graph.rs @@ -109,7 +109,7 @@ impl<'a, 'gcx, 'tcx> Children { let possible_sibling = *slot; let tcx = tcx.global_tcx(); - let (le, ge) = tcx.infer_ctxt(()).enter(|infcx| { + let (le, ge) = tcx.infer_ctxt().enter(|infcx| { let overlap = traits::overlapping_impls(&infcx, possible_sibling, impl_def_id); diff --git a/src/librustc/traits/trans/mod.rs b/src/librustc/traits/trans/mod.rs index 7ad2ef90f0d4..40bd88d731d3 100644 --- a/src/librustc/traits/trans/mod.rs +++ b/src/librustc/traits/trans/mod.rs @@ -13,7 +13,8 @@ // seems likely that they should eventually be merged into more // general routines. -use dep_graph::{DepGraph, DepNode, DepTrackingMap, DepTrackingMapConfig}; +use dep_graph::{DepGraph, DepNode, DepTrackingMap, DepTrackingMapConfig, + DepConstructor}; use hir::def_id::DefId; use infer::TransNormalize; use std::cell::RefCell; @@ -40,13 +41,13 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, '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, || { + self.trans_trait_caches.trait_cache.memoize(self, 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(()).enter(|infcx| { + self.infer_ctxt().enter(|infcx| { let mut selcx = SelectionContext::new(&infcx); let param_env = ty::ParamEnv::empty(Reveal::All); @@ -138,7 +139,7 @@ impl<'a, 'gcx> TypeFolder<'gcx, 'gcx> for AssociatedTypeNormalizer<'a, 'gcx> { if !ty.has_projection_types() { ty } else { - self.tcx.trans_trait_caches.project_cache.memoize(ty, || { + self.tcx.trans_trait_caches.project_cache.memoize(self.tcx, ty, || { debug!("AssociatedTypeNormalizer: ty={:?}", ty); self.tcx.normalize_associated_type(&ty) }) @@ -170,8 +171,8 @@ pub struct TraitSelectionCache<'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() + fn to_dep_node(tcx: TyCtxt, key: &ty::PolyTraitRef<'tcx>) -> DepNode { + key.to_poly_trait_predicate().dep_node(tcx) } } @@ -184,7 +185,7 @@ pub struct ProjectionCache<'gcx> { impl<'gcx> DepTrackingMapConfig for ProjectionCache<'gcx> { type Key = Ty<'gcx>; type Value = Ty<'gcx>; - fn to_dep_node(key: &Self::Key) -> DepNode { + fn to_dep_node(tcx: TyCtxt, 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 @@ -208,7 +209,7 @@ impl<'gcx> DepTrackingMapConfig for ProjectionCache<'gcx> { }) .collect(); - DepNode::ProjectionCache { def_ids: def_ids } + DepNode::new(tcx, DepConstructor::ProjectionCache { def_ids: def_ids }) } } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 2bbb71610ad0..2d81606329e5 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -376,8 +376,8 @@ impl<'tcx> TypeckTables<'tcx> { } } - pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option> { - Some(self.upvar_capture_map.get(&upvar_id).unwrap().clone()) + pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> ty::UpvarCapture<'tcx> { + self.upvar_capture_map[&upvar_id] } } diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index 7dca28df9da3..76103148ec3e 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use dep_graph::DepNode; +use dep_graph::DepConstructor; use hir::def_id::DefId; use ty::{self, Ty, TypeFoldable, Substs}; use util::ppaux; @@ -60,7 +60,8 @@ impl<'tcx> InstanceDef<'tcx> { tcx.get_attrs(self.def_id()) } - pub(crate) fn dep_node(&self) -> DepNode { + pub //(crate) + fn dep_node(&self) -> DepConstructor { // HACK: def-id binning, project-style; someone replace this with // real on-demand. let ty = match self { @@ -69,7 +70,7 @@ impl<'tcx> InstanceDef<'tcx> { _ => None }.into_iter(); - DepNode::MirShim( + DepConstructor::MirShim( Some(self.def_id()).into_iter().chain( ty.flat_map(|t| t.walk()).flat_map(|t| match t.sty { ty::TyAdt(adt_def, _) => Some(adt_def.did), diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs index 78536b53ba87..09a3bcd06138 100644 --- a/src/librustc/ty/item_path.rs +++ b/src/librustc/ty/item_path.rs @@ -100,7 +100,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // // Returns `None` for the local crate. if cnum != LOCAL_CRATE { - let opt_extern_crate = self.sess.cstore.extern_crate(cnum); + let opt_extern_crate = self.extern_crate(cnum.as_def_id()); let opt_extern_crate = opt_extern_crate.and_then(|extern_crate| { if extern_crate.direct { Some(extern_crate.def_id) @@ -129,15 +129,15 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn try_push_visible_item_path(self, buffer: &mut T, external_def_id: DefId) -> bool where T: ItemPathBuffer { - let visible_parent_map = self.sess.cstore.visible_parent_map(); + let visible_parent_map = self.sess.cstore.visible_parent_map(self.sess); let (mut cur_def, mut cur_path) = (external_def_id, Vec::::new()); loop { // If `cur_def` is a direct or injected extern crate, push the path to the crate // followed by the path to the item within the crate and return. if cur_def.index == CRATE_DEF_INDEX { - match self.sess.cstore.extern_crate(cur_def.krate) { - Some(extern_crate) if extern_crate.direct => { + match *self.extern_crate(cur_def) { + Some(ref extern_crate) if extern_crate.direct => { self.push_item_path(buffer, extern_crate.def_id); cur_path.iter().rev().map(|segment| buffer.push(&segment.as_str())).count(); return true; @@ -197,7 +197,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { data @ DefPathData::ClosureExpr | data @ DefPathData::Binding(..) | data @ DefPathData::ImplTrait | - data @ DefPathData::Typeof => { + data @ DefPathData::Typeof | + data @ DefPathData::GlobalMetaData(..) => { let parent_def_id = self.parent_def_id(def_id).unwrap(); self.push_item_path(buffer, parent_def_id); buffer.push(&data.as_interned_str()); diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index b5adcc8ed757..524cf57472bc 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -8,11 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use dep_graph::{DepNode, DepTrackingMapConfig}; +use dep_graph::{DepConstructor, DepNode, DepTrackingMapConfig}; use hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId, LOCAL_CRATE}; use hir::def::Def; use hir; use middle::const_val; +use middle::cstore::{ExternCrate, LinkagePreference}; use middle::privacy::AccessLevels; use middle::region::RegionMaps; use mir; @@ -476,6 +477,36 @@ impl<'tcx> QueryDescription for queries::is_object_safe<'tcx> { } } +impl<'tcx> QueryDescription for queries::is_const_fn<'tcx> { + fn describe(tcx: TyCtxt, def_id: DefId) -> String { + format!("checking if item is const fn: `{}`", tcx.item_path_str(def_id)) + } +} + +impl<'tcx> QueryDescription for queries::dylib_dependency_formats<'tcx> { + fn describe(_: TyCtxt, _: DefId) -> String { + "dylib dependency formats of crate".to_string() + } +} + +impl<'tcx> QueryDescription for queries::is_allocator<'tcx> { + fn describe(_: TyCtxt, _: DefId) -> String { + "checking if the crate is_allocator".to_string() + } +} + +impl<'tcx> QueryDescription for queries::is_panic_runtime<'tcx> { + fn describe(_: TyCtxt, _: DefId) -> String { + "checking if the crate is_panic_runtime".to_string() + } +} + +impl<'tcx> QueryDescription for queries::extern_crate<'tcx> { + fn describe(_: TyCtxt, _: DefId) -> String { + "getting crate's ExternCrateData".to_string() + } +} + macro_rules! define_maps { (<$tcx:tt> $($(#[$attr:meta])* @@ -524,10 +555,10 @@ macro_rules! define_maps { type Value = $V; #[allow(unused)] - fn to_dep_node(key: &$K) -> DepNode { - use dep_graph::DepNode::*; + fn to_dep_node(tcx: TyCtxt, key: &$K) -> DepNode { + use dep_graph::DepConstructor::*; - $node(*key) + DepNode::new(tcx, $node(*key)) } } impl<'a, $tcx, 'lcx> queries::$name<$tcx> { @@ -554,7 +585,7 @@ macro_rules! define_maps { span = key.default_span(tcx) } - let _task = tcx.dep_graph.in_task(Self::to_dep_node(&key)); + let _task = tcx.dep_graph.in_task(Self::to_dep_node(tcx, &key)); let result = tcx.cycle_check(span, Query::$name(key), || { let provider = tcx.maps.providers[key.map_crate()].$name; @@ -569,7 +600,7 @@ macro_rules! define_maps { // We register the `read` here, but not in `force`, since // `force` does not give access to the value produced (and thus // we actually don't read it). - tcx.dep_graph.read(Self::to_dep_node(&key)); + tcx.dep_graph.read(Self::to_dep_node(tcx, &key)); Self::try_get_with(tcx, span, key, Clone::clone) } @@ -782,7 +813,7 @@ define_maps! { <'tcx> /// To avoid cycles within the predicates of a single item we compute /// per-type-parameter predicates for resolving `T::AssocTy`. - [] type_param_predicates: TypeParamPredicates((DefId, DefId)) + [] type_param_predicates: type_param_predicates((DefId, DefId)) -> ty::GenericPredicates<'tcx>, [] trait_def: ItemSignature(DefId) -> &'tcx ty::TraitDef, @@ -791,6 +822,9 @@ define_maps! { <'tcx> [] adt_sized_constraint: SizedConstraint(DefId) -> &'tcx [Ty<'tcx>], [] adt_dtorck_constraint: DtorckConstraint(DefId) -> ty::DtorckConstraint<'tcx>, + /// True if this is a const fn + [] is_const_fn: IsConstFn(DefId) -> bool, + /// True if this is a foreign item (i.e., linked via `extern { ... }`). [] is_foreign_item: IsForeignItem(DefId) -> bool, @@ -929,76 +963,91 @@ define_maps! { <'tcx> [] needs_drop_raw: needs_drop_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool, [] layout_raw: layout_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> Result<&'tcx Layout, LayoutError<'tcx>>, + + [] dylib_dependency_formats: DylibDepFormats(DefId) + -> Rc>, + + [] is_allocator: IsAllocator(DefId) -> bool, + [] is_panic_runtime: IsPanicRuntime(DefId) -> bool, + + [] extern_crate: ExternCrate(DefId) -> Rc>, } -fn coherent_trait_dep_node((_, def_id): (CrateNum, DefId)) -> DepNode { - DepNode::CoherenceCheckTrait(def_id) +fn type_param_predicates((item_id, param_id): (DefId, DefId)) -> DepConstructor { + DepConstructor::TypeParamPredicates { + item_id, + param_id + } } -fn crate_inherent_impls_dep_node(_: CrateNum) -> DepNode { - DepNode::Coherence +fn coherent_trait_dep_node((_, def_id): (CrateNum, DefId)) -> DepConstructor { + DepConstructor::CoherenceCheckTrait(def_id) } -fn reachability_dep_node(_: CrateNum) -> DepNode { - DepNode::Reachability +fn crate_inherent_impls_dep_node(_: CrateNum) -> DepConstructor { + DepConstructor::Coherence } -fn mir_shim_dep_node(instance: ty::InstanceDef) -> DepNode { +fn reachability_dep_node(_: CrateNum) -> DepConstructor { + DepConstructor::Reachability +} + +fn mir_shim_dep_node(instance: ty::InstanceDef) -> DepConstructor { instance.dep_node() } -fn symbol_name_dep_node(instance: ty::Instance) -> DepNode { +fn symbol_name_dep_node(instance: ty::Instance) -> DepConstructor { // 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()) + DepConstructor::SymbolName(instance.def.def_id()) } -fn typeck_item_bodies_dep_node(_: CrateNum) -> DepNode { - DepNode::TypeckBodiesKrate +fn typeck_item_bodies_dep_node(_: CrateNum) -> DepConstructor { + DepConstructor::TypeckBodiesKrate } -fn const_eval_dep_node((def_id, _): (DefId, &Substs)) -> DepNode { - DepNode::ConstEval(def_id) +fn const_eval_dep_node((def_id, _): (DefId, &Substs)) -> DepConstructor { + DepConstructor::ConstEval(def_id) } -fn mir_keys(_: CrateNum) -> DepNode { - DepNode::MirKeys +fn mir_keys(_: CrateNum) -> DepConstructor { + DepConstructor::MirKeys } -fn crate_variances(_: CrateNum) -> DepNode { - DepNode::CrateVariances +fn crate_variances(_: CrateNum) -> DepConstructor { + DepConstructor::CrateVariances } -fn relevant_trait_impls_for((def_id, _): (DefId, SimplifiedType)) -> DepNode { - DepNode::TraitImpls(def_id) +fn relevant_trait_impls_for((def_id, _): (DefId, SimplifiedType)) -> DepConstructor { + DepConstructor::TraitImpls(def_id) } -fn is_copy_dep_node<'tcx>(key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepNode { +fn is_copy_dep_node<'tcx>(key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor { let def_id = ty::item_path::characteristic_def_id_of_type(key.value) .unwrap_or(DefId::local(CRATE_DEF_INDEX)); - DepNode::IsCopy(def_id) + DepConstructor::IsCopy(def_id) } -fn is_sized_dep_node<'tcx>(key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepNode { +fn is_sized_dep_node<'tcx>(key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor { let def_id = ty::item_path::characteristic_def_id_of_type(key.value) .unwrap_or(DefId::local(CRATE_DEF_INDEX)); - DepNode::IsSized(def_id) + DepConstructor::IsSized(def_id) } -fn is_freeze_dep_node<'tcx>(key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepNode { +fn is_freeze_dep_node<'tcx>(key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor { let def_id = ty::item_path::characteristic_def_id_of_type(key.value) .unwrap_or(DefId::local(CRATE_DEF_INDEX)); - DepNode::IsFreeze(def_id) + DepConstructor::IsFreeze(def_id) } -fn needs_drop_dep_node<'tcx>(key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepNode { +fn needs_drop_dep_node<'tcx>(key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor { let def_id = ty::item_path::characteristic_def_id_of_type(key.value) .unwrap_or(DefId::local(CRATE_DEF_INDEX)); - DepNode::NeedsDrop(def_id) + DepConstructor::NeedsDrop(def_id) } -fn layout_dep_node<'tcx>(key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepNode { +fn layout_dep_node<'tcx>(key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor { let def_id = ty::item_path::characteristic_def_id_of_type(key.value) .unwrap_or(DefId::local(CRATE_DEF_INDEX)); - DepNode::Layout(def_id) + DepConstructor::Layout(def_id) } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 653021119aab..13e46a265c69 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -15,7 +15,7 @@ pub use self::IntVarValue::*; pub use self::LvaluePreference::*; pub use self::fold::TypeFoldable; -use dep_graph::DepNode; +use dep_graph::{DepNode, DepConstructor}; use hir::{map as hir_map, FreevarMap, TraitMap}; use hir::def::{Def, CtorKind, ExportMap}; use hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE}; @@ -465,9 +465,27 @@ impl<'tcx> Hash for TyS<'tcx> { } } -impl<'a, 'tcx> HashStable> for ty::TyS<'tcx> { +impl<'tcx> TyS<'tcx> { + pub fn is_primitive_ty(&self) -> bool { + match self.sty { + TypeVariants::TyBool | + TypeVariants::TyChar | + TypeVariants::TyInt(_) | + TypeVariants::TyUint(_) | + TypeVariants::TyFloat(_) | + TypeVariants::TyInfer(InferTy::IntVar(_)) | + TypeVariants::TyInfer(InferTy::FloatVar(_)) | + TypeVariants::TyInfer(InferTy::FreshIntTy(_)) | + TypeVariants::TyInfer(InferTy::FreshFloatTy(_)) => true, + TypeVariants::TyRef(_, x) => x.ty.is_primitive_ty(), + _ => false, + } + } +} + +impl<'a, 'gcx, 'tcx> HashStable> for ty::TyS<'tcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { let ty::TyS { ref sty, @@ -918,7 +936,7 @@ impl<'tcx> TraitPredicate<'tcx> { } /// Creates the dep-node for selecting/evaluating this trait reference. - fn dep_node(&self) -> DepNode { + fn dep_node(&self, tcx: TyCtxt) -> DepNode { // Extact the trait-def and first def-id from inputs. See the // docs for `DepNode::TraitSelect` for more information. let trait_def_id = self.def_id(); @@ -926,15 +944,17 @@ impl<'tcx> TraitPredicate<'tcx> { self.input_types() .flat_map(|t| t.walk()) .filter_map(|t| match t.sty { - ty::TyAdt(adt_def, _) => Some(adt_def.did), + ty::TyAdt(adt_def, ..) => Some(adt_def.did), + ty::TyClosure(def_id, ..) => Some(def_id), + ty::TyFnDef(def_id, ..) => Some(def_id), _ => None }) .next() .unwrap_or(trait_def_id); - DepNode::TraitSelect { + DepNode::new(tcx, DepConstructor::TraitSelect { trait_def_id: trait_def_id, input_def_id: input_def_id - } + }) } pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator> + 'a { @@ -952,9 +972,9 @@ impl<'tcx> PolyTraitPredicate<'tcx> { self.0.def_id() } - pub fn dep_node(&self) -> DepNode { + pub fn dep_node(&self, tcx: TyCtxt) -> DepNode { // ok to skip binder since depnode does not care about regions - self.0.dep_node() + self.0.dep_node(tcx) } } @@ -1318,9 +1338,9 @@ impl<'tcx> serialize::UseSpecializedEncodable for &'tcx AdtDef { impl<'tcx> serialize::UseSpecializedDecodable for &'tcx AdtDef {} -impl<'a, 'tcx> HashStable> for AdtDef { +impl<'a, 'gcx, 'tcx> HashStable> for AdtDef { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { let ty::AdtDef { did, diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index ec4ca54d6f5e..a7029ac5fa9f 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -175,7 +175,7 @@ impl<'tcx> ty::ParamEnv<'tcx> { self_type: Ty<'tcx>, span: Span) -> Result<(), CopyImplementationError<'tcx>> { // FIXME: (@jroesch) float this code up - tcx.infer_ctxt(()).enter(|infcx| { + tcx.infer_ctxt().enter(|infcx| { let (adt, substs) = match self_type.sty { ty::TyAdt(adt, substs) => (adt, substs), _ => return Err(CopyImplementationError::NotAnAdt), @@ -977,7 +977,7 @@ fn is_copy_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, { let (param_env, ty) = query.into_parts(); let trait_def_id = tcx.require_lang_item(lang_items::CopyTraitLangItem); - tcx.infer_ctxt(()) + tcx.infer_ctxt() .enter(|infcx| traits::type_known_to_meet_bound(&infcx, param_env, ty, @@ -991,7 +991,7 @@ fn is_sized_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, { let (param_env, ty) = query.into_parts(); let trait_def_id = tcx.require_lang_item(lang_items::SizedTraitLangItem); - tcx.infer_ctxt(()) + tcx.infer_ctxt() .enter(|infcx| traits::type_known_to_meet_bound(&infcx, param_env, ty, @@ -1005,7 +1005,7 @@ fn is_freeze_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, { let (param_env, ty) = query.into_parts(); let trait_def_id = tcx.require_lang_item(lang_items::FreezeTraitLangItem); - tcx.infer_ctxt(()) + tcx.infer_ctxt() .enter(|infcx| traits::type_known_to_meet_bound(&infcx, param_env, ty, diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index aa2c9802e547..2eb0acac4f7e 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -10,7 +10,6 @@ use hir::def_id::DefId; use infer::InferCtxt; -use ty::outlives::Component; use ty::subst::Substs; use traits; use ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable}; @@ -107,133 +106,6 @@ pub fn predicate_obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, wf.normalize() } -/// Implied bounds are region relationships that we deduce -/// automatically. The idea is that (e.g.) a caller must check that a -/// function's argument types are well-formed immediately before -/// calling that fn, and hence the *callee* can assume that its -/// argument types are well-formed. This may imply certain relationships -/// between generic parameters. For example: -/// -/// fn foo<'a,T>(x: &'a T) -/// -/// can only be called with a `'a` and `T` such that `&'a T` is WF. -/// For `&'a T` to be WF, `T: 'a` must hold. So we can assume `T: 'a`. -#[derive(Debug)] -pub enum ImpliedBound<'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 -/// the fact that caller/projector has ensured that `ty` is WF. See -/// the `ImpliedBound` type for more details. -pub fn implied_bounds<'a, 'gcx, 'tcx>( - infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - body_id: ast::NodeId, - ty: Ty<'tcx>, - span: Span) - -> Vec> -{ - // Sometimes when we ask what it takes for T: WF, we get back that - // U: WF is required; in that case, we push U onto this stack and - // process it next. Currently (at least) these resulting - // predicates are always guaranteed to be a subset of the original - // type, so we need not fear non-termination. - let mut wf_types = vec![ty]; - - let mut implied_bounds = vec![]; - - while let Some(ty) = wf_types.pop() { - // Compute the obligations for `ty` to be well-formed. If `ty` is - // an unresolved inference variable, just substituted an empty set - // -- because the return type here is going to be things we *add* - // to the environment, it's always ok for this set to be smaller - // than the ultimate set. (Note: normally there won't be - // unresolved inference variables here anyway, but there might be - // during typeck under some circumstances.) - let obligations = obligations(infcx, param_env, body_id, ty, span).unwrap_or(vec![]); - - // From the full set of obligations, just filter down to the - // region relationships. - implied_bounds.extend( - obligations - .into_iter() - .flat_map(|obligation| { - assert!(!obligation.has_escaping_regions()); - match obligation.predicate { - ty::Predicate::Trait(..) | - ty::Predicate::Equate(..) | - ty::Predicate::Subtype(..) | - ty::Predicate::Projection(..) | - ty::Predicate::ClosureKind(..) | - ty::Predicate::ObjectSafe(..) => - vec![], - - ty::Predicate::WellFormed(subty) => { - wf_types.push(subty); - vec![] - } - - ty::Predicate::RegionOutlives(ref data) => - match infcx.tcx.no_late_bound_regions(data) { - None => - vec![], - Some(ty::OutlivesPredicate(r_a, r_b)) => - vec![ImpliedBound::RegionSubRegion(r_b, r_a)], - }, - - ty::Predicate::TypeOutlives(ref data) => - match infcx.tcx.no_late_bound_regions(data) { - None => vec![], - Some(ty::OutlivesPredicate(ty_a, r_b)) => { - let ty_a = infcx.resolve_type_vars_if_possible(&ty_a); - let components = infcx.tcx.outlives_components(ty_a); - implied_bounds_from_components(r_b, components) - } - }, - }})); - } - - implied_bounds -} - -/// When we have an implied bound that `T: 'a`, we can further break -/// 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: ty::Region<'tcx>, - sup_components: Vec>) - -> Vec> -{ - sup_components - .into_iter() - .flat_map(|component| { - match component { - Component::Region(r) => - vec![ImpliedBound::RegionSubRegion(sub_region, r)], - Component::Param(p) => - vec![ImpliedBound::RegionSubParam(sub_region, p)], - Component::Projection(p) => - vec![ImpliedBound::RegionSubProjection(sub_region, p)], - Component::EscapingProjection(_) => - // If the projection has escaping regions, don't - // try to infer any implied bounds even for its - // free components. This is conservative, because - // the caller will still have to prove that those - // free components outlive `sub_region`. But the - // idea is that the WAY that the caller proves - // that may change in the future and we want to - // give ourselves room to get smarter here. - vec![], - Component::UnresolvedInferenceVariable(..) => - vec![], - } - }) - .collect() -} - struct WfPredicates<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs index 17564671a1e3..40ee3cd28f56 100644 --- a/src/librustc/util/common.rs +++ b/src/librustc/util/common.rs @@ -19,6 +19,8 @@ use std::iter::repeat; use std::path::Path; use std::time::{Duration, Instant}; +use ty::TyCtxt; + // The name of the associated type for `Fn` return types pub const FN_OUTPUT_NAME: &'static str = "Output"; @@ -209,7 +211,7 @@ pub trait MemoizationMap { /// needed in the `op` to ensure that the correct edges are /// added into the dep graph. See the `DepTrackingMap` impl for /// more details! - fn memoize(&self, key: Self::Key, op: OP) -> Self::Value + fn memoize(&self, tcx: TyCtxt, key: Self::Key, op: OP) -> Self::Value where OP: FnOnce() -> Self::Value; } @@ -219,7 +221,7 @@ impl MemoizationMap for RefCell> type Key = K; type Value = V; - fn memoize(&self, key: K, op: OP) -> V + fn memoize(&self, _tcx: TyCtxt, key: K, op: OP) -> V where OP: FnOnce() -> V { let result = self.borrow().get(&key).cloned(); diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 15fbeb5108fd..1fa635771966 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -8,8 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use hir::BodyId; use hir::def_id::DefId; use hir::map::definitions::DefPathData; +use middle::region::{CodeExtent, BlockRemainder}; use ty::subst::{self, Subst}; use ty::{BrAnon, BrEnv, BrFresh, BrNamed}; use ty::{TyBool, TyChar, TyAdt}; @@ -32,6 +34,10 @@ pub fn verbose() -> bool { ty::tls::with(|tcx| tcx.sess.verbose()) } +pub fn identify_regions() -> bool { + ty::tls::with(|tcx| tcx.sess.opts.debugging_opts.identify_regions) +} + fn fn_sig(f: &mut fmt::Formatter, inputs: &[Ty], variadic: bool, @@ -519,6 +525,23 @@ impl fmt::Display for ty::RegionKind { ty::ReSkolemized(_, br) => { write!(f, "{}", br) } + ty::ReScope(code_extent) if identify_regions() => { + match code_extent { + CodeExtent::Misc(node_id) => + write!(f, "'{}mce", node_id.as_u32()), + CodeExtent::CallSiteScope(BodyId { node_id }) => + write!(f, "'{}cce", node_id.as_u32()), + CodeExtent::ParameterScope(BodyId { node_id }) => + write!(f, "'{}pce", node_id.as_u32()), + CodeExtent::DestructionScope(node_id) => + write!(f, "'{}dce", node_id.as_u32()), + CodeExtent::Remainder(BlockRemainder { block, first_statement_index }) => + write!(f, "'{}_{}rce", block, first_statement_index), + } + } + ty::ReVar(region_vid) if identify_regions() => { + write!(f, "'{}rv", region_vid.index) + } ty::ReScope(_) | ty::ReVar(_) | ty::ReErased => Ok(()), @@ -789,7 +812,11 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> { write!(f, "[closure")?; if let Some(node_id) = tcx.hir.as_local_node_id(did) { - write!(f, "@{:?}", tcx.hir.span(node_id))?; + if tcx.sess.opts.debugging_opts.span_free_formats { + write!(f, "@{:?}", node_id)?; + } else { + write!(f, "@{:?}", tcx.hir.span(node_id))?; + } let mut sep = " "; tcx.with_freevars(node_id, |freevars| { for (freevar, upvar_ty) in freevars.iter().zip(upvar_tys) { diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs index 122a37ee32ae..ae2be28c198b 100644 --- a/src/librustc_borrowck/borrowck/check_loans.rs +++ b/src/librustc_borrowck/borrowck/check_loans.rs @@ -192,7 +192,6 @@ pub fn check_loans<'a, 'b, 'c, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, debug!("check_loans(body id={})", body.value.id); let def_id = bccx.tcx.hir.body_owner_def_id(body.id()); - let infcx = bccx.tcx.borrowck_fake_infer_ctxt(body.id()); let param_env = bccx.tcx.param_env(def_id); let mut clcx = CheckLoanCtxt { bccx: bccx, @@ -201,7 +200,8 @@ pub fn check_loans<'a, 'b, 'c, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, all_loans: all_loans, param_env, }; - euv::ExprUseVisitor::new(&mut clcx, &bccx.region_maps, &infcx, param_env).consume_body(body); + euv::ExprUseVisitor::new(&mut clcx, bccx.tcx, param_env, &bccx.region_maps, bccx.tables) + .consume_body(body); } #[derive(PartialEq)] diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs index 85a09969ac81..7dcb6ce76a40 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs @@ -18,7 +18,6 @@ use borrowck::*; use borrowck::move_data::MoveData; -use rustc::infer::InferCtxt; use rustc::middle::expr_use_visitor as euv; use rustc::middle::mem_categorization as mc; use rustc::middle::mem_categorization::Categorization; @@ -40,11 +39,9 @@ pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, body: hir::BodyId) -> (Vec>, move_data::MoveData<'tcx>) { let def_id = bccx.tcx.hir.body_owner_def_id(body); - let infcx = bccx.tcx.borrowck_fake_infer_ctxt(body); let param_env = bccx.tcx.param_env(def_id); let mut glcx = GatherLoanCtxt { bccx: bccx, - infcx: &infcx, all_loans: Vec::new(), item_ub: region::CodeExtent::Misc(body.node_id), move_data: MoveData::new(), @@ -52,7 +49,8 @@ pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, }; let body = glcx.bccx.tcx.hir.body(body); - euv::ExprUseVisitor::new(&mut glcx, &bccx.region_maps, &infcx, param_env).consume_body(body); + euv::ExprUseVisitor::new(&mut glcx, bccx.tcx, param_env, &bccx.region_maps, bccx.tables) + .consume_body(body); glcx.report_potential_errors(); let GatherLoanCtxt { all_loans, move_data, .. } = glcx; @@ -61,7 +59,6 @@ pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, struct GatherLoanCtxt<'a, 'tcx: 'a> { bccx: &'a BorrowckCtxt<'a, 'tcx>, - infcx: &'a InferCtxt<'a, 'tcx, 'tcx>, move_data: move_data::MoveData<'tcx>, move_error_collector: move_error::MoveErrorCollector<'tcx>, all_loans: Vec>, @@ -158,7 +155,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for GatherLoanCtxt<'a, 'tcx> { } fn decl_without_init(&mut self, id: ast::NodeId, _span: Span) { - let ty = self.infcx.tables.borrow().node_id_to_type(id); + let ty = self.bccx.tables.node_id_to_type(id); gather_moves::gather_decl(self.bccx, &self.move_data, id, ty); } } diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs b/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs index da8aa231ccf1..1a1ac7f9c74d 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs @@ -474,6 +474,7 @@ impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> { mir::StatementKind::StorageLive(_) | mir::StatementKind::StorageDead(_) | mir::StatementKind::InlineAsm { .. } | + mir::StatementKind::EndRegion(_) | mir::StatementKind::Nop => {} } } diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs b/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs index 44e3b38ea385..2c55460fb301 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs @@ -105,6 +105,7 @@ fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>, mir::StatementKind::StorageLive(_) | mir::StatementKind::StorageDead(_) | mir::StatementKind::InlineAsm { .. } | + mir::StatementKind::EndRegion(_) | mir::StatementKind::Nop => continue, mir::StatementKind::SetDiscriminant{ .. } => span_bug!(stmt.source_info.span, diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs index b03d34819f63..833697726089 100644 --- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs +++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs @@ -594,6 +594,11 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { assert!(self.patch.is_patched(bb)); allow_initializations = false; } + TerminatorKind::Resume => { + // It is possible for `Resume` to be patched + // (in particular it can be patched to be replaced with + // a Goto; see `MirPatch::new`). + } _ => { assert!(!self.patch.is_patched(bb)); } diff --git a/src/librustc_borrowck/borrowck/mir/gather_moves.rs b/src/librustc_borrowck/borrowck/mir/gather_moves.rs index b03d2a775df7..a0ecdcc8e2ff 100644 --- a/src/librustc_borrowck/borrowck/mir/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/mir/gather_moves.rs @@ -413,6 +413,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { "SetDiscriminant should not exist during borrowck"); } StatementKind::InlineAsm { .. } | + StatementKind::EndRegion(_) | StatementKind::Nop => {} } } diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs index 2b39d2a256e1..e3b99b9d4bd4 100644 --- a/src/librustc_borrowck/borrowck/mir/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/mod.rs @@ -394,6 +394,7 @@ fn drop_flag_effects_for_location<'a, 'tcx, F>( mir::StatementKind::StorageLive(_) | mir::StatementKind::StorageDead(_) | mir::StatementKind::InlineAsm { .. } | + mir::StatementKind::EndRegion(_) | mir::StatementKind::Nop => {} }, None => { diff --git a/src/librustc_borrowck/diagnostics.rs b/src/librustc_borrowck/diagnostics.rs index 2a38dcfd26e1..c114c66559ff 100644 --- a/src/librustc_borrowck/diagnostics.rs +++ b/src/librustc_borrowck/diagnostics.rs @@ -144,7 +144,7 @@ that at most one writer or multiple readers can access the data at any one time. If you wish to learn more about ownership in Rust, start with the chapter in the Book: -https://doc.rust-lang.org/book/ownership.html +https://doc.rust-lang.org/book/first-edition/ownership.html "##, E0383: r##" @@ -366,8 +366,8 @@ let mut a = &mut i; Please note that in rust, you can either have many immutable references, or one mutable reference. Take a look at -https://doc.rust-lang.org/stable/book/references-and-borrowing.html for more -information. Example: +https://doc.rust-lang.org/book/first-edition/references-and-borrowing.html +for more information. Example: ``` @@ -533,7 +533,7 @@ fn foo(a: &mut i32) { ``` For more information on the rust ownership system, take a look at -https://doc.rust-lang.org/stable/book/references-and-borrowing.html. +https://doc.rust-lang.org/book/first-edition/references-and-borrowing.html. "##, E0503: r##" @@ -589,7 +589,7 @@ fn main() { ``` You can find more information about borrowing in the rust-book: -http://doc.rust-lang.org/stable/book/references-and-borrowing.html +http://doc.rust-lang.org/book/first-edition/references-and-borrowing.html "##, E0504: r##" @@ -773,7 +773,7 @@ fn main() { ``` You can find more information about borrowing in the rust-book: -http://doc.rust-lang.org/stable/book/references-and-borrowing.html +http://doc.rust-lang.org/book/first-edition/references-and-borrowing.html "##, E0506: r##" @@ -972,7 +972,7 @@ fn main() { ``` You can find more information about borrowing in the rust-book: -http://doc.rust-lang.org/stable/book/references-and-borrowing.html +http://doc.rust-lang.org/book/first-edition/references-and-borrowing.html "##, E0508: r##" diff --git a/src/librustc_const_eval/_match.rs b/src/librustc_const_eval/_match.rs index c1dc5f5f7a2b..98d90188312d 100644 --- a/src/librustc_const_eval/_match.rs +++ b/src/librustc_const_eval/_match.rs @@ -774,21 +774,26 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>, }, ty::TyRef(_, ref ty_and_mut) => vec![ty_and_mut.ty], ty::TyAdt(adt, substs) => { - adt.variants[ctor.variant_index_for_adt(adt)].fields.iter().map(|field| { - let is_visible = adt.is_enum() - || field.vis.is_accessible_from(cx.module, cx.tcx); - if is_visible { - field.ty(cx.tcx, substs) - } else { - // Treat all non-visible fields as nil. They - // can't appear in any other pattern from - // this match (because they are private), - // so their type does not matter - but - // we don't want to know they are - // uninhabited. - cx.tcx.mk_nil() - } - }).collect() + if adt.is_box() { + // Use T as the sub pattern type of Box. + vec![substs[0].as_type().unwrap()] + } else { + adt.variants[ctor.variant_index_for_adt(adt)].fields.iter().map(|field| { + let is_visible = adt.is_enum() + || field.vis.is_accessible_from(cx.module, cx.tcx); + if is_visible { + field.ty(cx.tcx, substs) + } else { + // Treat all non-visible fields as nil. They + // can't appear in any other pattern from + // this match (because they are private), + // so their type does not matter - but + // we don't want to know they are + // uninhabited. + cx.tcx.mk_nil() + } + }).collect() + } } _ => vec![], } diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index 7c3076fda4fe..fcdabf89e3cd 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -493,19 +493,18 @@ fn check_legality_of_move_bindings(cx: &MatchVisitor, /// /// FIXME: this should be done by borrowck. fn check_for_mutation_in_guard(cx: &MatchVisitor, guard: &hir::Expr) { - cx.tcx.infer_ctxt(cx.tables).enter(|infcx| { - let mut checker = MutationChecker { - cx: cx, - }; - ExprUseVisitor::new(&mut checker, cx.region_maps, &infcx, cx.param_env).walk_expr(guard); - }); + let mut checker = MutationChecker { + cx: cx, + }; + ExprUseVisitor::new(&mut checker, cx.tcx, cx.param_env, cx.region_maps, cx.tables) + .walk_expr(guard); } -struct MutationChecker<'a, 'gcx: 'a> { - cx: &'a MatchVisitor<'a, 'gcx>, +struct MutationChecker<'a, 'tcx: 'a> { + cx: &'a MatchVisitor<'a, 'tcx>, } -impl<'a, 'gcx, 'tcx> Delegate<'tcx> for MutationChecker<'a, 'gcx> { +impl<'a, 'tcx> Delegate<'tcx> for MutationChecker<'a, 'tcx> { fn matched_pat(&mut self, _: &Pat, _: cmt, _: euv::MatchMode) {} fn consume(&mut self, _: ast::NodeId, _: Span, _: cmt, _: ConsumeMode) {} fn consume_pat(&mut self, _: &Pat, _: cmt, _: ConsumeMode) {} diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index 3d07ffc2bc77..4ce985568ce2 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -351,7 +351,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, signal!(e, TypeckError) } } else { - if tcx.sess.cstore.is_const_fn(def_id) { + if tcx.is_const_fn(def_id) { tcx.sess.cstore.item_body(tcx, def_id) } else { signal!(e, TypeckError) @@ -483,7 +483,7 @@ fn resolve_trait_associated_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, debug!("resolve_trait_associated_const: trait_ref={:?}", trait_ref); - tcx.infer_ctxt(()).enter(|infcx| { + tcx.infer_ctxt().enter(|infcx| { let param_env = ty::ParamEnv::empty(Reveal::UserFacing); let mut selcx = traits::SelectionContext::new(&infcx); let obligation = traits::Obligation::new(traits::ObligationCause::dummy(), diff --git a/src/librustc_data_structures/fnv.rs b/src/librustc_data_structures/fnv.rs index ae90c2fac832..5bd57236e7c2 100644 --- a/src/librustc_data_structures/fnv.rs +++ b/src/librustc_data_structures/fnv.rs @@ -26,7 +26,7 @@ pub fn FnvHashSet() -> FnvHashSet { } /// A speedy hash algorithm for node ids and def ids. The hashmap in -/// libcollections by default uses SipHash which isn't quite as speedy as we +/// liballoc by default uses SipHash which isn't quite as speedy as we /// want. In the compiler we're not really worried about DOS attempts, so we /// just default to a non-cryptographic hash. /// diff --git a/src/librustc_data_structures/fx.rs b/src/librustc_data_structures/fx.rs index 1fb7673521d8..00dfc1617a8b 100644 --- a/src/librustc_data_structures/fx.rs +++ b/src/librustc_data_structures/fx.rs @@ -26,7 +26,7 @@ pub fn FxHashSet() -> FxHashSet { HashSet::default() } -/// A speedy hash algorithm for use within rustc. The hashmap in libcollections +/// A speedy hash algorithm for use within rustc. The hashmap in liballoc /// by default uses SipHash which isn't quite as speedy as we want. In the /// compiler we're not really worried about DOS attempts, so we use a fast /// non-cryptographic hash. diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 83cd5cef00cf..cc0e5dec266d 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -36,11 +36,11 @@ #![feature(discriminant_value)] #![feature(specialization)] #![feature(manually_drop)] -#![feature(struct_field_attributes)] #![cfg_attr(stage0, unstable(feature = "rustc_private", issue = "27812"))] #![cfg_attr(stage0, feature(rustc_private))] #![cfg_attr(stage0, feature(staged_api))] +#![cfg_attr(stage0, feature(struct_field_attributes))] #![cfg_attr(unix, feature(libc))] #![cfg_attr(test, feature(test))] diff --git a/src/librustc_data_structures/stable_hasher.rs b/src/librustc_data_structures/stable_hasher.rs index 635b95d861da..5e291ea3c152 100644 --- a/src/librustc_data_structures/stable_hasher.rs +++ b/src/librustc_data_structures/stable_hasher.rs @@ -78,6 +78,17 @@ impl StableHasherResult for [u8; 20] { } } +impl StableHasherResult for u128 { + fn finish(mut hasher: StableHasher) -> Self { + let hash_bytes: &[u8] = hasher.finalize(); + assert!(hash_bytes.len() >= mem::size_of::()); + + unsafe { + ::std::ptr::read_unaligned(hash_bytes.as_ptr() as *const u128) + } + } +} + impl StableHasherResult for u64 { fn finish(mut hasher: StableHasher) -> Self { hasher.state.finalize(); @@ -244,6 +255,14 @@ impl HashStable for f64 { } } +impl, CTX> HashStable for (T1,) { + fn hash_stable(&self, + ctx: &mut CTX, + hasher: &mut StableHasher) { + self.0.hash_stable(ctx, hasher); + } +} + impl, T2: HashStable, CTX> HashStable for (T1, T2) { fn hash_stable(&self, ctx: &mut CTX, @@ -273,6 +292,24 @@ impl, CTX> HashStable for Vec { } } +impl, CTX> HashStable for ::std::rc::Rc { + #[inline] + fn hash_stable(&self, + ctx: &mut CTX, + hasher: &mut StableHasher) { + (**self).hash_stable(ctx, hasher); + } +} + +impl, CTX> HashStable for ::std::sync::Arc { + #[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, diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index bca82ff9a46d..159fee6aa4c9 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -204,7 +204,8 @@ pub fn compile_input(sess: &Session, println!("Pre-trans"); tcx.print_debug_stats(); } - let trans = phase_4_translate_to_llvm(tcx, analysis, &incremental_hashes_map); + let trans = phase_4_translate_to_llvm(tcx, analysis, &incremental_hashes_map, + &outputs); if log_enabled!(::log::LogLevel::Info) { println!("Post-trans"); @@ -899,6 +900,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, reachable::provide(&mut local_providers); rustc_const_eval::provide(&mut local_providers); middle::region::provide(&mut local_providers); + cstore::provide_local(&mut local_providers); let mut extern_providers = ty::maps::Providers::default(); cstore::provide(&mut extern_providers); @@ -912,6 +914,9 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, let mut passes = Passes::new(); passes.push_hook(mir::transform::dump_mir::DumpMir); + // Remove all `EndRegion` statements that are not involved in borrows. + passes.push_pass(MIR_CONST, mir::transform::clean_end_regions::CleanEndRegions); + // 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); @@ -1042,18 +1047,19 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, /// be discarded. pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, analysis: ty::CrateAnalysis, - incremental_hashes_map: &IncrementalHashesMap) + incremental_hashes_map: &IncrementalHashesMap, + output_filenames: &OutputFilenames) -> trans::CrateTranslation { let time_passes = tcx.sess.time_passes(); time(time_passes, "resolving dependency formats", - || dependency_format::calculate(&tcx.sess)); + || dependency_format::calculate(tcx)); let translation = time(time_passes, "translation", - move || trans::trans_crate(tcx, analysis, &incremental_hashes_map)); + move || trans::trans_crate(tcx, analysis, &incremental_hashes_map, output_filenames)); time(time_passes, "assert dep graph", diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index c5f89e861fa1..6839274800ce 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -534,15 +534,12 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { fn save_analysis(sess: &Session) -> bool { sess.opts.debugging_opts.save_analysis || - sess.opts.debugging_opts.save_analysis_csv || sess.opts.debugging_opts.save_analysis_api } fn save_analysis_format(sess: &Session) -> save::Format { if sess.opts.debugging_opts.save_analysis { save::Format::Json - } else if sess.opts.debugging_opts.save_analysis_csv { - save::Format::Csv } else if sess.opts.debugging_opts.save_analysis_api { save::Format::JsonApi } else { @@ -1101,7 +1098,10 @@ pub fn monitor(f: F) { } let xs = ["the compiler unexpectedly panicked. this is a bug.".to_string(), - format!("we would appreciate a bug report: {}", BUG_REPORT_URL)]; + format!("we would appreciate a bug report: {}", BUG_REPORT_URL), + format!("rustc {} running on {}", + option_env!("CFG_VERSION").unwrap_or("unknown_version"), + config::host_triple())]; for note in &xs { handler.emit(&MultiSpan::new(), ¬e, diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 2b74d0a812b4..62e20a90f8a0 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -154,7 +154,7 @@ fn test_env(source_string: &str, index, "test_crate", |tcx| { - tcx.infer_ctxt(()).enter(|infcx| { + tcx.infer_ctxt().enter(|infcx| { let mut region_maps = RegionMaps::new(); body(Env { infcx: &infcx, diff --git a/src/librustc_errors/diagnostic.rs b/src/librustc_errors/diagnostic.rs index 7a64cdeee65c..d7c21127474a 100644 --- a/src/librustc_errors/diagnostic.rs +++ b/src/librustc_errors/diagnostic.rs @@ -248,6 +248,10 @@ impl Diagnostic { self.message.iter().map(|i| i.0.to_owned()).collect::() } + pub fn set_message(&mut self, message: &str) { + self.message = vec![(message.to_owned(), Style::NoStyle)]; + } + pub fn styled_message(&self) -> &Vec<(String, Style)> { &self.message } diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index f820ea4c5e17..2d25d12d3a96 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -17,6 +17,7 @@ use RenderSpan::*; use snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, StyledString, Style}; use styled_buffer::StyledBuffer; +use std::borrow::Cow; use std::io::prelude::*; use std::io; use std::rc::Rc; @@ -131,7 +132,7 @@ impl EmitterWriter { } } - fn preprocess_annotations(&self, msp: &MultiSpan) -> Vec { + fn preprocess_annotations(&mut self, msp: &MultiSpan) -> Vec { fn add_annotation_to_file(file_vec: &mut Vec, file: Rc, line_index: usize, @@ -175,6 +176,7 @@ impl EmitterWriter { 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); @@ -445,8 +447,11 @@ impl EmitterWriter { && 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()) + || (annotation.takes_space() && next.takes_space()) + || (overlaps(next, annotation, l) + && next.end_col <= annotation.end_col + && next.has_label() + && p == 0) // Avoid #42595. { // This annotation needs a new line in the output. p += 1; @@ -887,10 +892,10 @@ impl EmitterWriter { let mut annotated_files = self.preprocess_annotations(msp); // Make sure our primary file comes first - let primary_lo = if let (Some(ref cm), Some(ref primary_span)) = + let (primary_lo, cm) = if let (Some(cm), Some(ref primary_span)) = (self.cm.as_ref(), msp.primary_span().as_ref()) { if primary_span != &&DUMMY_SP { - cm.lookup_char_pos(primary_span.lo) + (cm.lookup_char_pos(primary_span.lo), cm) } else { emit_to_destination(&buffer.render(), level, &mut self.dst)?; return Ok(()); @@ -908,7 +913,7 @@ impl EmitterWriter { // Print out the annotate source lines that correspond with the error for annotated_file in annotated_files { // we can't annotate anything if the source is unavailable. - if annotated_file.file.src.is_none() { + if !cm.ensure_filemap_source_present(annotated_file.file.clone()) { continue; } @@ -1009,7 +1014,7 @@ impl EmitterWriter { } else if line_idx_delta == 2 { let unannotated_line = annotated_file.file .get_line(annotated_file.lines[line_idx].line_index) - .unwrap_or(""); + .unwrap_or_else(|| Cow::from("")); let last_buffer_line_num = buffer.num_lines(); diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index 8d5e9e776ed2..975b720276e8 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -37,6 +37,7 @@ use self::Level::*; use emitter::{Emitter, EmitterWriter}; +use std::borrow::Cow; use std::cell::{RefCell, Cell}; use std::{error, fmt}; use std::rc::Rc; @@ -49,7 +50,7 @@ pub mod registry; pub mod styled_buffer; mod lock; -use syntax_pos::{BytePos, Loc, FileLinesResult, FileName, MultiSpan, Span, NO_EXPANSION}; +use syntax_pos::{BytePos, Loc, FileLinesResult, FileMap, FileName, MultiSpan, Span, NO_EXPANSION}; #[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)] pub enum RenderSpan { @@ -103,6 +104,7 @@ pub trait CodeMapper { fn span_to_filename(&self, sp: Span) -> FileName; fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option; fn call_span_if_macro(&self, sp: Span) -> Span; + fn ensure_filemap_source_present(&self, file_map: Rc) -> bool; } impl CodeSuggestion { @@ -121,7 +123,7 @@ impl CodeSuggestion { use syntax_pos::{CharPos, Loc, Pos}; fn push_trailing(buf: &mut String, - line_opt: Option<&str>, + line_opt: Option<&Cow>, lo: &Loc, hi_opt: Option<&Loc>) { let (lo, hi_opt) = (lo.col.to_usize(), hi_opt.map(|hi| hi.col.to_usize())); @@ -183,13 +185,13 @@ impl CodeSuggestion { let cur_lo = cm.lookup_char_pos(sp.lo); for (buf, substitute) in bufs.iter_mut().zip(substitutes) { if prev_hi.line == cur_lo.line { - push_trailing(buf, prev_line, &prev_hi, Some(&cur_lo)); + push_trailing(buf, prev_line.as_ref(), &prev_hi, Some(&cur_lo)); } else { - push_trailing(buf, prev_line, &prev_hi, None); + push_trailing(buf, prev_line.as_ref(), &prev_hi, None); // push lines between the previous and current span (if any) for idx in prev_hi.line..(cur_lo.line - 1) { if let Some(line) = fm.get_line(idx) { - buf.push_str(line); + buf.push_str(line.as_ref()); buf.push('\n'); } } @@ -205,7 +207,7 @@ impl CodeSuggestion { for buf in &mut bufs { // if the replacement already ends with a newline, don't print the next line if !buf.ends_with('\n') { - push_trailing(buf, prev_line, &prev_hi, None); + push_trailing(buf, prev_line.as_ref(), &prev_hi, None); } // remove trailing newline buf.pop(); diff --git a/src/librustc_incremental/assert_dep_graph.rs b/src/librustc_incremental/assert_dep_graph.rs index 39fe2188f68d..04192c35ef3a 100644 --- a/src/librustc_incremental/assert_dep_graph.rs +++ b/src/librustc_incremental/assert_dep_graph.rs @@ -44,7 +44,7 @@ //! ``` use graphviz as dot; -use rustc::dep_graph::{DepGraphQuery, DepNode}; +use rustc::dep_graph::{DepGraphQuery, DepNode, DepKind}; use rustc::dep_graph::debug::{DepNodeFilter, EdgeFilter}; use rustc::hir::def_id::DefId; use rustc::ty::TyCtxt; @@ -95,8 +95,8 @@ pub fn assert_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { check_paths(tcx, &if_this_changed, &then_this_would_need); } -type Sources = Vec<(Span, DefId, DepNode)>; -type Targets = Vec<(Span, ast::Name, ast::NodeId, DepNode)>; +type Sources = Vec<(Span, DefId, DepNode)>; +type Targets = Vec<(Span, ast::Name, ast::NodeId, DepNode)>; struct IfThisChanged<'a, 'tcx:'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -121,13 +121,14 @@ impl<'a, 'tcx> IfThisChanged<'a, 'tcx> { fn process_attrs(&mut self, node_id: ast::NodeId, attrs: &[ast::Attribute]) { let def_id = self.tcx.hir.local_def_id(node_id); + let def_path_hash = self.tcx.def_path_hash(def_id); for attr in attrs { if attr.check_name(ATTR_IF_THIS_CHANGED) { let dep_node_interned = self.argument(attr); let dep_node = match dep_node_interned { - None => DepNode::Hir(def_id), + None => def_path_hash.to_dep_node(DepKind::Hir), Some(n) => { - match DepNode::from_label_string(&n.as_str(), def_id) { + match DepNode::from_label_string(&n.as_str(), def_path_hash) { Ok(n) => n, Err(()) => { self.tcx.sess.span_fatal( @@ -142,7 +143,7 @@ impl<'a, 'tcx> IfThisChanged<'a, 'tcx> { let dep_node_interned = self.argument(attr); let dep_node = match dep_node_interned { Some(n) => { - match DepNode::from_label_string(&n.as_str(), def_id) { + match DepNode::from_label_string(&n.as_str(), def_path_hash) { Ok(n) => n, Err(()) => { self.tcx.sess.span_fatal( @@ -263,34 +264,34 @@ fn dump_graph(tcx: TyCtxt) { } } -pub struct GraphvizDepGraph<'q>(FxHashSet<&'q DepNode>, - Vec<(&'q DepNode, &'q DepNode)>); +pub struct GraphvizDepGraph<'q>(FxHashSet<&'q DepNode>, + Vec<(&'q DepNode, &'q DepNode)>); impl<'a, 'tcx, 'q> dot::GraphWalk<'a> for GraphvizDepGraph<'q> { - type Node = &'q DepNode; - type Edge = (&'q DepNode, &'q DepNode); - fn nodes(&self) -> dot::Nodes<&'q DepNode> { + type Node = &'q DepNode; + type Edge = (&'q DepNode, &'q DepNode); + fn nodes(&self) -> dot::Nodes<&'q DepNode> { let nodes: Vec<_> = self.0.iter().cloned().collect(); nodes.into_cow() } - fn edges(&self) -> dot::Edges<(&'q DepNode, &'q DepNode)> { + fn edges(&self) -> dot::Edges<(&'q DepNode, &'q DepNode)> { self.1[..].into_cow() } - fn source(&self, edge: &(&'q DepNode, &'q DepNode)) -> &'q DepNode { + fn source(&self, edge: &(&'q DepNode, &'q DepNode)) -> &'q DepNode { edge.0 } - fn target(&self, edge: &(&'q DepNode, &'q DepNode)) -> &'q DepNode { + fn target(&self, edge: &(&'q DepNode, &'q DepNode)) -> &'q DepNode { edge.1 } } impl<'a, 'tcx, 'q> dot::Labeller<'a> for GraphvizDepGraph<'q> { - type Node = &'q DepNode; - type Edge = (&'q DepNode, &'q DepNode); + type Node = &'q DepNode; + type Edge = (&'q DepNode, &'q DepNode); fn graph_id(&self) -> dot::Id { dot::Id::new("DependencyGraph").unwrap() } - fn node_id(&self, n: &&'q DepNode) -> dot::Id { + fn node_id(&self, n: &&'q DepNode) -> dot::Id { let s: String = format!("{:?}", n).chars() .map(|c| if c == '_' || c.is_alphanumeric() { c } else { '_' }) @@ -298,7 +299,7 @@ impl<'a, 'tcx, 'q> dot::Labeller<'a> for GraphvizDepGraph<'q> { debug!("n={:?} s={:?}", n, s); dot::Id::new(s).unwrap() } - fn node_label(&self, n: &&'q DepNode) -> dot::LabelText { + fn node_label(&self, n: &&'q DepNode) -> dot::LabelText { dot::LabelText::label(format!("{:?}", n)) } } @@ -306,8 +307,8 @@ impl<'a, 'tcx, 'q> dot::Labeller<'a> for GraphvizDepGraph<'q> { // Given an optional filter like `"x,y,z"`, returns either `None` (no // filter) or the set of nodes whose labels contain all of those // substrings. -fn node_set<'q>(query: &'q DepGraphQuery, filter: &DepNodeFilter) - -> Option>> +fn node_set<'q>(query: &'q DepGraphQuery, filter: &DepNodeFilter) + -> Option> { debug!("node_set(filter={:?})", filter); @@ -318,10 +319,10 @@ fn node_set<'q>(query: &'q DepGraphQuery, filter: &DepNodeFilter) Some(query.nodes().into_iter().filter(|n| filter.test(n)).collect()) } -fn filter_nodes<'q>(query: &'q DepGraphQuery, - sources: &Option>>, - targets: &Option>>) - -> FxHashSet<&'q DepNode> +fn filter_nodes<'q>(query: &'q DepGraphQuery, + sources: &Option>, + targets: &Option>) + -> FxHashSet<&'q DepNode> { if let &Some(ref sources) = sources { if let &Some(ref targets) = targets { @@ -336,10 +337,10 @@ fn filter_nodes<'q>(query: &'q DepGraphQuery, } } -fn walk_nodes<'q>(query: &'q DepGraphQuery, - starts: &FxHashSet<&'q DepNode>, +fn walk_nodes<'q>(query: &'q DepGraphQuery, + starts: &FxHashSet<&'q DepNode>, direction: Direction) - -> FxHashSet<&'q DepNode> + -> FxHashSet<&'q DepNode> { let mut set = FxHashSet(); for &start in starts { @@ -360,10 +361,10 @@ fn walk_nodes<'q>(query: &'q DepGraphQuery, set } -fn walk_between<'q>(query: &'q DepGraphQuery, - sources: &FxHashSet<&'q DepNode>, - targets: &FxHashSet<&'q DepNode>) - -> FxHashSet<&'q DepNode> +fn walk_between<'q>(query: &'q DepGraphQuery, + sources: &FxHashSet<&'q DepNode>, + targets: &FxHashSet<&'q DepNode>) + -> FxHashSet<&'q DepNode> { // This is a bit tricky. We want to include a node only if it is: // (a) reachable from a source and (b) will reach a target. And we @@ -391,7 +392,7 @@ fn walk_between<'q>(query: &'q DepGraphQuery, }) .collect(); - fn recurse(query: &DepGraphQuery, + fn recurse(query: &DepGraphQuery, node_states: &mut [State], node: NodeIndex) -> bool @@ -428,9 +429,9 @@ fn walk_between<'q>(query: &'q DepGraphQuery, } } -fn filter_edges<'q>(query: &'q DepGraphQuery, - nodes: &FxHashSet<&'q DepNode>) - -> Vec<(&'q DepNode, &'q DepNode)> +fn filter_edges<'q>(query: &'q DepGraphQuery, + nodes: &FxHashSet<&'q DepNode>) + -> Vec<(&'q DepNode, &'q DepNode)> { query.edges() .into_iter() diff --git a/src/librustc_incremental/calculate_svh/mod.rs b/src/librustc_incremental/calculate_svh/mod.rs index be4d610a8955..f30a0f553b98 100644 --- a/src/librustc_incremental/calculate_svh/mod.rs +++ b/src/librustc_incremental/calculate_svh/mod.rs @@ -29,7 +29,7 @@ use std::cell::RefCell; use std::hash::Hash; -use rustc::dep_graph::DepNode; +use rustc::dep_graph::{DepNode, DepKind}; use rustc::hir; use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; use rustc::hir::map::DefPathHash; @@ -44,7 +44,7 @@ use rustc_data_structures::accumulate_vec::AccumulateVec; pub type IchHasher = StableHasher; pub struct IncrementalHashesMap { - hashes: FxHashMap, Fingerprint>, + hashes: FxHashMap, // These are the metadata hashes for the current crate as they were stored // during the last compilation session. They are only loaded if @@ -62,16 +62,16 @@ impl IncrementalHashesMap { } } - pub fn get(&self, k: &DepNode) -> Option<&Fingerprint> { + pub fn get(&self, k: &DepNode) -> Option<&Fingerprint> { self.hashes.get(k) } - pub fn insert(&mut self, k: DepNode, v: Fingerprint) -> Option { - self.hashes.insert(k, v) + pub fn insert(&mut self, k: DepNode, v: Fingerprint) { + assert!(self.hashes.insert(k, v).is_none()); } pub fn iter<'a>(&'a self) - -> ::std::collections::hash_map::Iter<'a, DepNode, Fingerprint> { + -> ::std::collections::hash_map::Iter<'a, DepNode, Fingerprint> { self.hashes.iter() } @@ -80,10 +80,10 @@ impl IncrementalHashesMap { } } -impl<'a> ::std::ops::Index<&'a DepNode> for IncrementalHashesMap { +impl<'a> ::std::ops::Index<&'a DepNode> for IncrementalHashesMap { type Output = Fingerprint; - fn index(&self, index: &'a DepNode) -> &Fingerprint { + fn index(&self, index: &'a DepNode) -> &Fingerprint { match self.hashes.get(index) { Some(fingerprint) => fingerprint, None => { @@ -94,16 +94,16 @@ impl<'a> ::std::ops::Index<&'a DepNode> for IncrementalHashesMap { } struct ComputeItemHashesVisitor<'a, 'tcx: 'a> { - hcx: StableHashingContext<'a, 'tcx>, + hcx: StableHashingContext<'a, 'tcx, 'tcx>, hashes: IncrementalHashesMap, } impl<'a, 'tcx: 'a> ComputeItemHashesVisitor<'a, 'tcx> { fn compute_and_store_ich_for_item_like(&mut self, - dep_node: DepNode, + dep_node: DepNode, hash_bodies: bool, item_like: T) - where T: HashStable> + where T: HashStable> { if !hash_bodies && !self.hcx.tcx().sess.opts.build_dep_graph() { // If we just need the hashes in order to compute the SVH, we don't @@ -143,36 +143,29 @@ impl<'a, 'tcx: 'a> ComputeItemHashesVisitor<'a, 'tcx> { // add each item (in some deterministic order) to the overall // crate hash. { - let hcx = &mut self.hcx; let mut item_hashes: Vec<_> = self.hashes.iter() - .filter_map(|(item_dep_node, &item_hash)| { + .filter_map(|(&item_dep_node, &item_hash)| { // This `match` determines what kinds of nodes // go into the SVH: - match *item_dep_node { - DepNode::Hir(_) | - DepNode::HirBody(_) => { + match item_dep_node.kind { + DepKind::Hir | + DepKind::HirBody => { // We want to incoporate these into the // SVH. } - DepNode::AllLocalTraitImpls => { + DepKind::AllLocalTraitImpls => { // These are already covered by hashing // the HIR. return None } ref other => { - bug!("Found unexpected DepNode during \ + bug!("Found unexpected DepKind during \ SVH computation: {:?}", other) } } - // Convert from a DepNode to a - // DepNode where the u64 is the hash of - // the def-id's def-path: - let item_dep_node = - item_dep_node.map_def(|&did| Some(hcx.def_path_hash(did))) - .unwrap(); Some((item_dep_node, item_hash)) }) .collect(); @@ -183,7 +176,7 @@ impl<'a, 'tcx: 'a> ComputeItemHashesVisitor<'a, 'tcx> { krate.attrs.hash_stable(&mut self.hcx, &mut crate_state); let crate_hash = crate_state.finish(); - self.hashes.insert(DepNode::Krate, crate_hash); + self.hashes.insert(DepNode::new_no_params(DepKind::Krate), crate_hash); debug!("calculate_crate_hash: crate_hash={:?}", crate_hash); } @@ -206,11 +199,11 @@ impl<'a, 'tcx: 'a> ComputeItemHashesVisitor<'a, 'tcx> { body_ids: _, } = *krate; - let def_id = DefId::local(CRATE_DEF_INDEX); - self.compute_and_store_ich_for_item_like(DepNode::Hir(def_id), + let def_path_hash = self.hcx.tcx().hir.definitions().def_path_hash(CRATE_DEF_INDEX); + self.compute_and_store_ich_for_item_like(def_path_hash.to_dep_node(DepKind::Hir), false, (module, (span, attrs))); - self.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id), + self.compute_and_store_ich_for_item_like(def_path_hash.to_dep_node(DepKind::HirBody), true, (module, (span, attrs))); } @@ -255,27 +248,43 @@ impl<'a, 'tcx: 'a> ComputeItemHashesVisitor<'a, 'tcx> { let mut hasher = StableHasher::new(); impls.hash_stable(&mut self.hcx, &mut hasher); - self.hashes.insert(DepNode::AllLocalTraitImpls, hasher.finish()); + self.hashes.insert(DepNode::new_no_params(DepKind::AllLocalTraitImpls), + hasher.finish()); } } impl<'a, 'tcx: 'a> ItemLikeVisitor<'tcx> for ComputeItemHashesVisitor<'a, 'tcx> { fn visit_item(&mut self, item: &'tcx hir::Item) { let def_id = self.hcx.tcx().hir.local_def_id(item.id); - self.compute_and_store_ich_for_item_like(DepNode::Hir(def_id), false, item); - self.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id), true, item); + let def_path_hash = self.hcx.tcx().def_path_hash(def_id); + self.compute_and_store_ich_for_item_like(def_path_hash.to_dep_node(DepKind::Hir), + false, + item); + self.compute_and_store_ich_for_item_like(def_path_hash.to_dep_node(DepKind::HirBody), + true, + item); } fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem) { let def_id = self.hcx.tcx().hir.local_def_id(item.id); - self.compute_and_store_ich_for_item_like(DepNode::Hir(def_id), false, item); - self.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id), true, item); + let def_path_hash = self.hcx.tcx().def_path_hash(def_id); + self.compute_and_store_ich_for_item_like(def_path_hash.to_dep_node(DepKind::Hir), + false, + item); + self.compute_and_store_ich_for_item_like(def_path_hash.to_dep_node(DepKind::HirBody), + true, + item); } fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem) { let def_id = self.hcx.tcx().hir.local_def_id(item.id); - self.compute_and_store_ich_for_item_like(DepNode::Hir(def_id), false, item); - self.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id), true, item); + let def_path_hash = self.hcx.tcx().def_path_hash(def_id); + self.compute_and_store_ich_for_item_like(def_path_hash.to_dep_node(DepKind::Hir), + false, + item); + self.compute_and_store_ich_for_item_like(def_path_hash.to_dep_node(DepKind::HirBody), + true, + item); } } @@ -297,8 +306,13 @@ pub fn compute_incremental_hashes_map<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) for macro_def in krate.exported_macros.iter() { let def_id = tcx.hir.local_def_id(macro_def.id); - visitor.compute_and_store_ich_for_item_like(DepNode::Hir(def_id), false, macro_def); - visitor.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id), true, macro_def); + let def_path_hash = tcx.def_path_hash(def_id); + visitor.compute_and_store_ich_for_item_like(def_path_hash.to_dep_node(DepKind::Hir), + false, + macro_def); + visitor.compute_and_store_ich_for_item_like(def_path_hash.to_dep_node(DepKind::HirBody), + true, + macro_def); } visitor.compute_and_store_ich_for_trait_impls(krate); diff --git a/src/librustc_incremental/persist/data.rs b/src/librustc_incremental/persist/data.rs index 682a7051a1e9..06acfb5d7780 100644 --- a/src/librustc_incremental/persist/data.rs +++ b/src/librustc_incremental/persist/data.rs @@ -15,7 +15,6 @@ use rustc::hir::def_id::DefIndex; use rustc::hir::map::DefPathHash; use rustc::ich::Fingerprint; use rustc::middle::cstore::EncodedMetadataHash; -use std::sync::Arc; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; @@ -23,11 +22,11 @@ use rustc_data_structures::indexed_vec::{IndexVec, Idx}; #[derive(Debug, RustcEncodable, RustcDecodable)] pub struct SerializedDepGraph { /// The set of all DepNodes in the graph - pub nodes: IndexVec>, + pub nodes: IndexVec, /// For each DepNode, stores the list of edges originating from that /// DepNode. Encoded as a [start, end) pair indexing into edge_list_data, /// which holds the actual DepNodeIndices of the target nodes. - pub edge_list_indices: Vec<(u32, u32)>, + pub edge_list_indices: IndexVec, /// A flattened list of all edge targets in the graph. Edge sources are /// implicit in edge_list_indices. pub edge_list_data: Vec, @@ -35,7 +34,7 @@ pub struct SerializedDepGraph { /// These are output nodes that have no incoming edges. We track /// these separately so that when we reload all edges, we don't /// lose track of these nodes. - pub bootstrap_outputs: Vec>, + pub bootstrap_outputs: Vec, /// These are hashes of two things: /// - the HIR nodes in this crate @@ -56,7 +55,14 @@ pub struct SerializedDepGraph { /// will be different when we next compile) related to each node, /// but rather the `DefPathIndex`. This can then be retraced /// to find the current def-id. - pub hashes: Vec, + pub hashes: Vec<(DepNodeIndex, Fingerprint)>, +} + +impl SerializedDepGraph { + pub fn edge_targets_from(&self, source: DepNodeIndex) -> &[DepNodeIndex] { + let targets = self.edge_list_indices[source]; + &self.edge_list_data[targets.0 as usize .. targets.1 as usize] + } } /// The index of a DepNode in the SerializedDepGraph::nodes array. @@ -85,20 +91,10 @@ impl Idx for DepNodeIndex { } } -#[derive(Debug, RustcEncodable, RustcDecodable)] -pub struct SerializedHash { - /// def-id of thing being hashed - pub dep_node: DepNode, - - /// the hash as of previous compilation, computed by code in - /// `hash` module - pub hash: Fingerprint, -} - #[derive(Debug, RustcEncodable, RustcDecodable)] pub struct SerializedWorkProduct { /// node that produced the work-product - pub id: Arc, + pub id: WorkProductId, /// work-product data itself pub work_product: WorkProduct, @@ -127,10 +123,6 @@ pub struct SerializedMetadataHashes { /// (matching the one found in this structure). pub entry_hashes: Vec, - /// This map contains fingerprints that are not specific to some DefId but - /// describe something global to the whole crate. - pub global_hashes: Vec<(DepNode<()>, Fingerprint)>, - /// For each DefIndex (as it occurs in SerializedMetadataHash), this /// map stores the DefPathIndex (as it occurs in DefIdDirectory), so /// that we can find the new DefId for a SerializedMetadataHash in a diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index 3a428bd7b8f7..3f3dc10365c6 100644 --- a/src/librustc_incremental/persist/dirty_clean.rs +++ b/src/librustc_incremental/persist/dirty_clean.rs @@ -40,8 +40,9 @@ //! previous revision to compare things to. //! +use super::data::DepNodeIndex; use super::load::DirtyNodes; -use rustc::dep_graph::{DepGraphQuery, DepNode}; +use rustc::dep_graph::{DepGraphQuery, DepNode, DepKind}; use rustc::hir; use rustc::hir::def_id::DefId; use rustc::hir::itemlikevisit::ItemLikeVisitor; @@ -50,6 +51,7 @@ use rustc::ich::{Fingerprint, ATTR_DIRTY, ATTR_CLEAN, ATTR_DIRTY_METADATA, ATTR_CLEAN_METADATA}; use syntax::ast::{self, Attribute, NestedMetaItem}; use rustc_data_structures::fx::{FxHashSet, FxHashMap}; +use rustc_data_structures::indexed_vec::IndexVec; use syntax_pos::Span; use rustc::ty::TyCtxt; @@ -57,6 +59,7 @@ const LABEL: &'static str = "label"; const CFG: &'static str = "cfg"; pub fn check_dirty_clean_annotations<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + nodes: &IndexVec, dirty_inputs: &DirtyNodes) { // can't add `#[rustc_dirty]` etc without opting in to this feature if !tcx.sess.features.borrow().rustc_attrs { @@ -64,13 +67,15 @@ pub fn check_dirty_clean_annotations<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } let _ignore = tcx.dep_graph.in_ignore(); - let def_path_hash_to_def_id = tcx.def_path_hash_to_def_id.as_ref().unwrap(); - let dirty_inputs: FxHashSet> = + let dirty_inputs: FxHashSet = dirty_inputs.keys() - .filter_map(|dep_node| { - dep_node.map_def(|def_path_hash| { - def_path_hash_to_def_id.get(def_path_hash).cloned() - }) + .filter_map(|dep_node_index| { + let dep_node = nodes[*dep_node_index]; + if dep_node.extract_def_id(tcx).is_some() { + Some(dep_node) + } else { + None + } }) .collect(); @@ -100,18 +105,19 @@ pub fn check_dirty_clean_annotations<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pub struct DirtyCleanVisitor<'a, 'tcx:'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, - query: &'a DepGraphQuery, - dirty_inputs: FxHashSet>, + query: &'a DepGraphQuery, + dirty_inputs: FxHashSet, checked_attrs: FxHashSet, } impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> { - fn dep_node(&self, attr: &Attribute, def_id: DefId) -> DepNode { + fn dep_node(&self, attr: &Attribute, def_id: DefId) -> DepNode { + let def_path_hash = self.tcx.def_path_hash(def_id); for item in attr.meta_item_list().unwrap_or_else(Vec::new) { if item.check_name(LABEL) { let value = expect_associated_value(self.tcx, &item); - match DepNode::from_label_string(&value.as_str(), def_id) { - Ok(def_id) => return def_id, + match DepNode::from_label_string(&value.as_str(), def_path_hash) { + Ok(dep_node) => return dep_node, Err(()) => { self.tcx.sess.span_fatal( item.span, @@ -124,24 +130,30 @@ impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> { self.tcx.sess.span_fatal(attr.span, "no `label` found"); } - fn dep_node_str(&self, dep_node: &DepNode) -> DepNode { - dep_node.map_def(|&def_id| Some(self.tcx.item_path_str(def_id))).unwrap() + fn dep_node_str(&self, dep_node: &DepNode) -> String { + if let Some(def_id) = dep_node.extract_def_id(self.tcx) { + format!("{:?}({})", + dep_node.kind, + self.tcx.item_path_str(def_id)) + } else { + format!("{:?}({:?})", dep_node.kind, dep_node.hash) + } } - fn assert_dirty(&self, item_span: Span, dep_node: DepNode) { + fn assert_dirty(&self, item_span: Span, dep_node: DepNode) { debug!("assert_dirty({:?})", dep_node); - match dep_node { - DepNode::Krate | - DepNode::Hir(_) | - DepNode::HirBody(_) => { + match dep_node.kind { + DepKind::Krate | + DepKind::Hir | + DepKind::HirBody => { // HIR nodes are inputs, so if we are asserting that the HIR node is // dirty, we check the dirty input set. if !self.dirty_inputs.contains(&dep_node) { let dep_node_str = self.dep_node_str(&dep_node); self.tcx.sess.span_err( item_span, - &format!("`{:?}` not found in dirty set, but should be dirty", + &format!("`{}` not found in dirty set, but should be dirty", dep_node_str)); } } @@ -152,25 +164,25 @@ impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> { let dep_node_str = self.dep_node_str(&dep_node); self.tcx.sess.span_err( item_span, - &format!("`{:?}` found in dep graph, but should be dirty", dep_node_str)); + &format!("`{}` found in dep graph, but should be dirty", dep_node_str)); } } } } - fn assert_clean(&self, item_span: Span, dep_node: DepNode) { + fn assert_clean(&self, item_span: Span, dep_node: DepNode) { debug!("assert_clean({:?})", dep_node); - match dep_node { - DepNode::Krate | - DepNode::Hir(_) | - DepNode::HirBody(_) => { + match dep_node.kind { + DepKind::Krate | + DepKind::Hir | + DepKind::HirBody => { // For HIR nodes, check the inputs. if self.dirty_inputs.contains(&dep_node) { let dep_node_str = self.dep_node_str(&dep_node); self.tcx.sess.span_err( item_span, - &format!("`{:?}` found in dirty-node set, but should be clean", + &format!("`{}` found in dirty-node set, but should be clean", dep_node_str)); } } @@ -180,7 +192,7 @@ impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> { let dep_node_str = self.dep_node_str(&dep_node); self.tcx.sess.span_err( item_span, - &format!("`{:?}` not found in dep graph, but should be clean", + &format!("`{}` not found in dep graph, but should be clean", dep_node_str)); } } diff --git a/src/librustc_incremental/persist/hash.rs b/src/librustc_incremental/persist/hash.rs index 6ab280be470d..0e8ffb9ee3c9 100644 --- a/src/librustc_incremental/persist/hash.rs +++ b/src/librustc_incremental/persist/hash.rs @@ -8,8 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use rustc::dep_graph::DepNode; -use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE, CRATE_DEF_INDEX}; +use rustc::dep_graph::{DepNode, DepKind}; +use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc::hir::svh::Svh; use rustc::ich::Fingerprint; use rustc::ty::TyCtxt; @@ -29,9 +29,8 @@ use std::fmt::Debug; pub struct HashContext<'a, 'tcx: 'a> { pub tcx: TyCtxt<'a, 'tcx, 'tcx>, incremental_hashes_map: &'a IncrementalHashesMap, - item_metadata_hashes: FxHashMap, + metadata_hashes: FxHashMap, crate_hashes: FxHashMap, - global_metadata_hashes: FxHashMap, Fingerprint>, } impl<'a, 'tcx> HashContext<'a, 'tcx> { @@ -41,38 +40,34 @@ impl<'a, 'tcx> HashContext<'a, 'tcx> { HashContext { tcx: tcx, incremental_hashes_map: incremental_hashes_map, - item_metadata_hashes: FxHashMap(), + metadata_hashes: FxHashMap(), crate_hashes: FxHashMap(), - global_metadata_hashes: FxHashMap(), } } - pub fn is_hashable(dep_node: &DepNode) -> bool { - match *dep_node { - DepNode::Krate | - DepNode::Hir(_) | - DepNode::HirBody(_) => + pub fn is_hashable(tcx: TyCtxt, dep_node: &DepNode) -> bool { + match dep_node.kind { + DepKind::Krate | + DepKind::Hir | + DepKind::HirBody => true, - DepNode::MetaData(def_id) | - DepNode::GlobalMetaData(def_id, _) => !def_id.is_local(), + DepKind::MetaData => { + let def_id = dep_node.extract_def_id(tcx).unwrap(); + !def_id.is_local() + } _ => false, } } - pub fn hash(&mut self, dep_node: &DepNode) -> Option { - match *dep_node { - DepNode::Krate => { + pub fn hash(&mut self, dep_node: &DepNode) -> Option { + match dep_node.kind { + DepKind::Krate => { Some(self.incremental_hashes_map[dep_node]) } // HIR nodes (which always come from our crate) are an input: - DepNode::Hir(def_id) | - DepNode::HirBody(def_id) => { - assert!(def_id.is_local(), - "cannot hash HIR for non-local def-id {:?} => {:?}", - def_id, - self.tcx.item_path_str(def_id)); - + DepKind::Hir | + DepKind::HirBody => { Some(self.incremental_hashes_map[dep_node]) } @@ -80,16 +75,15 @@ impl<'a, 'tcx> HashContext<'a, 'tcx> { // MetaData nodes from *our* crates are an *output*; we // don't hash them, but we do compute a hash for them and // save it for others to use. - DepNode::MetaData(def_id) if !def_id.is_local() => { - Some(self.metadata_hash(def_id, + DepKind::MetaData => { + let def_id = dep_node.extract_def_id(self.tcx).unwrap(); + if !def_id.is_local() { + Some(self.metadata_hash(def_id, def_id.krate, - |this| &mut this.item_metadata_hashes)) - } - - DepNode::GlobalMetaData(def_id, kind) => { - Some(self.metadata_hash(DepNode::GlobalMetaData(def_id, kind), - def_id.krate, - |this| &mut this.global_metadata_hashes)) + |this| &mut this.metadata_hashes)) + } else { + None + } } _ => { @@ -217,27 +211,11 @@ impl<'a, 'tcx> HashContext<'a, 'tcx> { let def_id = DefId { krate: cnum, index: serialized_hash.def_index }; // record the hash for this dep-node - let old = self.item_metadata_hashes.insert(def_id, serialized_hash.hash); + let old = self.metadata_hashes.insert(def_id, serialized_hash.hash); debug!("load_from_data: def_id={:?} hash={}", def_id, serialized_hash.hash); assert!(old.is_none(), "already have hash for {:?}", def_id); } - for (dep_node, fingerprint) in serialized_hashes.global_hashes { - // Here we need to remap the CrateNum in the DepNode. - let def_id = DefId { krate: cnum, index: CRATE_DEF_INDEX }; - let dep_node = match dep_node { - DepNode::GlobalMetaData(_, kind) => DepNode::GlobalMetaData(def_id, kind), - other => { - bug!("unexpected DepNode variant: {:?}", other) - } - }; - - // record the hash for this dep-node - debug!("load_from_data: def_node={:?} hash={}", dep_node, fingerprint); - let old = self.global_metadata_hashes.insert(dep_node.clone(), fingerprint); - assert!(old.is_none(), "already have hash for {:?}", dep_node); - } - Ok(()) } } diff --git a/src/librustc_incremental/persist/load.rs b/src/librustc_incremental/persist/load.rs index b30a1f4d3254..28a00bf4aa6c 100644 --- a/src/librustc_incremental/persist/load.rs +++ b/src/librustc_incremental/persist/load.rs @@ -10,19 +10,17 @@ //! Code to save/load the dep-graph from files. -use rustc::dep_graph::{DepNode, WorkProductId}; +use rustc::dep_graph::{DepNode, WorkProductId, DepKind}; use rustc::hir::def_id::DefId; -use rustc::hir::map::DefPathHash; use rustc::hir::svh::Svh; use rustc::ich::Fingerprint; use rustc::session::Session; use rustc::ty::TyCtxt; use rustc_data_structures::fx::{FxHashSet, FxHashMap}; +use rustc_data_structures::indexed_vec::IndexVec; use rustc_serialize::Decodable as RustcDecodable; use rustc_serialize::opaque::Decoder; -use std::default::Default; use std::path::{Path}; -use std::sync::Arc; use IncrementalHashesMap; use super::data::*; @@ -34,7 +32,7 @@ use super::work_product; // The key is a dirty node. The value is **some** base-input that we // can blame it on. -pub type DirtyNodes = FxHashMap, DepNode>; +pub type DirtyNodes = FxHashMap; /// If we are in incremental mode, and a previous dep-graph exists, /// then load up those nodes/edges that are still valid into the @@ -119,14 +117,20 @@ fn load_data(sess: &Session, path: &Path) -> Option> { None } -/// Try to convert a DepNode from the old dep-graph into a DepNode in the -/// current graph by mapping the DefPathHash to a valid DefId. This will fail -/// if the DefPathHash refers to something that has been removed (because -/// there is no DefId for that thing anymore). -fn retrace(tcx: TyCtxt, dep_node: &DepNode) -> Option> { - dep_node.map_def(|def_path_hash| { - tcx.def_path_hash_to_def_id.as_ref().unwrap().get(def_path_hash).cloned() - }) +/// Check if a DepNode from the previous dep-graph refers to something that +/// still exists in the current compilation session. Only works for DepNode +/// variants that represent inputs (HIR and imported Metadata). +fn does_still_exist(tcx: TyCtxt, dep_node: &DepNode) -> bool { + match dep_node.kind { + DepKind::Hir | + DepKind::HirBody | + DepKind::MetaData => { + dep_node.extract_def_id(tcx).is_some() + } + _ => { + bug!("unexpected Input DepNode: {:?}", dep_node) + } + } } /// Decode the dep graph and load the edges/nodes that are still clean @@ -162,86 +166,55 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let serialized_dep_graph = SerializedDepGraph::decode(&mut dep_graph_decoder)?; - let edge_map: FxHashMap, Vec>> = { - let capacity = serialized_dep_graph.edge_list_data.len(); - let mut edge_map = FxHashMap::with_capacity_and_hasher(capacity, Default::default()); - - for (node_index, source) in serialized_dep_graph.nodes.iter().enumerate() { - let (start, end) = serialized_dep_graph.edge_list_indices[node_index]; - let targets = - (&serialized_dep_graph.edge_list_data[start as usize .. end as usize]) - .into_iter() - .map(|&node_index| serialized_dep_graph.nodes[node_index].clone()) - .collect(); - - edge_map.insert(source.clone(), targets); - } - - edge_map - }; - // Compute the set of nodes from the old graph where some input - // has changed or been removed. These are "raw" source nodes, - // which means that they still use the original `DefPathIndex` - // values from the encoding, rather than having been retraced to a - // `DefId`. The reason for this is that this way we can include - // nodes that have been removed (which no longer have a `DefId` in - // the current compilation). + // has changed or been removed. let dirty_raw_nodes = initial_dirty_nodes(tcx, incremental_hashes_map, + &serialized_dep_graph.nodes, &serialized_dep_graph.hashes); - let dirty_raw_nodes = transitive_dirty_nodes(&edge_map, dirty_raw_nodes); + let dirty_raw_nodes = transitive_dirty_nodes(&serialized_dep_graph, + dirty_raw_nodes); // Recreate the edges in the graph that are still clean. let mut clean_work_products = FxHashSet(); let mut dirty_work_products = FxHashSet(); // incomplete; just used to suppress debug output - let mut extra_edges = vec![]; - for (source, targets) in &edge_map { - for target in targets { - process_edges(tcx, source, target, &edge_map, &dirty_raw_nodes, - &mut clean_work_products, &mut dirty_work_products, &mut extra_edges); + for (source, targets) in serialized_dep_graph.edge_list_indices.iter_enumerated() { + let target_begin = targets.0 as usize; + let target_end = targets.1 as usize; + + for &target in &serialized_dep_graph.edge_list_data[target_begin .. target_end] { + process_edge(tcx, + source, + target, + &serialized_dep_graph.nodes, + &dirty_raw_nodes, + &mut clean_work_products, + &mut dirty_work_products); } } - // Recreate bootstrap outputs, which are outputs that have no incoming edges (and hence cannot - // be dirty). + // Recreate bootstrap outputs, which are outputs that have no incoming edges + // (and hence cannot be dirty). for bootstrap_output in &serialized_dep_graph.bootstrap_outputs { - if let Some(n) = retrace(tcx, bootstrap_output) { - if let DepNode::WorkProduct(ref wp) = n { - clean_work_products.insert(wp.clone()); - } - - tcx.dep_graph.with_task(n, (), (), create_node); - - fn create_node((): (), (): ()) { - // just create the node with no inputs - } + if let DepKind::WorkProduct = bootstrap_output.kind { + let wp_id = WorkProductId::from_fingerprint(bootstrap_output.hash); + clean_work_products.insert(wp_id); } - } - // Subtle. Sometimes we have intermediate nodes that we can't recreate in the new graph. - // This is pretty unusual but it arises in a scenario like this: - // - // Hir(X) -> Foo(Y) -> Bar - // - // Note that the `Hir(Y)` is not an input to `Foo(Y)` -- this - // almost never happens, but can happen in some obscure - // scenarios. In that case, if `Y` is removed, then we can't - // recreate `Foo(Y)` (the def-id `Y` no longer exists); what we do - // then is to push the edge `Hir(X) -> Bar` onto `extra_edges` - // (along with any other targets of `Foo(Y)`). We will then add - // the edge from `Hir(X)` to `Bar` (or, if `Bar` itself cannot be - // recreated, to the targets of `Bar`). - while let Some((source, target)) = extra_edges.pop() { - process_edges(tcx, source, target, &edge_map, &dirty_raw_nodes, - &mut clean_work_products, &mut dirty_work_products, &mut extra_edges); + tcx.dep_graph.with_task(*bootstrap_output, (), (), create_node); + + fn create_node((): (), (): ()) { + // just create the node with no inputs + } } // Add in work-products that are still clean, and delete those that are // dirty. reconcile_work_products(tcx, work_products, &clean_work_products); - dirty_clean::check_dirty_clean_annotations(tcx, &dirty_raw_nodes); + dirty_clean::check_dirty_clean_annotations(tcx, + &serialized_dep_graph.nodes, + &dirty_raw_nodes); load_prev_metadata_hashes(tcx, &mut *incremental_hashes_map.prev_metadata_hashes.borrow_mut()); @@ -252,70 +225,65 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, /// a bit vector where the index is the DefPathIndex. fn initial_dirty_nodes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, incremental_hashes_map: &IncrementalHashesMap, - serialized_hashes: &[SerializedHash]) + nodes: &IndexVec, + serialized_hashes: &[(DepNodeIndex, Fingerprint)]) -> DirtyNodes { let mut hcx = HashContext::new(tcx, incremental_hashes_map); let mut dirty_nodes = FxHashMap(); - let print_removed_message = |dep_node: &DepNode<_>| { - if tcx.sess.opts.debugging_opts.incremental_dump_hash { - println!("node {:?} is dirty as it was removed", dep_node); - } + for &(dep_node_index, prev_hash) in serialized_hashes { + let dep_node = nodes[dep_node_index]; + if does_still_exist(tcx, &dep_node) { + let current_hash = hcx.hash(&dep_node).unwrap_or_else(|| { + bug!("Cannot find current ICH for input that still exists?") + }); - debug!("initial_dirty_nodes: {:?} is dirty as it was removed", dep_node); - }; - - for hash in serialized_hashes { - if let Some(dep_node) = retrace(tcx, &hash.dep_node) { - if let Some(current_hash) = hcx.hash(&dep_node) { - if current_hash == hash.hash { - debug!("initial_dirty_nodes: {:?} is clean (hash={:?})", - dep_node.map_def(|&def_id| Some(tcx.def_path(def_id))).unwrap(), + if current_hash == prev_hash { + debug!("initial_dirty_nodes: {:?} is clean (hash={:?})", + dep_node, current_hash); - continue; - } - - if tcx.sess.opts.debugging_opts.incremental_dump_hash { - println!("node {:?} is dirty as hash is {:?} was {:?}", - dep_node.map_def(|&def_id| Some(tcx.def_path(def_id))).unwrap(), - current_hash, - hash.hash); - } - - debug!("initial_dirty_nodes: {:?} is dirty as hash is {:?}, was {:?}", - dep_node.map_def(|&def_id| Some(tcx.def_path(def_id))).unwrap(), - current_hash, - hash.hash); - } else { - print_removed_message(&hash.dep_node); + continue; } - } else { - print_removed_message(&hash.dep_node); - } - dirty_nodes.insert(hash.dep_node.clone(), hash.dep_node.clone()); + if tcx.sess.opts.debugging_opts.incremental_dump_hash { + println!("node {:?} is dirty as hash is {:?}, was {:?}", + dep_node, + current_hash, + prev_hash); + } + + debug!("initial_dirty_nodes: {:?} is dirty as hash is {:?}, was {:?}", + dep_node, + current_hash, + prev_hash); + } else { + if tcx.sess.opts.debugging_opts.incremental_dump_hash { + println!("node {:?} is dirty as it was removed", dep_node); + } + + debug!("initial_dirty_nodes: {:?} is dirty as it was removed", dep_node); + } + dirty_nodes.insert(dep_node_index, dep_node_index); } dirty_nodes } -fn transitive_dirty_nodes(edge_map: &FxHashMap, Vec>>, +fn transitive_dirty_nodes(serialized_dep_graph: &SerializedDepGraph, mut dirty_nodes: DirtyNodes) -> DirtyNodes { - let mut stack: Vec<(DepNode, DepNode)> = vec![]; - stack.extend(dirty_nodes.iter().map(|(s, b)| (s.clone(), b.clone()))); + let mut stack: Vec<(DepNodeIndex, DepNodeIndex)> = vec![]; + stack.extend(dirty_nodes.iter().map(|(&s, &b)| (s, b))); while let Some((source, blame)) = stack.pop() { // we know the source is dirty (because of the node `blame`)... - assert!(dirty_nodes.contains_key(&source)); + debug_assert!(dirty_nodes.contains_key(&source)); // ...so we dirty all the targets (with the same blame) - if let Some(targets) = edge_map.get(&source) { - for target in targets { - if !dirty_nodes.contains_key(target) { - dirty_nodes.insert(target.clone(), blame.clone()); - stack.push((target.clone(), blame.clone())); - } + for &target in serialized_dep_graph.edge_targets_from(source) { + if !dirty_nodes.contains_key(&target) { + dirty_nodes.insert(target, blame); + stack.push((target, blame)); } } } @@ -327,7 +295,7 @@ fn transitive_dirty_nodes(edge_map: &FxHashMap, Vec(tcx: TyCtxt<'a, 'tcx, 'tcx>, work_products: Vec, - clean_work_products: &FxHashSet>) { + clean_work_products: &FxHashSet) { debug!("reconcile_work_products({:?})", work_products); for swp in work_products { if !clean_work_products.contains(&swp.id) { @@ -367,6 +335,7 @@ fn delete_dirty_work_product(tcx: TyCtxt, fn load_prev_metadata_hashes(tcx: TyCtxt, output: &mut FxHashMap) { if !tcx.sess.opts.debugging_opts.query_dep_graph { + // Previous metadata hashes are only needed for testing. return } @@ -418,71 +387,75 @@ fn load_prev_metadata_hashes(tcx: TyCtxt, serialized_hashes.index_map.len()); } -fn process_edges<'a, 'tcx, 'edges>( +fn process_edge<'a, 'tcx, 'edges>( tcx: TyCtxt<'a, 'tcx, 'tcx>, - source: &'edges DepNode, - target: &'edges DepNode, - edges: &'edges FxHashMap, Vec>>, + source: DepNodeIndex, + target: DepNodeIndex, + nodes: &IndexVec, dirty_raw_nodes: &DirtyNodes, - clean_work_products: &mut FxHashSet>, - dirty_work_products: &mut FxHashSet>, - extra_edges: &mut Vec<(&'edges DepNode, &'edges DepNode)>) + clean_work_products: &mut FxHashSet, + dirty_work_products: &mut FxHashSet) { // If the target is dirty, skip the edge. If this is an edge // that targets a work-product, we can print the blame // information now. - if let Some(blame) = dirty_raw_nodes.get(target) { - if let DepNode::WorkProduct(ref wp) = *target { + if let Some(&blame) = dirty_raw_nodes.get(&target) { + let target = nodes[target]; + if let DepKind::WorkProduct = target.kind { if tcx.sess.opts.debugging_opts.incremental_info { - if dirty_work_products.insert(wp.clone()) { + let wp_id = WorkProductId::from_fingerprint(target.hash); + + if dirty_work_products.insert(wp_id) { // Try to reconstruct the human-readable version of the // DepNode. This cannot be done for things that where // removed. - let readable_blame = if let Some(dep_node) = retrace(tcx, blame) { - dep_node.map_def(|&def_id| Some(tcx.def_path(def_id).to_string(tcx))) - .unwrap() + let blame = nodes[blame]; + let blame_str = if let Some(def_id) = blame.extract_def_id(tcx) { + format!("{:?}({})", + blame.kind, + tcx.def_path(def_id).to_string(tcx)) } else { - blame.map_def(|def_path_hash| Some(format!("{:?}", def_path_hash))) - .unwrap() + format!("{:?}", blame) }; println!("incremental: module {:?} is dirty because {:?} \ changed or was removed", - wp, - readable_blame); + wp_id, + blame_str); } } } return; } - // If the source is dirty, the target will be dirty. - assert!(!dirty_raw_nodes.contains_key(source)); + // At this point we have asserted that the target is clean -- otherwise, we + // would have hit the return above. We can do some further consistency + // checks based on this fact: - // Retrace the source -> target edges to def-ids and then create - // an edge in the graph. Retracing may yield none if some of the - // data happens to have been removed. - if let Some(source_node) = retrace(tcx, source) { - if let Some(target_node) = retrace(tcx, target) { - let _task = tcx.dep_graph.in_task(target_node); - tcx.dep_graph.read(source_node); - if let DepNode::WorkProduct(ref wp) = *target { - clean_work_products.insert(wp.clone()); - } - } else { - // As discussed in `decode_dep_graph` above, sometimes the - // target cannot be recreated again, in which case we add - // edges to go from `source` to the targets of `target`. - extra_edges.extend( - edges[target].iter().map(|t| (source, t))); + // We should never have an edge where the target is clean but the source + // was dirty. Otherwise something was wrong with the dirtying pass above: + debug_assert!(!dirty_raw_nodes.contains_key(&source)); + + // We also never should encounter an edge going from a removed input to a + // clean target because removing the input would have dirtied the input + // node and transitively dirtied the target. + debug_assert!(match nodes[source].kind { + DepKind::Hir | DepKind::HirBody | DepKind::MetaData => { + does_still_exist(tcx, &nodes[source]) + } + _ => true, + }); + + if !dirty_raw_nodes.contains_key(&target) { + let target = nodes[target]; + let source = nodes[source]; + let _task = tcx.dep_graph.in_task(target); + tcx.dep_graph.read(source); + + if let DepKind::WorkProduct = target.kind { + let wp_id = WorkProductId::from_fingerprint(target.hash); + clean_work_products.insert(wp_id); } - } else { - // It's also possible that the source can't be created! But we - // can ignore such cases, because (a) if `source` is a HIR - // node, it would be considered dirty; and (b) in other cases, - // there must be some input to this node that is clean, and so - // we'll re-create the edges over in the case where target is - // undefined. } } diff --git a/src/librustc_incremental/persist/preds/mod.rs b/src/librustc_incremental/persist/preds/mod.rs index e769641a4cad..f7b6b7376d1f 100644 --- a/src/librustc_incremental/persist/preds/mod.rs +++ b/src/librustc_incremental/persist/preds/mod.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use rustc::dep_graph::{DepGraphQuery, DepNode}; -use rustc::hir::def_id::DefId; +use rustc::dep_graph::{DepGraphQuery, DepNode, DepKind}; use rustc::ich::Fingerprint; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::graph::{Graph, NodeIndex}; @@ -26,7 +25,7 @@ pub struct Predecessors<'query> { // nodes) and all of the "work-products" we may care about // later. Other nodes may be retained if it keeps the overall size // of the graph down. - pub reduced_graph: Graph<&'query DepNode, ()>, + pub reduced_graph: Graph<&'query DepNode, ()>, // These are output nodes that have no incoming edges. We have to // track these specially because, when we load the data back up @@ -34,32 +33,31 @@ pub struct Predecessors<'query> { // to recreate the nodes where all incoming edges are clean; but // since we ordinarily just serialize edges, we wind up just // forgetting that bootstrap outputs even exist in that case.) - pub bootstrap_outputs: Vec<&'query DepNode>, + pub bootstrap_outputs: Vec<&'query DepNode>, // For the inputs (hir/foreign-metadata), we include hashes. - pub hashes: FxHashMap<&'query DepNode, Fingerprint>, + pub hashes: FxHashMap<&'query DepNode, Fingerprint>, } impl<'q> Predecessors<'q> { - pub fn new(query: &'q DepGraphQuery, hcx: &mut HashContext) -> Self { + pub fn new(query: &'q DepGraphQuery, hcx: &mut HashContext) -> Self { let tcx = hcx.tcx; // Find the set of "start nodes". These are nodes that we will // possibly query later. - let is_output = |node: &DepNode| -> bool { - match *node { - DepNode::WorkProduct(_) => true, - DepNode::MetaData(ref def_id) => { + let is_output = |node: &DepNode| -> bool { + match node.kind { + DepKind::WorkProduct => true, + DepKind::MetaData => { // We do *not* create dep-nodes for the current crate's // metadata anymore, just for metadata that we import/read // from other crates. - debug_assert!(!def_id.is_local()); + debug_assert!(!node.extract_def_id(tcx).unwrap().is_local()); false } // if -Z query-dep-graph is passed, save more extended data // to enable better unit testing - DepNode::TypeckTables(_) | - DepNode::TransCrateItem(_) => tcx.sess.opts.debugging_opts.query_dep_graph, + DepKind::TypeckTables => tcx.sess.opts.debugging_opts.query_dep_graph, _ => false, } @@ -67,7 +65,9 @@ impl<'q> Predecessors<'q> { // Reduce the graph to the most important nodes. let compress::Reduction { graph, input_nodes } = - compress::reduce_graph(&query.graph, HashContext::is_hashable, |n| is_output(n)); + compress::reduce_graph(&query.graph, + |n| HashContext::is_hashable(tcx, n), + |n| is_output(n)); let mut hashes = FxHashMap(); for input_index in input_nodes { @@ -81,8 +81,8 @@ impl<'q> Predecessors<'q> { // Not all inputs might have been reachable from an output node, // but we still want their hash for our unit tests. let hir_nodes = query.graph.all_nodes().iter().filter_map(|node| { - match node.data { - DepNode::Hir(_) => Some(&node.data), + match node.data.kind { + DepKind::Hir => Some(&node.data), _ => None, } }); @@ -93,7 +93,7 @@ impl<'q> Predecessors<'q> { } } - let bootstrap_outputs: Vec<&'q DepNode> = + let bootstrap_outputs: Vec<&'q DepNode> = (0 .. graph.len_nodes()) .map(NodeIndex) .filter(|&n| graph.incoming_edges(n).next().is_none()) diff --git a/src/librustc_incremental/persist/save.rs b/src/librustc_incremental/persist/save.rs index 6d717d6f409d..867452d97e8f 100644 --- a/src/librustc_incremental/persist/save.rs +++ b/src/librustc_incremental/persist/save.rs @@ -11,7 +11,6 @@ use rustc::dep_graph::DepNode; use rustc::hir::def_id::DefId; use rustc::hir::svh::Svh; -use rustc::hir::map::DefPathHash; use rustc::ich::Fingerprint; use rustc::middle::cstore::EncodedMetadataHashes; use rustc::session::Session; @@ -174,19 +173,15 @@ pub fn encode_dep_graph(tcx: TyCtxt, // First encode the commandline arguments hash tcx.sess.opts.dep_tracking_hash().encode(encoder)?; - let to_hash_based_node = |dep_node: &DepNode| { - dep_node.map_def(|&def_id| Some(tcx.def_path_hash(def_id))).unwrap() - }; - // NB: We rely on this Vec being indexable by reduced_graph's NodeIndex. - let nodes: IndexVec> = preds + let mut nodes: IndexVec = preds .reduced_graph .all_nodes() .iter() - .map(|node| to_hash_based_node(node.data)) + .map(|node| node.data.clone()) .collect(); - let mut edge_list_indices = Vec::with_capacity(nodes.len()); + let mut edge_list_indices = IndexVec::with_capacity(nodes.len()); let mut edge_list_data = Vec::with_capacity(preds.reduced_graph.len_edges()); for node_index in 0 .. nodes.len() { @@ -201,34 +196,62 @@ pub fn encode_dep_graph(tcx: TyCtxt, edge_list_indices.push((start, end)); } - // Let's make we had no overflow there. + // Let's make sure we had no overflow there. assert!(edge_list_data.len() <= ::std::u32::MAX as usize); // Check that we have a consistent number of edges. assert_eq!(edge_list_data.len(), preds.reduced_graph.len_edges()); - let bootstrap_outputs = preds - .bootstrap_outputs - .iter() - .map(|n| to_hash_based_node(n)) - .collect(); + let bootstrap_outputs = preds.bootstrap_outputs + .iter() + .map(|dep_node| (**dep_node).clone()) + .collect(); - let hashes = preds - .hashes - .iter() - .map(|(&dep_node, &hash)| { - SerializedHash { - dep_node: to_hash_based_node(dep_node), - hash: hash, - } - }) - .collect(); + // Next, build the map of content hashes. To this end, we need to transform + // the (DepNode -> Fingerprint) map that we have into a + // (DepNodeIndex -> Fingerprint) map. This may necessitate adding nodes back + // to the dep-graph that have been filtered out during reduction. + let content_hashes = { + // We have to build a (DepNode -> DepNodeIndex) map. We over-allocate a + // little because we expect some more nodes to be added. + let capacity = (nodes.len() * 120) / 100; + let mut node_to_index = FxHashMap::with_capacity_and_hasher(capacity, + Default::default()); + // Add the nodes we already have in the graph. + node_to_index.extend(nodes.iter_enumerated() + .map(|(index, &node)| (node, index))); + + let mut content_hashes = Vec::with_capacity(preds.hashes.len()); + + for (&&dep_node, &hash) in preds.hashes.iter() { + let dep_node_index = *node_to_index + .entry(dep_node) + .or_insert_with(|| { + // There is no DepNodeIndex for this DepNode yet. This + // happens when the DepNode got filtered out during graph + // reduction. Since we have a content hash for the DepNode, + // we add it back to the graph. + let next_index = nodes.len(); + nodes.push(dep_node); + + debug_assert_eq!(next_index, edge_list_indices.len()); + // Push an empty list of edges + edge_list_indices.push((0,0)); + + DepNodeIndex::new(next_index) + }); + + content_hashes.push((dep_node_index, hash)); + } + + content_hashes + }; let graph = SerializedDepGraph { nodes, edge_list_indices, edge_list_data, bootstrap_outputs, - hashes, + hashes: content_hashes, }; // Encode the graph data. @@ -255,9 +278,11 @@ pub fn encode_metadata_hashes(tcx: TyCtxt, current_metadata_hashes: &mut FxHashMap, encoder: &mut Encoder) -> io::Result<()> { + assert_eq!(metadata_hashes.hashes.len(), + metadata_hashes.hashes.iter().map(|x| (x.def_index, ())).collect::>().len()); + let mut serialized_hashes = SerializedMetadataHashes { - entry_hashes: metadata_hashes.entry_hashes.to_vec(), - global_hashes: metadata_hashes.global_hashes.to_vec(), + entry_hashes: metadata_hashes.hashes.to_vec(), index_map: FxHashMap() }; diff --git a/src/librustc_incremental/persist/work_product.rs b/src/librustc_incremental/persist/work_product.rs index 0e9f90615401..16ab10ab4bbb 100644 --- a/src/librustc_incremental/persist/work_product.rs +++ b/src/librustc_incremental/persist/work_product.rs @@ -16,7 +16,6 @@ use rustc::session::Session; use rustc::session::config::OutputType; use rustc::util::fs::link_or_copy; use std::path::PathBuf; -use std::sync::Arc; use std::fs as std_fs; pub fn save_trans_partition(sess: &Session, @@ -30,7 +29,7 @@ pub fn save_trans_partition(sess: &Session, if sess.opts.incremental.is_none() { return; } - let work_product_id = Arc::new(WorkProductId(cgu_name.to_string())); + let work_product_id = WorkProductId::from_cgu_name(cgu_name); let saved_files: Option> = files.iter() diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 3a4729e64548..9800012917c5 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -32,7 +32,7 @@ use rustc::hir::def::Def; use rustc::hir::def_id::DefId; use rustc::cfg; use rustc::ty::subst::Substs; -use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::{self, Ty}; use rustc::traits::{self, Reveal}; use rustc::hir::map as hir_map; use util::nodemap::NodeSet; @@ -893,7 +893,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion { for adjustment in cx.tables.expr_adjustments(expr) { if let Adjust::Deref(Some(deref)) = adjustment.kind { let (def_id, substs) = deref.method_call(cx.tcx, source); - if method_call_refers_to_method(cx.tcx, method, def_id, substs, id) { + if method_call_refers_to_method(cx, method, def_id, substs, id) { return true; } } @@ -904,7 +904,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion { if cx.tables.is_method_call(expr) { let def_id = cx.tables.type_dependent_defs[&id].def_id(); let substs = cx.tables.node_substs(id); - if method_call_refers_to_method(cx.tcx, method, def_id, substs, id) { + if method_call_refers_to_method(cx, method, def_id, substs, id) { return true; } } @@ -920,8 +920,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion { match def { Def::Method(def_id) => { let substs = cx.tables.node_substs(callee.id); - method_call_refers_to_method( - cx.tcx, method, def_id, substs, id) + method_call_refers_to_method(cx, method, def_id, substs, id) } _ => false, } @@ -932,12 +931,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion { // Check if the method call to the method with the ID `callee_id` // and instantiated with `callee_substs` refers to method `method`. - fn method_call_refers_to_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + fn method_call_refers_to_method<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, method: &ty::AssociatedItem, callee_id: DefId, callee_substs: &Substs<'tcx>, expr_id: ast::NodeId) -> bool { + let tcx = cx.tcx; let callee_item = tcx.associated_item(callee_id); match callee_item.container { @@ -951,13 +951,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion { let trait_ref = ty::TraitRef::from_method(tcx, trait_def_id, callee_substs); let trait_ref = ty::Binder(trait_ref); let span = tcx.hir.span(expr_id); - let param_env = tcx.param_env(method.def_id); let obligation = traits::Obligation::new(traits::ObligationCause::misc(span, expr_id), - param_env, + cx.param_env, trait_ref.to_poly_trait_predicate()); - tcx.infer_ctxt(()).enter(|infcx| { + tcx.infer_ctxt().enter(|infcx| { let mut selcx = traits::SelectionContext::new(&infcx); match selcx.select(&obligation) { // The method comes from a `T: Trait` bound. @@ -1224,11 +1223,9 @@ impl LintPass for UnionsWithDropFields { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnionsWithDropFields { fn check_item(&mut self, ctx: &LateContext, item: &hir::Item) { if let hir::ItemUnion(ref vdata, _) = item.node { - let item_def_id = ctx.tcx.hir.local_def_id(item.id); - let param_env = ctx.tcx.param_env(item_def_id); for field in vdata.fields() { let field_ty = ctx.tcx.type_of(ctx.tcx.hir.local_def_id(field.id)); - if field_ty.needs_drop(ctx.tcx, param_env) { + if field_ty.needs_drop(ctx.tcx, ctx.param_env) { ctx.span_lint(UNIONS_WITH_DROP_FIELDS, field.span, "union contains a field with possibly non-trivial drop code, \ diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 3019165bfbf9..32bde42b5261 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -725,7 +725,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences { // sizes only make sense for non-generic types let item_def_id = cx.tcx.hir.local_def_id(it.id); let t = cx.tcx.type_of(item_def_id); - let param_env = cx.tcx.param_env(item_def_id).reveal_all(); + let param_env = cx.param_env.reveal_all(); let ty = cx.tcx.erase_regions(&t); let layout = ty.layout(cx.tcx, param_env).unwrap_or_else(|e| { bug!("failed to get layout for `{}`: {}", t, e) diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs index d7b575d90a68..312b5a38d6e3 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -591,7 +591,9 @@ extern "C" { pub fn LLVMIsUndef(Val: ValueRef) -> Bool; // Operations on metadata + pub fn LLVMMDStringInContext(C: ContextRef, Str: *const c_char, SLen: c_uint) -> ValueRef; pub fn LLVMMDNodeInContext(C: ContextRef, Vals: *const ValueRef, Count: c_uint) -> ValueRef; + pub fn LLVMAddNamedMetadataOperand(M: ModuleRef, Name: *const c_char, Val: ValueRef); // Operations on scalar constants pub fn LLVMConstInt(IntTy: TypeRef, N: c_ulonglong, SignExtend: Bool) -> ValueRef; @@ -1332,6 +1334,8 @@ extern "C" { pub fn LLVMRustAddModuleFlag(M: ModuleRef, name: *const c_char, value: u32); + pub fn LLVMRustMetadataAsValue(C: ContextRef, MD: MetadataRef) -> ValueRef; + pub fn LLVMRustDIBuilderCreate(M: ModuleRef) -> DIBuilderRef; pub fn LLVMRustDIBuilderDispose(Builder: DIBuilderRef); diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 51f152991fda..27c2d22168c8 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -14,8 +14,7 @@ use cstore::{self, CStore, CrateSource, MetadataBlob}; use locator::{self, CratePaths}; use schema::{CrateRoot, Tracked}; -use rustc::dep_graph::{DepNode, GlobalMetaDataKind}; -use rustc::hir::def_id::{DefId, CrateNum, DefIndex, CRATE_DEF_INDEX}; +use rustc::hir::def_id::{CrateNum, DefIndex}; use rustc::hir::svh::Svh; use rustc::middle::cstore::DepKind; use rustc::session::Session; @@ -516,14 +515,11 @@ impl<'a> CrateLoader<'a> { return cstore::CrateNumMap::new(); } - let dep_node = DepNode::GlobalMetaData(DefId { krate, index: CRATE_DEF_INDEX }, - GlobalMetaDataKind::CrateDeps); - // The map from crate numbers in the crate we're resolving to local crate numbers. // We map 0 and all other holes in the map to our parent crate. The "additional" // self-dependencies should be harmless. ::std::iter::once(krate).chain(crate_root.crate_deps - .get(&self.sess.dep_graph, dep_node) + .get_untracked() .decode(metadata) .map(|dep| { debug!("resolving dep crate {} hash: `{}`", dep.name, dep.hash); @@ -906,6 +902,24 @@ impl<'a> CrateLoader<'a> { } } + fn inject_profiler_runtime(&mut self) { + if self.sess.opts.debugging_opts.profile { + info!("loading profiler"); + + let symbol = Symbol::intern("profiler_builtins"); + let dep_kind = DepKind::Implicit; + let (_, data) = + self.resolve_crate(&None, symbol, symbol, None, DUMMY_SP, + PathKind::Crate, dep_kind); + + // Sanity check the loaded crate to ensure it is indeed a profiler runtime + if !data.is_profiler_runtime(&self.sess.dep_graph) { + self.sess.err(&format!("the crate `profiler_builtins` is not \ + a profiler runtime")); + } + } + } + fn inject_allocator_crate(&mut self) { // Make sure that we actually need an allocator, if none of our // dependencies need one then we definitely don't! @@ -1108,6 +1122,7 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> { // inject the sanitizer runtime before the allocator runtime because all // sanitizers force the use of the `alloc_system` allocator self.inject_sanitizer_runtime(); + self.inject_profiler_runtime(); self.inject_allocator_crate(); self.inject_panic_runtime(krate); diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index 5066b927c115..86146fe3947b 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -13,9 +13,9 @@ use schema::{self, Tracked}; -use rustc::dep_graph::{DepGraph, DepNode, GlobalMetaDataKind}; +use rustc::dep_graph::DepGraph; use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, CrateNum, DefIndex, DefId}; -use rustc::hir::map::definitions::DefPathTable; +use rustc::hir::map::definitions::{DefPathTable, GlobalMetaDataKind}; use rustc::hir::svh::Svh; use rustc::middle::cstore::{DepKind, ExternCrate, MetadataLoader}; use rustc_back::PanicStrategy; @@ -34,7 +34,7 @@ pub use rustc::middle::cstore::{NativeLibrary, NativeLibraryKind, LinkagePrefere pub use rustc::middle::cstore::NativeLibraryKind::*; pub use rustc::middle::cstore::{CrateSource, LinkMeta, LibSource}; -pub use cstore_impl::provide; +pub use cstore_impl::{provide, provide_local}; // A map from external crate numbers (as decoded from some crate file) to // local crate numbers (as generated during this session). Each external @@ -255,6 +255,13 @@ impl CStore { pub fn do_extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option { self.extern_mod_crate_map.borrow().get(&emod_id).cloned() } + + pub fn read_dep_node(&self, def_id: DefId) { + use rustc::middle::cstore::CrateStore; + let def_path_hash = self.def_path_hash(def_id); + let dep_node = def_path_hash.to_dep_node(::rustc::dep_graph::DepKind::MetaData); + self.dep_graph.read(dep_node); + } } impl CrateMetadata { @@ -298,18 +305,18 @@ impl CrateMetadata { attr::contains_name(&attrs, "sanitizer_runtime") } + pub fn is_profiler_runtime(&self, dep_graph: &DepGraph) -> bool { + let attrs = self.get_item_attrs(CRATE_DEF_INDEX, dep_graph); + attr::contains_name(&attrs, "profiler_runtime") + } + pub fn is_no_builtins(&self, dep_graph: &DepGraph) -> bool { let attrs = self.get_item_attrs(CRATE_DEF_INDEX, dep_graph); attr::contains_name(&attrs, "no_builtins") } pub fn panic_strategy(&self, dep_graph: &DepGraph) -> PanicStrategy { - let def_id = DefId { - krate: self.cnum, - index: CRATE_DEF_INDEX, - }; - let dep_node = DepNode::GlobalMetaData(def_id, GlobalMetaDataKind::Krate); - + let dep_node = self.metadata_dep_node(GlobalMetaDataKind::Krate); self.root .panic_strategy .get(dep_graph, dep_node) diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index dcc55846b53d..c49712086d52 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -14,7 +14,7 @@ use schema; use rustc::dep_graph::DepTrackingMapConfig; use rustc::middle::cstore::{CrateStore, CrateSource, LibSource, DepKind, - ExternCrate, NativeLibrary, MetadataLoader, LinkMeta, + NativeLibrary, MetadataLoader, LinkMeta, LinkagePreference, LoadedMacro, EncodedMetadata}; use rustc::hir::def; use rustc::middle::lang_items; @@ -22,10 +22,9 @@ use rustc::session::Session; use rustc::ty::{self, TyCtxt}; use rustc::ty::maps::Providers; use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE}; - -use rustc::dep_graph::{DepNode, GlobalMetaDataKind}; use rustc::hir::map::{DefKey, DefPath, DisambiguatedDefPathData, DefPathHash}; -use rustc::hir::map::definitions::DefPathTable; +use rustc::hir::map::blocks::FnLikeNode; +use rustc::hir::map::definitions::{DefPathTable, GlobalMetaDataKind}; use rustc::util::nodemap::{NodeSet, DefIdMap}; use rustc_back::PanicStrategy; @@ -41,14 +40,17 @@ use rustc::hir::svh::Svh; use rustc::hir; macro_rules! provide { - (<$lt:tt> $tcx:ident, $def_id:ident, $cdata:ident $($name:ident => $compute:block)*) => { + (<$lt:tt> $tcx:ident, $def_id:ident, $cdata:ident, $($name:ident => $compute:block)*) => { pub fn provide<$lt>(providers: &mut Providers<$lt>) { $(fn $name<'a, $lt:$lt>($tcx: TyCtxt<'a, $lt, $lt>, $def_id: DefId) -> as DepTrackingMapConfig>::Value { assert!(!$def_id.is_local()); - $tcx.dep_graph.read(DepNode::MetaData($def_id)); + let def_path_hash = $tcx.def_path_hash($def_id); + let dep_node = def_path_hash.to_dep_node(::rustc::dep_graph::DepKind::MetaData); + + $tcx.dep_graph.read(dep_node); let $cdata = $tcx.sess.cstore.crate_data_as_rc_any($def_id.krate); let $cdata = $cdata.downcast_ref::() @@ -64,7 +66,7 @@ macro_rules! provide { } } -provide! { <'tcx> tcx, def_id, cdata +provide! { <'tcx> tcx, def_id, cdata, type_of => { cdata.get_type(def_id.index, tcx) } generics_of => { tcx.alloc_generics(cdata.get_generics(def_id.index)) } predicates_of => { cdata.get_predicates(def_id.index, tcx) } @@ -80,7 +82,8 @@ provide! { <'tcx> tcx, def_id, cdata variances_of => { Rc::new(cdata.get_item_variances(def_id.index)) } associated_item_def_ids => { let mut result = vec![]; - cdata.each_child_of_item(def_id.index, |child| result.push(child.def.def_id())); + cdata.each_child_of_item(def_id.index, + |child| result.push(child.def.def_id()), tcx.sess); Rc::new(result) } associated_item => { cdata.get_associated_item(def_id.index) } @@ -105,6 +108,7 @@ provide! { <'tcx> tcx, def_id, cdata closure_kind => { cdata.closure_kind(def_id.index) } closure_type => { cdata.closure_ty(def_id.index, tcx) } inherent_impls => { Rc::new(cdata.get_inherent_implementations_for_type(def_id.index)) } + is_const_fn => { cdata.is_const_fn(def_id.index) } is_foreign_item => { cdata.is_foreign_item(def_id.index) } is_default_impl => { cdata.is_default_impl(def_id.index) } describe_def => { cdata.get_def(def_id.index) } @@ -128,6 +132,29 @@ provide! { <'tcx> tcx, def_id, cdata cdata.const_is_rvalue_promotable_to_static(def_id.index) } is_mir_available => { cdata.is_item_mir_available(def_id.index) } + + dylib_dependency_formats => { Rc::new(cdata.get_dylib_dependency_formats(&tcx.dep_graph)) } + is_allocator => { cdata.is_allocator(&tcx.dep_graph) } + is_panic_runtime => { cdata.is_panic_runtime(&tcx.dep_graph) } + extern_crate => { Rc::new(cdata.extern_crate.get()) } +} + +pub fn provide_local<'tcx>(providers: &mut Providers<'tcx>) { + fn is_const_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool { + let node_id = tcx.hir.as_local_node_id(def_id) + .expect("Non-local call to local provider is_const_fn"); + + if let Some(fn_like) = FnLikeNode::from_node(tcx.hir.get(node_id)) { + fn_like.constness() == hir::Constness::Const + } else { + false + } + } + + *providers = Providers { + is_const_fn, + ..*providers + }; } impl CrateStore for cstore::CStore { @@ -140,12 +167,12 @@ impl CrateStore for cstore::CStore { } fn visibility(&self, def: DefId) -> ty::Visibility { - self.dep_graph.read(DepNode::MetaData(def)); + self.read_dep_node(def); self.get_crate_data(def.krate).get_visibility(def.index) } fn item_generics_cloned(&self, def: DefId) -> ty::Generics { - self.dep_graph.read(DepNode::MetaData(def)); + self.read_dep_node(def); self.get_crate_data(def.krate).get_generics(def.index) } @@ -161,22 +188,16 @@ impl CrateStore for cstore::CStore { fn impl_defaultness(&self, def: DefId) -> hir::Defaultness { - self.dep_graph.read(DepNode::MetaData(def)); + self.read_dep_node(def); self.get_crate_data(def.krate).get_impl_defaultness(def.index) } fn associated_item_cloned(&self, def: DefId) -> ty::AssociatedItem { - self.dep_graph.read(DepNode::MetaData(def)); + self.read_dep_node(def); self.get_crate_data(def.krate).get_associated_item(def.index) } - fn is_const_fn(&self, did: DefId) -> bool - { - self.dep_graph.read(DepNode::MetaData(did)); - self.get_crate_data(did.krate).is_const_fn(did.index) - } - fn is_statically_included_foreign_item(&self, def_id: DefId) -> bool { self.do_is_statically_included_foreign_item(def_id) @@ -191,12 +212,6 @@ impl CrateStore for cstore::CStore { } } - fn dylib_dependency_formats(&self, cnum: CrateNum) - -> Vec<(CrateNum, LinkagePreference)> - { - self.get_crate_data(cnum).get_dylib_dependency_formats(&self.dep_graph) - } - fn dep_kind(&self, cnum: CrateNum) -> DepKind { let data = self.get_crate_data(cnum); @@ -226,16 +241,6 @@ impl CrateStore for cstore::CStore { self.get_crate_data(cnum).get_missing_lang_items(&self.dep_graph) } - fn is_allocator(&self, cnum: CrateNum) -> bool - { - self.get_crate_data(cnum).is_allocator(&self.dep_graph) - } - - fn is_panic_runtime(&self, cnum: CrateNum) -> bool - { - self.get_crate_data(cnum).is_panic_runtime(&self.dep_graph) - } - fn is_compiler_builtins(&self, cnum: CrateNum) -> bool { self.get_crate_data(cnum).is_compiler_builtins(&self.dep_graph) } @@ -244,6 +249,10 @@ impl CrateStore for cstore::CStore { self.get_crate_data(cnum).is_sanitizer_runtime(&self.dep_graph) } + fn is_profiler_runtime(&self, cnum: CrateNum) -> bool { + self.get_crate_data(cnum).is_profiler_runtime(&self.dep_graph) + } + fn panic_strategy(&self, cnum: CrateNum) -> PanicStrategy { self.get_crate_data(cnum).panic_strategy(&self.dep_graph) } @@ -258,11 +267,6 @@ impl CrateStore for cstore::CStore { self.get_crate_data(cnum).name() } - fn extern_crate(&self, cnum: CrateNum) -> Option - { - self.get_crate_data(cnum).extern_crate.get() - } - fn crate_hash(&self, cnum: CrateNum) -> Svh { self.get_crate_hash(cnum) @@ -344,16 +348,16 @@ impl CrateStore for cstore::CStore { fn struct_field_names(&self, def: DefId) -> Vec { - self.dep_graph.read(DepNode::MetaData(def)); + self.read_dep_node(def); self.get_crate_data(def.krate).get_struct_field_names(def.index) } - fn item_children(&self, def_id: DefId) -> Vec + fn item_children(&self, def_id: DefId, sess: &Session) -> Vec { - self.dep_graph.read(DepNode::MetaData(def_id)); + self.read_dep_node(def_id); let mut result = vec![]; self.get_crate_data(def_id.krate) - .each_child_of_item(def_id.index, |child| result.push(child)); + .each_child_of_item(def_id.index, |child| result.push(child), sess); result } @@ -398,11 +402,12 @@ impl CrateStore for cstore::CStore { tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx hir::Body { - if let Some(cached) = tcx.hir.get_inlined_body(def_id) { + self.read_dep_node(def_id); + + if let Some(cached) = tcx.hir.get_inlined_body_untracked(def_id) { return cached; } - self.dep_graph.read(DepNode::MetaData(def_id)); debug!("item_body({:?}): inlining item", def_id); self.get_crate_data(def_id.krate).item_body(tcx, def_id.index) @@ -456,7 +461,7 @@ impl CrateStore for cstore::CStore { /// Returns a map from a sufficiently visible external item (i.e. an external item that is /// visible from at least one local module) to a sufficiently visible parent (considering /// modules that re-export the external item to be parents). - fn visible_parent_map<'a>(&'a self) -> ::std::cell::Ref<'a, DefIdMap> { + fn visible_parent_map<'a>(&'a self, sess: &Session) -> ::std::cell::Ref<'a, DefIdMap> { { let visible_parent_map = self.visible_parent_map.borrow(); if !visible_parent_map.is_empty() { @@ -506,7 +511,7 @@ impl CrateStore for cstore::CStore { index: CRATE_DEF_INDEX }); while let Some(def) = bfs_queue.pop_front() { - for child in self.item_children(def) { + for child in self.item_children(def, sess) { add_child(bfs_queue, child, def); } } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 91470f238ecb..728ab30bb17d 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -13,8 +13,9 @@ use cstore::{self, CrateMetadata, MetadataBlob, NativeLibrary}; use schema::*; -use rustc::dep_graph::{DepGraph, DepNode, GlobalMetaDataKind}; +use rustc::dep_graph::{DepGraph, DepNode, DepKind}; use rustc::hir::map::{DefKey, DefPath, DefPathData, DefPathHash}; +use rustc::hir::map::definitions::GlobalMetaDataKind; use rustc::hir; use rustc::middle::cstore::LinkagePreference; @@ -653,7 +654,7 @@ impl<'a, 'tcx> CrateMetadata { } /// Iterates over each child of the given item. - pub fn each_child_of_item(&self, id: DefIndex, mut callback: F) + pub fn each_child_of_item(&self, id: DefIndex, mut callback: F, sess: &Session) where F: FnMut(def::Export) { if let Some(ref proc_macros) = self.proc_macros { @@ -676,19 +677,19 @@ impl<'a, 'tcx> CrateMetadata { // Find the item. let item = match self.maybe_entry(id) { None => return, - Some(item) => item.decode(self), + Some(item) => item.decode((self, sess)), }; // Iterate over all children. let macros_only = self.dep_kind.get().macros_only(); - for child_index in item.children.decode(self) { + for child_index in item.children.decode((self, sess)) { if macros_only { continue } // Get the item. if let Some(child) = self.maybe_entry(child_index) { - let child = child.decode(self); + let child = child.decode((self, sess)); match child.kind { EntryKind::MacroDef(..) => {} _ if macros_only => continue, @@ -699,12 +700,12 @@ impl<'a, 'tcx> CrateMetadata { match child.kind { // FIXME(eddyb) Don't encode these in children. EntryKind::ForeignMod => { - for child_index in child.children.decode(self) { + for child_index in child.children.decode((self, sess)) { if let Some(def) = self.get_def(child_index) { callback(def::Export { def: def, ident: Ident::with_empty_ctxt(self.item_name(child_index)), - span: self.entry(child_index).span.decode(self), + span: self.entry(child_index).span.decode((self, sess)), }); } } @@ -717,7 +718,7 @@ impl<'a, 'tcx> CrateMetadata { } let def_key = self.def_key(child_index); - let span = child.span.decode(self); + let span = child.span.decode((self, sess)); if let (Some(def), Some(name)) = (self.get_def(child_index), def_key.disambiguated_data.data.get_opt_name()) { let ident = Ident::with_empty_ctxt(name); @@ -746,7 +747,7 @@ impl<'a, 'tcx> CrateMetadata { } if let EntryKind::Mod(data) = item.kind { - for exp in data.decode(self).reexports.decode(self) { + for exp in data.decode((self, sess)).reexports.decode((self, sess)) { match exp.def { Def::Macro(..) => {} _ if macros_only => continue, @@ -764,7 +765,7 @@ impl<'a, 'tcx> CrateMetadata { assert!(!self.is_proc_macro(id)); let ast = self.entry(id).ast.unwrap(); let def_id = self.local_def_id(id); - let body = ast.decode(self).body.decode(self); + let body = ast.decode((self, tcx)).body.decode((self, tcx)); tcx.hir.intern_inlined_body(def_id, body) } @@ -875,7 +876,8 @@ impl<'a, 'tcx> CrateMetadata { return Rc::new([]); } - dep_graph.read(DepNode::MetaData(self.local_def_id(node_id))); + let dep_node = self.def_path_hash(node_id).to_dep_node(DepKind::MetaData); + dep_graph.read(dep_node); if let Some(&Some(ref val)) = self.attribute_cache.borrow()[node_as].get(node_index) { @@ -993,12 +995,8 @@ impl<'a, 'tcx> CrateMetadata { pub fn get_dylib_dependency_formats(&self, dep_graph: &DepGraph) -> Vec<(CrateNum, LinkagePreference)> { - let def_id = DefId { - krate: self.cnum, - index: CRATE_DEF_INDEX, - }; - let dep_node = DepNode::GlobalMetaData(def_id, - GlobalMetaDataKind::DylibDependencyFormats); + let dep_node = + self.metadata_dep_node(GlobalMetaDataKind::DylibDependencyFormats); self.root .dylib_dependency_formats .get(dep_graph, dep_node) @@ -1151,6 +1149,7 @@ impl<'a, 'tcx> CrateMetadata { // containing the information we need. let syntax_pos::FileMap { name, name_was_remapped, + src_hash, start_pos, end_pos, lines, @@ -1176,6 +1175,7 @@ impl<'a, 'tcx> CrateMetadata { let local_version = local_codemap.new_imported_filemap(name, name_was_remapped, self.cnum.as_u32(), + src_hash, source_length, lines, multibyte_chars); @@ -1197,12 +1197,9 @@ impl<'a, 'tcx> CrateMetadata { self.codemap_import_info.borrow() } - pub fn metadata_dep_node(&self, kind: GlobalMetaDataKind) -> DepNode { - let def_id = DefId { - krate: self.cnum, - index: CRATE_DEF_INDEX, - }; - - DepNode::GlobalMetaData(def_id, kind) + pub fn metadata_dep_node(&self, kind: GlobalMetaDataKind) -> DepNode { + let def_index = kind.def_index(&self.def_path_table); + let def_path_hash = self.def_path_table.def_path_hash(def_index); + def_path_hash.to_dep_node(DepKind::MetaData) } } diff --git a/src/librustc_metadata/diagnostics.rs b/src/librustc_metadata/diagnostics.rs index fbdc4695cf82..9a174e05eabd 100644 --- a/src/librustc_metadata/diagnostics.rs +++ b/src/librustc_metadata/diagnostics.rs @@ -44,7 +44,8 @@ To solve this error you can use conditional compilation: extern {} ``` -See more: https://doc.rust-lang.org/book/conditional-compilation.html +See more: +https://doc.rust-lang.org/book/first-edition/conditional-compilation.html "##, E0458: r##" diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index a02a82dfe69a..2a504c4c0779 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -14,10 +14,10 @@ use isolated_encoder::IsolatedEncoder; use schema::*; use rustc::middle::cstore::{LinkMeta, LinkagePreference, NativeLibrary, - EncodedMetadata, EncodedMetadataHashes}; + EncodedMetadata, EncodedMetadataHashes, + EncodedMetadataHash}; use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefIndex, DefId, LOCAL_CRATE}; -use rustc::hir::map::definitions::DefPathTable; -use rustc::dep_graph::{DepNode, GlobalMetaDataKind}; +use rustc::hir::map::definitions::{DefPathTable, GlobalMetaDataKind}; use rustc::ich::Fingerprint; use rustc::middle::dependency_format::Linkage; use rustc::middle::lang_items; @@ -244,7 +244,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { // Encodes something that corresponds to a single DepNode::GlobalMetaData // and registers the Fingerprint in the `metadata_hashes` map. pub fn tracked<'x, DATA, R>(&'x mut self, - dep_node: DepNode<()>, + def_index: DefIndex, op: fn(&mut IsolatedEncoder<'x, 'a, 'tcx>, DATA) -> R, data: DATA) -> Tracked { @@ -253,7 +253,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let (fingerprint, this) = entry_builder.finish(); if let Some(fingerprint) = fingerprint { - this.metadata_hashes.global_hashes.push((dep_node, fingerprint)); + this.metadata_hashes.hashes.push(EncodedMetadataHash { + def_index, + hash: fingerprint, + }) } Tracked::new(ret) @@ -322,12 +325,17 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_crate_root(&mut self) -> Lazy { let mut i = self.position(); + let tcx = self.tcx; + let global_metadata_def_index = move |kind: GlobalMetaDataKind| { + kind.def_index(tcx.hir.definitions().def_path_table()) + }; + let crate_deps = self.tracked( - DepNode::GlobalMetaData((), GlobalMetaDataKind::CrateDeps), + global_metadata_def_index(GlobalMetaDataKind::CrateDeps), IsolatedEncoder::encode_crate_deps, ()); let dylib_dependency_formats = self.tracked( - DepNode::GlobalMetaData((), GlobalMetaDataKind::DylibDependencyFormats), + global_metadata_def_index(GlobalMetaDataKind::DylibDependencyFormats), IsolatedEncoder::encode_dylib_dependency_formats, ()); let dep_bytes = self.position() - i; @@ -335,12 +343,12 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { // Encode the language items. i = self.position(); let lang_items = self.tracked( - DepNode::GlobalMetaData((), GlobalMetaDataKind::LangItems), + global_metadata_def_index(GlobalMetaDataKind::LangItems), IsolatedEncoder::encode_lang_items, ()); let lang_items_missing = self.tracked( - DepNode::GlobalMetaData((), GlobalMetaDataKind::LangItemsMissing), + global_metadata_def_index(GlobalMetaDataKind::LangItemsMissing), IsolatedEncoder::encode_lang_items_missing, ()); let lang_item_bytes = self.position() - i; @@ -348,7 +356,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { // Encode the native libraries used i = self.position(); let native_libraries = self.tracked( - DepNode::GlobalMetaData((), GlobalMetaDataKind::NativeLibraries), + global_metadata_def_index(GlobalMetaDataKind::NativeLibraries), IsolatedEncoder::encode_native_libraries, ()); let native_lib_bytes = self.position() - i; @@ -366,7 +374,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { // Encode the def IDs of impls, for coherence checking. i = self.position(); let impls = self.tracked( - DepNode::GlobalMetaData((), GlobalMetaDataKind::Impls), + global_metadata_def_index(GlobalMetaDataKind::Impls), IsolatedEncoder::encode_impls, ()); let impl_bytes = self.position() - i; @@ -374,7 +382,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { // Encode exported symbols info. i = self.position(); let exported_symbols = self.tracked( - DepNode::GlobalMetaData((), GlobalMetaDataKind::ExportedSymbols), + global_metadata_def_index(GlobalMetaDataKind::ExportedSymbols), IsolatedEncoder::encode_exported_symbols, self.exported_symbols); let exported_symbols_bytes = self.position() - i; @@ -422,10 +430,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let total_bytes = self.position(); - self.metadata_hashes.global_hashes.push(( - DepNode::GlobalMetaData((), GlobalMetaDataKind::Krate), - Fingerprint::from_smaller_hash(link_meta.crate_hash.as_u64()) - )); + self.metadata_hashes.hashes.push(EncodedMetadataHash { + def_index: global_metadata_def_index(GlobalMetaDataKind::Krate), + hash: Fingerprint::from_smaller_hash(link_meta.crate_hash.as_u64()) + }); if self.tcx.sess.meta_stats() { let mut zero_bytes = 0; diff --git a/src/librustc_metadata/index_builder.rs b/src/librustc_metadata/index_builder.rs index 478202aeba44..2db9c6a4ff81 100644 --- a/src/librustc_metadata/index_builder.rs +++ b/src/librustc_metadata/index_builder.rs @@ -135,7 +135,7 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { let (fingerprint, ecx) = entry_builder.finish(); if let Some(hash) = fingerprint { - ecx.metadata_hashes.entry_hashes.push(EncodedMetadataHash { + ecx.metadata_hashes.hashes.push(EncodedMetadataHash { def_index: id.index, hash: hash, }); diff --git a/src/librustc_metadata/isolated_encoder.rs b/src/librustc_metadata/isolated_encoder.rs index ed1680fbfaee..c4116489357a 100644 --- a/src/librustc_metadata/isolated_encoder.rs +++ b/src/librustc_metadata/isolated_encoder.rs @@ -23,7 +23,7 @@ use rustc_serialize::Encodable; pub struct IsolatedEncoder<'a, 'b: 'a, 'tcx: 'b> { pub tcx: TyCtxt<'b, 'tcx, 'tcx>, ecx: &'a mut EncodeContext<'b, 'tcx>, - hcx: Option<(StableHashingContext<'b, 'tcx>, StableHasher)>, + hcx: Option<(StableHashingContext<'b, 'tcx, 'tcx>, StableHasher)>, } impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { @@ -61,7 +61,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { } pub fn lazy(&mut self, value: &T) -> Lazy - where T: Encodable + HashStable> + where T: Encodable + HashStable> { if let Some((ref mut hcx, ref mut hasher)) = self.hcx { value.hash_stable(hcx, hasher); @@ -72,7 +72,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { pub fn lazy_seq(&mut self, iter: I) -> LazySeq where I: IntoIterator, - T: Encodable + HashStable> + T: Encodable + HashStable> { if let Some((ref mut hcx, ref mut hasher)) = self.hcx { let iter = iter.into_iter(); @@ -111,7 +111,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { pub fn lazy_seq_ref<'x, I, T>(&mut self, iter: I) -> LazySeq where I: IntoIterator, - T: 'x + Encodable + HashStable> + T: 'x + Encodable + HashStable> { if let Some((ref mut hcx, ref mut hasher)) = self.hcx { let iter = iter.into_iter(); @@ -149,7 +149,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { } pub fn lazy_seq_from_slice(&mut self, slice: &[T]) -> LazySeq - where T: Encodable + HashStable> + where T: Encodable + HashStable> { if let Some((ref mut hcx, ref mut hasher)) = self.hcx { slice.hash_stable(hcx, hasher); @@ -159,7 +159,7 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { } pub fn lazy_seq_ref_from_slice(&mut self, slice: &[&T]) -> LazySeq - where T: Encodable + HashStable> + where T: Encodable + HashStable> { if let Some((ref mut hcx, ref mut hasher)) = self.hcx { slice.hash_stable(hcx, hasher); diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index 2ffe7cc02aaa..1337f90efa74 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -203,7 +203,7 @@ impl Tracked { } } - pub fn get(&self, dep_graph: &DepGraph, dep_node: DepNode) -> &T { + pub fn get(&self, dep_graph: &DepGraph, dep_node: DepNode) -> &T { dep_graph.read(dep_node); &self.state } @@ -221,11 +221,11 @@ impl Tracked { } } -impl<'a, 'tcx, T> HashStable> for Tracked - where T: HashStable> +impl<'a, 'gcx, 'tcx, T> HashStable> for Tracked + where T: HashStable> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { let Tracked { ref state @@ -277,9 +277,9 @@ pub struct TraitImpls { pub impls: LazySeq, } -impl<'a, 'tcx> HashStable> for TraitImpls { +impl<'a, 'gcx, 'tcx> HashStable> for TraitImpls { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { let TraitImpls { trait_id: (krate, def_index), @@ -359,9 +359,9 @@ pub enum EntryKind<'tcx> { AssociatedConst(AssociatedContainer, u8), } -impl<'a, 'tcx> HashStable> for EntryKind<'tcx> { +impl<'a, 'gcx, 'tcx> HashStable> for EntryKind<'tcx> { fn hash_stable(&self, - hcx: &mut StableHashingContext<'a, 'tcx>, + hcx: &mut StableHashingContext<'a, 'gcx, 'tcx>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { diff --git a/src/librustc_mir/build/block.rs b/src/librustc_mir/build/block.rs index d81de954dbf1..865174aa272e 100644 --- a/src/librustc_mir/build/block.rs +++ b/src/librustc_mir/build/block.rs @@ -21,21 +21,24 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ast_block: &'tcx hir::Block, source_info: SourceInfo) -> BlockAnd<()> { - let Block { extent, span, stmts, expr, targeted_by_break } = self.hir.mirror(ast_block); - self.in_scope(extent, block, move |this| { - if targeted_by_break { - // This is a `break`-able block (currently only `catch { ... }`) - let exit_block = this.cfg.start_new_block(); - let block_exit = this.in_breakable_scope(None, exit_block, - destination.clone(), |this| { + let Block { extent, opt_destruction_extent, span, stmts, expr, targeted_by_break } = + self.hir.mirror(ast_block); + self.in_opt_scope(opt_destruction_extent.map(|de|(de, source_info)), block, move |this| { + this.in_scope((extent, source_info), block, move |this| { + if targeted_by_break { + // This is a `break`-able block (currently only `catch { ... }`) + let exit_block = this.cfg.start_new_block(); + let block_exit = this.in_breakable_scope( + None, exit_block, destination.clone(), |this| { + this.ast_block_stmts(destination, block, span, stmts, expr) + }); + this.cfg.terminate(unpack!(block_exit), source_info, + TerminatorKind::Goto { target: exit_block }); + exit_block.unit() + } else { this.ast_block_stmts(destination, block, span, stmts, expr) - }); - this.cfg.terminate(unpack!(block_exit), source_info, - TerminatorKind::Goto { target: exit_block }); - exit_block.unit() - } else { - this.ast_block_stmts(destination, block, span, stmts, expr) - } + } + }) }) } @@ -66,14 +69,18 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // First we build all the statements in the block. let mut let_extent_stack = Vec::with_capacity(8); let outer_visibility_scope = this.visibility_scope; + let source_info = this.source_info(span); for stmt in stmts { - let Stmt { span: _, kind } = this.hir.mirror(stmt); + let Stmt { span, kind, opt_destruction_extent } = this.hir.mirror(stmt); match kind { StmtKind::Expr { scope, expr } => { - unpack!(block = this.in_scope(scope, block, |this| { - let expr = this.hir.mirror(expr); - this.stmt_expr(block, expr) - })); + unpack!(block = this.in_opt_scope( + opt_destruction_extent.map(|de|(de, source_info)), block, |this| { + this.in_scope((scope, source_info), block, |this| { + let expr = this.hir.mirror(expr); + this.stmt_expr(block, expr) + }) + })); } StmtKind::Let { remainder_scope, init_scope, pattern, initializer } => { let tcx = this.hir.tcx(); @@ -89,10 +96,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // Evaluate the initializer, if present. if let Some(init) = initializer { - unpack!(block = this.in_scope(init_scope, block, move |this| { - // FIXME #30046 ^~~~ - this.expr_into_pattern(block, pattern, init) - })); + unpack!(block = this.in_opt_scope( + opt_destruction_extent.map(|de|(de, source_info)), block, move |this| { + this.in_scope((init_scope, source_info), block, move |this| { + // FIXME #30046 ^~~~ + this.expr_into_pattern(block, pattern, init) + }) + })); } else { this.visit_bindings(&pattern, &mut |this, _, _, node, span, _| { this.storage_live_binding(block, node, span); @@ -112,13 +122,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { if let Some(expr) = expr { unpack!(block = this.into(destination, block, expr)); } else { - let source_info = this.source_info(span); this.cfg.push_assign_unit(block, source_info, destination); } // Finally, we pop all the let scopes before exiting out from the scope of block // itself. for extent in let_extent_stack.into_iter().rev() { - unpack!(block = this.pop_scope(extent, block)); + unpack!(block = this.pop_scope((extent, source_info), block)); } // Restore the original visibility scope. this.visibility_scope = outer_visibility_scope; diff --git a/src/librustc_mir/build/cfg.rs b/src/librustc_mir/build/cfg.rs index 40a78933aad2..c20f8bde7838 100644 --- a/src/librustc_mir/build/cfg.rs +++ b/src/librustc_mir/build/cfg.rs @@ -14,6 +14,7 @@ //! Routines for manipulating the control-flow graph. use build::CFG; +use rustc::middle::region::CodeExtent; use rustc::mir::*; impl<'tcx> CFG<'tcx> { @@ -43,6 +44,16 @@ impl<'tcx> CFG<'tcx> { self.block_data_mut(block).statements.push(statement); } + pub fn push_end_region(&mut self, + block: BasicBlock, + source_info: SourceInfo, + extent: CodeExtent) { + self.push(block, Statement { + source_info: source_info, + kind: StatementKind::EndRegion(extent), + }); + } + pub fn push_assign(&mut self, block: BasicBlock, source_info: SourceInfo, diff --git a/src/librustc_mir/build/expr/as_lvalue.rs b/src/librustc_mir/build/expr/as_lvalue.rs index df2841a66826..04c23215463d 100644 --- a/src/librustc_mir/build/expr/as_lvalue.rs +++ b/src/librustc_mir/build/expr/as_lvalue.rs @@ -40,7 +40,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let source_info = this.source_info(expr_span); match expr.kind { ExprKind::Scope { extent, value } => { - this.in_scope(extent, block, |this| this.as_lvalue(block, value)) + this.in_scope((extent, source_info), block, |this| this.as_lvalue(block, value)) } ExprKind::Field { lhs, name } => { let lvalue = unpack!(block = this.as_lvalue(block, lhs)); diff --git a/src/librustc_mir/build/expr/as_operand.rs b/src/librustc_mir/build/expr/as_operand.rs index 5178963179d6..4679e0bb0a5c 100644 --- a/src/librustc_mir/build/expr/as_operand.rs +++ b/src/librustc_mir/build/expr/as_operand.rs @@ -56,6 +56,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let this = self; if let ExprKind::Scope { extent, value } = expr.kind { + let source_info = this.source_info(expr.span); + let extent = (extent, source_info); return this.in_scope(extent, block, |this| { this.as_operand(block, scope, value) }); diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index 2884b60fdd8a..2512291f1a44 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -59,6 +59,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { match expr.kind { ExprKind::Scope { extent, value } => { + let extent = (extent, source_info); this.in_scope(extent, block, |this| this.as_rvalue(block, scope, value)) } ExprKind::Repeat { value, count } => { @@ -99,7 +100,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // to start, malloc some memory of suitable type (thus far, uninitialized): let box_ = Rvalue::NullaryOp(NullOp::Box, value.ty); this.cfg.push_assign(block, source_info, &result, box_); - this.in_scope(value_extents, block, |this| { + this.in_scope((value_extents, source_info), block, |this| { // schedule a shallow free of that memory, lest we unwind: this.schedule_box_free(expr_span, value_extents, &result, value.ty); // initialize the box contents: diff --git a/src/librustc_mir/build/expr/as_temp.rs b/src/librustc_mir/build/expr/as_temp.rs index 17d74571ce48..9be306d2848b 100644 --- a/src/librustc_mir/build/expr/as_temp.rs +++ b/src/librustc_mir/build/expr/as_temp.rs @@ -39,16 +39,16 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { block, temp_lifetime, expr); let this = self; + let expr_span = expr.span; + let source_info = this.source_info(expr_span); if let ExprKind::Scope { extent, value } = expr.kind { - return this.in_scope(extent, block, |this| { + return this.in_scope((extent, source_info), block, |this| { this.as_temp(block, temp_lifetime, value) }); } let expr_ty = expr.ty.clone(); - let expr_span = expr.span; let temp = this.temp(expr_ty.clone(), expr_span); - let source_info = this.source_info(expr_span); if !expr_ty.is_never() && temp_lifetime.is_some() { this.cfg.push(block, Statement { diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index d456bc3ded39..b7abc707a380 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -39,6 +39,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { match expr.kind { ExprKind::Scope { extent, value } => { + let extent = (extent, source_info); this.in_scope(extent, block, |this| this.into(destination, block, value)) } ExprKind::Block { body: ast_block } => { @@ -233,7 +234,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { .collect(); let success = this.cfg.start_new_block(); - let cleanup = this.diverge_cleanup(); + let cleanup = this.diverge_cleanup(expr_span); this.cfg.terminate(block, source_info, TerminatorKind::Call { func: fun, args: args, diff --git a/src/librustc_mir/build/expr/stmt.rs b/src/librustc_mir/build/expr/stmt.rs index 3c7ab373651d..3120ac219082 100644 --- a/src/librustc_mir/build/expr/stmt.rs +++ b/src/librustc_mir/build/expr/stmt.rs @@ -24,7 +24,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { match expr.kind { ExprKind::Scope { extent, value } => { let value = this.hir.mirror(value); - this.in_scope(extent, block, |this| this.stmt_expr(block, value)) + this.in_scope((extent, source_info), block, |this| this.stmt_expr(block, value)) } ExprKind::Assign { lhs, rhs } => { let lhs = this.hir.mirror(lhs); @@ -81,7 +81,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { *this.find_breakable_scope(expr_span, label); let continue_block = continue_block.expect( "Attempted to continue in non-continuable breakable block"); - this.exit_scope(expr_span, extent, block, continue_block); + this.exit_scope(expr_span, (extent, source_info), block, continue_block); this.cfg.start_new_block().unit() } ExprKind::Break { label, value } => { @@ -99,7 +99,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } else { this.cfg.push_assign_unit(block, source_info, &destination) } - this.exit_scope(expr_span, extent, block, break_block); + this.exit_scope(expr_span, (extent, source_info), block, break_block); this.cfg.start_new_block().unit() } ExprKind::Return { value } => { @@ -116,7 +116,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { }; let extent = this.extent_of_return_scope(); let return_block = this.return_block(); - this.exit_scope(expr_span, extent, block, return_block); + this.exit_scope(expr_span, (extent, source_info), block, return_block); this.cfg.start_new_block().unit() } ExprKind::InlineAsm { asm, outputs, inputs } => { diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index 28386fa598ce..f4d43e041ae8 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -306,7 +306,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let bool_ty = self.hir.bool_ty(); let eq_result = self.temp(bool_ty, test.span); let eq_block = self.cfg.start_new_block(); - let cleanup = self.diverge_cleanup(); + let cleanup = self.diverge_cleanup(test.span); self.cfg.terminate(block, source_info, TerminatorKind::Call { func: Operand::Constant(box Constant { span: test.span, diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 08a5cb37e578..eb1414d42e17 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -83,7 +83,7 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'t }; let src = MirSource::from_node(tcx, id); - tcx.infer_ctxt(body_id).enter(|infcx| { + tcx.infer_ctxt().enter(|infcx| { let cx = Cx::new(&infcx, src); let mut mir = if cx.tables().tainted_by_errors { build::construct_error(cx, body_id) @@ -171,7 +171,7 @@ fn create_constructor_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, { let span = tcx.hir.span(ctor_id); if let hir::VariantData::Tuple(ref fields, ctor_id) = *v { - tcx.infer_ctxt(()).enter(|infcx| { + tcx.infer_ctxt().enter(|infcx| { let (mut mir, src) = shim::build_adt_ctor(&infcx, ctor_id, fields, span); @@ -339,8 +339,9 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, let call_site_extent = CodeExtent::CallSiteScope(body.id()); let arg_extent = CodeExtent::ParameterScope(body.id()); let mut block = START_BLOCK; - unpack!(block = builder.in_scope(call_site_extent, block, |builder| { - unpack!(block = builder.in_scope(arg_extent, block, |builder| { + let source_info = builder.source_info(span); + unpack!(block = builder.in_scope((call_site_extent, source_info), block, |builder| { + unpack!(block = builder.in_scope((arg_extent, source_info), block, |builder| { builder.args_and_body(block, &arguments, arg_extent, &body.value) })); // Attribute epilogue to function's closing brace @@ -365,13 +366,14 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, let upvar_decls: Vec<_> = tcx.with_freevars(fn_id, |freevars| { freevars.iter().map(|fv| { let var_id = tcx.hir.as_local_node_id(fv.def.def_id()).unwrap(); - let by_ref = hir.tables().upvar_capture(ty::UpvarId { + let capture = hir.tables().upvar_capture(ty::UpvarId { var_id: var_id, closure_expr_id: fn_id - }).map_or(false, |capture| match capture { + }); + let by_ref = match capture { ty::UpvarCapture::ByValue => false, ty::UpvarCapture::ByRef(..) => true - }); + }; let mut decl = UpvarDecl { debug_name: keywords::Invalid.name(), by_ref: by_ref diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index a99e7b4be576..469fd5750a2f 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -94,10 +94,11 @@ use rustc::ty::subst::{Kind, Subst}; use rustc::ty::{Ty, TyCtxt}; use rustc::mir::*; use rustc::mir::transform::MirSource; -use syntax_pos::Span; +use syntax_pos::{Span}; use rustc_data_structures::indexed_vec::Idx; use rustc_data_structures::fx::FxHashMap; +#[derive(Debug)] pub struct Scope<'tcx> { /// The visibility scope this scope was created in. visibility_scope: VisibilityScope, @@ -114,7 +115,7 @@ pub struct Scope<'tcx> { /// * pollutting the cleanup MIR with StorageDead creates /// landing pads even though there's no actual destructors /// * freeing up stack space has no effect during unwinding - needs_cleanup: bool, + pub(super) needs_cleanup: bool, /// set of lvalues to drop when exiting this scope. This starts /// out empty but grows as variables are declared during the @@ -141,6 +142,7 @@ pub struct Scope<'tcx> { cached_exits: FxHashMap<(BasicBlock, CodeExtent), BasicBlock>, } +#[derive(Debug)] struct DropData<'tcx> { /// span where drop obligation was incurred (typically where lvalue was declared) span: Span, @@ -152,6 +154,7 @@ struct DropData<'tcx> { kind: DropKind } +#[derive(Debug)] enum DropKind { Value { /// The cached block for the cleanups-on-diverge path. This block @@ -163,6 +166,7 @@ enum DropKind { Storage } +#[derive(Debug)] struct FreeData<'tcx> { /// span where free obligation was incurred span: Span, @@ -269,17 +273,34 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { res } + pub fn in_opt_scope(&mut self, + opt_extent: Option<(CodeExtent, SourceInfo)>, + mut block: BasicBlock, + f: F) + -> BlockAnd + where F: FnOnce(&mut Builder<'a, 'gcx, 'tcx>) -> BlockAnd + { + debug!("in_opt_scope(opt_extent={:?}, block={:?})", opt_extent, block); + if let Some(extent) = opt_extent { self.push_scope(extent.0); } + let rv = unpack!(block = f(self)); + if let Some(extent) = opt_extent { + unpack!(block = self.pop_scope(extent, block)); + } + debug!("in_scope: exiting opt_extent={:?} block={:?}", opt_extent, block); + block.and(rv) + } + /// Convenience wrapper that pushes a scope and then executes `f` /// to build its contents, popping the scope afterwards. pub fn in_scope(&mut self, - extent: CodeExtent, + extent: (CodeExtent, SourceInfo), mut block: BasicBlock, f: F) -> BlockAnd where F: FnOnce(&mut Builder<'a, 'gcx, 'tcx>) -> BlockAnd { debug!("in_scope(extent={:?}, block={:?})", extent, block); - self.push_scope(extent); + self.push_scope(extent.0); let rv = unpack!(block = f(self)); unpack!(block = self.pop_scope(extent, block)); debug!("in_scope: exiting extent={:?} block={:?}", extent, block); @@ -307,20 +328,22 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { /// drops onto the end of `block` that are needed. This must /// match 1-to-1 with `push_scope`. pub fn pop_scope(&mut self, - extent: CodeExtent, + extent: (CodeExtent, SourceInfo), mut block: BasicBlock) -> BlockAnd<()> { debug!("pop_scope({:?}, {:?})", extent, block); // We need to have `cached_block`s available for all the drops, so we call diverge_cleanup // to make sure all the `cached_block`s are filled in. - self.diverge_cleanup(); + self.diverge_cleanup(extent.1.span); let scope = self.scopes.pop().unwrap(); - assert_eq!(scope.extent, extent); + assert_eq!(scope.extent, extent.0); unpack!(block = build_scope_drops(&mut self.cfg, &scope, &self.scopes, block, self.arg_count)); + + self.cfg.push_end_region(block, extent.1, scope.extent); block.unit() } @@ -331,11 +354,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { /// module comment for details. pub fn exit_scope(&mut self, span: Span, - extent: CodeExtent, + extent: (CodeExtent, SourceInfo), mut block: BasicBlock, target: BasicBlock) { debug!("exit_scope(extent={:?}, block={:?}, target={:?})", extent, block, target); - let scope_count = 1 + self.scopes.iter().rev().position(|scope| scope.extent == extent) + let scope_count = 1 + self.scopes.iter().rev().position(|scope| scope.extent == extent.0) .unwrap_or_else(||{ span_bug!(span, "extent {:?} does not enclose", extent) }); @@ -346,7 +369,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let mut rest = &mut self.scopes[(len - scope_count)..]; while let Some((scope, rest_)) = {rest}.split_last_mut() { rest = rest_; - block = if let Some(&e) = scope.cached_exits.get(&(target, extent)) { + block = if let Some(&e) = scope.cached_exits.get(&(target, extent.0)) { self.cfg.terminate(block, scope.source_info(span), TerminatorKind::Goto { target: e }); return; @@ -354,7 +377,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let b = self.cfg.start_new_block(); self.cfg.terminate(block, scope.source_info(span), TerminatorKind::Goto { target: b }); - scope.cached_exits.insert((target, extent), b); + scope.cached_exits.insert((target, extent.0), b); b }; unpack!(block = build_scope_drops(&mut self.cfg, @@ -362,6 +385,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { rest, block, self.arg_count)); + + // End all regions for scopes out of which we are breaking. + self.cfg.push_end_region(block, extent.1, scope.extent); + if let Some(ref free_data) = scope.free { let next = self.cfg.start_new_block(); let free = build_free(self.hir.tcx(), &tmp, free_data, next); @@ -590,7 +617,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { /// This path terminates in Resume. Returns the start of the path. /// See module comment for more details. None indicates there’s no /// cleanup to do at this point. - pub fn diverge_cleanup(&mut self) -> Option { + pub fn diverge_cleanup(&mut self, span: Span) -> Option { if !self.scopes.iter().any(|scope| scope.needs_cleanup) { return None; } @@ -623,8 +650,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { resumeblk }; - for scope in scopes.iter_mut().filter(|s| s.needs_cleanup) { - target = build_diverge_scope(hir.tcx(), cfg, &unit_temp, scope, target); + for scope in scopes.iter_mut() { + target = build_diverge_scope(hir.tcx(), cfg, &unit_temp, span, scope, target); } Some(target) } @@ -640,7 +667,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } let source_info = self.source_info(span); let next_target = self.cfg.start_new_block(); - let diverge_target = self.diverge_cleanup(); + let diverge_target = self.diverge_cleanup(span); self.cfg.terminate(block, source_info, TerminatorKind::Drop { location: location, @@ -658,7 +685,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { value: Operand<'tcx>) -> BlockAnd<()> { let source_info = self.source_info(span); let next_target = self.cfg.start_new_block(); - let diverge_target = self.diverge_cleanup(); + let diverge_target = self.diverge_cleanup(span); self.cfg.terminate(block, source_info, TerminatorKind::DropAndReplace { location: location, @@ -681,7 +708,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let source_info = self.source_info(span); let success_block = self.cfg.start_new_block(); - let cleanup = self.diverge_cleanup(); + let cleanup = self.diverge_cleanup(span); self.cfg.terminate(block, source_info, TerminatorKind::Assert { @@ -750,6 +777,7 @@ fn build_scope_drops<'tcx>(cfg: &mut CFG<'tcx>, fn build_diverge_scope<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, cfg: &mut CFG<'tcx>, unit_temp: &Lvalue<'tcx>, + span: Span, scope: &mut Scope<'tcx>, mut target: BasicBlock) -> BasicBlock @@ -757,9 +785,9 @@ fn build_diverge_scope<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, // Build up the drops in **reverse** order. The end result will // look like: // - // [drops[n]] -...-> [drops[0]] -> [Free] -> [target] - // | | - // +------------------------------------+ + // [EndRegion Block] -> [drops[n]] -...-> [drops[0]] -> [Free] -> [target] + // | | + // +---------------------------------------------------------+ // code for scope // // The code in this function reads from right to left. At each @@ -789,9 +817,16 @@ fn build_diverge_scope<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, // Next, build up the drops. Here we iterate the vector in // *forward* order, so that we generate drops[0] first (right to // left in diagram above). - for drop_data in &mut scope.drops { + for (j, drop_data) in scope.drops.iter_mut().enumerate() { + debug!("build_diverge_scope drop_data[{}]: {:?}", j, drop_data); // Only full value drops are emitted in the diverging path, // not StorageDead. + // + // Note: This may not actually be what we desire (are we + // "freeing" stack storage as we unwind, or merely observing a + // frozen stack)? In particular, the intent may have been to + // match the behavior of clang, but on inspection eddyb says + // this is not what clang does. let cached_block = match drop_data.kind { DropKind::Value { ref mut cached_block } => cached_block, DropKind::Storage => continue @@ -811,6 +846,15 @@ fn build_diverge_scope<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, }; } + // Finally, push the EndRegion block, used by mir-borrowck. (Block + // becomes trivial goto after pass that removes all EndRegions.) + { + let block = cfg.start_new_cleanup_block(); + cfg.push_end_region(block, source_info(span), scope.extent); + cfg.terminate(block, source_info(span), TerminatorKind::Goto { target: target }); + target = block + } + target } diff --git a/src/librustc_mir/diagnostics.rs b/src/librustc_mir/diagnostics.rs index bb07081fe433..6f3db0b388de 100644 --- a/src/librustc_mir/diagnostics.rs +++ b/src/librustc_mir/diagnostics.rs @@ -309,8 +309,8 @@ use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT}; const A: AtomicUsize = ATOMIC_USIZE_INIT; static B: &'static AtomicUsize = &A; -// error: cannot borrow a constant which contains interior mutability, create a -// static instead +// error: cannot borrow a constant which may contain interior mutability, +// create a static instead ``` A `const` represents a constant value that should never change. If one takes @@ -338,8 +338,8 @@ use std::cell::Cell; const A: Cell = Cell::new(1); const B: &'static Cell = &A; -// error: cannot borrow a constant which contains interior mutability, create -// a static instead +// error: cannot borrow a constant which may contain interior mutability, +// create a static instead // or: struct C { a: Cell } diff --git a/src/librustc_mir/hair/cx/block.rs b/src/librustc_mir/hair/cx/block.rs index 47c50b78f3ac..fad070ca8d8f 100644 --- a/src/librustc_mir/hair/cx/block.rs +++ b/src/librustc_mir/hair/cx/block.rs @@ -22,9 +22,14 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Block { // We have to eagerly translate the "spine" of the statements // in order to get the lexical scoping correctly. let stmts = mirror_stmts(cx, self.id, &*self.stmts); + let opt_def_id = cx.tcx.hir.opt_local_def_id(self.id); + let opt_destruction_extent = opt_def_id.and_then(|def_id| { + cx.tcx.region_maps(def_id).opt_destruction_extent(self.id) + }); Block { targeted_by_break: self.targeted_by_break, extent: CodeExtent::Misc(self.id), + opt_destruction_extent: opt_destruction_extent, span: self.span, stmts: stmts, expr: self.expr.to_ref(), @@ -37,7 +42,11 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, stmts: &'tcx [hir::Stmt]) -> Vec> { let mut result = vec![]; + let opt_def_id = cx.tcx.hir.opt_local_def_id(block_id); for (index, stmt) in stmts.iter().enumerate() { + let opt_dxn_ext = opt_def_id.and_then(|def_id| { + cx.tcx.region_maps(def_id).opt_destruction_extent(stmt.node.id()) + }); match stmt.node { hir::StmtExpr(ref expr, id) | hir::StmtSemi(ref expr, id) => { @@ -47,6 +56,7 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, scope: CodeExtent::Misc(id), expr: expr.to_ref(), }, + opt_destruction_extent: opt_dxn_ext, }))) } hir::StmtDecl(ref decl, id) => { @@ -69,6 +79,7 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, pattern: pattern, initializer: local.init.to_ref(), }, + opt_destruction_extent: opt_dxn_ext, }))); } } diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 8cfeecdafb51..474feefabbb8 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -758,13 +758,7 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, var_id: id_var, closure_expr_id: closure_expr_id, }; - let upvar_capture = match cx.tables().upvar_capture(upvar_id) { - Some(c) => c, - None => { - span_bug!(expr.span, "no upvar_capture for {:?}", upvar_id); - } - }; - match upvar_capture { + match cx.tables().upvar_capture(upvar_id) { ty::UpvarCapture::ByValue => field_kind, ty::UpvarCapture::ByRef(borrow) => { ExprKind::Deref { @@ -878,7 +872,7 @@ fn capture_freevar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, var_id: id_var, closure_expr_id: closure_expr.id, }; - let upvar_capture = cx.tables().upvar_capture(upvar_id).unwrap(); + let upvar_capture = cx.tables().upvar_capture(upvar_id); let temp_lifetime = cx.region_maps.temporary_scope(closure_expr.id); let var_ty = cx.tables().node_id_to_type(id_var); let captured_var = Expr { diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index 5b7b52a72b0a..2bb6b39966a8 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -37,6 +37,7 @@ pub struct Cx<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, pub param_env: ty::ParamEnv<'tcx>, pub region_maps: Rc, + pub tables: &'a ty::TypeckTables<'gcx>, /// This is `Constness::Const` if we are compiling a `static`, /// `const`, or the body of a `const fn`. @@ -67,6 +68,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { let param_env = tcx.param_env(src_def_id); let region_maps = tcx.region_maps(src_def_id); + let tables = tcx.typeck_tables_of(src_def_id); let attrs = tcx.hir.attrs(src_id); @@ -82,7 +84,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { // Constants and const fn's always need overflow checks. check_overflow |= constness == hir::Constness::Const; - Cx { tcx, infcx, param_env, region_maps, constness, src, check_overflow } + Cx { tcx, infcx, param_env, region_maps, tables, constness, src, check_overflow } } } @@ -184,7 +186,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { } pub fn tables(&self) -> &'a ty::TypeckTables<'gcx> { - self.infcx.tables.expect_interned() + self.tables } pub fn check_overflow(&self) -> bool { diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs index 044096699b1a..bb11cce74875 100644 --- a/src/librustc_mir/hair/mod.rs +++ b/src/librustc_mir/hair/mod.rs @@ -33,6 +33,7 @@ pub use rustc_const_eval::pattern::{BindingMode, Pattern, PatternKind, FieldPatt pub struct Block<'tcx> { pub targeted_by_break: bool, pub extent: CodeExtent, + pub opt_destruction_extent: Option, pub span: Span, pub stmts: Vec>, pub expr: Option>, @@ -47,6 +48,7 @@ pub enum StmtRef<'tcx> { pub struct Stmt<'tcx> { pub span: Span, pub kind: StmtKind<'tcx>, + pub opt_destruction_extent: Option, } #[derive(Clone, Debug)] diff --git a/src/librustc_mir/transform/clean_end_regions.rs b/src/librustc_mir/transform/clean_end_regions.rs new file mode 100644 index 000000000000..36125f945436 --- /dev/null +++ b/src/librustc_mir/transform/clean_end_regions.rs @@ -0,0 +1,84 @@ +// 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 provides one pass, `CleanEndRegions`, that reduces the +//! set of `EndRegion` statements in the MIR. +//! +//! The "pass" is actually implemented as two traversals (aka visits) +//! of the input MIR. The first traversal, `GatherBorrowedRegions`, +//! finds all of the regions in the MIR that are involved in a borrow. +//! +//! The second traversal, `DeleteTrivialEndRegions`, walks over the +//! MIR and removes any `EndRegion` that is applied to a region that +//! was not seen in the previous pass. + +use rustc_data_structures::fx::FxHashSet; + +use rustc::middle::region::CodeExtent; +use rustc::mir::transform::{MirPass, MirSource}; +use rustc::mir::{BasicBlock, Location, Mir, Rvalue, Statement, StatementKind}; +use rustc::mir::visit::{MutVisitor, Visitor}; +use rustc::ty::{RegionKind, TyCtxt}; + +pub struct CleanEndRegions; + +struct GatherBorrowedRegions { + seen_regions: FxHashSet, +} + +struct DeleteTrivialEndRegions<'a> { + seen_regions: &'a FxHashSet, +} + +impl MirPass for CleanEndRegions { + fn run_pass<'a, 'tcx>(&self, + _tcx: TyCtxt<'a, 'tcx, 'tcx>, + _source: MirSource, + mir: &mut Mir<'tcx>) { + let mut gather = GatherBorrowedRegions { seen_regions: FxHashSet() }; + gather.visit_mir(mir); + + let mut delete = DeleteTrivialEndRegions { seen_regions: &mut gather.seen_regions }; + delete.visit_mir(mir); + } +} + +impl<'tcx> Visitor<'tcx> for GatherBorrowedRegions { + fn visit_rvalue(&mut self, + rvalue: &Rvalue<'tcx>, + location: Location) { + if let Rvalue::Ref(r, _, _) = *rvalue { + if let RegionKind::ReScope(ce) = *r { + self.seen_regions.insert(ce); + } + } + self.super_rvalue(rvalue, location); + } +} + +impl<'a, 'tcx> MutVisitor<'tcx> for DeleteTrivialEndRegions<'a> { + fn visit_statement(&mut self, + block: BasicBlock, + statement: &mut Statement<'tcx>, + location: Location) { + let mut delete_it = false; + + if let StatementKind::EndRegion(ref extent) = statement.kind { + if !self.seen_regions.contains(extent) { + delete_it = true; + } + } + + if delete_it { + statement.kind = StatementKind::Nop; + } + self.super_statement(block, statement, location); + } +} diff --git a/src/librustc_mir/transform/copy_prop.rs b/src/librustc_mir/transform/copy_prop.rs index 08a4961c6cd1..dec0717e9e38 100644 --- a/src/librustc_mir/transform/copy_prop.rs +++ b/src/librustc_mir/transform/copy_prop.rs @@ -34,7 +34,6 @@ use rustc::mir::transform::{MirPass, MirSource}; use rustc::mir::visit::MutVisitor; use rustc::ty::TyCtxt; use util::def_use::DefUseAnalysis; -use transform::qualify_consts; pub struct CopyPropagation; @@ -55,7 +54,7 @@ impl MirPass for CopyPropagation { return } MirSource::Fn(function_node_id) => { - if qualify_consts::is_const_fn(tcx, tcx.hir.local_def_id(function_node_id)) { + if tcx.is_const_fn(tcx.hir.local_def_id(function_node_id)) { // Don't run on const functions, as, again, trans might not be able to evaluate // the optimized IR. return diff --git a/src/librustc_mir/transform/erase_regions.rs b/src/librustc_mir/transform/erase_regions.rs index fa88eca6ec3f..e809695c1804 100644 --- a/src/librustc_mir/transform/erase_regions.rs +++ b/src/librustc_mir/transform/erase_regions.rs @@ -65,6 +65,15 @@ impl<'a, 'tcx> MutVisitor<'tcx> for EraseRegionsVisitor<'a, 'tcx> { substs: &mut ClosureSubsts<'tcx>) { *substs = self.tcx.erase_regions(substs); } + + fn visit_statement(&mut self, + _block: BasicBlock, + statement: &mut Statement<'tcx>, + _location: Location) { + if let StatementKind::EndRegion(_) = statement.kind { + statement.kind = StatementKind::Nop; + } + } } pub struct EraseRegions; diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index fcea5d4c8604..4594c611d596 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -24,6 +24,7 @@ use syntax::ast; use syntax_pos::{DUMMY_SP, Span}; use transform; +pub mod clean_end_regions; pub mod simplify_branches; pub mod simplify; pub mod erase_regions; diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index ef88e813a50c..05a6cdd57ffc 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -19,7 +19,6 @@ use rustc_data_structures::indexed_vec::{IndexVec, Idx}; use rustc::hir; use rustc::hir::map as hir_map; use rustc::hir::def_id::DefId; -use rustc::hir::map::blocks::FnLikeNode; use rustc::traits::{self, Reveal}; use rustc::ty::{self, TyCtxt, Ty, TypeFoldable}; use rustc::ty::cast::CastTy; @@ -109,18 +108,6 @@ impl fmt::Display for Mode { } } -pub fn is_const_fn(tcx: TyCtxt, def_id: DefId) -> bool { - 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)) { - fn_like.constness() == hir::Constness::Const - } else { - false - } - } else { - tcx.sess.cstore.is_const_fn(def_id) - } -} - struct Qualifier<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { mode: Mode, span: Span, @@ -663,7 +650,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { self.add(Qualif::NOT_CONST); if self.mode != Mode::Fn { span_err!(self.tcx.sess, self.span, E0492, - "cannot borrow a constant which contains \ + "cannot borrow a constant which may contain \ interior mutability, create a static instead"); } } @@ -766,7 +753,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { ty::TyFnDef(def_id, _, f) => { (f.abi() == Abi::PlatformIntrinsic && self.tcx.item_name(def_id).as_str().starts_with("simd_shuffle"), - is_const_fn(self.tcx, def_id)) + self.tcx.is_const_fn(def_id)) } _ => (false, false) }; @@ -907,6 +894,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { StatementKind::StorageLive(_) | StatementKind::StorageDead(_) | StatementKind::InlineAsm {..} | + StatementKind::EndRegion(_) | StatementKind::Nop => {} } }); @@ -957,7 +945,7 @@ impl MirPass for QualifyAndPromoteConstants { let def_id = tcx.hir.local_def_id(id); let mode = match src { MirSource::Fn(_) => { - if is_const_fn(tcx, def_id) { + if tcx.is_const_fn(def_id) { Mode::ConstFn } else { Mode::Fn @@ -998,7 +986,7 @@ impl MirPass for QualifyAndPromoteConstants { // Statics must be Sync. if mode == Mode::Static { let ty = mir.return_ty; - tcx.infer_ctxt(()).enter(|infcx| { + tcx.infer_ctxt().enter(|infcx| { let param_env = ty::ParamEnv::empty(Reveal::UserFacing); let cause = traits::ObligationCause::new(mir.span, id, traits::SharedStatic); let mut fulfillment_cx = traits::FulfillmentContext::new(); diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index da8e3b5a42ba..efde39ad6a4c 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -413,6 +413,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } } StatementKind::InlineAsm { .. } | + StatementKind::EndRegion(_) | StatementKind::Nop => {} } } @@ -759,7 +760,7 @@ impl MirPass for TypeckMir { return; } let param_env = tcx.param_env(def_id); - tcx.infer_ctxt(()).enter(|infcx| { + tcx.infer_ctxt().enter(|infcx| { let mut checker = TypeChecker::new(&infcx, item_id, param_env); { let mut verifier = TypeVerifier::new(&mut checker, mir); diff --git a/src/librustc_mir/util/patch.rs b/src/librustc_mir/util/patch.rs index 7898d93c22e3..ac121131eb99 100644 --- a/src/librustc_mir/util/patch.rs +++ b/src/librustc_mir/util/patch.rs @@ -46,6 +46,7 @@ impl<'tcx> MirPatch<'tcx> { for (bb, block) in mir.basic_blocks().iter_enumerated() { if let TerminatorKind::Resume = block.terminator().kind { if block.statements.len() > 0 { + assert!(resume_stmt_block.is_none()); resume_stmt_block = Some(bb); } else { resume_block = Some(bb); diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index 65a9334bbae1..bec4c083905a 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -51,7 +51,6 @@ use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; use std::collections::hash_map::Entry; use std::cmp::Ordering; -use std::mem; struct CheckCrateVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -102,7 +101,7 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> { fn_like.constness() == hir::Constness::Const }) } else { - self.tcx.sess.cstore.is_const_fn(def_id) + self.tcx.is_const_fn(def_id) }; } } @@ -138,13 +137,14 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> { self.check_const_eval(&body.value); } - let outer_penv = self.tcx.infer_ctxt(body_id).enter(|infcx| { - let param_env = self.tcx.param_env(item_def_id); - let outer_penv = mem::replace(&mut self.param_env, param_env); - let region_maps = &self.tcx.region_maps(item_def_id); - euv::ExprUseVisitor::new(self, region_maps, &infcx, param_env).consume_body(body); - outer_penv - }); + let outer_penv = self.param_env; + self.param_env = self.tcx.param_env(item_def_id); + + let tcx = self.tcx; + let param_env = self.param_env; + let region_maps = self.tcx.region_maps(item_def_id); + euv::ExprUseVisitor::new(self, tcx, param_env, ®ion_maps, self.tables) + .consume_body(body); self.visit_body(body); diff --git a/src/librustc_passes/mir_stats.rs b/src/librustc_passes/mir_stats.rs index e29da3a64965..4dd38cc515c7 100644 --- a/src/librustc_passes/mir_stats.rs +++ b/src/librustc_passes/mir_stats.rs @@ -125,6 +125,7 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> { self.record("Statement", statement); self.record(match statement.kind { StatementKind::Assign(..) => "StatementKind::Assign", + StatementKind::EndRegion(..) => "StatementKind::EndRegion", StatementKind::SetDiscriminant { .. } => "StatementKind::SetDiscriminant", StatementKind::StorageLive(..) => "StatementKind::StorageLive", StatementKind::StorageDead(..) => "StatementKind::StorageDead", diff --git a/src/librustc_platform_intrinsics/arm.rs b/src/librustc_platform_intrinsics/arm.rs index 834528aaaa31..59ac5ccc53f5 100644 --- a/src/librustc_platform_intrinsics/arm.rs +++ b/src/librustc_platform_intrinsics/arm.rs @@ -25,232 +25,232 @@ pub fn find(name: &str) -> Option { "hadd_s8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I8x8, &::I8x8]; &INPUTS }, output: &::I8x8, - definition: Named("llvm.neon.vhadds.v8i8") + definition: Named("llvm.arm.neon.vhadds.v8i8") }, "hadd_u8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U8x8, &::U8x8]; &INPUTS }, output: &::U8x8, - definition: Named("llvm.neon.vhaddu.v8i8") + definition: Named("llvm.arm.neon.vhaddu.v8i8") }, "hadd_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I16x4, &::I16x4]; &INPUTS }, output: &::I16x4, - definition: Named("llvm.neon.vhadds.v4i16") + definition: Named("llvm.arm.neon.vhadds.v4i16") }, "hadd_u16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U16x4, &::U16x4]; &INPUTS }, output: &::U16x4, - definition: Named("llvm.neon.vhaddu.v4i16") + definition: Named("llvm.arm.neon.vhaddu.v4i16") }, "hadd_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I32x2, &::I32x2]; &INPUTS }, output: &::I32x2, - definition: Named("llvm.neon.vhadds.v2i32") + definition: Named("llvm.arm.neon.vhadds.v2i32") }, "hadd_u32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U32x2, &::U32x2]; &INPUTS }, output: &::U32x2, - definition: Named("llvm.neon.vhaddu.v2i32") + definition: Named("llvm.arm.neon.vhaddu.v2i32") }, "haddq_s8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I8x16, &::I8x16]; &INPUTS }, output: &::I8x16, - definition: Named("llvm.neon.vhadds.v16i8") + definition: Named("llvm.arm.neon.vhadds.v16i8") }, "haddq_u8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U8x16, &::U8x16]; &INPUTS }, output: &::U8x16, - definition: Named("llvm.neon.vhaddu.v16i8") + definition: Named("llvm.arm.neon.vhaddu.v16i8") }, "haddq_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I16x8, &::I16x8]; &INPUTS }, output: &::I16x8, - definition: Named("llvm.neon.vhadds.v8i16") + definition: Named("llvm.arm.neon.vhadds.v8i16") }, "haddq_u16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U16x8, &::U16x8]; &INPUTS }, output: &::U16x8, - definition: Named("llvm.neon.vhaddu.v8i16") + definition: Named("llvm.arm.neon.vhaddu.v8i16") }, "haddq_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I32x4, &::I32x4]; &INPUTS }, output: &::I32x4, - definition: Named("llvm.neon.vhadds.v4i32") + definition: Named("llvm.arm.neon.vhadds.v4i32") }, "haddq_u32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U32x4, &::U32x4]; &INPUTS }, output: &::U32x4, - definition: Named("llvm.neon.vhaddu.v4i32") + definition: Named("llvm.arm.neon.vhaddu.v4i32") }, "rhadd_s8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I8x8, &::I8x8]; &INPUTS }, output: &::I8x8, - definition: Named("llvm.neon.vrhadds.v8i8") + definition: Named("llvm.arm.neon.vrhadds.v8i8") }, "rhadd_u8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U8x8, &::U8x8]; &INPUTS }, output: &::U8x8, - definition: Named("llvm.neon.vrhaddu.v8i8") + definition: Named("llvm.arm.neon.vrhaddu.v8i8") }, "rhadd_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I16x4, &::I16x4]; &INPUTS }, output: &::I16x4, - definition: Named("llvm.neon.vrhadds.v4i16") + definition: Named("llvm.arm.neon.vrhadds.v4i16") }, "rhadd_u16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U16x4, &::U16x4]; &INPUTS }, output: &::U16x4, - definition: Named("llvm.neon.vrhaddu.v4i16") + definition: Named("llvm.arm.neon.vrhaddu.v4i16") }, "rhadd_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I32x2, &::I32x2]; &INPUTS }, output: &::I32x2, - definition: Named("llvm.neon.vrhadds.v2i32") + definition: Named("llvm.arm.neon.vrhadds.v2i32") }, "rhadd_u32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U32x2, &::U32x2]; &INPUTS }, output: &::U32x2, - definition: Named("llvm.neon.vrhaddu.v2i32") + definition: Named("llvm.arm.neon.vrhaddu.v2i32") }, "rhaddq_s8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I8x16, &::I8x16]; &INPUTS }, output: &::I8x16, - definition: Named("llvm.neon.vrhadds.v16i8") + definition: Named("llvm.arm.neon.vrhadds.v16i8") }, "rhaddq_u8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U8x16, &::U8x16]; &INPUTS }, output: &::U8x16, - definition: Named("llvm.neon.vrhaddu.v16i8") + definition: Named("llvm.arm.neon.vrhaddu.v16i8") }, "rhaddq_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I16x8, &::I16x8]; &INPUTS }, output: &::I16x8, - definition: Named("llvm.neon.vrhadds.v8i16") + definition: Named("llvm.arm.neon.vrhadds.v8i16") }, "rhaddq_u16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U16x8, &::U16x8]; &INPUTS }, output: &::U16x8, - definition: Named("llvm.neon.vrhaddu.v8i16") + definition: Named("llvm.arm.neon.vrhaddu.v8i16") }, "rhaddq_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I32x4, &::I32x4]; &INPUTS }, output: &::I32x4, - definition: Named("llvm.neon.vrhadds.v4i32") + definition: Named("llvm.arm.neon.vrhadds.v4i32") }, "rhaddq_u32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U32x4, &::U32x4]; &INPUTS }, output: &::U32x4, - definition: Named("llvm.neon.vrhaddu.v4i32") + definition: Named("llvm.arm.neon.vrhaddu.v4i32") }, "qadd_s8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I8x8, &::I8x8]; &INPUTS }, output: &::I8x8, - definition: Named("llvm.neon.vqadds.v8i8") + definition: Named("llvm.arm.neon.vqadds.v8i8") }, "qadd_u8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U8x8, &::U8x8]; &INPUTS }, output: &::U8x8, - definition: Named("llvm.neon.vqaddu.v8i8") + definition: Named("llvm.arm.neon.vqaddu.v8i8") }, "qadd_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I16x4, &::I16x4]; &INPUTS }, output: &::I16x4, - definition: Named("llvm.neon.vqadds.v4i16") + definition: Named("llvm.arm.neon.vqadds.v4i16") }, "qadd_u16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U16x4, &::U16x4]; &INPUTS }, output: &::U16x4, - definition: Named("llvm.neon.vqaddu.v4i16") + definition: Named("llvm.arm.neon.vqaddu.v4i16") }, "qadd_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I32x2, &::I32x2]; &INPUTS }, output: &::I32x2, - definition: Named("llvm.neon.vqadds.v2i32") + definition: Named("llvm.arm.neon.vqadds.v2i32") }, "qadd_u32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U32x2, &::U32x2]; &INPUTS }, output: &::U32x2, - definition: Named("llvm.neon.vqaddu.v2i32") + definition: Named("llvm.arm.neon.vqaddu.v2i32") }, "qadd_s64" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I64x1, &::I64x1]; &INPUTS }, output: &::I64x1, - definition: Named("llvm.neon.vqadds.v1i64") + definition: Named("llvm.arm.neon.vqadds.v1i64") }, "qadd_u64" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U64x1, &::U64x1]; &INPUTS }, output: &::U64x1, - definition: Named("llvm.neon.vqaddu.v1i64") + definition: Named("llvm.arm.neon.vqaddu.v1i64") }, "qaddq_s8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I8x16, &::I8x16]; &INPUTS }, output: &::I8x16, - definition: Named("llvm.neon.vqadds.v16i8") + definition: Named("llvm.arm.neon.vqadds.v16i8") }, "qaddq_u8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U8x16, &::U8x16]; &INPUTS }, output: &::U8x16, - definition: Named("llvm.neon.vqaddu.v16i8") + definition: Named("llvm.arm.neon.vqaddu.v16i8") }, "qaddq_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I16x8, &::I16x8]; &INPUTS }, output: &::I16x8, - definition: Named("llvm.neon.vqadds.v8i16") + definition: Named("llvm.arm.neon.vqadds.v8i16") }, "qaddq_u16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U16x8, &::U16x8]; &INPUTS }, output: &::U16x8, - definition: Named("llvm.neon.vqaddu.v8i16") + definition: Named("llvm.arm.neon.vqaddu.v8i16") }, "qaddq_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I32x4, &::I32x4]; &INPUTS }, output: &::I32x4, - definition: Named("llvm.neon.vqadds.v4i32") + definition: Named("llvm.arm.neon.vqadds.v4i32") }, "qaddq_u32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U32x4, &::U32x4]; &INPUTS }, output: &::U32x4, - definition: Named("llvm.neon.vqaddu.v4i32") + definition: Named("llvm.arm.neon.vqaddu.v4i32") }, "qaddq_s64" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I64x2, &::I64x2]; &INPUTS }, output: &::I64x2, - definition: Named("llvm.neon.vqadds.v2i64") + definition: Named("llvm.arm.neon.vqadds.v2i64") }, "qaddq_u64" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U64x2, &::U64x2]; &INPUTS }, output: &::U64x2, - definition: Named("llvm.neon.vqaddu.v2i64") + definition: Named("llvm.arm.neon.vqaddu.v2i64") }, "raddhn_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I16x8, &::I16x8]; &INPUTS }, output: &::I8x8, - definition: Named("llvm.neon.vraddhn.v8i8") + definition: Named("llvm.arm.neon.vraddhn.v8i8") }, "raddhn_u16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U16x8, &::U16x8]; &INPUTS }, output: &::U8x8, - definition: Named("llvm.neon.vraddhn.v8i8") + definition: Named("llvm.arm.neon.vraddhn.v8i8") }, "raddhn_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I32x4, &::I32x4]; &INPUTS }, output: &::I16x4, - definition: Named("llvm.neon.vraddhn.v4i16") + definition: Named("llvm.arm.neon.vraddhn.v4i16") }, "raddhn_u32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U32x4, &::U32x4]; &INPUTS }, output: &::U16x4, - definition: Named("llvm.neon.vraddhn.v4i16") + definition: Named("llvm.arm.neon.vraddhn.v4i16") }, "raddhn_s64" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I64x2, &::I64x2]; &INPUTS }, output: &::I32x2, - definition: Named("llvm.neon.vraddhn.v2i32") + definition: Named("llvm.arm.neon.vraddhn.v2i32") }, "raddhn_u64" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U64x2, &::U64x2]; &INPUTS }, output: &::U32x2, - definition: Named("llvm.neon.vraddhn.v2i32") + definition: Named("llvm.arm.neon.vraddhn.v2i32") }, "fma_f32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::F32x2, &::F32x2]; &INPUTS }, @@ -265,1122 +265,1122 @@ pub fn find(name: &str) -> Option { "qdmulh_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I16x4, &::I16x4]; &INPUTS }, output: &::I16x4, - definition: Named("llvm.neon.vsqdmulh.v4i16") + definition: Named("llvm.arm.neon.vsqdmulh.v4i16") }, "qdmulh_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I32x2, &::I32x2]; &INPUTS }, output: &::I32x2, - definition: Named("llvm.neon.vsqdmulh.v2i32") + definition: Named("llvm.arm.neon.vsqdmulh.v2i32") }, "qdmulhq_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I16x8, &::I16x8]; &INPUTS }, output: &::I16x8, - definition: Named("llvm.neon.vsqdmulh.v8i16") + definition: Named("llvm.arm.neon.vsqdmulh.v8i16") }, "qdmulhq_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I32x4, &::I32x4]; &INPUTS }, output: &::I32x4, - definition: Named("llvm.neon.vsqdmulh.v4i32") + definition: Named("llvm.arm.neon.vsqdmulh.v4i32") }, "qrdmulh_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I16x4, &::I16x4]; &INPUTS }, output: &::I16x4, - definition: Named("llvm.neon.vsqrdmulh.v4i16") + definition: Named("llvm.arm.neon.vsqrdmulh.v4i16") }, "qrdmulh_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I32x2, &::I32x2]; &INPUTS }, output: &::I32x2, - definition: Named("llvm.neon.vsqrdmulh.v2i32") + definition: Named("llvm.arm.neon.vsqrdmulh.v2i32") }, "qrdmulhq_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I16x8, &::I16x8]; &INPUTS }, output: &::I16x8, - definition: Named("llvm.neon.vsqrdmulh.v8i16") + definition: Named("llvm.arm.neon.vsqrdmulh.v8i16") }, "qrdmulhq_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I32x4, &::I32x4]; &INPUTS }, output: &::I32x4, - definition: Named("llvm.neon.vsqrdmulh.v4i32") + definition: Named("llvm.arm.neon.vsqrdmulh.v4i32") }, "mull_s8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I8x8, &::I8x8]; &INPUTS }, output: &::I16x8, - definition: Named("llvm.neon.vmulls.v8i16") + definition: Named("llvm.arm.neon.vmulls.v8i16") }, "mull_u8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U8x8, &::U8x8]; &INPUTS }, output: &::U16x8, - definition: Named("llvm.neon.vmullu.v8i16") + definition: Named("llvm.arm.neon.vmullu.v8i16") }, "mull_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I16x4, &::I16x4]; &INPUTS }, output: &::I32x4, - definition: Named("llvm.neon.vmulls.v4i32") + definition: Named("llvm.arm.neon.vmulls.v4i32") }, "mull_u16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U16x4, &::U16x4]; &INPUTS }, output: &::U32x4, - definition: Named("llvm.neon.vmullu.v4i32") + definition: Named("llvm.arm.neon.vmullu.v4i32") }, "mull_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I32x2, &::I32x2]; &INPUTS }, output: &::I64x2, - definition: Named("llvm.neon.vmulls.v2i64") + definition: Named("llvm.arm.neon.vmulls.v2i64") }, "mull_u32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U32x2, &::U32x2]; &INPUTS }, output: &::U64x2, - definition: Named("llvm.neon.vmullu.v2i64") + definition: Named("llvm.arm.neon.vmullu.v2i64") }, "qdmullq_s8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I8x8, &::I8x8]; &INPUTS }, output: &::I16x8, - definition: Named("llvm.neon.vsqdmull.v8i16") + definition: Named("llvm.arm.neon.vsqdmull.v8i16") }, "qdmullq_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I16x4, &::I16x4]; &INPUTS }, output: &::I32x4, - definition: Named("llvm.neon.vsqdmull.v4i32") + definition: Named("llvm.arm.neon.vsqdmull.v4i32") }, "hsub_s8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I8x8, &::I8x8]; &INPUTS }, output: &::I8x8, - definition: Named("llvm.neon.vhsubs.v8i8") + definition: Named("llvm.arm.neon.vhsubs.v8i8") }, "hsub_u8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U8x8, &::U8x8]; &INPUTS }, output: &::U8x8, - definition: Named("llvm.neon.vhsubu.v8i8") + definition: Named("llvm.arm.neon.vhsubu.v8i8") }, "hsub_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I16x4, &::I16x4]; &INPUTS }, output: &::I16x4, - definition: Named("llvm.neon.vhsubs.v4i16") + definition: Named("llvm.arm.neon.vhsubs.v4i16") }, "hsub_u16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U16x4, &::U16x4]; &INPUTS }, output: &::U16x4, - definition: Named("llvm.neon.vhsubu.v4i16") + definition: Named("llvm.arm.neon.vhsubu.v4i16") }, "hsub_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I32x2, &::I32x2]; &INPUTS }, output: &::I32x2, - definition: Named("llvm.neon.vhsubs.v2i32") + definition: Named("llvm.arm.neon.vhsubs.v2i32") }, "hsub_u32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U32x2, &::U32x2]; &INPUTS }, output: &::U32x2, - definition: Named("llvm.neon.vhsubu.v2i32") + definition: Named("llvm.arm.neon.vhsubu.v2i32") }, "hsubq_s8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I8x16, &::I8x16]; &INPUTS }, output: &::I8x16, - definition: Named("llvm.neon.vhsubs.v16i8") + definition: Named("llvm.arm.neon.vhsubs.v16i8") }, "hsubq_u8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U8x16, &::U8x16]; &INPUTS }, output: &::U8x16, - definition: Named("llvm.neon.vhsubu.v16i8") + definition: Named("llvm.arm.neon.vhsubu.v16i8") }, "hsubq_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I16x8, &::I16x8]; &INPUTS }, output: &::I16x8, - definition: Named("llvm.neon.vhsubs.v8i16") + definition: Named("llvm.arm.neon.vhsubs.v8i16") }, "hsubq_u16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U16x8, &::U16x8]; &INPUTS }, output: &::U16x8, - definition: Named("llvm.neon.vhsubu.v8i16") + definition: Named("llvm.arm.neon.vhsubu.v8i16") }, "hsubq_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I32x4, &::I32x4]; &INPUTS }, output: &::I32x4, - definition: Named("llvm.neon.vhsubs.v4i32") + definition: Named("llvm.arm.neon.vhsubs.v4i32") }, "hsubq_u32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U32x4, &::U32x4]; &INPUTS }, output: &::U32x4, - definition: Named("llvm.neon.vhsubu.v4i32") + definition: Named("llvm.arm.neon.vhsubu.v4i32") }, "qsub_s8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I8x8, &::I8x8]; &INPUTS }, output: &::I8x8, - definition: Named("llvm.neon.vqsubs.v8i8") + definition: Named("llvm.arm.neon.vqsubs.v8i8") }, "qsub_u8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U8x8, &::U8x8]; &INPUTS }, output: &::U8x8, - definition: Named("llvm.neon.vqsubu.v8i8") + definition: Named("llvm.arm.neon.vqsubu.v8i8") }, "qsub_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I16x4, &::I16x4]; &INPUTS }, output: &::I16x4, - definition: Named("llvm.neon.vqsubs.v4i16") + definition: Named("llvm.arm.neon.vqsubs.v4i16") }, "qsub_u16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U16x4, &::U16x4]; &INPUTS }, output: &::U16x4, - definition: Named("llvm.neon.vqsubu.v4i16") + definition: Named("llvm.arm.neon.vqsubu.v4i16") }, "qsub_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I32x2, &::I32x2]; &INPUTS }, output: &::I32x2, - definition: Named("llvm.neon.vqsubs.v2i32") + definition: Named("llvm.arm.neon.vqsubs.v2i32") }, "qsub_u32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U32x2, &::U32x2]; &INPUTS }, output: &::U32x2, - definition: Named("llvm.neon.vqsubu.v2i32") + definition: Named("llvm.arm.neon.vqsubu.v2i32") }, "qsub_s64" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I64x1, &::I64x1]; &INPUTS }, output: &::I64x1, - definition: Named("llvm.neon.vqsubs.v1i64") + definition: Named("llvm.arm.neon.vqsubs.v1i64") }, "qsub_u64" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U64x1, &::U64x1]; &INPUTS }, output: &::U64x1, - definition: Named("llvm.neon.vqsubu.v1i64") + definition: Named("llvm.arm.neon.vqsubu.v1i64") }, "qsubq_s8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I8x16, &::I8x16]; &INPUTS }, output: &::I8x16, - definition: Named("llvm.neon.vqsubs.v16i8") + definition: Named("llvm.arm.neon.vqsubs.v16i8") }, "qsubq_u8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U8x16, &::U8x16]; &INPUTS }, output: &::U8x16, - definition: Named("llvm.neon.vqsubu.v16i8") + definition: Named("llvm.arm.neon.vqsubu.v16i8") }, "qsubq_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I16x8, &::I16x8]; &INPUTS }, output: &::I16x8, - definition: Named("llvm.neon.vqsubs.v8i16") + definition: Named("llvm.arm.neon.vqsubs.v8i16") }, "qsubq_u16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U16x8, &::U16x8]; &INPUTS }, output: &::U16x8, - definition: Named("llvm.neon.vqsubu.v8i16") + definition: Named("llvm.arm.neon.vqsubu.v8i16") }, "qsubq_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I32x4, &::I32x4]; &INPUTS }, output: &::I32x4, - definition: Named("llvm.neon.vqsubs.v4i32") + definition: Named("llvm.arm.neon.vqsubs.v4i32") }, "qsubq_u32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U32x4, &::U32x4]; &INPUTS }, output: &::U32x4, - definition: Named("llvm.neon.vqsubu.v4i32") + definition: Named("llvm.arm.neon.vqsubu.v4i32") }, "qsubq_s64" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I64x2, &::I64x2]; &INPUTS }, output: &::I64x2, - definition: Named("llvm.neon.vqsubs.v2i64") + definition: Named("llvm.arm.neon.vqsubs.v2i64") }, "qsubq_u64" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U64x2, &::U64x2]; &INPUTS }, output: &::U64x2, - definition: Named("llvm.neon.vqsubu.v2i64") + definition: Named("llvm.arm.neon.vqsubu.v2i64") }, "rsubhn_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I16x8, &::I16x8]; &INPUTS }, output: &::I8x8, - definition: Named("llvm.neon.vrsubhn.v8i8") + definition: Named("llvm.arm.neon.vrsubhn.v8i8") }, "rsubhn_u16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U16x8, &::U16x8]; &INPUTS }, output: &::U8x8, - definition: Named("llvm.neon.vrsubhn.v8i8") + definition: Named("llvm.arm.neon.vrsubhn.v8i8") }, "rsubhn_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I32x4, &::I32x4]; &INPUTS }, output: &::I16x4, - definition: Named("llvm.neon.vrsubhn.v4i16") + definition: Named("llvm.arm.neon.vrsubhn.v4i16") }, "rsubhn_u32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U32x4, &::U32x4]; &INPUTS }, output: &::U16x4, - definition: Named("llvm.neon.vrsubhn.v4i16") + definition: Named("llvm.arm.neon.vrsubhn.v4i16") }, "rsubhn_s64" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I64x2, &::I64x2]; &INPUTS }, output: &::I32x2, - definition: Named("llvm.neon.vrsubhn.v2i32") + definition: Named("llvm.arm.neon.vrsubhn.v2i32") }, "rsubhn_u64" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U64x2, &::U64x2]; &INPUTS }, output: &::U32x2, - definition: Named("llvm.neon.vrsubhn.v2i32") + definition: Named("llvm.arm.neon.vrsubhn.v2i32") }, "abd_s8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I8x8, &::I8x8]; &INPUTS }, output: &::I8x8, - definition: Named("llvm.neon.vabds.v8i8") + definition: Named("llvm.arm.neon.vabds.v8i8") }, "abd_u8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U8x8, &::U8x8]; &INPUTS }, output: &::U8x8, - definition: Named("llvm.neon.vabdu.v8i8") + definition: Named("llvm.arm.neon.vabdu.v8i8") }, "abd_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I16x4, &::I16x4]; &INPUTS }, output: &::I16x4, - definition: Named("llvm.neon.vabds.v4i16") + definition: Named("llvm.arm.neon.vabds.v4i16") }, "abd_u16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U16x4, &::U16x4]; &INPUTS }, output: &::U16x4, - definition: Named("llvm.neon.vabdu.v4i16") + definition: Named("llvm.arm.neon.vabdu.v4i16") }, "abd_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I32x2, &::I32x2]; &INPUTS }, output: &::I32x2, - definition: Named("llvm.neon.vabds.v2i32") + definition: Named("llvm.arm.neon.vabds.v2i32") }, "abd_u32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U32x2, &::U32x2]; &INPUTS }, output: &::U32x2, - definition: Named("llvm.neon.vabdu.v2i32") + definition: Named("llvm.arm.neon.vabdu.v2i32") }, "abd_f32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::F32x2, &::F32x2]; &INPUTS }, output: &::F32x2, - definition: Named("llvm.neon.vabdf.v2f32") + definition: Named("llvm.arm.neon.vabdf.v2f32") }, "abdq_s8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I8x16, &::I8x16]; &INPUTS }, output: &::I8x16, - definition: Named("llvm.neon.vabds.v16i8") + definition: Named("llvm.arm.neon.vabds.v16i8") }, "abdq_u8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U8x16, &::U8x16]; &INPUTS }, output: &::U8x16, - definition: Named("llvm.neon.vabdu.v16i8") + definition: Named("llvm.arm.neon.vabdu.v16i8") }, "abdq_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I16x8, &::I16x8]; &INPUTS }, output: &::I16x8, - definition: Named("llvm.neon.vabds.v8i16") + definition: Named("llvm.arm.neon.vabds.v8i16") }, "abdq_u16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U16x8, &::U16x8]; &INPUTS }, output: &::U16x8, - definition: Named("llvm.neon.vabdu.v8i16") + definition: Named("llvm.arm.neon.vabdu.v8i16") }, "abdq_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I32x4, &::I32x4]; &INPUTS }, output: &::I32x4, - definition: Named("llvm.neon.vabds.v4i32") + definition: Named("llvm.arm.neon.vabds.v4i32") }, "abdq_u32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U32x4, &::U32x4]; &INPUTS }, output: &::U32x4, - definition: Named("llvm.neon.vabdu.v4i32") + definition: Named("llvm.arm.neon.vabdu.v4i32") }, "abdq_f32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::F32x4, &::F32x4]; &INPUTS }, output: &::F32x4, - definition: Named("llvm.neon.vabdf.v4f32") + definition: Named("llvm.arm.neon.vabdf.v4f32") }, "max_s8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I8x8, &::I8x8]; &INPUTS }, output: &::I8x8, - definition: Named("llvm.neon.vmaxs.v8i8") + definition: Named("llvm.arm.neon.vmaxs.v8i8") }, "max_u8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U8x8, &::U8x8]; &INPUTS }, output: &::U8x8, - definition: Named("llvm.neon.vmaxu.v8i8") + definition: Named("llvm.arm.neon.vmaxu.v8i8") }, "max_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I16x4, &::I16x4]; &INPUTS }, output: &::I16x4, - definition: Named("llvm.neon.vmaxs.v4i16") + definition: Named("llvm.arm.neon.vmaxs.v4i16") }, "max_u16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U16x4, &::U16x4]; &INPUTS }, output: &::U16x4, - definition: Named("llvm.neon.vmaxu.v4i16") + definition: Named("llvm.arm.neon.vmaxu.v4i16") }, "max_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I32x2, &::I32x2]; &INPUTS }, output: &::I32x2, - definition: Named("llvm.neon.vmaxs.v2i32") + definition: Named("llvm.arm.neon.vmaxs.v2i32") }, "max_u32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U32x2, &::U32x2]; &INPUTS }, output: &::U32x2, - definition: Named("llvm.neon.vmaxu.v2i32") + definition: Named("llvm.arm.neon.vmaxu.v2i32") }, "max_f32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::F32x2, &::F32x2]; &INPUTS }, output: &::F32x2, - definition: Named("llvm.neon.vmaxf.v2f32") + definition: Named("llvm.arm.neon.vmaxf.v2f32") }, "maxq_s8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I8x16, &::I8x16]; &INPUTS }, output: &::I8x16, - definition: Named("llvm.neon.vmaxs.v16i8") + definition: Named("llvm.arm.neon.vmaxs.v16i8") }, "maxq_u8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U8x16, &::U8x16]; &INPUTS }, output: &::U8x16, - definition: Named("llvm.neon.vmaxu.v16i8") + definition: Named("llvm.arm.neon.vmaxu.v16i8") }, "maxq_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I16x8, &::I16x8]; &INPUTS }, output: &::I16x8, - definition: Named("llvm.neon.vmaxs.v8i16") + definition: Named("llvm.arm.neon.vmaxs.v8i16") }, "maxq_u16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U16x8, &::U16x8]; &INPUTS }, output: &::U16x8, - definition: Named("llvm.neon.vmaxu.v8i16") + definition: Named("llvm.arm.neon.vmaxu.v8i16") }, "maxq_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I32x4, &::I32x4]; &INPUTS }, output: &::I32x4, - definition: Named("llvm.neon.vmaxs.v4i32") + definition: Named("llvm.arm.neon.vmaxs.v4i32") }, "maxq_u32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U32x4, &::U32x4]; &INPUTS }, output: &::U32x4, - definition: Named("llvm.neon.vmaxu.v4i32") + definition: Named("llvm.arm.neon.vmaxu.v4i32") }, "maxq_f32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::F32x4, &::F32x4]; &INPUTS }, output: &::F32x4, - definition: Named("llvm.neon.vmaxf.v4f32") + definition: Named("llvm.arm.neon.vmaxf.v4f32") }, "min_s8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I8x8, &::I8x8]; &INPUTS }, output: &::I8x8, - definition: Named("llvm.neon.vmins.v8i8") + definition: Named("llvm.arm.neon.vmins.v8i8") }, "min_u8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U8x8, &::U8x8]; &INPUTS }, output: &::U8x8, - definition: Named("llvm.neon.vminu.v8i8") + definition: Named("llvm.arm.neon.vminu.v8i8") }, "min_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I16x4, &::I16x4]; &INPUTS }, output: &::I16x4, - definition: Named("llvm.neon.vmins.v4i16") + definition: Named("llvm.arm.neon.vmins.v4i16") }, "min_u16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U16x4, &::U16x4]; &INPUTS }, output: &::U16x4, - definition: Named("llvm.neon.vminu.v4i16") + definition: Named("llvm.arm.neon.vminu.v4i16") }, "min_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I32x2, &::I32x2]; &INPUTS }, output: &::I32x2, - definition: Named("llvm.neon.vmins.v2i32") + definition: Named("llvm.arm.neon.vmins.v2i32") }, "min_u32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U32x2, &::U32x2]; &INPUTS }, output: &::U32x2, - definition: Named("llvm.neon.vminu.v2i32") + definition: Named("llvm.arm.neon.vminu.v2i32") }, "min_f32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::F32x2, &::F32x2]; &INPUTS }, output: &::F32x2, - definition: Named("llvm.neon.vminf.v2f32") + definition: Named("llvm.arm.neon.vminf.v2f32") }, "minq_s8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I8x16, &::I8x16]; &INPUTS }, output: &::I8x16, - definition: Named("llvm.neon.vmins.v16i8") + definition: Named("llvm.arm.neon.vmins.v16i8") }, "minq_u8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U8x16, &::U8x16]; &INPUTS }, output: &::U8x16, - definition: Named("llvm.neon.vminu.v16i8") + definition: Named("llvm.arm.neon.vminu.v16i8") }, "minq_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I16x8, &::I16x8]; &INPUTS }, output: &::I16x8, - definition: Named("llvm.neon.vmins.v8i16") + definition: Named("llvm.arm.neon.vmins.v8i16") }, "minq_u16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U16x8, &::U16x8]; &INPUTS }, output: &::U16x8, - definition: Named("llvm.neon.vminu.v8i16") + definition: Named("llvm.arm.neon.vminu.v8i16") }, "minq_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I32x4, &::I32x4]; &INPUTS }, output: &::I32x4, - definition: Named("llvm.neon.vmins.v4i32") + definition: Named("llvm.arm.neon.vmins.v4i32") }, "minq_u32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U32x4, &::U32x4]; &INPUTS }, output: &::U32x4, - definition: Named("llvm.neon.vminu.v4i32") + definition: Named("llvm.arm.neon.vminu.v4i32") }, "minq_f32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::F32x4, &::F32x4]; &INPUTS }, output: &::F32x4, - definition: Named("llvm.neon.vminf.v4f32") + definition: Named("llvm.arm.neon.vminf.v4f32") }, "shl_s8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I8x8, &::I8x8]; &INPUTS }, output: &::I8x8, - definition: Named("llvm.neon.vshls.v8i8") + definition: Named("llvm.arm.neon.vshls.v8i8") }, "shl_u8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U8x8, &::I8x8]; &INPUTS }, output: &::U8x8, - definition: Named("llvm.neon.vshlu.v8i8") + definition: Named("llvm.arm.neon.vshlu.v8i8") }, "shl_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I16x4, &::I16x4]; &INPUTS }, output: &::I16x4, - definition: Named("llvm.neon.vshls.v4i16") + definition: Named("llvm.arm.neon.vshls.v4i16") }, "shl_u16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U16x4, &::I16x4]; &INPUTS }, output: &::U16x4, - definition: Named("llvm.neon.vshlu.v4i16") + definition: Named("llvm.arm.neon.vshlu.v4i16") }, "shl_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I32x2, &::I32x2]; &INPUTS }, output: &::I32x2, - definition: Named("llvm.neon.vshls.v2i32") + definition: Named("llvm.arm.neon.vshls.v2i32") }, "shl_u32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U32x2, &::I32x2]; &INPUTS }, output: &::U32x2, - definition: Named("llvm.neon.vshlu.v2i32") + definition: Named("llvm.arm.neon.vshlu.v2i32") }, "shl_s64" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I64x1, &::I64x1]; &INPUTS }, output: &::I64x1, - definition: Named("llvm.neon.vshls.v1i64") + definition: Named("llvm.arm.neon.vshls.v1i64") }, "shl_u64" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U64x1, &::I64x1]; &INPUTS }, output: &::U64x1, - definition: Named("llvm.neon.vshlu.v1i64") + definition: Named("llvm.arm.neon.vshlu.v1i64") }, "shlq_s8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I8x16, &::I8x16]; &INPUTS }, output: &::I8x16, - definition: Named("llvm.neon.vshls.v16i8") + definition: Named("llvm.arm.neon.vshls.v16i8") }, "shlq_u8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U8x16, &::I8x16]; &INPUTS }, output: &::U8x16, - definition: Named("llvm.neon.vshlu.v16i8") + definition: Named("llvm.arm.neon.vshlu.v16i8") }, "shlq_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I16x8, &::I16x8]; &INPUTS }, output: &::I16x8, - definition: Named("llvm.neon.vshls.v8i16") + definition: Named("llvm.arm.neon.vshls.v8i16") }, "shlq_u16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U16x8, &::I16x8]; &INPUTS }, output: &::U16x8, - definition: Named("llvm.neon.vshlu.v8i16") + definition: Named("llvm.arm.neon.vshlu.v8i16") }, "shlq_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I32x4, &::I32x4]; &INPUTS }, output: &::I32x4, - definition: Named("llvm.neon.vshls.v4i32") + definition: Named("llvm.arm.neon.vshls.v4i32") }, "shlq_u32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U32x4, &::I32x4]; &INPUTS }, output: &::U32x4, - definition: Named("llvm.neon.vshlu.v4i32") + definition: Named("llvm.arm.neon.vshlu.v4i32") }, "shlq_s64" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I64x2, &::I64x2]; &INPUTS }, output: &::I64x2, - definition: Named("llvm.neon.vshls.v2i64") + definition: Named("llvm.arm.neon.vshls.v2i64") }, "shlq_u64" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U64x2, &::I64x2]; &INPUTS }, output: &::U64x2, - definition: Named("llvm.neon.vshlu.v2i64") + definition: Named("llvm.arm.neon.vshlu.v2i64") }, "qshl_s8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I8x8, &::I8x8]; &INPUTS }, output: &::I8x8, - definition: Named("llvm.neon.vqshls.v8i8") + definition: Named("llvm.arm.neon.vqshls.v8i8") }, "qshl_u8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U8x8, &::I8x8]; &INPUTS }, output: &::U8x8, - definition: Named("llvm.neon.vqshlu.v8i8") + definition: Named("llvm.arm.neon.vqshlu.v8i8") }, "qshl_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I16x4, &::I16x4]; &INPUTS }, output: &::I16x4, - definition: Named("llvm.neon.vqshls.v4i16") + definition: Named("llvm.arm.neon.vqshls.v4i16") }, "qshl_u16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U16x4, &::I16x4]; &INPUTS }, output: &::U16x4, - definition: Named("llvm.neon.vqshlu.v4i16") + definition: Named("llvm.arm.neon.vqshlu.v4i16") }, "qshl_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I32x2, &::I32x2]; &INPUTS }, output: &::I32x2, - definition: Named("llvm.neon.vqshls.v2i32") + definition: Named("llvm.arm.neon.vqshls.v2i32") }, "qshl_u32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U32x2, &::I32x2]; &INPUTS }, output: &::U32x2, - definition: Named("llvm.neon.vqshlu.v2i32") + definition: Named("llvm.arm.neon.vqshlu.v2i32") }, "qshl_s64" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I64x1, &::I64x1]; &INPUTS }, output: &::I64x1, - definition: Named("llvm.neon.vqshls.v1i64") + definition: Named("llvm.arm.neon.vqshls.v1i64") }, "qshl_u64" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U64x1, &::I64x1]; &INPUTS }, output: &::U64x1, - definition: Named("llvm.neon.vqshlu.v1i64") + definition: Named("llvm.arm.neon.vqshlu.v1i64") }, "qshlq_s8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I8x16, &::I8x16]; &INPUTS }, output: &::I8x16, - definition: Named("llvm.neon.vqshls.v16i8") + definition: Named("llvm.arm.neon.vqshls.v16i8") }, "qshlq_u8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U8x16, &::I8x16]; &INPUTS }, output: &::U8x16, - definition: Named("llvm.neon.vqshlu.v16i8") + definition: Named("llvm.arm.neon.vqshlu.v16i8") }, "qshlq_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I16x8, &::I16x8]; &INPUTS }, output: &::I16x8, - definition: Named("llvm.neon.vqshls.v8i16") + definition: Named("llvm.arm.neon.vqshls.v8i16") }, "qshlq_u16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U16x8, &::I16x8]; &INPUTS }, output: &::U16x8, - definition: Named("llvm.neon.vqshlu.v8i16") + definition: Named("llvm.arm.neon.vqshlu.v8i16") }, "qshlq_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I32x4, &::I32x4]; &INPUTS }, output: &::I32x4, - definition: Named("llvm.neon.vqshls.v4i32") + definition: Named("llvm.arm.neon.vqshls.v4i32") }, "qshlq_u32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U32x4, &::I32x4]; &INPUTS }, output: &::U32x4, - definition: Named("llvm.neon.vqshlu.v4i32") + definition: Named("llvm.arm.neon.vqshlu.v4i32") }, "qshlq_s64" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I64x2, &::I64x2]; &INPUTS }, output: &::I64x2, - definition: Named("llvm.neon.vqshls.v2i64") + definition: Named("llvm.arm.neon.vqshls.v2i64") }, "qshlq_u64" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U64x2, &::I64x2]; &INPUTS }, output: &::U64x2, - definition: Named("llvm.neon.vqshlu.v2i64") + definition: Named("llvm.arm.neon.vqshlu.v2i64") }, "rshl_s8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I8x8, &::I8x8]; &INPUTS }, output: &::I8x8, - definition: Named("llvm.neon.vrshls.v8i8") + definition: Named("llvm.arm.neon.vrshls.v8i8") }, "rshl_u8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U8x8, &::I8x8]; &INPUTS }, output: &::U8x8, - definition: Named("llvm.neon.vrshlu.v8i8") + definition: Named("llvm.arm.neon.vrshlu.v8i8") }, "rshl_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I16x4, &::I16x4]; &INPUTS }, output: &::I16x4, - definition: Named("llvm.neon.vrshls.v4i16") + definition: Named("llvm.arm.neon.vrshls.v4i16") }, "rshl_u16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U16x4, &::I16x4]; &INPUTS }, output: &::U16x4, - definition: Named("llvm.neon.vrshlu.v4i16") + definition: Named("llvm.arm.neon.vrshlu.v4i16") }, "rshl_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I32x2, &::I32x2]; &INPUTS }, output: &::I32x2, - definition: Named("llvm.neon.vrshls.v2i32") + definition: Named("llvm.arm.neon.vrshls.v2i32") }, "rshl_u32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U32x2, &::I32x2]; &INPUTS }, output: &::U32x2, - definition: Named("llvm.neon.vrshlu.v2i32") + definition: Named("llvm.arm.neon.vrshlu.v2i32") }, "rshl_s64" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I64x1, &::I64x1]; &INPUTS }, output: &::I64x1, - definition: Named("llvm.neon.vrshls.v1i64") + definition: Named("llvm.arm.neon.vrshls.v1i64") }, "rshl_u64" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U64x1, &::I64x1]; &INPUTS }, output: &::U64x1, - definition: Named("llvm.neon.vrshlu.v1i64") + definition: Named("llvm.arm.neon.vrshlu.v1i64") }, "rshlq_s8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I8x16, &::I8x16]; &INPUTS }, output: &::I8x16, - definition: Named("llvm.neon.vrshls.v16i8") + definition: Named("llvm.arm.neon.vrshls.v16i8") }, "rshlq_u8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U8x16, &::I8x16]; &INPUTS }, output: &::U8x16, - definition: Named("llvm.neon.vrshlu.v16i8") + definition: Named("llvm.arm.neon.vrshlu.v16i8") }, "rshlq_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I16x8, &::I16x8]; &INPUTS }, output: &::I16x8, - definition: Named("llvm.neon.vrshls.v8i16") + definition: Named("llvm.arm.neon.vrshls.v8i16") }, "rshlq_u16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U16x8, &::I16x8]; &INPUTS }, output: &::U16x8, - definition: Named("llvm.neon.vrshlu.v8i16") + definition: Named("llvm.arm.neon.vrshlu.v8i16") }, "rshlq_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I32x4, &::I32x4]; &INPUTS }, output: &::I32x4, - definition: Named("llvm.neon.vrshls.v4i32") + definition: Named("llvm.arm.neon.vrshls.v4i32") }, "rshlq_u32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U32x4, &::I32x4]; &INPUTS }, output: &::U32x4, - definition: Named("llvm.neon.vrshlu.v4i32") + definition: Named("llvm.arm.neon.vrshlu.v4i32") }, "rshlq_s64" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I64x2, &::I64x2]; &INPUTS }, output: &::I64x2, - definition: Named("llvm.neon.vrshls.v2i64") + definition: Named("llvm.arm.neon.vrshls.v2i64") }, "rshlq_u64" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U64x2, &::I64x2]; &INPUTS }, output: &::U64x2, - definition: Named("llvm.neon.vrshlu.v2i64") + definition: Named("llvm.arm.neon.vrshlu.v2i64") }, "qrshl_s8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I8x8, &::I8x8]; &INPUTS }, output: &::I8x8, - definition: Named("llvm.neon.vqrshls.v8i8") + definition: Named("llvm.arm.neon.vqrshls.v8i8") }, "qrshl_u8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U8x8, &::I8x8]; &INPUTS }, output: &::U8x8, - definition: Named("llvm.neon.vqrshlu.v8i8") + definition: Named("llvm.arm.neon.vqrshlu.v8i8") }, "qrshl_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I16x4, &::I16x4]; &INPUTS }, output: &::I16x4, - definition: Named("llvm.neon.vqrshls.v4i16") + definition: Named("llvm.arm.neon.vqrshls.v4i16") }, "qrshl_u16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U16x4, &::I16x4]; &INPUTS }, output: &::U16x4, - definition: Named("llvm.neon.vqrshlu.v4i16") + definition: Named("llvm.arm.neon.vqrshlu.v4i16") }, "qrshl_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I32x2, &::I32x2]; &INPUTS }, output: &::I32x2, - definition: Named("llvm.neon.vqrshls.v2i32") + definition: Named("llvm.arm.neon.vqrshls.v2i32") }, "qrshl_u32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U32x2, &::I32x2]; &INPUTS }, output: &::U32x2, - definition: Named("llvm.neon.vqrshlu.v2i32") + definition: Named("llvm.arm.neon.vqrshlu.v2i32") }, "qrshl_s64" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I64x1, &::I64x1]; &INPUTS }, output: &::I64x1, - definition: Named("llvm.neon.vqrshls.v1i64") + definition: Named("llvm.arm.neon.vqrshls.v1i64") }, "qrshl_u64" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U64x1, &::I64x1]; &INPUTS }, output: &::U64x1, - definition: Named("llvm.neon.vqrshlu.v1i64") + definition: Named("llvm.arm.neon.vqrshlu.v1i64") }, "qrshlq_s8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I8x16, &::I8x16]; &INPUTS }, output: &::I8x16, - definition: Named("llvm.neon.vqrshls.v16i8") + definition: Named("llvm.arm.neon.vqrshls.v16i8") }, "qrshlq_u8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U8x16, &::I8x16]; &INPUTS }, output: &::U8x16, - definition: Named("llvm.neon.vqrshlu.v16i8") + definition: Named("llvm.arm.neon.vqrshlu.v16i8") }, "qrshlq_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I16x8, &::I16x8]; &INPUTS }, output: &::I16x8, - definition: Named("llvm.neon.vqrshls.v8i16") + definition: Named("llvm.arm.neon.vqrshls.v8i16") }, "qrshlq_u16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U16x8, &::I16x8]; &INPUTS }, output: &::U16x8, - definition: Named("llvm.neon.vqrshlu.v8i16") + definition: Named("llvm.arm.neon.vqrshlu.v8i16") }, "qrshlq_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I32x4, &::I32x4]; &INPUTS }, output: &::I32x4, - definition: Named("llvm.neon.vqrshls.v4i32") + definition: Named("llvm.arm.neon.vqrshls.v4i32") }, "qrshlq_u32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U32x4, &::I32x4]; &INPUTS }, output: &::U32x4, - definition: Named("llvm.neon.vqrshlu.v4i32") + definition: Named("llvm.arm.neon.vqrshlu.v4i32") }, "qrshlq_s64" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I64x2, &::I64x2]; &INPUTS }, output: &::I64x2, - definition: Named("llvm.neon.vqrshls.v2i64") + definition: Named("llvm.arm.neon.vqrshls.v2i64") }, "qrshlq_u64" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U64x2, &::I64x2]; &INPUTS }, output: &::U64x2, - definition: Named("llvm.neon.vqrshlu.v2i64") + definition: Named("llvm.arm.neon.vqrshlu.v2i64") }, "qshrun_n_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I16x8, &::U32]; &INPUTS }, output: &::I8x8, - definition: Named("llvm.neon.vsqshrun.v8i8") + definition: Named("llvm.arm.neon.vsqshrun.v8i8") }, "qshrun_n_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I32x4, &::U32]; &INPUTS }, output: &::I16x4, - definition: Named("llvm.neon.vsqshrun.v4i16") + definition: Named("llvm.arm.neon.vsqshrun.v4i16") }, "qshrun_n_s64" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I64x2, &::U32]; &INPUTS }, output: &::I32x2, - definition: Named("llvm.neon.vsqshrun.v2i32") + definition: Named("llvm.arm.neon.vsqshrun.v2i32") }, "qrshrun_n_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I16x8, &::U32]; &INPUTS }, output: &::I8x8, - definition: Named("llvm.neon.vsqrshrun.v8i8") + definition: Named("llvm.arm.neon.vsqrshrun.v8i8") }, "qrshrun_n_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I32x4, &::U32]; &INPUTS }, output: &::I16x4, - definition: Named("llvm.neon.vsqrshrun.v4i16") + definition: Named("llvm.arm.neon.vsqrshrun.v4i16") }, "qrshrun_n_s64" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I64x2, &::U32]; &INPUTS }, output: &::I32x2, - definition: Named("llvm.neon.vsqrshrun.v2i32") + definition: Named("llvm.arm.neon.vsqrshrun.v2i32") }, "qshrn_n_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I16x8, &::U32]; &INPUTS }, output: &::I8x8, - definition: Named("llvm.neon.vqshrns.v8i8") + definition: Named("llvm.arm.neon.vqshrns.v8i8") }, "qshrn_n_u16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U16x8, &::U32]; &INPUTS }, output: &::U8x8, - definition: Named("llvm.neon.vqshrnu.v8i8") + definition: Named("llvm.arm.neon.vqshrnu.v8i8") }, "qshrn_n_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I32x4, &::U32]; &INPUTS }, output: &::I16x4, - definition: Named("llvm.neon.vqshrns.v4i16") + definition: Named("llvm.arm.neon.vqshrns.v4i16") }, "qshrn_n_u32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U32x4, &::U32]; &INPUTS }, output: &::U16x4, - definition: Named("llvm.neon.vqshrnu.v4i16") + definition: Named("llvm.arm.neon.vqshrnu.v4i16") }, "qshrn_n_s64" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I64x2, &::U32]; &INPUTS }, output: &::I32x2, - definition: Named("llvm.neon.vqshrns.v2i32") + definition: Named("llvm.arm.neon.vqshrns.v2i32") }, "qshrn_n_u64" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U64x2, &::U32]; &INPUTS }, output: &::U32x2, - definition: Named("llvm.neon.vqshrnu.v2i32") + definition: Named("llvm.arm.neon.vqshrnu.v2i32") }, "rshrn_n_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I16x8, &::U32]; &INPUTS }, output: &::I8x8, - definition: Named("llvm.neon.vrshrn.v8i8") + definition: Named("llvm.arm.neon.vrshrn.v8i8") }, "rshrn_n_u16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U16x8, &::U32]; &INPUTS }, output: &::U8x8, - definition: Named("llvm.neon.vrshrn.v8i8") + definition: Named("llvm.arm.neon.vrshrn.v8i8") }, "rshrn_n_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I32x4, &::U32]; &INPUTS }, output: &::I16x4, - definition: Named("llvm.neon.vrshrn.v4i16") + definition: Named("llvm.arm.neon.vrshrn.v4i16") }, "rshrn_n_u32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U32x4, &::U32]; &INPUTS }, output: &::U16x4, - definition: Named("llvm.neon.vrshrn.v4i16") + definition: Named("llvm.arm.neon.vrshrn.v4i16") }, "rshrn_n_s64" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I64x2, &::U32]; &INPUTS }, output: &::I32x2, - definition: Named("llvm.neon.vrshrn.v2i32") + definition: Named("llvm.arm.neon.vrshrn.v2i32") }, "rshrn_n_u64" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U64x2, &::U32]; &INPUTS }, output: &::U32x2, - definition: Named("llvm.neon.vrshrn.v2i32") + definition: Named("llvm.arm.neon.vrshrn.v2i32") }, "qrshrn_n_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I16x8, &::U32]; &INPUTS }, output: &::I8x8, - definition: Named("llvm.neon.vqrshrns.v8i8") + definition: Named("llvm.arm.neon.vqrshrns.v8i8") }, "qrshrn_n_u16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U16x8, &::U32]; &INPUTS }, output: &::U8x8, - definition: Named("llvm.neon.vqrshrnu.v8i8") + definition: Named("llvm.arm.neon.vqrshrnu.v8i8") }, "qrshrn_n_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I32x4, &::U32]; &INPUTS }, output: &::I16x4, - definition: Named("llvm.neon.vqrshrns.v4i16") + definition: Named("llvm.arm.neon.vqrshrns.v4i16") }, "qrshrn_n_u32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U32x4, &::U32]; &INPUTS }, output: &::U16x4, - definition: Named("llvm.neon.vqrshrnu.v4i16") + definition: Named("llvm.arm.neon.vqrshrnu.v4i16") }, "qrshrn_n_s64" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I64x2, &::U32]; &INPUTS }, output: &::I32x2, - definition: Named("llvm.neon.vqrshrns.v2i32") + definition: Named("llvm.arm.neon.vqrshrns.v2i32") }, "qrshrn_n_u64" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U64x2, &::U32]; &INPUTS }, output: &::U32x2, - definition: Named("llvm.neon.vqrshrnu.v2i32") + definition: Named("llvm.arm.neon.vqrshrnu.v2i32") }, "sri_s8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I8x8, &::I8x8]; &INPUTS }, output: &::I8x8, - definition: Named("llvm.neon.vvsri.v8i8") + definition: Named("llvm.arm.neon.vvsri.v8i8") }, "sri_u8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U8x8, &::U8x8]; &INPUTS }, output: &::U8x8, - definition: Named("llvm.neon.vvsri.v8i8") + definition: Named("llvm.arm.neon.vvsri.v8i8") }, "sri_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I16x4, &::I16x4]; &INPUTS }, output: &::I16x4, - definition: Named("llvm.neon.vvsri.v4i16") + definition: Named("llvm.arm.neon.vvsri.v4i16") }, "sri_u16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U16x4, &::U16x4]; &INPUTS }, output: &::U16x4, - definition: Named("llvm.neon.vvsri.v4i16") + definition: Named("llvm.arm.neon.vvsri.v4i16") }, "sri_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I32x2, &::I32x2]; &INPUTS }, output: &::I32x2, - definition: Named("llvm.neon.vvsri.v2i32") + definition: Named("llvm.arm.neon.vvsri.v2i32") }, "sri_u32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U32x2, &::U32x2]; &INPUTS }, output: &::U32x2, - definition: Named("llvm.neon.vvsri.v2i32") + definition: Named("llvm.arm.neon.vvsri.v2i32") }, "sri_s64" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I64x1, &::I64x1]; &INPUTS }, output: &::I64x1, - definition: Named("llvm.neon.vvsri.v1i64") + definition: Named("llvm.arm.neon.vvsri.v1i64") }, "sri_u64" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U64x1, &::U64x1]; &INPUTS }, output: &::U64x1, - definition: Named("llvm.neon.vvsri.v1i64") + definition: Named("llvm.arm.neon.vvsri.v1i64") }, "sriq_s8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I8x16, &::I8x16]; &INPUTS }, output: &::I8x16, - definition: Named("llvm.neon.vvsri.v16i8") + definition: Named("llvm.arm.neon.vvsri.v16i8") }, "sriq_u8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U8x16, &::U8x16]; &INPUTS }, output: &::U8x16, - definition: Named("llvm.neon.vvsri.v16i8") + definition: Named("llvm.arm.neon.vvsri.v16i8") }, "sriq_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I16x8, &::I16x8]; &INPUTS }, output: &::I16x8, - definition: Named("llvm.neon.vvsri.v8i16") + definition: Named("llvm.arm.neon.vvsri.v8i16") }, "sriq_u16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U16x8, &::U16x8]; &INPUTS }, output: &::U16x8, - definition: Named("llvm.neon.vvsri.v8i16") + definition: Named("llvm.arm.neon.vvsri.v8i16") }, "sriq_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I32x4, &::I32x4]; &INPUTS }, output: &::I32x4, - definition: Named("llvm.neon.vvsri.v4i32") + definition: Named("llvm.arm.neon.vvsri.v4i32") }, "sriq_u32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U32x4, &::U32x4]; &INPUTS }, output: &::U32x4, - definition: Named("llvm.neon.vvsri.v4i32") + definition: Named("llvm.arm.neon.vvsri.v4i32") }, "sriq_s64" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I64x2, &::I64x2]; &INPUTS }, output: &::I64x2, - definition: Named("llvm.neon.vvsri.v2i64") + definition: Named("llvm.arm.neon.vvsri.v2i64") }, "sriq_u64" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U64x2, &::U64x2]; &INPUTS }, output: &::U64x2, - definition: Named("llvm.neon.vvsri.v2i64") + definition: Named("llvm.arm.neon.vvsri.v2i64") }, "sli_s8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I8x8, &::I8x8]; &INPUTS }, output: &::I8x8, - definition: Named("llvm.neon.vvsli.v8i8") + definition: Named("llvm.arm.neon.vvsli.v8i8") }, "sli_u8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U8x8, &::U8x8]; &INPUTS }, output: &::U8x8, - definition: Named("llvm.neon.vvsli.v8i8") + definition: Named("llvm.arm.neon.vvsli.v8i8") }, "sli_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I16x4, &::I16x4]; &INPUTS }, output: &::I16x4, - definition: Named("llvm.neon.vvsli.v4i16") + definition: Named("llvm.arm.neon.vvsli.v4i16") }, "sli_u16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U16x4, &::U16x4]; &INPUTS }, output: &::U16x4, - definition: Named("llvm.neon.vvsli.v4i16") + definition: Named("llvm.arm.neon.vvsli.v4i16") }, "sli_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I32x2, &::I32x2]; &INPUTS }, output: &::I32x2, - definition: Named("llvm.neon.vvsli.v2i32") + definition: Named("llvm.arm.neon.vvsli.v2i32") }, "sli_u32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U32x2, &::U32x2]; &INPUTS }, output: &::U32x2, - definition: Named("llvm.neon.vvsli.v2i32") + definition: Named("llvm.arm.neon.vvsli.v2i32") }, "sli_s64" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I64x1, &::I64x1]; &INPUTS }, output: &::I64x1, - definition: Named("llvm.neon.vvsli.v1i64") + definition: Named("llvm.arm.neon.vvsli.v1i64") }, "sli_u64" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U64x1, &::U64x1]; &INPUTS }, output: &::U64x1, - definition: Named("llvm.neon.vvsli.v1i64") + definition: Named("llvm.arm.neon.vvsli.v1i64") }, "sliq_s8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I8x16, &::I8x16]; &INPUTS }, output: &::I8x16, - definition: Named("llvm.neon.vvsli.v16i8") + definition: Named("llvm.arm.neon.vvsli.v16i8") }, "sliq_u8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U8x16, &::U8x16]; &INPUTS }, output: &::U8x16, - definition: Named("llvm.neon.vvsli.v16i8") + definition: Named("llvm.arm.neon.vvsli.v16i8") }, "sliq_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I16x8, &::I16x8]; &INPUTS }, output: &::I16x8, - definition: Named("llvm.neon.vvsli.v8i16") + definition: Named("llvm.arm.neon.vvsli.v8i16") }, "sliq_u16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U16x8, &::U16x8]; &INPUTS }, output: &::U16x8, - definition: Named("llvm.neon.vvsli.v8i16") + definition: Named("llvm.arm.neon.vvsli.v8i16") }, "sliq_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I32x4, &::I32x4]; &INPUTS }, output: &::I32x4, - definition: Named("llvm.neon.vvsli.v4i32") + definition: Named("llvm.arm.neon.vvsli.v4i32") }, "sliq_u32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U32x4, &::U32x4]; &INPUTS }, output: &::U32x4, - definition: Named("llvm.neon.vvsli.v4i32") + definition: Named("llvm.arm.neon.vvsli.v4i32") }, "sliq_s64" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I64x2, &::I64x2]; &INPUTS }, output: &::I64x2, - definition: Named("llvm.neon.vvsli.v2i64") + definition: Named("llvm.arm.neon.vvsli.v2i64") }, "sliq_u64" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U64x2, &::U64x2]; &INPUTS }, output: &::U64x2, - definition: Named("llvm.neon.vvsli.v2i64") + definition: Named("llvm.arm.neon.vvsli.v2i64") }, "vqmovn_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::I16x8]; &INPUTS }, output: &::I8x8, - definition: Named("llvm.neon.vqxtns.v8i8") + definition: Named("llvm.arm.neon.vqxtns.v8i8") }, "vqmovn_u16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::U16x8]; &INPUTS }, output: &::U8x8, - definition: Named("llvm.neon.vqxtnu.v8i8") + definition: Named("llvm.arm.neon.vqxtnu.v8i8") }, "vqmovn_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::I32x4]; &INPUTS }, output: &::I16x4, - definition: Named("llvm.neon.vqxtns.v4i16") + definition: Named("llvm.arm.neon.vqxtns.v4i16") }, "vqmovn_u32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::U32x4]; &INPUTS }, output: &::U16x4, - definition: Named("llvm.neon.vqxtnu.v4i16") + definition: Named("llvm.arm.neon.vqxtnu.v4i16") }, "vqmovn_s64" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::I64x2]; &INPUTS }, output: &::I32x2, - definition: Named("llvm.neon.vqxtns.v2i32") + definition: Named("llvm.arm.neon.vqxtns.v2i32") }, "vqmovn_u64" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::U64x2]; &INPUTS }, output: &::U32x2, - definition: Named("llvm.neon.vqxtnu.v2i32") + definition: Named("llvm.arm.neon.vqxtnu.v2i32") }, "abs_s8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::I8x8]; &INPUTS }, output: &::I8x8, - definition: Named("llvm.neon.vabs.v8i8") + definition: Named("llvm.arm.neon.vabs.v8i8") }, "abs_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::I16x4]; &INPUTS }, output: &::I16x4, - definition: Named("llvm.neon.vabs.v4i16") + definition: Named("llvm.arm.neon.vabs.v4i16") }, "abs_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::I32x2]; &INPUTS }, output: &::I32x2, - definition: Named("llvm.neon.vabs.v2i32") + definition: Named("llvm.arm.neon.vabs.v2i32") }, "absq_s8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::I8x16]; &INPUTS }, output: &::I8x16, - definition: Named("llvm.neon.vabs.v16i8") + definition: Named("llvm.arm.neon.vabs.v16i8") }, "absq_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::I16x8]; &INPUTS }, output: &::I16x8, - definition: Named("llvm.neon.vabs.v8i16") + definition: Named("llvm.arm.neon.vabs.v8i16") }, "absq_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::I32x4]; &INPUTS }, output: &::I32x4, - definition: Named("llvm.neon.vabs.v4i32") + definition: Named("llvm.arm.neon.vabs.v4i32") }, "abs_f32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::F32x2]; &INPUTS }, @@ -1395,62 +1395,62 @@ pub fn find(name: &str) -> Option { "qabs_s8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::I8x8]; &INPUTS }, output: &::I8x8, - definition: Named("llvm.neon.vsqabs.v8i8") + definition: Named("llvm.arm.neon.vsqabs.v8i8") }, "qabs_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::I16x4]; &INPUTS }, output: &::I16x4, - definition: Named("llvm.neon.vsqabs.v4i16") + definition: Named("llvm.arm.neon.vsqabs.v4i16") }, "qabs_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::I32x2]; &INPUTS }, output: &::I32x2, - definition: Named("llvm.neon.vsqabs.v2i32") + definition: Named("llvm.arm.neon.vsqabs.v2i32") }, "qabsq_s8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::I8x16]; &INPUTS }, output: &::I8x16, - definition: Named("llvm.neon.vsqabs.v16i8") + definition: Named("llvm.arm.neon.vsqabs.v16i8") }, "qabsq_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::I16x8]; &INPUTS }, output: &::I16x8, - definition: Named("llvm.neon.vsqabs.v8i16") + definition: Named("llvm.arm.neon.vsqabs.v8i16") }, "qabsq_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::I32x4]; &INPUTS }, output: &::I32x4, - definition: Named("llvm.neon.vsqabs.v4i32") + definition: Named("llvm.arm.neon.vsqabs.v4i32") }, "qneg_s8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::I8x8]; &INPUTS }, output: &::I8x8, - definition: Named("llvm.neon.vsqneg.v8i8") + definition: Named("llvm.arm.neon.vsqneg.v8i8") }, "qneg_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::I16x4]; &INPUTS }, output: &::I16x4, - definition: Named("llvm.neon.vsqneg.v4i16") + definition: Named("llvm.arm.neon.vsqneg.v4i16") }, "qneg_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::I32x2]; &INPUTS }, output: &::I32x2, - definition: Named("llvm.neon.vsqneg.v2i32") + definition: Named("llvm.arm.neon.vsqneg.v2i32") }, "qnegq_s8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::I8x16]; &INPUTS }, output: &::I8x16, - definition: Named("llvm.neon.vsqneg.v16i8") + definition: Named("llvm.arm.neon.vsqneg.v16i8") }, "qnegq_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::I16x8]; &INPUTS }, output: &::I16x8, - definition: Named("llvm.neon.vsqneg.v8i16") + definition: Named("llvm.arm.neon.vsqneg.v8i16") }, "qnegq_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::I32x4]; &INPUTS }, output: &::I32x4, - definition: Named("llvm.neon.vsqneg.v4i32") + definition: Named("llvm.arm.neon.vsqneg.v4i32") }, "clz_s8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::I8x8]; &INPUTS }, @@ -1515,62 +1515,62 @@ pub fn find(name: &str) -> Option { "cls_s8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::I8x8]; &INPUTS }, output: &::I8x8, - definition: Named("llvm.neon.vcls.v8i8") + definition: Named("llvm.arm.neon.vcls.v8i8") }, "cls_u8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::U8x8]; &INPUTS }, output: &::U8x8, - definition: Named("llvm.neon.vcls.v8i8") + definition: Named("llvm.arm.neon.vcls.v8i8") }, "cls_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::I16x4]; &INPUTS }, output: &::I16x4, - definition: Named("llvm.neon.vcls.v4i16") + definition: Named("llvm.arm.neon.vcls.v4i16") }, "cls_u16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::U16x4]; &INPUTS }, output: &::U16x4, - definition: Named("llvm.neon.vcls.v4i16") + definition: Named("llvm.arm.neon.vcls.v4i16") }, "cls_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::I32x2]; &INPUTS }, output: &::I32x2, - definition: Named("llvm.neon.vcls.v2i32") + definition: Named("llvm.arm.neon.vcls.v2i32") }, "cls_u32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::U32x2]; &INPUTS }, output: &::U32x2, - definition: Named("llvm.neon.vcls.v2i32") + definition: Named("llvm.arm.neon.vcls.v2i32") }, "clsq_s8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::I8x16]; &INPUTS }, output: &::I8x16, - definition: Named("llvm.neon.vcls.v16i8") + definition: Named("llvm.arm.neon.vcls.v16i8") }, "clsq_u8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::U8x16]; &INPUTS }, output: &::U8x16, - definition: Named("llvm.neon.vcls.v16i8") + definition: Named("llvm.arm.neon.vcls.v16i8") }, "clsq_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::I16x8]; &INPUTS }, output: &::I16x8, - definition: Named("llvm.neon.vcls.v8i16") + definition: Named("llvm.arm.neon.vcls.v8i16") }, "clsq_u16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::U16x8]; &INPUTS }, output: &::U16x8, - definition: Named("llvm.neon.vcls.v8i16") + definition: Named("llvm.arm.neon.vcls.v8i16") }, "clsq_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::I32x4]; &INPUTS }, output: &::I32x4, - definition: Named("llvm.neon.vcls.v4i32") + definition: Named("llvm.arm.neon.vcls.v4i32") }, "clsq_u32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::U32x4]; &INPUTS }, output: &::U32x4, - definition: Named("llvm.neon.vcls.v4i32") + definition: Named("llvm.arm.neon.vcls.v4i32") }, "cnt_s8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::I8x8]; &INPUTS }, @@ -1595,32 +1595,32 @@ pub fn find(name: &str) -> Option { "recpe_u32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::U32x2]; &INPUTS }, output: &::U32x2, - definition: Named("llvm.neon.vrecpe.v2i32") + definition: Named("llvm.arm.neon.vrecpe.v2i32") }, "recpe_f32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::F32x2]; &INPUTS }, output: &::F32x2, - definition: Named("llvm.neon.vrecpe.v2f32") + definition: Named("llvm.arm.neon.vrecpe.v2f32") }, "recpeq_u32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::U32x4]; &INPUTS }, output: &::U32x4, - definition: Named("llvm.neon.vrecpe.v4i32") + definition: Named("llvm.arm.neon.vrecpe.v4i32") }, "recpeq_f32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::F32x4]; &INPUTS }, output: &::F32x4, - definition: Named("llvm.neon.vrecpe.v4f32") + definition: Named("llvm.arm.neon.vrecpe.v4f32") }, "recps_f32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::F32x2, &::F32x2]; &INPUTS }, output: &::F32x2, - definition: Named("llvm.neon.vfrecps.v2f32") + definition: Named("llvm.arm.neon.vfrecps.v2f32") }, "recpsq_f32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::F32x4, &::F32x4]; &INPUTS }, output: &::F32x4, - definition: Named("llvm.neon.vfrecps.v4f32") + definition: Named("llvm.arm.neon.vfrecps.v4f32") }, "sqrt_f32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::F32x2]; &INPUTS }, @@ -1635,452 +1635,452 @@ pub fn find(name: &str) -> Option { "rsqrte_u32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::U32x2]; &INPUTS }, output: &::U32x2, - definition: Named("llvm.neon.vrsqrte.v2i32") + definition: Named("llvm.arm.neon.vrsqrte.v2i32") }, "rsqrte_f32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::F32x2]; &INPUTS }, output: &::F32x2, - definition: Named("llvm.neon.vrsqrte.v2f32") + definition: Named("llvm.arm.neon.vrsqrte.v2f32") }, "rsqrteq_u32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::U32x4]; &INPUTS }, output: &::U32x4, - definition: Named("llvm.neon.vrsqrte.v4i32") + definition: Named("llvm.arm.neon.vrsqrte.v4i32") }, "rsqrteq_f32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::F32x4]; &INPUTS }, output: &::F32x4, - definition: Named("llvm.neon.vrsqrte.v4f32") + definition: Named("llvm.arm.neon.vrsqrte.v4f32") }, "rsqrts_f32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::F32x2, &::F32x2]; &INPUTS }, output: &::F32x2, - definition: Named("llvm.neon.vrsqrts.v2f32") + definition: Named("llvm.arm.neon.vrsqrts.v2f32") }, "rsqrtsq_f32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::F32x4, &::F32x4]; &INPUTS }, output: &::F32x4, - definition: Named("llvm.neon.vrsqrts.v4f32") + definition: Named("llvm.arm.neon.vrsqrts.v4f32") }, "bsl_s8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U8x8, &::I8x8]; &INPUTS }, output: &::I8x8, - definition: Named("llvm.neon.vbsl.v8i8") + definition: Named("llvm.arm.neon.vbsl.v8i8") }, "bsl_u8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U8x8, &::U8x8]; &INPUTS }, output: &::U8x8, - definition: Named("llvm.neon.vbsl.v8i8") + definition: Named("llvm.arm.neon.vbsl.v8i8") }, "bsl_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U16x4, &::I16x4]; &INPUTS }, output: &::I16x4, - definition: Named("llvm.neon.vbsl.v4i16") + definition: Named("llvm.arm.neon.vbsl.v4i16") }, "bsl_u16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U16x4, &::U16x4]; &INPUTS }, output: &::U16x4, - definition: Named("llvm.neon.vbsl.v4i16") + definition: Named("llvm.arm.neon.vbsl.v4i16") }, "bsl_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U32x2, &::I32x2]; &INPUTS }, output: &::I32x2, - definition: Named("llvm.neon.vbsl.v2i32") + definition: Named("llvm.arm.neon.vbsl.v2i32") }, "bsl_u32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U32x2, &::U32x2]; &INPUTS }, output: &::U32x2, - definition: Named("llvm.neon.vbsl.v2i32") + definition: Named("llvm.arm.neon.vbsl.v2i32") }, "bsl_s64" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U64x1, &::I64x1]; &INPUTS }, output: &::I64x1, - definition: Named("llvm.neon.vbsl.v1i64") + definition: Named("llvm.arm.neon.vbsl.v1i64") }, "bsl_u64" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U64x1, &::U64x1]; &INPUTS }, output: &::U64x1, - definition: Named("llvm.neon.vbsl.v1i64") + definition: Named("llvm.arm.neon.vbsl.v1i64") }, "bslq_s8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U8x16, &::I8x16]; &INPUTS }, output: &::I8x16, - definition: Named("llvm.neon.vbsl.v16i8") + definition: Named("llvm.arm.neon.vbsl.v16i8") }, "bslq_u8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U8x16, &::U8x16]; &INPUTS }, output: &::U8x16, - definition: Named("llvm.neon.vbsl.v16i8") + definition: Named("llvm.arm.neon.vbsl.v16i8") }, "bslq_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U16x8, &::I16x8]; &INPUTS }, output: &::I16x8, - definition: Named("llvm.neon.vbsl.v8i16") + definition: Named("llvm.arm.neon.vbsl.v8i16") }, "bslq_u16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U16x8, &::U16x8]; &INPUTS }, output: &::U16x8, - definition: Named("llvm.neon.vbsl.v8i16") + definition: Named("llvm.arm.neon.vbsl.v8i16") }, "bslq_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U32x4, &::I32x4]; &INPUTS }, output: &::I32x4, - definition: Named("llvm.neon.vbsl.v4i32") + definition: Named("llvm.arm.neon.vbsl.v4i32") }, "bslq_u32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U32x4, &::U32x4]; &INPUTS }, output: &::U32x4, - definition: Named("llvm.neon.vbsl.v4i32") + definition: Named("llvm.arm.neon.vbsl.v4i32") }, "bslq_s64" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U64x2, &::I64x2]; &INPUTS }, output: &::I64x2, - definition: Named("llvm.neon.vbsl.v2i64") + definition: Named("llvm.arm.neon.vbsl.v2i64") }, "bslq_u64" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U64x2, &::U64x2]; &INPUTS }, output: &::U64x2, - definition: Named("llvm.neon.vbsl.v2i64") + definition: Named("llvm.arm.neon.vbsl.v2i64") }, "padd_s8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I8x8, &::I8x8]; &INPUTS }, output: &::I8x8, - definition: Named("llvm.neon.vpadd.v8i8") + definition: Named("llvm.arm.neon.vpadd.v8i8") }, "padd_u8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U8x8, &::U8x8]; &INPUTS }, output: &::U8x8, - definition: Named("llvm.neon.vpadd.v8i8") + definition: Named("llvm.arm.neon.vpadd.v8i8") }, "padd_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I16x4, &::I16x4]; &INPUTS }, output: &::I16x4, - definition: Named("llvm.neon.vpadd.v4i16") + definition: Named("llvm.arm.neon.vpadd.v4i16") }, "padd_u16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U16x4, &::U16x4]; &INPUTS }, output: &::U16x4, - definition: Named("llvm.neon.vpadd.v4i16") + definition: Named("llvm.arm.neon.vpadd.v4i16") }, "padd_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I32x2, &::I32x2]; &INPUTS }, output: &::I32x2, - definition: Named("llvm.neon.vpadd.v2i32") + definition: Named("llvm.arm.neon.vpadd.v2i32") }, "padd_u32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U32x2, &::U32x2]; &INPUTS }, output: &::U32x2, - definition: Named("llvm.neon.vpadd.v2i32") + definition: Named("llvm.arm.neon.vpadd.v2i32") }, "padd_f32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::F32x2, &::F32x2]; &INPUTS }, output: &::F32x2, - definition: Named("llvm.neon.vpadd.v2f32") + definition: Named("llvm.arm.neon.vpadd.v2f32") }, "paddl_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::I8x8]; &INPUTS }, output: &::I16x4, - definition: Named("llvm.neon.vpaddls.v4i16.v8i8") + definition: Named("llvm.arm.neon.vpaddls.v4i16.v8i8") }, "paddl_u16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::U8x8]; &INPUTS }, output: &::U16x4, - definition: Named("llvm.neon.vpaddlu.v4i16.v8i8") + definition: Named("llvm.arm.neon.vpaddlu.v4i16.v8i8") }, "paddl_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::I16x4]; &INPUTS }, output: &::I32x2, - definition: Named("llvm.neon.vpaddls.v2i32.v4i16") + definition: Named("llvm.arm.neon.vpaddls.v2i32.v4i16") }, "paddl_u32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::U16x4]; &INPUTS }, output: &::U32x2, - definition: Named("llvm.neon.vpaddlu.v2i32.v4i16") + definition: Named("llvm.arm.neon.vpaddlu.v2i32.v4i16") }, "paddl_s64" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::I32x2]; &INPUTS }, output: &::I64x1, - definition: Named("llvm.neon.vpaddls.v1i64.v2i32") + definition: Named("llvm.arm.neon.vpaddls.v1i64.v2i32") }, "paddl_u64" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::U32x2]; &INPUTS }, output: &::U64x1, - definition: Named("llvm.neon.vpaddlu.v1i64.v2i32") + definition: Named("llvm.arm.neon.vpaddlu.v1i64.v2i32") }, "paddlq_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::I8x16]; &INPUTS }, output: &::I16x8, - definition: Named("llvm.neon.vpaddls.v8i16.v16i8") + definition: Named("llvm.arm.neon.vpaddls.v8i16.v16i8") }, "paddlq_u16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::U8x16]; &INPUTS }, output: &::U16x8, - definition: Named("llvm.neon.vpaddlu.v8i16.v16i8") + definition: Named("llvm.arm.neon.vpaddlu.v8i16.v16i8") }, "paddlq_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::I16x8]; &INPUTS }, output: &::I32x4, - definition: Named("llvm.neon.vpaddls.v4i32.v8i16") + definition: Named("llvm.arm.neon.vpaddls.v4i32.v8i16") }, "paddlq_u32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::U16x8]; &INPUTS }, output: &::U32x4, - definition: Named("llvm.neon.vpaddlu.v4i32.v8i16") + definition: Named("llvm.arm.neon.vpaddlu.v4i32.v8i16") }, "paddlq_s64" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::I32x4]; &INPUTS }, output: &::I64x2, - definition: Named("llvm.neon.vpaddls.v2i64.v4i32") + definition: Named("llvm.arm.neon.vpaddls.v2i64.v4i32") }, "paddlq_u64" => Intrinsic { inputs: { static INPUTS: [&'static Type; 1] = [&::U32x4]; &INPUTS }, output: &::U64x2, - definition: Named("llvm.neon.vpaddlu.v2i64.v4i32") + definition: Named("llvm.arm.neon.vpaddlu.v2i64.v4i32") }, "padal_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I16x4, &::I8x8]; &INPUTS }, output: &::I16x4, - definition: Named("llvm.neon.vpadals.v4i16.v4i16") + definition: Named("llvm.arm.neon.vpadals.v4i16.v4i16") }, "padal_u16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U16x4, &::U8x8]; &INPUTS }, output: &::U16x4, - definition: Named("llvm.neon.vpadalu.v4i16.v4i16") + definition: Named("llvm.arm.neon.vpadalu.v4i16.v4i16") }, "padal_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I32x2, &::I16x4]; &INPUTS }, output: &::I32x2, - definition: Named("llvm.neon.vpadals.v2i32.v2i32") + definition: Named("llvm.arm.neon.vpadals.v2i32.v2i32") }, "padal_u32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U32x2, &::U16x4]; &INPUTS }, output: &::U32x2, - definition: Named("llvm.neon.vpadalu.v2i32.v2i32") + definition: Named("llvm.arm.neon.vpadalu.v2i32.v2i32") }, "padal_s64" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I64x1, &::I32x2]; &INPUTS }, output: &::I64x1, - definition: Named("llvm.neon.vpadals.v1i64.v1i64") + definition: Named("llvm.arm.neon.vpadals.v1i64.v1i64") }, "padal_u64" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U64x1, &::U32x2]; &INPUTS }, output: &::U64x1, - definition: Named("llvm.neon.vpadalu.v1i64.v1i64") + definition: Named("llvm.arm.neon.vpadalu.v1i64.v1i64") }, "padalq_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I16x8, &::I8x16]; &INPUTS }, output: &::I16x8, - definition: Named("llvm.neon.vpadals.v8i16.v8i16") + definition: Named("llvm.arm.neon.vpadals.v8i16.v8i16") }, "padalq_u16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U16x8, &::U8x16]; &INPUTS }, output: &::U16x8, - definition: Named("llvm.neon.vpadalu.v8i16.v8i16") + definition: Named("llvm.arm.neon.vpadalu.v8i16.v8i16") }, "padalq_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I32x4, &::I16x8]; &INPUTS }, output: &::I32x4, - definition: Named("llvm.neon.vpadals.v4i32.v4i32") + definition: Named("llvm.arm.neon.vpadals.v4i32.v4i32") }, "padalq_u32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U32x4, &::U16x8]; &INPUTS }, output: &::U32x4, - definition: Named("llvm.neon.vpadalu.v4i32.v4i32") + definition: Named("llvm.arm.neon.vpadalu.v4i32.v4i32") }, "padalq_s64" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I64x2, &::I32x4]; &INPUTS }, output: &::I64x2, - definition: Named("llvm.neon.vpadals.v2i64.v2i64") + definition: Named("llvm.arm.neon.vpadals.v2i64.v2i64") }, "padalq_u64" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U64x2, &::U32x4]; &INPUTS }, output: &::U64x2, - definition: Named("llvm.neon.vpadalu.v2i64.v2i64") + definition: Named("llvm.arm.neon.vpadalu.v2i64.v2i64") }, "pmax_s8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I8x8, &::I8x8]; &INPUTS }, output: &::I8x8, - definition: Named("llvm.neon.vpmaxs.v8i8") + definition: Named("llvm.arm.neon.vpmaxs.v8i8") }, "pmax_u8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U8x8, &::U8x8]; &INPUTS }, output: &::U8x8, - definition: Named("llvm.neon.vpmaxu.v8i8") + definition: Named("llvm.arm.neon.vpmaxu.v8i8") }, "pmax_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I16x4, &::I16x4]; &INPUTS }, output: &::I16x4, - definition: Named("llvm.neon.vpmaxs.v4i16") + definition: Named("llvm.arm.neon.vpmaxs.v4i16") }, "pmax_u16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U16x4, &::U16x4]; &INPUTS }, output: &::U16x4, - definition: Named("llvm.neon.vpmaxu.v4i16") + definition: Named("llvm.arm.neon.vpmaxu.v4i16") }, "pmax_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I32x2, &::I32x2]; &INPUTS }, output: &::I32x2, - definition: Named("llvm.neon.vpmaxs.v2i32") + definition: Named("llvm.arm.neon.vpmaxs.v2i32") }, "pmax_u32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U32x2, &::U32x2]; &INPUTS }, output: &::U32x2, - definition: Named("llvm.neon.vpmaxu.v2i32") + definition: Named("llvm.arm.neon.vpmaxu.v2i32") }, "pmax_f32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::F32x2, &::F32x2]; &INPUTS }, output: &::F32x2, - definition: Named("llvm.neon.vpmaxf.v2f32") + definition: Named("llvm.arm.neon.vpmaxf.v2f32") }, "pmin_s8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I8x8, &::I8x8]; &INPUTS }, output: &::I8x8, - definition: Named("llvm.neon.vpmins.v8i8") + definition: Named("llvm.arm.neon.vpmins.v8i8") }, "pmin_u8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U8x8, &::U8x8]; &INPUTS }, output: &::U8x8, - definition: Named("llvm.neon.vpminu.v8i8") + definition: Named("llvm.arm.neon.vpminu.v8i8") }, "pmin_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I16x4, &::I16x4]; &INPUTS }, output: &::I16x4, - definition: Named("llvm.neon.vpmins.v4i16") + definition: Named("llvm.arm.neon.vpmins.v4i16") }, "pmin_u16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U16x4, &::U16x4]; &INPUTS }, output: &::U16x4, - definition: Named("llvm.neon.vpminu.v4i16") + definition: Named("llvm.arm.neon.vpminu.v4i16") }, "pmin_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I32x2, &::I32x2]; &INPUTS }, output: &::I32x2, - definition: Named("llvm.neon.vpmins.v2i32") + definition: Named("llvm.arm.neon.vpmins.v2i32") }, "pmin_u32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U32x2, &::U32x2]; &INPUTS }, output: &::U32x2, - definition: Named("llvm.neon.vpminu.v2i32") + definition: Named("llvm.arm.neon.vpminu.v2i32") }, "pmin_f32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::F32x2, &::F32x2]; &INPUTS }, output: &::F32x2, - definition: Named("llvm.neon.vpminf.v2f32") + definition: Named("llvm.arm.neon.vpminf.v2f32") }, "pminq_s8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I8x16, &::I8x16]; &INPUTS }, output: &::I8x16, - definition: Named("llvm.neon.vpmins.v16i8") + definition: Named("llvm.arm.neon.vpmins.v16i8") }, "pminq_u8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U8x16, &::U8x16]; &INPUTS }, output: &::U8x16, - definition: Named("llvm.neon.vpminu.v16i8") + definition: Named("llvm.arm.neon.vpminu.v16i8") }, "pminq_s16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I16x8, &::I16x8]; &INPUTS }, output: &::I16x8, - definition: Named("llvm.neon.vpmins.v8i16") + definition: Named("llvm.arm.neon.vpmins.v8i16") }, "pminq_u16" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U16x8, &::U16x8]; &INPUTS }, output: &::U16x8, - definition: Named("llvm.neon.vpminu.v8i16") + definition: Named("llvm.arm.neon.vpminu.v8i16") }, "pminq_s32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I32x4, &::I32x4]; &INPUTS }, output: &::I32x4, - definition: Named("llvm.neon.vpmins.v4i32") + definition: Named("llvm.arm.neon.vpmins.v4i32") }, "pminq_u32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U32x4, &::U32x4]; &INPUTS }, output: &::U32x4, - definition: Named("llvm.neon.vpminu.v4i32") + definition: Named("llvm.arm.neon.vpminu.v4i32") }, "pminq_f32" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::F32x4, &::F32x4]; &INPUTS }, output: &::F32x4, - definition: Named("llvm.neon.vpminf.v4f32") + definition: Named("llvm.arm.neon.vpminf.v4f32") }, "tbl1_s8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::I8x8, &::U8x8]; &INPUTS }, output: &::I8x8, - definition: Named("llvm.neon.vtbl1") + definition: Named("llvm.arm.neon.vtbl1") }, "tbl1_u8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [&::U8x8, &::U8x8]; &INPUTS }, output: &::U8x8, - definition: Named("llvm.neon.vtbl1") + definition: Named("llvm.arm.neon.vtbl1") }, "tbx1_s8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 3] = [&::I8x8, &::I8x8, &::U8x8]; &INPUTS }, output: &::I8x8, - definition: Named("llvm.neon.vtbx1") + definition: Named("llvm.arm.neon.vtbx1") }, "tbx1_u8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 3] = [&::U8x8, &::U8x8, &::U8x8]; &INPUTS }, output: &::U8x8, - definition: Named("llvm.neon.vtbx1") + definition: Named("llvm.arm.neon.vtbx1") }, "tbl2_s8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [{ static AGG: Type = Type::Aggregate(true, { static PARTS: [&'static Type; 2] = [&::I8x8, &::I8x8]; &PARTS }); &AGG }, &::U8x8]; &INPUTS }, output: &::I8x8, - definition: Named("llvm.neon.vtbl2") + definition: Named("llvm.arm.neon.vtbl2") }, "tbl2_u8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [{ static AGG: Type = Type::Aggregate(true, { static PARTS: [&'static Type; 2] = [&::U8x8, &::U8x8]; &PARTS }); &AGG }, &::U8x8]; &INPUTS }, output: &::U8x8, - definition: Named("llvm.neon.vtbl2") + definition: Named("llvm.arm.neon.vtbl2") }, "tbx2_s8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [{ static AGG: Type = Type::Aggregate(true, { static PARTS: [&'static Type; 2] = [&::I8x8, &::I8x8]; &PARTS }); &AGG }, &::U8x8]; &INPUTS }, output: &::I8x8, - definition: Named("llvm.neon.vtbx2") + definition: Named("llvm.arm.neon.vtbx2") }, "tbx2_u8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [{ static AGG: Type = Type::Aggregate(true, { static PARTS: [&'static Type; 2] = [&::U8x8, &::U8x8]; &PARTS }); &AGG }, &::U8x8]; &INPUTS }, output: &::U8x8, - definition: Named("llvm.neon.vtbx2") + definition: Named("llvm.arm.neon.vtbx2") }, "tbl3_s8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [{ static AGG: Type = Type::Aggregate(true, { static PARTS: [&'static Type; 3] = [&::I8x8, &::I8x8, &::I8x8]; &PARTS }); &AGG }, &::U8x8]; &INPUTS }, output: &::I8x8, - definition: Named("llvm.neon.vtbl3") + definition: Named("llvm.arm.neon.vtbl3") }, "tbl3_u8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [{ static AGG: Type = Type::Aggregate(true, { static PARTS: [&'static Type; 3] = [&::U8x8, &::U8x8, &::U8x8]; &PARTS }); &AGG }, &::U8x8]; &INPUTS }, output: &::U8x8, - definition: Named("llvm.neon.vtbl3") + definition: Named("llvm.arm.neon.vtbl3") }, "tbx3_s8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 3] = [&::I8x8, { static AGG: Type = Type::Aggregate(true, { static PARTS: [&'static Type; 3] = [&::I8x8, &::I8x8, &::I8x8]; &PARTS }); &AGG }, &::U8x8]; &INPUTS }, output: &::I8x8, - definition: Named("llvm.neon.vtbx3") + definition: Named("llvm.arm.neon.vtbx3") }, "tbx3_u8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 3] = [&::U8x8, { static AGG: Type = Type::Aggregate(true, { static PARTS: [&'static Type; 3] = [&::U8x8, &::U8x8, &::U8x8]; &PARTS }); &AGG }, &::U8x8]; &INPUTS }, output: &::U8x8, - definition: Named("llvm.neon.vtbx3") + definition: Named("llvm.arm.neon.vtbx3") }, "tbl4_s8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [{ static AGG: Type = Type::Aggregate(true, { static PARTS: [&'static Type; 4] = [&::I8x8, &::I8x8, &::I8x8, &::I8x8]; &PARTS }); &AGG }, &::U8x8]; &INPUTS }, output: &::I8x8, - definition: Named("llvm.neon.vtbl4") + definition: Named("llvm.arm.neon.vtbl4") }, "tbl4_u8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 2] = [{ static AGG: Type = Type::Aggregate(true, { static PARTS: [&'static Type; 4] = [&::U8x8, &::U8x8, &::U8x8, &::U8x8]; &PARTS }); &AGG }, &::U8x8]; &INPUTS }, output: &::U8x8, - definition: Named("llvm.neon.vtbl4") + definition: Named("llvm.arm.neon.vtbl4") }, "tbx4_s8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 3] = [&::I8x8, { static AGG: Type = Type::Aggregate(true, { static PARTS: [&'static Type; 4] = [&::I8x8, &::I8x8, &::I8x8, &::I8x8]; &PARTS }); &AGG }, &::U8x8]; &INPUTS }, output: &::I8x8, - definition: Named("llvm.neon.vtbx4") + definition: Named("llvm.arm.neon.vtbx4") }, "tbx4_u8" => Intrinsic { inputs: { static INPUTS: [&'static Type; 3] = [&::U8x8, { static AGG: Type = Type::Aggregate(true, { static PARTS: [&'static Type; 4] = [&::U8x8, &::U8x8, &::U8x8, &::U8x8]; &PARTS }); &AGG }, &::U8x8]; &INPUTS }, output: &::U8x8, - definition: Named("llvm.neon.vtbx4") + definition: Named("llvm.arm.neon.vtbx4") }, _ => return None, }) diff --git a/src/librustc_plugin/lib.rs b/src/librustc_plugin/lib.rs index 16ab593e47a7..0df82be3adc9 100644 --- a/src/librustc_plugin/lib.rs +++ b/src/librustc_plugin/lib.rs @@ -47,8 +47,8 @@ //! #![plugin(myplugin)] //! ``` //! -//! See the [Plugins Chapter](../../book/compiler-plugins.html) of the book -//! for more examples. +//! See the [`plugin` feature](../../unstable-book/language-features/plugin.html) of +//! the Unstable Book for more examples. #![crate_name = "rustc_plugin"] #![crate_type = "dylib"] diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 597a62f86884..49fb44f9d372 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -478,7 +478,7 @@ impl<'a> Resolver<'a> { span); self.define(parent, ident, TypeNS, (module, vis, DUMMY_SP, expansion)); - for child in self.session.cstore.item_children(def_id) { + for child in self.session.cstore.item_children(def_id, self.session) { let ns = if let Def::AssociatedTy(..) = child.def { TypeNS } else { ValueNS }; self.define(module, child.ident, ns, (child.def, ty::Visibility::Public, DUMMY_SP, expansion)); @@ -564,7 +564,7 @@ impl<'a> Resolver<'a> { /// is built, building it if it is not. pub fn populate_module_if_necessary(&mut self, module: Module<'a>) { if module.populated.get() { return } - for child in self.session.cstore.item_children(module.def_id().unwrap()) { + for child in self.session.cstore.item_children(module.def_id().unwrap(), self.session) { self.build_reduced_graph_for_external_crate_def(module, child); } module.populated.set(true) diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index 1a5cf89f9699..87c85a5fc96b 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -188,16 +188,16 @@ already been imported. Erroneous code example: ```compile_fail,E0254 -extern crate collections; +extern crate alloc; mod foo { - pub trait collections { + pub trait alloc { fn do_something(); } } -use foo::collections; // error: an extern crate named `collections` has already - // been imported in this module +use foo::alloc; // error: an extern crate named `alloc` has already + // been imported in this module fn main() {} ``` @@ -206,15 +206,15 @@ To fix issue issue, you have to rename at least one of the two imports. Example: ```ignore -extern crate collections as libcollections; // ok! +extern crate alloc as liballoc; // ok! mod foo { - pub trait collections { + pub trait alloc { fn do_something(); } } -use foo::collections; +use foo::alloc; fn main() {} ``` @@ -1425,7 +1425,7 @@ Erroneous code example: ```compile_fail,E0469 #[macro_use(drink, be_merry)] // error: imported macro not found -extern crate collections; +extern crate alloc; fn main() { // ... @@ -1467,7 +1467,7 @@ Erroneous code example: ```compile_fail,E0470 #[macro_reexport(drink, be_merry)] -extern crate collections; +extern crate alloc; fn main() { // ... diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index a950a9a23e47..60c07eda4d5c 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -285,10 +285,7 @@ impl<'a> base::Resolver for Resolver<'a> { -> Result>, Determinacy> { let def = match invoc.kind { InvocationKind::Attr { attr: None, .. } => return Ok(None), - _ => match self.resolve_invoc_to_def(invoc, scope, force) { - Ok(def) => def, - Err(determinacy) => return Err(determinacy), - }, + _ => self.resolve_invoc_to_def(invoc, scope, force)?, }; self.macro_defs.insert(invoc.expansion_data.mark, def.def_id()); diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index a892f9df6a64..405b2ed6ba9c 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -482,6 +482,16 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { if let Some(err) = self.finalize_import(import) { errors = true; + if let SingleImport { source, ref result, .. } = import.subclass { + if source.name == "self" { + // Silence `unresolved import` error if E0429 is already emitted + match result.value_ns.get() { + Err(Determined) => continue, + _ => {}, + } + } + } + // If the error is a single failed import then create a "fake" import // resolution for it so that later resolve stages won't complain. self.import_dummy_binding(import); diff --git a/src/librustc_save_analysis/Cargo.toml b/src/librustc_save_analysis/Cargo.toml index 6d04bff82829..53a82cf73e95 100644 --- a/src/librustc_save_analysis/Cargo.toml +++ b/src/librustc_save_analysis/Cargo.toml @@ -14,7 +14,7 @@ rustc = { path = "../librustc" } rustc_typeck = { path = "../librustc_typeck" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } -rls-data = "0.3" +rls-data = "0.6" rls-span = "0.4" # FIXME(#40527) should move rustc serialize out of tree rustc-serialize = "0.3" diff --git a/src/librustc_save_analysis/csv_dumper.rs b/src/librustc_save_analysis/csv_dumper.rs deleted file mode 100644 index 4bab135ff12f..000000000000 --- a/src/librustc_save_analysis/csv_dumper.rs +++ /dev/null @@ -1,436 +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 std::io::Write; - -use super::external_data::*; -use super::dump::Dump; - -use rls_data::{SpanData, CratePreludeData}; - -pub struct CsvDumper<'b, W: 'b> { - output: &'b mut W -} - -impl<'b, W: Write> CsvDumper<'b, W> { - pub fn new(writer: &'b mut W) -> CsvDumper<'b, W> { - CsvDumper { output: writer } - } - - fn record(&mut self, kind: &str, span: SpanData, values: String) { - let span_str = span_extent_str(span); - if let Err(_) = write!(self.output, "{},{}{}\n", kind, span_str, values) { - error!("Error writing output"); - } - } - - fn record_raw(&mut self, info: &str) { - if let Err(_) = write!(self.output, "{}", info) { - error!("Error writing output '{}'", info); - } - } -} - -impl<'b, W: Write + 'b> Dump for CsvDumper<'b, W> { - fn crate_prelude(&mut self, data: CratePreludeData) { - let values = make_values_str(&[ - ("name", &data.crate_name), - ("crate_root", &data.crate_root) - ]); - - self.record("crate", data.span, values); - - for c in data.external_crates { - let num = c.num.to_string(); - let values = make_values_str(&[ - ("name", &c.name), - ("crate", &num), - ("file_name", &c.file_name) - ]); - - self.record_raw(&format!("external_crate{}\n", values)); - } - - self.record_raw("end_external_crates\n"); - } - - fn enum_data(&mut self, data: EnumData) { - let id = data.id.index.as_u32().to_string(); - let scope = data.scope.index.as_u32().to_string(); - let values = make_values_str(&[ - ("id", &id), - ("qualname", &data.qualname), - ("scopeid", &scope), - ("value", &data.value) - ]); - - self.record("enum", data.span, values); - } - - fn extern_crate(&mut self, data: ExternCrateData) { - let id = data.id.index.as_u32().to_string(); - let crate_num = data.crate_num.to_string(); - let scope = data.scope.index.as_u32().to_string(); - let values = make_values_str(&[ - ("id", &id), - ("name", &data.name), - ("location", &data.location), - ("crate", &crate_num), - ("scopeid", &scope) - ]); - - self.record("extern_crate", data.span, values); - } - - fn impl_data(&mut self, data: ImplData) { - let self_ref = data.self_ref.unwrap_or(null_def_id()); - let trait_ref = data.trait_ref.unwrap_or(null_def_id()); - - let id = data.id.index.as_u32().to_string(); - let ref_id = self_ref.index.as_usize().to_string(); - let ref_id_crate = self_ref.krate.to_string(); - let trait_id = trait_ref.index.as_usize().to_string(); - let trait_id_crate = trait_ref.krate.to_string(); - let scope = data.scope.index.as_u32().to_string(); - let values = make_values_str(&[ - ("id", &id), - ("refid", &ref_id), - ("refidcrate", &ref_id_crate), - ("traitid", &trait_id), - ("traitidcrate", &trait_id_crate), - ("scopeid", &scope) - ]); - - self.record("impl", data.span, values); - } - - fn inheritance(&mut self, data: InheritanceData) { - let base_id = data.base_id.index.as_usize().to_string(); - let base_crate = data.base_id.krate.to_string(); - let deriv_id = data.deriv_id.index.as_u32().to_string(); - let deriv_crate = data.deriv_id.krate.to_string(); - let values = make_values_str(&[ - ("base", &base_id), - ("basecrate", &base_crate), - ("derived", &deriv_id), - ("derivedcrate", &deriv_crate) - ]); - - self.record("inheritance", data.span, values); - } - - fn function(&mut self, data: FunctionData) { - let (decl_id, decl_crate) = match data.declaration { - Some(id) => (id.index.as_usize().to_string(), id.krate.to_string()), - None => (String::new(), String::new()) - }; - - let id = data.id.index.as_u32().to_string(); - let scope = data.scope.index.as_u32().to_string(); - let values = make_values_str(&[ - ("id", &id), - ("qualname", &data.qualname), - ("declid", &decl_id), - ("declidcrate", &decl_crate), - ("scopeid", &scope) - ]); - - self.record("function", data.span, values); - } - - fn function_ref(&mut self, data: FunctionRefData) { - let ref_id = data.ref_id.index.as_usize().to_string(); - let ref_crate = data.ref_id.krate.to_string(); - let scope = data.scope.index.as_u32().to_string(); - let values = make_values_str(&[ - ("refid", &ref_id), - ("refidcrate", &ref_crate), - ("qualname", ""), - ("scopeid", &scope) - ]); - - self.record("fn_ref", data.span, values); - } - - fn function_call(&mut self, data: FunctionCallData) { - let ref_id = data.ref_id.index.as_usize().to_string(); - let ref_crate = data.ref_id.krate.to_string(); - let qualname = String::new(); - let scope = data.scope.index.as_u32().to_string(); - let values = make_values_str(&[ - ("refid", &ref_id), - ("refidcrate", &ref_crate), - ("qualname", &qualname), - ("scopeid", &scope) - ]); - - self.record("fn_call", data.span, values); - } - - fn method(&mut self, data: MethodData) { - let id = data.id.index.as_u32().to_string(); - let scope = data.scope.index.as_u32().to_string(); - let values = make_values_str(&[ - ("id", &id), - ("qualname", &data.qualname), - ("scopeid", &scope) - ]); - - self.record("method_decl", data.span, values); - } - - fn method_call(&mut self, data: MethodCallData) { - let (dcn, dck) = match data.decl_id { - Some(declid) => (declid.index.as_usize().to_string(), declid.krate.to_string()), - None => (String::new(), String::new()), - }; - - let ref_id = data.ref_id.unwrap_or(null_def_id()); - - let def_id = ref_id.index.as_usize().to_string(); - let def_crate = ref_id.krate.to_string(); - let scope = data.scope.index.as_u32().to_string(); - let values = make_values_str(&[ - ("refid", &def_id), - ("refidcrate", &def_crate), - ("declid", &dcn), - ("declidcrate", &dck), - ("scopeid", &scope) - ]); - - self.record("method_call", data.span, values); - } - - fn macro_data(&mut self, data: MacroData) { - let values = make_values_str(&[ - ("name", &data.name), - ("qualname", &data.qualname) - ]); - - self.record("macro", data.span, values); - } - - fn macro_use(&mut self, data: MacroUseData) { - let scope = data.scope.index.as_u32().to_string(); - let values = make_values_str(&[ - ("callee_name", &data.name), - ("qualname", &data.qualname), - ("scopeid", &scope) - ]); - - self.record("macro_use", data.span, values); - } - - fn mod_data(&mut self, data: ModData) { - let id = data.id.index.as_u32().to_string(); - let scope = data.scope.index.as_u32().to_string(); - let values = make_values_str(&[ - ("id", &id), - ("qualname", &data.qualname), - ("scopeid", &scope), - ("def_file", &data.filename) - ]); - - self.record("module", data.span, values); - } - - fn mod_ref(&mut self, data: ModRefData) { - let (ref_id, ref_crate) = match data.ref_id { - Some(rid) => (rid.index.as_usize().to_string(), rid.krate.to_string()), - None => (0.to_string(), 0.to_string()) - }; - - let scope = data.scope.index.as_u32().to_string(); - let values = make_values_str(&[ - ("refid", &ref_id), - ("refidcrate", &ref_crate), - ("qualname", &data.qualname), - ("scopeid", &scope) - ]); - - self.record("mod_ref", data.span, values); - } - - fn struct_data(&mut self, data: StructData) { - let id = data.id.index.as_u32().to_string(); - let ctor_id = data.ctor_id.index.as_u32().to_string(); - let scope = data.scope.index.as_u32().to_string(); - let values = make_values_str(&[ - ("id", &id), - ("ctor_id", &ctor_id), - ("qualname", &data.qualname), - ("scopeid", &scope), - ("value", &data.value) - ]); - - self.record("struct", data.span, values); - } - - fn struct_variant(&mut self, data: StructVariantData) { - let id = data.id.index.as_u32().to_string(); - let scope = data.scope.index.as_u32().to_string(); - let values = make_values_str(&[ - ("id", &id), - ("ctor_id", &id), - ("qualname", &data.qualname), - ("type", &data.type_value), - ("value", &data.value), - ("scopeid", &scope) - ]); - - self.record("variant_struct", data.span, values); - } - - fn trait_data(&mut self, data: TraitData) { - let id = data.id.index.as_u32().to_string(); - let scope = data.scope.index.as_u32().to_string(); - let values = make_values_str(&[ - ("id", &id), - ("qualname", &data.qualname), - ("scopeid", &scope), - ("value", &data.value) - ]); - - self.record("trait", data.span, values); - } - - fn tuple_variant(&mut self, data: TupleVariantData) { - let id = data.id.index.as_u32().to_string(); - let scope = data.scope.index.as_u32().to_string(); - let values = make_values_str(&[ - ("id", &id), - ("name", &data.name), - ("qualname", &data.qualname), - ("type", &data.type_value), - ("value", &data.value), - ("scopeid", &scope) - ]); - - self.record("variant", data.span, values); - } - - fn type_ref(&mut self, data: TypeRefData) { - let (ref_id, ref_crate) = match data.ref_id { - Some(id) => (id.index.as_usize().to_string(), id.krate.to_string()), - None => (0.to_string(), 0.to_string()) - }; - - let scope = data.scope.index.as_u32().to_string(); - let values = make_values_str(&[ - ("refid", &ref_id), - ("refidcrate", &ref_crate), - ("qualname", &data.qualname), - ("scopeid", &scope) - ]); - - self.record("type_ref", data.span, values); - } - - fn typedef(&mut self, data: TypeDefData) { - let id = data.id.index.as_u32().to_string(); - let values = make_values_str(&[ - ("id", &id), - ("qualname", &data.qualname), - ("value", &data.value) - ]); - - self.record("typedef", data.span, values); - } - - fn use_data(&mut self, data: UseData) { - let mod_id = data.mod_id.unwrap_or(null_def_id()); - - let id = data.id.index.as_u32().to_string(); - let ref_id = mod_id.index.as_usize().to_string(); - let ref_crate = mod_id.krate.to_string(); - let scope = data.scope.index.as_u32().to_string(); - let values = make_values_str(&[ - ("id", &id), - ("refid", &ref_id), - ("refidcrate", &ref_crate), - ("name", &data.name), - ("scopeid", &scope) - ]); - - self.record("use_alias", data.span, values); - } - - fn use_glob(&mut self, data: UseGlobData) { - let names = data.names.join(", "); - - let id = data.id.index.as_u32().to_string(); - let scope = data.scope.index.as_u32().to_string(); - let values = make_values_str(&[ - ("id", &id), - ("value", &names), - ("scopeid", &scope) - ]); - - self.record("use_glob", data.span, values); - } - - fn variable(&mut self, data: VariableData) { - let id = data.id.index.as_u32().to_string(); - let scope = data.scope.index.as_u32().to_string(); - let values = make_values_str(&[ - ("id", &id), - ("name", &data.name), - ("qualname", &data.qualname), - ("value", &data.value), - ("type", &data.type_value), - ("scopeid", &scope) - ]); - - self.record("variable", data.span, values); - } - - fn variable_ref(&mut self, data: VariableRefData) { - let ref_id = data.ref_id.index.as_usize().to_string(); - let ref_crate = data.ref_id.krate.to_string(); - let scope = data.scope.index.as_u32().to_string(); - let values = make_values_str(&[ - ("refid", &ref_id), - ("refidcrate", &ref_crate), - ("qualname", ""), - ("scopeid", &scope) - ]); - - self.record("var_ref", data.span, values) - } -} - -// Helper function to escape quotes in a string -fn escape(s: String) -> String { - s.replace("\"", "\"\"") -} - -fn make_values_str(pairs: &[(&'static str, &str)]) -> String { - let pairs = pairs.into_iter().map(|&(f, v)| { - // Never take more than 1020 chars - if v.len() > 1020 { - (f, &v[..1020]) - } else { - (f, v) - } - }); - - let strs = pairs.map(|(f, v)| format!(",{},\"{}\"", f, escape(String::from(v)))); - strs.fold(String::new(), |mut s, ss| { - s.push_str(&ss); - s - }) -} - -fn span_extent_str(span: SpanData) -> String { - format!("file_name,\"{}\",file_line,{},file_col,{},byte_start,{},\ - file_line_end,{},file_col_end,{},byte_end,{}", - span.file_name.to_str().unwrap(), span.line_start.0, span.column_start.0, - span.byte_start, span.line_end.0, span.column_end.0, span.byte_end) -} diff --git a/src/librustc_save_analysis/data.rs b/src/librustc_save_analysis/data.rs deleted file mode 100644 index cac1a2e3c5af..000000000000 --- a/src/librustc_save_analysis/data.rs +++ /dev/null @@ -1,446 +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. - -//! Structs representing the analysis data from a crate. -//! -//! The `Dump` trait can be used together with `DumpVisitor` in order to -//! retrieve the data from a crate. - -use rustc::hir; -use rustc::hir::def_id::{CrateNum, DefId}; -use syntax::ast::{self, Attribute, NodeId}; -use syntax_pos::Span; - -use rls_data::ExternalCrateData; - -pub struct CrateData { - pub name: String, - pub number: u32, - pub span: Span, -} - -/// Data for any entity in the Rust language. The actual data contained varies -/// with the kind of entity being queried. See the nested structs for details. -#[derive(Debug)] -pub enum Data { - /// Data for Enums. - EnumData(EnumData), - /// Data for extern crates. - ExternCrateData(ExternCrateData), - /// Data about a function call. - FunctionCallData(FunctionCallData), - /// Data for all kinds of functions and methods. - FunctionData(FunctionData), - /// Data about a function ref. - FunctionRefData(FunctionRefData), - /// Data for impls. - ImplData(ImplData2), - /// Data for trait inheritance. - InheritanceData(InheritanceData), - /// Data about a macro declaration. - MacroData(MacroData), - /// Data about a macro use. - MacroUseData(MacroUseData), - /// Data about a method call. - MethodCallData(MethodCallData), - /// Data for method declarations (methods with a body are treated as functions). - MethodData(MethodData), - /// Data for modules. - ModData(ModData), - /// Data for a reference to a module. - ModRefData(ModRefData), - /// Data for a struct declaration. - StructData(StructData), - /// Data for a struct variant. - StructVariantDat(StructVariantData), - /// Data for a trait declaration. - TraitData(TraitData), - /// Data for a tuple variant. - TupleVariantData(TupleVariantData), - /// Data for a typedef. - TypeDefData(TypeDefData), - /// Data for a reference to a type or trait. - TypeRefData(TypeRefData), - /// Data for a use statement. - UseData(UseData), - /// Data for a global use statement. - UseGlobData(UseGlobData), - /// Data for local and global variables (consts and statics), and fields. - VariableData(VariableData), - /// Data for the use of some variable (e.g., the use of a local variable, which - /// will refere to that variables declaration). - VariableRefData(VariableRefData), -} - -#[derive(Eq, PartialEq, Clone, Copy, Debug)] -pub enum Visibility { - Public, - Restricted, - Inherited, -} - -impl<'a> From<&'a ast::Visibility> for Visibility { - fn from(v: &'a ast::Visibility) -> Visibility { - match *v { - ast::Visibility::Public => Visibility::Public, - ast::Visibility::Crate(_) => Visibility::Restricted, - ast::Visibility::Restricted { .. } => Visibility::Restricted, - ast::Visibility::Inherited => Visibility::Inherited, - } - } -} - -impl<'a> From<&'a hir::Visibility> for Visibility { - fn from(v: &'a hir::Visibility) -> Visibility { - match *v { - hir::Visibility::Public => Visibility::Public, - hir::Visibility::Crate => Visibility::Restricted, - hir::Visibility::Restricted { .. } => Visibility::Restricted, - hir::Visibility::Inherited => Visibility::Inherited, - } - } -} - -/// Data for the prelude of a crate. -#[derive(Debug)] -pub struct CratePreludeData { - pub crate_name: String, - pub crate_root: String, - pub external_crates: Vec, - pub span: Span, -} - -/// Data for enum declarations. -#[derive(Clone, Debug)] -pub struct EnumData { - pub id: NodeId, - pub name: String, - pub value: String, - pub qualname: String, - pub span: Span, - pub scope: NodeId, - pub variants: Vec, - pub visibility: Visibility, - pub docs: String, - pub sig: Signature, - pub attributes: Vec, -} - -/// Data for extern crates. -#[derive(Debug)] -pub struct ExternCrateData { - pub id: NodeId, - pub name: String, - pub crate_num: CrateNum, - pub location: String, - pub span: Span, - pub scope: NodeId, -} - -/// Data about a function call. -#[derive(Debug)] -pub struct FunctionCallData { - pub span: Span, - pub scope: NodeId, - pub ref_id: DefId, -} - -/// Data for all kinds of functions and methods. -#[derive(Clone, Debug)] -pub struct FunctionData { - pub id: NodeId, - pub name: String, - pub qualname: String, - pub declaration: Option, - pub span: Span, - pub scope: NodeId, - pub value: String, - pub visibility: Visibility, - pub parent: Option, - pub docs: String, - pub sig: Signature, - pub attributes: Vec, -} - -/// Data about a function call. -#[derive(Debug)] -pub struct FunctionRefData { - pub span: Span, - pub scope: NodeId, - pub ref_id: DefId, -} - -#[derive(Debug)] -pub struct ImplData { - pub id: NodeId, - pub span: Span, - pub scope: NodeId, - pub trait_ref: Option, - pub self_ref: Option, -} - -#[derive(Debug)] -// FIXME: this struct should not exist. However, removing it requires heavy -// refactoring of dump_visitor.rs. See PR 31838 for more info. -pub struct ImplData2 { - pub id: NodeId, - pub span: Span, - pub scope: NodeId, - // FIXME: I'm not really sure inline data is the best way to do this. Seems - // OK in this case, but generalising leads to returning chunks of AST, which - // feels wrong. - pub trait_ref: Option, - pub self_ref: Option, -} - -#[derive(Debug)] -pub struct InheritanceData { - pub span: Span, - pub base_id: DefId, - pub deriv_id: NodeId -} - -/// Data about a macro declaration. -#[derive(Debug)] -pub struct MacroData { - pub span: Span, - pub name: String, - pub qualname: String, - pub docs: String, -} - -/// Data about a macro use. -#[derive(Debug)] -pub struct MacroUseData { - pub span: Span, - pub name: String, - pub qualname: String, - // Because macro expansion happens before ref-ids are determined, - // we use the callee span to reference the associated macro definition. - pub callee_span: Span, - pub scope: NodeId, - pub imported: bool, -} - -/// Data about a method call. -#[derive(Debug)] -pub struct MethodCallData { - pub span: Span, - pub scope: NodeId, - pub ref_id: Option, - pub decl_id: Option, -} - -/// Data for method declarations (methods with a body are treated as functions). -#[derive(Clone, Debug)] -pub struct MethodData { - pub id: NodeId, - pub name: String, - pub qualname: String, - pub span: Span, - pub scope: NodeId, - pub value: String, - pub decl_id: Option, - pub parent: Option, - pub visibility: Visibility, - pub docs: String, - pub sig: Signature, - pub attributes: Vec, -} - -/// Data for modules. -#[derive(Debug)] -pub struct ModData { - pub id: NodeId, - pub name: String, - pub qualname: String, - pub span: Span, - pub scope: NodeId, - pub filename: String, - pub items: Vec, - pub visibility: Visibility, - pub docs: String, - pub sig: Option, - pub attributes: Vec, -} - -/// Data for a reference to a module. -#[derive(Debug)] -pub struct ModRefData { - pub span: Span, - pub scope: NodeId, - pub ref_id: Option, - pub qualname: String -} - -#[derive(Debug)] -pub struct StructData { - pub span: Span, - pub name: String, - pub id: NodeId, - pub ctor_id: NodeId, - pub qualname: String, - pub scope: NodeId, - pub value: String, - pub fields: Vec, - pub visibility: Visibility, - pub docs: String, - pub sig: Signature, - pub attributes: Vec, -} - -#[derive(Debug)] -pub struct StructVariantData { - pub span: Span, - pub name: String, - pub id: NodeId, - pub qualname: String, - pub type_value: String, - pub value: String, - pub scope: NodeId, - pub parent: Option, - pub docs: String, - pub sig: Signature, - pub attributes: Vec, -} - -#[derive(Debug)] -pub struct TraitData { - pub span: Span, - pub id: NodeId, - pub name: String, - pub qualname: String, - pub scope: NodeId, - pub value: String, - pub items: Vec, - pub visibility: Visibility, - pub docs: String, - pub sig: Signature, - pub attributes: Vec, -} - -#[derive(Debug)] -pub struct TupleVariantData { - pub span: Span, - pub id: NodeId, - pub name: String, - pub qualname: String, - pub type_value: String, - pub value: String, - pub scope: NodeId, - pub parent: Option, - pub docs: String, - pub sig: Signature, - pub attributes: Vec, -} - -/// Data for a typedef. -#[derive(Debug)] -pub struct TypeDefData { - pub id: NodeId, - pub name: String, - pub span: Span, - pub qualname: String, - pub value: String, - pub visibility: Visibility, - pub parent: Option, - pub docs: String, - pub sig: Option, - pub attributes: Vec, -} - -/// Data for a reference to a type or trait. -#[derive(Clone, Debug)] -pub struct TypeRefData { - pub span: Span, - pub scope: NodeId, - pub ref_id: Option, - pub qualname: String, -} - -#[derive(Debug)] -pub struct UseData { - pub id: NodeId, - pub span: Span, - pub name: String, - pub mod_id: Option, - pub scope: NodeId, - pub visibility: Visibility, -} - -#[derive(Debug)] -pub struct UseGlobData { - pub id: NodeId, - pub span: Span, - pub names: Vec, - pub scope: NodeId, - pub visibility: Visibility, -} - -/// Data for local and global variables (consts and statics). -#[derive(Debug)] -pub struct VariableData { - pub id: NodeId, - pub kind: VariableKind, - pub name: String, - pub qualname: String, - pub span: Span, - pub scope: NodeId, - pub parent: Option, - pub value: String, - pub type_value: String, - pub visibility: Visibility, - pub docs: String, - pub sig: Option, - pub attributes: Vec, -} - -#[derive(Debug)] -pub enum VariableKind { - Static, - Const, - Local, - Field, -} - -/// Data for the use of some item (e.g., the use of a local variable, which -/// will refer to that variables declaration (by ref_id)). -#[derive(Debug)] -pub struct VariableRefData { - pub name: String, - pub span: Span, - pub scope: NodeId, - pub ref_id: DefId, -} - - -/// Encodes information about the signature of a definition. This should have -/// enough information to create a nice display about a definition without -/// access to the source code. -#[derive(Clone, Debug)] -pub struct Signature { - pub span: Span, - pub text: String, - // These identify the main identifier for the defintion as byte offsets into - // `text`. E.g., of `foo` in `pub fn foo(...)` - pub ident_start: usize, - pub ident_end: usize, - pub defs: Vec, - pub refs: Vec, -} - -/// An element of a signature. `start` and `end` are byte offsets into the `text` -/// of the parent `Signature`. -#[derive(Clone, Debug)] -pub struct SigElement { - pub id: DefId, - pub start: usize, - pub end: usize, -} diff --git a/src/librustc_save_analysis/dump.rs b/src/librustc_save_analysis/dump.rs deleted file mode 100644 index 795ff58e2060..000000000000 --- a/src/librustc_save_analysis/dump.rs +++ /dev/null @@ -1,40 +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 super::external_data::*; - -use rls_data::CratePreludeData; - -pub trait Dump { - fn crate_prelude(&mut self, _: CratePreludeData) {} - fn enum_data(&mut self, _: EnumData) {} - fn extern_crate(&mut self, _: ExternCrateData) {} - fn impl_data(&mut self, _: ImplData) {} - fn inheritance(&mut self, _: InheritanceData) {} - fn function(&mut self, _: FunctionData) {} - fn function_ref(&mut self, _: FunctionRefData) {} - fn function_call(&mut self, _: FunctionCallData) {} - fn method(&mut self, _: MethodData) {} - fn method_call(&mut self, _: MethodCallData) {} - fn macro_data(&mut self, _: MacroData) {} - fn macro_use(&mut self, _: MacroUseData) {} - fn mod_data(&mut self, _: ModData) {} - fn mod_ref(&mut self, _: ModRefData) {} - fn struct_data(&mut self, _: StructData) {} - fn struct_variant(&mut self, _: StructVariantData) {} - fn trait_data(&mut self, _: TraitData) {} - fn tuple_variant(&mut self, _: TupleVariantData) {} - fn type_ref(&mut self, _: TypeRefData) {} - fn typedef(&mut self, _: TypeDefData) {} - fn use_data(&mut self, _: UseData) {} - fn use_glob(&mut self, _: UseGlobData) {} - fn variable(&mut self, _: VariableData) {} - fn variable_ref(&mut self, _: VariableRefData) {} -} diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index a95236e2a507..cc33d3db8eba 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -8,10 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Write the output of rustc's analysis to an implementor of Dump. The data is -//! primarily designed to be used as input to the DXR tool, specifically its -//! Rust plugin. It could also be used by IDEs or other code browsing, search, or -//! cross-referencing tools. +//! Write the output of rustc's analysis to an implementor of Dump. //! //! Dumping the analysis is implemented by walking the AST and getting a bunch of //! info out from all over the place. We use Def IDs to identify objects. The @@ -27,16 +24,12 @@ //! is used for recording the output in a format-agnostic way (see CsvDumper //! for an example). -use rustc::hir; -use rustc::hir::def::Def; -use rustc::hir::def_id::{DefId, LOCAL_CRATE}; -use rustc::hir::map::{Node, NodeItem}; +use rustc::hir::def::Def as HirDef; +use rustc::hir::def_id::DefId; +use rustc::hir::map::Node; use rustc::session::Session; -use rustc::ty::{self, TyCtxt, AssociatedItemContainer}; +use rustc::ty::{self, TyCtxt}; -use std::collections::HashSet; -use std::collections::hash_map::DefaultHasher; -use std::hash::*; use std::path::Path; use syntax::ast::{self, NodeId, PatKind, Attribute, CRATE_NODE_ID}; @@ -48,14 +41,12 @@ use syntax::ptr::P; use syntax::codemap::Spanned; use syntax_pos::*; -use super::{escape, generated_code, SaveContext, PathCollector, docs_for_attrs}; -use super::data::*; -use super::dump::Dump; -use super::external_data::{Lower, make_def_id}; -use super::span_utils::SpanUtils; -use super::recorder; +use {escape, generated_code, SaveContext, PathCollector, docs_for_attrs, lower_attributes, Dump}; +use span_utils::SpanUtils; +use sig; -use rls_data::ExternalCrateData; +use rls_data::{CratePreludeData, Import, ImportKind, SpanData, Ref, RefKind, + Def, DefKind, Relation, RelationKind}; macro_rules! down_cast_data { ($id:ident, $kind:ident, $sp:expr) => { @@ -81,8 +72,7 @@ pub struct DumpVisitor<'l, 'tcx: 'l, 'll, D: 'll> { // of macro use (callsite) spans. We store these to ensure // we only write one macro def per unique macro definition, and // one macro use per unique callsite span. - mac_defs: HashSet, - mac_uses: HashSet, + // mac_defs: HashSet, } impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { @@ -97,8 +87,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { dumper: dumper, span: span_utils.clone(), cur_scope: CRATE_NODE_ID, - mac_defs: HashSet::new(), - mac_uses: HashSet::new(), + // mac_defs: HashSet::new(), } } @@ -126,6 +115,10 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { } } + fn span_from_span(&self, span: Span) -> SpanData { + self.save_ctxt.span_from_span(span) + } + pub fn dump_crate_info(&mut self, name: &str, krate: &ast::Crate) { let source_file = self.tcx.sess.local_crate_source_file.as_ref(); let crate_root = source_file.map(|source_file| { @@ -136,25 +129,14 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { } }); - // Info about all the external crates referenced from this crate. - let external_crates = self.save_ctxt.get_external_crates().into_iter().map(|c| { - let lo_loc = self.span.sess.codemap().lookup_char_pos(c.span.lo); - ExternalCrateData { - name: c.name, - num: c.number, - file_name: SpanUtils::make_path_string(&lo_loc.file.name), - } - }).collect(); - - // The current crate. let data = CratePreludeData { crate_name: name.into(), crate_root: crate_root.unwrap_or("".to_owned()), - external_crates: external_crates, - span: krate.span, + external_crates: self.save_ctxt.get_external_crates(), + span: self.span_from_span(krate.span), }; - self.dumper.crate_prelude(data.lower(self.tcx)); + self.dumper.crate_prelude(data); } // Return all non-empty prefixes of a path. @@ -210,13 +192,13 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { fn write_sub_paths(&mut self, path: &ast::Path) { let sub_paths = self.process_path_prefixes(path); - for (span, qualname) in sub_paths { - self.dumper.mod_ref(ModRefData { - span: span, - qualname: qualname, - scope: self.cur_scope, - ref_id: None - }.lower(self.tcx)); + for (span, _) in sub_paths { + let span = self.span_from_span(span); + self.dumper.dump_ref(Ref { + kind: RefKind::Mod, + span, + ref_id: ::null_id(), + }); } } @@ -229,13 +211,13 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { return; } - for (span, qualname) in sub_paths.into_iter().take(len - 1) { - self.dumper.mod_ref(ModRefData { - span: span, - qualname: qualname, - scope: self.cur_scope, - ref_id: None - }.lower(self.tcx)); + for (span, _) in sub_paths.into_iter().take(len - 1) { + let span = self.span_from_span(span); + self.dumper.dump_ref(Ref { + kind: RefKind::Mod, + span, + ref_id: ::null_id(), + }); } } @@ -250,32 +232,32 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { let sub_paths = &sub_paths[.. (len-1)]; // write the trait part of the sub-path - let (ref span, ref qualname) = sub_paths[len-2]; - self.dumper.type_ref(TypeRefData { - ref_id: None, - span: *span, - qualname: qualname.to_owned(), - scope: CRATE_NODE_ID - }.lower(self.tcx)); + let (ref span, _) = sub_paths[len-2]; + let span = self.span_from_span(*span); + self.dumper.dump_ref(Ref { + kind: RefKind::Type, + ref_id: ::null_id(), + span, + }); // write the other sub-paths if len <= 2 { return; } let sub_paths = &sub_paths[..len-2]; - for &(ref span, ref qualname) in sub_paths { - self.dumper.mod_ref(ModRefData { - span: *span, - qualname: qualname.to_owned(), - scope: self.cur_scope, - ref_id: None - }.lower(self.tcx)); + for &(ref span, _) in sub_paths { + let span = self.span_from_span(*span); + self.dumper.dump_ref(Ref { + kind: RefKind::Mod, + span, + ref_id: ::null_id(), + }); } } fn lookup_def_id(&self, ref_id: NodeId) -> Option { match self.save_ctxt.get_path_def(ref_id) { - Def::PrimTy(..) | Def::SelfTy(..) | Def::Err => None, + HirDef::PrimTy(..) | HirDef::SelfTy(..) | HirDef::Err => None, def => Some(def.def_id()), } } @@ -284,67 +266,67 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { ref_id: NodeId, span: Span, sub_span: Option, - def_id: DefId, - scope: NodeId) { + def_id: DefId) { if self.span.filter_generated(sub_span, span) { return; } let def = self.save_ctxt.get_path_def(ref_id); match def { - Def::Mod(_) => { - self.dumper.mod_ref(ModRefData { - span: sub_span.expect("No span found for mod ref"), - ref_id: Some(def_id), - scope: scope, - qualname: String::new() - }.lower(self.tcx)); + HirDef::Mod(_) => { + let span = self.span_from_span(sub_span.expect("No span found for mod ref")); + self.dumper.dump_ref(Ref { + kind: RefKind::Mod, + span, + ref_id: ::id_from_def_id(def_id), + }); } - Def::Struct(..) | - Def::Variant(..) | - Def::Union(..) | - Def::Enum(..) | - Def::TyAlias(..) | - Def::Trait(_) => { - self.dumper.type_ref(TypeRefData { - span: sub_span.expect("No span found for type ref"), - ref_id: Some(def_id), - scope: scope, - qualname: String::new() - }.lower(self.tcx)); + HirDef::Struct(..) | + HirDef::Variant(..) | + HirDef::Union(..) | + HirDef::Enum(..) | + HirDef::TyAlias(..) | + HirDef::Trait(_) => { + let span = self.span_from_span(sub_span.expect("No span found for type ref")); + self.dumper.dump_ref(Ref { + kind: RefKind::Type, + span, + ref_id: ::id_from_def_id(def_id), + }); } - Def::Static(..) | - Def::Const(..) | - Def::StructCtor(..) | - Def::VariantCtor(..) => { - self.dumper.variable_ref(VariableRefData { - span: sub_span.expect("No span found for var ref"), - ref_id: def_id, - scope: scope, - name: String::new() - }.lower(self.tcx)); + HirDef::Static(..) | + HirDef::Const(..) | + HirDef::StructCtor(..) | + HirDef::VariantCtor(..) => { + let span = self.span_from_span(sub_span.expect("No span found for var ref")); + self.dumper.dump_ref(Ref { + kind: RefKind::Variable, + span, + ref_id: ::id_from_def_id(def_id), + }); } - Def::Fn(..) => { - self.dumper.function_ref(FunctionRefData { - span: sub_span.expect("No span found for fn ref"), - ref_id: def_id, - scope: scope - }.lower(self.tcx)); + HirDef::Fn(..) => { + let span = self.span_from_span(sub_span.expect("No span found for fn ref")); + self.dumper.dump_ref(Ref { + kind: RefKind::Function, + span, + ref_id: ::id_from_def_id(def_id), + }); } // With macros 2.0, we can legitimately get a ref to a macro, but // we don't handle it properly for now (FIXME). - Def::Macro(..) => {} - Def::Local(..) | - Def::Upvar(..) | - Def::SelfTy(..) | - Def::Label(_) | - Def::TyParam(..) | - Def::Method(..) | - Def::AssociatedTy(..) | - Def::AssociatedConst(..) | - Def::PrimTy(_) | - Def::GlobalAsm(_) | - Def::Err => { + HirDef::Macro(..) => {} + HirDef::Local(..) | + HirDef::Upvar(..) | + HirDef::SelfTy(..) | + HirDef::Label(_) | + HirDef::TyParam(..) | + HirDef::Method(..) | + HirDef::AssociatedTy(..) | + HirDef::AssociatedConst(..) | + HirDef::PrimTy(_) | + HirDef::GlobalAsm(_) | + HirDef::Err => { span_bug!(span, "process_def_kind for unexpected item: {:?}", def); @@ -367,21 +349,23 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { // variable name, but who knows?) let sub_span = span_utils.span_for_last_ident(p.span); if !self.span.filter_generated(sub_span, p.span) { - self.dumper.variable(VariableData { - id: id, - kind: VariableKind::Local, - span: sub_span.expect("No span found for variable"), + let id = ::id_from_node_id(id, &self.save_ctxt); + let span = self.span_from_span(sub_span.expect("No span found for variable")); + + self.dumper.dump_def(false, Def { + kind: DefKind::Local, + id, + span, name: path_to_string(p), qualname: format!("{}::{}", qualname, path_to_string(p)), - type_value: typ, - value: String::new(), - scope: CRATE_NODE_ID, + value: typ, parent: None, - visibility: Visibility::Inherited, + children: vec![], + decl_id: None, docs: String::new(), sig: None, - attributes: vec![], - }.lower(self.tcx)); + attributes:vec![], + }); } } } @@ -391,13 +375,12 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { sig: &'l ast::MethodSig, body: Option<&'l ast::Block>, id: ast::NodeId, - name: ast::Name, - vis: Visibility, - attrs: &'l [Attribute], + name: ast::Ident, + vis: ast::Visibility, span: Span) { debug!("process_method: {}:{}", id, name); - if let Some(method_data) = self.save_ctxt.get_method_data(id, name, span) { + if let Some(mut method_data) = self.save_ctxt.get_method_data(id, name.name, span) { let sig_str = ::make_signature(&sig.decl, &sig.generics); if body.is_some() { @@ -406,61 +389,11 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { }); } - // If the method is defined in an impl, then try and find the corresponding - // method decl in a trait, and if there is one, make a decl_id for it. This - // requires looking up the impl, then the trait, then searching for a method - // with the right name. - if !self.span.filter_generated(Some(method_data.span), span) { - let container = - self.tcx.associated_item(self.tcx.hir.local_def_id(id)).container; - let mut trait_id; - let mut decl_id = None; - match container { - AssociatedItemContainer::ImplContainer(id) => { - trait_id = self.tcx.trait_id_of_impl(id); - - match trait_id { - Some(id) => { - for item in self.tcx.associated_items(id) { - if item.kind == ty::AssociatedKind::Method { - if item.name == name { - decl_id = Some(item.def_id); - break; - } - } - } - } - None => { - if let Some(NodeItem(item)) = self.tcx.hir.get_if_local(id) { - if let hir::ItemImpl(_, _, _, _, _, ref ty, _) = item.node { - trait_id = self.lookup_def_id(ty.id); - } - } - } - } - } - AssociatedItemContainer::TraitContainer(id) => { - trait_id = Some(id); - } - } - - self.dumper.method(MethodData { - id: method_data.id, - name: method_data.name, - span: method_data.span, - scope: method_data.scope, - qualname: method_data.qualname.clone(), - value: sig_str, - decl_id: decl_id, - parent: trait_id, - visibility: vis, - docs: docs_for_attrs(attrs), - sig: method_data.sig, - attributes: attrs.to_vec(), - }.lower(self.tcx)); - } - self.process_generic_params(&sig.generics, span, &method_data.qualname, id); + + method_data.value = sig_str; + method_data.sig = sig::method_signature(id, name, sig, &self.save_ctxt); + self.dumper.dump_def(vis == ast::Visibility::Public, method_data); } // walk arg and return types @@ -479,22 +412,17 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { } fn process_trait_ref(&mut self, trait_ref: &'l ast::TraitRef) { - let trait_ref_data = self.save_ctxt.get_trait_ref_data(trait_ref, self.cur_scope); + let trait_ref_data = self.save_ctxt.get_trait_ref_data(trait_ref); if let Some(trait_ref_data) = trait_ref_data { - if !self.span.filter_generated(Some(trait_ref_data.span), trait_ref.path.span) { - self.dumper.type_ref(trait_ref_data.lower(self.tcx)); - } + self.dumper.dump_ref(trait_ref_data); } - self.process_path(trait_ref.ref_id, &trait_ref.path, Some(recorder::TypeRef)); + self.process_path(trait_ref.ref_id, &trait_ref.path); } fn process_struct_field_def(&mut self, field: &ast::StructField, parent_id: NodeId) { let field_data = self.save_ctxt.get_field_data(field, parent_id); - if let Some(mut field_data) = field_data { - if !self.span.filter_generated(Some(field_data.span), field.span) { - field_data.value = String::new(); - self.dumper.variable(field_data.lower(self.tcx)); - } + if let Some(field_data) = field_data { + self.dumper.dump_def(field.vis == ast::Visibility::Public, field_data); } } @@ -518,18 +446,23 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { name, id); if !self.span.filter_generated(Some(param_ss), full_span) { - self.dumper.typedef(TypeDefData { - span: param_ss, - name: name, - id: param.id, - qualname: qualname, + let id = ::id_from_node_id(param.id, &self.save_ctxt); + let span = self.span_from_span(param_ss); + + self.dumper.dump_def(false, Def { + kind: DefKind::Type, + id, + span, + name, + qualname, value: String::new(), - visibility: Visibility::Inherited, parent: None, + children: vec![], + decl_id: None, docs: String::new(), sig: None, attributes: vec![], - }.lower(self.tcx)); + }); } } self.visit_generics(generics); @@ -541,13 +474,10 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { ty_params: &'l ast::Generics, body: &'l ast::Block) { if let Some(fn_data) = self.save_ctxt.get_item_data(item) { - down_cast_data!(fn_data, FunctionData, item.span); - if !self.span.filter_generated(Some(fn_data.span), item.span) { - self.dumper.function(fn_data.clone().lower(self.tcx)); - } - + down_cast_data!(fn_data, DefData, item.span); self.nest_tables(item.id, |v| v.process_formals(&decl.inputs, &fn_data.qualname)); self.process_generic_params(ty_params, item.span, &fn_data.qualname, item.id); + self.dumper.dump_def(item.vis == ast::Visibility::Public, fn_data); } for arg in &decl.inputs { @@ -566,10 +496,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { typ: &'l ast::Ty, expr: &'l ast::Expr) { if let Some(var_data) = self.save_ctxt.get_item_data(item) { - down_cast_data!(var_data, VariableData, item.span); - if !self.span.filter_generated(Some(var_data.span), item.span) { - self.dumper.variable(var_data.lower(self.tcx)); - } + down_cast_data!(var_data, DefData, item.span); + self.dumper.dump_def(item.vis == ast::Visibility::Public, var_data); } self.visit_ty(&typ); self.visit_expr(expr); @@ -580,35 +508,40 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { name: ast::Name, span: Span, typ: &'l ast::Ty, - expr: &'l ast::Expr, + expr: Option<&'l ast::Expr>, parent_id: DefId, - vis: Visibility, + vis: ast::Visibility, attrs: &'l [Attribute]) { let qualname = format!("::{}", self.tcx.node_path_str(id)); let sub_span = self.span.sub_span_after_keyword(span, keywords::Const); if !self.span.filter_generated(sub_span, span) { - self.dumper.variable(VariableData { - span: sub_span.expect("No span found for variable"), - kind: VariableKind::Const, - id: id, + let sig = sig::assoc_const_signature(id, name, typ, expr, &self.save_ctxt); + let id = ::id_from_node_id(id, &self.save_ctxt); + let span = self.span_from_span(sub_span.expect("No span found for variable")); + + self.dumper.dump_def(vis == ast::Visibility::Public, Def { + kind: DefKind::Const, + id, + span, name: name.to_string(), - qualname: qualname, - value: self.span.snippet(expr.span), - type_value: ty_to_string(&typ), - scope: self.cur_scope, - parent: Some(parent_id), - visibility: vis, + qualname, + value: ty_to_string(&typ), + parent: Some(::id_from_def_id(parent_id)), + children: vec![], + decl_id: None, docs: docs_for_attrs(attrs), - sig: None, - attributes: attrs.to_vec(), - }.lower(self.tcx)); + sig, + attributes: lower_attributes(attrs.to_owned(), &self.save_ctxt), + }); } // walk type and init value self.visit_ty(typ); - self.visit_expr(expr); + if let Some(expr) = expr { + self.visit_expr(expr); + } } // FIXME tuple structs should generate tuple-specific data. @@ -620,7 +553,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { let qualname = format!("::{}", self.tcx.node_path_str(item.id)); let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Struct); - let (val, fields) = + let (value, fields) = if let ast::ItemKind::Struct(ast::VariantData::Struct(ref fields, _), _) = item.node { let fields_str = fields.iter() @@ -629,26 +562,28 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { .unwrap_or(i.to_string())) .collect::>() .join(", "); - (format!("{} {{ {} }}", name, fields_str), fields.iter().map(|f| f.id).collect()) + (format!("{} {{ {} }}", name, fields_str), + fields.iter().map(|f| ::id_from_node_id(f.id, &self.save_ctxt)).collect()) } else { (String::new(), vec![]) }; if !self.span.filter_generated(sub_span, item.span) { - self.dumper.struct_data(StructData { - span: sub_span.expect("No span found for struct"), - id: item.id, - name: name, - ctor_id: def.id(), + let span = self.span_from_span(sub_span.expect("No span found for struct")); + self.dumper.dump_def(item.vis == ast::Visibility::Public, Def { + kind: DefKind::Struct, + id: ::id_from_node_id(item.id, &self.save_ctxt), + span, + name, qualname: qualname.clone(), - scope: self.cur_scope, - value: val, - fields: fields, - visibility: From::from(&item.vis), + value, + parent: None, + children: fields, + decl_id: None, docs: docs_for_attrs(&item.attrs), - sig: self.save_ctxt.sig_base(item), - attributes: item.attrs.clone(), - }.lower(self.tcx)); + sig: sig::item_signature(item, &self.save_ctxt), + attributes: lower_attributes(item.attrs.clone(), &self.save_ctxt), + }); } for field in def.fields() { @@ -668,10 +603,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { None => return, Some(data) => data, }; - down_cast_data!(enum_data, EnumData, item.span); - if !self.span.filter_generated(Some(enum_data.span), item.span) { - self.dumper.enum_data(enum_data.clone().lower(self.tcx)); - } + down_cast_data!(enum_data, DefData, item.span); for variant in &enum_definition.variants { let name = variant.node.name.name.to_string(); @@ -679,18 +611,6 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { qualname.push_str("::"); qualname.push_str(&name); - let text = self.span.signature_string_for_span(variant.span); - let ident_start = text.find(&name).unwrap(); - let ident_end = ident_start + name.len(); - let sig = Signature { - span: variant.span, - text: text, - ident_start: ident_start, - ident_end: ident_end, - defs: vec![], - refs: vec![], - }; - match variant.node.data { ast::VariantData::Struct(ref fields, _) => { let sub_span = self.span.span_for_first_ident(variant.span); @@ -700,48 +620,62 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { .unwrap_or(i.to_string())) .collect::>() .join(", "); - let val = format!("{}::{} {{ {} }}", enum_data.name, name, fields_str); + let value = format!("{}::{} {{ {} }}", enum_data.name, name, fields_str); if !self.span.filter_generated(sub_span, variant.span) { - self.dumper.struct_variant(StructVariantData { - span: sub_span.expect("No span found for struct variant"), - id: variant.node.data.id(), - name: name, - qualname: qualname, - type_value: enum_data.qualname.clone(), - value: val, - scope: enum_data.scope, - parent: Some(make_def_id(item.id, &self.tcx.hir)), + let span = self.span_from_span( + sub_span.expect("No span found for struct variant")); + let id = ::id_from_node_id(variant.node.data.id(), &self.save_ctxt); + let parent = Some(::id_from_node_id(item.id, &self.save_ctxt)); + + self.dumper.dump_def(item.vis == ast::Visibility::Public, Def { + kind: DefKind::Struct, + id, + span, + name, + qualname, + value, + parent, + children: vec![], + decl_id: None, docs: docs_for_attrs(&variant.node.attrs), - sig: sig, - attributes: variant.node.attrs.clone(), - }.lower(self.tcx)); + sig: sig::variant_signature(variant, &self.save_ctxt), + attributes: lower_attributes(variant.node.attrs.clone(), + &self.save_ctxt), + }); } } ref v => { let sub_span = self.span.span_for_first_ident(variant.span); - let mut val = format!("{}::{}", enum_data.name, name); + let mut value = format!("{}::{}", enum_data.name, name); if let &ast::VariantData::Tuple(ref fields, _) = v { - val.push('('); - val.push_str(&fields.iter() - .map(|f| ty_to_string(&f.ty)) - .collect::>() - .join(", ")); - val.push(')'); + value.push('('); + value.push_str(&fields.iter() + .map(|f| ty_to_string(&f.ty)) + .collect::>() + .join(", ")); + value.push(')'); } if !self.span.filter_generated(sub_span, variant.span) { - self.dumper.tuple_variant(TupleVariantData { - span: sub_span.expect("No span found for tuple variant"), - id: variant.node.data.id(), - name: name, - qualname: qualname, - type_value: enum_data.qualname.clone(), - value: val, - scope: enum_data.scope, - parent: Some(make_def_id(item.id, &self.tcx.hir)), + let span = + self.span_from_span(sub_span.expect("No span found for tuple variant")); + let id = ::id_from_node_id(variant.node.data.id(), &self.save_ctxt); + let parent = Some(::id_from_node_id(item.id, &self.save_ctxt)); + + self.dumper.dump_def(item.vis == ast::Visibility::Public, Def { + kind: DefKind::Tuple, + id, + span, + name, + qualname, + value, + parent, + children: vec![], + decl_id: None, docs: docs_for_attrs(&variant.node.attrs), - sig: sig, - attributes: variant.node.attrs.clone(), - }.lower(self.tcx)); + sig: sig::variant_signature(variant, &self.save_ctxt), + attributes: lower_attributes(variant.node.attrs.clone(), + &self.save_ctxt), + }); } } } @@ -752,7 +686,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { self.visit_ty(&field.ty); } } - self.process_generic_params(ty_params, item.span, &enum_data.qualname, enum_data.id); + self.process_generic_params(ty_params, item.span, &enum_data.qualname, item.id); + self.dumper.dump_def(item.vis == ast::Visibility::Public, enum_data); } fn process_impl(&mut self, @@ -762,25 +697,17 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { typ: &'l ast::Ty, impl_items: &'l [ast::ImplItem]) { if let Some(impl_data) = self.save_ctxt.get_item_data(item) { - down_cast_data!(impl_data, ImplData, item.span); - if !self.span.filter_generated(Some(impl_data.span), item.span) { - self.dumper.impl_data(ImplData { - id: impl_data.id, - span: impl_data.span, - scope: impl_data.scope, - trait_ref: impl_data.trait_ref.map(|d| d.ref_id.unwrap()), - self_ref: impl_data.self_ref.map(|d| d.ref_id.unwrap()) - }.lower(self.tcx)); - } + down_cast_data!(impl_data, RelationData, item.span); + self.dumper.dump_relation(impl_data); } self.visit_ty(&typ); if let &Some(ref trait_ref) = trait_ref { - self.process_path(trait_ref.ref_id, &trait_ref.path, Some(recorder::TypeRef)); + self.process_path(trait_ref.ref_id, &trait_ref.path); } self.process_generic_params(type_parameters, item.span, "", item.id); for impl_item in impl_items { let map = &self.tcx.hir; - self.process_impl_item(impl_item, make_def_id(item.id, map)); + self.process_impl_item(impl_item, map.local_def_id(item.id)); } } @@ -801,19 +728,24 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { } let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Trait); if !self.span.filter_generated(sub_span, item.span) { - self.dumper.trait_data(TraitData { - span: sub_span.expect("No span found for trait"), - id: item.id, - name: name, + let id = ::id_from_node_id(item.id, &self.save_ctxt); + let span = self.span_from_span(sub_span.expect("No span found for trait")); + let children = + methods.iter().map(|i| ::id_from_node_id(i.id, &self.save_ctxt)).collect(); + self.dumper.dump_def(item.vis == ast::Visibility::Public, Def { + kind: DefKind::Trait, + id, + span, + name, qualname: qualname.clone(), - scope: self.cur_scope, value: val, - items: methods.iter().map(|i| i.id).collect(), - visibility: From::from(&item.vis), + parent: None, + children, + decl_id: None, docs: docs_for_attrs(&item.attrs), - sig: self.save_ctxt.sig_base(item), - attributes: item.attrs.clone(), - }.lower(self.tcx)); + sig: sig::item_signature(item, &self.save_ctxt), + attributes: lower_attributes(item.attrs.clone(), &self.save_ctxt), + }); } // super-traits @@ -831,21 +763,22 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { if let Some(id) = self.lookup_def_id(trait_ref.ref_id) { let sub_span = self.span.sub_span_for_type_name(trait_ref.path.span); if !self.span.filter_generated(sub_span, trait_ref.path.span) { - self.dumper.type_ref(TypeRefData { - span: sub_span.expect("No span found for trait ref"), - ref_id: Some(id), - scope: self.cur_scope, - qualname: String::new() - }.lower(self.tcx)); + let span = self.span_from_span(sub_span.expect("No span found for trait ref")); + self.dumper.dump_ref(Ref { + kind: RefKind::Type, + span, + ref_id: ::id_from_def_id(id), + }); } if !self.span.filter_generated(sub_span, trait_ref.path.span) { - let sub_span = sub_span.expect("No span for inheritance"); - self.dumper.inheritance(InheritanceData { + let sub_span = self.span_from_span(sub_span.expect("No span for inheritance")); + self.dumper.dump_relation(Relation { + kind: RelationKind::SuperTrait, span: sub_span, - base_id: id, - deriv_id: item.id - }.lower(self.tcx)); + from: ::id_from_def_id(id), + to: ::id_from_node_id(item.id, &self.save_ctxt), + }); } } } @@ -854,21 +787,19 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { self.process_generic_params(generics, item.span, &qualname, item.id); for method in methods { let map = &self.tcx.hir; - self.process_trait_item(method, make_def_id(item.id, map)) + self.process_trait_item(method, map.local_def_id(item.id)) } } // `item` is the module in question, represented as an item. fn process_mod(&mut self, item: &ast::Item) { if let Some(mod_data) = self.save_ctxt.get_item_data(item) { - down_cast_data!(mod_data, ModData, item.span); - if !self.span.filter_generated(Some(mod_data.span), item.span) { - self.dumper.mod_data(mod_data.lower(self.tcx)); - } + down_cast_data!(mod_data, DefData, item.span); + self.dumper.dump_def(item.vis == ast::Visibility::Public, mod_data); } } - fn process_path(&mut self, id: NodeId, path: &ast::Path, ref_kind: Option) { + fn process_path(&mut self, id: NodeId, path: &ast::Path) { let path_data = self.save_ctxt.get_path_data(id, path); if generated_code(path.span) && path_data.is_none() { return; @@ -881,81 +812,29 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { } }; - match path_data { - Data::VariableRefData(vrd) => { - // FIXME: this whole block duplicates the code in process_def_kind - if !self.span.filter_generated(Some(vrd.span), path.span) { - match ref_kind { - Some(recorder::TypeRef) => { - self.dumper.type_ref(TypeRefData { - span: vrd.span, - ref_id: Some(vrd.ref_id), - scope: vrd.scope, - qualname: String::new() - }.lower(self.tcx)); - } - Some(recorder::FnRef) => { - self.dumper.function_ref(FunctionRefData { - span: vrd.span, - ref_id: vrd.ref_id, - scope: vrd.scope - }.lower(self.tcx)); - } - Some(recorder::ModRef) => { - self.dumper.mod_ref( ModRefData { - span: vrd.span, - ref_id: Some(vrd.ref_id), - scope: vrd.scope, - qualname: String::new() - }.lower(self.tcx)); - } - Some(recorder::VarRef) | None - => self.dumper.variable_ref(vrd.lower(self.tcx)) - } - } - - } - Data::TypeRefData(trd) => { - if !self.span.filter_generated(Some(trd.span), path.span) { - self.dumper.type_ref(trd.lower(self.tcx)); - } - } - Data::MethodCallData(mcd) => { - if !self.span.filter_generated(Some(mcd.span), path.span) { - self.dumper.method_call(mcd.lower(self.tcx)); - } - } - Data::FunctionCallData(fcd) => { - if !self.span.filter_generated(Some(fcd.span), path.span) { - self.dumper.function_call(fcd.lower(self.tcx)); - } - } - _ => { - span_bug!(path.span, "Unexpected data: {:?}", path_data); - } - } + self.dumper.dump_ref(path_data); // Modules or types in the path prefix. match self.save_ctxt.get_path_def(id) { - Def::Method(did) => { + HirDef::Method(did) => { let ti = self.tcx.associated_item(did); if ti.kind == ty::AssociatedKind::Method && ti.method_has_self_argument { self.write_sub_path_trait_truncated(path); } } - Def::Fn(..) | - Def::Const(..) | - Def::Static(..) | - Def::StructCtor(..) | - Def::VariantCtor(..) | - Def::AssociatedConst(..) | - Def::Local(..) | - Def::Upvar(..) | - Def::Struct(..) | - Def::Union(..) | - Def::Variant(..) | - Def::TyAlias(..) | - Def::AssociatedTy(..) => self.write_sub_paths_truncated(path), + HirDef::Fn(..) | + HirDef::Const(..) | + HirDef::Static(..) | + HirDef::StructCtor(..) | + HirDef::VariantCtor(..) | + HirDef::AssociatedConst(..) | + HirDef::Local(..) | + HirDef::Upvar(..) | + HirDef::Struct(..) | + HirDef::Union(..) | + HirDef::Variant(..) | + HirDef::TyAlias(..) | + HirDef::AssociatedTy(..) => self.write_sub_paths_truncated(path), _ => {} } } @@ -969,20 +848,15 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { self.write_sub_paths_truncated(path); if let Some(struct_lit_data) = self.save_ctxt.get_expr_data(ex) { - down_cast_data!(struct_lit_data, TypeRefData, ex.span); - if !self.span.filter_generated(Some(struct_lit_data.span), ex.span) { - self.dumper.type_ref(struct_lit_data.lower(self.tcx)); + down_cast_data!(struct_lit_data, RefData, ex.span); + if !generated_code(ex.span) { + self.dumper.dump_ref(struct_lit_data); } - let scope = self.save_ctxt.enclosing_scope(ex.id); - for field in fields { if let Some(field_data) = self.save_ctxt - .get_field_ref_data(field, variant, scope) { - - if !self.span.filter_generated(Some(field_data.span), field.ident.span) { - self.dumper.variable_ref(field_data.lower(self.tcx)); - } + .get_field_ref_data(field, variant) { + self.dumper.dump_ref(field_data); } self.visit_expr(&field.expr) @@ -994,9 +868,9 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { fn process_method_call(&mut self, ex: &'l ast::Expr, args: &'l [P]) { if let Some(mcd) = self.save_ctxt.get_expr_data(ex) { - down_cast_data!(mcd, MethodCallData, ex.span); - if !self.span.filter_generated(Some(mcd.span), ex.span) { - self.dumper.method_call(mcd.lower(self.tcx)); + down_cast_data!(mcd, RefData, ex.span); + if !generated_code(ex.span) { + self.dumper.dump_ref(mcd); } } @@ -1021,12 +895,13 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { let sub_span = self.span.span_for_first_ident(span); if let Some(f) = variant.find_field_named(field.ident.name) { if !self.span.filter_generated(sub_span, span) { - self.dumper.variable_ref(VariableRefData { - span: sub_span.expect("No span fund for var ref"), - ref_id: f.did, - scope: self.cur_scope, - name: String::new() - }.lower(self.tcx)); + let span = + self.span_from_span(sub_span.expect("No span fund for var ref")); + self.dumper.dump_ref(Ref { + kind: RefKind::Variable, + span, + ref_id: ::id_from_def_id(f.did), + }); } } self.visit_pat(&field.pat); @@ -1044,7 +919,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { collector.visit_pat(&p); self.visit_pat(&p); - for &(id, ref p, immut, _) in &collector.collected_paths { + for &(id, ref p, immut) in &collector.collected_paths { let mut value = match immut { ast::Mutability::Immutable => value.to_string(), _ => String::new(), @@ -1066,21 +941,24 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { let sub_span = self.span.span_for_last_ident(p.span); // Rust uses the id of the pattern for var lookups, so we'll use it too. if !self.span.filter_generated(sub_span, p.span) { - self.dumper.variable(VariableData { - span: sub_span.expect("No span found for variable"), - kind: VariableKind::Local, - id: id, + let qualname = format!("{}${}", path_to_string(p), id); + let id = ::id_from_node_id(id, &self.save_ctxt); + let span = self.span_from_span(sub_span.expect("No span found for variable")); + + self.dumper.dump_def(false, Def { + kind: DefKind::Local, + id, + span, name: path_to_string(p), - qualname: format!("{}${}", path_to_string(p), id), - value: value, - type_value: typ, - scope: CRATE_NODE_ID, + qualname, + value: typ, parent: None, - visibility: Visibility::Inherited, + children: vec![], + decl_id: None, docs: String::new(), sig: None, - attributes: vec![], - }.lower(self.tcx)); + attributes:vec![], + }); } } } @@ -1092,119 +970,120 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { /// If the span is not macro-generated, do nothing, else use callee and /// callsite spans to record macro definition and use data, using the /// mac_uses and mac_defs sets to prevent multiples. - fn process_macro_use(&mut self, span: Span, id: NodeId) { - let data = match self.save_ctxt.get_macro_use_data(span, id) { + fn process_macro_use(&mut self, span: Span) { + let data = match self.save_ctxt.get_macro_use_data(span) { None => return, Some(data) => data, }; - let mut hasher = DefaultHasher::new(); - data.callee_span.hash(&mut hasher); - let hash = hasher.finish(); - let qualname = format!("{}::{}", data.name, hash); + + // FIXME write the macro def + // let mut hasher = DefaultHasher::new(); + // data.callee_span.hash(&mut hasher); + // let hash = hasher.finish(); + // let qualname = format!("{}::{}", data.name, hash); // Don't write macro definition for imported macros - if !self.mac_defs.contains(&data.callee_span) - && !data.imported { - self.mac_defs.insert(data.callee_span); - if let Some(sub_span) = self.span.span_for_macro_def_name(data.callee_span) { - self.dumper.macro_data(MacroData { - span: sub_span, - name: data.name.clone(), - qualname: qualname.clone(), - // FIXME where do macro docs come from? - docs: String::new(), - }.lower(self.tcx)); - } - } - if !self.mac_uses.contains(&data.span) { - self.mac_uses.insert(data.span); - if let Some(sub_span) = self.span.span_for_macro_use_name(data.span) { - self.dumper.macro_use(MacroUseData { - span: sub_span, - name: data.name, - qualname: qualname, - scope: data.scope, - callee_span: data.callee_span, - imported: data.imported, - }.lower(self.tcx)); - } - } + // if !self.mac_defs.contains(&data.callee_span) + // && !data.imported { + // self.mac_defs.insert(data.callee_span); + // if let Some(sub_span) = self.span.span_for_macro_def_name(data.callee_span) { + // self.dumper.macro_data(MacroData { + // span: sub_span, + // name: data.name.clone(), + // qualname: qualname.clone(), + // // FIXME where do macro docs come from? + // docs: String::new(), + // }.lower(self.tcx)); + // } + // } + self.dumper.macro_use(data); } fn process_trait_item(&mut self, trait_item: &'l ast::TraitItem, trait_id: DefId) { - self.process_macro_use(trait_item.span, trait_item.id); + self.process_macro_use(trait_item.span); match trait_item.node { - ast::TraitItemKind::Const(ref ty, Some(ref expr)) => { + ast::TraitItemKind::Const(ref ty, ref expr) => { self.process_assoc_const(trait_item.id, trait_item.ident.name, trait_item.span, &ty, - &expr, + expr.as_ref().map(|e| &**e), trait_id, - Visibility::Public, + ast::Visibility::Public, &trait_item.attrs); } ast::TraitItemKind::Method(ref sig, ref body) => { self.process_method(sig, body.as_ref().map(|x| &**x), trait_item.id, - trait_item.ident.name, - Visibility::Public, - &trait_item.attrs, + trait_item.ident, + ast::Visibility::Public, trait_item.span); } - ast::TraitItemKind::Type(ref _bounds, ref default_ty) => { + ast::TraitItemKind::Type(ref bounds, ref default_ty) => { // FIXME do something with _bounds (for type refs) let name = trait_item.ident.name.to_string(); let qualname = format!("::{}", self.tcx.node_path_str(trait_item.id)); let sub_span = self.span.sub_span_after_keyword(trait_item.span, keywords::Type); if !self.span.filter_generated(sub_span, trait_item.span) { - self.dumper.typedef(TypeDefData { - span: sub_span.expect("No span found for assoc type"), - name: name, - id: trait_item.id, - qualname: qualname, + let span = self.span_from_span(sub_span.expect("No span found for assoc type")); + let id = ::id_from_node_id(trait_item.id, &self.save_ctxt); + + self.dumper.dump_def(true, Def { + kind: DefKind::Type, + id, + span, + name, + qualname, value: self.span.snippet(trait_item.span), - visibility: Visibility::Public, - parent: Some(trait_id), + parent: Some(::id_from_def_id(trait_id)), + children: vec![], + decl_id: None, docs: docs_for_attrs(&trait_item.attrs), - sig: None, - attributes: trait_item.attrs.clone(), - }.lower(self.tcx)); + sig: sig::assoc_type_signature(trait_item.id, + trait_item.ident, + Some(bounds), + default_ty.as_ref().map(|ty| &**ty), + &self.save_ctxt), + attributes: lower_attributes(trait_item.attrs.clone(), &self.save_ctxt), + }); } if let &Some(ref default_ty) = default_ty { self.visit_ty(default_ty) } } - ast::TraitItemKind::Const(ref ty, None) => self.visit_ty(ty), ast::TraitItemKind::Macro(_) => {} } } fn process_impl_item(&mut self, impl_item: &'l ast::ImplItem, impl_id: DefId) { - self.process_macro_use(impl_item.span, impl_item.id); + self.process_macro_use(impl_item.span); match impl_item.node { ast::ImplItemKind::Const(ref ty, ref expr) => { self.process_assoc_const(impl_item.id, impl_item.ident.name, impl_item.span, &ty, - &expr, + Some(expr), impl_id, - From::from(&impl_item.vis), + impl_item.vis.clone(), &impl_item.attrs); } ast::ImplItemKind::Method(ref sig, ref body) => { self.process_method(sig, Some(body), impl_item.id, - impl_item.ident.name, - From::from(&impl_item.vis), - &impl_item.attrs, + impl_item.ident, + impl_item.vis.clone(), impl_item.span); } - ast::ImplItemKind::Type(ref ty) => self.visit_ty(ty), + ast::ImplItemKind::Type(ref ty) => { + // FIXME uses of the assoc type should ideally point to this + // 'def' and the name here should be a ref to the def in the + // trait. + self.visit_ty(ty) + } ast::ImplItemKind::Macro(_) => {} } } @@ -1220,25 +1099,30 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll, let cm = self.tcx.sess.codemap(); let filename = cm.span_to_filename(span); - self.dumper.mod_data(ModData { - id: id, + let data_id = ::id_from_node_id(id, &self.save_ctxt); + let children = m.items.iter().map(|i| ::id_from_node_id(i.id, &self.save_ctxt)).collect(); + let span = self.span_from_span(span); + + self.dumper.dump_def(true, Def { + kind: DefKind::Mod, + id: data_id, name: String::new(), - qualname: qualname, - span: span, - scope: id, - filename: filename, - items: m.items.iter().map(|i| i.id).collect(), - visibility: Visibility::Public, + qualname, + span, + value: filename, + children, + parent: None, + decl_id: None, docs: docs_for_attrs(attrs), sig: None, - attributes: attrs.to_owned(), - }.lower(self.tcx)); + attributes: lower_attributes(attrs.to_owned(), &self.save_ctxt), + }); self.nest_scope(id, |v| visit::walk_mod(v, m)); } fn visit_item(&mut self, item: &'l ast::Item) { use syntax::ast::ItemKind::*; - self.process_macro_use(item.span, item.id); + self.process_macro_use(item.span); match item.node { Use(ref use_item) => { match use_item.node { @@ -1246,9 +1130,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll, let sub_span = self.span.span_for_last_ident(path.span); let mod_id = match self.lookup_def_id(item.id) { Some(def_id) => { - let scope = self.cur_scope; - self.process_def_kind(item.id, path.span, sub_span, def_id, scope); - + self.process_def_kind(item.id, path.span, sub_span, def_id); Some(def_id) } None => None, @@ -1263,14 +1145,15 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll, }; if !self.span.filter_generated(sub_span, path.span) { - self.dumper.use_data(UseData { - span: sub_span.expect("No span found for use"), - id: item.id, - mod_id: mod_id, + let span = + self.span_from_span(sub_span.expect("No span found for use")); + self.dumper.import(item.vis == ast::Visibility::Public, Import { + kind: ImportKind::Use, + ref_id: mod_id.map(|id| ::id_from_def_id(id)), + span, name: ident.to_string(), - scope: self.cur_scope, - visibility: From::from(&item.vis), - }.lower(self.tcx)); + value: String::new(), + }); } self.write_sub_paths_truncated(path); } @@ -1288,23 +1171,24 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll, let sub_span = self.span .sub_span_of_token(item.span, token::BinOp(token::Star)); if !self.span.filter_generated(sub_span, item.span) { - self.dumper.use_glob(UseGlobData { - span: sub_span.expect("No span found for use glob"), - id: item.id, - names: names, - scope: self.cur_scope, - visibility: From::from(&item.vis), - }.lower(self.tcx)); + let span = + self.span_from_span(sub_span.expect("No span found for use glob")); + self.dumper.import(item.vis == ast::Visibility::Public, Import { + kind: ImportKind::GlobUse, + ref_id: None, + span, + name: "*".to_owned(), + value: names.join(", "), + }); } self.write_sub_paths(path); } ast::ViewPathList(ref path, ref list) => { for plid in list { - let scope = self.cur_scope; let id = plid.node.id; if let Some(def_id) = self.lookup_def_id(id) { let span = plid.span; - self.process_def_kind(id, span, Some(span), def_id, scope); + self.process_def_kind(id, span, Some(span), def_id); } } @@ -1312,26 +1196,19 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll, } } } - ExternCrate(ref s) => { - let location = match *s { - Some(s) => s.to_string(), - None => item.ident.to_string(), - }; + ExternCrate(_) => { let alias_span = self.span.span_for_last_ident(item.span); - let cnum = match self.sess.cstore.extern_mod_stmt_cnum(item.id) { - Some(cnum) => cnum, - None => LOCAL_CRATE, - }; if !self.span.filter_generated(alias_span, item.span) { - self.dumper.extern_crate(ExternCrateData { - id: item.id, + let span = + self.span_from_span(alias_span.expect("No span found for extern crate")); + self.dumper.import(false, Import { + kind: ImportKind::ExternCrate, + ref_id: None, + span, name: item.ident.to_string(), - crate_num: cnum, - location: location, - span: alias_span.expect("No span found for extern crate"), - scope: self.cur_scope, - }.lower(self.tcx)); + value: String::new(), + }); } } Fn(ref decl, .., ref ty_params, ref body) => @@ -1360,18 +1237,23 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll, let value = ty_to_string(&ty); let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Type); if !self.span.filter_generated(sub_span, item.span) { - self.dumper.typedef(TypeDefData { - span: sub_span.expect("No span found for typedef"), + let span = self.span_from_span(sub_span.expect("No span found for typedef")); + let id = ::id_from_node_id(item.id, &self.save_ctxt); + + self.dumper.dump_def(item.vis == ast::Visibility::Public, Def { + kind: DefKind::Type, + id, + span, name: item.ident.to_string(), - id: item.id, qualname: qualname.clone(), - value: value, - visibility: From::from(&item.vis), + value, parent: None, + children: vec![], + decl_id: None, docs: docs_for_attrs(&item.attrs), - sig: Some(self.save_ctxt.sig_base(item)), - attributes: item.attrs.clone(), - }.lower(self.tcx)); + sig: sig::item_signature(item, &self.save_ctxt), + attributes: lower_attributes(item.attrs.clone(), &self.save_ctxt), + }); } self.visit_ty(&ty); @@ -1396,7 +1278,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll, } fn visit_ty(&mut self, t: &'l ast::Ty) { - self.process_macro_use(t.span, t.id); + self.process_macro_use(t.span); match t.node { ast::TyKind::Path(_, ref path) => { if generated_code(t.span) { @@ -1405,12 +1287,12 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll, if let Some(id) = self.lookup_def_id(t.id) { if let Some(sub_span) = self.span.sub_span_for_type_name(t.span) { - self.dumper.type_ref(TypeRefData { - span: sub_span, - ref_id: Some(id), - scope: self.cur_scope, - qualname: String::new() - }.lower(self.tcx)); + let span = self.span_from_span(sub_span); + self.dumper.dump_ref(Ref { + kind: RefKind::Type, + span, + ref_id: ::id_from_def_id(id), + }); } } @@ -1427,7 +1309,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll, fn visit_expr(&mut self, ex: &'l ast::Expr) { debug!("visit_expr {:?}", ex.node); - self.process_macro_use(ex.span, ex.id); + self.process_macro_use(ex.span); match ex.node { ast::ExprKind::Struct(ref path, ref fields, ref base) => { let hir_expr = self.save_ctxt.tcx.hir.expect_expr(ex.id); @@ -1446,9 +1328,9 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll, self.visit_expr(&sub_ex); if let Some(field_data) = self.save_ctxt.get_expr_data(ex) { - down_cast_data!(field_data, VariableRefData, ex.span); - if !self.span.filter_generated(Some(field_data.span), ex.span) { - self.dumper.variable_ref(field_data.lower(self.tcx)); + down_cast_data!(field_data, RefData, ex.span); + if !generated_code(ex.span) { + self.dumper.dump_ref(field_data); } } } @@ -1474,12 +1356,13 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll, ty::TyAdt(def, _) => { let sub_span = self.span.sub_span_after_token(ex.span, token::Dot); if !self.span.filter_generated(sub_span, ex.span) { - self.dumper.variable_ref(VariableRefData { - span: sub_span.expect("No span found for var ref"), - ref_id: def.struct_variant().fields[idx.node].did, - scope: self.cur_scope, - name: String::new() - }.lower(self.tcx)); + let span = + self.span_from_span(sub_span.expect("No span found for var ref")); + self.dumper.dump_ref(Ref { + kind: RefKind::Variable, + span: span, + ref_id: ::id_from_def_id(def.struct_variant().fields[idx.node].did), + }); } } ty::TyTuple(..) => {} @@ -1540,7 +1423,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll, } fn visit_pat(&mut self, p: &'l ast::Pat) { - self.process_macro_use(p.span, p.id); + self.process_macro_use(p.span); self.process_pat(p); } @@ -1556,9 +1439,9 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll, let mut paths_to_process = vec![]; // process collected paths - for &(id, ref p, immut, ref_kind) in &collector.collected_paths { + for &(id, ref p, immut) in &collector.collected_paths { match self.save_ctxt.get_path_def(id) { - Def::Local(def_id) => { + HirDef::Local(def_id) => { let id = self.tcx.hir.as_local_node_id(def_id).unwrap(); let mut value = if immut == ast::Mutability::Immutable { self.span.snippet(p.span).to_string() @@ -1573,53 +1456,56 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll, assert!(p.segments.len() == 1, "qualified path for local variable def in arm"); if !self.span.filter_generated(Some(p.span), p.span) { - self.dumper.variable(VariableData { - span: p.span, - kind: VariableKind::Local, - id: id, + let qualname = format!("{}${}", path_to_string(p), id); + let id = ::id_from_node_id(id, &self.save_ctxt); + let span = self.span_from_span(p.span); + + self.dumper.dump_def(false, Def { + kind: DefKind::Local, + id, + span, name: path_to_string(p), - qualname: format!("{}${}", path_to_string(p), id), - value: value, - type_value: typ, - scope: CRATE_NODE_ID, + qualname, + value: typ, parent: None, - visibility: Visibility::Inherited, + children: vec![], + decl_id: None, docs: String::new(), sig: None, - attributes: vec![], - }.lower(self.tcx)); + attributes:vec![], + }); } } - Def::StructCtor(..) | Def::VariantCtor(..) | - Def::Const(..) | Def::AssociatedConst(..) | - Def::Struct(..) | Def::Variant(..) | - Def::TyAlias(..) | Def::AssociatedTy(..) | - Def::SelfTy(..) => { - paths_to_process.push((id, p.clone(), Some(ref_kind))) + HirDef::StructCtor(..) | HirDef::VariantCtor(..) | + HirDef::Const(..) | HirDef::AssociatedConst(..) | + HirDef::Struct(..) | HirDef::Variant(..) | + HirDef::TyAlias(..) | HirDef::AssociatedTy(..) | + HirDef::SelfTy(..) => { + paths_to_process.push((id, p.clone())) } def => error!("unexpected definition kind when processing collected paths: {:?}", def), } } - for &(id, ref path, ref_kind) in &paths_to_process { - self.process_path(id, path, ref_kind); + for &(id, ref path) in &paths_to_process { + self.process_path(id, path); } walk_list!(self, visit_expr, &arm.guard); self.visit_expr(&arm.body); } fn visit_path(&mut self, p: &'l ast::Path, id: NodeId) { - self.process_path(id, p, None); + self.process_path(id, p); } fn visit_stmt(&mut self, s: &'l ast::Stmt) { - self.process_macro_use(s.span, s.id); + self.process_macro_use(s.span); visit::walk_stmt(self, s) } fn visit_local(&mut self, l: &'l ast::Local) { - self.process_macro_use(l.span, l.id); + self.process_macro_use(l.span); let value = l.init.as_ref().map(|i| self.span.snippet(i.span)).unwrap_or(String::new()); self.process_var_decl(&l.pat, value); @@ -1632,14 +1518,12 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll, match item.node { ast::ForeignItemKind::Fn(ref decl, ref generics) => { if let Some(fn_data) = self.save_ctxt.get_extern_item_data(item) { - down_cast_data!(fn_data, FunctionData, item.span); - if !self.span.filter_generated(Some(fn_data.span), item.span) { - self.dumper.function(fn_data.clone().lower(self.tcx)); - } + down_cast_data!(fn_data, DefData, item.span); self.nest_tables(item.id, |v| v.process_formals(&decl.inputs, &fn_data.qualname)); self.process_generic_params(generics, item.span, &fn_data.qualname, item.id); + self.dumper.dump_def(item.vis == ast::Visibility::Public, fn_data); } for arg in &decl.inputs { @@ -1652,10 +1536,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll, } ast::ForeignItemKind::Static(ref ty, _) => { if let Some(var_data) = self.save_ctxt.get_extern_item_data(item) { - down_cast_data!(var_data, VariableData, item.span); - if !self.span.filter_generated(Some(var_data.span), item.span) { - self.dumper.variable(var_data.lower(self.tcx)); - } + down_cast_data!(var_data, DefData, item.span); + self.dumper.dump_def(item.vis == ast::Visibility::Public, var_data); } self.visit_ty(ty); diff --git a/src/librustc_save_analysis/external_data.rs b/src/librustc_save_analysis/external_data.rs deleted file mode 100644 index 02441a0587eb..000000000000 --- a/src/librustc_save_analysis/external_data.rs +++ /dev/null @@ -1,775 +0,0 @@ -// 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. - -use rustc::hir::def_id::{CrateNum, DefId, DefIndex}; -use rustc::hir::map::Map; -use rustc::ty::TyCtxt; -use syntax::ast::{self, NodeId}; -use syntax::codemap::CodeMap; -use syntax::print::pprust; -use syntax_pos::Span; - -use data::{self, Visibility, SigElement}; - -use rls_data::{SpanData, CratePreludeData, Attribute}; -use rls_span::{Column, Row}; - -// FIXME: this should be pub(crate), but the current snapshot doesn't allow it yet -pub trait Lower { - type Target; - fn lower(self, tcx: TyCtxt) -> Self::Target; -} - -pub fn make_def_id(id: NodeId, map: &Map) -> DefId { - map.opt_local_def_id(id).unwrap_or(null_def_id()) -} - -pub fn null_def_id() -> DefId { - DefId { - krate: CrateNum::from_u32(u32::max_value()), - index: DefIndex::from_u32(u32::max_value()) - } -} - -pub fn span_from_span(span: Span, cm: &CodeMap) -> SpanData { - let start = cm.lookup_char_pos(span.lo); - let end = cm.lookup_char_pos(span.hi); - - SpanData { - file_name: start.file.name.clone().into(), - byte_start: span.lo.0, - byte_end: span.hi.0, - line_start: Row::new_one_indexed(start.line as u32), - line_end: Row::new_one_indexed(end.line as u32), - column_start: Column::new_one_indexed(start.col.0 as u32 + 1), - column_end: Column::new_one_indexed(end.col.0 as u32 + 1), - } -} - -impl Lower for Vec { - type Target = Vec; - - fn lower(self, tcx: TyCtxt) -> Vec { - self.into_iter() - // Only retain real attributes. Doc comments are lowered separately. - .filter(|attr| attr.path != "doc") - .map(|mut attr| { - // Remove the surrounding '#[..]' or '#![..]' of the pretty printed - // attribute. First normalize all inner attribute (#![..]) to outer - // ones (#[..]), then remove the two leading and the one trailing character. - attr.style = ast::AttrStyle::Outer; - let value = pprust::attribute_to_string(&attr); - // This str slicing works correctly, because the leading and trailing characters - // are in the ASCII range and thus exactly one byte each. - let value = value[2..value.len()-1].to_string(); - - Attribute { - value: value, - span: span_from_span(attr.span, tcx.sess.codemap()), - } - }).collect() - } -} - -impl Lower for data::CratePreludeData { - type Target = CratePreludeData; - - fn lower(self, tcx: TyCtxt) -> CratePreludeData { - CratePreludeData { - crate_name: self.crate_name, - crate_root: self.crate_root, - external_crates: self.external_crates, - span: span_from_span(self.span, tcx.sess.codemap()), - } - } -} - -/// Data for enum declarations. -#[derive(Clone, Debug)] -pub struct EnumData { - pub id: DefId, - pub value: String, - pub name: String, - pub qualname: String, - pub span: SpanData, - pub scope: DefId, - pub variants: Vec, - pub visibility: Visibility, - pub docs: String, - pub sig: Signature, - pub attributes: Vec, -} - -impl Lower for data::EnumData { - type Target = EnumData; - - fn lower(self, tcx: TyCtxt) -> EnumData { - EnumData { - id: make_def_id(self.id, &tcx.hir), - name: self.name, - value: self.value, - qualname: self.qualname, - span: span_from_span(self.span, tcx.sess.codemap()), - scope: make_def_id(self.scope, &tcx.hir), - variants: self.variants.into_iter().map(|id| make_def_id(id, &tcx.hir)).collect(), - visibility: self.visibility, - docs: self.docs, - sig: self.sig.lower(tcx), - attributes: self.attributes.lower(tcx), - } - } -} - -/// Data for extern crates. -#[derive(Debug)] -pub struct ExternCrateData { - pub id: DefId, - pub name: String, - pub crate_num: CrateNum, - pub location: String, - pub span: SpanData, - pub scope: DefId, -} - -impl Lower for data::ExternCrateData { - type Target = ExternCrateData; - - fn lower(self, tcx: TyCtxt) -> ExternCrateData { - ExternCrateData { - id: make_def_id(self.id, &tcx.hir), - name: self.name, - crate_num: self.crate_num, - location: self.location, - span: span_from_span(self.span, tcx.sess.codemap()), - scope: make_def_id(self.scope, &tcx.hir), - } - } -} - -/// Data about a function call. -#[derive(Debug)] -pub struct FunctionCallData { - pub span: SpanData, - pub scope: DefId, - pub ref_id: DefId, -} - -impl Lower for data::FunctionCallData { - type Target = FunctionCallData; - - fn lower(self, tcx: TyCtxt) -> FunctionCallData { - FunctionCallData { - span: span_from_span(self.span, tcx.sess.codemap()), - scope: make_def_id(self.scope, &tcx.hir), - ref_id: self.ref_id, - } - } -} - -/// Data for all kinds of functions and methods. -#[derive(Clone, Debug)] -pub struct FunctionData { - pub id: DefId, - pub name: String, - pub qualname: String, - pub declaration: Option, - pub span: SpanData, - pub scope: DefId, - pub value: String, - pub visibility: Visibility, - pub parent: Option, - pub docs: String, - pub sig: Signature, - pub attributes: Vec, -} - -impl Lower for data::FunctionData { - type Target = FunctionData; - - fn lower(self, tcx: TyCtxt) -> FunctionData { - FunctionData { - id: make_def_id(self.id, &tcx.hir), - name: self.name, - qualname: self.qualname, - declaration: self.declaration, - span: span_from_span(self.span, tcx.sess.codemap()), - scope: make_def_id(self.scope, &tcx.hir), - value: self.value, - visibility: self.visibility, - parent: self.parent, - docs: self.docs, - sig: self.sig.lower(tcx), - attributes: self.attributes.lower(tcx), - } - } -} - -/// Data about a function call. -#[derive(Debug)] -pub struct FunctionRefData { - pub span: SpanData, - pub scope: DefId, - pub ref_id: DefId, -} - -impl Lower for data::FunctionRefData { - type Target = FunctionRefData; - - fn lower(self, tcx: TyCtxt) -> FunctionRefData { - FunctionRefData { - span: span_from_span(self.span, tcx.sess.codemap()), - scope: make_def_id(self.scope, &tcx.hir), - ref_id: self.ref_id, - } - } -} -#[derive(Debug)] -pub struct ImplData { - pub id: DefId, - pub span: SpanData, - pub scope: DefId, - pub trait_ref: Option, - pub self_ref: Option, -} - -impl Lower for data::ImplData { - type Target = ImplData; - - fn lower(self, tcx: TyCtxt) -> ImplData { - ImplData { - id: make_def_id(self.id, &tcx.hir), - span: span_from_span(self.span, tcx.sess.codemap()), - scope: make_def_id(self.scope, &tcx.hir), - trait_ref: self.trait_ref, - self_ref: self.self_ref, - } - } -} - -#[derive(Debug)] -pub struct InheritanceData { - pub span: SpanData, - pub base_id: DefId, - pub deriv_id: DefId -} - -impl Lower for data::InheritanceData { - type Target = InheritanceData; - - fn lower(self, tcx: TyCtxt) -> InheritanceData { - InheritanceData { - span: span_from_span(self.span, tcx.sess.codemap()), - base_id: self.base_id, - deriv_id: make_def_id(self.deriv_id, &tcx.hir) - } - } -} - -/// Data about a macro declaration. -#[derive(Debug)] -pub struct MacroData { - pub span: SpanData, - pub name: String, - pub qualname: String, - pub docs: String, -} - -impl Lower for data::MacroData { - type Target = MacroData; - - fn lower(self, tcx: TyCtxt) -> MacroData { - MacroData { - span: span_from_span(self.span, tcx.sess.codemap()), - name: self.name, - qualname: self.qualname, - docs: self.docs, - } - } -} - -/// Data about a macro use. -#[derive(Debug)] -pub struct MacroUseData { - pub span: SpanData, - pub name: String, - pub qualname: String, - // Because macro expansion happens before ref-ids are determined, - // we use the callee span to reference the associated macro definition. - pub callee_span: SpanData, - pub scope: DefId, -} - -impl Lower for data::MacroUseData { - type Target = MacroUseData; - - fn lower(self, tcx: TyCtxt) -> MacroUseData { - MacroUseData { - span: span_from_span(self.span, tcx.sess.codemap()), - name: self.name, - qualname: self.qualname, - callee_span: span_from_span(self.callee_span, tcx.sess.codemap()), - scope: make_def_id(self.scope, &tcx.hir), - } - } -} - -/// Data about a method call. -#[derive(Debug)] -pub struct MethodCallData { - pub span: SpanData, - pub scope: DefId, - pub ref_id: Option, - pub decl_id: Option, -} - -impl Lower for data::MethodCallData { - type Target = MethodCallData; - - fn lower(self, tcx: TyCtxt) -> MethodCallData { - MethodCallData { - span: span_from_span(self.span, tcx.sess.codemap()), - scope: make_def_id(self.scope, &tcx.hir), - ref_id: self.ref_id, - decl_id: self.decl_id, - } - } -} - -/// Data for method declarations (methods with a body are treated as functions). -#[derive(Clone, Debug)] -pub struct MethodData { - pub id: DefId, - pub name: String, - pub qualname: String, - pub span: SpanData, - pub scope: DefId, - pub value: String, - pub decl_id: Option, - pub visibility: Visibility, - pub parent: Option, - pub docs: String, - pub sig: Signature, - pub attributes: Vec, -} - -impl Lower for data::MethodData { - type Target = MethodData; - - fn lower(self, tcx: TyCtxt) -> MethodData { - MethodData { - span: span_from_span(self.span, tcx.sess.codemap()), - name: self.name, - scope: make_def_id(self.scope, &tcx.hir), - id: make_def_id(self.id, &tcx.hir), - qualname: self.qualname, - value: self.value, - decl_id: self.decl_id, - visibility: self.visibility, - parent: self.parent, - docs: self.docs, - sig: self.sig.lower(tcx), - attributes: self.attributes.lower(tcx), - } - } -} - -/// Data for modules. -#[derive(Debug)] -pub struct ModData { - pub id: DefId, - pub name: String, - pub qualname: String, - pub span: SpanData, - pub scope: DefId, - pub filename: String, - pub items: Vec, - pub visibility: Visibility, - pub docs: String, - pub sig: Option, - pub attributes: Vec, -} - -impl Lower for data::ModData { - type Target = ModData; - - fn lower(self, tcx: TyCtxt) -> ModData { - ModData { - id: make_def_id(self.id, &tcx.hir), - name: self.name, - qualname: self.qualname, - span: span_from_span(self.span, tcx.sess.codemap()), - scope: make_def_id(self.scope, &tcx.hir), - filename: self.filename, - items: self.items.into_iter().map(|id| make_def_id(id, &tcx.hir)).collect(), - visibility: self.visibility, - docs: self.docs, - sig: self.sig.map(|s| s.lower(tcx)), - attributes: self.attributes.lower(tcx), - } - } -} - -/// Data for a reference to a module. -#[derive(Debug)] -pub struct ModRefData { - pub span: SpanData, - pub scope: DefId, - pub ref_id: Option, - pub qualname: String -} - -impl Lower for data::ModRefData { - type Target = ModRefData; - - fn lower(self, tcx: TyCtxt) -> ModRefData { - ModRefData { - span: span_from_span(self.span, tcx.sess.codemap()), - scope: make_def_id(self.scope, &tcx.hir), - ref_id: self.ref_id, - qualname: self.qualname, - } - } -} - -#[derive(Debug)] -pub struct StructData { - pub span: SpanData, - pub name: String, - pub id: DefId, - pub ctor_id: DefId, - pub qualname: String, - pub scope: DefId, - pub value: String, - pub fields: Vec, - pub visibility: Visibility, - pub docs: String, - pub sig: Signature, - pub attributes: Vec, -} - -impl Lower for data::StructData { - type Target = StructData; - - fn lower(self, tcx: TyCtxt) -> StructData { - StructData { - span: span_from_span(self.span, tcx.sess.codemap()), - name: self.name, - id: make_def_id(self.id, &tcx.hir), - ctor_id: make_def_id(self.ctor_id, &tcx.hir), - qualname: self.qualname, - scope: make_def_id(self.scope, &tcx.hir), - value: self.value, - fields: self.fields.into_iter().map(|id| make_def_id(id, &tcx.hir)).collect(), - visibility: self.visibility, - docs: self.docs, - sig: self.sig.lower(tcx), - attributes: self.attributes.lower(tcx), - } - } -} - -#[derive(Debug)] -pub struct StructVariantData { - pub span: SpanData, - pub name: String, - pub id: DefId, - pub qualname: String, - pub type_value: String, - pub value: String, - pub scope: DefId, - pub parent: Option, - pub docs: String, - pub sig: Signature, - pub attributes: Vec, -} - -impl Lower for data::StructVariantData { - type Target = StructVariantData; - - fn lower(self, tcx: TyCtxt) -> StructVariantData { - StructVariantData { - span: span_from_span(self.span, tcx.sess.codemap()), - name: self.name, - id: make_def_id(self.id, &tcx.hir), - qualname: self.qualname, - type_value: self.type_value, - value: self.value, - scope: make_def_id(self.scope, &tcx.hir), - parent: self.parent, - docs: self.docs, - sig: self.sig.lower(tcx), - attributes: self.attributes.lower(tcx), - } - } -} - -#[derive(Debug)] -pub struct TraitData { - pub span: SpanData, - pub name: String, - pub id: DefId, - pub qualname: String, - pub scope: DefId, - pub value: String, - pub items: Vec, - pub visibility: Visibility, - pub docs: String, - pub sig: Signature, - pub attributes: Vec, -} - -impl Lower for data::TraitData { - type Target = TraitData; - - fn lower(self, tcx: TyCtxt) -> TraitData { - TraitData { - span: span_from_span(self.span, tcx.sess.codemap()), - name: self.name, - id: make_def_id(self.id, &tcx.hir), - qualname: self.qualname, - scope: make_def_id(self.scope, &tcx.hir), - value: self.value, - items: self.items.into_iter().map(|id| make_def_id(id, &tcx.hir)).collect(), - visibility: self.visibility, - docs: self.docs, - sig: self.sig.lower(tcx), - attributes: self.attributes.lower(tcx), - } - } -} - -#[derive(Debug)] -pub struct TupleVariantData { - pub span: SpanData, - pub id: DefId, - pub name: String, - pub qualname: String, - pub type_value: String, - pub value: String, - pub scope: DefId, - pub parent: Option, - pub docs: String, - pub sig: Signature, - pub attributes: Vec, -} - -impl Lower for data::TupleVariantData { - type Target = TupleVariantData; - - fn lower(self, tcx: TyCtxt) -> TupleVariantData { - TupleVariantData { - span: span_from_span(self.span, tcx.sess.codemap()), - id: make_def_id(self.id, &tcx.hir), - name: self.name, - qualname: self.qualname, - type_value: self.type_value, - value: self.value, - scope: make_def_id(self.scope, &tcx.hir), - parent: self.parent, - docs: self.docs, - sig: self.sig.lower(tcx), - attributes: self.attributes.lower(tcx), - } - } -} - -/// Data for a typedef. -#[derive(Debug)] -pub struct TypeDefData { - pub id: DefId, - pub name: String, - pub span: SpanData, - pub qualname: String, - pub value: String, - pub visibility: Visibility, - pub parent: Option, - pub docs: String, - pub sig: Option, - pub attributes: Vec, -} - -impl Lower for data::TypeDefData { - type Target = TypeDefData; - - fn lower(self, tcx: TyCtxt) -> TypeDefData { - TypeDefData { - id: make_def_id(self.id, &tcx.hir), - name: self.name, - span: span_from_span(self.span, tcx.sess.codemap()), - qualname: self.qualname, - value: self.value, - visibility: self.visibility, - parent: self.parent, - docs: self.docs, - sig: self.sig.map(|s| s.lower(tcx)), - attributes: self.attributes.lower(tcx), - } - } -} - -/// Data for a reference to a type or trait. -#[derive(Clone, Debug)] -pub struct TypeRefData { - pub span: SpanData, - pub scope: DefId, - pub ref_id: Option, - pub qualname: String, -} - -impl Lower for data::TypeRefData { - type Target = TypeRefData; - - fn lower(self, tcx: TyCtxt) -> TypeRefData { - TypeRefData { - span: span_from_span(self.span, tcx.sess.codemap()), - scope: make_def_id(self.scope, &tcx.hir), - ref_id: self.ref_id, - qualname: self.qualname, - } - } -} - -#[derive(Debug)] -pub struct UseData { - pub id: DefId, - pub span: SpanData, - pub name: String, - pub mod_id: Option, - pub scope: DefId, - pub visibility: Visibility, -} - -impl Lower for data::UseData { - type Target = UseData; - - fn lower(self, tcx: TyCtxt) -> UseData { - UseData { - id: make_def_id(self.id, &tcx.hir), - span: span_from_span(self.span, tcx.sess.codemap()), - name: self.name, - mod_id: self.mod_id, - scope: make_def_id(self.scope, &tcx.hir), - visibility: self.visibility, - } - } -} - -#[derive(Debug)] -pub struct UseGlobData { - pub id: DefId, - pub span: SpanData, - pub names: Vec, - pub scope: DefId, - pub visibility: Visibility, -} - -impl Lower for data::UseGlobData { - type Target = UseGlobData; - - fn lower(self, tcx: TyCtxt) -> UseGlobData { - UseGlobData { - id: make_def_id(self.id, &tcx.hir), - span: span_from_span(self.span, tcx.sess.codemap()), - names: self.names, - scope: make_def_id(self.scope, &tcx.hir), - visibility: self.visibility, - } - } -} - -/// Data for local and global variables (consts and statics). -#[derive(Debug)] -pub struct VariableData { - pub id: DefId, - pub name: String, - pub kind: data::VariableKind, - pub qualname: String, - pub span: SpanData, - pub scope: DefId, - pub value: String, - pub type_value: String, - pub parent: Option, - pub visibility: Visibility, - pub docs: String, - pub sig: Option, - pub attributes: Vec, -} - -impl Lower for data::VariableData { - type Target = VariableData; - - fn lower(self, tcx: TyCtxt) -> VariableData { - VariableData { - id: make_def_id(self.id, &tcx.hir), - kind: self.kind, - name: self.name, - qualname: self.qualname, - span: span_from_span(self.span, tcx.sess.codemap()), - scope: make_def_id(self.scope, &tcx.hir), - value: self.value, - type_value: self.type_value, - parent: self.parent, - visibility: self.visibility, - docs: self.docs, - sig: self.sig.map(|s| s.lower(tcx)), - attributes: self.attributes.lower(tcx), - } - } -} - -/// Data for the use of some item (e.g., the use of a local variable, which -/// will refer to that variables declaration (by ref_id)). -#[derive(Debug)] -pub struct VariableRefData { - pub name: String, - pub span: SpanData, - pub scope: DefId, - pub ref_id: DefId, -} - -impl Lower for data::VariableRefData { - type Target = VariableRefData; - - fn lower(self, tcx: TyCtxt) -> VariableRefData { - VariableRefData { - name: self.name, - span: span_from_span(self.span, tcx.sess.codemap()), - scope: make_def_id(self.scope, &tcx.hir), - ref_id: self.ref_id, - } - } -} - -#[derive(Clone, Debug)] -pub struct Signature { - pub span: SpanData, - pub text: String, - // These identify the main identifier for the defintion as byte offsets into - // `text`. E.g., of `foo` in `pub fn foo(...)` - pub ident_start: usize, - pub ident_end: usize, - pub defs: Vec, - pub refs: Vec, -} - -impl Lower for data::Signature { - type Target = Signature; - - fn lower(self, tcx: TyCtxt) -> Signature { - Signature { - span: span_from_span(self.span, tcx.sess.codemap()), - text: self.text, - ident_start: self.ident_start, - ident_end: self.ident_end, - defs: self.defs, - refs: self.refs, - } - } -} diff --git a/src/librustc_save_analysis/json_api_dumper.rs b/src/librustc_save_analysis/json_api_dumper.rs index 49b14f5eca07..4b2301fd7f80 100644 --- a/src/librustc_save_analysis/json_api_dumper.rs +++ b/src/librustc_save_analysis/json_api_dumper.rs @@ -12,12 +12,9 @@ use std::io::Write; use rustc_serialize::json::as_json; -use external_data::*; -use data::{VariableKind, Visibility}; -use dump::Dump; -use json_dumper::id_from_def_id; +use Dump; -use rls_data::{Analysis, Import, ImportKind, Def, DefKind, CratePreludeData}; +use rls_data::{Analysis, Import, Def, CratePreludeData, Format, Relation}; // A dumper to dump a restricted set of JSON information, designed for use with @@ -33,7 +30,9 @@ pub struct JsonApiDumper<'b, W: Write + 'b> { impl<'b, W: Write> JsonApiDumper<'b, W> { pub fn new(writer: &'b mut W) -> JsonApiDumper<'b, W> { - JsonApiDumper { output: writer, result: Analysis::new() } + let mut result = Analysis::new(); + result.kind = Format::JsonApi; + JsonApiDumper { output: writer, result } } } @@ -45,306 +44,23 @@ impl<'b, W: Write> Drop for JsonApiDumper<'b, W> { } } -macro_rules! impl_fn { - ($fn_name: ident, $data_type: ident, $bucket: ident) => { - fn $fn_name(&mut self, data: $data_type) { - if let Some(datum) = data.into() { - self.result.$bucket.push(datum); - } - } - } -} - impl<'b, W: Write + 'b> Dump for JsonApiDumper<'b, W> { fn crate_prelude(&mut self, data: CratePreludeData) { self.result.prelude = Some(data) } - impl_fn!(use_data, UseData, imports); - impl_fn!(use_glob, UseGlobData, imports); - - impl_fn!(enum_data, EnumData, defs); - impl_fn!(tuple_variant, TupleVariantData, defs); - impl_fn!(struct_variant, StructVariantData, defs); - impl_fn!(struct_data, StructData, defs); - impl_fn!(trait_data, TraitData, defs); - impl_fn!(function, FunctionData, defs); - impl_fn!(method, MethodData, defs); - impl_fn!(macro_data, MacroData, defs); - impl_fn!(mod_data, ModData, defs); - impl_fn!(typedef, TypeDefData, defs); - impl_fn!(variable, VariableData, defs); - - fn impl_data(&mut self, data: ImplData) { - if data.self_ref.is_some() { - self.result.relations.push(data.into()); + fn dump_relation(&mut self, data: Relation) { + self.result.relations.push(data); + } + fn import(&mut self, public: bool, import: Import) { + if public { + self.result.imports.push(import); } } - fn inheritance(&mut self, data: InheritanceData) { - self.result.relations.push(data.into()); - } -} - -// FIXME methods. The defs have information about possible overriding and the -// refs have decl information (e.g., a trait method where we know the required -// method, but not the supplied method). In both cases, we are currently -// ignoring it. - -impl Into> for UseData { - fn into(self) -> Option { - match self.visibility { - Visibility::Public => Some(Import { - kind: ImportKind::Use, - ref_id: self.mod_id.map(|id| id_from_def_id(id)), - span: self.span, - name: self.name, - value: String::new(), - }), - _ => None, - } - } -} -impl Into> for UseGlobData { - fn into(self) -> Option { - match self.visibility { - Visibility::Public => Some(Import { - kind: ImportKind::GlobUse, - ref_id: None, - span: self.span, - name: "*".to_owned(), - value: self.names.join(", "), - }), - _ => None, - } - } -} - -impl Into> for EnumData { - fn into(self) -> Option { - match self.visibility { - Visibility::Public => Some(Def { - kind: DefKind::Enum, - id: id_from_def_id(self.id), - span: self.span, - name: self.name, - qualname: self.qualname, - value: self.value, - parent: None, - children: self.variants.into_iter().map(|id| id_from_def_id(id)).collect(), - decl_id: None, - docs: self.docs, - sig: Some(self.sig.into()), - attributes: vec![], - }), - _ => None, - } - } -} - -impl Into> for TupleVariantData { - fn into(self) -> Option { - Some(Def { - kind: DefKind::Tuple, - id: id_from_def_id(self.id), - span: self.span, - name: self.name, - qualname: self.qualname, - value: self.value, - parent: self.parent.map(|id| id_from_def_id(id)), - children: vec![], - decl_id: None, - docs: self.docs, - sig: Some(self.sig.into()), - attributes: vec![], - }) - } -} -impl Into> for StructVariantData { - fn into(self) -> Option { - Some(Def { - kind: DefKind::Struct, - id: id_from_def_id(self.id), - span: self.span, - name: self.name, - qualname: self.qualname, - value: self.value, - parent: self.parent.map(|id| id_from_def_id(id)), - children: vec![], - decl_id: None, - docs: self.docs, - sig: Some(self.sig.into()), - attributes: vec![], - }) - } -} -impl Into> for StructData { - fn into(self) -> Option { - match self.visibility { - Visibility::Public => Some(Def { - kind: DefKind::Struct, - id: id_from_def_id(self.id), - span: self.span, - name: self.name, - qualname: self.qualname, - value: self.value, - parent: None, - children: self.fields.into_iter().map(|id| id_from_def_id(id)).collect(), - decl_id: None, - docs: self.docs, - sig: Some(self.sig.into()), - attributes: vec![], - }), - _ => None, - } - } -} -impl Into> for TraitData { - fn into(self) -> Option { - match self.visibility { - Visibility::Public => Some(Def { - kind: DefKind::Trait, - id: id_from_def_id(self.id), - span: self.span, - name: self.name, - qualname: self.qualname, - value: self.value, - children: self.items.into_iter().map(|id| id_from_def_id(id)).collect(), - parent: None, - decl_id: None, - docs: self.docs, - sig: Some(self.sig.into()), - attributes: vec![], - }), - _ => None, - } - } -} -impl Into> for FunctionData { - fn into(self) -> Option { - match self.visibility { - Visibility::Public => Some(Def { - kind: DefKind::Function, - id: id_from_def_id(self.id), - span: self.span, - name: self.name, - qualname: self.qualname, - value: self.value, - children: vec![], - parent: self.parent.map(|id| id_from_def_id(id)), - decl_id: None, - docs: self.docs, - sig: Some(self.sig.into()), - attributes: vec![], - }), - _ => None, - } - } -} -impl Into> for MethodData { - fn into(self) -> Option { - match self.visibility { - Visibility::Public => Some(Def { - kind: DefKind::Method, - id: id_from_def_id(self.id), - span: self.span, - name: self.name, - qualname: self.qualname, - value: self.value, - children: vec![], - parent: self.parent.map(|id| id_from_def_id(id)), - decl_id: self.decl_id.map(|id| id_from_def_id(id)), - docs: self.docs, - sig: Some(self.sig.into()), - attributes: vec![], - }), - _ => None, - } - } -} -impl Into> for MacroData { - fn into(self) -> Option { - Some(Def { - kind: DefKind::Macro, - id: id_from_def_id(null_def_id()), - span: self.span, - name: self.name, - qualname: self.qualname, - value: String::new(), - children: vec![], - parent: None, - decl_id: None, - docs: self.docs, - sig: None, - attributes: vec![], - }) - } -} -impl Into> for ModData { - fn into(self) -> Option { - match self.visibility { - Visibility::Public => Some(Def { - kind: DefKind::Mod, - id: id_from_def_id(self.id), - span: self.span, - name: self.name, - qualname: self.qualname, - value: self.filename, - children: self.items.into_iter().map(|id| id_from_def_id(id)).collect(), - parent: None, - decl_id: None, - docs: self.docs, - sig: self.sig.map(|s| s.into()), - attributes: vec![], - }), - _ => None, - } - } -} -impl Into> for TypeDefData { - fn into(self) -> Option { - match self.visibility { - Visibility::Public => Some(Def { - kind: DefKind::Type, - id: id_from_def_id(self.id), - span: self.span, - name: self.name, - qualname: self.qualname, - value: self.value, - children: vec![], - parent: self.parent.map(|id| id_from_def_id(id)), - decl_id: None, - docs: String::new(), - sig: self.sig.map(|s| s.into()), - attributes: vec![], - }), - _ => None, - } - } -} - -impl Into> for VariableData { - fn into(self) -> Option { - match self.visibility { - Visibility::Public => Some(Def { - kind: match self.kind { - VariableKind::Static => DefKind::Static, - VariableKind::Const => DefKind::Const, - VariableKind::Local => { return None } - VariableKind::Field => DefKind::Field, - }, - id: id_from_def_id(self.id), - span: self.span, - name: self.name, - qualname: self.qualname, - value: self.value, - children: vec![], - parent: self.parent.map(|id| id_from_def_id(id)), - decl_id: None, - docs: self.docs, - sig: self.sig.map(|s| s.into()), - attributes: vec![], - }), - _ => None, + fn dump_def(&mut self, public: bool, mut data: Def) { + if public { + data.attributes = vec![]; + self.result.defs.push(data); } } } diff --git a/src/librustc_save_analysis/json_dumper.rs b/src/librustc_save_analysis/json_dumper.rs index eaa0c0825f0e..9cd375e98558 100644 --- a/src/librustc_save_analysis/json_dumper.rs +++ b/src/librustc_save_analysis/json_dumper.rs @@ -10,17 +10,13 @@ use std::io::Write; -use rustc::hir::def_id::DefId; use rustc_serialize::json::as_json; -use rls_data::{self, Id, Analysis, Import, ImportKind, Def, DefKind, Ref, RefKind, MacroRef, - Relation, RelationKind, Signature, SigElement, CratePreludeData}; +use rls_data::{self, Analysis, Import, Def, DefKind, Ref, RefKind, MacroRef, + Relation, CratePreludeData}; use rls_span::{Column, Row}; -use external_data; -use external_data::*; -use data::{self, VariableKind}; -use dump::Dump; +use Dump; pub struct JsonDumper { result: Analysis, @@ -71,71 +67,35 @@ impl Drop for JsonDumper { } } -macro_rules! impl_fn { - ($fn_name: ident, $data_type: ident, $bucket: ident) => { - fn $fn_name(&mut self, data: $data_type) { - self.result.$bucket.push(data.into()); - } - } -} - impl<'b, O: DumpOutput + 'b> Dump for JsonDumper { fn crate_prelude(&mut self, data: CratePreludeData) { self.result.prelude = Some(data) } - impl_fn!(extern_crate, ExternCrateData, imports); - impl_fn!(use_data, UseData, imports); - impl_fn!(use_glob, UseGlobData, imports); + fn macro_use(&mut self, data: MacroRef) { + self.result.macro_refs.push(data); + } - impl_fn!(enum_data, EnumData, defs); - impl_fn!(tuple_variant, TupleVariantData, defs); - impl_fn!(struct_variant, StructVariantData, defs); - impl_fn!(struct_data, StructData, defs); - impl_fn!(trait_data, TraitData, defs); - impl_fn!(function, FunctionData, defs); - impl_fn!(method, MethodData, defs); - impl_fn!(macro_data, MacroData, defs); - impl_fn!(typedef, TypeDefData, defs); - impl_fn!(variable, VariableData, defs); + fn import(&mut self, _: bool, import: Import) { + self.result.imports.push(import); + } - impl_fn!(function_ref, FunctionRefData, refs); - impl_fn!(function_call, FunctionCallData, refs); - impl_fn!(method_call, MethodCallData, refs); - impl_fn!(mod_ref, ModRefData, refs); - impl_fn!(type_ref, TypeRefData, refs); - impl_fn!(variable_ref, VariableRefData, refs); - - impl_fn!(macro_use, MacroUseData, macro_refs); - - fn mod_data(&mut self, data: ModData) { - let id: Id = id_from_def_id(data.id); - let mut def = Def { - kind: DefKind::Mod, - id: id, - span: data.span.into(), - name: data.name, - qualname: data.qualname, - value: data.filename, - parent: None, - children: data.items.into_iter().map(|id| id_from_def_id(id)).collect(), - decl_id: None, - docs: data.docs, - sig: data.sig.map(|s| s.into()), - attributes: data.attributes.into_iter().map(|a| a.into()).collect(), - }; - if def.span.file_name.to_str().unwrap() != def.value { + fn dump_ref(&mut self, data: Ref) { + self.result.refs.push(data); + } + fn dump_def(&mut self, _: bool, mut data: Def) { + if data.kind == DefKind::Mod && data.span.file_name.to_str().unwrap() != data.value { // If the module is an out-of-line defintion, then we'll make the // defintion the first character in the module's file and turn the // the declaration into a reference to it. let rf = Ref { kind: RefKind::Mod, - span: def.span, - ref_id: id, + span: data.span, + ref_id: data.id, }; self.result.refs.push(rf); - def.span = rls_data::SpanData { - file_name: def.value.clone().into(), + data.span = rls_data::SpanData { + file_name: data.value.clone().into(), byte_start: 0, byte_end: 0, line_start: Row::new_one_indexed(1), @@ -144,362 +104,10 @@ impl<'b, O: DumpOutput + 'b> Dump for JsonDumper { column_end: Column::new_one_indexed(1), } } - - self.result.defs.push(def); + self.result.defs.push(data); } - fn impl_data(&mut self, data: ImplData) { - if data.self_ref.is_some() { - self.result.relations.push(data.into()); - } - } - fn inheritance(&mut self, data: InheritanceData) { - self.result.relations.push(data.into()); - } -} - -// FIXME do we want to change ExternalData to this mode? It will break DXR. -// FIXME methods. The defs have information about possible overriding and the -// refs have decl information (e.g., a trait method where we know the required -// method, but not the supplied method). In both cases, we are currently -// ignoring it. - -// DefId::index is a newtype and so the JSON serialisation is ugly. Therefore -// we use our own Id which is the same, but without the newtype. -pub fn id_from_def_id(id: DefId) -> Id { - Id { - krate: id.krate.as_u32(), - index: id.index.as_u32(), - } -} - -impl Into for ExternCrateData { - fn into(self) -> Import { - Import { - kind: ImportKind::ExternCrate, - ref_id: None, - span: self.span, - name: self.name, - value: String::new(), - } - } -} -impl Into for UseData { - fn into(self) -> Import { - Import { - kind: ImportKind::Use, - ref_id: self.mod_id.map(|id| id_from_def_id(id)), - span: self.span, - name: self.name, - value: String::new(), - } - } -} -impl Into for UseGlobData { - fn into(self) -> Import { - Import { - kind: ImportKind::GlobUse, - ref_id: None, - span: self.span, - name: "*".to_owned(), - value: self.names.join(", "), - } - } -} - -impl Into for EnumData { - fn into(self) -> Def { - Def { - kind: DefKind::Enum, - id: id_from_def_id(self.id), - span: self.span, - name: self.name, - qualname: self.qualname, - value: self.value, - parent: None, - children: self.variants.into_iter().map(|id| id_from_def_id(id)).collect(), - decl_id: None, - docs: self.docs, - sig: Some(self.sig.into()), - attributes: self.attributes, - } - } -} - -impl Into for TupleVariantData { - fn into(self) -> Def { - Def { - kind: DefKind::Tuple, - id: id_from_def_id(self.id), - span: self.span, - name: self.name, - qualname: self.qualname, - value: self.value, - parent: None, - children: vec![], - decl_id: None, - docs: self.docs, - sig: Some(self.sig.into()), - attributes: self.attributes, - } - } -} -impl Into for StructVariantData { - fn into(self) -> Def { - Def { - kind: DefKind::Struct, - id: id_from_def_id(self.id), - span: self.span, - name: self.name, - qualname: self.qualname, - value: self.value, - parent: None, - children: vec![], - decl_id: None, - docs: self.docs, - sig: Some(self.sig.into()), - attributes: self.attributes, - } - } -} -impl Into for StructData { - fn into(self) -> Def { - Def { - kind: DefKind::Struct, - id: id_from_def_id(self.id), - span: self.span, - name: self.name, - qualname: self.qualname, - value: self.value, - parent: None, - children: self.fields.into_iter().map(|id| id_from_def_id(id)).collect(), - decl_id: None, - docs: self.docs, - sig: Some(self.sig.into()), - attributes: self.attributes, - } - } -} -impl Into for TraitData { - fn into(self) -> Def { - Def { - kind: DefKind::Trait, - id: id_from_def_id(self.id), - span: self.span, - name: self.name, - qualname: self.qualname, - value: self.value, - parent: None, - children: self.items.into_iter().map(|id| id_from_def_id(id)).collect(), - decl_id: None, - docs: self.docs, - sig: Some(self.sig.into()), - attributes: self.attributes, - } - } -} -impl Into for FunctionData { - fn into(self) -> Def { - Def { - kind: DefKind::Function, - id: id_from_def_id(self.id), - span: self.span, - name: self.name, - qualname: self.qualname, - value: self.value, - parent: None, - children: vec![], - decl_id: None, - docs: self.docs, - sig: Some(self.sig.into()), - attributes: self.attributes, - } - } -} -impl Into for MethodData { - fn into(self) -> Def { - Def { - kind: DefKind::Method, - id: id_from_def_id(self.id), - span: self.span, - name: self.name, - qualname: self.qualname, - value: self.value, - parent: None, - children: vec![], - decl_id: self.decl_id.map(|id| id_from_def_id(id)), - docs: self.docs, - sig: Some(self.sig.into()), - attributes: self.attributes, - } - } -} -impl Into for MacroData { - fn into(self) -> Def { - Def { - kind: DefKind::Macro, - id: id_from_def_id(null_def_id()), - span: self.span, - name: self.name, - qualname: self.qualname, - value: String::new(), - parent: None, - children: vec![], - decl_id: None, - docs: self.docs, - sig: None, - attributes: vec![], - } - } -} -impl Into for TypeDefData { - fn into(self) -> Def { - Def { - kind: DefKind::Type, - id: id_from_def_id(self.id), - span: self.span, - name: self.name, - qualname: self.qualname, - value: self.value, - parent: None, - children: vec![], - decl_id: None, - docs: String::new(), - sig: self.sig.map(|s| s.into()), - attributes: self.attributes, - } - } -} -impl Into for VariableData { - fn into(self) -> Def { - Def { - kind: match self.kind { - VariableKind::Static => DefKind::Static, - VariableKind::Const => DefKind::Const, - VariableKind::Local => DefKind::Local, - VariableKind::Field => DefKind::Field, - }, - id: id_from_def_id(self.id), - span: self.span, - name: self.name, - qualname: self.qualname, - value: self.type_value, - parent: None, - children: vec![], - decl_id: None, - docs: self.docs, - sig: None, - attributes: self.attributes, - } - } -} - -impl Into for FunctionRefData { - fn into(self) -> Ref { - Ref { - kind: RefKind::Function, - span: self.span, - ref_id: id_from_def_id(self.ref_id), - } - } -} -impl Into for FunctionCallData { - fn into(self) -> Ref { - Ref { - kind: RefKind::Function, - span: self.span, - ref_id: id_from_def_id(self.ref_id), - } - } -} -impl Into for MethodCallData { - fn into(self) -> Ref { - Ref { - kind: RefKind::Function, - span: self.span, - ref_id: id_from_def_id(self.ref_id.or(self.decl_id).unwrap_or(null_def_id())), - } - } -} -impl Into for ModRefData { - fn into(self) -> Ref { - Ref { - kind: RefKind::Mod, - span: self.span, - ref_id: id_from_def_id(self.ref_id.unwrap_or(null_def_id())), - } - } -} -impl Into for TypeRefData { - fn into(self) -> Ref { - Ref { - kind: RefKind::Type, - span: self.span, - ref_id: id_from_def_id(self.ref_id.unwrap_or(null_def_id())), - } - } -} -impl Into for VariableRefData { - fn into(self) -> Ref { - Ref { - kind: RefKind::Variable, - span: self.span, - ref_id: id_from_def_id(self.ref_id), - } - } -} - -impl Into for MacroUseData { - fn into(self) -> MacroRef { - MacroRef { - span: self.span, - qualname: self.qualname, - callee_span: self.callee_span.into(), - } - } -} - -impl Into for ImplData { - fn into(self) -> Relation { - Relation { - span: self.span, - kind: RelationKind::Impl, - from: id_from_def_id(self.self_ref.unwrap_or(null_def_id())), - to: id_from_def_id(self.trait_ref.unwrap_or(null_def_id())), - } - } -} - -impl Into for InheritanceData { - fn into(self) -> Relation { - Relation { - span: self.span, - kind: RelationKind::SuperTrait, - from: id_from_def_id(self.base_id), - to: id_from_def_id(self.deriv_id), - } - } -} - -impl Into for external_data::Signature { - fn into(self) -> Signature { - Signature { - span: self.span, - text: self.text, - ident_start: self.ident_start, - ident_end: self.ident_end, - defs: self.defs.into_iter().map(|s| s.into()).collect(), - refs: self.refs.into_iter().map(|s| s.into()).collect(), - } - } -} - -impl Into for data::SigElement { - fn into(self) -> SigElement { - SigElement { - id: id_from_def_id(self.id), - start: self.start, - end: self.end, - } + fn dump_relation(&mut self, data: Relation) { + self.result.relations.push(data); } } diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index b74d3982d61c..4e9e72fe2496 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -35,19 +35,16 @@ extern crate rls_data; extern crate rls_span; -mod csv_dumper; mod json_api_dumper; mod json_dumper; -mod data; -mod dump; mod dump_visitor; -pub mod external_data; #[macro_use] -pub mod span_utils; +mod span_utils; +mod sig; use rustc::hir; -use rustc::hir::def::Def; -use rustc::hir::map::Node; +use rustc::hir::def::Def as HirDef; +use rustc::hir::map::{Node, NodeItem}; use rustc::hir::def_id::DefId; use rustc::session::config::CrateType::CrateTypeExecutable; use rustc::session::Session; @@ -61,33 +58,21 @@ use std::path::{Path, PathBuf}; use syntax::ast::{self, NodeId, PatKind, Attribute, CRATE_NODE_ID}; use syntax::parse::lexer::comments::strip_doc_comment_decoration; use syntax::parse::token; +use syntax::print::pprust; use syntax::symbol::keywords; use syntax::visit::{self, Visitor}; use syntax::print::pprust::{ty_to_string, arg_to_string}; use syntax::codemap::MacroAttribute; use syntax_pos::*; -pub use self::csv_dumper::CsvDumper; -pub use self::json_api_dumper::JsonApiDumper; -pub use self::json_dumper::JsonDumper; -pub use self::data::*; -pub use self::external_data::make_def_id; -pub use self::dump::Dump; -pub use self::dump_visitor::DumpVisitor; -use self::span_utils::SpanUtils; +pub use json_api_dumper::JsonApiDumper; +pub use json_dumper::JsonDumper; +use dump_visitor::DumpVisitor; +use span_utils::SpanUtils; -// FIXME this is legacy code and should be removed -pub mod recorder { - pub use self::Row::*; +use rls_data::{Ref, RefKind, SpanData, MacroRef, Def, DefKind, Relation, RelationKind, + ExternalCrateData, Import, CratePreludeData}; - #[derive(Copy, Clone, Debug, Eq, PartialEq)] - pub enum Row { - TypeRef, - ModRef, - VarRef, - FnRef, - } -} pub struct SaveContext<'l, 'tcx: 'l> { tcx: TyCtxt<'l, 'tcx, 'tcx>, @@ -96,27 +81,64 @@ pub struct SaveContext<'l, 'tcx: 'l> { span_utils: SpanUtils<'tcx>, } +#[derive(Debug)] +pub enum Data { + /// Data about a macro use. + MacroUseData(MacroRef), + RefData(Ref), + DefData(Def), + RelationData(Relation), +} + +pub trait Dump { + fn crate_prelude(&mut self, _: CratePreludeData); + fn macro_use(&mut self, _: MacroRef) {} + fn import(&mut self, _: bool, _: Import); + fn dump_ref(&mut self, _: Ref) {} + fn dump_def(&mut self, _: bool, _: Def); + fn dump_relation(&mut self, data: Relation); +} + macro_rules! option_try( ($e:expr) => (match $e { Some(e) => e, None => return None }) ); impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { + fn span_from_span(&self, span: Span) -> SpanData { + use rls_span::{Row, Column}; + + let cm = self.tcx.sess.codemap(); + let start = cm.lookup_char_pos(span.lo); + let end = cm.lookup_char_pos(span.hi); + + SpanData { + file_name: start.file.name.clone().into(), + byte_start: span.lo.0, + byte_end: span.hi.0, + line_start: Row::new_one_indexed(start.line as u32), + line_end: Row::new_one_indexed(end.line as u32), + column_start: Column::new_one_indexed(start.col.0 as u32 + 1), + column_end: Column::new_one_indexed(end.col.0 as u32 + 1), + } + } + // List external crates used by the current crate. - pub fn get_external_crates(&self) -> Vec { + pub fn get_external_crates(&self) -> Vec { let mut result = Vec::new(); for n in self.tcx.sess.cstore.crates() { - let span = match self.tcx.sess.cstore.extern_crate(n) { + let span = match *self.tcx.extern_crate(n.as_def_id()) { Some(ref c) => c.span, None => { debug!("Skipping crate {}, no data", n); continue; } }; - result.push(CrateData { + let lo_loc = self.span_utils.sess.codemap().lookup_char_pos(span.lo); + result.push(ExternalCrateData { name: self.tcx.sess.cstore.crate_name(n).to_string(), - number: n.as_u32(), - span: span, + num: n.as_u32(), + file_name: SpanUtils::make_path_string(&lo_loc.file.name), }); } @@ -129,39 +151,43 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { ast::ForeignItemKind::Fn(ref decl, ref generics) => { let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Fn); filter!(self.span_utils, sub_span, item.span, None); - Some(Data::FunctionData(FunctionData { - id: item.id, + + Some(Data::DefData(Def { + kind: DefKind::Function, + id: id_from_node_id(item.id, self), + span: self.span_from_span(sub_span.unwrap()), name: item.ident.to_string(), - qualname: qualname, - declaration: None, - span: sub_span.unwrap(), - scope: self.enclosing_scope(item.id), + qualname, value: make_signature(decl, generics), - visibility: From::from(&item.vis), parent: None, + children: vec![], + decl_id: None, docs: docs_for_attrs(&item.attrs), - sig: self.sig_base_extern(item), - attributes: item.attrs.clone(), + sig: sig::foreign_item_signature(item, self), + attributes: lower_attributes(item.attrs.clone(), self), })) } ast::ForeignItemKind::Static(ref ty, m) => { let keyword = if m { keywords::Mut } else { keywords::Static }; let sub_span = self.span_utils.sub_span_after_keyword(item.span, keyword); filter!(self.span_utils, sub_span, item.span, None); - Some(Data::VariableData(VariableData { - id: item.id, - kind: VariableKind::Static, + + let id = ::id_from_node_id(item.id, self); + let span = self.span_from_span(sub_span.unwrap()); + + Some(Data::DefData(Def { + kind: DefKind::Static, + id, + span, name: item.ident.to_string(), - qualname: qualname, - span: sub_span.unwrap(), - scope: self.enclosing_scope(item.id), + qualname, + value: ty_to_string(ty), parent: None, - value: String::new(), - type_value: ty_to_string(ty), - visibility: From::from(&item.vis), + children: vec![], + decl_id: None, docs: docs_for_attrs(&item.attrs), - sig: Some(self.sig_base_extern(item)), - attributes: item.attrs.clone(), + sig: sig::foreign_item_signature(item, self), + attributes: lower_attributes(item.attrs.clone(), self), })) } } @@ -173,70 +199,71 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { let qualname = format!("::{}", self.tcx.node_path_str(item.id)); let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Fn); filter!(self.span_utils, sub_span, item.span, None); - - - Some(Data::FunctionData(FunctionData { - id: item.id, + Some(Data::DefData(Def { + kind: DefKind::Function, + id: id_from_node_id(item.id, self), + span: self.span_from_span(sub_span.unwrap()), name: item.ident.to_string(), - qualname: qualname, - declaration: None, - span: sub_span.unwrap(), - scope: self.enclosing_scope(item.id), + qualname, value: make_signature(decl, generics), - visibility: From::from(&item.vis), parent: None, + children: vec![], + decl_id: None, docs: docs_for_attrs(&item.attrs), - sig: self.sig_base(item), - attributes: item.attrs.clone(), + sig: sig::item_signature(item, self), + attributes: lower_attributes(item.attrs.clone(), self), })) } - ast::ItemKind::Static(ref typ, mt, ref expr) => { + ast::ItemKind::Static(ref typ, mt, _) => { let qualname = format!("::{}", self.tcx.node_path_str(item.id)); - // If the variable is immutable, save the initialising expression. - let (value, keyword) = match mt { - ast::Mutability::Mutable => (String::from(""), keywords::Mut), - ast::Mutability::Immutable => { - (self.span_utils.snippet(expr.span), keywords::Static) - }, + let keyword = match mt { + ast::Mutability::Mutable => keywords::Mut, + ast::Mutability::Immutable => keywords::Static, }; let sub_span = self.span_utils.sub_span_after_keyword(item.span, keyword); filter!(self.span_utils, sub_span, item.span, None); - Some(Data::VariableData(VariableData { - id: item.id, - kind: VariableKind::Static, + + let id = id_from_node_id(item.id, self); + let span = self.span_from_span(sub_span.unwrap()); + + Some(Data::DefData(Def { + kind: DefKind::Static, + id, + span, name: item.ident.to_string(), - qualname: qualname, - span: sub_span.unwrap(), - scope: self.enclosing_scope(item.id), + qualname, + value: ty_to_string(&typ), parent: None, - value: value, - type_value: ty_to_string(&typ), - visibility: From::from(&item.vis), + children: vec![], + decl_id: None, docs: docs_for_attrs(&item.attrs), - sig: Some(self.sig_base(item)), - attributes: item.attrs.clone(), + sig: sig::item_signature(item, self), + attributes: lower_attributes(item.attrs.clone(), self), })) } - ast::ItemKind::Const(ref typ, ref expr) => { + ast::ItemKind::Const(ref typ, _) => { let qualname = format!("::{}", self.tcx.node_path_str(item.id)); let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Const); filter!(self.span_utils, sub_span, item.span, None); - Some(Data::VariableData(VariableData { - id: item.id, - kind: VariableKind::Const, + + let id = id_from_node_id(item.id, self); + let span = self.span_from_span(sub_span.unwrap()); + + Some(Data::DefData(Def { + kind: DefKind::Const, + id, + span, name: item.ident.to_string(), - qualname: qualname, - span: sub_span.unwrap(), - scope: self.enclosing_scope(item.id), + qualname, + value: ty_to_string(typ), parent: None, - value: self.span_utils.snippet(expr.span), - type_value: ty_to_string(&typ), - visibility: From::from(&item.vis), + children: vec![], + decl_id: None, docs: docs_for_attrs(&item.attrs), - sig: Some(self.sig_base(item)), - attributes: item.attrs.clone(), + sig: sig::item_signature(item, self), + attributes: lower_attributes(item.attrs.clone(), self), })) } ast::ItemKind::Mod(ref m) => { @@ -248,18 +275,19 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Mod); filter!(self.span_utils, sub_span, item.span, None); - Some(Data::ModData(ModData { - id: item.id, + Some(Data::DefData(Def { + kind: DefKind::Mod, + id: id_from_node_id(item.id, self), name: item.ident.to_string(), - qualname: qualname, - span: sub_span.unwrap(), - scope: self.enclosing_scope(item.id), - filename: filename, - items: m.items.iter().map(|i| i.id).collect(), - visibility: From::from(&item.vis), + qualname, + span: self.span_from_span(sub_span.unwrap()), + value: filename, + parent: None, + children: m.items.iter().map(|i| id_from_node_id(i.id, self)).collect(), + decl_id: None, docs: docs_for_attrs(&item.attrs), - sig: Some(self.sig_base(item)), - attributes: item.attrs.clone(), + sig: sig::item_signature(item, self), + attributes: lower_attributes(item.attrs.clone(), self), })) } ast::ItemKind::Enum(ref def, _) => { @@ -271,61 +299,47 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { .map(|v| v.node.name.to_string()) .collect::>() .join(", "); - let val = format!("{}::{{{}}}", name, variants_str); - Some(Data::EnumData(EnumData { - id: item.id, - name: name, - value: val, - span: sub_span.unwrap(), - qualname: qualname, - scope: self.enclosing_scope(item.id), - variants: def.variants.iter().map(|v| v.node.data.id()).collect(), - visibility: From::from(&item.vis), + let value = format!("{}::{{{}}}", name, variants_str); + Some(Data::DefData(Def { + kind: DefKind::Enum, + id: id_from_node_id(item.id, self), + span: self.span_from_span(sub_span.unwrap()), + name, + qualname, + value, + parent: None, + children: def.variants + .iter() + .map(|v| id_from_node_id(v.node.data.id(), self)) + .collect(), + decl_id: None, docs: docs_for_attrs(&item.attrs), - sig: self.sig_base(item), - attributes: item.attrs.clone(), + sig: sig::item_signature(item, self), + attributes: lower_attributes(item.attrs.to_owned(), self), })) } ast::ItemKind::Impl(.., ref trait_ref, ref typ, _) => { - let mut type_data = None; - let sub_span; - - let parent = self.enclosing_scope(item.id); - - match typ.node { + if let ast::TyKind::Path(None, ref path) = typ.node { // Common case impl for a struct or something basic. - ast::TyKind::Path(None, ref path) => { - if generated_code(path.span) { - return None; - } - sub_span = self.span_utils.sub_span_for_type_name(path.span); - type_data = self.lookup_ref_id(typ.id).map(|id| { - TypeRefData { - span: sub_span.unwrap(), - scope: parent, - ref_id: Some(id), - qualname: String::new() // FIXME: generate the real qualname - } - }); - } - _ => { - // Less useful case, impl for a compound type. - let span = typ.span; - sub_span = self.span_utils.sub_span_for_type_name(span).or(Some(span)); + if generated_code(path.span) { + return None; } + let sub_span = self.span_utils.sub_span_for_type_name(path.span); + filter!(self.span_utils, sub_span, typ.span, None); + + let type_data = self.lookup_ref_id(typ.id); + type_data.map(|type_data| Data::RelationData(Relation { + kind: RelationKind::Impl, + span: self.span_from_span(sub_span.unwrap()), + from: id_from_def_id(type_data), + to: trait_ref.as_ref() + .and_then(|t| self.lookup_ref_id(t.ref_id)) + .map(id_from_def_id) + .unwrap_or(null_id()), + })) + } else { + None } - - let trait_data = trait_ref.as_ref() - .and_then(|tr| self.get_trait_ref_data(tr, parent)); - - filter!(self.span_utils, sub_span, typ.span, None); - Some(Data::ImplData(ImplData2 { - id: item.id, - span: sub_span.unwrap(), - scope: parent, - trait_ref: trait_data, - self_ref: type_data, - })) } _ => { // FIXME @@ -337,7 +351,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { pub fn get_field_data(&self, field: &ast::StructField, scope: NodeId) - -> Option { + -> Option { if let Some(ident) = field.ident { let name = ident.to_string(); let qualname = format!("::{}::{}", self.tcx.node_path_str(scope), ident); @@ -346,32 +360,23 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { let def_id = self.tcx.hir.local_def_id(field.id); let typ = self.tcx.type_of(def_id).to_string(); - let span = field.span; - let text = self.span_utils.snippet(field.span); - let ident_start = text.find(&name).unwrap(); - let ident_end = ident_start + name.len(); - let sig = Signature { - span: span, - text: text, - ident_start: ident_start, - ident_end: ident_end, - defs: vec![], - refs: vec![], - }; - Some(VariableData { - id: field.id, - kind: VariableKind::Field, - name: name, - qualname: qualname, - span: sub_span.unwrap(), - scope: scope, - parent: Some(make_def_id(scope, &self.tcx.hir)), - value: "".to_owned(), - type_value: typ, - visibility: From::from(&field.vis), + + let id = id_from_node_id(field.id, self); + let span = self.span_from_span(sub_span.unwrap()); + + Some(Def { + kind: DefKind::Field, + id, + span, + name, + qualname, + value: typ, + parent: Some(id_from_node_id(scope, self)), + children: vec![], + decl_id: None, docs: docs_for_attrs(&field.attrs), - sig: Some(sig), - attributes: field.attrs.clone(), + sig: sig::field_signature(field, self), + attributes: lower_attributes(field.attrs.clone(), self), }) } else { None @@ -380,11 +385,14 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { // FIXME would be nice to take a MethodItem here, but the ast provides both // trait and impl flavours, so the caller must do the disassembly. - pub fn get_method_data(&self, id: ast::NodeId, - name: ast::Name, span: Span) -> Option { + pub fn get_method_data(&self, + id: ast::NodeId, + name: ast::Name, + span: Span) + -> Option { // The qualname for a method is the trait name or name of the struct in an impl in // which the method is declared in, followed by the method's name. - let (qualname, parent_scope, decl_id, vis, docs, attributes) = + let (qualname, parent_scope, decl_id, docs, attributes) = match self.tcx.impl_of_method(self.tcx.hir.local_def_id(id)) { Some(impl_id) => match self.tcx.hir.get_if_local(impl_id) { Some(Node::NodeItem(item)) => { @@ -393,7 +401,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { let mut result = String::from("<"); result.push_str(&self.tcx.hir.node_to_pretty_string(ty.id)); - let trait_id = self.tcx.trait_id_of_impl(impl_id); + let mut trait_id = self.tcx.trait_id_of_impl(impl_id); let mut decl_id = None; if let Some(def_id) = trait_id { result.push_str(" as "); @@ -401,11 +409,16 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { self.tcx.associated_items(def_id) .find(|item| item.name == name) .map(|item| decl_id = Some(item.def_id)); + } else { + if let Some(NodeItem(item)) = self.tcx.hir.find(id) { + if let hir::ItemImpl(_, _, _, _, _, ref ty, _) = item.node { + trait_id = self.lookup_ref_id(ty.id); + } + } } result.push_str(">"); (result, trait_id, decl_id, - From::from(&item.vis), docs_for_attrs(&item.attrs), item.attrs.to_vec()) } @@ -431,7 +444,6 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { Some(Node::NodeItem(item)) => { (format!("::{}", self.tcx.item_path_str(def_id)), Some(def_id), None, - From::from(&item.vis), docs_for_attrs(&item.attrs), item.attrs.to_vec()) } @@ -459,40 +471,26 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { let sub_span = self.span_utils.sub_span_after_keyword(span, keywords::Fn); filter!(self.span_utils, sub_span, span, None); - let name = name.to_string(); - let text = self.span_utils.signature_string_for_span(span); - let ident_start = text.find(&name).unwrap(); - let ident_end = ident_start + name.len(); - let sig = Signature { - span: span, - text: text, - ident_start: ident_start, - ident_end: ident_end, - defs: vec![], - refs: vec![], - }; - - Some(FunctionData { - id: id, - name: name, - qualname: qualname, - declaration: decl_id, - span: sub_span.unwrap(), - scope: self.enclosing_scope(id), + Some(Def { + kind: DefKind::Method, + id: id_from_node_id(id, self), + span: self.span_from_span(sub_span.unwrap()), + name: name.to_string(), + qualname, // FIXME you get better data here by using the visitor. value: String::new(), - visibility: vis, - parent: parent_scope, - docs: docs, - sig: sig, - attributes: attributes, + parent: parent_scope.map(|id| id_from_def_id(id)), + children: vec![], + decl_id: decl_id.map(|id| id_from_def_id(id)), + docs, + sig: None, + attributes: lower_attributes(attributes, self), }) } pub fn get_trait_ref_data(&self, - trait_ref: &ast::TraitRef, - parent: NodeId) - -> Option { + trait_ref: &ast::TraitRef) + -> Option { self.lookup_ref_id(trait_ref.ref_id).and_then(|def_id| { let span = trait_ref.path.span; if generated_code(span) { @@ -500,11 +498,11 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } let sub_span = self.span_utils.sub_span_for_type_name(span).or(Some(span)); filter!(self.span_utils, sub_span, span, None); - Some(TypeRefData { - span: sub_span.unwrap(), - scope: parent, - ref_id: Some(def_id), - qualname: String::new() // FIXME: generate the real qualname + let span = self.span_from_span(sub_span.unwrap()); + Some(Ref { + kind: RefKind::Type, + span, + ref_id: id_from_def_id(def_id), }) }) } @@ -530,11 +528,11 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { let f = def.struct_variant().field_named(ident.node.name); let sub_span = self.span_utils.span_for_last_ident(expr.span); filter!(self.span_utils, sub_span, expr.span, None); - return Some(Data::VariableRefData(VariableRefData { - name: ident.node.to_string(), - span: sub_span.unwrap(), - scope: self.enclosing_scope(expr.id), - ref_id: f.did, + let span = self.span_from_span(sub_span.unwrap()); + return Some(Data::RefData(Ref { + kind: RefKind::Variable, + span, + ref_id: id_from_def_id(f.did), })); } _ => { @@ -548,11 +546,11 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { ty::TyAdt(def, _) if !def.is_enum() => { let sub_span = self.span_utils.span_for_last_ident(path.span); filter!(self.span_utils, sub_span, path.span, None); - Some(Data::TypeRefData(TypeRefData { - span: sub_span.unwrap(), - scope: self.enclosing_scope(expr.id), - ref_id: Some(def.did), - qualname: String::new() // FIXME: generate the real qualname + let span = self.span_from_span(sub_span.unwrap()); + Some(Data::RefData(Ref { + kind: RefKind::Type, + span, + ref_id: id_from_def_id(def.did), })) } _ => { @@ -571,16 +569,15 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { }; let sub_span = self.span_utils.sub_span_for_meth_name(expr.span); filter!(self.span_utils, sub_span, expr.span, None); - let parent = self.enclosing_scope(expr.id); - Some(Data::MethodCallData(MethodCallData { - span: sub_span.unwrap(), - scope: parent, - ref_id: def_id, - decl_id: decl_id, + let span = self.span_from_span(sub_span.unwrap()); + Some(Data::RefData(Ref { + kind: RefKind::Function, + span, + ref_id: def_id.or(decl_id).map(|id| id_from_def_id(id)).unwrap_or(null_id()), })) } ast::ExprKind::Path(_, ref path) => { - self.get_path_data(expr.id, path) + self.get_path_data(expr.id, path).map(|d| Data::RefData(d)) } _ => { // FIXME @@ -589,7 +586,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } } - pub fn get_path_def(&self, id: NodeId) -> Def { + pub fn get_path_def(&self, id: NodeId) -> HirDef { match self.tcx.hir.get(id) { Node::NodeTraitRef(tr) => tr.path.def, @@ -605,7 +602,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } Node::NodeLocal(&hir::Pat { node: hir::PatKind::Binding(_, def_id, ..), .. }) => { - Def::Local(def_id) + HirDef::Local(def_id) } Node::NodeTy(ty) => { @@ -618,58 +615,58 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { for item in self.tcx.associated_items(proj.trait_ref.def_id) { if item.kind == ty::AssociatedKind::Type { if item.name == proj.item_name(self.tcx) { - return Def::AssociatedTy(item.def_id); + return HirDef::AssociatedTy(item.def_id); } } } } - Def::Err + HirDef::Err } } } else { - Def::Err + HirDef::Err } } - _ => Def::Err + _ => HirDef::Err } } - pub fn get_path_data(&self, id: NodeId, path: &ast::Path) -> Option { + pub fn get_path_data(&self, id: NodeId, path: &ast::Path) -> Option { let def = self.get_path_def(id); let sub_span = self.span_utils.span_for_last_ident(path.span); filter!(self.span_utils, sub_span, path.span, None); match def { - Def::Upvar(..) | - Def::Local(..) | - Def::Static(..) | - Def::Const(..) | - Def::AssociatedConst(..) | - Def::StructCtor(..) | - Def::VariantCtor(..) => { - Some(Data::VariableRefData(VariableRefData { - name: self.span_utils.snippet(sub_span.unwrap()), - span: sub_span.unwrap(), - scope: self.enclosing_scope(id), - ref_id: def.def_id(), - })) + HirDef::Upvar(..) | + HirDef::Local(..) | + HirDef::Static(..) | + HirDef::Const(..) | + HirDef::AssociatedConst(..) | + HirDef::StructCtor(..) | + HirDef::VariantCtor(..) => { + let span = self.span_from_span(sub_span.unwrap()); + Some(Ref { + kind: RefKind::Variable, + span, + ref_id: id_from_def_id(def.def_id()), + }) } - Def::Struct(def_id) | - Def::Variant(def_id, ..) | - Def::Union(def_id) | - Def::Enum(def_id) | - Def::TyAlias(def_id) | - Def::AssociatedTy(def_id) | - Def::Trait(def_id) | - Def::TyParam(def_id) => { - Some(Data::TypeRefData(TypeRefData { - span: sub_span.unwrap(), - ref_id: Some(def_id), - scope: self.enclosing_scope(id), - qualname: String::new() // FIXME: generate the real qualname - })) + HirDef::Struct(def_id) | + HirDef::Variant(def_id, ..) | + HirDef::Union(def_id) | + HirDef::Enum(def_id) | + HirDef::TyAlias(def_id) | + HirDef::AssociatedTy(def_id) | + HirDef::Trait(def_id) | + HirDef::TyParam(def_id) => { + let span = self.span_from_span(sub_span.unwrap()); + Some(Ref { + kind: RefKind::Type, + span, + ref_id: id_from_def_id(def_id), + }) } - Def::Method(decl_id) => { + HirDef::Method(decl_id) => { let sub_span = self.span_utils.sub_span_for_meth_name(path.span); filter!(self.span_utils, sub_span, path.span, None); let def_id = if decl_id.is_local() { @@ -680,60 +677,60 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } else { None }; - Some(Data::MethodCallData(MethodCallData { - span: sub_span.unwrap(), - scope: self.enclosing_scope(id), - ref_id: def_id, - decl_id: Some(decl_id), - })) + let span = self.span_from_span(sub_span.unwrap()); + Some(Ref { + kind: RefKind::Function, + span, + ref_id: id_from_def_id(def_id.unwrap_or(decl_id)), + }) } - Def::Fn(def_id) => { - Some(Data::FunctionCallData(FunctionCallData { - ref_id: def_id, - span: sub_span.unwrap(), - scope: self.enclosing_scope(id), - })) + HirDef::Fn(def_id) => { + let span = self.span_from_span(sub_span.unwrap()); + Some(Ref { + kind: RefKind::Function, + span, + ref_id: id_from_def_id(def_id), + }) } - Def::Mod(def_id) => { - Some(Data::ModRefData(ModRefData { - ref_id: Some(def_id), - span: sub_span.unwrap(), - scope: self.enclosing_scope(id), - qualname: String::new() // FIXME: generate the real qualname - })) + HirDef::Mod(def_id) => { + let span = self.span_from_span(sub_span.unwrap()); + Some(Ref { + kind: RefKind::Mod, + span, + ref_id: id_from_def_id(def_id), + }) } - Def::PrimTy(..) | - Def::SelfTy(..) | - Def::Label(..) | - Def::Macro(..) | - Def::GlobalAsm(..) | - Def::Err => None, + HirDef::PrimTy(..) | + HirDef::SelfTy(..) | + HirDef::Label(..) | + HirDef::Macro(..) | + HirDef::GlobalAsm(..) | + HirDef::Err => None, } } pub fn get_field_ref_data(&self, field_ref: &ast::Field, - variant: &ty::VariantDef, - parent: NodeId) - -> Option { + variant: &ty::VariantDef) + -> Option { let f = variant.field_named(field_ref.ident.node.name); // We don't really need a sub-span here, but no harm done let sub_span = self.span_utils.span_for_last_ident(field_ref.ident.span); filter!(self.span_utils, sub_span, field_ref.ident.span, None); - Some(VariableRefData { - name: field_ref.ident.node.to_string(), - span: sub_span.unwrap(), - scope: parent, - ref_id: f.did, + let span = self.span_from_span(sub_span.unwrap()); + Some(Ref { + kind: RefKind::Variable, + span, + ref_id: id_from_def_id(f.did), }) } - /// Attempt to return MacroUseData for any AST node. + /// Attempt to return MacroRef for any AST node. /// /// For a given piece of AST defined by the supplied Span and NodeId, /// returns None if the node is not macro-generated or the span is malformed, - /// else uses the expansion callsite and callee to return some MacroUseData. - pub fn get_macro_use_data(&self, span: Span, id: NodeId) -> Option { + /// else uses the expansion callsite and callee to return some MacroRef. + pub fn get_macro_use_data(&self, span: Span) -> Option { if !generated_code(span) { return None; } @@ -741,6 +738,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { // nested expansions and ensure we only generate data for source-visible // macro uses. let callsite = span.source_callsite(); + let callsite_span = self.span_from_span(callsite); let callee = option_try!(span.source_callee()); let callee_span = option_try!(callee.span); @@ -754,68 +752,29 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { // when read in, and no longer correspond to the source. if let Some(mac) = self.tcx.sess.imported_macro_spans.borrow().get(&callee_span) { let &(ref mac_name, mac_span) = mac; - return Some(MacroUseData { - span: callsite, - name: mac_name.clone(), - callee_span: mac_span, - scope: self.enclosing_scope(id), - imported: true, - qualname: String::new()// FIXME: generate the real qualname - }); + let mac_span = self.span_from_span(mac_span); + return Some(MacroRef { + span: callsite_span, + qualname: mac_name.clone(), // FIXME: generate the real qualname + callee_span: mac_span, + }); } - Some(MacroUseData { - span: callsite, - name: callee.name().to_string(), - callee_span: callee_span, - scope: self.enclosing_scope(id), - imported: false, - qualname: String::new() // FIXME: generate the real qualname + let callee_span = self.span_from_span(callee_span); + Some(MacroRef { + span: callsite_span, + qualname: callee.name().to_string(), // FIXME: generate the real qualname + callee_span, }) } - pub fn get_data_for_id(&self, _id: &NodeId) -> Data { - // FIXME - bug!(); - } - fn lookup_ref_id(&self, ref_id: NodeId) -> Option { match self.get_path_def(ref_id) { - Def::PrimTy(_) | Def::SelfTy(..) | Def::Err => None, + HirDef::PrimTy(_) | HirDef::SelfTy(..) | HirDef::Err => None, def => Some(def.def_id()), } } - fn sig_base(&self, item: &ast::Item) -> Signature { - let text = self.span_utils.signature_string_for_span(item.span); - let name = item.ident.to_string(); - let ident_start = text.find(&name).expect("Name not in signature?"); - let ident_end = ident_start + name.len(); - Signature { - span: Span { hi: item.span.lo + BytePos(text.len() as u32), ..item.span }, - text: text, - ident_start: ident_start, - ident_end: ident_end, - defs: vec![], - refs: vec![], - } - } - - fn sig_base_extern(&self, item: &ast::ForeignItem) -> Signature { - let text = self.span_utils.signature_string_for_span(item.span); - let name = item.ident.to_string(); - let ident_start = text.find(&name).expect("Name not in signature?"); - let ident_end = ident_start + name.len(); - Signature { - span: Span { hi: item.span.lo + BytePos(text.len() as u32), ..item.span }, - text: text, - ident_start: ident_start, - ident_end: ident_end, - defs: vec![], - refs: vec![], - } - } - #[inline] pub fn enclosing_scope(&self, id: NodeId) -> NodeId { self.tcx.hir.get_enclosing_scope(id).unwrap_or(CRATE_NODE_ID) @@ -853,7 +812,7 @@ fn make_signature(decl: &ast::FnDecl, generics: &ast::Generics) -> String { // An AST visitor for collecting paths from patterns. struct PathCollector { // The Row field identifies the kind of pattern. - collected_paths: Vec<(NodeId, ast::Path, ast::Mutability, recorder::Row)>, + collected_paths: Vec<(NodeId, ast::Path, ast::Mutability)>, } impl PathCollector { @@ -867,12 +826,12 @@ impl<'a> Visitor<'a> for PathCollector { match p.node { PatKind::Struct(ref path, ..) => { self.collected_paths.push((p.id, path.clone(), - ast::Mutability::Mutable, recorder::TypeRef)); + ast::Mutability::Mutable)); } PatKind::TupleStruct(ref path, ..) | PatKind::Path(_, ref path) => { self.collected_paths.push((p.id, path.clone(), - ast::Mutability::Mutable, recorder::VarRef)); + ast::Mutability::Mutable)); } PatKind::Ident(bm, ref path1, _) => { debug!("PathCollector, visit ident in pat {}: {:?} {:?}", @@ -888,7 +847,7 @@ impl<'a> Visitor<'a> for PathCollector { }; // collect path for either visit_local or visit_arm let path = ast::Path::from_ident(path1.span, path1.node); - self.collected_paths.push((p.id, path, immut, recorder::VarRef)); + self.collected_paths.push((p.id, path, immut)); } _ => {} } @@ -917,17 +876,13 @@ fn docs_for_attrs(attrs: &[Attribute]) -> String { #[derive(Clone, Copy, Debug, RustcEncodable)] pub enum Format { - Csv, Json, JsonApi, } impl Format { fn extension(&self) -> &'static str { - match *self { - Format::Csv => ".csv", - Format::Json | Format::JsonApi => ".json", - } + ".json" } } @@ -1010,7 +965,6 @@ impl<'a> SaveHandler for DumpHandler<'a> { let output = &mut self.output_file(&save_ctxt.tcx.sess); match self.format { - Format::Csv => dump!(CsvDumper::new(output)), Format::Json => dump!(JsonDumper::new(output)), Format::JsonApi => dump!(JsonApiDumper::new(output)), } @@ -1076,6 +1030,48 @@ fn escape(s: String) -> String { // Helper function to determine if a span came from a // macro expansion or syntax extension. -pub fn generated_code(span: Span) -> bool { +fn generated_code(span: Span) -> bool { span.ctxt != NO_EXPANSION || span == DUMMY_SP } + +// DefId::index is a newtype and so the JSON serialisation is ugly. Therefore +// we use our own Id which is the same, but without the newtype. +fn id_from_def_id(id: DefId) -> rls_data::Id { + rls_data::Id { + krate: id.krate.as_u32(), + index: id.index.as_u32(), + } +} + +fn id_from_node_id(id: NodeId, scx: &SaveContext) -> rls_data::Id { + let def_id = scx.tcx.hir.opt_local_def_id(id); + def_id.map(|id| id_from_def_id(id)).unwrap_or_else(null_id) +} + +fn null_id() -> rls_data::Id { + rls_data::Id { + krate: u32::max_value(), + index: u32::max_value(), + } +} + +fn lower_attributes(attrs: Vec, scx: &SaveContext) -> Vec { + attrs.into_iter() + // Only retain real attributes. Doc comments are lowered separately. + .filter(|attr| attr.path != "doc") + .map(|mut attr| { + // Remove the surrounding '#[..]' or '#![..]' of the pretty printed + // attribute. First normalize all inner attribute (#![..]) to outer + // ones (#[..]), then remove the two leading and the one trailing character. + attr.style = ast::AttrStyle::Outer; + let value = pprust::attribute_to_string(&attr); + // This str slicing works correctly, because the leading and trailing characters + // are in the ASCII range and thus exactly one byte each. + let value = value[2..value.len()-1].to_string(); + + rls_data::Attribute { + value: value, + span: scx.span_from_span(attr.span), + } + }).collect() +} diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs new file mode 100644 index 000000000000..1d03ab1383af --- /dev/null +++ b/src/librustc_save_analysis/sig.rs @@ -0,0 +1,925 @@ +// 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. + +// A signature is a string representation of an item's type signature, excluding +// any body. It also includes ids for any defs or refs in the signature. For +// example: +// +// ``` +// fn foo(x: String) { +// println!("{}", x); +// } +// ``` +// The signature string is something like "fn foo(x: String) {}" and the signature +// will have defs for `foo` and `x` and a ref for `String`. +// +// All signature text should parse in the correct context (i.e., in a module or +// impl, etc.). Clients may want to trim trailing `{}` or `;`. The text of a +// signature is not guaranteed to be stable (it may improve or change as the +// syntax changes, or whitespace or punctuation may change). It is also likely +// not to be pretty - no attempt is made to prettify the text. It is recommended +// that clients run the text through Rustfmt. +// +// This module generates Signatures for items by walking the AST and looking up +// references. +// +// Signatures do not include visibility info. I'm not sure if this is a feature +// or an ommission (FIXME). +// +// FIXME where clauses need implementing, defs/refs in generics are mostly missing. + +use {SaveContext, id_from_def_id, id_from_node_id}; + +use rls_data::{Signature, SigElement}; + +use rustc::hir::def::Def; +use syntax::ast::{self, NodeId}; +use syntax::print::pprust; + + +pub fn item_signature(item: &ast::Item, scx: &SaveContext) -> Option { + item.make(0, None, scx).ok() +} + +pub fn foreign_item_signature(item: &ast::ForeignItem, scx: &SaveContext) -> Option { + item.make(0, None, scx).ok() +} + +/// Signature for a struct or tuple field declaration. +/// Does not include a trailing comma. +pub fn field_signature(field: &ast::StructField, scx: &SaveContext) -> Option { + field.make(0, None, scx).ok() +} + +/// Does not include a trailing comma. +pub fn variant_signature(variant: &ast::Variant, scx: &SaveContext) -> Option { + variant.node.make(0, None, scx).ok() +} + +pub fn method_signature(id: NodeId, + ident: ast::Ident, + m: &ast::MethodSig, + scx: &SaveContext) + -> Option { + make_method_signature(id, ident, m, scx).ok() +} + +pub fn assoc_const_signature(id: NodeId, + ident: ast::Name, + ty: &ast::Ty, + default: Option<&ast::Expr>, + scx: &SaveContext) + -> Option { + make_assoc_const_signature(id, ident, ty, default, scx).ok() +} + +pub fn assoc_type_signature(id: NodeId, + ident: ast::Ident, + bounds: Option<&ast::TyParamBounds>, + default: Option<&ast::Ty>, + scx: &SaveContext) + -> Option { + make_assoc_type_signature(id, ident, bounds, default, scx).ok() +} + +type Result = ::std::result::Result; + +trait Sig { + fn make(&self, offset: usize, id: Option, scx: &SaveContext) -> Result; +} + +fn extend_sig(mut sig: Signature, + text: String, + defs: Vec, + refs: Vec) + -> Signature { + sig.text = text; + sig.defs.extend(defs.into_iter()); + sig.refs.extend(refs.into_iter()); + sig +} + +fn replace_text(mut sig: Signature, text: String) -> Signature { + sig.text = text; + sig +} + +fn merge_sigs(text: String, sigs: Vec) -> Signature { + let mut result = Signature { + text, + defs: vec![], + refs: vec![], + }; + + let (defs, refs): (Vec<_>, Vec<_>) = sigs.into_iter().map(|s| (s.defs, s.refs)).unzip(); + + result.defs.extend(defs.into_iter().flat_map(|ds| ds.into_iter())); + result.refs.extend(refs.into_iter().flat_map(|rs| rs.into_iter())); + + result +} + +fn text_sig(text: String) -> Signature { + Signature { + text: text, + defs: vec![], + refs: vec![], + } +} + +impl Sig for ast::Ty { + fn make(&self, offset: usize, _parent_id: Option, scx: &SaveContext) -> Result { + let id = Some(self.id); + match self.node { + ast::TyKind::Slice(ref ty) => { + let nested = ty.make(offset + 1, id, scx)?; + let text = format!("[{}]", nested.text); + Ok(replace_text(nested, text)) + } + ast::TyKind::Ptr(ref mt) => { + let prefix = match mt.mutbl { + ast::Mutability::Mutable => "*mut ", + ast::Mutability::Immutable => "*const ", + }; + let nested = mt.ty.make(offset + prefix.len(), id, scx)?; + let text = format!("{}{}", prefix, nested.text); + Ok(replace_text(nested, text)) + } + ast::TyKind::Rptr(ref lifetime, ref mt) => { + let mut prefix = "&".to_owned(); + if let &Some(ref l) = lifetime { + prefix.push_str(&l.ident.to_string()); + prefix.push(' '); + } + if let ast::Mutability::Mutable = mt.mutbl { + prefix.push_str("mut "); + }; + + let nested = mt.ty.make(offset + prefix.len(), id, scx)?; + let text = format!("{}{}", prefix, nested.text); + Ok(replace_text(nested, text)) + } + ast::TyKind::Never => { + Ok(text_sig("!".to_owned())) + }, + ast::TyKind::Tup(ref ts) => { + let mut text = "(".to_owned(); + let mut defs = vec![]; + let mut refs = vec![]; + for t in ts { + let nested = t.make(offset + text.len(), id, scx)?; + text.push_str(&nested.text); + text.push(','); + defs.extend(nested.defs.into_iter()); + refs.extend(nested.refs.into_iter()); + } + text.push(')'); + Ok(Signature { text, defs, refs }) + } + ast::TyKind::Paren(ref ty) => { + let nested = ty.make(offset + 1, id, scx)?; + let text = format!("({})", nested.text); + Ok(replace_text(nested, text)) + } + ast::TyKind::BareFn(ref f) => { + let mut text = String::new(); + if !f.lifetimes.is_empty() { + // FIXME defs, bounds on lifetimes + text.push_str("for<"); + text.push_str(&f.lifetimes.iter().map(|l| + l.lifetime.ident.to_string()).collect::>().join(", ")); + text.push('>'); + } + + if f.unsafety == ast::Unsafety::Unsafe { + text.push_str("unsafe "); + } + if f.abi != ::syntax::abi::Abi::Rust { + text.push_str("extern"); + text.push_str(&f.abi.to_string()); + text.push(' '); + } + text.push_str("fn("); + + let mut defs = vec![]; + let mut refs = vec![]; + for i in &f.decl.inputs { + let nested = i.ty.make(offset + text.len(), Some(i.id), scx)?; + text.push_str(&nested.text); + text.push(','); + defs.extend(nested.defs.into_iter()); + refs.extend(nested.refs.into_iter()); + } + text.push(')'); + if let ast::FunctionRetTy::Ty(ref t) = f.decl.output { + text.push_str(" -> "); + let nested = t.make(offset + text.len(), None, scx)?; + text.push_str(&nested.text); + text.push(','); + defs.extend(nested.defs.into_iter()); + refs.extend(nested.refs.into_iter()); + } + + Ok(Signature { text, defs, refs }) + } + ast::TyKind::Path(None, ref path) => { + path.make(offset, id, scx) + } + ast::TyKind::Path(Some(ref qself), ref path) => { + let nested_ty = qself.ty.make(offset + 1, id, scx)?; + let prefix = if qself.position == 0 { + format!("<{}>::", nested_ty.text) + } else if qself.position == 1 { + let first = pprust::path_segment_to_string(&path.segments[0]); + format!("<{} as {}>::", nested_ty.text, first) + } else { + // FIXME handle path instead of elipses. + format!("<{} as ...>::", nested_ty.text) + }; + + let name = pprust::path_segment_to_string(path.segments.last().ok_or("Bad path")?); + let def = scx.get_path_def(id.ok_or("Missing id for Path")?); + let id = id_from_def_id(def.def_id()); + if path.segments.len() - qself.position == 1 { + let start = offset + prefix.len(); + let end = start + name.len(); + + Ok(Signature { + text: prefix + &name, + defs: vec![], + refs: vec![SigElement { id, start, end }], + }) + } else { + let start = offset + prefix.len() + 5; + let end = start + name.len(); + // FIXME should put the proper path in there, not elipses. + Ok(Signature { + text: prefix + "...::" + &name, + defs: vec![], + refs: vec![SigElement { id, start, end }], + }) + } + } + ast::TyKind::TraitObject(ref bounds) => { + // FIXME recurse into bounds + let nested = pprust::bounds_to_string(bounds); + Ok(text_sig(nested)) + } + ast::TyKind::ImplTrait(ref bounds) => { + // FIXME recurse into bounds + let nested = pprust::bounds_to_string(bounds); + Ok(text_sig(format!("impl {}", nested))) + } + ast::TyKind::Array(ref ty, ref v) => { + let nested_ty = ty.make(offset + 1, id, scx)?; + let expr = pprust::expr_to_string(v).replace('\n', " "); + let text = format!("[{}; {}]", nested_ty.text, expr); + Ok(replace_text(nested_ty, text)) + } + ast::TyKind::Typeof(_) | + ast::TyKind::Infer | + ast::TyKind::Err | + ast::TyKind::ImplicitSelf | + ast::TyKind::Mac(_) => Err("Ty"), + } + } +} + +impl Sig for ast::Item { + fn make(&self, offset: usize, _parent_id: Option, scx: &SaveContext) -> Result { + let id = Some(self.id); + + match self.node { + ast::ItemKind::Static(ref ty, m, ref expr) => { + let mut text = "static ".to_owned(); + if m == ast::Mutability::Mutable { + text.push_str("mut "); + } + let name = self.ident.to_string(); + let defs = vec![SigElement { + id: id_from_node_id(self.id, scx), + start: offset + text.len(), + end: offset + text.len() + name.len(), + }]; + text.push_str(&name); + text.push_str(": "); + + let ty = ty.make(offset + text.len(), id, scx)?; + text.push_str(&ty.text); + text.push_str(" = "); + + let expr = pprust::expr_to_string(expr).replace('\n', " "); + text.push_str(&expr); + text.push(';'); + + Ok(extend_sig(ty, text, defs, vec![])) + } + ast::ItemKind::Const(ref ty, ref expr) => { + let mut text = "const ".to_owned(); + let name = self.ident.to_string(); + let defs = vec![SigElement { + id: id_from_node_id(self.id, scx), + start: offset + text.len(), + end: offset + text.len() + name.len(), + }]; + text.push_str(&name); + text.push_str(": "); + + let ty = ty.make(offset + text.len(), id, scx)?; + text.push_str(&ty.text); + text.push_str(" = "); + + let expr = pprust::expr_to_string(expr).replace('\n', " "); + text.push_str(&expr); + text.push(';'); + + Ok(extend_sig(ty, text, defs, vec![])) + } + ast::ItemKind::Fn(ref decl, unsafety, constness, abi, ref generics, _) => { + let mut text = String::new(); + if constness.node == ast::Constness::Const { + text.push_str("const "); + } + if unsafety == ast::Unsafety::Unsafe { + text.push_str("unsafe "); + } + if abi != ::syntax::abi::Abi::Rust { + text.push_str("extern"); + text.push_str(&abi.to_string()); + text.push(' '); + } + text.push_str("fn "); + + let mut sig = name_and_generics(text, + offset, + generics, + self.id, + self.ident, + scx)?; + + sig.text.push('('); + for i in &decl.inputs { + // FIXME shoudl descend into patterns to add defs. + sig.text.push_str(&pprust::pat_to_string(&i.pat)); + sig.text.push_str(": "); + let nested = i.ty.make(offset + sig.text.len(), Some(i.id), scx)?; + sig.text.push_str(&nested.text); + sig.text.push(','); + sig.defs.extend(nested.defs.into_iter()); + sig.refs.extend(nested.refs.into_iter()); + } + sig.text.push(')'); + + if let ast::FunctionRetTy::Ty(ref t) = decl.output { + sig.text.push_str(" -> "); + let nested = t.make(offset + sig.text.len(), None, scx)?; + sig.text.push_str(&nested.text); + sig.defs.extend(nested.defs.into_iter()); + sig.refs.extend(nested.refs.into_iter()); + } + sig.text.push_str(" {}"); + + Ok(sig) + } + ast::ItemKind::Mod(ref _mod) => { + let mut text = "mod ".to_owned(); + let name = self.ident.to_string(); + let defs = vec![SigElement { + id: id_from_node_id(self.id, scx), + start: offset + text.len(), + end: offset + text.len() + name.len(), + }]; + text.push_str(&name); + // Could be either `mod foo;` or `mod foo { ... }`, but we'll just puck one. + text.push(';'); + + Ok(Signature { + text, + defs, + refs: vec![], + }) + } + ast::ItemKind::Ty(ref ty, ref generics) => { + let text = "type ".to_owned(); + let mut sig = name_and_generics(text, + offset, + generics, + self.id, + self.ident, + scx)?; + + sig.text.push_str(" = "); + let ty = ty.make(offset + sig.text.len(), id, scx)?; + sig.text.push_str(&ty.text); + sig.text.push(';'); + + Ok(merge_sigs(sig.text.clone(), vec![sig, ty])) + } + ast::ItemKind::Enum(_, ref generics) => { + let text = "enum ".to_owned(); + let mut sig = name_and_generics(text, + offset, + generics, + self.id, + self.ident, + scx)?; + sig.text.push_str(" {}"); + Ok(sig) + } + ast::ItemKind::Struct(_, ref generics) => { + let text = "struct ".to_owned(); + let mut sig = name_and_generics(text, + offset, + generics, + self.id, + self.ident, + scx)?; + sig.text.push_str(" {}"); + Ok(sig) + } + ast::ItemKind::Union(_, ref generics) => { + let text = "union ".to_owned(); + let mut sig = name_and_generics(text, + offset, + generics, + self.id, + self.ident, + scx)?; + sig.text.push_str(" {}"); + Ok(sig) + } + ast::ItemKind::Trait(unsafety, ref generics, ref bounds, _) => { + let mut text = String::new(); + if unsafety == ast::Unsafety::Unsafe { + text.push_str("unsafe "); + } + text.push_str("trait "); + let mut sig = name_and_generics(text, + offset, + generics, + self.id, + self.ident, + scx)?; + + if !bounds.is_empty() { + sig.text.push_str(": "); + sig.text.push_str(&pprust::bounds_to_string(bounds)); + } + // FIXME where clause + sig.text.push_str(" {}"); + + Ok(sig) + } + ast::ItemKind::DefaultImpl(unsafety, ref trait_ref) => { + let mut text = String::new(); + if unsafety == ast::Unsafety::Unsafe { + text.push_str("unsafe "); + } + text.push_str("impl "); + let trait_sig = trait_ref.path.make(offset + text.len(), id, scx)?; + text.push_str(&trait_sig.text); + text.push_str(" for .. {}"); + Ok(replace_text(trait_sig, text)) + } + ast::ItemKind::Impl(unsafety, + polarity, + defaultness, + ref generics, + ref opt_trait, + ref ty, + _) => { + let mut text = String::new(); + if let ast::Defaultness::Default = defaultness { + text.push_str("default "); + } + if unsafety == ast::Unsafety::Unsafe { + text.push_str("unsafe "); + } + text.push_str("impl"); + + let generics_sig = generics.make(offset + text.len(), id, scx)?; + text.push_str(&generics_sig.text); + + text.push(' '); + + let trait_sig = if let Some(ref t) = *opt_trait { + if polarity == ast::ImplPolarity::Negative { + text.push('!'); + } + let trait_sig = t.path.make(offset + text.len(), id, scx)?; + text.push_str(&trait_sig.text); + text.push_str(" for "); + trait_sig + } else { + text_sig(String::new()) + }; + + let ty_sig = ty.make(offset + text.len(), id, scx)?; + text.push_str(&ty_sig.text); + + text.push_str(" {}"); + + Ok(merge_sigs(text, vec![generics_sig, trait_sig, ty_sig])) + + // FIXME where clause + } + ast::ItemKind::ForeignMod(_) => Err("extern mod"), + ast::ItemKind::GlobalAsm(_) => Err("glboal asm"), + ast::ItemKind::ExternCrate(_) => Err("extern crate"), + // FIXME should implement this (e.g., pub use). + ast::ItemKind::Use(_) => Err("import"), + ast::ItemKind::Mac(..) | + ast::ItemKind::MacroDef(_) => Err("Macro"), + } + } +} + +impl Sig for ast::Path { + fn make(&self, offset: usize, id: Option, scx: &SaveContext) -> Result { + let def = scx.get_path_def(id.ok_or("Missing id for Path")?); + + let (name, start, end) = match def { + Def::Label(..) | + Def::PrimTy(..) | + Def::SelfTy(..) | + Def::Err => { + return Ok(Signature { + text: pprust::path_to_string(self), + defs: vec![], + refs: vec![], + }) + } + Def::AssociatedConst(..) | + Def::Variant(..) | + Def::VariantCtor(..) => { + let len = self.segments.len(); + if len < 2 { + return Err("Bad path"); + } + // FIXME: really we should descend into the generics here and add SigElements for + // them. + // FIXME: would be nice to have a def for the first path segment. + let seg1 = pprust::path_segment_to_string(&self.segments[len - 2]); + let seg2 = pprust::path_segment_to_string(&self.segments[len - 1]); + let start = offset + seg1.len() + 2; + (format!("{}::{}", seg1, seg2), start, start + seg2.len()) + } + _ => { + let name = pprust::path_segment_to_string(self.segments.last().ok_or("Bad path")?); + let end = offset + name.len(); + (name, offset, end) + } + }; + + let id = id_from_def_id(def.def_id()); + Ok(Signature { + text: name, + defs: vec![], + refs: vec![SigElement { id, start, end }], + }) + } +} + +// This does not cover the where clause, which must be processed separately. +impl Sig for ast::Generics { + fn make(&self, offset: usize, _parent_id: Option, scx: &SaveContext) -> Result { + let total = self.lifetimes.len() + self.ty_params.len(); + if total == 0 { + return Ok(text_sig(String::new())); + } + + let mut text = "<".to_owned(); + + let mut defs = vec![]; + for l in &self.lifetimes { + let mut l_text = l.lifetime.ident.to_string(); + defs.push(SigElement { + id: id_from_node_id(l.lifetime.id, scx), + start: offset + text.len(), + end: offset + text.len() + l_text.len(), + }); + + if !l.bounds.is_empty() { + l_text.push_str(": "); + let bounds = l.bounds.iter().map(|l| { + l.ident.to_string() + }).collect::>().join(" + "); + l_text.push_str(&bounds); + // FIXME add lifetime bounds refs. + } + text.push_str(&l_text); + text.push(','); + } + for t in &self.ty_params { + let mut t_text = t.ident.to_string(); + defs.push(SigElement { + id: id_from_node_id(t.id, scx), + start: offset + text.len(), + end: offset + text.len() + t_text.len(), + }); + + if !t.bounds.is_empty() { + t_text.push_str(": "); + t_text.push_str(&pprust::bounds_to_string(&t.bounds)); + // FIXME descend properly into bounds. + } + text.push_str(&t_text); + text.push(','); + } + + text.push('>'); + Ok(Signature {text, defs, refs: vec![] }) + } +} + +impl Sig for ast::StructField { + fn make(&self, offset: usize, _parent_id: Option, scx: &SaveContext) -> Result { + let mut text = String::new(); + let mut defs = None; + if let Some(ref ident) = self.ident { + text.push_str(&ident.to_string()); + defs = Some(SigElement { + id: id_from_node_id(self.id, scx), + start: offset, + end: offset + text.len(), + }); + text.push_str(": "); + } + + let mut ty_sig = self.ty.make(offset + text.len(), Some(self.id), scx)?; + text.push_str(&ty_sig.text); + ty_sig.text = text; + ty_sig.defs.extend(defs.into_iter()); + Ok(ty_sig) + } +} + + +impl Sig for ast::Variant_ { + fn make(&self, offset: usize, _parent_id: Option, scx: &SaveContext) -> Result { + let mut text = self.name.to_string(); + match self.data { + ast::VariantData::Struct(ref fields, id) => { + let name_def = SigElement { + id: id_from_node_id(id, scx), + start: offset, + end: offset + text.len(), + }; + text.push_str(" { "); + let mut defs = vec![name_def]; + let mut refs = vec![]; + for f in fields { + let field_sig = f.make(offset + text.len(), Some(id), scx)?; + text.push_str(&field_sig.text); + text.push_str(", "); + defs.extend(field_sig.defs.into_iter()); + refs.extend(field_sig.refs.into_iter()); + } + text.push('}'); + Ok(Signature { + text, + defs: defs, + refs: refs, + }) + } + ast::VariantData::Tuple(ref fields, id) => { + let name_def = SigElement { + id: id_from_node_id(id, scx), + start: offset, + end: offset + text.len(), + }; + text.push('('); + let mut defs = vec![name_def]; + let mut refs = vec![]; + for f in fields { + let field_sig = f.make(offset + text.len(), Some(id), scx)?; + text.push_str(&field_sig.text); + text.push_str(", "); + defs.extend(field_sig.defs.into_iter()); + refs.extend(field_sig.refs.into_iter()); + } + text.push(')'); + Ok(Signature { + text, + defs: defs, + refs: refs, + }) + } + ast::VariantData::Unit(id) => { + let name_def = SigElement { + id: id_from_node_id(id, scx), + start: offset, + end: offset + text.len(), + }; + Ok(Signature { + text, + defs: vec![name_def], + refs: vec![], + }) + } + } + } +} + +impl Sig for ast::ForeignItem { + fn make(&self, offset: usize, _parent_id: Option, scx: &SaveContext) -> Result { + let id = Some(self.id); + match self.node { + ast::ForeignItemKind::Fn(ref decl, ref generics) => { + let mut text = String::new(); + text.push_str("fn "); + + let mut sig = name_and_generics(text, + offset, + generics, + self.id, + self.ident, + scx)?; + + sig.text.push('('); + for i in &decl.inputs { + // FIXME should descend into patterns to add defs. + sig.text.push_str(&pprust::pat_to_string(&i.pat)); + sig.text.push_str(": "); + let nested = i.ty.make(offset + sig.text.len(), Some(i.id), scx)?; + sig.text.push_str(&nested.text); + sig.text.push(','); + sig.defs.extend(nested.defs.into_iter()); + sig.refs.extend(nested.refs.into_iter()); + } + sig.text.push(')'); + + if let ast::FunctionRetTy::Ty(ref t) = decl.output { + sig.text.push_str(" -> "); + let nested = t.make(offset + sig.text.len(), None, scx)?; + sig.text.push_str(&nested.text); + sig.defs.extend(nested.defs.into_iter()); + sig.refs.extend(nested.refs.into_iter()); + } + sig.text.push(';'); + + Ok(sig) + } + ast::ForeignItemKind::Static(ref ty, m) => { + let mut text = "static ".to_owned(); + if m { + text.push_str("mut "); + } + let name = self.ident.to_string(); + let defs = vec![SigElement { + id: id_from_node_id(self.id, scx), + start: offset + text.len(), + end: offset + text.len() + name.len(), + }]; + text.push_str(&name); + text.push_str(": "); + + let ty_sig = ty.make(offset + text.len(), id, scx)?; + text.push(';'); + + Ok(extend_sig(ty_sig, text, defs, vec![])) + } + } + } +} + +fn name_and_generics(mut text: String, + offset: usize, + generics: &ast::Generics, + id: NodeId, + name: ast::Ident, + scx: &SaveContext) + -> Result { + let name = name.to_string(); + let def = SigElement { + id: id_from_node_id(id, scx), + start: offset + text.len(), + end: offset + text.len() + name.len(), + }; + text.push_str(&name); + let generics: Signature = generics.make(offset + text.len(), Some(id), scx)?; + // FIXME where clause + let text = format!("{}{}", text, generics.text); + Ok(extend_sig(generics, text, vec![def], vec![])) +} + + +fn make_assoc_type_signature(id: NodeId, + ident: ast::Ident, + bounds: Option<&ast::TyParamBounds>, + default: Option<&ast::Ty>, + scx: &SaveContext) + -> Result { + let mut text = "type ".to_owned(); + let name = ident.to_string(); + let mut defs = vec![SigElement { + id: id_from_node_id(id, scx), + start: text.len(), + end: text.len() + name.len(), + }]; + let mut refs = vec![]; + text.push_str(&name); + if let Some(bounds) = bounds { + text.push_str(": "); + // FIXME should descend into bounds + text.push_str(&pprust::bounds_to_string(bounds)); + } + if let Some(default) = default { + text.push_str(" = "); + let ty_sig = default.make(text.len(), Some(id), scx)?; + text.push_str(&ty_sig.text); + defs.extend(ty_sig.defs.into_iter()); + refs.extend(ty_sig.refs.into_iter()); + } + text.push(';'); + Ok(Signature { text, defs, refs }) +} + +fn make_assoc_const_signature(id: NodeId, + ident: ast::Name, + ty: &ast::Ty, + default: Option<&ast::Expr>, + scx: &SaveContext) + -> Result { + let mut text = "const ".to_owned(); + let name = ident.to_string(); + let mut defs = vec![SigElement { + id: id_from_node_id(id, scx), + start: text.len(), + end: text.len() + name.len(), + }]; + let mut refs = vec![]; + text.push_str(&name); + text.push_str(": "); + + let ty_sig = ty.make(text.len(), Some(id), scx)?; + text.push_str(&ty_sig.text); + defs.extend(ty_sig.defs.into_iter()); + refs.extend(ty_sig.refs.into_iter()); + + if let Some(default) = default { + text.push_str(" = "); + text.push_str(&pprust::expr_to_string(default)); + } + text.push(';'); + Ok(Signature { text, defs, refs }) +} + +fn make_method_signature(id: NodeId, + ident: ast::Ident, + m: &ast::MethodSig, + scx: &SaveContext) + -> Result { + // FIXME code dup with function signature + let mut text = String::new(); + if m.constness.node == ast::Constness::Const { + text.push_str("const "); + } + if m.unsafety == ast::Unsafety::Unsafe { + text.push_str("unsafe "); + } + if m.abi != ::syntax::abi::Abi::Rust { + text.push_str("extern"); + text.push_str(&m.abi.to_string()); + text.push(' '); + } + text.push_str("fn "); + + let mut sig = name_and_generics(text, + 0, + &m.generics, + id, + ident, + scx)?; + + sig.text.push('('); + for i in &m.decl.inputs { + // FIXME shoudl descend into patterns to add defs. + sig.text.push_str(&pprust::pat_to_string(&i.pat)); + sig.text.push_str(": "); + let nested = i.ty.make(sig.text.len(), Some(i.id), scx)?; + sig.text.push_str(&nested.text); + sig.text.push(','); + sig.defs.extend(nested.defs.into_iter()); + sig.refs.extend(nested.refs.into_iter()); + } + sig.text.push(')'); + + if let ast::FunctionRetTy::Ty(ref t) = m.decl.output { + sig.text.push_str(" -> "); + let nested = t.make(sig.text.len(), None, scx)?; + sig.text.push_str(&nested.text); + sig.defs.extend(nested.defs.into_iter()); + sig.refs.extend(nested.refs.into_iter()); + } + sig.text.push_str(" {}"); + + Ok(sig) +} diff --git a/src/librustc_save_analysis/span_utils.rs b/src/librustc_save_analysis/span_utils.rs index af3efb480908..77cde33e9620 100644 --- a/src/librustc_save_analysis/span_utils.rs +++ b/src/librustc_save_analysis/span_utils.rs @@ -20,7 +20,6 @@ use syntax::ast; use syntax::parse::lexer::{self, StringReader}; use syntax::parse::token::{self, Token}; use syntax::symbol::keywords; -use syntax::tokenstream::TokenTree; use syntax_pos::*; #[derive(Clone)] @@ -277,45 +276,6 @@ impl<'a> SpanUtils<'a> { } } - /// `span` must be the span for an item such as a function or struct. This - /// function returns the program text from the start of the span until the - /// end of the 'signature' part, that is up to, but not including an opening - /// brace or semicolon. - pub fn signature_string_for_span(&self, span: Span) -> String { - let mut toks = self.retokenise_span(span); - toks.real_token(); - let mut toks = toks.parse_all_token_trees().unwrap().trees(); - let mut prev = toks.next().unwrap(); - - let first_span = prev.span(); - let mut angle_count = 0; - for tok in toks { - if let TokenTree::Token(_, ref tok) = prev { - angle_count += match *tok { - token::Eof => { break; } - token::Lt => 1, - token::Gt => -1, - token::BinOp(token::Shl) => 2, - token::BinOp(token::Shr) => -2, - _ => 0, - }; - } - if angle_count > 0 { - prev = tok; - continue; - } - if let TokenTree::Token(_, token::Semi) = tok { - return self.snippet(first_span.to(prev.span())); - } else if let TokenTree::Delimited(_, ref d) = tok { - if d.delim == token::Brace { - return self.snippet(first_span.to(prev.span())); - } - } - prev = tok; - } - self.snippet(span) - } - pub fn sub_span_before_token(&self, span: Span, tok: Token) -> Option { let mut toks = self.retokenise_span(span); let mut prev = toks.real_token(); @@ -385,57 +345,44 @@ impl<'a> SpanUtils<'a> { self.spans_with_brackets(span, 1, number) } - pub fn report_span_err(&self, kind: &str, span: Span) { - let loc = self.sess.codemap().lookup_char_pos(span.lo); - info!("({}) Could not find sub_span in `{}` in {}, line {}", - kind, - self.snippet(span), - loc.file.name, - loc.line); - self.err_count.set(self.err_count.get() + 1); - if self.err_count.get() > 1000 { - bug!("span errors reached 1000, giving up"); - } - } + // // Return the name for a macro definition (identifier after first `!`) + // pub fn span_for_macro_def_name(&self, span: Span) -> Option { + // let mut toks = self.retokenise_span(span); + // loop { + // let ts = toks.real_token(); + // if ts.tok == token::Eof { + // return None; + // } + // if ts.tok == token::Not { + // let ts = toks.real_token(); + // if ts.tok.is_ident() { + // return Some(ts.sp); + // } else { + // return None; + // } + // } + // } + // } - // Return the name for a macro definition (identifier after first `!`) - pub fn span_for_macro_def_name(&self, span: Span) -> Option { - let mut toks = self.retokenise_span(span); - loop { - let ts = toks.real_token(); - if ts.tok == token::Eof { - return None; - } - if ts.tok == token::Not { - let ts = toks.real_token(); - if ts.tok.is_ident() { - return Some(ts.sp); - } else { - return None; - } - } - } - } - - // Return the name for a macro use (identifier before first `!`). - pub fn span_for_macro_use_name(&self, span:Span) -> Option { - let mut toks = self.retokenise_span(span); - let mut prev = toks.real_token(); - loop { - if prev.tok == token::Eof { - return None; - } - let ts = toks.real_token(); - if ts.tok == token::Not { - if prev.tok.is_ident() { - return Some(prev.sp); - } else { - return None; - } - } - prev = ts; - } - } + // // Return the name for a macro use (identifier before first `!`). + // pub fn span_for_macro_use_name(&self, span:Span) -> Option { + // let mut toks = self.retokenise_span(span); + // let mut prev = toks.real_token(); + // loop { + // if prev.tok == token::Eof { + // return None; + // } + // let ts = toks.real_token(); + // if ts.tok == token::Not { + // if prev.tok.is_ident() { + // return Some(prev.sp); + // } else { + // return None; + // } + // } + // prev = ts; + // } + // } /// Return true if the span is generated code, and /// it is not a subspan of the root callsite. diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index ee92a4b4a2df..087be9a9a19c 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -23,7 +23,7 @@ use rustc::middle::dependency_format::Linkage; use CrateTranslation; use rustc::util::common::time; use rustc::util::fs::fix_windows_verbatim_for_gcc; -use rustc::dep_graph::DepNode; +use rustc::dep_graph::{DepKind, DepNode}; use rustc::hir::def_id::CrateNum; use rustc::hir::svh::Svh; use rustc_back::tempdir::TempDir; @@ -134,24 +134,28 @@ pub fn find_crate_name(sess: Option<&Session>, } pub fn build_link_meta(incremental_hashes_map: &IncrementalHashesMap) -> LinkMeta { + let krate_dep_node = &DepNode::new_no_params(DepKind::Krate); let r = LinkMeta { - crate_hash: Svh::new(incremental_hashes_map[&DepNode::Krate].to_smaller_hash()), + crate_hash: Svh::new(incremental_hashes_map[krate_dep_node].to_smaller_hash()), }; info!("{:?}", r); return r; } -// The third parameter is for an env vars, used to set up the path for MSVC -// to find its DLLs +// The third parameter is for env vars, used on windows to set up the +// path for MSVC to find its DLLs, and gcc to find its bundled +// toolchain pub fn get_linker(sess: &Session) -> (String, Command, Vec<(OsString, OsString)>) { + let envs = vec![("PATH".into(), command_path(sess))]; + if let Some(ref linker) = sess.opts.cg.linker { - (linker.clone(), Command::new(linker), vec![]) + (linker.clone(), Command::new(linker), envs) } else if sess.target.target.options.is_like_msvc { let (cmd, envs) = msvc_link_exe_cmd(sess); ("link.exe".to_string(), cmd, envs) } else { - (sess.target.target.options.linker.clone(), - Command::new(&sess.target.target.options.linker), vec![]) + let linker = &sess.target.target.options.linker; + (linker.clone(), Command::new(&linker), envs) } } @@ -182,7 +186,7 @@ pub fn get_ar_prog(sess: &Session) -> String { }) } -fn command_path(sess: &Session, extra: Option) -> OsString { +fn command_path(sess: &Session) -> OsString { // The compiler's sysroot often has some bundled tools, so add it to the // PATH for the child. let mut new_path = sess.host_filesearch(PathKind::All) @@ -190,7 +194,6 @@ fn command_path(sess: &Session, extra: Option) -> OsString { if let Some(path) = env::var_os("PATH") { new_path.extend(env::split_paths(&path)); } - new_path.extend(extra); env::join_paths(new_path).unwrap() } @@ -451,7 +454,7 @@ fn archive_config<'a>(sess: &'a Session, src: input.map(|p| p.to_path_buf()), lib_search_paths: archive_search_paths(sess), ar_prog: get_ar_prog(sess), - command_path: command_path(sess, None), + command_path: command_path(sess), } } @@ -727,7 +730,7 @@ fn link_natively(sess: &Session, // The invocations of cc share some flags across platforms let (pname, mut cmd, envs) = get_linker(sess); - // This will set PATH on MSVC + // This will set PATH on windows cmd.envs(envs); let root = sess.target_filesearch(PathKind::Native).get_lib_path(); @@ -1098,6 +1101,9 @@ fn add_upstream_rust_crates(cmd: &mut Linker, // symbols from the dylib. let src = sess.cstore.used_crate_source(cnum); match data[cnum.as_usize() - 1] { + _ if sess.cstore.is_profiler_runtime(cnum) => { + add_static_crate(cmd, sess, tmpdir, crate_type, cnum); + } _ if sess.cstore.is_sanitizer_runtime(cnum) => { link_sanitizer_runtime(cmd, sess, tmpdir, cnum); } diff --git a/src/librustc_trans/back/symbol_export.rs b/src/librustc_trans/back/symbol_export.rs index ef75de04045e..b38dc1883892 100644 --- a/src/librustc_trans/back/symbol_export.rs +++ b/src/librustc_trans/back/symbol_export.rs @@ -92,8 +92,8 @@ impl ExportedSymbols { // Down below we'll hardwire all of the symbols to the `Rust` export // level instead. let special_runtime_crate = - scx.sess().cstore.is_allocator(cnum) || - scx.sess().cstore.is_panic_runtime(cnum) || + scx.tcx().is_allocator(cnum.as_def_id()) || + scx.tcx().is_panic_runtime(cnum.as_def_id()) || scx.sess().cstore.is_compiler_builtins(cnum); let crate_exports = scx diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 6ed0cb0092f5..4871d638d129 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -701,6 +701,10 @@ pub fn run_passes(sess: &Session, } } + if sess.opts.debugging_opts.profile { + modules_config.passes.push("insert-gcov-profiling".to_owned()) + } + modules_config.opt_level = Some(get_llvm_opt_level(sess.opts.optimize)); modules_config.opt_size = Some(get_llvm_opt_size(sess.opts.optimize)); diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 88c30cd86659..2685c22d60d4 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -43,7 +43,7 @@ use rustc::dep_graph::AssertDepGraphSafe; use rustc::middle::cstore::LinkMeta; use rustc::hir::map as hir_map; use rustc::util::common::time; -use rustc::session::config::{self, NoDebugInfo}; +use rustc::session::config::{self, NoDebugInfo, OutputFilenames}; use rustc::session::Session; use rustc_incremental::IncrementalHashesMap; use abi; @@ -1049,7 +1049,8 @@ pub fn find_exported_symbols(tcx: TyCtxt, reachable: &NodeSet) -> NodeSet { pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, analysis: ty::CrateAnalysis, - incremental_hashes_map: &IncrementalHashesMap) + incremental_hashes_map: &IncrementalHashesMap, + output_filenames: &OutputFilenames) -> CrateTranslation { // Be careful with this krate: obviously it gives access to the // entire contents of the krate. So if you push any subtasks of @@ -1066,7 +1067,8 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let shared_ccx = SharedCrateContext::new(tcx, exported_symbols, - check_overflow); + check_overflow, + output_filenames); // Translate the metadata. let (metadata_llcx, metadata_llmod, metadata) = time(tcx.sess.time_passes(), "write metadata", || { diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index da74ed88eaf8..d723cf325718 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -493,6 +493,8 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { } mir::Rvalue::Cast(mir::CastKind::ClosureFnPointer, ref operand, _) => { let source_ty = operand.ty(self.mir, self.scx.tcx()); + let source_ty = self.scx.tcx().trans_apply_param_substs(self.param_substs, + &source_ty); match source_ty.sty { ty::TyClosure(def_id, substs) => { let instance = monomorphize::resolve_closure( @@ -543,6 +545,8 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { block: mir::BasicBlock, kind: &mir::TerminatorKind<'tcx>, location: Location) { + debug!("visiting terminator {:?} @ {:?}", kind, location); + let tcx = self.scx.tcx(); match *kind { mir::TerminatorKind::Call { ref func, .. } => { diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 6266452419ed..208e994653b5 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -23,7 +23,7 @@ use monomorphize::Instance; use partitioning::CodegenUnit; use type_::Type; use rustc_data_structures::base_n; -use rustc::session::config::{self, NoDebugInfo}; +use rustc::session::config::{self, NoDebugInfo, OutputFilenames}; use rustc::session::Session; use rustc::ty::subst::Substs; use rustc::ty::{self, Ty, TyCtxt}; @@ -81,6 +81,8 @@ pub struct SharedCrateContext<'a, 'tcx: 'a> { check_overflow: bool, use_dll_storage_attrs: bool, + + output_filenames: &'a OutputFilenames, } /// The local portion of a `CrateContext`. There is one `LocalCrateContext` @@ -264,7 +266,8 @@ pub unsafe fn create_context_and_module(sess: &Session, mod_name: &str) -> (Cont impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { pub fn new(tcx: TyCtxt<'b, 'tcx, 'tcx>, exported_symbols: NodeSet, - check_overflow: bool) + check_overflow: bool, + output_filenames: &'b OutputFilenames) -> SharedCrateContext<'b, 'tcx> { // An interesting part of Windows which MSVC forces our hand on (and // apparently MinGW didn't) is the usage of `dllimport` and `dllexport` @@ -316,6 +319,7 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { tcx: tcx, check_overflow: check_overflow, use_dll_storage_attrs: use_dll_storage_attrs, + output_filenames: output_filenames, } } @@ -350,6 +354,10 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { pub fn use_dll_storage_attrs(&self) -> bool { self.use_dll_storage_attrs } + + pub fn output_filenames(&self) -> &OutputFilenames { + self.output_filenames + } } impl<'a, 'tcx> LocalCrateContext<'a, 'tcx> { diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index fea24e6da873..95ceec610eaa 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -38,10 +38,12 @@ use rustc::ty::{self, AdtKind, Ty}; use rustc::ty::layout::{self, LayoutTyper}; use rustc::session::{Session, config}; use rustc::util::nodemap::FxHashMap; +use rustc::util::common::path2cstr; use libc::{c_uint, c_longlong}; use std::ffi::CString; use std::ptr; +use std::path::Path; use syntax::ast; use syntax::symbol::{Interner, InternedString, Symbol}; use syntax_pos::{self, Span}; @@ -794,7 +796,7 @@ pub fn compile_unit_metadata(scc: &SharedCrateContext, let file_metadata = llvm::LLVMRustDIBuilderCreateFile( debug_context.builder, name_in_debuginfo.as_ptr(), work_dir.as_ptr()); - return llvm::LLVMRustDIBuilderCreateCompileUnit( + let unit_metadata = llvm::LLVMRustDIBuilderCreateCompileUnit( debug_context.builder, DW_LANG_RUST, file_metadata, @@ -802,8 +804,40 @@ pub fn compile_unit_metadata(scc: &SharedCrateContext, sess.opts.optimize != config::OptLevel::No, flags.as_ptr() as *const _, 0, - split_name.as_ptr() as *const _) + split_name.as_ptr() as *const _); + + if sess.opts.debugging_opts.profile { + let cu_desc_metadata = llvm::LLVMRustMetadataAsValue(debug_context.llcontext, + unit_metadata); + + let gcov_cu_info = [ + path_to_mdstring(debug_context.llcontext, + &scc.output_filenames().with_extension("gcno")), + path_to_mdstring(debug_context.llcontext, + &scc.output_filenames().with_extension("gcda")), + cu_desc_metadata, + ]; + let gcov_metadata = llvm::LLVMMDNodeInContext(debug_context.llcontext, + gcov_cu_info.as_ptr(), + gcov_cu_info.len() as c_uint); + + let llvm_gcov_ident = CString::new("llvm.gcov").unwrap(); + llvm::LLVMAddNamedMetadataOperand(debug_context.llmod, + llvm_gcov_ident.as_ptr(), + gcov_metadata); + } + + return unit_metadata; }; + + fn path_to_mdstring(llcx: llvm::ContextRef, path: &Path) -> llvm::ValueRef { + let path_str = path2cstr(path); + unsafe { + llvm::LLVMMDStringInContext(llcx, + path_str.as_ptr(), + path_str.as_bytes().len() as c_uint) + } + } } struct MetadataCreationResult { diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index 4d781d6f77de..d4d098ee5e74 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -67,6 +67,7 @@ const DW_TAG_arg_variable: c_uint = 0x101; /// A context object for maintaining all state needed by the debuginfo module. pub struct CrateDebugContext<'tcx> { llcontext: ContextRef, + llmod: ModuleRef, builder: DIBuilderRef, created_files: RefCell>, created_enum_disr_types: RefCell>, @@ -87,6 +88,7 @@ impl<'tcx> CrateDebugContext<'tcx> { let llcontext = unsafe { llvm::LLVMGetModuleContext(llmod) }; CrateDebugContext { llcontext: llcontext, + llmod: llmod, builder: builder, created_files: RefCell::new(FxHashMap()), created_enum_disr_types: RefCell::new(FxHashMap()), diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index f2e6aa3ef00b..de908bb24a7a 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -267,7 +267,7 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, }; bcx.call(expect, &[llargs[0], C_i32(ccx, rw), llargs[1], C_i32(ccx, cache_type)], None) }, - "ctlz" | "cttz" | "ctpop" | "bswap" | + "ctlz" | "ctlz_nonzero" | "cttz" | "cttz_nonzero" | "ctpop" | "bswap" | "add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" | "overflowing_add" | "overflowing_sub" | "overflowing_mul" | "unchecked_div" | "unchecked_rem" | "unchecked_shl" | "unchecked_shr" => { @@ -280,6 +280,12 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, let llfn = ccx.get_intrinsic(&format!("llvm.{}.i{}", name, width)); bcx.call(llfn, &[llargs[0], y], None) } + "ctlz_nonzero" | "cttz_nonzero" => { + let y = C_bool(bcx.ccx, true); + let llvm_name = &format!("llvm.{}.i{}", &name[..4], width); + let llfn = ccx.get_intrinsic(llvm_name); + bcx.call(llfn, &[llargs[0], y], None) + } "ctpop" => bcx.call(ccx.get_intrinsic(&format!("llvm.ctpop.i{}", width)), &llargs, None), "bswap" => { diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 71fb2e5fb202..4c7037c9ef2d 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -33,7 +33,6 @@ #![feature(quote)] #![feature(rustc_diagnostic_macros)] #![feature(slice_patterns)] -#![feature(unicode)] #![feature(conservative_impl_trait)] #![feature(command_envs)] diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 4967ef2f7908..16ef32ccf577 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -284,6 +284,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { } mir::StatementKind::StorageLive(_) | mir::StatementKind::StorageDead(_) | + mir::StatementKind::EndRegion(_) | mir::StatementKind::Nop => {} mir::StatementKind::InlineAsm { .. } | mir::StatementKind::SetDiscriminant{ .. } => { diff --git a/src/librustc_trans/mir/statement.rs b/src/librustc_trans/mir/statement.rs index 52c2afca4748..170a76a49497 100644 --- a/src/librustc_trans/mir/statement.rs +++ b/src/librustc_trans/mir/statement.rs @@ -86,6 +86,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { asm::trans_inline_asm(&bcx, asm, outputs, input_vals); bcx } + mir::StatementKind::EndRegion(_) | mir::StatementKind::Nop => bcx, } } diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs index 2fe463e92a8a..ead442d33882 100644 --- a/src/librustc_trans/partitioning.rs +++ b/src/librustc_trans/partitioning.rs @@ -114,7 +114,6 @@ use rustc::ty::{self, TyCtxt}; use rustc::ty::item_path::characteristic_def_id_of_type; use rustc_incremental::IchHasher; use std::hash::Hash; -use std::sync::Arc; use syntax::ast::NodeId; use syntax::symbol::{Symbol, InternedString}; use trans_item::{TransItem, InstantiationMode}; @@ -164,12 +163,12 @@ impl<'tcx> CodegenUnit<'tcx> { &self.items } - pub fn work_product_id(&self) -> Arc { - Arc::new(WorkProductId(self.name().to_string())) + pub fn work_product_id(&self) -> WorkProductId { + WorkProductId::from_cgu_name(self.name()) } - pub fn work_product_dep_node(&self) -> DepNode { - DepNode::WorkProduct(self.work_product_id()) + pub fn work_product_dep_node(&self) -> DepNode { + self.work_product_id().to_dep_node() } pub fn compute_symbol_name_hash<'a>(&self, diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 392ee71d52b4..0dc2bc85e30e 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -23,7 +23,6 @@ use common; use declare; use llvm; use monomorphize::Instance; -use rustc::dep_graph::DepNode; use rustc::hir; use rustc::hir::def_id::DefId; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; @@ -63,26 +62,15 @@ impl<'a, 'tcx> TransItem<'tcx> { self.to_raw_string(), ccx.codegen_unit().name()); - // (*) This code executes in the context of a dep-node for the - // entire CGU. In some cases, we introduce dep-nodes for - // particular items that we are translating (these nodes will - // have read edges coming into the CGU node). These smaller - // nodes are not needed for correctness -- we always - // invalidate an entire CGU at a time -- but they enable - // finer-grained testing, since you can write tests that check - // that the incoming edges to a particular fn are from a - // particular set. - match *self { TransItem::Static(node_id) => { - let def_id = ccx.tcx().hir.local_def_id(node_id); - let _task = ccx.tcx().dep_graph.in_task(DepNode::TransCrateItem(def_id)); // (*) - let item = ccx.tcx().hir.expect_item(node_id); + let tcx = ccx.tcx(); + let item = tcx.hir.expect_item(node_id); if let hir::ItemStatic(_, m, _) = item.node { match consts::trans_static(&ccx, m, item.id, &item.attrs) { Ok(_) => { /* Cool, everything's alright. */ }, Err(err) => { - err.report(ccx.tcx(), item.span, "static"); + err.report(tcx, item.span, "static"); } }; } else { @@ -98,9 +86,6 @@ impl<'a, 'tcx> TransItem<'tcx> { } } TransItem::Fn(instance) => { - let _task = ccx.tcx().dep_graph.in_task( - DepNode::TransCrateItem(instance.def_id())); // (*) - base::trans_instance(&ccx, instance); } } diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 33f0b0282d17..bdd8169b84fe 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -413,7 +413,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // discriminant. This is sort of a workaround, see note (*) in // `check_pat` for some details. discrim_ty = self.next_ty_var(TypeVariableOrigin::TypeInference(discrim.span)); - self.check_expr_has_type(discrim, discrim_ty); + self.check_expr_has_type_or_error(discrim, discrim_ty); }; // If the discriminant diverges, the match is pointless (e.g., @@ -480,7 +480,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { for (i, (arm, pats_diverge)) in arms.iter().zip(all_arm_pats_diverge).enumerate() { if let Some(ref e) = arm.guard { self.diverges.set(pats_diverge); - self.check_expr_has_type(e, tcx.types.bool); + self.check_expr_has_type_or_error(e, tcx.types.bool); } self.diverges.set(pats_diverge); diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index d5ee66a2f0a0..385ed7eb0e38 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -15,7 +15,7 @@ use super::method::MethodCallee; use hir::def::Def; use hir::def_id::{DefId, LOCAL_CRATE}; use rustc::{infer, traits}; -use rustc::ty::{self, TyCtxt, LvaluePreference, Ty}; +use rustc::ty::{self, TyCtxt, TypeFoldable, LvaluePreference, Ty}; use rustc::ty::subst::Subst; use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow}; use syntax::abi; @@ -209,17 +209,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } } - let mut err = if let Some(path) = unit_variant { - let mut err = self.type_error_struct(call_expr.span, |_| { - format!("`{}` is being called, but it is not a function", path) - }, callee_ty); + let mut err = type_error_struct!(self.tcx.sess, call_expr.span, callee_ty, E0618, + "expected function, found `{}`", + if let Some(ref path) = unit_variant { + path.to_string() + } else { + callee_ty.to_string() + }); + if let Some(path) = unit_variant { err.help(&format!("did you mean to write `{}`?", path)); - err - } else { - self.type_error_struct(call_expr.span, |actual| { - format!("expected function, found `{}`", actual) - }, callee_ty) - }; + } if let hir::ExprCall(ref expr, _) = call_expr.node { let def = if let hir::ExprPath(ref qpath) = expr.node { diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 8b76431fd2e6..29742469f84d 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -219,7 +219,7 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env, normalize_cause.clone()); - tcx.infer_ctxt(()).enter(|infcx| { + tcx.infer_ctxt().enter(|infcx| { let inh = Inherited::new(infcx, impl_m.def_id); let infcx = &inh.infcx; @@ -726,7 +726,7 @@ pub fn compare_const_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl_trait_ref: ty::TraitRef<'tcx>) { debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref); - tcx.infer_ctxt(()).enter(|infcx| { + tcx.infer_ctxt().enter(|infcx| { let param_env = ty::ParamEnv::empty(Reveal::UserFacing); let inh = Inherited::new(infcx, impl_c.def_id); let infcx = &inh.infcx; diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 9ed50dd1e4d4..1b6f96cf6513 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -26,13 +26,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Requires that the two types unify, and prints an error message if // they don't. pub fn demand_suptype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) { + self.demand_suptype_diag(sp, expected, actual).map(|mut e| e.emit()); + } + + pub fn demand_suptype_diag(&self, + sp: Span, + expected: Ty<'tcx>, + actual: Ty<'tcx>) -> Option> { let cause = &self.misc(sp); match self.at(cause, self.param_env).sup(expected, actual) { Ok(InferOk { obligations, value: () }) => { self.register_predicates(obligations); + None }, Err(e) => { - self.report_mismatched_types(&cause, expected, actual, e).emit(); + Some(self.report_mismatched_types(&cause, expected, actual, e)) } } } diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index bff9289de505..93057f91997d 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -79,7 +79,7 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>( // check that the impl type can be made to match the trait type. - tcx.infer_ctxt(()).enter(|ref infcx| { + tcx.infer_ctxt().enter(|ref infcx| { let impl_param_env = tcx.param_env(self_type_did); let tcx = infcx.tcx; let mut fulfillment_cx = traits::FulfillmentContext::new(); diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index daf202cd7973..4d9f50b0fc0c 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -272,7 +272,8 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, "volatile_store" => (1, vec![ tcx.mk_mut_ptr(param(0)), param(0) ], tcx.mk_nil()), - "ctpop" | "ctlz" | "cttz" | "bswap" => (1, vec![param(0)], param(0)), + "ctpop" | "ctlz" | "ctlz_nonzero" | "cttz" | "cttz_nonzero" | "bswap" => + (1, vec![param(0)], param(0)), "add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" => (1, vec![param(0), param(0)], diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index f8dd5774793a..4faf71e0cc94 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -526,7 +526,7 @@ pub fn all_traits<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> AllTraits<'a> if !external_mods.insert(def_id) { return; } - for child in tcx.sess.cstore.item_children(def_id) { + for child in tcx.sess.cstore.item_children(def_id, tcx.sess) { handle_external_def(tcx, traits, external_mods, child.def) } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index c3bce8048796..f7e23d289873 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -108,7 +108,7 @@ use lint; use util::common::{ErrorReported, indenter}; use util::nodemap::{DefIdMap, FxHashMap, NodeMap}; -use std::cell::{Cell, RefCell}; +use std::cell::{Cell, RefCell, Ref, RefMut}; use std::collections::hash_map::Entry; use std::cmp; use std::mem::replace; @@ -120,7 +120,7 @@ use syntax::feature_gate::{GateIssue, emit_feature_err}; use syntax::ptr::P; use syntax::symbol::{Symbol, InternedString, keywords}; use syntax::util::lev_distance::find_best_match_for_name; -use syntax_pos::{self, BytePos, Span, DUMMY_SP}; +use syntax_pos::{self, BytePos, Span}; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; use rustc::hir::itemlikevisit::ItemLikeVisitor; @@ -147,6 +147,33 @@ mod compare_method; mod intrinsic; mod op; +/// A wrapper for InferCtxt's `in_progress_tables` field. +#[derive(Copy, Clone)] +struct MaybeInProgressTables<'a, 'tcx: 'a> { + maybe_tables: Option<&'a RefCell>>, +} + +impl<'a, 'tcx> MaybeInProgressTables<'a, 'tcx> { + fn borrow(self) -> Ref<'a, ty::TypeckTables<'tcx>> { + match self.maybe_tables { + Some(tables) => tables.borrow(), + None => { + bug!("MaybeInProgressTables: inh/fcx.tables.borrow() with no tables") + } + } + } + + fn borrow_mut(self) -> RefMut<'a, ty::TypeckTables<'tcx>> { + match self.maybe_tables { + Some(tables) => tables.borrow_mut(), + None => { + bug!("MaybeInProgressTables: inh/fcx.tables.borrow_mut() with no tables") + } + } + } +} + + /// closures defined within the function. For example: /// /// fn foo() { @@ -159,6 +186,8 @@ mod op; pub struct Inherited<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { infcx: InferCtxt<'a, 'gcx, 'tcx>, + tables: MaybeInProgressTables<'a, 'tcx>, + locals: RefCell>>, fulfillment_cx: RefCell>, @@ -203,6 +232,9 @@ pub enum Expectation<'tcx> { /// We know nothing about what type this expression should have. NoExpectation, + /// This expression is an `if` condition, it must resolve to `bool`. + ExpectIfCondition, + /// This expression should have the type given (or some subtype) ExpectHasType(Ty<'tcx>), @@ -281,9 +313,8 @@ impl<'a, 'gcx, 'tcx> Expectation<'tcx> { // no constraints yet present), just returns `None`. fn resolve(self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) -> Expectation<'tcx> { match self { - NoExpectation => { - NoExpectation - } + NoExpectation => NoExpectation, + ExpectIfCondition => ExpectIfCondition, ExpectCastableToType(t) => { ExpectCastableToType(fcx.resolve_type_vars_if_possible(&t)) } @@ -299,6 +330,7 @@ impl<'a, 'gcx, 'tcx> Expectation<'tcx> { fn to_option(self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) -> Option> { match self.resolve(fcx) { NoExpectation => None, + ExpectIfCondition => Some(fcx.tcx.types.bool), ExpectCastableToType(ty) | ExpectHasType(ty) | ExpectRvalueLikeUnsized(ty) => Some(ty), @@ -312,7 +344,8 @@ impl<'a, 'gcx, 'tcx> Expectation<'tcx> { fn only_has_type(self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) -> Option> { match self.resolve(fcx) { ExpectHasType(ty) => Some(ty), - _ => None + ExpectIfCondition => Some(fcx.tcx.types.bool), + NoExpectation | ExpectCastableToType(_) | ExpectRvalueLikeUnsized(_) => None, } } @@ -535,9 +568,8 @@ pub struct InheritedBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> { pub fn build(tcx: TyCtxt<'a, 'gcx, 'gcx>, def_id: DefId) -> InheritedBuilder<'a, 'gcx, 'tcx> { - let tables = ty::TypeckTables::empty(); InheritedBuilder { - infcx: tcx.infer_ctxt(tables), + infcx: tcx.infer_ctxt().with_fresh_in_progress_tables(), def_id, } } @@ -562,6 +594,9 @@ impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> { }); Inherited { + tables: MaybeInProgressTables { + maybe_tables: infcx.in_progress_tables, + }, infcx: infcx, fulfillment_cx: RefCell::new(traits::FulfillmentContext::new()), locals: RefCell::new(NodeMap()), @@ -583,7 +618,8 @@ impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> { .register_predicate_obligation(self, obligation); } - fn register_predicates(&self, obligations: Vec>) { + fn register_predicates(&self, obligations: I) + where I: IntoIterator> { for obligation in obligations { self.register_predicate(obligation); } @@ -1901,14 +1937,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { value) } - pub fn write_nil(&self, node_id: ast::NodeId) { - self.write_ty(node_id, self.tcx.mk_nil()); - } - - pub fn write_error(&self, node_id: ast::NodeId) { - self.write_ty(node_id, self.tcx.types.err); - } - pub fn require_type_meets(&self, ty: Ty<'tcx>, span: Span, @@ -2530,42 +2558,32 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // We also need to make sure we at least write the ty of the other // arguments which we skipped above. if variadic { + fn variadic_error<'tcx>(s: &Session, span: Span, t: Ty<'tcx>, cast_ty: &str) { + type_error_struct!(s, span, t, E0617, + "can't pass `{}` to variadic function, cast to `{}`", + t, cast_ty).emit(); + } + for arg in args.iter().skip(expected_arg_count) { let arg_ty = self.check_expr(&arg); // There are a few types which get autopromoted when passed via varargs // in C but we just error out instead and require explicit casts. - let arg_ty = self.structurally_resolved_type(arg.span, - arg_ty); + let arg_ty = self.structurally_resolved_type(arg.span, arg_ty); match arg_ty.sty { ty::TyFloat(ast::FloatTy::F32) => { - self.type_error_message(arg.span, |t| { - format!("can't pass an `{}` to variadic \ - function, cast to `c_double`", t) - }, arg_ty); + variadic_error(tcx.sess, arg.span, arg_ty, "c_double"); } ty::TyInt(ast::IntTy::I8) | ty::TyInt(ast::IntTy::I16) | ty::TyBool => { - self.type_error_message(arg.span, |t| { - format!("can't pass `{}` to variadic \ - function, cast to `c_int`", - t) - }, arg_ty); + variadic_error(tcx.sess, arg.span, arg_ty, "c_int"); } ty::TyUint(ast::UintTy::U8) | ty::TyUint(ast::UintTy::U16) => { - self.type_error_message(arg.span, |t| { - format!("can't pass `{}` to variadic \ - function, cast to `c_uint`", - t) - }, arg_ty); + variadic_error(tcx.sess, arg.span, arg_ty, "c_uint"); } ty::TyFnDef(.., f) => { let ptr_ty = self.tcx.mk_fn_ptr(f); let ptr_ty = self.resolve_type_vars_if_possible(&ptr_ty); - self.type_error_message(arg.span, - |t| { - format!("can't pass `{}` to variadic \ - function, cast to `{}`", t, ptr_ty) - }, arg_ty); + variadic_error(tcx.sess, arg.span, arg_ty, &format!("{}", ptr_ty)); } _ => {} } @@ -2630,10 +2648,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.demand_eqtype(expr.span, expected, ty); } - pub fn check_expr_has_type(&self, - expr: &'gcx hir::Expr, - expected: Ty<'tcx>) -> Ty<'tcx> { - let mut ty = self.check_expr_with_hint(expr, expected); + pub fn check_expr_has_type_or_error(&self, + expr: &'gcx hir::Expr, + expected: Ty<'tcx>) -> Ty<'tcx> { + self.check_expr_meets_expectation_or_error(expr, ExpectHasType(expected)) + } + + fn check_expr_meets_expectation_or_error(&self, + expr: &'gcx hir::Expr, + expected: Expectation<'tcx>) -> Ty<'tcx> { + let expected_ty = expected.to_option(&self).unwrap_or(self.tcx.types.bool); + let mut ty = self.check_expr_with_expectation(expr, expected); // While we don't allow *arbitrary* coercions here, we *do* allow // coercions from ! to `expected`. @@ -2649,7 +2674,24 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ty = adj_ty; } - self.demand_suptype(expr.span, expected, ty); + if let Some(mut err) = self.demand_suptype_diag(expr.span, expected_ty, ty) { + // Add help to type error if this is an `if` condition with an assignment + match (expected, &expr.node) { + (ExpectIfCondition, &hir::ExprAssign(ref lhs, ref rhs)) => { + let msg = "did you mean to compare equality?"; + if let (Ok(left), Ok(right)) = ( + self.tcx.sess.codemap().span_to_snippet(lhs.span), + self.tcx.sess.codemap().span_to_snippet(rhs.span)) + { + err.span_suggestion(expr.span, msg, format!("{} == {}", left, right)); + } else { + err.help(msg); + } + } + _ => (), + } + err.emit(); + } ty } @@ -2824,7 +2866,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { opt_else_expr: Option<&'gcx hir::Expr>, sp: Span, expected: Expectation<'tcx>) -> Ty<'tcx> { - let cond_ty = self.check_expr_has_type(cond_expr, self.tcx.types.bool); + let cond_ty = self.check_expr_meets_expectation_or_error(cond_expr, ExpectIfCondition); let cond_diverges = self.diverges.get(); self.diverges.set(Diverges::Maybe); @@ -2929,30 +2971,34 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { .emit(); self.tcx().types.err } else { - let mut err = self.type_error_struct(field.span, |actual| { - format!("no field `{}` on type `{}`", - field.node, actual) - }, expr_t); - match expr_t.sty { - ty::TyAdt(def, _) if !def.is_enum() => { - if let Some(suggested_field_name) = - Self::suggest_field_name(def.struct_variant(), field, vec![]) { - err.span_label(field.span, - format!("did you mean `{}`?", suggested_field_name)); - } else { - err.span_label(field.span, - "unknown field"); - }; + if !expr_t.is_primitive_ty() { + let mut err = type_error_struct!(self.tcx().sess, field.span, expr_t, E0609, + "no field `{}` on type `{}`", + field.node, expr_t); + match expr_t.sty { + ty::TyAdt(def, _) if !def.is_enum() => { + if let Some(suggested_field_name) = + Self::suggest_field_name(def.struct_variant(), field, vec![]) { + err.span_label(field.span, + format!("did you mean `{}`?", suggested_field_name)); + } else { + err.span_label(field.span, "unknown field"); + }; + } + ty::TyRawPtr(..) => { + err.note(&format!("`{0}` is a native pointer; perhaps you need to deref \ + with `(*{0}).{1}`", + self.tcx.hir.node_to_pretty_string(base.id), + field.node)); + } + _ => {} } - ty::TyRawPtr(..) => { - err.note(&format!("`{0}` is a native pointer; perhaps you need to deref with \ - `(*{0}).{1}`", - self.tcx.hir.node_to_pretty_string(base.id), - field.node)); - } - _ => {} - } - err.emit(); + err + } else { + type_error_struct!(self.tcx().sess, field.span, expr_t, E0610, + "`{}` is a primitive type and therefore doesn't have fields", + expr_t) + }.emit(); self.tcx().types.err } } @@ -3307,17 +3353,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.check_expr_struct_fields(struct_ty, expected, expr.id, path_span, variant, fields, base_expr.is_none()); if let &Some(ref base_expr) = base_expr { - self.check_expr_has_type(base_expr, struct_ty); + self.check_expr_has_type_or_error(base_expr, struct_ty); match struct_ty.sty { ty::TyAdt(adt, substs) if adt.is_struct() => { - self.tables.borrow_mut().fru_field_types.insert( - expr.id, - adt.struct_variant().fields.iter().map(|f| { - self.normalize_associated_types_in( - expr.span, &f.ty(self.tcx, substs) - ) - }).collect() - ); + let fru_field_types = adt.struct_variant().fields.iter().map(|f| { + self.normalize_associated_types_in(expr.span, &f.ty(self.tcx, substs)) + }).collect(); + self.tables.borrow_mut().fru_field_types.insert(expr.id, fru_field_types); } _ => { span_err!(self.tcx.sess, base_expr.span, E0436, @@ -3624,19 +3666,28 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { hir::ExprAssign(ref lhs, ref rhs) => { let lhs_ty = self.check_expr_with_lvalue_pref(&lhs, PreferMutLvalue); - let tcx = self.tcx; - if !tcx.expr_is_lval(&lhs) { - struct_span_err!( - tcx.sess, expr.span, E0070, - "invalid left-hand side expression") - .span_label( - expr.span, - "left-hand of expression not valid") - .emit(); - } - let rhs_ty = self.check_expr_coercable_to_type(&rhs, lhs_ty); + match expected { + ExpectIfCondition => { + self.tcx.sess.delay_span_bug(lhs.span, "invalid lhs expression in if;\ + expected error elsehwere"); + } + _ => { + // Only check this if not in an `if` condition, as the + // mistyped comparison help is more appropriate. + if !self.tcx.expr_is_lval(&lhs) { + struct_span_err!( + self.tcx.sess, expr.span, E0070, + "invalid left-hand side expression") + .span_label( + expr.span, + "left-hand of expression not valid") + .emit(); + } + } + } + self.require_type_is_sized(lhs_ty, lhs.span, traits::AssignmentLhsSized); if lhs_ty.references_error() || rhs_ty.references_error() { @@ -3657,7 +3708,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; self.with_breakable_ctxt(expr.id, ctxt, || { - self.check_expr_has_type(&cond, tcx.types.bool); + self.check_expr_has_type_or_error(&cond, tcx.types.bool); let cond_diverging = self.diverges.get(); self.check_block_no_value(&body); @@ -3795,7 +3846,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } None => { let t: Ty = self.next_ty_var(TypeVariableOrigin::MiscVariable(element.span)); - let element_ty = self.check_expr_has_type(&element, t); + let element_ty = self.check_expr_has_type_or_error(&element, t); (element_ty, t) } }; @@ -3866,13 +3917,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { element_ty } None => { - let mut err = self.type_error_struct( - expr.span, - |actual| { - format!("cannot index a value of type `{}`", - actual) - }, - base_t); + let mut err = type_error_struct!(tcx.sess, expr.span, base_t, E0608, + "cannot index into a value of type `{}`", + base_t); // Try to give some advice about indexing tuples. if let ty::TyTuple(..) = base_t.sty { let mut needs_note = true; @@ -4020,11 +4067,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn check_stmt(&self, stmt: &'gcx hir::Stmt) { // Don't do all the complex logic below for DeclItem. match stmt.node { - hir::StmtDecl(ref decl, id) => { + hir::StmtDecl(ref decl, _) => { match decl.node { hir::DeclLocal(_) => {} hir::DeclItem(_) => { - self.write_nil(id); return; } } @@ -4040,34 +4086,22 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.diverges.set(Diverges::Maybe); self.has_errors.set(false); - let (node_id, _span) = match stmt.node { - hir::StmtDecl(ref decl, id) => { - let span = match decl.node { + match stmt.node { + hir::StmtDecl(ref decl, _) => { + match decl.node { hir::DeclLocal(ref l) => { self.check_decl_local(&l); - l.span } - hir::DeclItem(_) => {/* ignore for now */ - DUMMY_SP - } - }; - (id, span) + hir::DeclItem(_) => {/* ignore for now */} + } } - hir::StmtExpr(ref expr, id) => { + hir::StmtExpr(ref expr, _) => { // Check with expected type of () - self.check_expr_has_type(&expr, self.tcx.mk_nil()); - (id, expr.span) + self.check_expr_has_type_or_error(&expr, self.tcx.mk_nil()); } - hir::StmtSemi(ref expr, id) => { + hir::StmtSemi(ref expr, _) => { self.check_expr(&expr); - (id, expr.span) } - }; - - if self.has_errors.get() { - self.write_error(node_id); - } else { - self.write_nil(node_id); } // Combine the diverging and has_error flags. @@ -4207,7 +4241,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { hir::StmtSemi(ref e, _) => e, _ => return, }; - let last_expr_ty = self.expr_ty(last_expr); + let last_expr_ty = self.node_ty(last_expr.id); if self.can_sub(self.param_env, last_expr_ty, expected_ty).is_err() { return; } diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index b66e311f04c6..5e79237da69d 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -94,7 +94,8 @@ use rustc::traits; use rustc::ty::{self, Ty, TypeFoldable}; use rustc::infer::{self, GenericKind, SubregionOrigin, VerifyBound}; use rustc::ty::adjustment; -use rustc::ty::wf::ImpliedBound; +use rustc::ty::outlives::Component; +use rustc::ty::wf; use std::mem; use std::ops::Deref; @@ -196,6 +197,24 @@ pub struct RegionCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { } +/// Implied bounds are region relationships that we deduce +/// automatically. The idea is that (e.g.) a caller must check that a +/// function's argument types are well-formed immediately before +/// calling that fn, and hence the *callee* can assume that its +/// argument types are well-formed. This may imply certain relationships +/// between generic parameters. For example: +/// +/// fn foo<'a,T>(x: &'a T) +/// +/// can only be called with a `'a` and `T` such that `&'a T` is WF. +/// For `&'a T` to be WF, `T: 'a` must hold. So we can assume `T: 'a`. +#[derive(Debug)] +enum ImpliedBound<'tcx> { + RegionSubRegion(ty::Region<'tcx>, ty::Region<'tcx>), + RegionSubParam(ty::Region<'tcx>, ty::ParamTy), + RegionSubProjection(ty::Region<'tcx>, ty::ProjectionTy<'tcx>), +} + impl<'a, 'gcx, 'tcx> Deref for RegionCtxt<'a, 'gcx, 'tcx> { type Target = FnCtxt<'a, 'gcx, 'tcx>; fn deref(&self) -> &Self::Target { @@ -386,11 +405,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { for &ty in fn_sig_tys { let ty = self.resolve_type(ty); debug!("relate_free_regions(t={:?})", ty); - let implied_bounds = - ty::wf::implied_bounds(self, self.fcx.param_env, body_id, ty, span); - - // Record any relations between free regions that we observe into the free-region-map. - self.free_region_map.relate_free_regions_from_implied_bounds(&implied_bounds); + let implied_bounds = self.implied_bounds(body_id, ty, span); // But also record other relationships, such as `T:'x`, // that don't go into the free-region-map but which we use @@ -410,16 +425,18 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { ImpliedBound::RegionSubProjection(r_a, projection_b) => { self.region_bound_pairs.push((r_a, GenericKind::Projection(projection_b))); } - ImpliedBound::RegionSubRegion(..) => { + ImpliedBound::RegionSubRegion(r_a, r_b) => { // In principle, we could record (and take // advantage of) every relationship here, but // we are also free not to -- it simply means // strictly less that we can successfully type - // check. (It may also be that we should - // revise our inference system to be more - // general and to make use of *every* - // relationship that arises here, but - // presently we do not.) + // check. Right now we only look for things + // relationships between free regions. (It may + // also be that we should revise our inference + // system to be more general and to make use + // of *every* relationship that arises here, + // but presently we do not.) + self.free_region_map.relate_regions(r_a, r_b); } } } @@ -428,6 +445,138 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { debug!("<< relate_free_regions"); } + /// Compute the implied bounds that a callee/impl can assume based on + /// the fact that caller/projector has ensured that `ty` is WF. See + /// the `ImpliedBound` type for more details. + fn implied_bounds(&mut self, body_id: ast::NodeId, ty: Ty<'tcx>, span: Span) + -> Vec> { + // Sometimes when we ask what it takes for T: WF, we get back that + // U: WF is required; in that case, we push U onto this stack and + // process it next. Currently (at least) these resulting + // predicates are always guaranteed to be a subset of the original + // type, so we need not fear non-termination. + let mut wf_types = vec![ty]; + + let mut implied_bounds = vec![]; + + while let Some(ty) = wf_types.pop() { + // Compute the obligations for `ty` to be well-formed. If `ty` is + // an unresolved inference variable, just substituted an empty set + // -- because the return type here is going to be things we *add* + // to the environment, it's always ok for this set to be smaller + // than the ultimate set. (Note: normally there won't be + // unresolved inference variables here anyway, but there might be + // during typeck under some circumstances.) + let obligations = + wf::obligations(self, self.fcx.param_env, body_id, ty, span) + .unwrap_or(vec![]); + + // NB: All of these predicates *ought* to be easily proven + // true. In fact, their correctness is (mostly) implied by + // other parts of the program. However, in #42552, we had + // an annoying scenario where: + // + // - Some `T::Foo` gets normalized, resulting in a + // variable `_1` and a `T: Trait` constraint + // (not sure why it couldn't immediately get + // solved). This result of `_1` got cached. + // - These obligations were dropped on the floor here, + // rather than being registered. + // - Then later we would get a request to normalize + // `T::Foo` which would result in `_1` being used from + // the cache, but hence without the `T: Trait` + // constraint. As a result, `_1` never gets resolved, + // and we get an ICE (in dropck). + // + // Therefore, we register any predicates involving + // inference variables. We restrict ourselves to those + // involving inference variables both for efficiency and + // to avoids duplicate errors that otherwise show up. + self.fcx.register_predicates( + obligations.iter() + .filter(|o| o.predicate.has_infer_types()) + .cloned()); + + // From the full set of obligations, just filter down to the + // region relationships. + implied_bounds.extend( + obligations + .into_iter() + .flat_map(|obligation| { + assert!(!obligation.has_escaping_regions()); + match obligation.predicate { + ty::Predicate::Trait(..) | + ty::Predicate::Equate(..) | + ty::Predicate::Subtype(..) | + ty::Predicate::Projection(..) | + ty::Predicate::ClosureKind(..) | + ty::Predicate::ObjectSafe(..) => + vec![], + + ty::Predicate::WellFormed(subty) => { + wf_types.push(subty); + vec![] + } + + ty::Predicate::RegionOutlives(ref data) => + match self.tcx.no_late_bound_regions(data) { + None => + vec![], + Some(ty::OutlivesPredicate(r_a, r_b)) => + vec![ImpliedBound::RegionSubRegion(r_b, r_a)], + }, + + ty::Predicate::TypeOutlives(ref data) => + match self.tcx.no_late_bound_regions(data) { + None => vec![], + Some(ty::OutlivesPredicate(ty_a, r_b)) => { + let ty_a = self.resolve_type_vars_if_possible(&ty_a); + let components = self.tcx.outlives_components(ty_a); + self.implied_bounds_from_components(r_b, components) + } + }, + }})); + } + + implied_bounds + } + + /// When we have an implied bound that `T: 'a`, we can further break + /// 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(&self, + sub_region: ty::Region<'tcx>, + sup_components: Vec>) + -> Vec> + { + sup_components + .into_iter() + .flat_map(|component| { + match component { + Component::Region(r) => + vec![ImpliedBound::RegionSubRegion(sub_region, r)], + Component::Param(p) => + vec![ImpliedBound::RegionSubParam(sub_region, p)], + Component::Projection(p) => + vec![ImpliedBound::RegionSubProjection(sub_region, p)], + Component::EscapingProjection(_) => + // If the projection has escaping regions, don't + // try to infer any implied bounds even for its + // free components. This is conservative, because + // the caller will still have to prove that those + // free components outlive `sub_region`. But the + // idea is that the WAY that the caller proves + // that may change in the future and we want to + // give ourselves room to get smarter here. + vec![], + Component::UnresolvedInferenceVariable(..) => + vec![], + } + }) + .collect() + } + fn resolve_regions_and_report_errors(&self) { self.fcx.resolve_regions_and_report_errors(self.subject_def_id, &self.region_maps, @@ -824,18 +973,24 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { } } + /// Create a temporary `MemCategorizationContext` and pass it to the closure. + fn with_mc(&self, f: F) -> R + where F: for<'b> FnOnce(mc::MemCategorizationContext<'b, 'gcx, 'tcx>) -> R + { + f(mc::MemCategorizationContext::with_infer(&self.infcx, + &self.region_maps, + &self.tables.borrow())) + } + /// Invoked on any adjustments that occur. Checks that if this is a region pointer being /// dereferenced, the lifetime of the pointer includes the deref expr. fn constrain_adjustments(&mut self, expr: &hir::Expr) -> mc::McResult> { debug!("constrain_adjustments(expr={:?})", expr); - let mut cmt = { - let mc = mc::MemCategorizationContext::new(self, &self.region_maps); - mc.cat_expr_unadjusted(expr)? - }; + let mut cmt = self.with_mc(|mc| mc.cat_expr_unadjusted(expr))?; - //NOTE(@jroesch): mixed RefCell borrow causes crash - let adjustments = self.tables.borrow().expr_adjustments(&expr).to_vec(); + let tables = self.tables.borrow(); + let adjustments = tables.expr_adjustments(&expr); if adjustments.is_empty() { return Ok(cmt); } @@ -886,10 +1041,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { expr.id, expr_region); } - { - let mc = mc::MemCategorizationContext::new(self, &self.region_maps); - cmt = mc.cat_expr_adjusted(expr, cmt, &adjustment)?; - } + cmt = self.with_mc(|mc| mc.cat_expr_adjusted(expr, cmt, &adjustment))?; if let Categorization::Deref(_, mc::BorrowedPtr(_, r_ptr)) = cmt.cat { self.mk_subregion_due_to_dereference(expr.span, @@ -981,10 +1133,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { mutability: hir::Mutability, base: &hir::Expr) { debug!("link_addr_of(expr={:?}, base={:?})", expr, base); - let cmt = { - let mc = mc::MemCategorizationContext::new(self, &self.region_maps); - ignore_err!(mc.cat_expr(base)) - }; + let cmt = ignore_err!(self.with_mc(|mc| mc.cat_expr(base))); debug!("link_addr_of: cmt={:?}", cmt); @@ -1000,9 +1149,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { None => { return; } Some(ref expr) => &**expr, }; - let mc = &mc::MemCategorizationContext::new(self, &self.region_maps); - let discr_cmt = ignore_err!(mc.cat_expr(init_expr)); - self.link_pattern(mc, discr_cmt, &local.pat); + let discr_cmt = ignore_err!(self.with_mc(|mc| mc.cat_expr(init_expr))); + self.link_pattern(discr_cmt, &local.pat); } /// Computes the guarantors for any ref bindings in a match and @@ -1010,12 +1158,11 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { /// linked to the lifetime of its guarantor (if any). fn link_match(&self, discr: &hir::Expr, arms: &[hir::Arm]) { debug!("regionck::for_match()"); - let mc = &mc::MemCategorizationContext::new(self, &self.region_maps); - let discr_cmt = ignore_err!(mc.cat_expr(discr)); + let discr_cmt = ignore_err!(self.with_mc(|mc| mc.cat_expr(discr))); debug!("discr_cmt={:?}", discr_cmt); for arm in arms { for root_pat in &arm.pats { - self.link_pattern(mc, discr_cmt.clone(), &root_pat); + self.link_pattern(discr_cmt.clone(), &root_pat); } } } @@ -1025,30 +1172,28 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { /// linked to the lifetime of its guarantor (if any). fn link_fn_args(&self, body_scope: CodeExtent, args: &[hir::Arg]) { debug!("regionck::link_fn_args(body_scope={:?})", body_scope); - let mc = &mc::MemCategorizationContext::new(self, &self.region_maps); for arg in args { let arg_ty = self.node_ty(arg.id); let re_scope = self.tcx.mk_region(ty::ReScope(body_scope)); - let arg_cmt = mc.cat_rvalue( - arg.id, arg.pat.span, re_scope, arg_ty); + let arg_cmt = self.with_mc(|mc| { + mc.cat_rvalue(arg.id, arg.pat.span, re_scope, arg_ty) + }); debug!("arg_ty={:?} arg_cmt={:?} arg={:?}", arg_ty, arg_cmt, arg); - self.link_pattern(mc, arg_cmt, &arg.pat); + self.link_pattern(arg_cmt, &arg.pat); } } /// Link lifetimes of any ref bindings in `root_pat` to the pointers found /// in the discriminant, if needed. - fn link_pattern<'t>(&self, - mc: &mc::MemCategorizationContext<'a, 'gcx, 'tcx>, - discr_cmt: mc::cmt<'tcx>, - root_pat: &hir::Pat) { + fn link_pattern(&self, discr_cmt: mc::cmt<'tcx>, root_pat: &hir::Pat) { debug!("link_pattern(discr_cmt={:?}, root_pat={:?})", discr_cmt, root_pat); - let _ = mc.cat_pattern(discr_cmt, root_pat, |_, sub_cmt, sub_pat| { + let _ = self.with_mc(|mc| { + mc.cat_pattern(discr_cmt, root_pat, |sub_cmt, sub_pat| { match sub_pat.node { // `ref x` pattern PatKind::Binding(hir::BindByRef(mutbl), ..) => { @@ -1057,7 +1202,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { } _ => {} } - }); + }) + }); } /// Link lifetime of borrowed pointer resulting from autoref to lifetimes in the value being @@ -1215,8 +1361,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { // Detect by-ref upvar `x`: let cause = match note { mc::NoteUpvarRef(ref upvar_id) => { - let upvar_capture_map = &self.tables.borrow_mut().upvar_capture_map; - match upvar_capture_map.get(upvar_id) { + match self.tables.borrow().upvar_capture_map.get(upvar_id) { Some(&ty::UpvarCapture::ByRef(ref upvar_borrow)) => { // The mutability of the upvar may have been modified // by the above adjustment, so update our local variable. @@ -1357,25 +1502,25 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { fn components_must_outlive(&self, origin: infer::SubregionOrigin<'tcx>, - components: Vec>, + components: Vec>, region: ty::Region<'tcx>) { for component in components { let origin = origin.clone(); match component { - ty::outlives::Component::Region(region1) => { + Component::Region(region1) => { self.sub_regions(origin, region, region1); } - ty::outlives::Component::Param(param_ty) => { + Component::Param(param_ty) => { self.param_ty_must_outlive(origin, region, param_ty); } - ty::outlives::Component::Projection(projection_ty) => { + Component::Projection(projection_ty) => { self.projection_must_outlive(origin, region, projection_ty); } - ty::outlives::Component::EscapingProjection(subcomponents) => { + Component::EscapingProjection(subcomponents) => { self.components_must_outlive(origin, subcomponents, region); } - ty::outlives::Component::UnresolvedInferenceVariable(v) => { + Component::UnresolvedInferenceVariable(v) => { // ignore this, we presume it will yield an error // later, since if a type variable is not resolved by // this point it never will be diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index 25f5418bea9c..59ca896b347f 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -53,31 +53,22 @@ use rustc::hir; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; use rustc::util::nodemap::NodeMap; -/////////////////////////////////////////////////////////////////////////// -// PUBLIC ENTRY POINTS +use std::collections::hash_map::Entry; impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pub fn closure_analyze(&self, body: &'gcx hir::Body) { - let mut seed = SeedBorrowKind::new(self); - seed.visit_body(body); - - let mut adjust = AdjustBorrowKind::new(self, seed.temp_closure_kinds); - adjust.visit_body(body); + InferBorrowKindVisitor { fcx: self }.visit_body(body); // it's our job to process these. assert!(self.deferred_call_resolutions.borrow().is_empty()); } } -/////////////////////////////////////////////////////////////////////////// -// SEED BORROW KIND - -struct SeedBorrowKind<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { +struct InferBorrowKindVisitor<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, - temp_closure_kinds: NodeMap<(ty::ClosureKind, Option<(Span, ast::Name)>)>, } -impl<'a, 'gcx, 'tcx> Visitor<'gcx> for SeedBorrowKind<'a, 'gcx, 'tcx> { +impl<'a, 'gcx, 'tcx> Visitor<'gcx> for InferBorrowKindVisitor<'a, 'gcx, 'tcx> { fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> { NestedVisitorMap::None } @@ -87,7 +78,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for SeedBorrowKind<'a, 'gcx, 'tcx> { hir::ExprClosure(cc, _, body_id, _) => { let body = self.fcx.tcx.hir.body(body_id); self.visit_body(body); - self.check_closure(expr, cc); + self.fcx.analyze_closure(expr.id, expr.span, body, cc); } _ => { } @@ -97,26 +88,33 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for SeedBorrowKind<'a, 'gcx, 'tcx> { } } -impl<'a, 'gcx, 'tcx> SeedBorrowKind<'a, 'gcx, 'tcx> { - fn new(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>) -> SeedBorrowKind<'a, 'gcx, 'tcx> { - SeedBorrowKind { fcx: fcx, temp_closure_kinds: NodeMap() } - } +impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { + fn analyze_closure(&self, + id: ast::NodeId, + span: Span, + body: &hir::Body, + capture_clause: hir::CaptureClause) { + /*! + * Analysis starting point. + */ - fn check_closure(&mut self, - expr: &hir::Expr, - capture_clause: hir::CaptureClause) - { - if !self.fcx.tables.borrow().closure_kinds.contains_key(&expr.id) { - self.temp_closure_kinds.insert(expr.id, (ty::ClosureKind::Fn, None)); - debug!("check_closure: adding closure {:?} as Fn", expr.id); - } + debug!("analyze_closure(id={:?}, body.id={:?})", id, body.id()); - self.fcx.tcx.with_freevars(expr.id, |freevars| { + let infer_kind = match self.tables.borrow_mut().closure_kinds.entry(id) { + Entry::Occupied(_) => false, + Entry::Vacant(entry) => { + debug!("check_closure: adding closure {:?} as Fn", id); + entry.insert((ty::ClosureKind::Fn, None)); + true + } + }; + + self.tcx.with_freevars(id, |freevars| { for freevar in freevars { let def_id = freevar.def.def_id(); - let var_node_id = self.fcx.tcx.hir.as_local_node_id(def_id).unwrap(); + let var_node_id = self.tcx.hir.as_local_node_id(def_id).unwrap(); let upvar_id = ty::UpvarId { var_id: var_node_id, - closure_expr_id: expr.id }; + closure_expr_id: id }; debug!("seed upvar_id {:?}", upvar_id); let capture_kind = match capture_clause { @@ -124,58 +122,41 @@ impl<'a, 'gcx, 'tcx> SeedBorrowKind<'a, 'gcx, 'tcx> { ty::UpvarCapture::ByValue } hir::CaptureByRef => { - let origin = UpvarRegion(upvar_id, expr.span); - let freevar_region = self.fcx.next_region_var(origin); + let origin = UpvarRegion(upvar_id, span); + let freevar_region = self.next_region_var(origin); let upvar_borrow = ty::UpvarBorrow { kind: ty::ImmBorrow, region: freevar_region }; ty::UpvarCapture::ByRef(upvar_borrow) } }; - self.fcx.tables.borrow_mut().upvar_capture_map.insert(upvar_id, capture_kind); + self.tables.borrow_mut().upvar_capture_map.insert(upvar_id, capture_kind); } }); - } -} - -/////////////////////////////////////////////////////////////////////////// -// ADJUST BORROW KIND - -struct AdjustBorrowKind<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { - fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, - temp_closure_kinds: NodeMap<(ty::ClosureKind, Option<(Span, ast::Name)>)>, -} - -impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { - fn new(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, - temp_closure_kinds: NodeMap<(ty::ClosureKind, Option<(Span, ast::Name)>)>) - -> AdjustBorrowKind<'a, 'gcx, 'tcx> { - AdjustBorrowKind { fcx: fcx, temp_closure_kinds: temp_closure_kinds } - } - - fn analyze_closure(&mut self, - id: ast::NodeId, - span: Span, - body: &hir::Body) { - /*! - * Analysis starting point. - */ - - debug!("analyze_closure(id={:?}, body.id={:?})", id, body.id()); { - let body_owner_def_id = self.fcx.tcx.hir.body_owner_def_id(body.id()); - let region_maps = &self.fcx.tcx.region_maps(body_owner_def_id); - let param_env = self.fcx.param_env; - let mut euv = - euv::ExprUseVisitor::with_options(self, - self.fcx, - param_env, - region_maps, - mc::MemCategorizationOptions { - during_closure_kind_inference: true - }); - euv.consume_body(body); + let body_owner_def_id = self.tcx.hir.body_owner_def_id(body.id()); + let region_maps = &self.tcx.region_maps(body_owner_def_id); + let mut delegate = InferBorrowKind { + fcx: self, + adjust_closure_kinds: NodeMap(), + adjust_upvar_captures: ty::UpvarCaptureMap::default(), + }; + euv::ExprUseVisitor::with_infer(&mut delegate, + &self.infcx, + self.param_env, + region_maps, + &self.tables.borrow()) + .consume_body(body); + + // Write the adjusted values back into the main tables. + if infer_kind { + if let Some(kind) = delegate.adjust_closure_kinds.remove(&id) { + self.tables.borrow_mut().closure_kinds.insert(id, kind); + } + } + self.tables.borrow_mut().upvar_capture_map.extend( + delegate.adjust_upvar_captures); } // Now that we've analyzed the closure, we know how each @@ -191,7 +172,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { // inference algorithm will reject it). // Extract the type variables UV0...UVn. - let (def_id, closure_substs) = match self.fcx.node_ty(id).sty { + let (def_id, closure_substs) = match self.node_ty(id).sty { ty::TyClosure(def_id, substs) => (def_id, substs), ref t => { span_bug!( @@ -206,44 +187,41 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { debug!("analyze_closure: id={:?} closure_substs={:?} final_upvar_tys={:?}", id, closure_substs, final_upvar_tys); for (upvar_ty, final_upvar_ty) in - closure_substs.upvar_tys(def_id, self.fcx.tcx).zip(final_upvar_tys) + closure_substs.upvar_tys(def_id, self.tcx).zip(final_upvar_tys) { - self.fcx.demand_eqtype(span, final_upvar_ty, upvar_ty); + self.demand_eqtype(span, final_upvar_ty, upvar_ty); } - // If we are also inferred the closure kind here, update the - // main table and process any deferred resolutions. - if let Some(&(kind, context)) = self.temp_closure_kinds.get(&id) { - self.fcx.tables.borrow_mut().closure_kinds.insert(id, (kind, context)); - let closure_def_id = self.fcx.tcx.hir.local_def_id(id); - debug!("closure_kind({:?}) = {:?}", closure_def_id, kind); - + // If we are also inferred the closure kind here, + // process any deferred resolutions. + if infer_kind { + let closure_def_id = self.tcx.hir.local_def_id(id); let deferred_call_resolutions = - self.fcx.remove_deferred_call_resolutions(closure_def_id); + self.remove_deferred_call_resolutions(closure_def_id); for deferred_call_resolution in deferred_call_resolutions { - deferred_call_resolution.resolve(self.fcx); + deferred_call_resolution.resolve(self); } } } // Returns a list of `ClosureUpvar`s for each upvar. - fn final_upvar_tys(&mut self, closure_id: ast::NodeId) -> Vec> { + fn final_upvar_tys(&self, closure_id: ast::NodeId) -> Vec> { // Presently an unboxed closure type cannot "escape" out of a // function, so we will only encounter ones that originated in the // local crate or were inlined into it along with some function. // This may change if abstract return types of some sort are // implemented. - let tcx = self.fcx.tcx; + let tcx = self.tcx; tcx.with_freevars(closure_id, |freevars| { freevars.iter().map(|freevar| { let def_id = freevar.def.def_id(); let var_id = tcx.hir.as_local_node_id(def_id).unwrap(); - let freevar_ty = self.fcx.node_ty(var_id); + let freevar_ty = self.node_ty(var_id); let upvar_id = ty::UpvarId { var_id: var_id, closure_expr_id: closure_id }; - let capture = self.fcx.upvar_capture(upvar_id).unwrap(); + let capture = self.tables.borrow().upvar_capture(upvar_id); debug!("var_id={:?} freevar_ty={:?} capture={:?}", var_id, freevar_ty, capture); @@ -260,7 +238,15 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { }).collect() }) } +} +struct InferBorrowKind<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { + fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, + adjust_closure_kinds: NodeMap<(ty::ClosureKind, Option<(Span, ast::Name)>)>, + adjust_upvar_captures: ty::UpvarCaptureMap<'tcx>, +} + +impl<'a, 'gcx, 'tcx> InferBorrowKind<'a, 'gcx, 'tcx> { fn adjust_upvar_borrow_kind_for_consume(&mut self, cmt: mc::cmt<'tcx>, mode: euv::ConsumeMode) @@ -297,9 +283,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { guarantor.span, tcx.hir.name(upvar_id.var_id)); - let upvar_capture_map = - &mut self.fcx.tables.borrow_mut().upvar_capture_map; - upvar_capture_map.insert(upvar_id, ty::UpvarCapture::ByValue); + self.adjust_upvar_captures.insert(upvar_id, ty::UpvarCapture::ByValue); } mc::NoteClosureEnv(upvar_id) => { // we get just a closureenv ref if this is a @@ -410,11 +394,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { // upvar, then we need to modify the // borrow_kind of the upvar to make sure it // is inferred to mutable if necessary - { - let upvar_capture_map = &mut self.fcx.tables.borrow_mut().upvar_capture_map; - let ub = upvar_capture_map.get_mut(&upvar_id).unwrap(); - self.adjust_upvar_borrow_kind(upvar_id, ub, borrow_kind); - } + self.adjust_upvar_borrow_kind(upvar_id, borrow_kind); // also need to be in an FnMut closure since this is not an ImmBorrow self.adjust_closure_kind(upvar_id.closure_expr_id, @@ -448,22 +428,25 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { /// some particular use. fn adjust_upvar_borrow_kind(&mut self, upvar_id: ty::UpvarId, - upvar_capture: &mut ty::UpvarCapture, kind: ty::BorrowKind) { + let upvar_capture = self.adjust_upvar_captures.get(&upvar_id).cloned() + .unwrap_or_else(|| self.fcx.tables.borrow().upvar_capture(upvar_id)); debug!("adjust_upvar_borrow_kind(upvar_id={:?}, upvar_capture={:?}, kind={:?})", upvar_id, upvar_capture, kind); - match *upvar_capture { + match upvar_capture { ty::UpvarCapture::ByValue => { // Upvar is already by-value, the strongest criteria. } - ty::UpvarCapture::ByRef(ref mut upvar_borrow) => { + ty::UpvarCapture::ByRef(mut upvar_borrow) => { match (upvar_borrow.kind, kind) { // Take RHS: (ty::ImmBorrow, ty::UniqueImmBorrow) | (ty::ImmBorrow, ty::MutBorrow) | (ty::UniqueImmBorrow, ty::MutBorrow) => { upvar_borrow.kind = kind; + self.adjust_upvar_captures.insert(upvar_id, + ty::UpvarCapture::ByRef(upvar_borrow)); } // Take LHS: (ty::ImmBorrow, ty::ImmBorrow) | @@ -484,7 +467,9 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { debug!("adjust_closure_kind(closure_id={}, new_kind={:?}, upvar_span={:?}, var_name={})", closure_id, new_kind, upvar_span, var_name); - if let Some(&(existing_kind, _)) = self.temp_closure_kinds.get(&closure_id) { + let closure_kind = self.adjust_closure_kinds.get(&closure_id).cloned() + .or_else(|| self.fcx.tables.borrow().closure_kinds.get(&closure_id).cloned()); + if let Some((existing_kind, _)) = closure_kind { debug!("adjust_closure_kind: closure_id={}, existing_kind={:?}, new_kind={:?}", closure_id, existing_kind, new_kind); @@ -500,7 +485,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) | (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => { // new kind is stronger than the old kind - self.temp_closure_kinds.insert( + self.adjust_closure_kinds.insert( closure_id, (new_kind, Some((upvar_span, var_name))) ); @@ -510,27 +495,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { } } -impl<'a, 'gcx, 'tcx> Visitor<'gcx> for AdjustBorrowKind<'a, 'gcx, 'tcx> { - fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> { - NestedVisitorMap::None - } - - fn visit_fn(&mut self, - fn_kind: intravisit::FnKind<'gcx>, - decl: &'gcx hir::FnDecl, - body: hir::BodyId, - span: Span, - id: ast::NodeId) - { - intravisit::walk_fn(self, fn_kind, decl, body, span, id); - - let body = self.fcx.tcx.hir.body(body); - self.visit_body(body); - self.analyze_closure(id, span, body); - } -} - -impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for AdjustBorrowKind<'a, 'gcx, 'tcx> { +impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'gcx, 'tcx> { fn consume(&mut self, _consume_id: ast::NodeId, _consume_span: Span, diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 012fde16d875..4af262bcb78d 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -155,11 +155,6 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> { NestedVisitorMap::None } - fn visit_stmt(&mut self, s: &'gcx hir::Stmt) { - self.visit_node_id(s.span, s.node.id()); - intravisit::walk_stmt(self, s); - } - fn visit_expr(&mut self, e: &'gcx hir::Expr) { self.fix_scalar_builtin_expr(e); diff --git a/src/librustc_typeck/coherence/builtin.rs b/src/librustc_typeck/coherence/builtin.rs index 377b7b069d33..ccbc02990418 100644 --- a/src/librustc_typeck/coherence/builtin.rs +++ b/src/librustc_typeck/coherence/builtin.rs @@ -208,7 +208,7 @@ pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, source, target); - tcx.infer_ctxt(()).enter(|infcx| { + tcx.infer_ctxt().enter(|infcx| { let cause = ObligationCause::misc(span, impl_node_id); let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>, mt_b: ty::TypeAndMut<'tcx>, diff --git a/src/librustc_typeck/coherence/inherent_impls.rs b/src/librustc_typeck/coherence/inherent_impls.rs index f7ebc2104422..e24d76600218 100644 --- a/src/librustc_typeck/coherence/inherent_impls.rs +++ b/src/librustc_typeck/coherence/inherent_impls.rs @@ -17,7 +17,7 @@ //! `tcx.inherent_impls(def_id)`). That value, however, //! is computed by selecting an idea from this table. -use rustc::dep_graph::DepNode; +use rustc::dep_graph::DepKind; use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc::hir; use rustc::hir::itemlikevisit::ItemLikeVisitor; @@ -79,7 +79,8 @@ pub fn inherent_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }); for &impl_def_id in &result[..] { - tcx.dep_graph.read(DepNode::Hir(impl_def_id)); + let def_path_hash = tcx.def_path_hash(impl_def_id); + tcx.dep_graph.read(def_path_hash.to_dep_node(DepKind::Hir)); } result diff --git a/src/librustc_typeck/coherence/inherent_impls_overlap.rs b/src/librustc_typeck/coherence/inherent_impls_overlap.rs index afeb85a7a065..078ae34bc524 100644 --- a/src/librustc_typeck/coherence/inherent_impls_overlap.rs +++ b/src/librustc_typeck/coherence/inherent_impls_overlap.rs @@ -70,7 +70,7 @@ impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> { for (i, &impl1_def_id) in impls.iter().enumerate() { for &impl2_def_id in &impls[(i + 1)..] { - self.tcx.infer_ctxt(()).enter(|infcx| { + self.tcx.infer_ctxt().enter(|infcx| { if traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id).is_some() { self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id) } diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs index ba1d7b18e8c7..59ebae16d08c 100644 --- a/src/librustc_typeck/coherence/overlap.rs +++ b/src/librustc_typeck/coherence/overlap.rs @@ -15,7 +15,6 @@ use rustc::traits; use rustc::ty::{self, TyCtxt, TypeFoldable}; use syntax::ast; -use rustc::dep_graph::DepNode; use rustc::hir; use rustc::hir::itemlikevisit::ItemLikeVisitor; @@ -38,9 +37,6 @@ pub fn check_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, node_id: ast::NodeId) { return } - let _task = - tcx.dep_graph.in_task(DepNode::CoherenceOverlapCheck(trait_def_id)); - // Trigger building the specialization graph for the trait of this impl. // This will detect any overlap errors. tcx.specialization_graph_of(trait_def_id); diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 910d5d740247..f72af2084f02 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -1642,7 +1642,7 @@ fn f() {} It is not possible to declare type parameters on a function that has the `start` attribute. Such a function must have the following type signature (for more -information: http://doc.rust-lang.org/stable/book/no-stdlib.html): +information: http://doc.rust-lang.org/stable/book/first-edition/no-stdlib.html): ```ignore fn(isize, *const *const u8) -> isize; @@ -2265,8 +2265,8 @@ If `ForeignTrait` is a trait defined in some external crate `foo`, then the following trait `impl` is an error: ```compile_fail,E0210 -extern crate collections; -use collections::range::RangeArgument; +extern crate alloc; +use alloc::range::RangeArgument; impl RangeArgument for T { } // error @@ -3186,7 +3186,7 @@ impl Baz for Bar { } // Note: This is OK E0374: r##" A struct without a field containing an unsized type cannot implement `CoerceUnsized`. An -[unsized type](https://doc.rust-lang.org/book/unsized-types.html) +[unsized type](https://doc.rust-lang.org/book/first-edition/unsized-types.html) is any type that the compiler doesn't know the length or alignment of at compile time. Any struct containing an unsized type is also unsized. @@ -3245,9 +3245,9 @@ A struct with more than one field containing an unsized type cannot implement `CoerceUnsized`. This only occurs when you are trying to coerce one of the types in your struct to another type in the struct. In this case we try to impl `CoerceUnsized` from `T` to `U` which are both types that the struct -takes. An [unsized type](https://doc.rust-lang.org/book/unsized-types.html) -is any type that the compiler doesn't know the length or alignment of at -compile time. Any struct containing an unsized type is also unsized. +takes. An [unsized type] is any type that the compiler doesn't know the length +or alignment of at compile time. Any struct containing an unsized type is also +unsized. Example of erroneous code: @@ -3292,6 +3292,7 @@ fn coerce_foo, U>(t: T) -> Foo { } ``` +[unsized type]: https://doc.rust-lang.org/book/first-edition/unsized-types.html "##, E0376: r##" @@ -3300,7 +3301,7 @@ The type you are trying to impl `CoerceUnsized` for is not a struct. already able to be coerced without an implementation of `CoerceUnsized` whereas a struct containing an unsized type needs to know the unsized type field it's containing is able to be coerced. An -[unsized type](https://doc.rust-lang.org/book/unsized-types.html) +[unsized type](https://doc.rust-lang.org/book/first-edition/unsized-types.html) is any type that the compiler doesn't know the length or alignment of at compile time. Any struct containing an unsized type is also unsized. @@ -4095,6 +4096,133 @@ assert_eq!(!Question::No, true); ``` "##, +E0608: r##" +An attempt to index into a type which doesn't implement the `std::ops::Index` +trait was performed. + +Erroneous code example: + +```compile_fail,E0608 +0u8[2]; // error: cannot index into a value of type `u8` +``` + +To be able to index into a type it needs to implement the `std::ops::Index` +trait. Example: + +``` +let v: Vec = vec![0, 1, 2, 3]; + +// The `Vec` type implements the `Index` trait so you can do: +println!("{}", v[2]); +``` +"##, + +E0609: r##" +Attempted to access a non-existent field in a struct. + +Erroneous code example: + +```compile_fail,E0609 +struct StructWithFields { + x: u32, +} + +let s = StructWithFields { x: 0 }; +println!("{}", s.foo); // error: no field `foo` on type `StructWithFields` +``` + +To fix this error, check that you didn't misspell the field's name or that the +field actually exists. Example: + +``` +struct StructWithFields { + x: u32, +} + +let s = StructWithFields { x: 0 }; +println!("{}", s.x); // ok! +``` +"##, + +E0610: r##" +Attempted to access a field on a primitive type. + +Erroneous code example: + +```compile_fail,E0610 +let x: u32 = 0; +println!("{}", x.foo); // error: `{integer}` is a primitive type, therefore + // doesn't have fields +``` + +Primitive types are the most basic types available in Rust and don't have +fields. To access data via named fields, struct types are used. Example: + +``` +// We declare struct called `Foo` containing two fields: +struct Foo { + x: u32, + y: i64, +} + +// We create an instance of this struct: +let variable = Foo { x: 0, y: -12 }; +// And we can now access its fields: +println!("x: {}, y: {}", variable.x, variable.y); +``` + +For more information see The Rust Book: https://doc.rust-lang.org/book/ +"##, + +E0617: r##" +Attempted to pass an invalid type of variable into a variadic function. + +Erroneous code example: + +```compile_fail,E0617 +extern { + fn printf(c: *const i8, ...); +} + +unsafe { + printf(::std::ptr::null(), 0f32); + // error: can't pass an `f32` to variadic function, cast to `c_double` +} +``` + +To fix this error, you need to pass variables corresponding to C types as much +as possible. For better explanations, see The Rust Book: +https://doc.rust-lang.org/book/ +"##, + +E0618: r##" +Attempted to call something which isn't a function nor a method. + +Erroneous code examples: + +```compile_fail,E0618 +enum X { + Entry, +} + +X::Entry(); // error: expected function, found `X::Entry` + +// Or even simpler: +let x = 0i32; +x(); // error: expected function, found `i32` +``` + +Only functions and methods can be called using `()`. Example: + +``` +// We declare a function: +fn i_am_a_function() {} + +// And we call it: +i_am_a_function(); +``` +"##, + } register_diagnostics! { diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 06cb9f948c9b..26ea3ab3a335 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -155,7 +155,7 @@ fn require_same_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, expected: Ty<'tcx>, actual: Ty<'tcx>) -> bool { - tcx.infer_ctxt(()).enter(|ref infcx| { + tcx.infer_ctxt().enter(|ref infcx| { let param_env = ty::ParamEnv::empty(Reveal::UserFacing); let mut fulfill_cx = FulfillmentContext::new(); match infcx.at(&cause, param_env).eq(expected, actual) { diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index cb2ee7dd1bcd..c434edb1c31a 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -15,7 +15,7 @@ use hir::def_id::DefId; use middle::resolve_lifetime as rl; -use rustc::dep_graph::{AssertDepGraphSafe, DepNode}; +use rustc::dep_graph::{AssertDepGraphSafe, DepKind}; use rustc::ty::subst::Substs; use rustc::ty::{self, Ty, TyCtxt}; use rustc::hir::map as hir_map; @@ -104,7 +104,8 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ConstraintContext<'a, 'tcx> { hir::ItemEnum(..) | hir::ItemStruct(..) | hir::ItemUnion(..) => { - tcx.dep_graph.with_task(DepNode::ItemVarianceConstraints(def_id), + let dep_node = def_id.to_dep_node(tcx, DepKind::ItemVarianceConstraints); + tcx.dep_graph.with_task(dep_node, AssertDepGraphSafe(self), def_id, visit_item_task); diff --git a/src/librustc_typeck/variance/mod.rs b/src/librustc_typeck/variance/mod.rs index 1afe2725ac87..8f9f40ca40b0 100644 --- a/src/librustc_typeck/variance/mod.rs +++ b/src/librustc_typeck/variance/mod.rs @@ -12,7 +12,7 @@ //! parameters. See README.md for details. use arena; -use rustc::dep_graph::DepNode; +use rustc::dep_graph::DepKind; use rustc::hir; use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc::ty::{self, CrateVariancesMap, TyCtxt}; @@ -72,12 +72,15 @@ fn variances_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_def_id: DefId) // Lacking red/green, we read the variances for all items here // but ignore the dependencies, then re-synthesize the ones we need. let crate_map = tcx.dep_graph.with_ignore(|| tcx.crate_variances(LOCAL_CRATE)); - tcx.dep_graph.read(DepNode::ItemVarianceConstraints(item_def_id)); + let dep_node = item_def_id.to_dep_node(tcx, DepKind::ItemVarianceConstraints); + tcx.dep_graph.read(dep_node); for &dep_def_id in crate_map.dependencies.less_than(&item_def_id) { if dep_def_id.is_local() { - tcx.dep_graph.read(DepNode::ItemVarianceConstraints(dep_def_id)); + let dep_node = dep_def_id.to_dep_node(tcx, DepKind::ItemVarianceConstraints); + tcx.dep_graph.read(dep_node); } else { - tcx.dep_graph.read(DepNode::ItemVariances(dep_def_id)); + let dep_node = dep_def_id.to_dep_node(tcx, DepKind::ItemVariances); + tcx.dep_graph.read(dep_node); } } diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 8f7add14d0a0..aeade4704822 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -77,10 +77,10 @@ pub fn try_inline(cx: &DocContext, def: Def, name: ast::Name) ret.extend(build_impls(cx, did)); clean::EnumItem(build_enum(cx, did)) } - // Assume that the enum type is reexported next to the variant, and - // variants don't show up in documentation specially. - // Similarly, consider that struct type is reexported next to its constructor. - Def::Variant(..) | + // Never inline enum variants but leave them shown as reexports. + Def::Variant(..) => return None, + // Assume that enum variants and struct types are reexported next to + // their constructors. Def::VariantCtor(..) | Def::StructCtor(..) => return Some(Vec::new()), Def::Mod(did) => { @@ -151,7 +151,7 @@ pub fn build_external_trait(cx: &DocContext, did: DefId) -> clean::Trait { fn build_external_function(cx: &DocContext, did: DefId) -> clean::Function { let sig = cx.tcx.type_of(did).fn_sig(); - let constness = if cx.tcx.sess.cstore.is_const_fn(did) { + let constness = if cx.tcx.is_const_fn(did) { hir::Constness::Const } else { hir::Constness::NotConst @@ -352,7 +352,7 @@ pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec) { clean::TyMethodItem(clean::TyMethod { unsafety, decl, generics, abi }) => { - let constness = if tcx.sess.cstore.is_const_fn(item.def_id) { + let constness = if tcx.is_const_fn(item.def_id) { hir::Constness::Const } else { hir::Constness::NotConst @@ -443,7 +443,7 @@ fn build_module(cx: &DocContext, did: DefId) -> clean::Module { // two namespaces, so the target may be listed twice. Make sure we only // visit each node at most once. let mut visited = FxHashSet(); - for item in cx.tcx.sess.cstore.item_children(did) { + for item in cx.tcx.sess.cstore.item_children(did, cx.tcx.sess) { let def_id = item.def.def_id(); if cx.tcx.sess.cstore.visibility(def_id) == ty::Visibility::Public { if !visited.insert(def_id) { continue } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 20ce2c024962..8fc8ccd0cfd9 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -241,7 +241,7 @@ impl Clean for CrateNum { } }).collect() } else { - cx.tcx.sess.cstore.item_children(root).iter().map(|item| item.def) + cx.tcx.sess.cstore.item_children(root, cx.tcx.sess).iter().map(|item| item.def) .filter_map(as_primitive).collect() }; @@ -311,6 +311,9 @@ impl Item { pub fn is_ty_method(&self) -> bool { self.type_() == ItemType::TyMethod } + pub fn is_typedef(&self) -> bool { + self.type_() == ItemType::Typedef + } pub fn is_primitive(&self) -> bool { self.type_() == ItemType::Primitive } diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 86660c28f80a..635691dd3458 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -459,22 +459,10 @@ pub fn href(did: DefId) -> Option<(String, ItemType, Vec)> { /// rendering function with the necessary arguments for linking to a local path. fn resolved_path(w: &mut fmt::Formatter, did: DefId, path: &clean::Path, print_all: bool, use_absolute: bool) -> fmt::Result { - let empty = clean::PathSegment { - name: String::new(), - params: clean::PathParameters::Parenthesized { - inputs: Vec::new(), - output: None, - } - }; - let last = path.segments.last() - .unwrap_or(&empty); - let rel_root = if path.segments.is_empty() { - None - } else { - match &*path.segments[0].name { - "self" => Some("./".to_string()), - _ => None, - } + let last = path.segments.last().unwrap(); + let rel_root = match &*path.segments[0].name { + "self" => Some("./".to_string()), + _ => None, }; if print_all { @@ -508,7 +496,7 @@ fn resolved_path(w: &mut fmt::Formatter, did: DefId, path: &clean::Path, Some((_, _, fqp)) => { format!("{}::{}", fqp[..fqp.len() - 1].join("::"), - HRef::new(did, fqp.last().unwrap_or(&String::new()))) + HRef::new(did, fqp.last().unwrap())) } None => format!("{}", HRef::new(did, &last.name)), } @@ -740,10 +728,8 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter, use_absolute: bool) -> fmt: } clean::QPath { ref name, ref self_type, ref trait_ } => { let should_show_cast = match *trait_ { - box clean::ResolvedPath { .. } => { - let path = clean::Path::singleton(name.clone()); - !path.segments.is_empty() && &format!("{:#}", trait_) != "()" && - &format!("{:#}", self_type) != "Self" + box clean::ResolvedPath { ref path, .. } => { + !path.segments.is_empty() && !self_type.is_self_type() } _ => true, }; @@ -772,8 +758,18 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter, use_absolute: bool) -> fmt: // everything comes in as a fully resolved QPath (hard to // look at). box clean::ResolvedPath { did, ref typarams, .. } => { - let path = clean::Path::singleton(name.clone()); - resolved_path(f, did, &path, true, use_absolute)?; + match href(did) { + Some((ref url, _, ref path)) if !f.alternate() => { + write!(f, + "{name}", + url = url, + shortty = ItemType::AssociatedType, + name = name, + path = path.join("::"))?; + } + _ => write!(f, "{}", name)?, + } // FIXME: `typarams` are not rendered, and this seems bad? drop(typarams); diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 0d9f98e05d2c..0299e45599b8 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -492,7 +492,7 @@ pub fn run(mut krate: clean::Crate, } } } - try_err!(mkdir(&dst), &dst); + try_err!(fs::create_dir_all(&dst), &dst); krate = render_sources(&dst, &mut scx, krate)?; let cx = Context { current: Vec::new(), @@ -658,7 +658,7 @@ fn write_shared(cx: &Context, // Write out the shared files. Note that these are shared among all rustdoc // docs placed in the output directory, so this needs to be a synchronized // operation with respect to all other rustdocs running around. - try_err!(mkdir(&cx.dst), &cx.dst); + try_err!(fs::create_dir_all(&cx.dst), &cx.dst); let _lock = flock::Lock::panicking_new(&cx.dst.join(".lock"), true, true, true); // Add all the static files. These may already exist, but we just @@ -808,10 +808,8 @@ fn write_shared(cx: &Context, fn render_sources(dst: &Path, scx: &mut SharedContext, krate: clean::Crate) -> Result { info!("emitting source files"); - let dst = dst.join("src"); - try_err!(mkdir(&dst), &dst); - let dst = dst.join(&krate.name); - try_err!(mkdir(&dst), &dst); + let dst = dst.join("src").join(&krate.name); + try_err!(fs::create_dir_all(&dst), &dst); let mut folder = SourceCollector { dst: dst, scx: scx, @@ -825,19 +823,6 @@ fn write(dst: PathBuf, contents: &[u8]) -> Result<(), Error> { Ok(try_err!(try_err!(File::create(&dst), &dst).write_all(contents), &dst)) } -/// Makes a directory on the filesystem, failing the thread if an error occurs -/// and skipping if the directory already exists. -/// -/// Note that this also handles races as rustdoc is likely to be run -/// concurrently against another invocation. -fn mkdir(path: &Path) -> io::Result<()> { - match fs::create_dir(path) { - Ok(()) => Ok(()), - Err(ref e) if e.kind() == io::ErrorKind::AlreadyExists => Ok(()), - Err(e) => Err(e) - } -} - /// Takes a path to a source file and cleans the path to it. This canonicalizes /// things like ".." to components which preserve the "top down" hierarchy of a /// static HTML tree. Each component in the cleaned path will be passed as an @@ -951,7 +936,7 @@ impl<'a> SourceCollector<'a> { let mut href = String::new(); clean_srcpath(&self.scx.src_root, &p, false, |component| { cur.push(component); - mkdir(&cur).unwrap(); + fs::create_dir_all(&cur).unwrap(); root_path.push_str("../"); href.push_str(component); href.push('/'); @@ -1349,7 +1334,7 @@ impl Context { // these modules are recursed into, but not rendered normally // (a flag on the context). if !self.render_redirect_pages { - self.render_redirect_pages = maybe_ignore_item(&item); + self.render_redirect_pages = item.is_stripped(); } if item.is_mod() { @@ -1432,7 +1417,7 @@ impl Context { // BTreeMap instead of HashMap to get a sorted output let mut map = BTreeMap::new(); for item in &m.items { - if maybe_ignore_item(item) { continue } + if item.is_stripped() { continue } let short = item.type_().css_class(); let myname = match item.name { @@ -1733,7 +1718,7 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context, if let clean::DefaultImplItem(..) = items[*i].inner { return false; } - !maybe_ignore_item(&items[*i]) + !items[*i].is_stripped() }).collect::>(); // the order of item types in the listing @@ -1902,17 +1887,6 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context, Ok(()) } -fn maybe_ignore_item(it: &clean::Item) -> bool { - match it.inner { - clean::StrippedItem(..) => true, - clean::ModuleItem(ref m) => { - it.doc_value().is_none() && m.items.is_empty() - && it.visibility != Some(clean::Public) - }, - _ => false, - } -} - fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Vec { let mut stability = vec![]; @@ -3082,7 +3056,13 @@ fn item_typedef(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, where_clause = WhereClause { gens: &t.generics, indent: 0, end_newline: true }, type_ = t.type_)?; - document(w, cx, it) + document(w, cx, it)?; + + // Render any items associated directly to this alias, as otherwise they + // won't be visible anywhere in the docs. It would be nice to also show + // associated items from the aliased type (see discussion in #32077), but + // we need #14072 to make sense of the generics. + render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All) } impl<'a> fmt::Display for Sidebar<'a> { @@ -3092,7 +3072,7 @@ impl<'a> fmt::Display for Sidebar<'a> { let parentlen = cx.current.len() - if it.is_mod() {1} else {0}; if it.is_struct() || it.is_trait() || it.is_primitive() || it.is_union() - || it.is_enum() || it.is_mod() + || it.is_enum() || it.is_mod() || it.is_typedef() { write!(fmt, "

")?; match it.inner { @@ -3101,6 +3081,7 @@ impl<'a> fmt::Display for Sidebar<'a> { clean::PrimitiveItem(..) => write!(fmt, "Primitive Type ")?, clean::UnionItem(..) => write!(fmt, "Union ")?, clean::EnumItem(..) => write!(fmt, "Enum ")?, + clean::TypedefItem(..) => write!(fmt, "Type Definition ")?, clean::ModuleItem(..) => if it.is_crate() { write!(fmt, "Crate ")?; } else { @@ -3117,6 +3098,7 @@ impl<'a> fmt::Display for Sidebar<'a> { clean::PrimitiveItem(ref p) => sidebar_primitive(fmt, it, p)?, clean::UnionItem(ref u) => sidebar_union(fmt, it, u)?, clean::EnumItem(ref e) => sidebar_enum(fmt, it, e)?, + clean::TypedefItem(ref t, _) => sidebar_typedef(fmt, it, t)?, clean::ModuleItem(ref m) => sidebar_module(fmt, it, &m.items)?, _ => (), } @@ -3259,6 +3241,16 @@ fn sidebar_primitive(fmt: &mut fmt::Formatter, it: &clean::Item, Ok(()) } +fn sidebar_typedef(fmt: &mut fmt::Formatter, it: &clean::Item, + _t: &clean::Typedef) -> fmt::Result { + let sidebar = sidebar_assoc_items(it); + + if !sidebar.is_empty() { + write!(fmt, "

    {}
", sidebar)?; + } + Ok(()) +} + fn sidebar_union(fmt: &mut fmt::Formatter, it: &clean::Item, u: &clean::Union) -> fmt::Result { let mut sidebar = String::new(); @@ -3314,7 +3306,7 @@ fn sidebar_module(fmt: &mut fmt::Formatter, _it: &clean::Item, if let clean::DefaultImplItem(..) = it.inner { false } else { - !maybe_ignore_item(it) && !it.is_stripped() && it.type_() == myty + !it.is_stripped() && it.type_() == myty } }) { let (short, name) = match myty { diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 53e341226af3..38f83687d1d8 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -1,12 +1,14 @@ -// 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. +/*! + * 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. + */ /*jslint browser: true, es5: true */ /*globals $: true, rootPath: true */ diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs index 1cc4f9371cb6..8f6faabd157d 100644 --- a/src/librustdoc/passes/mod.rs +++ b/src/librustdoc/passes/mod.rs @@ -145,20 +145,12 @@ impl<'a> fold::DocFolder for Stripper<'a> { self.fold_item_recur(i) }; - i.and_then(|i| { - match i.inner { - // emptied modules have no need to exist - clean::ModuleItem(ref m) - if m.items.is_empty() && - i.doc_value().is_none() => None, - _ => { - if self.update_retained { - self.retained.insert(i.def_id); - } - Some(i) - } + if let Some(ref i) = i { + if self.update_retained { + self.retained.insert(i.def_id); } - }) + } + i } } diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 39ebe490d0eb..657aab958bb9 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -329,25 +329,21 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { if !self.view_item_stack.insert(def_node_id) { return false } let ret = match tcx.hir.get(def_node_id) { - hir_map::NodeItem(it) => { + hir_map::NodeItem(&hir::Item { node: hir::ItemMod(ref m), .. }) if glob => { let prev = mem::replace(&mut self.inlining, true); - if glob { - match it.node { - hir::ItemMod(ref m) => { - for i in &m.item_ids { - let i = self.cx.tcx.hir.expect_item(i.id); - self.visit_item(i, None, om); - } - } - hir::ItemEnum(..) => {} - _ => { panic!("glob not mapped to a module or enum"); } - } - } else { - self.visit_item(it, renamed, om); + for i in &m.item_ids { + let i = self.cx.tcx.hir.expect_item(i.id); + self.visit_item(i, None, om); } self.inlining = prev; true } + hir_map::NodeItem(it) if !glob => { + let prev = mem::replace(&mut self.inlining, true); + self.visit_item(it, renamed, om); + self.inlining = prev; + true + } _ => false, }; self.view_item_stack.remove(&def_node_id); diff --git a/src/librustdoc/visit_lib.rs b/src/librustdoc/visit_lib.rs index 40a6ffe9505f..5518d854348c 100644 --- a/src/librustdoc/visit_lib.rs +++ b/src/librustdoc/visit_lib.rs @@ -70,7 +70,7 @@ impl<'a, 'b, 'tcx> LibEmbargoVisitor<'a, 'b, 'tcx> { return; } - for item in self.cstore.item_children(def_id) { + for item in self.cstore.item_children(def_id, self.cx.tcx.sess) { self.visit_item(item.def); } } diff --git a/src/libserialize/collection_impls.rs b/src/libserialize/collection_impls.rs index 05cfb6352fbb..1a995276931d 100644 --- a/src/libserialize/collection_impls.rs +++ b/src/libserialize/collection_impls.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Implementations of serialization for structures found in libcollections +//! Implementations of serialization for structures found in liballoc use std::hash::{Hash, BuildHasher}; diff --git a/src/libserialize/lib.rs b/src/libserialize/lib.rs index 4eb2cad5c91b..ca27b34d6810 100644 --- a/src/libserialize/lib.rs +++ b/src/libserialize/lib.rs @@ -28,15 +28,12 @@ Core encoding and decoding interfaces. #![deny(warnings)] #![feature(box_syntax)] -#![feature(collections)] #![feature(core_intrinsics)] #![feature(i128_type)] #![feature(specialization)] #![cfg_attr(stage0, feature(staged_api))] #![cfg_attr(test, feature(test))] -extern crate collections; - pub use self::serialize::{Decoder, Encoder, Decodable, Encodable}; pub use self::serialize::{SpecializationError, SpecializedEncoder, SpecializedDecoder}; diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml index e17918506fe5..b516cbd08ca0 100644 --- a/src/libstd/Cargo.toml +++ b/src/libstd/Cargo.toml @@ -20,6 +20,7 @@ core = { path = "../libcore" } libc = { path = "../rustc/libc_shim" } rand = { path = "../librand" } compiler_builtins = { path = "../libcompiler_builtins" } +profiler_builtins = { path = "../libprofiler_builtins", optional = true } std_unicode = { path = "../libstd_unicode" } unwind = { path = "../libunwind" } @@ -43,3 +44,4 @@ debug-jemalloc = ["alloc_jemalloc/debug"] jemalloc = ["alloc_jemalloc"] force_alloc_system = [] panic-unwind = ["panic_unwind"] +profiler = ["profiler_builtins"] diff --git a/src/libstd/collections/mod.rs b/src/libstd/collections/mod.rs index 506bf717337b..b8a6a66eaa65 100644 --- a/src/libstd/collections/mod.rs +++ b/src/libstd/collections/mod.rs @@ -420,15 +420,15 @@ #![stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")] -pub use core_collections::Bound; +pub use alloc::Bound; #[stable(feature = "rust1", since = "1.0.0")] -pub use core_collections::{BinaryHeap, BTreeMap, BTreeSet}; +pub use alloc::{BinaryHeap, BTreeMap, BTreeSet}; #[stable(feature = "rust1", since = "1.0.0")] -pub use core_collections::{LinkedList, VecDeque}; +pub use alloc::{LinkedList, VecDeque}; #[stable(feature = "rust1", since = "1.0.0")] -pub use core_collections::{binary_heap, btree_map, btree_set}; +pub use alloc::{binary_heap, btree_map, btree_set}; #[stable(feature = "rust1", since = "1.0.0")] -pub use core_collections::{linked_list, vec_deque}; +pub use alloc::{linked_list, vec_deque}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::hash_map::HashMap; @@ -436,7 +436,7 @@ pub use self::hash_map::HashMap; pub use self::hash_set::HashSet; #[stable(feature = "rust1", since = "1.0.0")] -pub use core_collections::range; +pub use alloc::range; mod hash; diff --git a/src/libstd/env.rs b/src/libstd/env.rs index 27b40793ff64..889ba81e7781 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -367,7 +367,7 @@ fn _remove_var(k: &OsStr) { /// An iterator that splits an environment variable into paths according to /// platform-specific conventions. /// -/// This structure is created by the [`std::env::split_paths`] function See its +/// This structure is created by the [`std::env::split_paths`] function. See its /// documentation for more. /// /// [`std::env::split_paths`]: fn.split_paths.html @@ -605,14 +605,15 @@ pub fn current_exe() -> io::Result { os_imp::current_exe() } -/// An iterator over the arguments of a process, yielding a [`String`] value -/// for each argument. +/// An iterator over the arguments of a process, yielding a [`String`] value for +/// each argument. /// -/// This structure is created through the [`std::env::args`] function. +/// This struct is created by the [`std::env::args`] function. See its +/// documentation for more. /// /// The first element is traditionally the path of the executable, but it can be -/// set to arbitrary text, and may not even exist. This means this property should -/// not be relied upon for security purposes. +/// set to arbitrary text, and may not even exist. This means this property +/// should not be relied upon for security purposes. /// /// [`String`]: ../string/struct.String.html /// [`std::env::args`]: ./fn.args.html @@ -622,11 +623,12 @@ pub struct Args { inner: ArgsOs } /// An iterator over the arguments of a process, yielding an [`OsString`] value /// for each argument. /// -/// This structure is created through the [`std::env::args_os`] function. +/// This struct is created by the [`std::env::args_os`] function. See its +/// documentation for more. /// /// The first element is traditionally the path of the executable, but it can be -/// set to arbitrary text, and may not even exist. This means this property should -/// not be relied upon for security purposes. +/// set to arbitrary text, and may not even exist. This means this property +/// should not be relied upon for security purposes. /// /// [`OsString`]: ../ffi/struct.OsString.html /// [`std::env::args_os`]: ./fn.args_os.html diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index 4abad7e24f81..6134b0b882c5 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -46,8 +46,6 @@ mod cmath { pub fn erfcf(n: c_float) -> c_float; pub fn expm1f(n: c_float) -> c_float; pub fn fdimf(a: c_float, b: c_float) -> c_float; - pub fn fmaxf(a: c_float, b: c_float) -> c_float; - pub fn fminf(a: c_float, b: c_float) -> c_float; pub fn fmodf(a: c_float, b: c_float) -> c_float; pub fn ilogbf(n: c_float) -> c_int; pub fn logbf(n: c_float) -> c_float; @@ -673,7 +671,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn max(self, other: f32) -> f32 { - unsafe { cmath::fmaxf(self, other) } + num::Float::max(self, other) } /// Returns the minimum of the two numbers. @@ -689,7 +687,7 @@ impl f32 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn min(self, other: f32) -> f32 { - unsafe { cmath::fminf(self, other) } + num::Float::min(self, other) } /// The positive difference of two numbers. diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index 82e3903eec7b..e8d25cfbf949 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -51,8 +51,6 @@ mod cmath { pub fn erfc(n: c_double) -> c_double; pub fn expm1(n: c_double) -> c_double; pub fn fdim(a: c_double, b: c_double) -> c_double; - pub fn fmax(a: c_double, b: c_double) -> c_double; - pub fn fmin(a: c_double, b: c_double) -> c_double; pub fn fmod(a: c_double, b: c_double) -> c_double; pub fn frexp(n: c_double, value: &mut c_int) -> c_double; pub fn ilogb(n: c_double) -> c_int; @@ -587,7 +585,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn max(self, other: f64) -> f64 { - unsafe { cmath::fmax(self, other) } + num::Float::max(self, other) } /// Returns the minimum of the two numbers. @@ -603,7 +601,7 @@ impl f64 { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn min(self, other: f64) -> f64 { - unsafe { cmath::fmin(self, other) } + num::Float::min(self, other) } /// The positive difference of two numbers. @@ -1158,6 +1156,7 @@ mod tests { assert_eq!(Fp::Zero, neg_zero.classify()); } + #[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630 #[test] fn test_one() { let one: f64 = 1.0f64; @@ -1210,6 +1209,7 @@ mod tests { assert!((-109.2f64).is_finite()); } + #[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630 #[test] fn test_is_normal() { let nan: f64 = NAN; @@ -1227,6 +1227,7 @@ mod tests { assert!(!1e-308f64.is_normal()); } + #[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630 #[test] fn test_classify() { let nan: f64 = NAN; diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index 1167c39dba8e..2d78f0511d6d 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -288,6 +288,26 @@ impl CString { /// Failure to call [`from_raw`] will lead to a memory leak. /// /// [`from_raw`]: #method.from_raw + /// + /// # Examples + /// + /// ``` + /// use std::ffi::CString; + /// + /// let c_string = CString::new("foo").unwrap(); + /// + /// let ptr = c_string.into_raw(); + /// + /// unsafe { + /// assert_eq!(b'f', *ptr as u8); + /// assert_eq!(b'o', *ptr.offset(1) as u8); + /// assert_eq!(b'o', *ptr.offset(2) as u8); + /// assert_eq!(b'\0', *ptr.offset(3) as u8); + /// + /// // retake pointer to free memory + /// let _ = CString::from_raw(ptr); + /// } + /// ``` #[stable(feature = "cstr_memory", since = "1.4.0")] pub fn into_raw(self) -> *mut c_char { Box::into_raw(self.into_inner()) as *mut c_char @@ -311,6 +331,16 @@ impl CString { /// /// The returned buffer does **not** contain the trailing nul separator and /// it is guaranteed to not have any interior nul bytes. + /// + /// # Examples + /// + /// ``` + /// use std::ffi::CString; + /// + /// let c_string = CString::new("foo").unwrap(); + /// let bytes = c_string.into_bytes(); + /// assert_eq!(bytes, vec![b'f', b'o', b'o']); + /// ``` #[stable(feature = "cstring_into", since = "1.7.0")] pub fn into_bytes(self) -> Vec { let mut vec = self.into_inner().into_vec(); @@ -323,6 +353,16 @@ impl CString { /// includes the trailing nul byte. /// /// [`into_bytes`]: #method.into_bytes + /// + /// # Examples + /// + /// ``` + /// use std::ffi::CString; + /// + /// let c_string = CString::new("foo").unwrap(); + /// let bytes = c_string.into_bytes_with_nul(); + /// assert_eq!(bytes, vec![b'f', b'o', b'o', b'\0']); + /// ``` #[stable(feature = "cstring_into", since = "1.7.0")] pub fn into_bytes_with_nul(self) -> Vec { self.into_inner().into_vec() @@ -332,6 +372,16 @@ impl CString { /// /// The returned slice does **not** contain the trailing nul separator and /// it is guaranteed to not have any interior nul bytes. + /// + /// # Examples + /// + /// ``` + /// use std::ffi::CString; + /// + /// let c_string = CString::new("foo").unwrap(); + /// let bytes = c_string.as_bytes(); + /// assert_eq!(bytes, &[b'f', b'o', b'o']); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn as_bytes(&self) -> &[u8] { &self.inner[..self.inner.len() - 1] @@ -341,6 +391,16 @@ impl CString { /// includes the trailing nul byte. /// /// [`as_bytes`]: #method.as_bytes + /// + /// # Examples + /// + /// ``` + /// use std::ffi::CString; + /// + /// let c_string = CString::new("foo").unwrap(); + /// let bytes = c_string.as_bytes_with_nul(); + /// assert_eq!(bytes, &[b'f', b'o', b'o', b'\0']); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn as_bytes_with_nul(&self) -> &[u8] { &self.inner diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index a5a1b5e5f091..f54d79c201f4 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -9,7 +9,7 @@ // except according to those terms. use borrow::{Borrow, Cow}; -use fmt::{self, Debug}; +use fmt; use mem; use ops; use cmp; @@ -312,8 +312,8 @@ impl Default for OsString { } #[stable(feature = "rust1", since = "1.0.0")] -impl Debug for OsString { - fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { +impl fmt::Debug for OsString { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(&**self, formatter) } } @@ -669,9 +669,15 @@ impl Hash for OsStr { } #[stable(feature = "rust1", since = "1.0.0")] -impl Debug for OsStr { - fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { - self.inner.fmt(formatter) +impl fmt::Debug for OsStr { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&self.inner, formatter) + } +} + +impl OsStr { + pub(crate) fn display(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.inner, formatter) } } diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index c872a8e52611..3f859c45c28c 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -263,7 +263,7 @@ //! [`println!`]: ../macro.println.html //! [`Lines`]: struct.Lines.html //! [`io::Result`]: type.Result.html -//! [`?` operator]: ../../book/syntax-index.html +//! [`?` operator]: ../../book/first-edition/syntax-index.html //! [`Read::read`]: trait.Read.html#tymethod.read #![stable(feature = "rust1", since = "1.0.0")] @@ -389,7 +389,7 @@ fn read_to_end(r: &mut R, buf: &mut Vec) -> Result /// The `Read` trait allows for reading bytes from a source. /// -/// Implementors of the `Read` trait are sometimes called 'readers'. +/// Implementors of the `Read` trait are called 'readers'. /// /// Readers are defined by one required method, `read()`. Each call to `read` /// will attempt to pull bytes from this source into a provided buffer. A diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index b0820d6f05a0..105f4026ec84 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -254,7 +254,6 @@ #![feature(cfg_target_vendor)] #![feature(char_escape_debug)] #![feature(char_internals)] -#![feature(collections)] #![feature(collections_range)] #![feature(compiler_builtins_lib)] #![feature(const_fn)] @@ -337,11 +336,9 @@ use prelude::v1::*; debug_assert_ne, unreachable, unimplemented, write, writeln, try)] extern crate core as __core; +#[allow(deprecated)] extern crate rand as core_rand; #[macro_use] #[macro_reexport(vec, format)] -extern crate collections as core_collections; - -#[allow(deprecated)] extern crate rand as core_rand; extern crate alloc; extern crate std_unicode; extern crate libc; @@ -430,17 +427,17 @@ pub use alloc::boxed; #[stable(feature = "rust1", since = "1.0.0")] pub use alloc::rc; #[stable(feature = "rust1", since = "1.0.0")] -pub use core_collections::borrow; +pub use alloc::borrow; #[stable(feature = "rust1", since = "1.0.0")] -pub use core_collections::fmt; +pub use alloc::fmt; #[stable(feature = "rust1", since = "1.0.0")] -pub use core_collections::slice; +pub use alloc::slice; #[stable(feature = "rust1", since = "1.0.0")] -pub use core_collections::str; +pub use alloc::str; #[stable(feature = "rust1", since = "1.0.0")] -pub use core_collections::string; +pub use alloc::string; #[stable(feature = "rust1", since = "1.0.0")] -pub use core_collections::vec; +pub use alloc::vec; #[stable(feature = "rust1", since = "1.0.0")] pub use std_unicode::char; #[unstable(feature = "i128", issue = "35118")] @@ -487,7 +484,7 @@ pub mod rt; // but it may be stabilized long-term. As a result we're exposing a hidden, // unstable module so we can get our build working. #[doc(hidden)] -#[unstable(feature = "rand", issue = "0")] +#[unstable(feature = "rand", issue = "27703")] pub mod __rand { pub use rand::{thread_rng, ThreadRng, Rng}; } diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index df3fce0da765..496c014f70e2 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -486,7 +486,7 @@ pub mod builtin { /// leads to less duplicated code. /// /// The syntax given to this macro is the same syntax as [the `cfg` - /// attribute](../book/conditional-compilation.html). + /// attribute](../book/first-edition/conditional-compilation.html). /// /// # Examples /// diff --git a/src/libstd/num.rs b/src/libstd/num.rs index ff89887ac92c..a2c133954a32 100644 --- a/src/libstd/num.rs +++ b/src/libstd/num.rs @@ -173,7 +173,10 @@ mod tests { fn $test_name() { #![test] assert_eq!((0 as $T).checked_next_power_of_two(), Some(1)); - assert!(($T::MAX / 2).checked_next_power_of_two().is_some()); + let smax = $T::MAX >> 1; + assert_eq!(smax.checked_next_power_of_two(), Some(smax+1)); + assert_eq!((smax + 1).checked_next_power_of_two(), Some(smax + 1)); + assert_eq!((smax + 2).checked_next_power_of_two(), None); assert_eq!(($T::MAX - 1).checked_next_power_of_two(), None); assert_eq!($T::MAX.checked_next_power_of_two(), None); let mut next_power = 1; diff --git a/src/libstd/panic.rs b/src/libstd/panic.rs index f99634ecac23..58356bc43eeb 100644 --- a/src/libstd/panic.rs +++ b/src/libstd/panic.rs @@ -112,7 +112,7 @@ pub trait UnwindSafe {} /// This is a "helper marker trait" used to provide impl blocks for the /// `UnwindSafe` trait, for more information see that documentation. #[stable(feature = "catch_unwind", since = "1.9.0")] -#[rustc_on_unimplemented = "the type {Self} contains interior mutability \ +#[rustc_on_unimplemented = "the type {Self} may contain interior mutability \ and a reference may not be safely transferrable \ across a catch_unwind boundary"] pub trait RefUnwindSafe {} diff --git a/src/libstd/path.rs b/src/libstd/path.rs index e128a4164d74..42a54ed6d754 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -2281,8 +2281,8 @@ impl AsRef for Path { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for Path { - fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { - self.inner.fmt(formatter) + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&self.inner, formatter) } } @@ -2314,14 +2314,14 @@ pub struct Display<'a> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a> fmt::Debug for Display<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(&self.path.to_string_lossy(), f) + fmt::Debug::fmt(&self.path, f) } } #[stable(feature = "rust1", since = "1.0.0")] impl<'a> fmt::Display for Display<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(&self.path.to_string_lossy(), f) + self.path.inner.display(f) } } diff --git a/src/libstd/prelude/mod.rs b/src/libstd/prelude/mod.rs index 86e661d7948f..195662637f01 100644 --- a/src/libstd/prelude/mod.rs +++ b/src/libstd/prelude/mod.rs @@ -136,10 +136,10 @@ //! [`std::string`]: ../string/index.html //! [`std::vec`]: ../vec/index.html //! [`to_owned`]: ../borrow/trait.ToOwned.html#tymethod.to_owned -//! [book-closures]: ../../book/closures.html -//! [book-dtor]: ../../book/drop.html -//! [book-enums]: ../../book/enums.html -//! [book-iter]: ../../book/iterators.html +//! [book-closures]: ../../book/first-edition/closures.html +//! [book-dtor]: ../../book/first-edition/drop.html +//! [book-enums]: ../../book/first-edition/enums.html +//! [book-iter]: ../../book/first-edition/iterators.html #![stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/rand/mod.rs b/src/libstd/rand/mod.rs index 4f33d7263981..8da070e7a497 100644 --- a/src/libstd/rand/mod.rs +++ b/src/libstd/rand/mod.rs @@ -56,7 +56,7 @@ //! between the two sources. (Also note that, on some systems e.g. FreeBSD, both `/dev/random` //! and `/dev/urandom` may block once if the CSPRNG has not seeded yet.) -#![unstable(feature = "rand", issue = "0")] +#![unstable(feature = "rand", issue = "27703")] use cell::RefCell; use fmt; diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs index c120a3045e4b..564021758176 100644 --- a/src/libstd/sync/condvar.rs +++ b/src/libstd/sync/condvar.rs @@ -480,9 +480,10 @@ impl Drop for Condvar { mod tests { use sync::mpsc::channel; use sync::{Condvar, Mutex, Arc}; + use sync::atomic::{AtomicBool, Ordering}; use thread; use time::Duration; - use u32; + use u64; #[test] fn smoke() { @@ -547,23 +548,58 @@ mod tests { #[test] #[cfg_attr(target_os = "emscripten", ignore)] - fn wait_timeout_ms() { + fn wait_timeout_wait() { let m = Arc::new(Mutex::new(())); - let m2 = m.clone(); let c = Arc::new(Condvar::new()); - let c2 = c.clone(); - let g = m.lock().unwrap(); - let (g, _no_timeout) = c.wait_timeout(g, Duration::from_millis(1)).unwrap(); - // spurious wakeups mean this isn't necessarily true - // assert!(!no_timeout); - let _t = thread::spawn(move || { - let _g = m2.lock().unwrap(); - c2.notify_one(); - }); - let (g, timeout_res) = c.wait_timeout(g, Duration::from_millis(u32::MAX as u64)).unwrap(); - assert!(!timeout_res.timed_out()); - drop(g); + loop { + let g = m.lock().unwrap(); + let (_g, no_timeout) = c.wait_timeout(g, Duration::from_millis(1)).unwrap(); + // spurious wakeups mean this isn't necessarily true + // so execute test again, if not timeout + if !no_timeout.timed_out() { + continue; + } + + break; + } + } + + #[test] + #[cfg_attr(target_os = "emscripten", ignore)] + fn wait_timeout_wake() { + let m = Arc::new(Mutex::new(())); + let c = Arc::new(Condvar::new()); + + loop { + let g = m.lock().unwrap(); + + let c2 = c.clone(); + let m2 = m.clone(); + + let notified = Arc::new(AtomicBool::new(false)); + let notified_copy = notified.clone(); + + let t = thread::spawn(move || { + let _g = m2.lock().unwrap(); + thread::sleep(Duration::from_millis(1)); + notified_copy.store(true, Ordering::SeqCst); + c2.notify_one(); + }); + let (g, timeout_res) = c.wait_timeout(g, Duration::from_millis(u64::MAX)).unwrap(); + assert!(!timeout_res.timed_out()); + // spurious wakeups mean this isn't necessarily true + // so execute test again, if not notified + if !notified.load(Ordering::SeqCst) { + t.join().unwrap(); + continue; + } + drop(g); + + t.join().unwrap(); + + break; + } } #[test] diff --git a/src/libstd/sys/redox/os_str.rs b/src/libstd/sys/redox/os_str.rs index c2bba07f68ce..c54286353a92 100644 --- a/src/libstd/sys/redox/os_str.rs +++ b/src/libstd/sys/redox/os_str.rs @@ -12,10 +12,11 @@ /// a `Vec`/`[u8]`. use borrow::Cow; -use fmt::{self, Debug}; +use fmt; use str; use mem; use sys_common::{AsInner, IntoInner}; +use std_unicode::lossy::Utf8Lossy; #[derive(Clone, Hash)] pub struct Buf { @@ -26,15 +27,27 @@ pub struct Slice { pub inner: [u8] } -impl Debug for Slice { - fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { - self.to_string_lossy().fmt(formatter) +impl fmt::Debug for Slice { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&Utf8Lossy::from_bytes(&self.inner), formatter) } } -impl Debug for Buf { - fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { - self.as_slice().fmt(formatter) +impl fmt::Display for Slice { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&Utf8Lossy::from_bytes(&self.inner), formatter) + } +} + +impl fmt::Debug for Buf { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(self.as_slice(), formatter) + } +} + +impl fmt::Display for Buf { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(self.as_slice(), formatter) } } diff --git a/src/libstd/sys/unix/condvar.rs b/src/libstd/sys/unix/condvar.rs index 27b9f131d120..b9ea573b323d 100644 --- a/src/libstd/sys/unix/condvar.rs +++ b/src/libstd/sys/unix/condvar.rs @@ -23,6 +23,14 @@ const TIMESPEC_MAX: libc::timespec = libc::timespec { tv_nsec: 1_000_000_000 - 1, }; +fn saturating_cast_to_time_t(value: u64) -> libc::time_t { + if value > ::max_value() as u64 { + ::max_value() + } else { + value as libc::time_t + } +} + impl Condvar { pub const fn new() -> Condvar { // Might be moved and address is changing it is better to avoid @@ -79,8 +87,7 @@ impl Condvar { // Nanosecond calculations can't overflow because both values are below 1e9. let nsec = dur.subsec_nanos() as libc::c_long + now.tv_nsec as libc::c_long; - // FIXME: Casting u64 into time_t could truncate the value. - let sec = (dur.as_secs() as libc::time_t) + let sec = saturating_cast_to_time_t(dur.as_secs()) .checked_add((nsec / 1_000_000_000) as libc::time_t) .and_then(|s| s.checked_add(now.tv_sec)); let nsec = nsec % 1_000_000_000; @@ -100,10 +107,29 @@ impl Condvar { // https://github.com/llvm-mirror/libcxx/blob/release_35/src/condition_variable.cpp#L46 // https://github.com/llvm-mirror/libcxx/blob/release_35/include/__mutex_base#L367 #[cfg(any(target_os = "macos", target_os = "ios", target_os = "android"))] - pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { + pub unsafe fn wait_timeout(&self, mutex: &Mutex, mut dur: Duration) -> bool { use ptr; use time::Instant; + // 1000 years + let max_dur = Duration::from_secs(1000 * 365 * 86400); + + if dur > max_dur { + // OSX implementation of `pthread_cond_timedwait` is buggy + // with super long durations. When duration is greater than + // 0x100_0000_0000_0000 seconds, `pthread_cond_timedwait` + // in macOS Sierra return error 316. + // + // This program demonstrates the issue: + // https://gist.github.com/stepancheg/198db4623a20aad2ad7cddb8fda4a63c + // + // To work around this issue, and possible bugs of other OSes, timeout + // is clamped to 1000 years, which is allowable per the API of `wait_timeout` + // because of spurious wakeups. + + dur = max_dur; + } + // First, figure out what time it currently is, in both system and // stable time. pthread_cond_timedwait uses system time, but we want to // report timeout based on stable time. @@ -116,7 +142,7 @@ impl Condvar { (sys_now.tv_usec * 1000) as libc::c_long; let extra = (nsec / 1_000_000_000) as libc::time_t; let nsec = nsec % 1_000_000_000; - let seconds = dur.as_secs() as libc::time_t; + let seconds = saturating_cast_to_time_t(dur.as_secs()); let timeout = sys_now.tv_sec.checked_add(extra).and_then(|s| { s.checked_add(seconds) diff --git a/src/libstd/sys/unix/os_str.rs b/src/libstd/sys/unix/os_str.rs index f5b942d3343d..777db17e3e16 100644 --- a/src/libstd/sys/unix/os_str.rs +++ b/src/libstd/sys/unix/os_str.rs @@ -12,10 +12,11 @@ /// a `Vec`/`[u8]`. use borrow::Cow; -use fmt::{self, Debug}; +use fmt; use str; use mem; use sys_common::{AsInner, IntoInner}; +use std_unicode::lossy::Utf8Lossy; #[derive(Clone, Hash)] pub struct Buf { @@ -26,15 +27,27 @@ pub struct Slice { pub inner: [u8] } -impl Debug for Slice { - fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { - self.to_string_lossy().fmt(formatter) +impl fmt::Debug for Slice { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&Utf8Lossy::from_bytes(&self.inner), formatter) } } -impl Debug for Buf { - fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { - self.as_slice().fmt(formatter) +impl fmt::Display for Slice { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&Utf8Lossy::from_bytes(&self.inner), formatter) + } +} + +impl fmt::Debug for Buf { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(self.as_slice(), formatter) + } +} + +impl fmt::Display for Buf { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(self.as_slice(), formatter) } } diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs index 706256ff10ec..ca5ef4bcfc5f 100644 --- a/src/libstd/sys/unix/pipe.rs +++ b/src/libstd/sys/unix/pipe.rs @@ -11,8 +11,9 @@ use io; use libc::{self, c_int}; use mem; -use sys::{cvt, cvt_r}; +use sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering}; use sys::fd::FileDesc; +use sys::{cvt, cvt_r}; //////////////////////////////////////////////////////////////////////////////// // Anonymous pipes @@ -21,6 +22,9 @@ use sys::fd::FileDesc; pub struct AnonPipe(FileDesc); pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> { + weak! { fn pipe2(*mut c_int, c_int) -> c_int } + static INVALID: AtomicBool = ATOMIC_BOOL_INIT; + let mut fds = [0; 2]; // Unfortunately the only known way right now to create atomically set the @@ -31,13 +35,26 @@ pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> { target_os = "freebsd", target_os = "linux", target_os = "netbsd", - target_os = "openbsd")) + target_os = "openbsd")) && + !INVALID.load(Ordering::SeqCst) { - weak! { fn pipe2(*mut c_int, c_int) -> c_int } + if let Some(pipe) = pipe2.get() { - cvt(unsafe { pipe(fds.as_mut_ptr(), libc::O_CLOEXEC) })?; - return Ok((AnonPipe(FileDesc::new(fds[0])), - AnonPipe(FileDesc::new(fds[1])))); + // Note that despite calling a glibc function here we may still + // get ENOSYS. Glibc has `pipe2` since 2.9 and doesn't try to + // emulate on older kernels, so if you happen to be running on + // an older kernel you may see `pipe2` as a symbol but still not + // see the syscall. + match cvt(unsafe { pipe(fds.as_mut_ptr(), libc::O_CLOEXEC) }) { + Ok(_) => { + return Ok((AnonPipe(FileDesc::new(fds[0])), + AnonPipe(FileDesc::new(fds[1])))); + } + Err(ref e) if e.raw_os_error() == Some(libc::ENOSYS) => { + INVALID.store(true, Ordering::SeqCst); + } + Err(e) => return Err(e), + } } } cvt(unsafe { libc::pipe(fds.as_mut_ptr()) })?; diff --git a/src/libstd/sys/windows/os_str.rs b/src/libstd/sys/windows/os_str.rs index f401e7b35c8d..3eb4582718b5 100644 --- a/src/libstd/sys/windows/os_str.rs +++ b/src/libstd/sys/windows/os_str.rs @@ -12,7 +12,7 @@ /// wrapper around the "WTF-8" encoding; see the `wtf8` module for more. use borrow::Cow; -use fmt::{self, Debug}; +use fmt; use sys_common::wtf8::{Wtf8, Wtf8Buf}; use mem; use sys_common::{AsInner, IntoInner}; @@ -34,9 +34,15 @@ impl AsInner for Buf { } } -impl Debug for Buf { - fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { - self.as_slice().fmt(formatter) +impl fmt::Debug for Buf { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(self.as_slice(), formatter) + } +} + +impl fmt::Display for Buf { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(self.as_slice(), formatter) } } @@ -44,9 +50,15 @@ pub struct Slice { pub inner: Wtf8 } -impl Debug for Slice { - fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { - self.inner.fmt(formatter) +impl fmt::Debug for Slice { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&self.inner, formatter) + } +} + +impl fmt::Display for Slice { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.inner, formatter) } } diff --git a/src/libstd/sys_common/wtf8.rs b/src/libstd/sys_common/wtf8.rs index df5e4ef1d886..4e4a6e77d124 100644 --- a/src/libstd/sys_common/wtf8.rs +++ b/src/libstd/sys_common/wtf8.rs @@ -39,7 +39,7 @@ use slice; use str; use sys_common::AsInner; -const UTF8_REPLACEMENT_CHARACTER: &'static [u8] = b"\xEF\xBF\xBD"; +const UTF8_REPLACEMENT_CHARACTER: &'static str = "\u{FFFD}"; /// A Unicode code point: from U+0000 to U+10FFFF. /// @@ -339,7 +339,7 @@ impl Wtf8Buf { Some((surrogate_pos, _)) => { pos = surrogate_pos + 3; self.bytes[surrogate_pos..pos] - .copy_from_slice(UTF8_REPLACEMENT_CHARACTER); + .copy_from_slice(UTF8_REPLACEMENT_CHARACTER.as_bytes()); }, None => return unsafe { String::from_utf8_unchecked(self.bytes) } } @@ -438,6 +438,30 @@ impl fmt::Debug for Wtf8 { } } +impl fmt::Display for Wtf8 { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let wtf8_bytes = &self.bytes; + let mut pos = 0; + loop { + match self.next_surrogate(pos) { + Some((surrogate_pos, _)) => { + formatter.write_str(unsafe { + str::from_utf8_unchecked(&wtf8_bytes[pos .. surrogate_pos]) + })?; + formatter.write_str(UTF8_REPLACEMENT_CHARACTER)?; + pos = surrogate_pos + 3; + }, + None => { + formatter.write_str(unsafe { + str::from_utf8_unchecked(&wtf8_bytes[pos..]) + })?; + return Ok(()); + } + } + } + } +} + impl Wtf8 { /// Creates a WTF-8 slice from a UTF-8 `&str` slice. /// @@ -516,13 +540,13 @@ impl Wtf8 { let wtf8_bytes = &self.bytes; let mut utf8_bytes = Vec::with_capacity(self.len()); utf8_bytes.extend_from_slice(&wtf8_bytes[..surrogate_pos]); - utf8_bytes.extend_from_slice(UTF8_REPLACEMENT_CHARACTER); + utf8_bytes.extend_from_slice(UTF8_REPLACEMENT_CHARACTER.as_bytes()); let mut pos = surrogate_pos + 3; loop { match self.next_surrogate(pos) { Some((surrogate_pos, _)) => { utf8_bytes.extend_from_slice(&wtf8_bytes[pos .. surrogate_pos]); - utf8_bytes.extend_from_slice(UTF8_REPLACEMENT_CHARACTER); + utf8_bytes.extend_from_slice(UTF8_REPLACEMENT_CHARACTER.as_bytes()); pos = surrogate_pos + 3; }, None => { @@ -1200,6 +1224,20 @@ mod tests { assert_eq!(string.to_string_lossy(), expected); } + #[test] + fn wtf8_display() { + fn d(b: &[u8]) -> String { + format!("{}", &unsafe { Wtf8::from_bytes_unchecked(b) }) + } + + assert_eq!("", d("".as_bytes())); + assert_eq!("aé 💩", d("aé 💩".as_bytes())); + + let mut string = Wtf8Buf::from_str("aé 💩"); + string.push(CodePoint::from_u32(0xD800).unwrap()); + assert_eq!("aé 💩�", d(string.as_inner())); + } + #[test] fn wtf8_encode_wide() { let mut string = Wtf8Buf::from_str("aé "); diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 64c31c2a681c..dda11e50380f 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -787,12 +787,16 @@ pub fn park_timeout_ms(ms: u32) { /// /// let timeout = Duration::from_secs(2); /// let beginning_park = Instant::now(); -/// park_timeout(timeout); /// -/// while beginning_park.elapsed() < timeout { -/// println!("restarting park_timeout after {:?}", beginning_park.elapsed()); -/// let timeout = timeout - beginning_park.elapsed(); -/// park_timeout(timeout); +/// let mut timeout_remaining = timeout; +/// loop { +/// park_timeout(timeout_remaining); +/// let elapsed = beginning_park.elapsed(); +/// if elapsed >= timeout { +/// break; +/// } +/// println!("restarting park_timeout after {:?}", elapsed); +/// timeout_remaining = timeout - elapsed; /// } /// ``` /// diff --git a/src/libstd_unicode/Cargo.toml b/src/libstd_unicode/Cargo.toml index 28fbd3c1aa94..b3346dbe2fb1 100644 --- a/src/libstd_unicode/Cargo.toml +++ b/src/libstd_unicode/Cargo.toml @@ -9,5 +9,9 @@ path = "lib.rs" test = false bench = false +[[test]] +name = "std_unicode_tests" +path = "tests/lib.rs" + [dependencies] core = { path = "../libcore" } diff --git a/src/libstd_unicode/char.rs b/src/libstd_unicode/char.rs index 92e5369758b4..eb36cbe3b1f5 100644 --- a/src/libstd_unicode/char.rs +++ b/src/libstd_unicode/char.rs @@ -599,9 +599,9 @@ impl char { /// 'XID_Start' is a Unicode Derived Property specified in /// [UAX #31](http://unicode.org/reports/tr31/#NFKC_Modifications), /// mostly similar to `ID_Start` but modified for closure under `NFKx`. - #[unstable(feature = "unicode", + #[unstable(feature = "rustc_private", reason = "mainly needed for compiler internals", - issue = "0")] + issue = "27812")] #[inline] pub fn is_xid_start(self) -> bool { derived_property::XID_Start(self) @@ -613,9 +613,9 @@ impl char { /// 'XID_Continue' is a Unicode Derived Property specified in /// [UAX #31](http://unicode.org/reports/tr31/#NFKC_Modifications), /// mostly similar to 'ID_Continue' but modified for closure under NFKx. - #[unstable(feature = "unicode", + #[unstable(feature = "rustc_private", reason = "mainly needed for compiler internals", - issue = "0")] + issue = "27812")] #[inline] pub fn is_xid_continue(self) -> bool { derived_property::XID_Continue(self) diff --git a/src/libstd_unicode/lib.rs b/src/libstd_unicode/lib.rs index d63878a7a7c2..98624800b4c6 100644 --- a/src/libstd_unicode/lib.rs +++ b/src/libstd_unicode/lib.rs @@ -34,6 +34,8 @@ #![feature(char_escape_debug)] #![feature(core_char_ext)] +#![feature(str_internals)] +#![feature(core_intrinsics)] #![feature(decode_utf8)] #![feature(fused)] #![feature(fn_traits)] @@ -45,6 +47,7 @@ mod tables; mod u_str; pub mod char; +pub mod lossy; #[allow(deprecated)] pub mod str { @@ -52,7 +55,7 @@ pub mod str { pub use u_str::Utf16Encoder; } -// For use in libcollections, not re-exported in libstd. +// For use in liballoc, not re-exported in libstd. pub mod derived_property { pub use tables::derived_property::{Case_Ignorable, Cased}; } diff --git a/src/libstd_unicode/lossy.rs b/src/libstd_unicode/lossy.rs new file mode 100644 index 000000000000..b914cbcf4b85 --- /dev/null +++ b/src/libstd_unicode/lossy.rs @@ -0,0 +1,198 @@ +// 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. +// +// 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 core::str as core_str; +use core::fmt; +use core::fmt::Write; +use char; +use core::intrinsics; + + +/// Lossy UTF-8 string. +#[unstable(feature = "str_internals", issue = "0")] +pub struct Utf8Lossy { + bytes: [u8] +} + +impl Utf8Lossy { + pub fn from_str(s: &str) -> &Utf8Lossy { + Utf8Lossy::from_bytes(s.as_bytes()) + } + + pub fn from_bytes(bytes: &[u8]) -> &Utf8Lossy { + unsafe { intrinsics::transmute(bytes) } + } + + pub fn chunks(&self) -> Utf8LossyChunksIter { + Utf8LossyChunksIter { source: &self.bytes } + } +} + + +/// Iterator over lossy UTF-8 string +#[unstable(feature = "str_internals", issue = "0")] +pub struct Utf8LossyChunksIter<'a> { + source: &'a [u8], +} + +#[unstable(feature = "str_internals", issue = "0")] +#[derive(PartialEq, Eq, Debug)] +pub struct Utf8LossyChunk<'a> { + /// Sequence of valid chars. + /// Can be empty between broken UTF-8 chars. + pub valid: &'a str, + /// Single broken char, empty if none. + /// Empty iff iterator item is last. + pub broken: &'a [u8], +} + +impl<'a> Iterator for Utf8LossyChunksIter<'a> { + type Item = Utf8LossyChunk<'a>; + + fn next(&mut self) -> Option> { + if self.source.len() == 0 { + return None; + } + + const TAG_CONT_U8: u8 = 128; + fn unsafe_get(xs: &[u8], i: usize) -> u8 { + unsafe { *xs.get_unchecked(i) } + } + fn safe_get(xs: &[u8], i: usize) -> u8 { + if i >= xs.len() { 0 } else { unsafe_get(xs, i) } + } + + let mut i = 0; + while i < self.source.len() { + let i_ = i; + + let byte = unsafe_get(self.source, i); + i += 1; + + if byte < 128 { + + } else { + let w = core_str::utf8_char_width(byte); + + macro_rules! error { () => ({ + unsafe { + let r = Utf8LossyChunk { + valid: core_str::from_utf8_unchecked(&self.source[0..i_]), + broken: &self.source[i_..i], + }; + self.source = &self.source[i..]; + return Some(r); + } + })} + + match w { + 2 => { + if safe_get(self.source, i) & 192 != TAG_CONT_U8 { + error!(); + } + i += 1; + } + 3 => { + match (byte, safe_get(self.source, i)) { + (0xE0, 0xA0 ... 0xBF) => (), + (0xE1 ... 0xEC, 0x80 ... 0xBF) => (), + (0xED, 0x80 ... 0x9F) => (), + (0xEE ... 0xEF, 0x80 ... 0xBF) => (), + _ => { + error!(); + } + } + i += 1; + if safe_get(self.source, i) & 192 != TAG_CONT_U8 { + error!(); + } + i += 1; + } + 4 => { + match (byte, safe_get(self.source, i)) { + (0xF0, 0x90 ... 0xBF) => (), + (0xF1 ... 0xF3, 0x80 ... 0xBF) => (), + (0xF4, 0x80 ... 0x8F) => (), + _ => { + error!(); + } + } + i += 1; + if safe_get(self.source, i) & 192 != TAG_CONT_U8 { + error!(); + } + i += 1; + if safe_get(self.source, i) & 192 != TAG_CONT_U8 { + error!(); + } + i += 1; + } + _ => { + error!(); + } + } + } + } + + let r = Utf8LossyChunk { + valid: unsafe { core_str::from_utf8_unchecked(self.source) }, + broken: &[], + }; + self.source = &[]; + return Some(r); + } +} + + +impl fmt::Display for Utf8Lossy { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + for Utf8LossyChunk { valid, broken } in self.chunks() { + f.write_str(valid)?; + if !broken.is_empty() { + f.write_char(char::REPLACEMENT_CHARACTER)?; + } + } + Ok(()) + } +} + +impl fmt::Debug for Utf8Lossy { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_char('"')?; + + for Utf8LossyChunk { valid, broken } in self.chunks() { + + // Valid part. + // Here we partially parse UTF-8 again which is suboptimal. + { + let mut from = 0; + for (i, c) in valid.char_indices() { + let esc = c.escape_debug(); + // If char needs escaping, flush backlog so far and write, else skip + if esc.len() != 1 { + f.write_str(&valid[from..i])?; + for c in esc { + f.write_char(c)?; + } + from = i + c.len_utf8(); + } + } + f.write_str(&valid[from..])?; + } + + // Broken parts of string as hex escape. + for &b in broken { + write!(f, "\\x{:02x}", b)?; + } + } + + f.write_char('"') + } +} diff --git a/src/libstd_unicode/tests/lib.rs b/src/libstd_unicode/tests/lib.rs new file mode 100644 index 000000000000..9535ec18763e --- /dev/null +++ b/src/libstd_unicode/tests/lib.rs @@ -0,0 +1,15 @@ +// 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. +// +// 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(str_internals, unicode)] + +extern crate std_unicode; + +mod lossy; diff --git a/src/libstd_unicode/tests/lossy.rs b/src/libstd_unicode/tests/lossy.rs new file mode 100644 index 000000000000..e05d06685563 --- /dev/null +++ b/src/libstd_unicode/tests/lossy.rs @@ -0,0 +1,91 @@ +// 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. +// +// 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_unicode::lossy::*; + +#[test] +fn chunks() { + let mut iter = Utf8Lossy::from_bytes(b"hello").chunks(); + assert_eq!(Some(Utf8LossyChunk { valid: "hello", broken: b"", }), iter.next()); + assert_eq!(None, iter.next()); + + let mut iter = Utf8Lossy::from_bytes("ศไทย中华Việt Nam".as_bytes()).chunks(); + assert_eq!(Some(Utf8LossyChunk { valid: "ศไทย中华Việt Nam", broken: b"", }), iter.next()); + assert_eq!(None, iter.next()); + + let mut iter = Utf8Lossy::from_bytes(b"Hello\xC2 There\xFF Goodbye").chunks(); + assert_eq!(Some(Utf8LossyChunk { valid: "Hello", broken: b"\xC2", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: " There", broken: b"\xFF", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: " Goodbye", broken: b"", }), iter.next()); + assert_eq!(None, iter.next()); + + let mut iter = Utf8Lossy::from_bytes(b"Hello\xC0\x80 There\xE6\x83 Goodbye").chunks(); + assert_eq!(Some(Utf8LossyChunk { valid: "Hello", broken: b"\xC0", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: " There", broken: b"\xE6\x83", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: " Goodbye", broken: b"", }), iter.next()); + assert_eq!(None, iter.next()); + + let mut iter = Utf8Lossy::from_bytes(b"\xF5foo\xF5\x80bar").chunks(); + assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xF5", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "foo", broken: b"\xF5", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "bar", broken: b"", }), iter.next()); + assert_eq!(None, iter.next()); + + let mut iter = Utf8Lossy::from_bytes(b"\xF1foo\xF1\x80bar\xF1\x80\x80baz").chunks(); + assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xF1", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "foo", broken: b"\xF1\x80", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "bar", broken: b"\xF1\x80\x80", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "baz", broken: b"", }), iter.next()); + assert_eq!(None, iter.next()); + + let mut iter = Utf8Lossy::from_bytes(b"\xF4foo\xF4\x80bar\xF4\xBFbaz").chunks(); + assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xF4", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "foo", broken: b"\xF4\x80", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "bar", broken: b"\xF4", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xBF", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "baz", broken: b"", }), iter.next()); + assert_eq!(None, iter.next()); + + let mut iter = Utf8Lossy::from_bytes(b"\xF0\x80\x80\x80foo\xF0\x90\x80\x80bar").chunks(); + assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xF0", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "foo\u{10000}bar", broken: b"", }), iter.next()); + assert_eq!(None, iter.next()); + + // surrogates + let mut iter = Utf8Lossy::from_bytes(b"\xED\xA0\x80foo\xED\xBF\xBFbar").chunks(); + assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xED", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xA0", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\x80", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "foo", broken: b"\xED", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xBF", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "", broken: b"\xBF", }), iter.next()); + assert_eq!(Some(Utf8LossyChunk { valid: "bar", broken: b"", }), iter.next()); + assert_eq!(None, iter.next()); +} + +#[test] +fn display() { + assert_eq!( + "Hello\u{FFFD}\u{FFFD} There\u{FFFD} Goodbye", + &format!("{}", Utf8Lossy::from_bytes(b"Hello\xC0\x80 There\xE6\x83 Goodbye"))); +} + +#[test] +fn debug() { + assert_eq!( + "\"Hello\\xc0\\x80 There\\xe6\\x83 Goodbye\\u{10d4ea}\"", + &format!("{:?}", Utf8Lossy::from_bytes( + b"Hello\xC0\x80 There\xE6\x83 Goodbye\xf4\x8d\x93\xaa"))); +} diff --git a/src/libstd_unicode/u_str.rs b/src/libstd_unicode/u_str.rs index 1454168d2d5c..54a5288a57c8 100644 --- a/src/libstd_unicode/u_str.rs +++ b/src/libstd_unicode/u_str.rs @@ -32,7 +32,7 @@ pub struct SplitWhitespace<'a> { } /// Methods for Unicode string slices -#[allow(missing_docs)] // docs in libcollections +#[allow(missing_docs)] // docs in liballoc pub trait UnicodeStr { fn split_whitespace<'a>(&'a self) -> SplitWhitespace<'a>; fn is_whitespace(&self) -> bool; diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 830a457df748..b3d9cf9da36c 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -158,29 +158,13 @@ impl CodeMap { /// Creates a new filemap without setting its line information. If you don't /// intend to set the line information yourself, you should use new_filemap_and_lines. - pub fn new_filemap(&self, filename: FileName, mut src: String) -> Rc { + pub fn new_filemap(&self, filename: FileName, src: String) -> Rc { let start_pos = self.next_start_pos(); let mut files = self.files.borrow_mut(); - // Remove utf-8 BOM if any. - if src.starts_with("\u{feff}") { - src.drain(..3); - } - - let end_pos = start_pos + src.len(); - let (filename, was_remapped) = self.path_mapping.map_prefix(filename); - - let filemap = Rc::new(FileMap { - name: filename, - name_was_remapped: was_remapped, - crate_of_origin: 0, - src: Some(Rc::new(src)), - start_pos: Pos::from_usize(start_pos), - end_pos: Pos::from_usize(end_pos), - lines: RefCell::new(Vec::new()), - multibyte_chars: RefCell::new(Vec::new()), - }); + let filemap = + Rc::new(FileMap::new(filename, was_remapped, src, Pos::from_usize(start_pos))); files.push(filemap.clone()); @@ -210,6 +194,7 @@ impl CodeMap { filename: FileName, name_was_remapped: bool, crate_of_origin: u32, + src_hash: u128, source_len: usize, mut file_local_lines: Vec, mut file_local_multibyte_chars: Vec) @@ -233,6 +218,8 @@ impl CodeMap { name_was_remapped: name_was_remapped, crate_of_origin: crate_of_origin, src: None, + src_hash: src_hash, + external_src: RefCell::new(ExternalSource::AbsentOk), start_pos: start_pos, end_pos: end_pos, lines: RefCell::new(file_local_lines), @@ -428,30 +415,31 @@ impl CodeMap { local_end.fm.start_pos) })); } else { - match local_begin.fm.src { - Some(ref src) => { - let start_index = local_begin.pos.to_usize(); - let end_index = local_end.pos.to_usize(); - let source_len = (local_begin.fm.end_pos - - local_begin.fm.start_pos).to_usize(); + self.ensure_filemap_source_present(local_begin.fm.clone()); - if start_index > end_index || end_index > source_len { - return Err(SpanSnippetError::MalformedForCodemap( - MalformedCodemapPositions { - name: local_begin.fm.name.clone(), - source_len: source_len, - begin_pos: local_begin.pos, - end_pos: local_end.pos, - })); - } + let start_index = local_begin.pos.to_usize(); + let end_index = local_end.pos.to_usize(); + let source_len = (local_begin.fm.end_pos - + local_begin.fm.start_pos).to_usize(); - return Ok((&src[start_index..end_index]).to_string()) - } - None => { - return Err(SpanSnippetError::SourceNotAvailable { - filename: local_begin.fm.name.clone() - }); - } + if start_index > end_index || end_index > source_len { + return Err(SpanSnippetError::MalformedForCodemap( + MalformedCodemapPositions { + name: local_begin.fm.name.clone(), + source_len: source_len, + begin_pos: local_begin.pos, + end_pos: local_end.pos, + })); + } + + if let Some(ref src) = local_begin.fm.src { + return Ok((&src[start_index..end_index]).to_string()); + } else if let Some(src) = local_begin.fm.external_src.borrow().get_source() { + return Ok((&src[start_index..end_index]).to_string()); + } else { + return Err(SpanSnippetError::SourceNotAvailable { + filename: local_begin.fm.name.clone() + }); } } } @@ -572,6 +560,10 @@ impl CodeMapper for CodeMap { } sp } + fn ensure_filemap_source_present(&self, file_map: Rc) -> bool { + let src = self.file_loader.read_file(Path::new(&file_map.name)).ok(); + return file_map.add_external_src(src) + } } #[derive(Clone)] @@ -617,6 +609,7 @@ impl FilePathMapping { #[cfg(test)] mod tests { use super::*; + use std::borrow::Cow; use std::rc::Rc; #[test] @@ -626,12 +619,12 @@ mod tests { "first line.\nsecond line".to_string()); fm.next_line(BytePos(0)); // Test we can get lines with partial line info. - assert_eq!(fm.get_line(0), Some("first line.")); + assert_eq!(fm.get_line(0), Some(Cow::from("first line."))); // TESTING BROKEN BEHAVIOR: line break declared before actual line break. fm.next_line(BytePos(10)); - assert_eq!(fm.get_line(1), Some(".")); + assert_eq!(fm.get_line(1), Some(Cow::from("."))); fm.next_line(BytePos(12)); - assert_eq!(fm.get_line(2), Some("second line")); + assert_eq!(fm.get_line(2), Some(Cow::from("second line"))); } #[test] diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index 2e98c7d96260..54e6dde41e6d 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -223,7 +223,6 @@ impl<'a> StripUnconfigured<'a> { ast::ExprKind::Struct(path, fields, base) => { let fields = fields.into_iter() .filter_map(|field| { - self.visit_struct_field_attrs(field.attrs()); self.configure(field) }) .collect(); @@ -256,17 +255,6 @@ impl<'a> StripUnconfigured<'a> { } pub fn configure_struct_expr_field(&mut self, field: ast::Field) -> Option { - if !self.features.map(|features| features.struct_field_attributes).unwrap_or(true) { - if !field.attrs.is_empty() { - let mut err = feature_err(self.sess, - "struct_field_attributes", - field.span, - GateIssue::Language, - "attributes on struct literal fields are unstable"); - err.emit(); - } - } - self.configure(field) } @@ -275,7 +263,6 @@ impl<'a> StripUnconfigured<'a> { if let ast::PatKind::Struct(path, fields, etc) = pattern.node { let fields = fields.into_iter() .filter_map(|field| { - self.visit_struct_field_attrs(field.attrs()); self.configure(field) }) .collect(); @@ -284,21 +271,6 @@ impl<'a> StripUnconfigured<'a> { pattern }) } - - fn visit_struct_field_attrs(&mut self, attrs: &[ast::Attribute]) { - // flag the offending attributes - for attr in attrs.iter() { - if !self.features.map(|features| features.struct_field_attributes).unwrap_or(true) { - let mut err = feature_err( - self.sess, - "struct_field_attributes", - attr.span, - GateIssue::Language, - "attributes on struct pattern or literal fields are unstable"); - err.emit(); - } - } - } } impl<'a> fold::Folder for StripUnconfigured<'a> { diff --git a/src/libsyntax/diagnostics/macros.rs b/src/libsyntax/diagnostics/macros.rs index 13016d72127e..e8ecf58072a6 100644 --- a/src/libsyntax/diagnostics/macros.rs +++ b/src/libsyntax/diagnostics/macros.rs @@ -74,6 +74,17 @@ macro_rules! struct_span_err { }) } +#[macro_export] +macro_rules! type_error_struct { + ($session:expr, $span:expr, $typ:expr, $code:ident, $($message:tt)*) => ({ + if $typ.references_error() { + $session.diagnostic().struct_dummy() + } else { + struct_span_err!($session, $span, $code, $($message)*) + } + }) +} + #[macro_export] macro_rules! struct_span_warn { ($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({ diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index 0b6a2eb536a2..61d8fc2941af 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -139,13 +139,20 @@ struct MatcherPos { sep: Option, idx: usize, up: Option>, - matches: Vec>>, + matches: Vec>>, match_lo: usize, match_cur: usize, match_hi: usize, sp_lo: BytePos, } +impl MatcherPos { + fn push_match(&mut self, idx: usize, m: NamedMatch) { + let matches = Rc::make_mut(&mut self.matches[idx]); + matches.push(m); + } +} + pub type NamedParseResult = ParseResult>>; pub fn count_names(ms: &[TokenTree]) -> usize { @@ -199,14 +206,15 @@ fn initial_matcher_pos(ms: Vec, lo: BytePos) -> Box { /// only on the nesting depth of `ast::TTSeq`s in the originating /// token tree it was derived from. +#[derive(Debug, Clone)] pub enum NamedMatch { - MatchedSeq(Vec>, syntax_pos::Span), + MatchedSeq(Rc>, syntax_pos::Span), MatchedNonterminal(Rc) } -fn nameize>>(sess: &ParseSess, ms: &[TokenTree], mut res: I) +fn nameize>(sess: &ParseSess, ms: &[TokenTree], mut res: I) -> NamedParseResult { - fn n_rec>>(sess: &ParseSess, m: &TokenTree, mut res: &mut I, + fn n_rec>(sess: &ParseSess, m: &TokenTree, mut res: &mut I, ret_val: &mut HashMap>) -> Result<(), (syntax_pos::Span, String)> { match *m { @@ -228,7 +236,8 @@ fn nameize>>(sess: &ParseSess, ms: &[TokenTree], TokenTree::MetaVarDecl(sp, bind_name, _) => { match ret_val.entry(bind_name) { Vacant(spot) => { - spot.insert(res.next().unwrap()); + // FIXME(simulacrum): Don't construct Rc here + spot.insert(Rc::new(res.next().unwrap())); } Occupied(..) => { return Err((sp, format!("duplicated bind name: {}", bind_name))) @@ -280,8 +289,8 @@ fn token_name_eq(t1 : &Token, t2 : &Token) -> bool { } } -fn create_matches(len: usize) -> Vec>> { - (0..len).into_iter().map(|_| Vec::new()).collect() +fn create_matches(len: usize) -> Vec>> { + (0..len).into_iter().map(|_| Rc::new(Vec::new())).collect() } fn inner_parse_loop(sess: &ParseSess, @@ -320,15 +329,10 @@ fn inner_parse_loop(sess: &ParseSess, // update matches (the MBE "parse tree") by appending // each tree as a subtree. - // I bet this is a perf problem: we're preemptively - // doing a lot of array work that will get thrown away - // most of the time. - // Only touch the binders we have actually bound for idx in ei.match_lo..ei.match_hi { let sub = ei.matches[idx].clone(); - new_pos.matches[idx] - .push(Rc::new(MatchedSeq(sub, Span { lo: ei.sp_lo, ..span }))); + new_pos.push_match(idx, MatchedSeq(sub, Span { lo: ei.sp_lo, ..span })); } new_pos.match_cur = ei.match_hi; @@ -362,7 +366,7 @@ fn inner_parse_loop(sess: &ParseSess, new_ei.match_cur += seq.num_captures; new_ei.idx += 1; for idx in ei.match_cur..ei.match_cur + seq.num_captures { - new_ei.matches[idx].push(Rc::new(MatchedSeq(vec![], sp))); + new_ei.push_match(idx, MatchedSeq(Rc::new(vec![]), sp)); } cur_eis.push(new_ei); } @@ -446,7 +450,9 @@ pub fn parse(sess: &ParseSess, /* error messages here could be improved with links to orig. rules */ if token_name_eq(&parser.token, &token::Eof) { if eof_eis.len() == 1 { - let matches = eof_eis[0].matches.iter_mut().map(|mut dv| dv.pop().unwrap()); + let matches = eof_eis[0].matches.iter_mut().map(|mut dv| { + Rc::make_mut(dv).pop().unwrap() + }); return nameize(sess, ms, matches); } else if eof_eis.len() > 1 { return Error(parser.span, "ambiguity: multiple successful parses".to_string()); @@ -479,8 +485,8 @@ pub fn parse(sess: &ParseSess, let mut ei = bb_eis.pop().unwrap(); if let TokenTree::MetaVarDecl(span, _, ident) = ei.top_elts.get_tt(ei.idx) { let match_cur = ei.match_cur; - ei.matches[match_cur].push(Rc::new(MatchedNonterminal( - Rc::new(parse_nt(&mut parser, span, &ident.name.as_str()))))); + ei.push_match(match_cur, + MatchedNonterminal(Rc::new(parse_nt(&mut parser, span, &ident.name.as_str())))); ei.idx += 1; ei.match_cur += 1; } else { diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 0472a94e0ced..9c728c9f2ebf 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -219,7 +219,7 @@ pub fn compile(sess: &ParseSess, features: &RefCell, def: &ast::Item) let lhses = match *argument_map[&lhs_nm] { MatchedSeq(ref s, _) => { s.iter().map(|m| { - if let MatchedNonterminal(ref nt) = **m { + if let MatchedNonterminal(ref nt) = *m { if let NtTT(ref tt) = **nt { let tt = quoted::parse(tt.clone().into(), true, sess).pop().unwrap(); valid &= check_lhs_nt_follows(sess, features, &tt); @@ -235,7 +235,7 @@ pub fn compile(sess: &ParseSess, features: &RefCell, def: &ast::Item) let rhses = match *argument_map[&rhs_nm] { MatchedSeq(ref s, _) => { s.iter().map(|m| { - if let MatchedNonterminal(ref nt) = **m { + if let MatchedNonterminal(ref nt) = *m { if let NtTT(ref tt) = **nt { return quoted::parse(tt.clone().into(), false, sess).pop().unwrap(); } diff --git a/src/libsyntax/ext/tt/transcribe.rs b/src/libsyntax/ext/tt/transcribe.rs index 2a435bdea107..78e755e73fa3 100644 --- a/src/libsyntax/ext/tt/transcribe.rs +++ b/src/libsyntax/ext/tt/transcribe.rs @@ -182,15 +182,16 @@ fn lookup_cur_matched(ident: Ident, repeats: &[(usize, usize)]) -> Option> { interpolations.get(&ident).map(|matched| { - repeats.iter().fold(matched.clone(), |ad, &(idx, _)| { - match *ad { - MatchedNonterminal(_) => { - // end of the line; duplicate henceforth - ad.clone() - } - MatchedSeq(ref ads, _) => ads[idx].clone() + let mut matched = matched.clone(); + for &(idx, _) in repeats { + let m = matched.clone(); + match *m { + MatchedNonterminal(_) => break, + MatchedSeq(ref ads, _) => matched = Rc::new(ads[idx].clone()), } - }) + } + + matched }) } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index b2f52d11db2b..4543378789df 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -312,9 +312,6 @@ declare_features! ( // Declarative macros 2.0 (`macro`). (active, decl_macro, "1.17.0", Some(39412)), - // Allows attributes on struct literal fields. - (active, struct_field_attributes, "1.16.0", Some(38814)), - // Allows #[link(kind="static-nobundle"...] (active, static_nobundle, "1.16.0", Some(37403)), @@ -325,6 +322,10 @@ declare_features! ( // rustc internal (active, sanitizer_runtime, "1.17.0", None), + // Used to identify crates that contain the profiler runtime + // rustc internal + (active, profiler_runtime, "1.18.0", None), + // `extern "x86-interrupt" fn()` (active, abi_x86_interrupt, "1.17.0", Some(40180)), @@ -426,6 +427,8 @@ declare_features! ( (accepted, relaxed_adts, "1.19.0", Some(35626)), // Coerces non capturing closures to function pointers (accepted, closure_to_fn_coercion, "1.19.0", Some(39817)), + // Allows attributes on struct literal fields. + (accepted, struct_field_attributes, "1.20.0", Some(38814)), ); // If you change this, please modify src/doc/unstable-book as well. You must @@ -691,6 +694,13 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG identify crates that contain the runtime of a \ sanitizer and will never be stable", cfg_fn!(sanitizer_runtime))), + ("profiler_runtime", Whitelisted, Gated(Stability::Unstable, + "profiler_runtime", + "the `#[profiler_runtime]` attribute is used to \ + identify the `profiler_builtins` crate which \ + contains the profiler runtime and will never be \ + stable", + cfg_fn!(profiler_runtime))), ("allow_internal_unstable", Normal, Gated(Stability::Unstable, "allow_internal_unstable", diff --git a/src/libsyntax/json.rs b/src/libsyntax/json.rs index f37dcfdde898..e60edafe4ee4 100644 --- a/src/libsyntax/json.rs +++ b/src/libsyntax/json.rs @@ -314,7 +314,7 @@ impl DiagnosticSpanLine { h_end: usize) -> DiagnosticSpanLine { DiagnosticSpanLine { - text: fm.get_line(index).unwrap_or("").to_owned(), + text: fm.get_line(index).map_or(String::new(), |l| l.into_owned()), highlight_start: h_start, highlight_end: h_end, } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index d9cb2b4ab7db..0b145c54f619 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -150,7 +150,7 @@ fn maybe_append(mut lhs: Vec, rhs: Option>) lhs } -#[derive(PartialEq)] +#[derive(Clone, PartialEq)] enum PrevTokenKind { DocComment, Comma, @@ -162,6 +162,7 @@ enum PrevTokenKind { /* ident is handled by common.rs */ +#[derive(Clone)] pub struct Parser<'a> { pub sess: &'a ParseSess, /// the current token: @@ -193,11 +194,13 @@ pub struct Parser<'a> { } +#[derive(Clone)] struct TokenCursor { frame: TokenCursorFrame, stack: Vec, } +#[derive(Clone)] struct TokenCursorFrame { delim: token::DelimToken, span: Span, @@ -397,6 +400,7 @@ impl Error { } } +#[derive(Debug)] pub enum LhsExpr { NotYetParsed, AttributesParsed(ThinVec), @@ -1249,10 +1253,7 @@ impl<'a> Parser<'a> { let mac = respan(lo.to(self.prev_span), Mac_ { path: pth, tts: tts }); (keywords::Invalid.ident(), ast::TraitItemKind::Macro(mac)) } else { - let (constness, unsafety, abi) = match self.parse_fn_front_matter() { - Ok(cua) => cua, - Err(e) => return Err(e), - }; + let (constness, unsafety, abi) = self.parse_fn_front_matter()?; let ident = self.parse_ident()?; let mut generics = self.parse_generics()?; @@ -1724,7 +1725,7 @@ impl<'a> Parser<'a> { let segments = match mode { PathStyle::Type => { - self.parse_path_segments_without_colons()? + self.parse_path_segments_without_colons(true)? } PathStyle::Expr => { self.parse_path_segments_with_colons()? @@ -1745,6 +1746,16 @@ impl<'a> Parser<'a> { /// bounds are permitted and whether `::` must precede type parameter /// groups. pub fn parse_path(&mut self, mode: PathStyle) -> PResult<'a, ast::Path> { + self.parse_path_common(mode, true) + } + + pub fn parse_path_without_generics(&mut self, mode: PathStyle) -> PResult<'a, ast::Path> { + self.parse_path_common(mode, false) + } + + fn parse_path_common(&mut self, mode: PathStyle, parse_generics: bool) + -> PResult<'a, ast::Path> + { maybe_whole!(self, NtPath, |x| x); let lo = self.meta_var_span.unwrap_or(self.span); @@ -1755,7 +1766,7 @@ impl<'a> Parser<'a> { // A bound set is a set of type parameter bounds. let mut segments = match mode { PathStyle::Type => { - self.parse_path_segments_without_colons()? + self.parse_path_segments_without_colons(parse_generics)? } PathStyle::Expr => { self.parse_path_segments_with_colons()? @@ -1800,7 +1811,9 @@ impl<'a> Parser<'a> { /// - `a::b::c` /// - `a::b::c(V) -> W` /// - `a::b::c(V)` - pub fn parse_path_segments_without_colons(&mut self) -> PResult<'a, Vec> { + pub fn parse_path_segments_without_colons(&mut self, parse_generics: bool) + -> PResult<'a, Vec> + { let mut segments = Vec::new(); loop { // First, parse an identifier. @@ -1819,7 +1832,7 @@ impl<'a> Parser<'a> { } // Parse types, optionally. - let parameters = if self.eat_lt() { + let parameters = if parse_generics && self.eat_lt() { let (lifetimes, types, bindings) = self.parse_generic_args()?; self.expect_gt()?; ast::AngleBracketedParameterData { @@ -2798,8 +2811,9 @@ impl<'a> Parser<'a> { } // Special cases: if op == AssocOp::As { - let rhs = self.parse_ty_no_plus()?; - lhs = self.mk_expr(lhs_span.to(rhs.span), ExprKind::Cast(lhs, rhs), ThinVec::new()); + // Save the state of the parser before parsing type normally, in case there is a + // LessThan comparison after this cast. + lhs = self.parse_assoc_op_as(lhs, lhs_span)?; continue } else if op == AssocOp::Colon { let rhs = self.parse_ty_no_plus()?; @@ -2897,11 +2911,74 @@ impl<'a> Parser<'a> { Ok(lhs) } + fn parse_assoc_op_as(&mut self, lhs: P, lhs_span: Span) -> PResult<'a, P> { + let rp = self.clone(); + match self.parse_ty_no_plus() { + Ok(rhs) => { + Ok(self.mk_expr(lhs_span.to(rhs.span), + ExprKind::Cast(lhs, rhs), + ThinVec::new())) + } + Err(mut err) => { + let rp_err = self.clone(); + let sp = rp_err.span.clone(); + + // Rewind to before attempting to parse the type with generics, to get + // arround #22644. + mem::replace(self, rp); + let lo = self.span; + match self.parse_path_without_generics(PathStyle::Type) { + Ok(path) => { + // Successfully parsed the type leaving a `<` yet to parse + err.cancel(); + let codemap = self.sess.codemap(); + let suggestion_span = lhs_span.to(self.prev_span); + let suggestion = match codemap.span_to_snippet(suggestion_span) { + Ok(lstring) => format!("({})", lstring), + _ => format!("( as )") + }; + let warn_message = match codemap.span_to_snippet(self.prev_span) { + Ok(lstring) => format!("`{}`", lstring), + _ => "a type".to_string(), + }; + let msg = format!("`<` is interpreted as a start of generic \ + arguments for {}, not a comparison", + warn_message); + let mut err = self.sess.span_diagnostic.struct_span_err(sp, &msg); + err.span_label(sp, "interpreted as generic argument"); + err.span_label(self.span, "not interpreted as comparison"); + err.span_suggestion(suggestion_span, + "if you want to compare the casted value then write:", + suggestion); + err.emit(); + + let path = TyKind::Path(None, path); + let span = lo.to(self.prev_span); + let rhs = P(Ty { node: path, span: span, id: ast::DUMMY_NODE_ID }); + // Letting the parser accept the recovered type to avoid further errors, + // but the code will still not compile due to the error emitted above. + Ok(self.mk_expr(lhs_span.to(rhs.span), + ExprKind::Cast(lhs, rhs), + ThinVec::new())) + } + Err(mut path_err) => { + // Still couldn't parse, return original error and parser state + path_err.cancel(); + mem::replace(self, rp_err); + Err(err) + } + } + } + } + } + /// Produce an error if comparison operators are chained (RFC #558). /// We only need to check lhs, not rhs, because all comparison ops /// have same precedence and are left-associative fn check_no_chained_comparison(&mut self, lhs: &Expr, outer_op: &AssocOp) { - debug_assert!(outer_op.is_comparison()); + debug_assert!(outer_op.is_comparison(), + "check_no_chained_comparison: {:?} is not comparison", + outer_op); match lhs.node { ExprKind::Binary(op, _, _) if op.node.is_comparison() => { // respan to include both operators @@ -2925,7 +3002,9 @@ impl<'a> Parser<'a> { fn parse_prefix_range_expr(&mut self, already_parsed_attrs: Option>) -> PResult<'a, P> { - debug_assert!(self.token == token::DotDot || self.token == token::DotDotDot); + debug_assert!(self.token == token::DotDot || self.token == token::DotDotDot, + "parse_prefix_range_expr: token {:?} is not DotDot or DotDotDot", + self.token); let tok = self.token.clone(); let attrs = self.parse_or_use_outer_attributes(already_parsed_attrs)?; let lo = self.span; diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 073ededcb0ce..34cda433d525 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -370,6 +370,10 @@ pub fn path_to_string(p: &ast::Path) -> String { to_string(|s| s.print_path(p, false, 0, false)) } +pub fn path_segment_to_string(p: &ast::PathSegment) -> String { + to_string(|s| s.print_path_segment(p, false)) +} + pub fn ident_to_string(id: ast::Ident) -> String { to_string(|s| s.print_ident(id)) } @@ -2359,18 +2363,27 @@ impl<'a> State<'a> { if i > 0 { word(&mut self.s, "::")? } - if segment.identifier.name != keywords::CrateRoot.name() && - segment.identifier.name != "$crate" { - self.print_ident(segment.identifier)?; - if let Some(ref parameters) = segment.parameters { - self.print_path_parameters(parameters, colons_before_params)?; - } - } + self.print_path_segment(segment, colons_before_params)?; } Ok(()) } + fn print_path_segment(&mut self, + segment: &ast::PathSegment, + colons_before_params: bool) + -> io::Result<()> + { + if segment.identifier.name != keywords::CrateRoot.name() && + segment.identifier.name != "$crate" { + self.print_ident(segment.identifier)?; + if let Some(ref parameters) = segment.parameters { + self.print_path_parameters(parameters, colons_before_params)?; + } + } + Ok(()) + } + fn print_qpath(&mut self, path: &ast::Path, qself: &ast::QSelf, diff --git a/src/libsyntax/ptr.rs b/src/libsyntax/ptr.rs index 15111bbba0a9..d51ff9860ac8 100644 --- a/src/libsyntax/ptr.rs +++ b/src/libsyntax/ptr.rs @@ -211,10 +211,7 @@ impl Encodable for P<[T]> { impl Decodable for P<[T]> { fn decode(d: &mut D) -> Result, D::Error> { - Ok(P::from_vec(match Decodable::decode(d) { - Ok(t) => t, - Err(e) => return Err(e) - })) + Ok(P::from_vec(Decodable::decode(d)?)) } } diff --git a/src/libsyntax/test_snippet.rs b/src/libsyntax/test_snippet.rs index b3fa1e97376d..4fae2ff9814f 100644 --- a/src/libsyntax/test_snippet.rs +++ b/src/libsyntax/test_snippet.rs @@ -735,6 +735,49 @@ error: foo "#); } +#[test] +fn multiple_labels_secondary_without_message_3() { + test_harness(r#" +fn foo() { + a bc d +} +"#, + vec![ + SpanLabel { + start: Position { + string: "a", + count: 1, + }, + end: Position { + string: "b", + count: 1, + }, + label: "`a` is a good letter", + }, + SpanLabel { + start: Position { + string: "c", + count: 1, + }, + end: Position { + string: "d", + count: 1, + }, + label: "", + }, + ], + r#" +error: foo + --> test.rs:3:3 + | +3 | a bc d + | ^^^^---- + | | + | `a` is a good letter + +"#); +} + #[test] fn multiple_labels_without_message() { test_harness(r#" diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs index 339e7c0b628a..963482fc223f 100644 --- a/src/libsyntax/tokenstream.rs +++ b/src/libsyntax/tokenstream.rs @@ -227,14 +227,17 @@ impl TokenStream { } } +#[derive(Clone)] pub struct Cursor(CursorKind); +#[derive(Clone)] enum CursorKind { Empty, Tree(TokenTree, bool /* consumed? */), Stream(StreamCursor), } +#[derive(Clone)] struct StreamCursor { stream: RcSlice, index: usize, diff --git a/src/libsyntax_pos/Cargo.toml b/src/libsyntax_pos/Cargo.toml index 760aaa8a9578..dd8129bab510 100644 --- a/src/libsyntax_pos/Cargo.toml +++ b/src/libsyntax_pos/Cargo.toml @@ -10,3 +10,4 @@ crate-type = ["dylib"] [dependencies] serialize = { path = "../libserialize" } +rustc_data_structures = { path = "../librustc_data_structures" } diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 25f74aeecf40..94656b3aea79 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -24,6 +24,7 @@ #![feature(const_fn)] #![feature(custom_attribute)] +#![feature(i128_type)] #![feature(optin_builtin_traits)] #![allow(unused_attributes)] #![feature(specialization)] @@ -32,12 +33,17 @@ #![cfg_attr(stage0, feature(rustc_private))] #![cfg_attr(stage0, feature(staged_api))] +use std::borrow::Cow; use std::cell::{Cell, RefCell}; use std::ops::{Add, Sub}; use std::rc::Rc; use std::cmp; - use std::fmt; +use std::hash::Hasher; + +use rustc_data_structures::stable_hasher::StableHasher; + +extern crate rustc_data_structures; use serialize::{Encodable, Decodable, Encoder, Decoder}; @@ -369,6 +375,35 @@ pub struct MultiByteChar { pub bytes: usize, } +/// The state of the lazy external source loading mechanism of a FileMap. +#[derive(PartialEq, Eq, Clone)] +pub enum ExternalSource { + /// The external source has been loaded already. + Present(String), + /// No attempt has been made to load the external source. + AbsentOk, + /// A failed attempt has been made to load the external source. + AbsentErr, + /// No external source has to be loaded, since the FileMap represents a local crate. + Unneeded, +} + +impl ExternalSource { + pub fn is_absent(&self) -> bool { + match *self { + ExternalSource::Present(_) => false, + _ => true, + } + } + + pub fn get_source(&self) -> Option<&str> { + match *self { + ExternalSource::Present(ref src) => Some(src), + _ => None, + } + } +} + /// A single source in the CodeMap. #[derive(Clone)] pub struct FileMap { @@ -382,6 +417,11 @@ pub struct FileMap { pub crate_of_origin: u32, /// The complete source code pub src: Option>, + /// The source code's hash + pub src_hash: u128, + /// The external source code (used for external crates, which will have a `None` + /// value as `self.src`. + pub external_src: RefCell, /// The start position of this source in the CodeMap pub start_pos: BytePos, /// The end position of this source in the CodeMap @@ -394,9 +434,10 @@ pub struct FileMap { impl Encodable for FileMap { fn encode(&self, s: &mut S) -> Result<(), S::Error> { - s.emit_struct("FileMap", 6, |s| { + s.emit_struct("FileMap", 7, |s| { s.emit_struct_field("name", 0, |s| self.name.encode(s))?; s.emit_struct_field("name_was_remapped", 1, |s| self.name_was_remapped.encode(s))?; + s.emit_struct_field("src_hash", 6, |s| self.src_hash.encode(s))?; s.emit_struct_field("start_pos", 2, |s| self.start_pos.encode(s))?; s.emit_struct_field("end_pos", 3, |s| self.end_pos.encode(s))?; s.emit_struct_field("lines", 4, |s| { @@ -459,7 +500,10 @@ impl Decodable for FileMap { let name: String = d.read_struct_field("name", 0, |d| Decodable::decode(d))?; let name_was_remapped: bool = d.read_struct_field("name_was_remapped", 1, |d| Decodable::decode(d))?; - let start_pos: BytePos = d.read_struct_field("start_pos", 2, |d| Decodable::decode(d))?; + let src_hash: u128 = + d.read_struct_field("src_hash", 6, |d| Decodable::decode(d))?; + let start_pos: BytePos = + d.read_struct_field("start_pos", 2, |d| Decodable::decode(d))?; let end_pos: BytePos = d.read_struct_field("end_pos", 3, |d| Decodable::decode(d))?; let lines: Vec = d.read_struct_field("lines", 4, |d| { let num_lines: u32 = Decodable::decode(d)?; @@ -501,6 +545,8 @@ impl Decodable for FileMap { start_pos: start_pos, end_pos: end_pos, src: None, + src_hash: src_hash, + external_src: RefCell::new(ExternalSource::AbsentOk), lines: RefCell::new(lines), multibyte_chars: RefCell::new(multibyte_chars) }) @@ -515,6 +561,32 @@ impl fmt::Debug for FileMap { } impl FileMap { + pub fn new(name: FileName, + name_was_remapped: bool, + mut src: String, + start_pos: BytePos) -> FileMap { + remove_bom(&mut src); + + let mut hasher: StableHasher = StableHasher::new(); + hasher.write(src.as_bytes()); + let src_hash = hasher.finish(); + + let end_pos = start_pos.to_usize() + src.len(); + + FileMap { + name: name, + name_was_remapped: name_was_remapped, + crate_of_origin: 0, + src: Some(Rc::new(src)), + src_hash: src_hash, + external_src: RefCell::new(ExternalSource::Unneeded), + start_pos: start_pos, + end_pos: Pos::from_usize(end_pos), + lines: RefCell::new(Vec::new()), + multibyte_chars: RefCell::new(Vec::new()), + } + } + /// EFFECT: register a start-of-line offset in the /// table of line-beginnings. /// UNCHECKED INVARIANT: these offsets must be added in the right @@ -532,26 +604,60 @@ impl FileMap { lines.push(pos); } - /// get a line from the list of pre-computed line-beginnings. - /// line-number here is 0-based. - pub fn get_line(&self, line_number: usize) -> Option<&str> { - match self.src { - Some(ref src) => { - let lines = self.lines.borrow(); - lines.get(line_number).map(|&line| { - let begin: BytePos = line - self.start_pos; - let begin = begin.to_usize(); - // We can't use `lines.get(line_number+1)` because we might - // be parsing when we call this function and thus the current - // line is the last one we have line info for. - let slice = &src[begin..]; - match slice.find('\n') { - Some(e) => &slice[..e], - None => slice - } - }) + /// Add externally loaded source. + /// If the hash of the input doesn't match or no input is supplied via None, + /// it is interpreted as an error and the corresponding enum variant is set. + /// The return value signifies whether some kind of source is present. + pub fn add_external_src(&self, src: Option) -> bool { + if *self.external_src.borrow() == ExternalSource::AbsentOk { + let mut external_src = self.external_src.borrow_mut(); + if let Some(src) = src { + let mut hasher: StableHasher = StableHasher::new(); + hasher.write(src.as_bytes()); + + if hasher.finish() == self.src_hash { + *external_src = ExternalSource::Present(src); + return true; + } + } else { + *external_src = ExternalSource::AbsentErr; } - None => None + + false + } else { + self.src.is_some() || self.external_src.borrow().get_source().is_some() + } + } + + /// Get a line from the list of pre-computed line-beginnings. + /// The line number here is 0-based. + pub fn get_line(&self, line_number: usize) -> Option> { + fn get_until_newline(src: &str, begin: usize) -> &str { + // We can't use `lines.get(line_number+1)` because we might + // be parsing when we call this function and thus the current + // line is the last one we have line info for. + let slice = &src[begin..]; + match slice.find('\n') { + Some(e) => &slice[..e], + None => slice + } + } + + let lines = self.lines.borrow(); + let line = if let Some(line) = lines.get(line_number) { + line + } else { + return None; + }; + let begin: BytePos = *line - self.start_pos; + let begin = begin.to_usize(); + + if let Some(ref src) = self.src { + Some(Cow::from(get_until_newline(src, begin))) + } else if let Some(src) = self.external_src.borrow().get_source() { + Some(Cow::Owned(String::from(get_until_newline(src, begin)))) + } else { + None } } @@ -614,6 +720,13 @@ impl FileMap { } } +/// Remove utf-8 BOM if any. +fn remove_bom(src: &mut String) { + if src.starts_with("\u{feff}") { + src.drain(..3); + } +} + // _____________________________________________________________________________ // Pos, BytePos, CharPos // diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index ef048ac8ca35..74212625eea0 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -16,7 +16,7 @@ //! benchmarks themselves) should be done via the `#[test]` and //! `#[bench]` attributes. //! -//! See the [Testing Chapter](../book/testing.html) of the book for more details. +//! See the [Testing Chapter](../book/first-edition/testing.html) of the book for more details. // Currently, not much of this is meant for users. It is intended to // support the simplest interface possible for representing and diff --git a/src/llvm b/src/llvm index 1ef3b9128e1b..5415ff0264c1 160000 --- a/src/llvm +++ b/src/llvm @@ -1 +1 @@ -Subproject commit 1ef3b9128e1baaed61b42d5b0de79dee100acf17 +Subproject commit 5415ff0264c134152cca65ae8f5d50b356d61162 diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 838c180c70b7..c11c5f4186ec 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -466,6 +466,10 @@ extern "C" void LLVMRustAddModuleFlag(LLVMModuleRef M, const char *Name, unwrap(M)->addModuleFlag(Module::Warning, Name, Value); } +extern "C" void LLVMRustMetadataAsValue(LLVMContextRef C, LLVMRustMetadataRef MD) { + wrap(MetadataAsValue::get(*unwrap(C), unwrap(MD))); +} + extern "C" LLVMRustDIBuilderRef LLVMRustDIBuilderCreate(LLVMModuleRef M) { return new DIBuilder(*unwrap(M)); } diff --git a/src/rustllvm/llvm-rebuild-trigger b/src/rustllvm/llvm-rebuild-trigger index 70663f30e8f9..792b496f1dbe 100644 --- a/src/rustllvm/llvm-rebuild-trigger +++ b/src/rustllvm/llvm-rebuild-trigger @@ -1,4 +1,4 @@ # If this file is modified, then llvm will be (optionally) cleaned and then rebuilt. # The actual contents of this file do not matter, but to trigger a change on the # build bots then the contents should be changed so git updates the mtime. -2017-05-13 +2017-06-18 diff --git a/src/test/codegen-units/item-collection/function-as-argument.rs b/src/test/codegen-units/item-collection/function-as-argument.rs index c4aed7465bcb..c3d46ff5314f 100644 --- a/src/test/codegen-units/item-collection/function-as-argument.rs +++ b/src/test/codegen-units/item-collection/function-as-argument.rs @@ -28,12 +28,12 @@ fn main() { //~ TRANS_ITEM fn function_as_argument::take_fn_once[0] //~ TRANS_ITEM fn function_as_argument::function[0] - //~ TRANS_ITEM fn core::ops[0]::FnOnce[0]::call_once[0] + //~ TRANS_ITEM fn core::ops[0]::function[0]::FnOnce[0]::call_once[0] take_fn_once(function, 0u32, "abc"); //~ TRANS_ITEM fn function_as_argument::take_fn_once[0] //~ TRANS_ITEM fn function_as_argument::function[0] - //~ TRANS_ITEM fn core::ops[0]::FnOnce[0]::call_once[0] + //~ TRANS_ITEM fn core::ops[0]::function[0]::FnOnce[0]::call_once[0] take_fn_once(function, 'c', 0f64); //~ TRANS_ITEM fn function_as_argument::take_fn_pointer[0] diff --git a/src/test/codegen-units/item-collection/trait-method-as-argument.rs b/src/test/codegen-units/item-collection/trait-method-as-argument.rs index f095b637a84e..21c9c254e51c 100644 --- a/src/test/codegen-units/item-collection/trait-method-as-argument.rs +++ b/src/test/codegen-units/item-collection/trait-method-as-argument.rs @@ -40,27 +40,27 @@ fn take_foo_mut T>(mut f: F, arg: T) -> T { fn main() { //~ TRANS_ITEM fn trait_method_as_argument::take_foo_once[0] u32> //~ TRANS_ITEM fn trait_method_as_argument::{{impl}}[0]::foo[0] - //~ TRANS_ITEM fn core::ops[0]::FnOnce[0]::call_once[0] u32, (u32)> + //~ TRANS_ITEM fn core::ops[0]::function[0]::FnOnce[0]::call_once[0] u32, (u32)> take_foo_once(Trait::foo, 0u32); //~ TRANS_ITEM fn trait_method_as_argument::take_foo_once[0] char> //~ TRANS_ITEM fn trait_method_as_argument::Trait[0]::foo[0] - //~ TRANS_ITEM fn core::ops[0]::FnOnce[0]::call_once[0] char, (char)> + //~ TRANS_ITEM fn core::ops[0]::function[0]::FnOnce[0]::call_once[0] char, (char)> take_foo_once(Trait::foo, 'c'); //~ TRANS_ITEM fn trait_method_as_argument::take_foo[0] u32> - //~ TRANS_ITEM fn core::ops[0]::Fn[0]::call[0] u32, (u32)> + //~ TRANS_ITEM fn core::ops[0]::function[0]::Fn[0]::call[0] u32, (u32)> take_foo(Trait::foo, 0u32); //~ TRANS_ITEM fn trait_method_as_argument::take_foo[0] char> - //~ TRANS_ITEM fn core::ops[0]::Fn[0]::call[0] char, (char)> + //~ TRANS_ITEM fn core::ops[0]::function[0]::Fn[0]::call[0] char, (char)> take_foo(Trait::foo, 'c'); //~ TRANS_ITEM fn trait_method_as_argument::take_foo_mut[0] u32> - //~ TRANS_ITEM fn core::ops[0]::FnMut[0]::call_mut[0] char, (char)> + //~ TRANS_ITEM fn core::ops[0]::function[0]::FnMut[0]::call_mut[0] char, (char)> take_foo_mut(Trait::foo, 0u32); //~ TRANS_ITEM fn trait_method_as_argument::take_foo_mut[0] char> - //~ TRANS_ITEM fn core::ops[0]::FnMut[0]::call_mut[0] u32, (u32)> + //~ TRANS_ITEM fn core::ops[0]::function[0]::FnMut[0]::call_mut[0] u32, (u32)> take_foo_mut(Trait::foo, 'c'); } diff --git a/src/test/codegen/alloc-optimisation.rs b/src/test/codegen/alloc-optimisation.rs new file mode 100644 index 000000000000..07dc1350714b --- /dev/null +++ b/src/test/codegen/alloc-optimisation.rs @@ -0,0 +1,22 @@ +// 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. +// +// no-system-llvm +// compile-flags: -O +#![crate_type="lib"] + +#[no_mangle] +pub fn alloc_test(data: u32) { + // CHECK-LABEL: @alloc_test + // CHECK-NEXT: start: + // CHECK-NEXT: ret void + let x = Box::new(data); + drop(x); +} diff --git a/src/test/codegen/drop.rs b/src/test/codegen/drop.rs index d7e2cb6d9a50..1961060c2c26 100644 --- a/src/test/codegen/drop.rs +++ b/src/test/codegen/drop.rs @@ -32,9 +32,9 @@ pub fn droppy() { // CHECK-NOT: invoke{{.*}}drop{{.*}}SomeUniqueName // CHECK: call{{.*}}drop{{.*}}SomeUniqueName // CHECK: call{{.*}}drop{{.*}}SomeUniqueName -// CHECK: call{{.*}}drop{{.*}}SomeUniqueName // CHECK-NOT: call{{.*}}drop{{.*}}SomeUniqueName // CHECK: invoke{{.*}}drop{{.*}}SomeUniqueName +// CHECK: call{{.*}}drop{{.*}}SomeUniqueName // CHECK: invoke{{.*}}drop{{.*}}SomeUniqueName // CHECK: call{{.*}}drop{{.*}}SomeUniqueName // CHECK-NOT: {{(call|invoke).*}}drop{{.*}}SomeUniqueName diff --git a/src/test/compile-fail/E0254.rs b/src/test/compile-fail/E0254.rs index fe7ee1c129f8..bc17a46a0172 100644 --- a/src/test/compile-fail/E0254.rs +++ b/src/test/compile-fail/E0254.rs @@ -8,18 +8,18 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(collections)] +#![feature(alloc)] -extern crate collections; -//~^ NOTE previous import of `collections` here +extern crate alloc; +//~^ NOTE previous import of `alloc` here mod foo { - pub trait collections { + pub trait alloc { fn do_something(); } } -use foo::collections; +use foo::alloc; //~^ ERROR E0254 //~| NOTE already imported diff --git a/src/test/compile-fail/E0259.rs b/src/test/compile-fail/E0259.rs index b2129902ef9c..259d67fe7cd6 100644 --- a/src/test/compile-fail/E0259.rs +++ b/src/test/compile-fail/E0259.rs @@ -8,13 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(collections, libc)] +#![feature(alloc, libc)] -extern crate collections; -//~^ NOTE previous import of `collections` here +extern crate alloc; +//~^ NOTE previous import of `alloc` here -extern crate libc as collections; +extern crate libc as alloc; //~^ ERROR E0259 -//~| NOTE `collections` already imported +//~| NOTE `alloc` already imported fn main() {} diff --git a/src/test/compile-fail/E0260.rs b/src/test/compile-fail/E0260.rs index ae018d2ada93..08d78782e4cd 100644 --- a/src/test/compile-fail/E0260.rs +++ b/src/test/compile-fail/E0260.rs @@ -8,14 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(collections)] +#![feature(alloc)] -extern crate collections; -//~^ NOTE previous import of `collections` here +extern crate alloc; +//~^ NOTE previous import of `alloc` here -mod collections { -//~^ ERROR `collections` has already been imported in this module [E0260] -//~| NOTE `collections` already imported +mod alloc { +//~^ ERROR `alloc` has already been imported in this module [E0260] +//~| NOTE `alloc` already imported pub trait MyTrait { fn do_something(); } diff --git a/src/test/compile-fail/E0429.rs b/src/test/compile-fail/E0429.rs index a7d19744f3fc..f1cad200be61 100644 --- a/src/test/compile-fail/E0429.rs +++ b/src/test/compile-fail/E0429.rs @@ -9,7 +9,6 @@ // except according to those terms. use std::fmt::self; //~ ERROR E0429 - //~^ ERROR E0432 fn main () { } diff --git a/src/test/compile-fail/E0608.rs b/src/test/compile-fail/E0608.rs new file mode 100644 index 000000000000..d47356a97eed --- /dev/null +++ b/src/test/compile-fail/E0608.rs @@ -0,0 +1,13 @@ +// 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. + +fn main() { + 0u8[2]; //~ ERROR E0608 +} diff --git a/src/test/compile-fail/struct-field-attr-feature-gate.rs b/src/test/compile-fail/E0609.rs similarity index 62% rename from src/test/compile-fail/struct-field-attr-feature-gate.rs rename to src/test/compile-fail/E0609.rs index 47495be4ad2c..f76c97274bde 100644 --- a/src/test/compile-fail/struct-field-attr-feature-gate.rs +++ b/src/test/compile-fail/E0609.rs @@ -8,15 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// gate-test-struct_field_attributes - struct Foo { - present: (), + x: u32, } fn main() { - let foo = Foo { #[cfg(all())] present: () }; - //~^ ERROR attributes on struct pattern or literal fields are unstable - let Foo { #[cfg(all())] present: () } = foo; - //~^ ERROR attributes on struct pattern or literal fields are unstable + let x = Foo { x: 0 }; + let _ = x.foo; //~ ERROR E0609 } diff --git a/src/test/compile-fail/E0610.rs b/src/test/compile-fail/E0610.rs new file mode 100644 index 000000000000..522d8b0b9438 --- /dev/null +++ b/src/test/compile-fail/E0610.rs @@ -0,0 +1,14 @@ +// 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. + +fn main() { + let x = 0; + let _ = x.foo; //~ ERROR E0610 +} diff --git a/src/test/compile-fail/E0617.rs b/src/test/compile-fail/E0617.rs new file mode 100644 index 000000000000..7b769ff4ae2e --- /dev/null +++ b/src/test/compile-fail/E0617.rs @@ -0,0 +1,32 @@ +// 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. + +// ignore-tidy-linelength + +extern { + fn printf(c: *const i8, ...); +} + +fn main() { + unsafe { + printf(::std::ptr::null(), 0f32); + //~^ ERROR can't pass `f32` to variadic function, cast to `c_double` [E0617] + printf(::std::ptr::null(), 0i8); + //~^ ERROR can't pass `i8` to variadic function, cast to `c_int` [E0617] + printf(::std::ptr::null(), 0i16); + //~^ ERROR can't pass `i16` to variadic function, cast to `c_int` [E0617] + printf(::std::ptr::null(), 0u8); + //~^ ERROR can't pass `u8` to variadic function, cast to `c_uint` [E0617] + printf(::std::ptr::null(), 0u16); + //~^ ERROR can't pass `u16` to variadic function, cast to `c_uint` [E0617] + printf(::std::ptr::null(), printf); + //~^ ERROR can't pass `unsafe extern "C" fn(*const i8, ...) {printf}` to variadic function, cast to `unsafe extern "C" fn(*const i8, ...)` [E0617] + } +} diff --git a/src/test/compile-fail/E0618.rs b/src/test/compile-fail/E0618.rs new file mode 100644 index 000000000000..1ba2e8e2e561 --- /dev/null +++ b/src/test/compile-fail/E0618.rs @@ -0,0 +1,20 @@ +// 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. + +enum X { + Entry, +} + +fn main() { + X::Entry(); //~ ERROR expected function, found `X::Entry` [E0618] + //~| HELP did you mean to write `X::Entry`? + let x = 0i32; + x(); //~ ERROR expected function, found `i32` [E0618] +} diff --git a/src/test/compile-fail/attempted-access-non-fatal.rs b/src/test/compile-fail/attempted-access-non-fatal.rs index fe8e793ed781..3d6c46f5ce3e 100644 --- a/src/test/compile-fail/attempted-access-non-fatal.rs +++ b/src/test/compile-fail/attempted-access-non-fatal.rs @@ -11,6 +11,6 @@ // Check that bogus field access is non-fatal fn main() { let x = 0; - let _ = x.foo; //~ no field `foo` on type `{integer}` - let _ = x.bar; //~ no field `bar` on type `{integer}` + let _ = x.foo; //~ `{integer}` is a primitive type and therefore doesn't have fields [E0610] + let _ = x.bar; //~ `{integer}` is a primitive type and therefore doesn't have fields [E0610] } diff --git a/src/test/compile-fail/dep-graph-assoc-type-trans.rs b/src/test/compile-fail/dep-graph-assoc-type-trans.rs index fe76a4d439f3..007a80008a84 100644 --- a/src/test/compile-fail/dep-graph-assoc-type-trans.rs +++ b/src/test/compile-fail/dep-graph-assoc-type-trans.rs @@ -36,7 +36,6 @@ mod y { use Foo; #[rustc_then_this_would_need(TypeckTables)] //~ ERROR OK - #[rustc_then_this_would_need(TransCrateItem)] //~ ERROR OK pub fn use_char_assoc() { // Careful here: in the representation, ::T gets // normalized away, so at a certain point we had no edge to diff --git a/src/test/compile-fail/dep-graph-caller-callee.rs b/src/test/compile-fail/dep-graph-caller-callee.rs index 9cb87886809a..222c19720055 100644 --- a/src/test/compile-fail/dep-graph-caller-callee.rs +++ b/src/test/compile-fail/dep-graph-caller-callee.rs @@ -28,7 +28,6 @@ mod y { // These dependencies SHOULD exist: #[rustc_then_this_would_need(TypeckTables)] //~ ERROR OK - #[rustc_then_this_would_need(TransCrateItem)] //~ ERROR OK pub fn y() { x::x(); } @@ -40,7 +39,6 @@ mod z { // These are expected to yield errors, because changes to `x` // affect the BODY of `y`, but not its signature. #[rustc_then_this_would_need(TypeckTables)] //~ ERROR no path - #[rustc_then_this_would_need(TransCrateItem)] //~ ERROR no path pub fn z() { y::y(); } diff --git a/src/test/compile-fail/dep-graph-trait-impl.rs b/src/test/compile-fail/dep-graph-trait-impl.rs index c0f9f0546260..85b3e69065d9 100644 --- a/src/test/compile-fail/dep-graph-trait-impl.rs +++ b/src/test/compile-fail/dep-graph-trait-impl.rs @@ -35,25 +35,21 @@ mod y { use Foo; #[rustc_then_this_would_need(TypeckTables)] //~ ERROR OK - #[rustc_then_this_would_need(TransCrateItem)] //~ ERROR OK pub fn with_char() { char::method('a'); } #[rustc_then_this_would_need(TypeckTables)] //~ ERROR OK - #[rustc_then_this_would_need(TransCrateItem)] //~ ERROR OK pub fn take_foo_with_char() { take_foo::('a'); } #[rustc_then_this_would_need(TypeckTables)] //~ ERROR OK - #[rustc_then_this_would_need(TransCrateItem)] //~ ERROR OK pub fn with_u32() { u32::method(22); } #[rustc_then_this_would_need(TypeckTables)] //~ ERROR OK - #[rustc_then_this_would_need(TransCrateItem)] //~ ERROR OK pub fn take_foo_with_u32() { take_foo::(22); } @@ -67,7 +63,6 @@ mod z { // These are expected to yield errors, because changes to `x` // affect the BODY of `y`, but not its signature. #[rustc_then_this_would_need(TypeckTables)] //~ ERROR no path - #[rustc_then_this_would_need(TransCrateItem)] //~ ERROR no path pub fn z() { y::with_char(); y::with_u32(); diff --git a/src/test/compile-fail/empty-struct-unit-expr.rs b/src/test/compile-fail/empty-struct-unit-expr.rs index 273ce91a7c5b..9655007604de 100644 --- a/src/test/compile-fail/empty-struct-unit-expr.rs +++ b/src/test/compile-fail/empty-struct-unit-expr.rs @@ -24,10 +24,10 @@ enum E { fn main() { let e2 = Empty2(); //~ ERROR expected function, found `Empty2` let e4 = E::Empty4(); - //~^ ERROR `E::Empty4` is being called, but it is not a function + //~^ ERROR expected function, found `E::Empty4` [E0618] //~| HELP did you mean to write `E::Empty4`? let xe2 = XEmpty2(); //~ ERROR expected function, found `empty_struct::XEmpty2` let xe4 = XE::XEmpty4(); - //~^ ERROR `XE::XEmpty4` is being called, but it is not a function + //~^ ERROR expected function, found `XE::XEmpty4` [E0618] //~| HELP did you mean to write `XE::XEmpty4`? } diff --git a/src/test/compile-fail/extern-wrong-value-type.rs b/src/test/compile-fail/extern-wrong-value-type.rs index 576368aef312..66b06c505e47 100644 --- a/src/test/compile-fail/extern-wrong-value-type.rs +++ b/src/test/compile-fail/extern-wrong-value-type.rs @@ -18,5 +18,4 @@ fn main() { let _x: extern "C" fn() = f; // OK is_fn(f); //~^ ERROR `extern "C" fn() {f}: std::ops::Fn<()>` is not satisfied - //~| ERROR `extern "C" fn() {f}: std::ops::FnOnce<()>` is not satisfied } diff --git a/src/test/compile-fail/feature-gate-profiler-runtime.rs b/src/test/compile-fail/feature-gate-profiler-runtime.rs new file mode 100644 index 000000000000..c6b2cb2eb077 --- /dev/null +++ b/src/test/compile-fail/feature-gate-profiler-runtime.rs @@ -0,0 +1,13 @@ +// 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. + +#![profiler_runtime] //~ ERROR the `#[profiler_runtime]` attribute is + +fn main() {} diff --git a/src/test/compile-fail/fn-trait-formatting.rs b/src/test/compile-fail/fn-trait-formatting.rs index 6377550d3d22..6d70f54edb42 100644 --- a/src/test/compile-fail/fn-trait-formatting.rs +++ b/src/test/compile-fail/fn-trait-formatting.rs @@ -28,5 +28,4 @@ fn main() { needs_fn(1); //~^ ERROR : std::ops::Fn<(isize,)>` - //~| ERROR : std::ops::FnOnce<(isize,)>` } diff --git a/src/test/compile-fail/index-bot.rs b/src/test/compile-fail/index-bot.rs index 05b047233004..fc88ff6f47b8 100644 --- a/src/test/compile-fail/index-bot.rs +++ b/src/test/compile-fail/index-bot.rs @@ -9,5 +9,5 @@ // except according to those terms. fn main() { - (return)[0]; //~ ERROR cannot index a value of type `!` + (return)[0]; //~ ERROR cannot index into a value of type `!` } diff --git a/src/test/compile-fail/index_message.rs b/src/test/compile-fail/index_message.rs index 26dd98757a8c..b9daad936c33 100644 --- a/src/test/compile-fail/index_message.rs +++ b/src/test/compile-fail/index_message.rs @@ -10,5 +10,5 @@ fn main() { let z = (); - let _ = z[0]; //~ ERROR cannot index a value of type `()` + let _ = z[0]; //~ ERROR cannot index into a value of type `()` } diff --git a/src/test/compile-fail/issue-11740.rs b/src/test/compile-fail/issue-11740.rs new file mode 100644 index 000000000000..0bda06be9e8c --- /dev/null +++ b/src/test/compile-fail/issue-11740.rs @@ -0,0 +1,38 @@ +// 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. + +#![feature(rustc_attrs)] +#![allow(warnings)] + +struct Attr { + name: String, + value: String, +} + +struct Element { + attrs: Vec>, +} + +impl Element { + pub unsafe fn get_attr<'a>(&'a self, name: &str) { + self.attrs + .iter() + .find(|attr| { + let attr: &&Box = std::mem::transmute(attr); + true + }); + } +} + +#[rustc_error] +fn main() { //~ ERROR compilation successful + let element = Element { attrs: Vec::new() }; + let _ = unsafe { element.get_attr("foo") }; +} diff --git a/src/test/compile-fail/issue-17718-const-borrow.rs b/src/test/compile-fail/issue-17718-const-borrow.rs index ec6d1141c1a0..327b69468229 100644 --- a/src/test/compile-fail/issue-17718-const-borrow.rs +++ b/src/test/compile-fail/issue-17718-const-borrow.rs @@ -14,13 +14,13 @@ use std::cell::UnsafeCell; const A: UnsafeCell = UnsafeCell::new(1); const B: &'static UnsafeCell = &A; -//~^ ERROR: cannot borrow a constant which contains interior mutability +//~^ ERROR: cannot borrow a constant which may contain interior mutability struct C { a: UnsafeCell } const D: C = C { a: UnsafeCell::new(1) }; const E: &'static UnsafeCell = &D.a; -//~^ ERROR: cannot borrow a constant which contains interior mutability +//~^ ERROR: cannot borrow a constant which may contain interior mutability const F: &'static C = &D; -//~^ ERROR: cannot borrow a constant which contains interior mutability +//~^ ERROR: cannot borrow a constant which may contain interior mutability fn main() {} diff --git a/src/test/compile-fail/issue-19601.rs b/src/test/compile-fail/issue-19601.rs new file mode 100644 index 000000000000..02b4932cea8c --- /dev/null +++ b/src/test/compile-fail/issue-19601.rs @@ -0,0 +1,19 @@ +// 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. + +#![feature(rustc_attrs)] +#![allow(warnings)] + +trait A {} +struct B where B: A> { t: T } + +#[rustc_error] +fn main() { //~ ERROR compilation successful +} diff --git a/src/test/compile-fail/issue-22034.rs b/src/test/compile-fail/issue-22034.rs index dfa9520f38bb..5271ea799178 100644 --- a/src/test/compile-fail/issue-22034.rs +++ b/src/test/compile-fail/issue-22034.rs @@ -17,6 +17,5 @@ fn main() { let _: &mut Fn() = unsafe { &mut *(ptr as *mut Fn()) //~^ ERROR `(): std::ops::Fn<()>` is not satisfied - //~| ERROR `(): std::ops::FnOnce<()>` is not satisfied }; } diff --git a/src/test/compile-fail/issue-22603.rs b/src/test/compile-fail/issue-22603.rs new file mode 100644 index 000000000000..d08f916b870c --- /dev/null +++ b/src/test/compile-fail/issue-22603.rs @@ -0,0 +1,23 @@ +// 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. + +#![feature(unboxed_closures, fn_traits, rustc_attrs)] + +struct Foo; + +impl FnOnce<(A,)> for Foo { + type Output = (); + extern "rust-call" fn call_once(self, (_,): (A,)) { + } +} +#[rustc_error] +fn main() { //~ ERROR compilation successful + println!("{:?}", Foo("bar")); +} diff --git a/src/test/compile-fail/issue-22789.rs b/src/test/compile-fail/issue-22789.rs new file mode 100644 index 000000000000..cba1c367bb9b --- /dev/null +++ b/src/test/compile-fail/issue-22789.rs @@ -0,0 +1,17 @@ +// 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. + +#![feature(unboxed_closures, fn_traits, rustc_attrs)] + +#[rustc_error] +fn main() { //~ ERROR compilation successful + let k = |x: i32| { x + 1 }; + Fn::call(&k, (0,)); +} diff --git a/src/test/compile-fail/issue-23966.rs b/src/test/compile-fail/issue-23966.rs index 7f9c7a292f2b..544d3c8af205 100644 --- a/src/test/compile-fail/issue-23966.rs +++ b/src/test/compile-fail/issue-23966.rs @@ -11,5 +11,4 @@ fn main() { "".chars().fold(|_, _| (), ()); //~^ ERROR E0277 - //~| ERROR E0277 } diff --git a/src/test/compile-fail/issue-24363.rs b/src/test/compile-fail/issue-24363.rs index 03cae6e64ef5..619ad74ad00e 100644 --- a/src/test/compile-fail/issue-24363.rs +++ b/src/test/compile-fail/issue-24363.rs @@ -9,7 +9,7 @@ // except according to those terms. fn main() { - 1.create_a_type_error[ //~ no field `create_a_type_error` on type `{integer}` + 1.create_a_type_error[ //~ `{integer}` is a primitive type and therefore doesn't have fields ()+() //~ ERROR binary operation `+` cannot be applied // ^ ensure that we typeck the inner expression ^ ]; diff --git a/src/test/compile-fail/dep-graph-unrelated.rs b/src/test/compile-fail/issue-26614.rs similarity index 57% rename from src/test/compile-fail/dep-graph-unrelated.rs rename to src/test/compile-fail/issue-26614.rs index 079f2b52fd46..c128fb3b4795 100644 --- a/src/test/compile-fail/dep-graph-unrelated.rs +++ b/src/test/compile-fail/issue-26614.rs @@ -1,4 +1,4 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -8,15 +8,20 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Test that two unrelated functions have no trans dependency. - -// compile-flags: -Z query-dep-graph - #![feature(rustc_attrs)] -#![allow(dead_code)] +#![allow(warnings)] -#[rustc_if_this_changed] -fn main() { } +trait Mirror { + type It; +} -#[rustc_then_this_would_need(TransCrateItem)] //~ ERROR no path from `main` -fn bar() { } +impl Mirror for T { + type It = Self; +} + + +#[rustc_error] +fn main() { //~ ERROR compilation successful + let c: ::It = 5; + const CCCC: ::It = 5; +} diff --git a/src/test/compile-fail/issue-27842.rs b/src/test/compile-fail/issue-27842.rs index f7cd4e03c3b1..8c71761df2fb 100644 --- a/src/test/compile-fail/issue-27842.rs +++ b/src/test/compile-fail/issue-27842.rs @@ -12,13 +12,13 @@ fn main() { let tup = (0, 1, 2); // the case where we show a suggestion let _ = tup[0]; - //~^ ERROR cannot index a value of type + //~^ ERROR cannot index into a value of type //~| HELP to access tuple elements, use //~| SUGGESTION let _ = tup.0 // the case where we show just a general hint let i = 0_usize; let _ = tup[i]; - //~^ ERROR cannot index a value of type + //~^ ERROR cannot index into a value of type //~| HELP to access tuple elements, use tuple indexing syntax (e.g. `tuple.0`) } diff --git a/src/test/compile-fail/issue-40861.rs b/src/test/compile-fail/issue-40861.rs index e525b3954f5e..75d58c58538d 100644 --- a/src/test/compile-fail/issue-40861.rs +++ b/src/test/compile-fail/issue-40861.rs @@ -12,5 +12,5 @@ fn f(_: &[f32]) {} fn main() { ()[f(&[1.0])]; - //~^ ERROR cannot index a value of type `()` + //~^ ERROR cannot index into a value of type `()` } diff --git a/src/test/compile-fail/lint-unused-extern-crate.rs b/src/test/compile-fail/lint-unused-extern-crate.rs index 40671353f8ac..010c55afb2b8 100644 --- a/src/test/compile-fail/lint-unused-extern-crate.rs +++ b/src/test/compile-fail/lint-unused-extern-crate.rs @@ -13,13 +13,13 @@ #![deny(unused_extern_crates)] #![allow(unused_variables)] #![allow(deprecated)] +#![feature(alloc)] #![feature(libc)] -#![feature(collections)] #![feature(rand)] extern crate libc; //~ ERROR: unused extern crate -extern crate collections as collecs; // no error, it is used +extern crate alloc as collecs; // no error, it is used extern crate rand; // no error, the use marks it as used // even if imported objects aren't used diff --git a/src/test/compile-fail/parse-error-correct.rs b/src/test/compile-fail/parse-error-correct.rs index 17b58a9f7c29..7dedfcf27275 100644 --- a/src/test/compile-fail/parse-error-correct.rs +++ b/src/test/compile-fail/parse-error-correct.rs @@ -17,5 +17,5 @@ fn main() { let y = 42; let x = y.; //~ ERROR unexpected token let x = y.(); //~ ERROR unexpected token - let x = y.foo; //~ ERROR no field + let x = y.foo; //~ ERROR `{integer}` is a primitive type and therefore doesn't have fields [E061 } diff --git a/src/test/compile-fail/range_traits-1.rs b/src/test/compile-fail/range_traits-1.rs index 852197177585..cf5c40bd1761 100644 --- a/src/test/compile-fail/range_traits-1.rs +++ b/src/test/compile-fail/range_traits-1.rs @@ -17,8 +17,8 @@ use std::ops::*; struct AllTheRanges { a: Range, //~^ ERROR PartialOrd - //~^^ ERROR PartialOrd - //~^^^ ERROR Ord + //~^^ ERROR Ord + //~^^^ ERROR binary operation //~^^^^ ERROR binary operation //~^^^^^ ERROR binary operation //~^^^^^^ ERROR binary operation @@ -26,11 +26,10 @@ struct AllTheRanges { //~^^^^^^^^ ERROR binary operation //~^^^^^^^^^ ERROR binary operation //~^^^^^^^^^^ ERROR binary operation - //~^^^^^^^^^^^ ERROR binary operation b: RangeTo, //~^ ERROR PartialOrd - //~^^ ERROR PartialOrd - //~^^^ ERROR Ord + //~^^ ERROR Ord + //~^^^ ERROR binary operation //~^^^^ ERROR binary operation //~^^^^^ ERROR binary operation //~^^^^^^ ERROR binary operation @@ -38,11 +37,10 @@ struct AllTheRanges { //~^^^^^^^^ ERROR binary operation //~^^^^^^^^^ ERROR binary operation //~^^^^^^^^^^ ERROR binary operation - //~^^^^^^^^^^^ ERROR binary operation c: RangeFrom, //~^ ERROR PartialOrd - //~^^ ERROR PartialOrd - //~^^^ ERROR Ord + //~^^ ERROR Ord + //~^^^ ERROR binary operation //~^^^^ ERROR binary operation //~^^^^^ ERROR binary operation //~^^^^^^ ERROR binary operation @@ -50,11 +48,10 @@ struct AllTheRanges { //~^^^^^^^^ ERROR binary operation //~^^^^^^^^^ ERROR binary operation //~^^^^^^^^^^ ERROR binary operation - //~^^^^^^^^^^^ ERROR binary operation d: RangeFull, //~^ ERROR PartialOrd - //~^^ ERROR PartialOrd - //~^^^ ERROR Ord + //~^^ ERROR Ord + //~^^^ ERROR binary operation //~^^^^ ERROR binary operation //~^^^^^ ERROR binary operation //~^^^^^^ ERROR binary operation @@ -62,11 +59,10 @@ struct AllTheRanges { //~^^^^^^^^ ERROR binary operation //~^^^^^^^^^ ERROR binary operation //~^^^^^^^^^^ ERROR binary operation - //~^^^^^^^^^^^ ERROR binary operation e: RangeInclusive, //~^ ERROR PartialOrd - //~^^ ERROR PartialOrd - //~^^^ ERROR Ord + //~^^ ERROR Ord + //~^^^ ERROR binary operation //~^^^^ ERROR binary operation //~^^^^^ ERROR binary operation //~^^^^^^ ERROR binary operation @@ -74,11 +70,10 @@ struct AllTheRanges { //~^^^^^^^^ ERROR binary operation //~^^^^^^^^^ ERROR binary operation //~^^^^^^^^^^ ERROR binary operation - //~^^^^^^^^^^^ ERROR binary operation f: RangeToInclusive, //~^ ERROR PartialOrd - //~^^ ERROR PartialOrd - //~^^^ ERROR Ord + //~^^ ERROR Ord + //~^^^ ERROR binary operation //~^^^^ ERROR binary operation //~^^^^^ ERROR binary operation //~^^^^^^ ERROR binary operation @@ -86,8 +81,6 @@ struct AllTheRanges { //~^^^^^^^^ ERROR binary operation //~^^^^^^^^^ ERROR binary operation //~^^^^^^^^^^ ERROR binary operation - //~^^^^^^^^^^^ ERROR binary operation } fn main() {} - diff --git a/src/test/compile-fail/resolve_self_super_hint.rs b/src/test/compile-fail/resolve_self_super_hint.rs index 530dc873f750..d49f136f11f3 100644 --- a/src/test/compile-fail/resolve_self_super_hint.rs +++ b/src/test/compile-fail/resolve_self_super_hint.rs @@ -8,25 +8,25 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(collections)] +#![feature(alloc)] mod a { - extern crate collections; - use collections::HashMap; - //~^ ERROR unresolved import `collections::HashMap` [E0432] - //~| Did you mean `self::collections`? + extern crate alloc; + use alloc::HashMap; + //~^ ERROR unresolved import `alloc::HashMap` [E0432] + //~| Did you mean `self::alloc`? mod b { - use collections::HashMap; - //~^ ERROR unresolved import `collections::HashMap` [E0432] - //~| Did you mean `a::collections`? + use alloc::HashMap; + //~^ ERROR unresolved import `alloc::HashMap` [E0432] + //~| Did you mean `a::alloc`? mod c { - use collections::HashMap; - //~^ ERROR unresolved import `collections::HashMap` [E0432] - //~| Did you mean `a::collections`? + use alloc::HashMap; + //~^ ERROR unresolved import `alloc::HashMap` [E0432] + //~| Did you mean `a::alloc`? mod d { - use collections::HashMap; - //~^ ERROR unresolved import `collections::HashMap` [E0432] - //~| Did you mean `a::collections`? + use alloc::HashMap; + //~^ ERROR unresolved import `alloc::HashMap` [E0432] + //~| Did you mean `a::alloc`? } } } diff --git a/src/test/compile-fail/slice-2.rs b/src/test/compile-fail/slice-2.rs index 99dc3e68c8f7..44b9d94c5665 100644 --- a/src/test/compile-fail/slice-2.rs +++ b/src/test/compile-fail/slice-2.rs @@ -14,8 +14,8 @@ struct Foo; fn main() { let x = Foo; - &x[..]; //~ ERROR cannot index a value of type `Foo` - &x[Foo..]; //~ ERROR cannot index a value of type `Foo` - &x[..Foo]; //~ ERROR cannot index a value of type `Foo` - &x[Foo..Foo]; //~ ERROR cannot index a value of type `Foo` + &x[..]; //~ ERROR cannot index into a value of type `Foo` + &x[Foo..]; //~ ERROR cannot index into a value of type `Foo` + &x[..Foo]; //~ ERROR cannot index into a value of type `Foo` + &x[Foo..Foo]; //~ ERROR cannot index into a value of type `Foo` } diff --git a/src/test/compile-fail/str-mut-idx.rs b/src/test/compile-fail/str-mut-idx.rs index 8851e5e07973..219fcdfd7026 100644 --- a/src/test/compile-fail/str-mut-idx.rs +++ b/src/test/compile-fail/str-mut-idx.rs @@ -15,8 +15,7 @@ fn mutate(s: &mut str) { //~^ ERROR `str: std::marker::Sized` is not satisfied //~| ERROR `str: std::marker::Sized` is not satisfied s[1usize] = bot(); - //~^ ERROR `str: std::ops::Index` is not satisfied - //~| ERROR `str: std::ops::IndexMut` is not satisfied + //~^ ERROR `str: std::ops::IndexMut` is not satisfied } pub fn main() {} diff --git a/src/test/compile-fail/struct-field-cfg.rs b/src/test/compile-fail/struct-field-cfg.rs index 9fb130f4d54f..974d500d9cbd 100644 --- a/src/test/compile-fail/struct-field-cfg.rs +++ b/src/test/compile-fail/struct-field-cfg.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(struct_field_attributes)] - struct Foo { present: (), } diff --git a/src/test/compile-fail/unboxed-closures-unsafe-extern-fn.rs b/src/test/compile-fail/unboxed-closures-unsafe-extern-fn.rs index 2b0a8baf4f23..5ba93bf483f2 100644 --- a/src/test/compile-fail/unboxed-closures-unsafe-extern-fn.rs +++ b/src/test/compile-fail/unboxed-closures-unsafe-extern-fn.rs @@ -21,13 +21,11 @@ fn call_it_onceisize>(_: F, _: isize) -> isize { 0 } fn a() { let x = call_it(&square, 22); //~^ ERROR E0277 - //~| ERROR E0277 } fn b() { let y = call_it_mut(&mut square, 22); //~^ ERROR E0277 - //~| ERROR E0277 } fn c() { diff --git a/src/test/compile-fail/unboxed-closures-wrong-abi.rs b/src/test/compile-fail/unboxed-closures-wrong-abi.rs index f6ba25f43685..ff06f7c559b2 100644 --- a/src/test/compile-fail/unboxed-closures-wrong-abi.rs +++ b/src/test/compile-fail/unboxed-closures-wrong-abi.rs @@ -21,13 +21,11 @@ fn call_it_onceisize>(_: F, _: isize) -> isize { 0 } fn a() { let x = call_it(&square, 22); //~^ ERROR E0277 - //~| ERROR E0277 } fn b() { let y = call_it_mut(&mut square, 22); //~^ ERROR E0277 - //~| ERROR E0277 } fn c() { diff --git a/src/test/compile-fail/unboxed-closures-wrong-arg-type-extern-fn.rs b/src/test/compile-fail/unboxed-closures-wrong-arg-type-extern-fn.rs index 9d907ffc17f2..d77750d2a040 100644 --- a/src/test/compile-fail/unboxed-closures-wrong-arg-type-extern-fn.rs +++ b/src/test/compile-fail/unboxed-closures-wrong-arg-type-extern-fn.rs @@ -22,13 +22,11 @@ fn call_it_onceisize>(_: F, _: isize) -> isize { 0 } fn a() { let x = call_it(&square, 22); //~^ ERROR E0277 - //~| ERROR E0277 } fn b() { let y = call_it_mut(&mut square, 22); //~^ ERROR E0277 - //~| ERROR E0277 } fn c() { diff --git a/src/test/compile-fail/unsized6.rs b/src/test/compile-fail/unsized6.rs index 462d760a60ce..dec8699f46e3 100644 --- a/src/test/compile-fail/unsized6.rs +++ b/src/test/compile-fail/unsized6.rs @@ -12,15 +12,15 @@ trait T {} -fn f1(x: &X) { - let _: X; // <-- this is OK, no bindings created, no initializer. +fn f1(x: &X) { + let _: W; // <-- this is OK, no bindings created, no initializer. let _: (isize, (X, isize)); //~ERROR `X: std::marker::Sized` is not satisfie - let y: X; //~ERROR `X: std::marker::Sized` is not satisfied - let y: (isize, (X, usize)); + let y: Y; //~ERROR `Y: std::marker::Sized` is not satisfied + let y: (isize, (Z, usize)); //~ERROR `Z: std::marker::Sized` is not satisfied } -fn f2(x: &X) { +fn f2(x: &X) { let y: X; //~ERROR `X: std::marker::Sized` is not satisfied - let y: (isize, (X, isize)); //~ERROR `X: std::marker::Sized` is not satisfied + let y: (isize, (Y, isize)); //~ERROR `Y: std::marker::Sized` is not satisfied } fn f3(x1: Box, x2: Box, x3: Box) { diff --git a/src/test/compile-fail/use-keyword.rs b/src/test/compile-fail/use-keyword.rs index 6df20d414a78..aff54f18c19a 100644 --- a/src/test/compile-fail/use-keyword.rs +++ b/src/test/compile-fail/use-keyword.rs @@ -13,9 +13,8 @@ mod a { mod b { - use self as A; //~ ERROR `self` imports are only allowed within a { } list - //~^ ERROR unresolved import `self` [E0432] - //~| no `self` in the root + use self as A; + //~^ ERROR `self` imports are only allowed within a { } list use super as B; //~^ ERROR unresolved import `super` [E0432] //~| no `super` in the root diff --git a/src/test/compile-fail/use-mod-4.rs b/src/test/compile-fail/use-mod-4.rs index 146d37f41d63..f102a68c2c5e 100644 --- a/src/test/compile-fail/use-mod-4.rs +++ b/src/test/compile-fail/use-mod-4.rs @@ -11,4 +11,7 @@ use foo::self; //~ ERROR unresolved import `foo::self` //~^ ERROR `self` imports are only allowed within a { } list +use std::mem::self; +//~^ ERROR `self` imports are only allowed within a { } list + fn main() {} diff --git a/src/test/compile-fail/variadic-ffi-3.rs b/src/test/compile-fail/variadic-ffi-3.rs index 565d8549b372..fb102027180f 100644 --- a/src/test/compile-fail/variadic-ffi-3.rs +++ b/src/test/compile-fail/variadic-ffi-3.rs @@ -35,11 +35,11 @@ fn main() { //~| found type `extern "C" fn(isize, u8) {bar}` //~| NOTE: expected variadic fn, found non-variadic function - foo(1, 2, 3f32); //~ ERROR: can't pass an `f32` to variadic function, cast to `c_double` - foo(1, 2, true); //~ ERROR: can't pass `bool` to variadic function, cast to `c_int` - foo(1, 2, 1i8); //~ ERROR: can't pass `i8` to variadic function, cast to `c_int` - foo(1, 2, 1u8); //~ ERROR: can't pass `u8` to variadic function, cast to `c_uint` - foo(1, 2, 1i16); //~ ERROR: can't pass `i16` to variadic function, cast to `c_int` - foo(1, 2, 1u16); //~ ERROR: can't pass `u16` to variadic function, cast to `c_uint` + foo(1, 2, 3f32); //~ ERROR can't pass `f32` to variadic function, cast to `c_double` + foo(1, 2, true); //~ ERROR can't pass `bool` to variadic function, cast to `c_int` + foo(1, 2, 1i8); //~ ERROR can't pass `i8` to variadic function, cast to `c_int` + foo(1, 2, 1u8); //~ ERROR can't pass `u8` to variadic function, cast to `c_uint` + foo(1, 2, 1i16); //~ ERROR can't pass `i16` to variadic function, cast to `c_int` + foo(1, 2, 1u16); //~ ERROR can't pass `u16` to variadic function, cast to `c_uint` } } diff --git a/src/test/compile-fail/variadic-ffi.rs b/src/test/compile-fail/variadic-ffi.rs index 125177efc53c..f245306f4d8f 100644 --- a/src/test/compile-fail/variadic-ffi.rs +++ b/src/test/compile-fail/variadic-ffi.rs @@ -9,6 +9,7 @@ // except according to those terms. // ignore-arm stdcall isn't suppported +// ignore-aarch64 stdcall isn't suppported extern "stdcall" { fn printf(_: *const u8, ...); //~ ERROR: variadic function must have C or cdecl calling diff --git a/src/test/debuginfo/pretty-std.rs b/src/test/debuginfo/pretty-std.rs index 153f0c8271fc..9596f0287bc5 100644 --- a/src/test/debuginfo/pretty-std.rs +++ b/src/test/debuginfo/pretty-std.rs @@ -38,6 +38,12 @@ // gdbg-check:$6 = None // gdbr-check:$6 = core::option::Option::None +// gdb-command: print os_string +// gdb-check:$7 = "IAMA OS string 😃" + +// gdb-command: print some_string +// gdb-check:$8 = Some = {"IAMA optional string!"} + // === LLDB TESTS ================================================================================== @@ -63,6 +69,8 @@ #![allow(unused_variables)] +use std::ffi::OsString; + fn main() { @@ -78,10 +86,15 @@ fn main() { // String let string = "IAMA string!".to_string(); + // OsString + let os_string = OsString::from("IAMA OS string \u{1F603}"); + // Option let some = Some(8i16); let none: Option = None; + let some_string = Some("IAMA optional string!".to_owned()); + zzz(); // #break } diff --git a/src/test/incremental/dirty_clean.rs b/src/test/incremental/dirty_clean.rs index 9f20128de4f5..b828cc9c70ae 100644 --- a/src/test/incremental/dirty_clean.rs +++ b/src/test/incremental/dirty_clean.rs @@ -36,19 +36,15 @@ mod y { use x; #[rustc_clean(label="TypeckTables", cfg="cfail2")] - #[rustc_clean(label="TransCrateItem", cfg="cfail2")] pub fn y() { - //[cfail2]~^ ERROR `TypeckTables("y::y")` not found in dep graph, but should be clean - //[cfail2]~| ERROR `TransCrateItem("y::y")` not found in dep graph, but should be clean + //[cfail2]~^ ERROR `TypeckTables(y::y)` not found in dep graph, but should be clean x::x(); } } mod z { #[rustc_dirty(label="TypeckTables", cfg="cfail2")] - #[rustc_dirty(label="TransCrateItem", cfg="cfail2")] pub fn z() { - //[cfail2]~^ ERROR `TypeckTables("z::z")` found in dep graph, but should be dirty - //[cfail2]~| ERROR `TransCrateItem("z::z")` found in dep graph, but should be dirty + //[cfail2]~^ ERROR `TypeckTables(z::z)` found in dep graph, but should be dirty } } diff --git a/src/test/incremental/issue-42602.rs b/src/test/incremental/issue-42602.rs new file mode 100644 index 000000000000..cb2236d37503 --- /dev/null +++ b/src/test/incremental/issue-42602.rs @@ -0,0 +1,45 @@ +// 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. + +// Regression test for #42602. It used to be that we had +// a dep-graph like +// +// typeck(foo) -> FnOnce -> typeck(bar) +// +// This was fixed by improving the resolution of the `FnOnce` trait +// selection node. + +// revisions:cfail1 +// compile-flags:-Zquery-dep-graph + +#![feature(rustc_attrs)] + +fn main() { + a::foo(); + b::bar(); +} + +mod a { + #[rustc_if_this_changed(HirBody)] + pub fn foo() { + let x = vec![1, 2, 3]; + let v = || ::std::mem::drop(x); + v(); + } +} + +mod b { + #[rustc_then_this_would_need(TypeckTables)] //[cfail1]~ ERROR no path + pub fn bar() { + let x = vec![1, 2, 3]; + let v = || ::std::mem::drop(x); + v(); + } +} diff --git a/src/test/incremental/krate-inlined.rs b/src/test/incremental/krate-inlined.rs index ba32b41983fc..043cb761da09 100644 --- a/src/test/incremental/krate-inlined.rs +++ b/src/test/incremental/krate-inlined.rs @@ -9,20 +9,22 @@ // except according to those terms. // Regr. test that using HIR inlined from another krate does *not* add -// a dependency from the local Krate node. +// a dependency from the local Krate node. We can't easily test that +// directly anymore, so now we test that we get reuse. -// revisions: cfail1 +// revisions: rpass1 rpass2 // compile-flags: -Z query-dep-graph #![allow(warnings)] #![feature(rustc_attrs)] +#![rustc_partition_reused(module="krate_inlined-x", cfg="rpass2")] -#![rustc_if_this_changed(Krate)] - -fn main() { } +fn main() { + #[cfg(rpass2)] + () +} mod x { - #[rustc_then_this_would_need(TransCrateItem)] //[cfail1]~ ERROR no path fn method() { // use some methods that require inlining HIR from another crate: let mut v = vec![]; diff --git a/src/test/incremental/remapped_paths_cc/main.rs b/src/test/incremental/remapped_paths_cc/main.rs index be4764c7d994..701c5fec49b5 100644 --- a/src/test/incremental/remapped_paths_cc/main.rs +++ b/src/test/incremental/remapped_paths_cc/main.rs @@ -25,8 +25,6 @@ extern crate extern_crate; -#[rustc_clean(label="TransCrateItem", cfg="rpass2")] -#[rustc_clean(label="TransCrateItem", cfg="rpass3")] fn main() { some_mod::some_fn(); } @@ -34,8 +32,6 @@ fn main() { mod some_mod { use extern_crate; - #[rustc_clean(label="TransCrateItem", cfg="rpass2")] - #[rustc_dirty(label="TransCrateItem", cfg="rpass3")] pub fn some_fn() { extern_crate::inline_fn(); } diff --git a/src/test/incremental/string_constant.rs b/src/test/incremental/string_constant.rs index 669d001cc63d..36a26cf1755a 100644 --- a/src/test/incremental/string_constant.rs +++ b/src/test/incremental/string_constant.rs @@ -28,7 +28,6 @@ mod x { #[cfg(rpass2)] #[rustc_dirty(label="TypeckTables", cfg="rpass2")] - #[rustc_dirty(label="TransCrateItem", cfg="rpass2")] pub fn x() { println!("{}", "2"); } @@ -38,7 +37,6 @@ mod y { use x; #[rustc_clean(label="TypeckTables", cfg="rpass2")] - #[rustc_clean(label="TransCrateItem", cfg="rpass2")] pub fn y() { x::x(); } @@ -48,7 +46,6 @@ mod z { use y; #[rustc_clean(label="TypeckTables", cfg="rpass2")] - #[rustc_clean(label="TransCrateItem", cfg="rpass2")] pub fn z() { y::y(); } diff --git a/src/test/mir-opt/README.md b/src/test/mir-opt/README.md index 9144e9757f6a..28a124e3c61c 100644 --- a/src/test/mir-opt/README.md +++ b/src/test/mir-opt/README.md @@ -22,7 +22,32 @@ All the test information is in comments so the test is runnable. For each $file_name, compiletest expects [$expected_line_0, ..., $expected_line_N] to appear in the dumped MIR in order. Currently it allows -other non-matched lines before, after and in-between. +other non-matched lines before, after and in-between. Note that this includes +lines that end basic blocks or begin new ones; it is good practice +in your tests to include the terminator for each of your basic blocks as an +internal sanity check guarding against a test like: + +``` +bb0: { + StorageLive(_1); + _1 = const true; + StorageDead(_1); +} +``` + +that will inadvertantly pattern-matching against: + +``` +bb0: { + StorageLive(_1); + _1 = const true; + goto -> bb1 +} +bb1: { + StorageDead(_1); + return; +} +``` Lines match ignoring whitespace, and the prefix "//" is removed. diff --git a/src/test/mir-opt/basic_assignment.rs b/src/test/mir-opt/basic_assignment.rs index e4eb1aeaf9be..ef5158a403a9 100644 --- a/src/test/mir-opt/basic_assignment.rs +++ b/src/test/mir-opt/basic_assignment.rs @@ -50,7 +50,7 @@ fn main() { // StorageLive(_6); // StorageLive(_7); // _7 = _4; -// replace(_6 <- _7) -> [return: bb5, unwind: bb4]; +// replace(_6 <- _7) -> [return: bb6, unwind: bb7]; // } // bb1: { // resume; @@ -59,24 +59,30 @@ fn main() { // drop(_4) -> bb1; // } // bb3: { -// drop(_6) -> bb2; +// goto -> bb2; // } // bb4: { -// drop(_7) -> bb3; +// drop(_6) -> bb3; // } // bb5: { -// drop(_7) -> [return: bb6, unwind: bb3]; +// goto -> bb4; // } // bb6: { -// StorageDead(_7); -// _0 = (); -// drop(_6) -> [return: bb7, unwind: bb2]; +// drop(_7) -> [return: bb8, unwind: bb4]; // } // bb7: { -// StorageDead(_6); -// drop(_4) -> bb8; +// drop(_7) -> bb5; // } // bb8: { +// StorageDead(_7); +// _0 = (); +// drop(_6) -> [return: bb9, unwind: bb2]; +// } +// bb9: { +// StorageDead(_6); +// drop(_4) -> bb10; +// } +// bb10: { // StorageDead(_4); // StorageDead(_2); // StorageDead(_1); diff --git a/src/test/mir-opt/end_region_1.rs b/src/test/mir-opt/end_region_1.rs new file mode 100644 index 000000000000..55dac4440275 --- /dev/null +++ b/src/test/mir-opt/end_region_1.rs @@ -0,0 +1,38 @@ +// 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. + +// compile-flags: -Z identify_regions +// ignore-tidy-linelength + +// This is just about the simplest program that exhibits an EndRegion. + +fn main() { + let a = 3; + let b = &a; +} + +// END RUST SOURCE +// START rustc.node4.SimplifyCfg-qualify-consts.after.mir +// let mut _0: (); +// let _1: i32; +// let _2: &'6_1rce i32; +// +// bb0: { +// StorageLive(_1); +// _1 = const 3i32; +// StorageLive(_2); +// _2 = &'6_1rce _1; +// _0 = (); +// StorageDead(_2); +// EndRegion('6_1rce); +// StorageDead(_1); +// return; +// } +// END rustc.node4.SimplifyCfg-qualify-consts.after.mir diff --git a/src/test/mir-opt/end_region_2.rs b/src/test/mir-opt/end_region_2.rs new file mode 100644 index 000000000000..a1386ec47a13 --- /dev/null +++ b/src/test/mir-opt/end_region_2.rs @@ -0,0 +1,66 @@ +// 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. + +// compile-flags: -Z identify_regions +// ignore-tidy-linelength + +// We will EndRegion for borrows in a loop that occur before break but +// not those after break. + +fn main() { + loop { + let a = true; + let b = &a; + if a { break; } + let c = &a; + } +} + +// END RUST SOURCE +// START rustc.node4.SimplifyCfg-qualify-consts.after.mir +// let mut _0: (); +// let _2: bool; +// let _3: &'7_1rce bool; +// let _7: &'7_3rce bool; +// let mut _4: (); +// let mut _5: bool; +// bb0: { +// goto -> bb1; +// } +// bb1: { +// StorageLive(_2); +// _2 = const true; +// StorageLive(_3); +// _3 = &'7_1rce _2; +// StorageLive(_5); +// _5 = _2; +// switchInt(_5) -> [0u8: bb3, otherwise: bb2]; +// } +// bb2: { +// _0 = (); +// StorageDead(_5); +// StorageDead(_3); +// EndRegion('7_1rce); +// StorageDead(_2); +// return; +// } +// bb3: { +// StorageDead(_5); +// StorageLive(_7); +// _7 = &'7_3rce _2; +// _1 = (); +// StorageDead(_7); +// EndRegion('7_3rce); +// StorageDead(_3); +// EndRegion('7_1rce); +// StorageDead(_2); +// goto -> bb1; +// } +// END rustc.node4.SimplifyCfg-qualify-consts.after.mir diff --git a/src/test/mir-opt/end_region_3.rs b/src/test/mir-opt/end_region_3.rs new file mode 100644 index 000000000000..b3d2809e76ce --- /dev/null +++ b/src/test/mir-opt/end_region_3.rs @@ -0,0 +1,69 @@ +// 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. + +// compile-flags: -Z identify_regions +// ignore-tidy-linelength + +// Binding the borrow's subject outside the loop does not increase the +// scope of the borrow. + +fn main() { + let mut a; + loop { + a = true; + let b = &a; + if a { break; } + let c = &a; + } +} + +// END RUST SOURCE +// START rustc.node4.SimplifyCfg-qualify-consts.after.mir +// let mut _0: (); +// let mut _1: bool; +// let _3: &'9_1rce bool; +// let _7: &'9_3rce bool; +// let mut _2: (); +// let mut _4: (); +// let mut _5: bool; +// +// bb0: { +// StorageLive(_1); +// goto -> bb1; +// } +// bb1: { +// _1 = const true; +// StorageLive(_3); +// _3 = &'9_1rce _1; +// StorageLive(_5); +// _5 = _1; +// switchInt(_5) -> [0u8: bb3, otherwise: bb2]; +// } +// bb2: { +// _0 = (); +// StorageDead(_5); +// StorageDead(_3); +// EndRegion('9_1rce); +// StorageDead(_1); +// return; +// } +// bb3: { +// _4 = (); +// StorageDead(_5); +// StorageLive(_7); +// _7 = &'9_3rce _1; +// _2 = (); +// StorageDead(_7); +// EndRegion('9_3rce); +// StorageDead(_3); +// EndRegion('9_1rce); +// goto -> bb1; +// } +// END rustc.node4.SimplifyCfg-qualify-consts.after.mir diff --git a/src/test/mir-opt/end_region_4.rs b/src/test/mir-opt/end_region_4.rs new file mode 100644 index 000000000000..16ade9f96fd1 --- /dev/null +++ b/src/test/mir-opt/end_region_4.rs @@ -0,0 +1,75 @@ +// 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. + +// compile-flags: -Z identify_regions +// ignore-tidy-linelength + +// Unwinding should EndRegion for in-scope borrows: Direct borrows. + +fn main() { + let d = D(0); + let a = 0; + let b = &a; + foo(*b); + let c = &a; +} + +struct D(i32); +impl Drop for D { fn drop(&mut self) { println!("dropping D({})", self.0); } } + +fn foo(i: i32) { + if i > 0 { panic!("im positive"); } +} + +// END RUST SOURCE +// START rustc.node4.SimplifyCfg-qualify-consts.after.mir +// let mut _0: (); +// let _1: D; +// let _3: i32; +// let _4: &'6_2rce i32; +// let _7: &'6_4rce i32; +// let mut _5: (); +// let mut _6: i32; +// +// bb0: { +// StorageLive(_1); +// _1 = D::{{constructor}}(const 0i32,); +// StorageLive(_3); +// _3 = const 0i32; +// StorageLive(_4); +// _4 = &'6_2rce _3; +// StorageLive(_6); +// _6 = (*_4); +// _5 = const foo(_6) -> [return: bb2, unwind: bb3]; +// } +// bb1: { +// resume; +// } +// bb2: { +// StorageDead(_6); +// StorageLive(_7); +// _7 = &'6_4rce _3; +// _0 = (); +// StorageDead(_7); +// EndRegion('6_4rce); +// StorageDead(_4); +// EndRegion('6_2rce); +// StorageDead(_3); +// drop(_1) -> bb4; +// } +// bb3: { +// EndRegion('6_2rce); +// drop(_1) -> bb1; +// } +// bb4: { +// StorageDead(_1); +// return; +// } +// END rustc.node4.SimplifyCfg-qualify-consts.after.mir diff --git a/src/test/mir-opt/end_region_5.rs b/src/test/mir-opt/end_region_5.rs new file mode 100644 index 000000000000..513632a4cdf3 --- /dev/null +++ b/src/test/mir-opt/end_region_5.rs @@ -0,0 +1,80 @@ +// 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. + +// compile-flags: -Z identify_regions -Z span_free_formats +// ignore-tidy-linelength + +// Unwinding should EndRegion for in-scope borrows: Borrowing via by-ref closure. + +fn main() { + let d = D(0); + foo(|| -> i32 { d.0 }); +} + +struct D(i32); +impl Drop for D { fn drop(&mut self) { println!("dropping D({})", self.0); } } + +fn foo(f: F) where F: FnOnce() -> i32 { + if f() > 0 { panic!("im positive"); } +} + +// END RUST SOURCE +// START rustc.node4.SimplifyCfg-qualify-consts.after.mir +// fn main() -> () { +// let mut _0: (); +// let _1: D; +// let mut _2: (); +// let mut _3: (); +// let mut _4: [closure@NodeId(18) d: &'19mce D]; +// let mut _5: &'19mce D; +// +// bb0: { +// StorageLive(_1); +// _1 = D::{{constructor}}(const 0i32,); +// StorageLive(_4); +// StorageLive(_5); +// _5 = &'19mce _1; +// _4 = [closure@NodeId(18)] { d: _5 }; +// StorageDead(_5); +// _3 = const foo(_4) -> [return: bb2, unwind: bb3]; +// } +// bb1: { +// resume; +// } +// bb2: { +// StorageDead(_4); +// EndRegion('19mce); +// _0 = (); +// drop(_1) -> bb4; +// } +// bb3: { +// EndRegion('19mce); +// drop(_1) -> bb1; +// } +// bb4: { +// StorageDead(_1); +// return; +// } +// } +// END rustc.node4.SimplifyCfg-qualify-consts.after.mir + +// START rustc.node18.SimplifyCfg-qualify-consts.after.mir +// fn main::{{closure}}(_1: [closure@NodeId(18) d:&'19mce D]) -> i32 { +// let mut _0: i32; +// let mut _2: i32; +// +// bb0: { +// StorageLive(_2); +// _2 = ((*(_1.0: &'19mce D)).0: i32); +// _0 = _2; +// StorageDead(_2); +// return; +// } +// END rustc.node18.SimplifyCfg-qualify-consts.after.mir diff --git a/src/test/mir-opt/end_region_6.rs b/src/test/mir-opt/end_region_6.rs new file mode 100644 index 000000000000..e82556f3ce4b --- /dev/null +++ b/src/test/mir-opt/end_region_6.rs @@ -0,0 +1,83 @@ +// 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. + +// compile-flags: -Z identify_regions -Z span_free_formats +// ignore-tidy-linelength + +// Unwinding should EndRegion for in-scope borrows: 2nd borrow within by-ref closure. + +fn main() { + let d = D(0); + foo(|| -> i32 { let r = &d; r.0 }); +} + +struct D(i32); +impl Drop for D { fn drop(&mut self) { println!("dropping D({})", self.0); } } + +fn foo(f: F) where F: FnOnce() -> i32 { + if f() > 0 { panic!("im positive"); } +} + +// END RUST SOURCE +// START rustc.node4.SimplifyCfg-qualify-consts.after.mir +// let mut _0: (); +// let _1: D; +// let mut _2: (); +// let mut _3: (); +// let mut _4: [closure@NodeId(22) d:&'23mce D]; +// let mut _5: &'23mce D; +// +// bb0: { +// StorageLive(_1); +// _1 = D::{{constructor}}(const 0i32,); +// StorageLive(_4); +// StorageLive(_5); +// _5 = &'23mce _1; +// _4 = [closure@NodeId(22)] { d: _5 }; +// StorageDead(_5); +// _3 = const foo(_4) -> [return: bb2, unwind: bb3]; +// } +// bb1: { +// resume; +// } +// bb2: { +// StorageDead(_4); +// EndRegion('23mce); +// _0 = (); +// drop(_1) -> bb4; +// } +// bb3: { +// EndRegion('23mce); +// drop(_1) -> bb1; +// } +// bb4: { +// StorageDead(_1); +// return; +// } +// END rustc.node4.SimplifyCfg-qualify-consts.after.mir + +// START rustc.node22.SimplifyCfg-qualify-consts.after.mir +// fn main::{{closure}}(_1: [closure@NodeId(22) d:&'23mce D]) -> i32 { +// let mut _0: i32; +// let _2: &'14_0rce D; +// let mut _3: i32; +// +// bb0: { +// StorageLive(_2); +// _2 = &'14_0rce (*(_1.0: &'23mce D)); +// StorageLive(_3); +// _3 = ((*_2).0: i32); +// _0 = _3; +// StorageDead(_3); +// StorageDead(_2); +// EndRegion('14_0rce); +// return; +// } +// END rustc.node22.SimplifyCfg-qualify-consts.after.mir diff --git a/src/test/mir-opt/end_region_7.rs b/src/test/mir-opt/end_region_7.rs new file mode 100644 index 000000000000..3fbd3f368659 --- /dev/null +++ b/src/test/mir-opt/end_region_7.rs @@ -0,0 +1,97 @@ +// 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. + +// compile-flags: -Z identify_regions -Z span_free_formats +// ignore-tidy-linelength + +// Unwinding should EndRegion for in-scope borrows: Borrow of moved data. + +fn main() { + let d = D(0); + foo(move || -> i32 { let r = &d; r.0 }); +} + +struct D(i32); +impl Drop for D { fn drop(&mut self) { println!("dropping D({})", self.0); } } + +fn foo(f: F) where F: FnOnce() -> i32 { + if f() > 0 { panic!("im positive"); } +} + +// END RUST SOURCE +// START rustc.node4.SimplifyCfg-qualify-consts.after.mir +// fn main() -> () { +// let mut _0: (); +// let _1: D; +// let mut _2: (); +// let mut _3: (); +// let mut _4: [closure@NodeId(22) d:D]; +// let mut _5: D; +// +// bb0: { +// StorageLive(_1); +// _1 = D::{{constructor}}(const 0i32,); +// StorageLive(_4); +// StorageLive(_5); +// _5 = _1; +// _4 = [closure@NodeId(22)] { d: _5 }; +// drop(_5) -> [return: bb4, unwind: bb3]; +// } +// bb1: { +// resume; +// } +// bb2: { +// drop(_1) -> bb1; +// } +// bb3: { +// drop(_4) -> bb2; +// } +// bb4: { +// StorageDead(_5); +// _3 = const foo(_4) -> [return: bb5, unwind: bb3]; +// } +// bb5: { +// drop(_4) -> [return: bb6, unwind: bb2]; +// } +// bb6: { +// StorageDead(_4); +// _0 = (); +// drop(_1) -> bb7; +// } +// bb7: { +// StorageDead(_1); +// return; +// } +// } +// END rustc.node4.SimplifyCfg-qualify-consts.after.mir + +// START rustc.node22.SimplifyCfg-qualify-consts.after.mir +// fn main::{{closure}}(_1: [closure@NodeId(22) d:D]) -> i32 { +// let mut _0: i32; +// let _2: &'14_0rce D; +// let mut _3: (); +// let mut _4: i32; +// +// bb0: { +// StorageLive(_2); +// _2 = &'14_0rce (_1.0: D); +// StorageLive(_4); +// _4 = ((*_2).0: i32); +// _0 = _4; +// StorageDead(_4); +// StorageDead(_2); +// EndRegion('14_0rce); +// drop(_1) -> bb1; +// } +// bb1: { +// return; +// } +// } +// END rustc.node22.SimplifyCfg-qualify-consts.after.mir diff --git a/src/test/mir-opt/end_region_8.rs b/src/test/mir-opt/end_region_8.rs new file mode 100644 index 000000000000..7fb3f0b91181 --- /dev/null +++ b/src/test/mir-opt/end_region_8.rs @@ -0,0 +1,86 @@ +// 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. + +// compile-flags: -Z identify_regions -Z span_free_formats +// ignore-tidy-linelength + +// Unwinding should EndRegion for in-scope borrows: Move of borrow into closure. + +fn main() { + let d = D(0); + let r = &d; + foo(move || -> i32 { r.0 }); +} + +struct D(i32); +impl Drop for D { fn drop(&mut self) { println!("dropping D({})", self.0); } } + +fn foo(f: F) where F: FnOnce() -> i32 { + if f() > 0 { panic!("im positive"); } +} + +// END RUST SOURCE +// START rustc.node4.SimplifyCfg-qualify-consts.after.mir +// fn main() -> () { +// let mut _0: (); +// let _1: D; +// let _3: &'6_1rce D; +// let mut _2: (); +// let mut _4: (); +// let mut _5: [closure@NodeId(22) r:&'6_1rce D]; +// let mut _6: &'6_1rce D; +// +// bb0: { +// StorageLive(_1); +// _1 = D::{{constructor}}(const 0i32,); +// StorageLive(_3); +// _3 = &'6_1rce _1; +// StorageLive(_5); +// StorageLive(_6); +// _6 = _3; +// _5 = [closure@NodeId(22)] { r: _6 }; +// StorageDead(_6); +// _4 = const foo(_5) -> [return: bb2, unwind: bb3]; +// } +// bb1: { +// resume; +// } +// bb2: { +// StorageDead(_5); +// _0 = (); +// StorageDead(_3); +// EndRegion('6_1rce); +// drop(_1) -> bb4; +// } +// bb3: { +// EndRegion('6_1rce); +// drop(_1) -> bb1; +// } +// bb4: { +// StorageDead(_1); +// return; +// } +// } +// END rustc.node4.SimplifyCfg-qualify-consts.after.mir + +// START rustc.node22.SimplifyCfg-qualify-consts.after.mir +// fn main::{{closure}}(_1: [closure@NodeId(22) r:&'6_1rce D]) -> i32 { +// let mut _0: i32; +// let mut _2: i32; +// +// bb0: { +// StorageLive(_2); +// _2 = ((*(_1.0: &'6_1rce D)).0: i32); +// _0 = _2; +// StorageDead(_2); +// return; +// } +// } +// END rustc.node22.SimplifyCfg-qualify-consts.after.mir diff --git a/src/test/mir-opt/end_region_9.rs b/src/test/mir-opt/end_region_9.rs new file mode 100644 index 000000000000..deff984e4d0d --- /dev/null +++ b/src/test/mir-opt/end_region_9.rs @@ -0,0 +1,85 @@ +// 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. + +// compile-flags: -Z identify_regions -Z span_free_formats +// ignore-tidy-linelength + +// This test models a scenario that arielb1 found during review. +// Namely, any filtering of EndRegions must ensure to continue to emit +// any necessary EndRegions that occur earlier in the source than the +// first borrow involving that region. +// +// It is tricky to actually construct examples of this, which is the +// main reason that I am keeping this test even though I have now +// removed the pre-filter that motivated the test in the first place. + +fn main() { + let mut second_iter = false; + let x = 3; + 'a: loop { + let mut y; + loop { + if second_iter { + break 'a; // want to generate `EndRegion('a)` here + } else { + y = &/*'a*/ x; + } + second_iter = true; + } + } +} + +// END RUST SOURCE +// START rustc.node4.SimplifyCfg-qualify-consts.after.mir +// fn main() -> () { +// let mut _0: (); +// let mut _1: bool; +// let _2: i32; +// let mut _4: &'13_0rce i32; +// let mut _3: (); +// let mut _5: !; +// let mut _6: (); +// let mut _7: bool; +// let mut _8: !; +// +// bb0: { +// StorageLive(_1); +// _1 = const false; +// StorageLive(_2); +// _2 = const 3i32; +// StorageLive(_4); +// goto -> bb1; +// } +// +// bb1: { +// StorageLive(_7); +// _7 = _1; +// switchInt(_7) -> [0u8: bb3, otherwise: bb2]; +// } +// +// bb2: { +// _0 = (); +// StorageDead(_7); +// StorageDead(_4); +// EndRegion('13_0rce); +// StorageDead(_2); +// StorageDead(_1); +// return; +// } +// +// bb3: { +// _4 = &'13_0rce _2; +// _6 = (); +// StorageDead(_7); +// _1 = const true; +// _3 = (); +// goto -> bb1; +// } +// } diff --git a/src/test/run-make/profile/Makefile b/src/test/run-make/profile/Makefile new file mode 100644 index 000000000000..7300bfc95536 --- /dev/null +++ b/src/test/run-make/profile/Makefile @@ -0,0 +1,9 @@ +-include ../tools.mk + +all: +ifeq ($(PROFILER_SUPPORT),1) + $(RUSTC) -g -Z profile test.rs + $(call RUN,test) || exit 1 + [ -e "$(TMPDIR)/test.gcno" ] || (echo "No .gcno file"; exit 1) + [ -e "$(TMPDIR)/test.gcda" ] || (echo "No .gcda file"; exit 1) +endif diff --git a/src/test/run-make/profile/test.rs b/src/test/run-make/profile/test.rs new file mode 100644 index 000000000000..046d27a9f0fe --- /dev/null +++ b/src/test/run-make/profile/test.rs @@ -0,0 +1,11 @@ +// 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. + +fn main() {} diff --git a/src/test/run-make/rustdoc-output-path/Makefile b/src/test/run-make/rustdoc-output-path/Makefile new file mode 100644 index 000000000000..4e570718a62f --- /dev/null +++ b/src/test/run-make/rustdoc-output-path/Makefile @@ -0,0 +1,4 @@ +-include ../tools.mk + +all: + $(HOST_RPATH_ENV) '$(RUSTDOC)' -o "$(TMPDIR)/foo/bar/doc" foo.rs diff --git a/src/test/run-make/rustdoc-output-path/foo.rs b/src/test/run-make/rustdoc-output-path/foo.rs new file mode 100644 index 000000000000..11fc2cd2b8d1 --- /dev/null +++ b/src/test/run-make/rustdoc-output-path/foo.rs @@ -0,0 +1,11 @@ +// 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. + +pub struct Foo; diff --git a/src/test/run-make/save-analysis/Makefile b/src/test/run-make/save-analysis/Makefile index 3711b6ea8959..9ebc40d4013c 100644 --- a/src/test/run-make/save-analysis/Makefile +++ b/src/test/run-make/save-analysis/Makefile @@ -3,6 +3,5 @@ all: code krate2: krate2.rs $(RUSTC) $< code: foo.rs krate2 - $(RUSTC) foo.rs -Zsave-analysis-csv $(RUSTC) foo.rs -Zsave-analysis $(RUSTC) foo.rs -Zsave-analysis-api diff --git a/src/test/run-pass-fulldeps/auxiliary/procedural_mbe_matching.rs b/src/test/run-pass-fulldeps/auxiliary/procedural_mbe_matching.rs index c9fa96b83c28..b5d6ff595afd 100644 --- a/src/test/run-pass-fulldeps/auxiliary/procedural_mbe_matching.rs +++ b/src/test/run-pass-fulldeps/auxiliary/procedural_mbe_matching.rs @@ -54,7 +54,7 @@ fn expand_mbe_matches(cx: &mut ExtCtxt, _: Span, args: &[TokenTree]) let mac_expr = match (&*matched_nt, &*map[&Ident::from_str("pat")]) { (&NtExpr(ref matched_expr), &MatchedSeq(ref pats, seq_sp)) => { let pats: Vec> = pats.iter().map(|pat_nt| { - match **pat_nt { + match *pat_nt { MatchedNonterminal(ref nt) => match **nt { NtPat(ref pat) => pat.clone(), _ => unreachable!(), diff --git a/src/test/run-pass-fulldeps/issue-2804.rs b/src/test/run-pass-fulldeps/issue-2804.rs index a2b4e218a079..f999d2d0ed99 100644 --- a/src/test/run-pass-fulldeps/issue-2804.rs +++ b/src/test/run-pass-fulldeps/issue-2804.rs @@ -8,10 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(collections)] #![feature(rustc_private)] -extern crate collections; extern crate serialize; use std::collections::HashMap; diff --git a/src/test/run-pass-fulldeps/regions-mock-tcx.rs b/src/test/run-pass-fulldeps/regions-mock-tcx.rs index ed3cec465eff..670f5380d81f 100644 --- a/src/test/run-pass-fulldeps/regions-mock-tcx.rs +++ b/src/test/run-pass-fulldeps/regions-mock-tcx.rs @@ -15,10 +15,9 @@ // - Multiple lifetime parameters // - Arenas -#![feature(rustc_private, libc, collections)] +#![feature(rustc_private, libc)] extern crate arena; -extern crate collections; extern crate libc; use TypeStructure::{TypeInt, TypeFunction}; diff --git a/src/test/run-pass/asm-concat-src.rs b/src/test/run-pass/asm-concat-src.rs index ea3d0c3aa0ee..fb257bf7b500 100644 --- a/src/test/run-pass/asm-concat-src.rs +++ b/src/test/run-pass/asm-concat-src.rs @@ -9,7 +9,7 @@ // except according to those terms. // pretty-expanded FIXME #23616 -// ignore-asmjs +// ignore-emscripten #![feature(asm)] diff --git a/src/test/run-pass/closure-to-fn-coercion.rs b/src/test/run-pass/closure-to-fn-coercion.rs index 7fb26bdc9360..343209143cc2 100644 --- a/src/test/run-pass/closure-to-fn-coercion.rs +++ b/src/test/run-pass/closure-to-fn-coercion.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use std::mem; + const FOO: fn(u8) -> u8 = |v: u8| { v }; const BAR: [fn(&mut u32); 5] = [ @@ -21,6 +23,10 @@ fn func_specific() -> (fn() -> u32) { || return 42 } +fn generic(_: T) -> fn() -> usize { + || mem::size_of::() +} + fn main() { // Items assert_eq!(func_specific()(), 42); @@ -34,4 +40,5 @@ fn main() { assert_eq!({ BAR[2](&mut a); a }, 3); assert_eq!({ BAR[3](&mut a); a }, 6); assert_eq!({ BAR[4](&mut a); a }, 10); + assert_eq!(generic(0i8)(), 1); } diff --git a/src/test/run-pass/conditional-compile-arch.rs b/src/test/run-pass/conditional-compile-arch.rs index 24c461d5f511..6e3e4be0d8e8 100644 --- a/src/test/run-pass/conditional-compile-arch.rs +++ b/src/test/run-pass/conditional-compile-arch.rs @@ -36,3 +36,6 @@ pub fn main() { } #[cfg(target_arch = "asmjs")] pub fn main() { } + +#[cfg(target_arch = "wasm32")] +pub fn main() { } diff --git a/src/test/run-pass/drop-with-type-ascription-2.rs b/src/test/run-pass/drop-with-type-ascription-2.rs index 53005ea5291f..1f486c1834c0 100644 --- a/src/test/run-pass/drop-with-type-ascription-2.rs +++ b/src/test/run-pass/drop-with-type-ascription-2.rs @@ -9,8 +9,6 @@ // except according to those terms. -#![feature(collections)] - fn main() { let args = vec!["foobie", "asdf::asdf"]; let arr: Vec<&str> = args[1].split("::").collect(); diff --git a/src/test/run-pass/for-loop-no-std.rs b/src/test/run-pass/for-loop-no-std.rs index 73de1fa9c0de..856857156c94 100644 --- a/src/test/run-pass/for-loop-no-std.rs +++ b/src/test/run-pass/for-loop-no-std.rs @@ -8,12 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(lang_items, start, collections)] +#![feature(lang_items, start, alloc)] #![no_std] extern crate std as other; -#[macro_use] extern crate collections; +#[macro_use] extern crate alloc; #[start] fn start(_argc: isize, _argv: *const *const u8) -> isize { diff --git a/src/test/run-pass/foreach-external-iterators-hashmap-break-restart.rs b/src/test/run-pass/foreach-external-iterators-hashmap-break-restart.rs index cedb96014314..232af7eca419 100644 --- a/src/test/run-pass/foreach-external-iterators-hashmap-break-restart.rs +++ b/src/test/run-pass/foreach-external-iterators-hashmap-break-restart.rs @@ -9,10 +9,6 @@ // except according to those terms. -#![feature(collections)] - -extern crate collections; - use std::collections::HashMap; // This is a fancy one: it uses an external iterator established diff --git a/src/test/run-pass/foreach-external-iterators-hashmap.rs b/src/test/run-pass/foreach-external-iterators-hashmap.rs index 79304fce5c16..2ef420187ded 100644 --- a/src/test/run-pass/foreach-external-iterators-hashmap.rs +++ b/src/test/run-pass/foreach-external-iterators-hashmap.rs @@ -9,10 +9,6 @@ // except according to those terms. -#![feature(collections)] - -extern crate collections; - use std::collections::HashMap; pub fn main() { diff --git a/src/test/run-pass/format-no-std.rs b/src/test/run-pass/format-no-std.rs index 1b9b4ab32ca4..9e8a32185188 100644 --- a/src/test/run-pass/format-no-std.rs +++ b/src/test/run-pass/format-no-std.rs @@ -10,14 +10,14 @@ // ignore-emscripten missing rust_begin_unwind -#![feature(lang_items, start, collections)] +#![feature(lang_items, start, alloc)] #![no_std] extern crate std as other; -#[macro_use] extern crate collections; +#[macro_use] extern crate alloc; -use collections::string::ToString; +use alloc::string::ToString; #[start] fn start(_argc: isize, _argv: *const *const u8) -> isize { diff --git a/src/test/run-pass/intrinsics-integer.rs b/src/test/run-pass/intrinsics-integer.rs index 759dc515456d..4896f02da20b 100644 --- a/src/test/run-pass/intrinsics-integer.rs +++ b/src/test/run-pass/intrinsics-integer.rs @@ -14,7 +14,9 @@ mod rusti { extern "rust-intrinsic" { pub fn ctpop(x: T) -> T; pub fn ctlz(x: T) -> T; + pub fn ctlz_nonzero(x: T) -> T; pub fn cttz(x: T) -> T; + pub fn cttz_nonzero(x: T) -> T; pub fn bswap(x: T) -> T; } } @@ -68,6 +70,21 @@ pub fn main() { assert_eq!(ctlz(100u32), 25); assert_eq!(ctlz(100i32), 25); assert_eq!(ctlz(100u64), 57); assert_eq!(ctlz(100i64), 57); + assert_eq!(ctlz_nonzero(1u8), 7); assert_eq!(ctlz_nonzero(1i8), 7); + assert_eq!(ctlz_nonzero(1u16), 15); assert_eq!(ctlz_nonzero(1i16), 15); + assert_eq!(ctlz_nonzero(1u32), 31); assert_eq!(ctlz_nonzero(1i32), 31); + assert_eq!(ctlz_nonzero(1u64), 63); assert_eq!(ctlz_nonzero(1i64), 63); + + assert_eq!(ctlz_nonzero(10u8), 4); assert_eq!(ctlz_nonzero(10i8), 4); + assert_eq!(ctlz_nonzero(10u16), 12); assert_eq!(ctlz_nonzero(10i16), 12); + assert_eq!(ctlz_nonzero(10u32), 28); assert_eq!(ctlz_nonzero(10i32), 28); + assert_eq!(ctlz_nonzero(10u64), 60); assert_eq!(ctlz_nonzero(10i64), 60); + + assert_eq!(ctlz_nonzero(100u8), 1); assert_eq!(ctlz_nonzero(100i8), 1); + assert_eq!(ctlz_nonzero(100u16), 9); assert_eq!(ctlz_nonzero(100i16), 9); + assert_eq!(ctlz_nonzero(100u32), 25); assert_eq!(ctlz_nonzero(100i32), 25); + assert_eq!(ctlz_nonzero(100u64), 57); assert_eq!(ctlz_nonzero(100i64), 57); + assert_eq!(cttz(-1i8 as u8), 0); assert_eq!(cttz(-1i8), 0); assert_eq!(cttz(-1i16 as u16), 0); assert_eq!(cttz(-1i16), 0); assert_eq!(cttz(-1i32 as u32), 0); assert_eq!(cttz(-1i32), 0); @@ -93,6 +110,26 @@ pub fn main() { assert_eq!(cttz(100u32), 2); assert_eq!(cttz(100i32), 2); assert_eq!(cttz(100u64), 2); assert_eq!(cttz(100i64), 2); + assert_eq!(cttz_nonzero(-1i8 as u8), 0); assert_eq!(cttz_nonzero(-1i8), 0); + assert_eq!(cttz_nonzero(-1i16 as u16), 0); assert_eq!(cttz_nonzero(-1i16), 0); + assert_eq!(cttz_nonzero(-1i32 as u32), 0); assert_eq!(cttz_nonzero(-1i32), 0); + assert_eq!(cttz_nonzero(-1i64 as u64), 0); assert_eq!(cttz_nonzero(-1i64), 0); + + assert_eq!(cttz_nonzero(1u8), 0); assert_eq!(cttz_nonzero(1i8), 0); + assert_eq!(cttz_nonzero(1u16), 0); assert_eq!(cttz_nonzero(1i16), 0); + assert_eq!(cttz_nonzero(1u32), 0); assert_eq!(cttz_nonzero(1i32), 0); + assert_eq!(cttz_nonzero(1u64), 0); assert_eq!(cttz_nonzero(1i64), 0); + + assert_eq!(cttz_nonzero(10u8), 1); assert_eq!(cttz_nonzero(10i8), 1); + assert_eq!(cttz_nonzero(10u16), 1); assert_eq!(cttz_nonzero(10i16), 1); + assert_eq!(cttz_nonzero(10u32), 1); assert_eq!(cttz_nonzero(10i32), 1); + assert_eq!(cttz_nonzero(10u64), 1); assert_eq!(cttz_nonzero(10i64), 1); + + assert_eq!(cttz_nonzero(100u8), 2); assert_eq!(cttz_nonzero(100i8), 2); + assert_eq!(cttz_nonzero(100u16), 2); assert_eq!(cttz_nonzero(100i16), 2); + assert_eq!(cttz_nonzero(100u32), 2); assert_eq!(cttz_nonzero(100i32), 2); + assert_eq!(cttz_nonzero(100u64), 2); assert_eq!(cttz_nonzero(100i64), 2); + assert_eq!(bswap(0x0Au8), 0x0A); // no-op assert_eq!(bswap(0x0Ai8), 0x0A); // no-op assert_eq!(bswap(0x0A0Bu16), 0x0B0A); diff --git a/src/test/run-pass/issue-12860.rs b/src/test/run-pass/issue-12860.rs index 5c9ee74472b1..58ce390cac69 100644 --- a/src/test/run-pass/issue-12860.rs +++ b/src/test/run-pass/issue-12860.rs @@ -8,10 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(collections)] - -extern crate collections; - use std::collections::HashSet; #[derive(Copy, Clone, PartialEq, Eq, Hash)] diff --git a/src/test/run-pass/issue-1696.rs b/src/test/run-pass/issue-1696.rs index 4c6c200c7164..b06285b06a5e 100644 --- a/src/test/run-pass/issue-1696.rs +++ b/src/test/run-pass/issue-1696.rs @@ -8,10 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(collections)] - -extern crate collections; - use std::collections::HashMap; pub fn main() { diff --git a/src/test/run-pass/issue-19811-escape-unicode.rs b/src/test/run-pass/issue-19811-escape-unicode.rs index cff431065ffe..b447ffd69b4c 100644 --- a/src/test/run-pass/issue-19811-escape-unicode.rs +++ b/src/test/run-pass/issue-19811-escape-unicode.rs @@ -9,8 +9,6 @@ // except according to those terms. -#![feature(collections)] - fn main() { let mut escaped = String::from(""); for c in '\u{10401}'.escape_unicode() { diff --git a/src/test/run-pass/issue-2383.rs b/src/test/run-pass/issue-2383.rs index 9c400aac1dcf..a497a9fda6a6 100644 --- a/src/test/run-pass/issue-2383.rs +++ b/src/test/run-pass/issue-2383.rs @@ -10,9 +10,6 @@ // pretty-expanded FIXME #23616 -#![feature(collections)] - -extern crate collections; use std::collections::VecDeque; pub fn main() { diff --git a/src/test/run-pass/issue-27859.rs b/src/test/run-pass/issue-27859.rs index 900614be612f..56036caca15b 100644 --- a/src/test/run-pass/issue-27859.rs +++ b/src/test/run-pass/issue-27859.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-wasm32 issue 42629 + #[inline(never)] fn foo(a: f32, b: f32) -> f32 { a % b diff --git a/src/test/run-pass/issue-2804-2.rs b/src/test/run-pass/issue-2804-2.rs index 6afb31619d1c..e428ecd4e5bb 100644 --- a/src/test/run-pass/issue-2804-2.rs +++ b/src/test/run-pass/issue-2804-2.rs @@ -11,10 +11,6 @@ // Minimized version of issue-2804.rs. Both check that callee IDs don't // clobber the previous node ID in a macro expr -#![feature(collections)] - -extern crate collections; - use std::collections::HashMap; fn add_interfaces(managed_ip: String, device: HashMap) { diff --git a/src/test/run-pass/issue-3026.rs b/src/test/run-pass/issue-3026.rs index d8499992f94d..7c0dc8a00489 100644 --- a/src/test/run-pass/issue-3026.rs +++ b/src/test/run-pass/issue-3026.rs @@ -10,10 +10,7 @@ // pretty-expanded FIXME #23616 -#![allow(unknown_features)] -#![feature(box_syntax, collections)] - -extern crate collections; +#![feature(box_syntax)] use std::collections::HashMap; diff --git a/src/test/run-pass/issue-3559.rs b/src/test/run-pass/issue-3559.rs index c2ea24ac6ba9..64f053d9a8c6 100644 --- a/src/test/run-pass/issue-3559.rs +++ b/src/test/run-pass/issue-3559.rs @@ -8,10 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(collections)] - -extern crate collections; - use std::collections::HashMap; fn check_strs(actual: &str, expected: &str) -> bool { diff --git a/src/test/run-pass/issue-42552.rs b/src/test/run-pass/issue-42552.rs new file mode 100644 index 000000000000..fd1265b7174f --- /dev/null +++ b/src/test/run-pass/issue-42552.rs @@ -0,0 +1,40 @@ +// 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. + +// Regression test for an obscure issue with the projection cache. + +fn into_iter(a: &I) -> Groups { + Groups { _a: a } +} + +pub struct Groups<'a, I: 'a> { + _a: &'a I, +} + +impl<'a, I: Iterator> Iterator for Groups<'a, I> { + type Item = Group<'a, I>; + fn next(&mut self) -> Option { + None + } +} + +pub struct Group<'a, I: Iterator + 'a> + where I::Item: 'a // <-- needed to trigger ICE! +{ + _phantom: &'a (), + _ice_trigger: I::Item, // <-- needed to trigger ICE! +} + + +fn main() { + let _ = into_iter(&[0].iter().map(|_| 0)).map(|grp| { + let _g = grp; + }); +} diff --git a/src/test/run-pass/issue-42679.rs b/src/test/run-pass/issue-42679.rs new file mode 100644 index 000000000000..312835225edf --- /dev/null +++ b/src/test/run-pass/issue-42679.rs @@ -0,0 +1,31 @@ +// 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. + +#![feature(box_syntax)] +#![feature(box_patterns)] + +#[derive(Debug, PartialEq)] +enum Test { + Foo(usize), + Bar(isize), +} + +fn main() { + let a = box Test::Foo(10); + let b = box Test::Bar(-20); + match (a, b) { + (_, box Test::Foo(_)) => unreachable!(), + (box Test::Foo(x), b) => { + assert_eq!(x, 10); + assert_eq!(b, box Test::Bar(-20)); + }, + _ => unreachable!(), + } +} diff --git a/src/test/run-pass/issue-6128.rs b/src/test/run-pass/issue-6128.rs index 5fb24fe3ef1a..8725b1378965 100644 --- a/src/test/run-pass/issue-6128.rs +++ b/src/test/run-pass/issue-6128.rs @@ -9,10 +9,7 @@ // except according to those terms. -#![allow(unknown_features)] -#![feature(box_syntax, collections)] - -extern crate collections; +#![feature(box_syntax)] use std::collections::HashMap; diff --git a/src/test/run-pass/issue-7660.rs b/src/test/run-pass/issue-7660.rs index b0ebc6c9cc82..3f3e11a2ddb0 100644 --- a/src/test/run-pass/issue-7660.rs +++ b/src/test/run-pass/issue-7660.rs @@ -13,10 +13,6 @@ // pretty-expanded FIXME #23616 -#![feature(collections)] - -extern crate collections; - use std::collections::HashMap; struct A(isize, isize); diff --git a/src/test/run-pass/istr.rs b/src/test/run-pass/istr.rs index 3197d7f0160a..7ebeb79f5666 100644 --- a/src/test/run-pass/istr.rs +++ b/src/test/run-pass/istr.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(collections)] - use std::string::String; fn test_stack_assign() { diff --git a/src/test/run-pass/new-unicode-escapes.rs b/src/test/run-pass/new-unicode-escapes.rs index 83c2dadcd2f7..2c0417576052 100644 --- a/src/test/run-pass/new-unicode-escapes.rs +++ b/src/test/run-pass/new-unicode-escapes.rs @@ -9,8 +9,6 @@ // except according to those terms. -#![feature(collections)] - pub fn main() { let s = "\u{2603}"; assert_eq!(s, "☃"); diff --git a/src/test/run-pass/option-ext.rs b/src/test/run-pass/option-ext.rs index 03ba6097cd92..c054171ff008 100644 --- a/src/test/run-pass/option-ext.rs +++ b/src/test/run-pass/option-ext.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(collections)] - pub fn main() { let thing = "{{ f }}"; let f = thing.find("{{"); diff --git a/src/test/run-pass/out-of-stack.rs b/src/test/run-pass/out-of-stack.rs index a7748b6d6a2a..7e70c4a7ab38 100644 --- a/src/test/run-pass/out-of-stack.rs +++ b/src/test/run-pass/out-of-stack.rs @@ -10,7 +10,7 @@ // ignore-android: FIXME (#20004) // ignore-musl -// ignore-asmjs +// ignore-emscripten #![feature(asm)] #![feature(libc)] diff --git a/src/test/run-pass/overloaded-autoderef.rs b/src/test/run-pass/overloaded-autoderef.rs index 97da5fc8c09e..d9ffbe51aa59 100644 --- a/src/test/run-pass/overloaded-autoderef.rs +++ b/src/test/run-pass/overloaded-autoderef.rs @@ -9,7 +9,7 @@ // except according to those terms. #![allow(unknown_features)] -#![feature(box_syntax, collections, core)] +#![feature(box_syntax, core)] use std::cell::RefCell; use std::rc::Rc; diff --git a/src/test/run-pass/overloaded-deref.rs b/src/test/run-pass/overloaded-deref.rs index e2ca880719a8..9cdf45b485c1 100644 --- a/src/test/run-pass/overloaded-deref.rs +++ b/src/test/run-pass/overloaded-deref.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(collections)] - use std::cell::RefCell; use std::rc::Rc; use std::string::String; diff --git a/src/test/run-pass/rustc-rust-log.rs b/src/test/run-pass/rustc-rust-log.rs new file mode 100644 index 000000000000..629387d4cb11 --- /dev/null +++ b/src/test/run-pass/rustc-rust-log.rs @@ -0,0 +1,13 @@ +// 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. + +// rustc-env:RUST_LOG=debug + +fn main() {} diff --git a/src/test/run-pass/sync-send-iterators-in-libcollections.rs b/src/test/run-pass/sync-send-iterators-in-libcollections.rs index ea154590deef..903532e9bc80 100644 --- a/src/test/run-pass/sync-send-iterators-in-libcollections.rs +++ b/src/test/run-pass/sync-send-iterators-in-libcollections.rs @@ -9,21 +9,16 @@ // except according to those terms. #![allow(warnings)] -#![feature(collections)] #![feature(drain, collections_bound, btree_range, vecmap)] -extern crate collections; - -use collections::BinaryHeap; -use collections::{BTreeMap, BTreeSet}; -use collections::LinkedList; -use collections::String; -use collections::Vec; -use collections::VecDeque; +use std::collections::BinaryHeap; +use std::collections::{BTreeMap, BTreeSet}; +use std::collections::LinkedList; +use std::collections::VecDeque; use std::collections::HashMap; use std::collections::HashSet; -use collections::Bound::Included; +use std::collections::Bound::Included; use std::mem; fn is_sync(_: T) where T: Sync {} diff --git a/src/test/run-pass/utf8_chars.rs b/src/test/run-pass/utf8_chars.rs index 0a984429fabb..b54aed79665a 100644 --- a/src/test/run-pass/utf8_chars.rs +++ b/src/test/run-pass/utf8_chars.rs @@ -9,7 +9,7 @@ // except according to those terms. // -#![feature(collections, core, str_char)] +#![feature(core, str_char)] use std::str; diff --git a/src/test/run-pass/vec-macro-no-std.rs b/src/test/run-pass/vec-macro-no-std.rs index a51ef7322646..5dd551ff5137 100644 --- a/src/test/run-pass/vec-macro-no-std.rs +++ b/src/test/run-pass/vec-macro-no-std.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(lang_items, start, libc, collections)] +#![feature(lang_items, start, libc, alloc)] #![no_std] extern crate std as other; @@ -16,9 +16,9 @@ extern crate std as other; extern crate libc; #[macro_use] -extern crate collections; +extern crate alloc; -use collections::vec::Vec; +use alloc::vec::Vec; // Issue #16806 diff --git a/src/test/run-pass/while-prelude-drop.rs b/src/test/run-pass/while-prelude-drop.rs index e4ca5515653c..39ed4f53cf7e 100644 --- a/src/test/run-pass/while-prelude-drop.rs +++ b/src/test/run-pass/while-prelude-drop.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(collections)] - use std::string::String; #[derive(PartialEq)] diff --git a/src/test/rustdoc/assoc-types.rs b/src/test/rustdoc/assoc-types.rs index e5485c356c29..d152be33f4c7 100644 --- a/src/test/rustdoc/assoc-types.rs +++ b/src/test/rustdoc/assoc-types.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-tidy-linelength + #![crate_type="lib"] // @has assoc_types/trait.Index.html @@ -18,11 +20,14 @@ pub trait Index { // @has - '//*[@id="index.v"]//code' 'fn index' // @has - '//*[@id="tymethod.index"]//code' \ // "fn index<'a>(&'a self, index: I) -> &'a Self::Output" + // @has - '//*[@id="tymethod.index"]//code//a[@href="../assoc_types/trait.Index.html#associatedtype.Output"]' \ + // "Output" fn index<'a>(&'a self, index: I) -> &'a Self::Output; } // @has assoc_types/fn.use_output.html // @has - '//*[@class="rust fn"]' '-> &T::Output' +// @has - '//*[@class="rust fn"]//a[@href="../assoc_types/trait.Index.html#associatedtype.Output"]' 'Output' pub fn use_output>(obj: &T, index: usize) -> &T::Output { obj.index(index) } @@ -33,10 +38,12 @@ pub trait Feed { // @has assoc_types/fn.use_input.html // @has - '//*[@class="rust fn"]' 'T::Input' +// @has - '//*[@class="rust fn"]//a[@href="../assoc_types/trait.Feed.html#associatedtype.Input"]' 'Input' pub fn use_input(_feed: &T, _element: T::Input) { } // @has assoc_types/fn.cmp_input.html // @has - '//*[@class="rust fn"]' 'where T::Input: PartialEq' +// @has - '//*[@class="rust fn"]//a[@href="../assoc_types/trait.Feed.html#associatedtype.Input"]' 'Input' pub fn cmp_input(a: &T::Input, b: &U::Input) -> bool where T::Input: PartialEq { diff --git a/src/test/rustdoc/empty-mod-private.rs b/src/test/rustdoc/empty-mod-private.rs new file mode 100644 index 000000000000..6b86af62a663 --- /dev/null +++ b/src/test/rustdoc/empty-mod-private.rs @@ -0,0 +1,27 @@ +// 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. + +// ignore-tidy-linelength +// compile-flags: --no-defaults --passes collapse-docs --passes unindent-comments --passes strip-priv-imports + +// @has 'empty_mod_private/index.html' '//a[@href="foo/index.html"]' 'foo' +// @has 'empty_mod_private/sidebar-items.js' 'foo' +// @matches 'empty_mod_private/foo/index.html' '//h1' 'Module empty_mod_private::foo' +mod foo {} + +// @has 'empty_mod_private/index.html' '//a[@href="bar/index.html"]' 'bar' +// @has 'empty_mod_private/sidebar-items.js' 'bar' +// @matches 'empty_mod_private/bar/index.html' '//h1' 'Module empty_mod_private::bar' +mod bar { + // @has 'empty_mod_private/bar/index.html' '//a[@href="baz/index.html"]' 'baz' + // @has 'empty_mod_private/bar/sidebar-items.js' 'baz' + // @matches 'empty_mod_private/bar/baz/index.html' '//h1' 'Module empty_mod_private::bar::baz' + mod baz {} +} diff --git a/src/test/rustdoc/empty-mod-public.rs b/src/test/rustdoc/empty-mod-public.rs new file mode 100644 index 000000000000..413fe1614240 --- /dev/null +++ b/src/test/rustdoc/empty-mod-public.rs @@ -0,0 +1,24 @@ +// 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. + +// @has 'empty_mod_public/index.html' '//a[@href="foo/index.html"]' 'foo' +// @has 'empty_mod_public/sidebar-items.js' 'foo' +// @matches 'empty_mod_public/foo/index.html' '//h1' 'Module empty_mod_public::foo' +pub mod foo {} + +// @has 'empty_mod_public/index.html' '//a[@href="bar/index.html"]' 'bar' +// @has 'empty_mod_public/sidebar-items.js' 'bar' +// @matches 'empty_mod_public/bar/index.html' '//h1' 'Module empty_mod_public::bar' +pub mod bar { + // @has 'empty_mod_public/bar/index.html' '//a[@href="baz/index.html"]' 'baz' + // @has 'empty_mod_public/bar/sidebar-items.js' 'baz' + // @matches 'empty_mod_public/bar/baz/index.html' '//h1' 'Module empty_mod_public::bar::baz' + pub mod baz {} +} diff --git a/src/test/rustdoc/issue-35488.rs b/src/test/rustdoc/issue-35488.rs new file mode 100644 index 000000000000..f24166a65f05 --- /dev/null +++ b/src/test/rustdoc/issue-35488.rs @@ -0,0 +1,23 @@ +// 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. + +mod foo { + pub enum Foo { + Bar, + } + pub use self::Foo::*; +} + +// @has 'issue_35488/index.html' '//code' 'pub use self::Foo::*;' +// @has 'issue_35488/enum.Foo.html' +pub use self::foo::*; + +// @has 'issue_35488/index.html' '//code' 'pub use std::option::Option::None;' +pub use std::option::Option::None; diff --git a/src/test/rustdoc/typedef.rs b/src/test/rustdoc/typedef.rs new file mode 100644 index 000000000000..4ac91d354514 --- /dev/null +++ b/src/test/rustdoc/typedef.rs @@ -0,0 +1,35 @@ +// 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. + +pub trait MyTrait { + fn method_on_mytrait() {} +} + +pub struct MyStruct; + +impl MyStruct { + pub fn method_on_mystruct() {} +} + +// @has typedef/type.MyAlias.html +// @has - '//*[@class="impl"]//code' 'impl MyAlias' +// @has - '//*[@class="impl"]//code' 'impl MyTrait for MyAlias' +// @has - 'Alias docstring' +// @has - '//*[@class="sidebar"]//p[@class="location"]' 'Type Definition MyAlias' +// @has - '//*[@class="sidebar"]//a[@href="#methods"]' 'Methods' +// @has - '//*[@class="sidebar"]//a[@href="#implementations"]' 'Trait Implementations' +/// Alias docstring +pub type MyAlias = MyStruct; + +impl MyAlias { + pub fn method_on_myalias() {} +} + +impl MyTrait for MyAlias {} diff --git a/src/test/ui/closure_context/issue-26046-fn-mut.rs b/src/test/ui/closure_context/issue-26046-fn-mut.rs new file mode 100644 index 000000000000..5ed7ace5437d --- /dev/null +++ b/src/test/ui/closure_context/issue-26046-fn-mut.rs @@ -0,0 +1,21 @@ +// 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. + +fn foo() -> Box { + let num = 5; + + let closure = || { + num += 1; + }; + + Box::new(closure) +} + +fn main() {} diff --git a/src/test/ui/closure_context/issue-26046-fn-mut.stderr b/src/test/ui/closure_context/issue-26046-fn-mut.stderr new file mode 100644 index 000000000000..dbf702e45030 --- /dev/null +++ b/src/test/ui/closure_context/issue-26046-fn-mut.stderr @@ -0,0 +1,20 @@ +error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnMut` + --> $DIR/issue-26046-fn-mut.rs:14:19 + | +14 | let closure = || { + | ___________________^ +15 | | num += 1; +16 | | }; + | |_____^ +17 | +18 | Box::new(closure) + | ----------------- the requirement to implement `Fn` derives from here + | +note: closure is `FnMut` because it mutates the variable `num` here + --> $DIR/issue-26046-fn-mut.rs:15:9 + | +15 | num += 1; + | ^^^ + +error: aborting due to previous error(s) + diff --git a/src/test/ui/closure_context/issue-26046-fn-once.rs b/src/test/ui/closure_context/issue-26046-fn-once.rs new file mode 100644 index 000000000000..de06de530c6c --- /dev/null +++ b/src/test/ui/closure_context/issue-26046-fn-once.rs @@ -0,0 +1,21 @@ +// 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. + +fn get_closure() -> Box Vec> { + let vec = vec![1u8, 2u8]; + + let closure = move || { + vec + }; + + Box::new(closure) +} + +fn main() {} diff --git a/src/test/ui/closure_context/issue-26046-fn-once.stderr b/src/test/ui/closure_context/issue-26046-fn-once.stderr new file mode 100644 index 000000000000..3ec3f0cc9aa5 --- /dev/null +++ b/src/test/ui/closure_context/issue-26046-fn-once.stderr @@ -0,0 +1,20 @@ +error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce` + --> $DIR/issue-26046-fn-once.rs:14:19 + | +14 | let closure = move || { + | ___________________^ +15 | | vec +16 | | }; + | |_____^ +17 | +18 | Box::new(closure) + | ----------------- the requirement to implement `Fn` derives from here + | +note: closure is `FnOnce` because it moves the variable `vec` out of its environment + --> $DIR/issue-26046-fn-once.rs:15:9 + | +15 | vec + | ^^^ + +error: aborting due to previous error(s) + diff --git a/src/test/ui/fn_once-moved.rs b/src/test/ui/closure_context/issue-42065.rs similarity index 100% rename from src/test/ui/fn_once-moved.rs rename to src/test/ui/closure_context/issue-42065.rs diff --git a/src/test/ui/fn_once-moved.stderr b/src/test/ui/closure_context/issue-42065.stderr similarity index 86% rename from src/test/ui/fn_once-moved.stderr rename to src/test/ui/closure_context/issue-42065.stderr index 27b7d91d1d4b..5bbd372adb6c 100644 --- a/src/test/ui/fn_once-moved.stderr +++ b/src/test/ui/closure_context/issue-42065.stderr @@ -1,5 +1,5 @@ error[E0382]: use of moved value: `debug_dump_dict` - --> $DIR/fn_once-moved.rs:21:5 + --> $DIR/issue-42065.rs:21:5 | 20 | debug_dump_dict(); | --------------- value moved here @@ -7,7 +7,7 @@ error[E0382]: use of moved value: `debug_dump_dict` | ^^^^^^^^^^^^^^^ value used here after move | note: closure cannot be invoked more than once because it moves the variable `dict` out of its environment - --> $DIR/fn_once-moved.rs:16:29 + --> $DIR/issue-42065.rs:16:29 | 16 | for (key, value) in dict { | ^^^^ diff --git a/src/test/ui/coercion-missing-tail-expected-type.rs b/src/test/ui/coercion-missing-tail-expected-type.rs index 489ad817ea8b..15ce79a054f2 100644 --- a/src/test/ui/coercion-missing-tail-expected-type.rs +++ b/src/test/ui/coercion-missing-tail-expected-type.rs @@ -14,6 +14,10 @@ fn plus_one(x: i32) -> i32 { x + 1; } +fn foo() -> Result { + Ok(1); +} + fn main() { let x = plus_one(5); println!("X = {}", x); diff --git a/src/test/ui/coercion-missing-tail-expected-type.stderr b/src/test/ui/coercion-missing-tail-expected-type.stderr index 28a99e58eca8..e96bc425e0b4 100644 --- a/src/test/ui/coercion-missing-tail-expected-type.stderr +++ b/src/test/ui/coercion-missing-tail-expected-type.stderr @@ -15,5 +15,22 @@ help: consider removing this semicolon: 14 | x + 1; | ^ +error[E0308]: mismatched types + --> $DIR/coercion-missing-tail-expected-type.rs:17:29 + | +17 | fn foo() -> Result { + | _____________________________^ +18 | | Ok(1); +19 | | } + | |_^ expected enum `std::result::Result`, found () + | + = note: expected type `std::result::Result` + found type `()` +help: consider removing this semicolon: + --> $DIR/coercion-missing-tail-expected-type.rs:18:10 + | +18 | Ok(1); + | ^ + error: aborting due to previous error(s) diff --git a/src/test/ui/did_you_mean/issue-36798.stderr b/src/test/ui/did_you_mean/issue-36798.stderr index ea628f10e0fd..a8d978d55140 100644 --- a/src/test/ui/did_you_mean/issue-36798.stderr +++ b/src/test/ui/did_you_mean/issue-36798.stderr @@ -1,4 +1,4 @@ -error: no field `baz` on type `Foo` +error[E0609]: no field `baz` on type `Foo` --> $DIR/issue-36798.rs:17:7 | 17 | f.baz; diff --git a/src/test/ui/did_you_mean/issue-36798_unknown_field.stderr b/src/test/ui/did_you_mean/issue-36798_unknown_field.stderr index a9090e3911b0..8228f9f3face 100644 --- a/src/test/ui/did_you_mean/issue-36798_unknown_field.stderr +++ b/src/test/ui/did_you_mean/issue-36798_unknown_field.stderr @@ -1,4 +1,4 @@ -error: no field `zz` on type `Foo` +error[E0609]: no field `zz` on type `Foo` --> $DIR/issue-36798_unknown_field.rs:17:7 | 17 | f.zz; diff --git a/src/test/ui/interior-mutability/interior-mutability.rs b/src/test/ui/interior-mutability/interior-mutability.rs new file mode 100644 index 000000000000..60d85d1b3b78 --- /dev/null +++ b/src/test/ui/interior-mutability/interior-mutability.rs @@ -0,0 +1,16 @@ +// 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. + +use std::cell::Cell; +use std::panic::catch_unwind; +fn main() { + let mut x = Cell::new(22); + catch_unwind(|| { x.set(23); }); +} diff --git a/src/test/ui/interior-mutability/interior-mutability.stderr b/src/test/ui/interior-mutability/interior-mutability.stderr new file mode 100644 index 000000000000..a9535f1c8303 --- /dev/null +++ b/src/test/ui/interior-mutability/interior-mutability.stderr @@ -0,0 +1,14 @@ +error[E0277]: the trait bound `std::cell::UnsafeCell: std::panic::RefUnwindSafe` is not satisfied in `std::cell::Cell` + --> $DIR/interior-mutability.rs:15:5 + | +15 | catch_unwind(|| { x.set(23); }); + | ^^^^^^^^^^^^ the type std::cell::UnsafeCell may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary + | + = help: within `std::cell::Cell`, the trait `std::panic::RefUnwindSafe` is not implemented for `std::cell::UnsafeCell` + = note: required because it appears within the type `std::cell::Cell` + = note: required because of the requirements on the impl of `std::panic::UnwindSafe` for `&std::cell::Cell` + = note: required because it appears within the type `[closure@$DIR/interior-mutability.rs:15:18: 15:35 x:&std::cell::Cell]` + = note: required by `std::panic::catch_unwind` + +error: aborting due to previous error(s) + diff --git a/src/test/ui/issue-22644.rs b/src/test/ui/issue-22644.rs new file mode 100644 index 000000000000..9269180396c5 --- /dev/null +++ b/src/test/ui/issue-22644.rs @@ -0,0 +1,18 @@ +// 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. + +fn main() { + let a : u32 = 0; + let b : usize = 0; + + println!("{}", a as usize > b); + println!("{}", a as usize < b); + println!("{}", a as usize < 4); +} diff --git a/src/test/ui/issue-22644.stderr b/src/test/ui/issue-22644.stderr new file mode 100644 index 000000000000..a22496357d99 --- /dev/null +++ b/src/test/ui/issue-22644.stderr @@ -0,0 +1,24 @@ +error: `<` is interpreted as a start of generic arguments for `usize`, not a comparison + --> $DIR/issue-22644.rs:16:33 + | +16 | println!("{}", a as usize < b); + | - ^ interpreted as generic argument + | | + | not interpreted as comparison + | +help: if you want to compare the casted value then write: + | println!("{}", (a as usize) < b); + +error: `<` is interpreted as a start of generic arguments for `usize`, not a comparison + --> $DIR/issue-22644.rs:17:33 + | +17 | println!("{}", a as usize < 4); + | - ^ interpreted as generic argument + | | + | not interpreted as comparison + | +help: if you want to compare the casted value then write: + | println!("{}", (a as usize) < 4); + +error: aborting due to previous error(s) + diff --git a/src/test/ui/issue-38875/auxiliary/issue_38875_b.rs b/src/test/ui/issue-38875/auxiliary/issue_38875_b.rs new file mode 100644 index 000000000000..dd58735209b8 --- /dev/null +++ b/src/test/ui/issue-38875/auxiliary/issue_38875_b.rs @@ -0,0 +1,11 @@ +// 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. + +pub const FOO: usize = *&0; diff --git a/src/test/ui/issue-38875/issue_38875.rs b/src/test/ui/issue-38875/issue_38875.rs new file mode 100644 index 000000000000..42e3c05a38c7 --- /dev/null +++ b/src/test/ui/issue-38875/issue_38875.rs @@ -0,0 +1,17 @@ +// 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. + +// aux-build:issue_38875_b.rs + +extern crate issue_38875_b; + +fn main() { + let test_x = [0; issue_38875_b::FOO]; +} diff --git a/src/test/ui/issue-38875/issue_38875.stderr b/src/test/ui/issue-38875/issue_38875.stderr new file mode 100644 index 000000000000..ceed83d9313c --- /dev/null +++ b/src/test/ui/issue-38875/issue_38875.stderr @@ -0,0 +1,14 @@ +error[E0080]: constant evaluation error + --> $DIR/auxiliary/issue_38875_b.rs:11:24 + | +11 | pub const FOO: usize = *&0; + | ^^^ unimplemented constant expression: deref operation + | +note: for repeat count here + --> $DIR/issue_38875.rs:16:22 + | +16 | let test_x = [0; issue_38875_b::FOO]; + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error(s) + diff --git a/src/test/ui/issue-41652/issue_41652.stderr b/src/test/ui/issue-41652/issue_41652.stderr index 4625e9269c99..b7b1ddb7b88d 100644 --- a/src/test/ui/issue-41652/issue_41652.stderr +++ b/src/test/ui/issue-41652/issue_41652.stderr @@ -6,6 +6,11 @@ error[E0599]: no method named `f` found for type `{integer}` in the current scop | = note: found the following associated functions; to be used as methods, functions must have a `self` parameter note: candidate #1 is defined in the trait `issue_41652_b::Tr` + --> $DIR/auxiliary/issue_41652_b.rs:14:5 + | +14 | / fn f() +15 | | where Self: Sized; + | |__________________________^ = help: to disambiguate the method call, write `issue_41652_b::Tr::f(3)` instead error: aborting due to previous error(s) diff --git a/src/test/ui/macros/macro-backtrace-invalid-internals.stderr b/src/test/ui/macros/macro-backtrace-invalid-internals.stderr index 2c83a84f0040..95db694a0c61 100644 --- a/src/test/ui/macros/macro-backtrace-invalid-internals.stderr +++ b/src/test/ui/macros/macro-backtrace-invalid-internals.stderr @@ -7,7 +7,7 @@ error[E0599]: no method named `fake` found for type `{integer}` in the current s 50 | fake_method_stmt!(); | -------------------- in this macro invocation -error: no field `fake` on type `{integer}` +error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields --> $DIR/macro-backtrace-invalid-internals.rs:21:13 | 21 | 1.fake @@ -34,7 +34,7 @@ error[E0599]: no method named `fake` found for type `{integer}` in the current s 54 | let _ = fake_method_expr!(); | ------------------- in this macro invocation -error: no field `fake` on type `{integer}` +error[E0610]: `{integer}` is a primitive type and therefore doesn't have fields --> $DIR/macro-backtrace-invalid-internals.rs:39:13 | 39 | 1.fake diff --git a/src/test/ui/mismatched_types/E0281.stderr b/src/test/ui/mismatched_types/E0281.stderr index fab48e9a740a..3eb5c125789f 100644 --- a/src/test/ui/mismatched_types/E0281.stderr +++ b/src/test/ui/mismatched_types/E0281.stderr @@ -9,16 +9,5 @@ error[E0281]: type mismatch: `[closure@$DIR/E0281.rs:14:9: 14:24]` implements th | = note: required by `foo` -error[E0281]: type mismatch: `[closure@$DIR/E0281.rs:14:9: 14:24]` implements the trait `std::ops::FnOnce<(std::string::String,)>`, but the trait `std::ops::FnOnce<(usize,)>` is required - --> $DIR/E0281.rs:14:5 - | -14 | foo(|y: String| { }); - | ^^^ --------------- implements `std::ops::FnOnce<(std::string::String,)>` - | | - | requires `std::ops::FnOnce<(usize,)>` - | expected usize, found struct `std::string::String` - | - = note: required by `foo` - error: aborting due to previous error(s) diff --git a/src/test/ui/mismatched_types/binops.stderr b/src/test/ui/mismatched_types/binops.stderr index 1faf72cd760b..cebdc12f5684 100644 --- a/src/test/ui/mismatched_types/binops.stderr +++ b/src/test/ui/mismatched_types/binops.stderr @@ -30,14 +30,6 @@ error[E0277]: the trait bound `{integer}: std::ops::Div<&str>` is not satisfied | = help: the trait `std::ops::Div<&str>` is not implemented for `{integer}` -error[E0277]: the trait bound `{integer}: std::cmp::PartialEq` is not satisfied - --> $DIR/binops.rs:16:7 - | -16 | 5 < String::new(); - | ^ can't compare `{integer}` with `std::string::String` - | - = help: the trait `std::cmp::PartialEq` is not implemented for `{integer}` - error[E0277]: the trait bound `{integer}: std::cmp::PartialOrd` is not satisfied --> $DIR/binops.rs:16:7 | diff --git a/src/test/ui/mismatched_types/cast-rfc0401.stderr b/src/test/ui/mismatched_types/cast-rfc0401.stderr index 8d31dd7500a3..58cd130dcc25 100644 --- a/src/test/ui/mismatched_types/cast-rfc0401.stderr +++ b/src/test/ui/mismatched_types/cast-rfc0401.stderr @@ -14,7 +14,7 @@ error: casting `*const U` as `*const str` is invalid | = note: vtable kinds may not match -error: no field `f` on type `fn() {main}` +error[E0609]: no field `f` on type `fn() {main}` --> $DIR/cast-rfc0401.rs:75:18 | 75 | let _ = main.f as *const u32; diff --git a/src/test/ui/mismatched_types/closure-arg-count.stderr b/src/test/ui/mismatched_types/closure-arg-count.stderr index cd16e5d70b68..85734dfac70d 100644 --- a/src/test/ui/mismatched_types/closure-arg-count.stderr +++ b/src/test/ui/mismatched_types/closure-arg-count.stderr @@ -6,22 +6,6 @@ error[E0593]: closure takes 0 arguments but 2 arguments are required | | | expected closure that takes 2 arguments -error[E0593]: closure takes 0 arguments but 2 arguments are required - --> $DIR/closure-arg-count.rs:12:15 - | -12 | [1, 2, 3].sort_by(|| panic!()); - | ^^^^^^^ ----------- takes 0 arguments - | | - | expected closure that takes 2 arguments - -error[E0593]: closure takes 1 argument but 2 arguments are required - --> $DIR/closure-arg-count.rs:13:15 - | -13 | [1, 2, 3].sort_by(|tuple| panic!()); - | ^^^^^^^ ---------------- takes 1 argument - | | - | expected closure that takes 2 arguments - error[E0593]: closure takes 1 argument but 2 arguments are required --> $DIR/closure-arg-count.rs:13:15 | @@ -47,13 +31,5 @@ error[E0593]: closure takes 1 argument but 2 arguments are required | | | expected closure that takes 2 arguments -error[E0593]: closure takes 1 argument but 2 arguments are required - --> $DIR/closure-arg-count.rs:14:15 - | -14 | [1, 2, 3].sort_by(|(tuple, tuple2)| panic!()); - | ^^^^^^^ -------------------------- takes 1 argument - | | - | expected closure that takes 2 arguments - error: aborting due to previous error(s) diff --git a/src/test/ui/mismatched_types/issue-36053-2.stderr b/src/test/ui/mismatched_types/issue-36053-2.stderr index 8b756814ced8..f818bd8bcb1b 100644 --- a/src/test/ui/mismatched_types/issue-36053-2.stderr +++ b/src/test/ui/mismatched_types/issue-36053-2.stderr @@ -17,14 +17,5 @@ error[E0281]: type mismatch: `[closure@$DIR/issue-36053-2.rs:17:39: 17:53]` impl | requires `for<'r> std::ops::FnMut<(&'r &str,)>` | expected &str, found str -error[E0281]: type mismatch: `[closure@$DIR/issue-36053-2.rs:17:39: 17:53]` implements the trait `for<'r> std::ops::FnOnce<(&'r str,)>`, but the trait `for<'r> std::ops::FnOnce<(&'r &str,)>` is required - --> $DIR/issue-36053-2.rs:17:32 - | -17 | once::<&str>("str").fuse().filter(|a: &str| true).count(); - | ^^^^^^ -------------- implements `for<'r> std::ops::FnOnce<(&'r str,)>` - | | - | requires `for<'r> std::ops::FnOnce<(&'r &str,)>` - | expected &str, found str - error: aborting due to previous error(s) diff --git a/src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.rs b/src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.rs index 7400a27fb6bc..693a1585320e 100644 --- a/src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.rs +++ b/src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.rs @@ -24,7 +24,6 @@ pub fn main() { //~| NOTE implements let z = call_it(3, f); //~^ ERROR type mismatch - //~| ERROR type mismatch //~| NOTE expected isize, found usize //~| NOTE expected isize, found usize //~| NOTE requires diff --git a/src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.stderr b/src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.stderr index c5bfb6e45e77..643c9b36dbd5 100644 --- a/src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.stderr +++ b/src/test/ui/mismatched_types/unboxed-closures-vtable-mismatch.stderr @@ -12,19 +12,5 @@ error[E0281]: type mismatch: `[closure@$DIR/unboxed-closures-vtable-mismatch.rs: | = note: required by `call_it` -error[E0281]: type mismatch: `[closure@$DIR/unboxed-closures-vtable-mismatch.rs:22:23: 22:73]` implements the trait `std::ops::FnOnce<(usize, isize)>`, but the trait `std::ops::FnOnce<(isize, isize)>` is required - --> $DIR/unboxed-closures-vtable-mismatch.rs:25:13 - | -22 | let f = to_fn_mut(|x: usize, y: isize| -> isize { (x as isize) + y }); - | -------------------------------------------------- implements `std::ops::FnOnce<(usize, isize)>` -... -25 | let z = call_it(3, f); - | ^^^^^^^ - | | - | requires `std::ops::FnOnce<(isize, isize)>` - | expected isize, found usize - | - = note: required by `call_it` - error: aborting due to previous error(s) diff --git a/src/test/ui/span/suggestion-non-ascii.stderr b/src/test/ui/span/suggestion-non-ascii.stderr index b6353c0f6a20..68d43d3f5cd8 100644 --- a/src/test/ui/span/suggestion-non-ascii.stderr +++ b/src/test/ui/span/suggestion-non-ascii.stderr @@ -1,4 +1,4 @@ -error: cannot index a value of type `({integer},)` +error[E0608]: cannot index into a value of type `({integer},)` --> $DIR/suggestion-non-ascii.rs:14:21 | 14 | println!("☃{}", tup[0]); diff --git a/src/test/compile-fail/issue-17283.rs b/src/test/ui/type-check/assignment-in-if.rs similarity index 71% rename from src/test/compile-fail/issue-17283.rs rename to src/test/ui/type-check/assignment-in-if.rs index 98208bcfdbde..98dc55c66630 100644 --- a/src/test/compile-fail/issue-17283.rs +++ b/src/test/ui/type-check/assignment-in-if.rs @@ -24,25 +24,29 @@ fn main() { // `x { ... }` should not be interpreted as a struct literal here if x = x { //~^ ERROR mismatched types - //~| expected type `bool` - //~| found type `()` - //~| expected bool, found () + //~| HELP did you mean to compare equality? println!("{}", x); } // Explicit parentheses on the left should match behavior of above if (x = x) { //~^ ERROR mismatched types - //~| expected type `bool` - //~| found type `()` - //~| expected bool, found () + //~| HELP did you mean to compare equality? println!("{}", x); } // The struct literal interpretation is fine with explicit parentheses on the right if y = (Foo { foo: x }) { //~^ ERROR mismatched types - //~| expected type `bool` - //~| found type `()` - //~| expected bool, found () + //~| HELP did you mean to compare equality? + println!("{}", x); + } + // "invalid left-hand side expression" error is suppresed + if 3 = x { + //~^ ERROR mismatched types + //~| HELP did you mean to compare equality? + println!("{}", x); + } + if (if true { x = 4 } else { x = 5 }) { + //~^ ERROR mismatched types println!("{}", x); } } diff --git a/src/test/ui/type-check/assignment-in-if.stderr b/src/test/ui/type-check/assignment-in-if.stderr new file mode 100644 index 000000000000..294399992732 --- /dev/null +++ b/src/test/ui/type-check/assignment-in-if.stderr @@ -0,0 +1,59 @@ +error[E0308]: mismatched types + --> $DIR/assignment-in-if.rs:25:8 + | +25 | if x = x { + | ^^^^^ + | | + | help: did you mean to compare equality? `x == x` + | expected bool, found () + | + = note: expected type `bool` + found type `()` + +error[E0308]: mismatched types + --> $DIR/assignment-in-if.rs:31:8 + | +31 | if (x = x) { + | ^^^^^^^ + | | + | help: did you mean to compare equality? `x == x` + | expected bool, found () + | + = note: expected type `bool` + found type `()` + +error[E0308]: mismatched types + --> $DIR/assignment-in-if.rs:37:8 + | +37 | if y = (Foo { foo: x }) { + | ^^^^^^^^^^^^^^^^^^^^ + | | + | help: did you mean to compare equality? `y == (Foo { foo: x })` + | expected bool, found () + | + = note: expected type `bool` + found type `()` + +error[E0308]: mismatched types + --> $DIR/assignment-in-if.rs:43:8 + | +43 | if 3 = x { + | ^^^^^ + | | + | help: did you mean to compare equality? `3 == x` + | expected bool, found () + | + = note: expected type `bool` + found type `()` + +error[E0308]: mismatched types + --> $DIR/assignment-in-if.rs:48:8 + | +48 | if (if true { x = 4 } else { x = 5 }) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected bool, found () + | + = note: expected type `bool` + found type `()` + +error: aborting due to previous error(s) + diff --git a/src/test/ui/type-check/issue-40294.stderr b/src/test/ui/type-check/issue-40294.stderr index bf03e52369fe..cd474b14193f 100644 --- a/src/test/ui/type-check/issue-40294.stderr +++ b/src/test/ui/type-check/issue-40294.stderr @@ -1,4 +1,4 @@ -error[E0282]: type annotations needed +error[E0283]: type annotations required: cannot resolve `&'a T: Foo` --> $DIR/issue-40294.rs:15:1 | 15 | / fn foo<'a,'b,T>(x: &'a T, y: &'b T) @@ -8,7 +8,9 @@ error[E0282]: type annotations needed 19 | | x.foo(); 20 | | y.foo(); 21 | | } - | |_^ cannot infer type for `&'a T` + | |_^ + | + = note: required by `Foo` error: aborting due to previous error(s) diff --git a/src/tools/cargo b/src/tools/cargo index 82733b01471a..50b1c24d146f 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 82733b01471a2c62bb1cec966d888c52ff118914 +Subproject commit 50b1c24d146fa072db71f12005deed319ac5ba9a diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 92f6f36d69d9..cc95e1b89305 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -166,6 +166,9 @@ pub struct Config { // Version of LLVM pub llvm_version: Option, + // Is LLVM a system LLVM + pub system_llvm: bool, + // Path to the android tools pub android_cross_path: PathBuf, diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index c503ca7d8cd1..aa33580b337c 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -166,6 +166,9 @@ impl EarlyProps { } fn ignore_llvm(config: &Config, line: &str) -> bool { + if config.system_llvm && line.starts_with("no-system-llvm") { + return true; + } if let Some(ref actual_version) = config.llvm_version { if line.starts_with("min-llvm-version") { let min_version = line.trim_right() diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index 1bb0b765f9f1..3dac580a5f4b 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -97,6 +97,7 @@ pub fn parse_config(args: Vec ) -> Config { optopt("", "gdb", "path to GDB to use for GDB debuginfo tests", "PATH"), optopt("", "lldb-version", "the version of LLDB used", "VERSION STRING"), optopt("", "llvm-version", "the version of LLVM used", "VERSION STRING"), + optflag("", "system-llvm", "is LLVM the system LLVM"), optopt("", "android-cross-path", "Android NDK standalone path", "PATH"), optopt("", "adb-path", "path to the android debugger", "PATH"), optopt("", "adb-test-dir", "path to tests for the android debugger", "PATH"), @@ -183,6 +184,7 @@ pub fn parse_config(args: Vec ) -> Config { gdb_native_rust: gdb_native_rust, lldb_version: extract_lldb_version(matches.opt_str("lldb-version")), llvm_version: matches.opt_str("llvm-version"), + system_llvm: matches.opt_present("system-llvm"), android_cross_path: opt_path(matches, "android-cross-path"), adb_path: opt_str2(matches.opt_str("adb-path")), adb_test_dir: opt_str2(matches.opt_str("adb-test-dir")), diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs index 1b55dc792c2e..3ea2e6313af4 100644 --- a/src/tools/linkchecker/main.rs +++ b/src/tools/linkchecker/main.rs @@ -118,15 +118,15 @@ fn check(cache: &mut Cache, return None; } // FIXME(#32553) - if file.ends_with("collections/string/struct.String.html") { + if file.ends_with("string/struct.String.html") { return None; } // FIXME(#32130) if file.ends_with("btree_set/struct.BTreeSet.html") || - file.ends_with("collections/struct.BTreeSet.html") || - file.ends_with("collections/btree_map/struct.BTreeMap.html") || - file.ends_with("collections/hash_map/struct.HashMap.html") || - file.ends_with("collections/hash_set/struct.HashSet.html") { + file.ends_with("struct.BTreeSet.html") || + file.ends_with("btree_map/struct.BTreeMap.html") || + file.ends_with("hash_map/struct.HashMap.html") || + file.ends_with("hash_set/struct.HashSet.html") { return None; } diff --git a/src/tools/rls b/src/tools/rls index 38ca9b702b73..e53e2f8d5b7f 160000 --- a/src/tools/rls +++ b/src/tools/rls @@ -1 +1 @@ -Subproject commit 38ca9b702b73c03959e447f5dae56eff7497c986 +Subproject commit e53e2f8d5b7f7751dd478fff68c1dbe7247cb096 diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index e34821e3584c..722fc2b317eb 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -24,7 +24,7 @@ use std::fs::File; use std::io::prelude::*; use std::path::Path; -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Clone)] pub enum Status { Stable, Removed, @@ -42,18 +42,21 @@ impl fmt::Display for Status { } } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Feature { pub level: Status, pub since: String, pub has_gate_test: bool, + pub tracking_issue: Option, } +pub type Features = HashMap; + pub fn check(path: &Path, bad: &mut bool, quiet: bool) { let mut features = collect_lang_features(path); assert!(!features.is_empty()); - let lib_features = collect_lib_features(path, bad, &features); + let lib_features = get_and_check_lib_features(path, bad, &features); assert!(!lib_features.is_empty()); let mut contents = String::new(); @@ -168,8 +171,7 @@ fn find_attr_val<'a>(line: &'a str, attr: &str) -> Option<&'a str> { .map(|(i, j)| &line[i..j]) } -fn test_filen_gate(filen_underscore: &str, - features: &mut HashMap) -> bool { +fn test_filen_gate(filen_underscore: &str, features: &mut Features) -> bool { if filen_underscore.starts_with("feature_gate") { for (n, f) in features.iter_mut() { if filen_underscore == format!("feature_gate_{}", n) { @@ -181,7 +183,7 @@ fn test_filen_gate(filen_underscore: &str, return false; } -pub fn collect_lang_features(base_src_path: &Path) -> HashMap { +pub fn collect_lang_features(base_src_path: &Path) -> Features { let mut contents = String::new(); let path = base_src_path.join("libsyntax/feature_gate.rs"); t!(t!(File::open(path)).read_to_string(&mut contents)); @@ -197,20 +199,79 @@ pub fn collect_lang_features(base_src_path: &Path) -> HashMap { }; let name = parts.next().unwrap().trim(); let since = parts.next().unwrap().trim().trim_matches('"'); + let issue_str = parts.next().unwrap().trim(); + let tracking_issue = if issue_str.starts_with("None") { + None + } else { + let s = issue_str.split("(").nth(1).unwrap().split(")").nth(0).unwrap(); + Some(s.parse().unwrap()) + }; Some((name.to_owned(), Feature { - level: level, + level, since: since.to_owned(), has_gate_test: false, + tracking_issue, })) }) .collect() } -pub fn collect_lib_features(base_src_path: &Path, - bad: &mut bool, - features: &HashMap) -> HashMap { - let mut lib_features = HashMap::::new(); +pub fn collect_lib_features(base_src_path: &Path) -> Features { + let mut lib_features = Features::new(); + map_lib_features(base_src_path, + &mut |res, _, _| { + match res { + Ok((name, feature)) => { + if lib_features.get(name).is_some() { + return; + } + lib_features.insert(name.to_owned(), feature); + }, + Err(_) => (), + } + }); + lib_features +} + +fn get_and_check_lib_features(base_src_path: &Path, + bad: &mut bool, + lang_features: &Features) -> Features { + let mut lib_features = Features::new(); + map_lib_features(base_src_path, + &mut |res, file, line| { + match res { + Ok((name, f)) => { + let mut err = |msg: &str| { + tidy_error!(bad, "{}:{}: {}", file.display(), line, msg); + }; + if lang_features.contains_key(name) { + err("duplicating a lang feature"); + } + if let Some(ref s) = lib_features.get(name) { + if s.level != f.level { + err("different stability level than before"); + } + if s.since != f.since { + err("different `since` than before"); + } + if s.tracking_issue != f.tracking_issue { + err("different `tracking_issue` than before"); + } + } + lib_features.insert(name.to_owned(), f); + }, + Err(msg) => { + tidy_error!(bad, "{}:{}: {}", file.display(), line, msg); + }, + } + + }); + lib_features +} + +fn map_lib_features(base_src_path: &Path, + mf: &mut FnMut(Result<(&str, Feature), &str>, &Path, usize)) { let mut contents = String::new(); super::walk(base_src_path, &mut |path| super::filter_dirs(path) || path.ends_with("src/test"), @@ -224,10 +285,35 @@ pub fn collect_lib_features(base_src_path: &Path, contents.truncate(0); t!(t!(File::open(&file), &file).read_to_string(&mut contents)); + let mut becoming_feature: Option<(String, Feature)> = None; for (i, line) in contents.lines().enumerate() { - let mut err = |msg: &str| { - tidy_error!(bad, "{}:{}: {}", file.display(), i + 1, msg); + macro_rules! err { + ($msg:expr) => {{ + mf(Err($msg), file, i + 1); + continue; + }}; }; + if let Some((ref name, ref mut f)) = becoming_feature { + if f.tracking_issue.is_none() { + f.tracking_issue = find_attr_val(line, "issue") + .map(|s| s.parse().unwrap()); + } + if line.ends_with("]") { + mf(Ok((name, f.clone())), file, i + 1); + } else if !line.ends_with(",") && !line.ends_with("\\") { + // We need to bail here because we might have missed the + // end of a stability attribute above because the "]" + // might not have been at the end of the line. + // We could then get into the very unfortunate situation that + // we continue parsing the file assuming the current stability + // attribute has not ended, and ignoring possible feature + // attributes in the process. + err!("malformed stability attribute"); + } else { + continue; + } + } + becoming_feature = None; let level = if line.contains("[unstable(") { Status::Unstable } else if line.contains("[stable(") { @@ -237,39 +323,28 @@ pub fn collect_lib_features(base_src_path: &Path, }; let feature_name = match find_attr_val(line, "feature") { Some(name) => name, - None => { - err("malformed stability attribute"); - continue; - } + None => err!("malformed stability attribute"), }; let since = match find_attr_val(line, "since") { Some(name) => name, None if level == Status::Stable => { - err("malformed stability attribute"); - continue; + err!("malformed stability attribute"); } None => "None", }; + let tracking_issue = find_attr_val(line, "issue").map(|s| s.parse().unwrap()); - if features.contains_key(feature_name) { - err("duplicating a lang feature"); + let feature = Feature { + level, + since: since.to_owned(), + has_gate_test: false, + tracking_issue, + }; + if line.contains("]") { + mf(Ok((feature_name, feature)), file, i + 1); + } else { + becoming_feature = Some((feature_name.to_owned(), feature)); } - if let Some(ref s) = lib_features.get(feature_name) { - if s.level != level { - err("different stability level than before"); - } - if s.since != since { - err("different `since` than before"); - } - continue; - } - lib_features.insert(feature_name.to_owned(), - Feature { - level: level, - since: since.to_owned(), - has_gate_test: false, - }); } }); - lib_features } diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs new file mode 100644 index 000000000000..bcf86e4489be --- /dev/null +++ b/src/tools/tidy/src/lib.rs @@ -0,0 +1,88 @@ +// 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. + +//! Library used by tidy and other tools +//! +//! This library contains the tidy lints and exposes it +//! to be used by tools. + +#![deny(warnings)] + +use std::fs; + +use std::path::Path; + +macro_rules! t { + ($e:expr, $p:expr) => (match $e { + Ok(e) => e, + Err(e) => panic!("{} failed on {} with {}", stringify!($e), ($p).display(), e), + }); + + ($e:expr) => (match $e { + Ok(e) => e, + Err(e) => panic!("{} failed with {}", stringify!($e), e), + }) +} + +macro_rules! tidy_error { + ($bad:expr, $fmt:expr, $($arg:tt)*) => ({ + use std::io::Write; + *$bad = true; + write!(::std::io::stderr(), "tidy error: ").expect("could not write to stderr"); + writeln!(::std::io::stderr(), $fmt, $($arg)*).expect("could not write to stderr"); + }); +} + +pub mod bins; +pub mod style; +pub mod errors; +pub mod features; +pub mod cargo; +pub mod pal; +pub mod deps; +pub mod unstable_book; + +fn filter_dirs(path: &Path) -> bool { + let skip = [ + "src/jemalloc", + "src/llvm", + "src/libbacktrace", + "src/compiler-rt", + "src/rustllvm", + "src/liblibc", + "src/vendor", + "src/rt/hoedown", + "src/tools/cargo", + "src/tools/rls", + "src/tools/rust-installer", + ]; + skip.iter().any(|p| path.ends_with(p)) +} + +fn walk_many(paths: &[&Path], skip: &mut FnMut(&Path) -> bool, f: &mut FnMut(&Path)) { + for path in paths { + walk(path, skip, f); + } +} + +fn walk(path: &Path, skip: &mut FnMut(&Path) -> bool, f: &mut FnMut(&Path)) { + for entry in t!(fs::read_dir(path), path) { + let entry = t!(entry); + let kind = t!(entry.file_type()); + let path = entry.path(); + if kind.is_dir() { + if !skip(&path) { + walk(&path, skip, f); + } + } else { + f(&path); + } + } +} diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index 23a31131f7a6..433192a21ec9 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -8,47 +8,21 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Tidy checks for source code in this repository +//! Tidy checks source code in this repository //! //! This program runs all of the various tidy checks for style, cleanliness, //! etc. This is run by default on `make check` and as part of the auto //! builders. -use std::env; -use std::fs; -use std::io::{self, Write}; -use std::path::{PathBuf, Path}; +#![deny(warnings)] + +extern crate tidy; +use tidy::*; + use std::process; - -macro_rules! t { - ($e:expr, $p:expr) => (match $e { - Ok(e) => e, - Err(e) => panic!("{} failed on {} with {}", stringify!($e), ($p).display(), e), - }); - - ($e:expr) => (match $e { - Ok(e) => e, - Err(e) => panic!("{} failed with {}", stringify!($e), e), - }) -} - -macro_rules! tidy_error { - ($bad:expr, $fmt:expr, $($arg:tt)*) => ({ - use std::io::Write; - *$bad = true; - write!(::std::io::stderr(), "tidy error: ").expect("could not write to stderr"); - writeln!(::std::io::stderr(), $fmt, $($arg)*).expect("could not write to stderr"); - }); -} - -mod bins; -mod style; -mod errors; -mod features; -mod cargo; -mod pal; -mod deps; -mod unstable_book; +use std::path::PathBuf; +use std::env; +use std::io::{self, Write}; fn main() { let path = env::args_os().skip(1).next().expect("need an argument"); @@ -74,41 +48,3 @@ fn main() { process::exit(1); } } - -fn filter_dirs(path: &Path) -> bool { - let skip = [ - "src/jemalloc", - "src/llvm", - "src/libbacktrace", - "src/compiler-rt", - "src/rustllvm", - "src/liblibc", - "src/vendor", - "src/rt/hoedown", - "src/tools/cargo", - "src/tools/rls", - "src/tools/rust-installer", - ]; - skip.iter().any(|p| path.ends_with(p)) -} - -fn walk_many(paths: &[&Path], skip: &mut FnMut(&Path) -> bool, f: &mut FnMut(&Path)) { - for path in paths { - walk(path, skip, f); - } -} - -fn walk(path: &Path, skip: &mut FnMut(&Path) -> bool, f: &mut FnMut(&Path)) { - for entry in t!(fs::read_dir(path), path) { - let entry = t!(entry); - let kind = t!(entry.file_type()); - let path = entry.path(); - if kind.is_dir() { - if !skip(&path) { - walk(&path, skip, f); - } - } else { - f(&path); - } - } -} diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs index 8bf683de8704..35073b63723d 100644 --- a/src/tools/tidy/src/style.rs +++ b/src/tools/tidy/src/style.rs @@ -169,8 +169,10 @@ fn licenseck(file: &Path, contents: &str) -> bool { lines.windows(LICENSE.lines().count()).any(|window| { let offset = if window.iter().all(|w| w.starts_with("//")) { 2 - } else if window.iter().all(|w| w.starts_with("#")) { + } else if window.iter().all(|w| w.starts_with('#')) { 1 + } else if window.iter().all(|w| w.starts_with(" *")) { + 2 } else { return false }; diff --git a/src/tools/tidy/src/unstable_book.rs b/src/tools/tidy/src/unstable_book.rs index 5a6524b3e88e..ff032b14ad1d 100644 --- a/src/tools/tidy/src/unstable_book.rs +++ b/src/tools/tidy/src/unstable_book.rs @@ -8,29 +8,31 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::collections::HashSet; +use std::collections::BTreeSet; use std::fs; use std::path; -use features::{collect_lang_features, collect_lib_features, Status}; +use features::{collect_lang_features, collect_lib_features, Features, Status}; -const PATH_STR: &'static str = "doc/unstable-book/src"; +pub const PATH_STR: &str = "doc/unstable-book/src"; -const LANG_FEATURES_DIR: &'static str = "language-features"; +pub const COMPILER_FLAGS_DIR: &str = "compiler-flags"; -const LIB_FEATURES_DIR: &'static str = "library-features"; +pub const LANG_FEATURES_DIR: &str = "language-features"; + +pub const LIB_FEATURES_DIR: &str = "library-features"; /// Build the path to the Unstable Book source directory from the Rust 'src' directory -fn unstable_book_path(base_src_path: &path::Path) -> path::PathBuf { +pub fn unstable_book_path(base_src_path: &path::Path) -> path::PathBuf { base_src_path.join(PATH_STR) } /// Directory where the features are documented within the Unstable Book source directory -fn unstable_book_lang_features_path(base_src_path: &path::Path) -> path::PathBuf { +pub fn unstable_book_lang_features_path(base_src_path: &path::Path) -> path::PathBuf { unstable_book_path(base_src_path).join(LANG_FEATURES_DIR) } /// Directory where the features are documented within the Unstable Book source directory -fn unstable_book_lib_features_path(base_src_path: &path::Path) -> path::PathBuf { +pub fn unstable_book_lib_features_path(base_src_path: &path::Path) -> path::PathBuf { unstable_book_path(base_src_path).join(LIB_FEATURES_DIR) } @@ -42,27 +44,16 @@ fn dir_entry_is_file(dir_entry: &fs::DirEntry) -> bool { .is_file() } -/// Retrieve names of all lang-related unstable features -fn collect_unstable_lang_feature_names(base_src_path: &path::Path) -> HashSet { - collect_lang_features(base_src_path) - .into_iter() +/// Retrieve names of all unstable features +pub fn collect_unstable_feature_names(features: &Features) -> BTreeSet { + features + .iter() .filter(|&(_, ref f)| f.level == Status::Unstable) - .map(|(ref name, _)| name.to_owned()) + .map(|(name, _)| name.to_owned()) .collect() } -/// Retrieve names of all lib-related unstable features -fn collect_unstable_lib_feature_names(base_src_path: &path::Path) -> HashSet { - let mut bad = true; - let lang_features = collect_lang_features(base_src_path); - collect_lib_features(base_src_path, &mut bad, &lang_features) - .into_iter() - .filter(|&(_, ref f)| f.level == Status::Unstable) - .map(|(ref name, _)| name.to_owned()) - .collect() -} - -fn collect_unstable_book_section_file_names(dir: &path::Path) -> HashSet { +pub fn collect_unstable_book_section_file_names(dir: &path::Path) -> BTreeSet { fs::read_dir(dir) .expect("could not read directory") .into_iter() @@ -78,7 +69,7 @@ fn collect_unstable_book_section_file_names(dir: &path::Path) -> HashSet /// * hyphens replaced by underscores /// * the markdown suffix ('.md') removed fn collect_unstable_book_lang_features_section_file_names(base_src_path: &path::Path) - -> HashSet { + -> BTreeSet { collect_unstable_book_section_file_names(&unstable_book_lang_features_path(base_src_path)) } @@ -87,7 +78,7 @@ fn collect_unstable_book_lang_features_section_file_names(base_src_path: &path:: /// * hyphens replaced by underscores /// * the markdown suffix ('.md') removed fn collect_unstable_book_lib_features_section_file_names(base_src_path: &path::Path) - -> HashSet { + -> BTreeSet { collect_unstable_book_section_file_names(&unstable_book_lib_features_path(base_src_path)) } @@ -95,19 +86,13 @@ pub fn check(path: &path::Path, bad: &mut bool) { // Library features - let unstable_lib_feature_names = collect_unstable_lib_feature_names(path); + let lang_features = collect_lang_features(path); + let lib_features = collect_lib_features(path); + + let unstable_lib_feature_names = collect_unstable_feature_names(&lib_features); let unstable_book_lib_features_section_file_names = collect_unstable_book_lib_features_section_file_names(path); - // Check for unstable features that don't have Unstable Book sections - for feature_name in &unstable_lib_feature_names - - &unstable_book_lib_features_section_file_names { - tidy_error!(bad, - "Unstable library feature '{}' needs to have a section within the \ - 'library features' section of The Unstable Book", - feature_name); - } - // Check for Unstable Book sections that don't have a corresponding unstable feature for feature_name in &unstable_book_lib_features_section_file_names - &unstable_lib_feature_names { @@ -119,18 +104,10 @@ pub fn check(path: &path::Path, bad: &mut bool) { // Language features - let unstable_lang_feature_names = collect_unstable_lang_feature_names(path); + let unstable_lang_feature_names = collect_unstable_feature_names(&lang_features); let unstable_book_lang_features_section_file_names = collect_unstable_book_lang_features_section_file_names(path); - for feature_name in &unstable_lang_feature_names - - &unstable_book_lang_features_section_file_names { - tidy_error!(bad, - "Unstable language feature '{}' needs to have a section within the \ - 'language features' section of The Unstable Book", - feature_name); - } - // Check for Unstable Book sections that don't have a corresponding unstable feature for feature_name in &unstable_book_lang_features_section_file_names - &unstable_lang_feature_names { @@ -139,4 +116,20 @@ pub fn check(path: &path::Path, bad: &mut bool) { correspond to an unstable language feature", feature_name) } + + // List unstable features that don't have Unstable Book sections + // Remove the comment marker if you want the list printed + /* + println!("Lib features without unstable book sections:"); + for feature_name in &unstable_lang_feature_names - + &unstable_book_lang_features_section_file_names { + println!(" * {} {:?}", feature_name, lib_features[&feature_name].tracking_issue); + } + + println!("Lang features without unstable book sections:"); + for feature_name in &unstable_lib_feature_names- + &unstable_book_lib_features_section_file_names { + println!(" * {} {:?}", feature_name, lang_features[&feature_name].tracking_issue); + } + // */ } diff --git a/src/tools/unstable-book-gen/Cargo.toml b/src/tools/unstable-book-gen/Cargo.toml new file mode 100644 index 000000000000..4751a5e41510 --- /dev/null +++ b/src/tools/unstable-book-gen/Cargo.toml @@ -0,0 +1,9 @@ +[package] +authors = ["est31 ", + "The Rust Project Developers"] +name = "unstable-book-gen" +version = "0.1.0" +license = "MIT/Apache-2.0" + +[dependencies] +tidy = { path = "../tidy" } diff --git a/src/tools/unstable-book-gen/src/SUMMARY.md b/src/tools/unstable-book-gen/src/SUMMARY.md new file mode 100644 index 000000000000..933c928e2f09 --- /dev/null +++ b/src/tools/unstable-book-gen/src/SUMMARY.md @@ -0,0 +1,8 @@ +[The Unstable Book](the-unstable-book.md) + +- [Compiler flags](compiler-flags.md) +{compiler_flags} +- [Language features](language-features.md) +{language_features} +- [Library Features](library-features.md) +{library_features} diff --git a/src/tools/unstable-book-gen/src/main.rs b/src/tools/unstable-book-gen/src/main.rs new file mode 100644 index 000000000000..5c2bd1e3e087 --- /dev/null +++ b/src/tools/unstable-book-gen/src/main.rs @@ -0,0 +1,148 @@ +// 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. + +//! Auto-generate stub docs for the unstable book + +#![deny(warnings)] + +extern crate tidy; + +use tidy::features::{Feature, Features, collect_lib_features, collect_lang_features}; +use tidy::unstable_book::{collect_unstable_feature_names, collect_unstable_book_section_file_names, + PATH_STR, LANG_FEATURES_DIR, LIB_FEATURES_DIR}; +use std::collections::BTreeSet; +use std::io::Write; +use std::fs::{self, File}; +use std::env; +use std::path::Path; + +/// A helper macro to `unwrap` a result except also print out details like: +/// +/// * The file/line of the panic +/// * The expression that failed +/// * The error itself +macro_rules! t { + ($e:expr) => (match $e { + Ok(e) => e, + Err(e) => panic!("{} failed with {}", stringify!($e), e), + }) +} + +fn generate_stub_issue(path: &Path, name: &str, issue: u32) { + let mut file = t!(File::create(path)); + t!(file.write_fmt(format_args!(include_str!("stub-issue.md"), + name = name, + issue = issue))); +} + +fn generate_stub_no_issue(path: &Path, name: &str) { + let mut file = t!(File::create(path)); + t!(file.write_fmt(format_args!(include_str!("stub-no-issue.md"), + name = name))); +} + +fn set_to_summary_str(set: &BTreeSet, dir: &str +) -> String { + set + .iter() + .map(|ref n| format!(" - [{}]({}/{}.md)", + n, + dir, + n.replace('_', "-"))) + .fold("".to_owned(), |s, a| s + &a + "\n") +} + +fn generate_summary(path: &Path, lang_features: &Features, lib_features: &Features) { + let compiler_flags = collect_unstable_book_section_file_names( + &path.join("compiler-flags")); + + let compiler_flags_str = set_to_summary_str(&compiler_flags, + "compiler-flags"); + + let unstable_lang_features = collect_unstable_feature_names(&lang_features); + let unstable_lib_features = collect_unstable_feature_names(&lib_features); + + let lang_features_str = set_to_summary_str(&unstable_lang_features, + LANG_FEATURES_DIR); + let lib_features_str = set_to_summary_str(&unstable_lib_features, + LIB_FEATURES_DIR); + + let mut file = t!(File::create(&path.join("SUMMARY.md"))); + t!(file.write_fmt(format_args!(include_str!("SUMMARY.md"), + compiler_flags = compiler_flags_str, + language_features = lang_features_str, + library_features = lib_features_str))); + +} + +fn has_valid_tracking_issue(f: &Feature) -> bool { + if let Some(n) = f.tracking_issue { + if n > 0 { + return true; + } + } + false +} + +fn generate_unstable_book_files(src :&Path, out: &Path, features :&Features) { + let unstable_features = collect_unstable_feature_names(features); + let unstable_section_file_names = collect_unstable_book_section_file_names(src); + t!(fs::create_dir_all(&out)); + for feature_name in &unstable_features - &unstable_section_file_names { + let file_name = format!("{}.md", feature_name.replace('_', "-")); + let out_file_path = out.join(&file_name); + let feature = &features[&feature_name]; + + if has_valid_tracking_issue(&feature) { + generate_stub_issue(&out_file_path, &feature_name, feature.tracking_issue.unwrap()); + } else { + generate_stub_no_issue(&out_file_path, &feature_name); + } + } +} + +fn copy_recursive(path: &Path, to: &Path) { + for entry in t!(fs::read_dir(path)) { + let e = t!(entry); + let t = t!(e.metadata()); + let dest = &to.join(e.file_name()); + if t.is_file() { + t!(fs::copy(&e.path(), dest)); + } else if t.is_dir() { + t!(fs::create_dir_all(dest)); + copy_recursive(&e.path(), dest); + } + } +} + +fn main() { + let src_path_str = env::args_os().skip(1).next().expect("source path required"); + let dest_path_str = env::args_os().skip(2).next().expect("destination path required"); + let src_path = Path::new(&src_path_str); + let dest_path = Path::new(&dest_path_str).join("src"); + + let lang_features = collect_lang_features(src_path); + let lib_features = collect_lib_features(src_path); + + let doc_src_path = src_path.join(PATH_STR); + + t!(fs::create_dir_all(&dest_path)); + + generate_unstable_book_files(&doc_src_path.join(LANG_FEATURES_DIR), + &dest_path.join(LANG_FEATURES_DIR), + &lang_features); + generate_unstable_book_files(&doc_src_path.join(LIB_FEATURES_DIR), + &dest_path.join(LIB_FEATURES_DIR), + &lib_features); + + copy_recursive(&doc_src_path, &dest_path); + + generate_summary(&dest_path, &lang_features, &lib_features); +} diff --git a/src/tools/unstable-book-gen/src/stub-issue.md b/src/tools/unstable-book-gen/src/stub-issue.md new file mode 100644 index 000000000000..8698fb7278f6 --- /dev/null +++ b/src/tools/unstable-book-gen/src/stub-issue.md @@ -0,0 +1,7 @@ +# `{name}` + +The tracking issue for this feature is: [#{issue}] + +[#{issue}]: https://github.com/rust-lang/rust/issues/{issue} + +------------------------ diff --git a/src/tools/unstable-book-gen/src/stub-no-issue.md b/src/tools/unstable-book-gen/src/stub-no-issue.md new file mode 100644 index 000000000000..3da140633d0f --- /dev/null +++ b/src/tools/unstable-book-gen/src/stub-no-issue.md @@ -0,0 +1,5 @@ +# `{name}` + +This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use. + +------------------------