EXE=$(echo $CORE | sed 's|obj/cores/core\.[0-9]*\.!checkout!\(.*\)|\1|;y|!|/|');
if [ -f "$EXE" ]; then
printf travis_fold":start:crashlog\n\033[31;1m%s\033[0m\n" "$CORE";
- gdb -q -c "$CORE" "$EXE"
+ gdb --batch -q -c "$CORE" "$EXE"
-iex 'set auto-load off'
-iex 'dir src/'
-iex 'set sysroot .'
dependencies = [
"compiler_builtins 0.0.0",
"core 0.0.0",
- "rand 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
version = "0.0.0"
dependencies = [
"build_helper 0.1.0",
- "cc 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
"compiler_builtins 0.0.0",
"core 0.0.0",
"libc 0.0.0",
version = "0.1.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cc 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
]
version = "0.0.0"
dependencies = [
"build_helper 0.1.0",
- "cc 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
"cmake 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)",
"filetime 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"getopts 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
version = "1.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
+[[package]]
+name = "bytesize"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
[[package]]
name = "cargo"
-version = "0.31.0"
+version = "0.32.0"
dependencies = [
"atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"bufstream 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bytesize 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
"core-foundation 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "crates-io 0.19.0",
+ "crates-io 0.20.0",
"crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"crypto-hash 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "curl 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)",
+ "curl 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.5.12 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"filetime 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazycell 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
- "libgit2-sys 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libgit2-sys 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
[[package]]
name = "cc"
-version = "1.0.22"
+version = "1.0.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
version = "0.1.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cc 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "compiler_builtins"
version = "0.0.0"
dependencies = [
- "cc 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
"core 0.0.0",
]
name = "core"
version = "0.0.0"
dependencies = [
- "rand 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
[[package]]
name = "crates-io"
-version = "0.19.0"
+version = "0.20.0"
dependencies = [
- "curl 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)",
+ "curl 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.75 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam-epoch 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam-utils 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "curl"
-version = "0.4.14"
+version = "0.4.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "curl-sys 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "curl-sys 0.4.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.43 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
[[package]]
name = "curl-sys"
-version = "0.4.8"
+version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cc 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
- "libz-sys 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libnghttp2-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libz-sys 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl-sys 0.9.35 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
"vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
+[[package]]
+name = "getset"
+version = "0.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.13.11 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "git2"
version = "0.7.5"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
- "libgit2-sys 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libgit2-sys 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl-sys 0.9.35 (registry+https://github.com/rust-lang/crates.io-index)",
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "curl 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)",
+ "curl 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)",
"git2 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
[[package]]
name = "libgit2-sys"
-version = "0.7.7"
+version = "0.7.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cc 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)",
- "cmake 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)",
- "curl-sys 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
+ "curl-sys 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
- "libssh2-sys 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "libz-sys 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libssh2-sys 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libz-sys 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl-sys 0.9.35 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "libnghttp2-sys"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "libssh2-sys"
-version = "0.2.10"
+version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cmake 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
- "libz-sys 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libz-sys 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl-sys 0.9.35 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
"vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
[[package]]
name = "libz-sys"
-version = "1.0.20"
+version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cc 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
"vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cc 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
"filetime 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cc 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
]
"colored 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"compiletest_rs 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.5.12 (registry+https://github.com/rust-lang/crates.io-index)",
- "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "regex 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "vergen 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
version = "110.0.7+1.1.0i"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cc 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
version = "0.9.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cc 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl-src 110.0.7+1.1.0i (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
name = "profiler_builtins"
version = "0.0.0"
dependencies = [
- "cc 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
"compiler_builtins 0.0.0",
"core 0.0.0",
]
[[package]]
name = "rand"
-version = "0.5.4"
+version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
name = "rls"
version = "0.130.5"
dependencies = [
- "cargo 0.31.0",
+ "cargo 0.32.0",
"cargo_metadata 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"clippy_lints 0.0.212",
"crossbeam-channel 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ordslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"racer 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-analysis 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)",
name = "rustc_codegen_llvm"
version = "0.0.0"
dependencies = [
- "cc 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
"memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
version = "0.0.0"
dependencies = [
"atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_cratesio_shim 0.0.0",
"rustc_data_structures 0.0.0",
"serialize 0.0.0",
dependencies = [
"graphviz 0.0.0",
"log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc 0.0.0",
"rustc_data_structures 0.0.0",
"rustc_fs_util 0.0.0",
version = "0.0.0"
dependencies = [
"build_helper 0.1.0",
- "cc 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
version = "0.0.0"
dependencies = [
"minifier 0.0.19 (registry+https://github.com/rust-lang/crates.io-index)",
+ "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
"pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"tempfile 3.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
"alloc_jemalloc 0.0.0",
"alloc_system 0.0.0",
"build_helper 0.1.0",
- "cc 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
"compiler_builtins 0.0.0",
"core 0.0.0",
"libc 0.0.0",
"panic_abort 0.0.0",
"panic_unwind 0.0.0",
"profiler_builtins 0.0.0",
- "rand 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_asan 0.0.0",
"rustc_lsan 0.0.0",
"rustc_msan 0.0.0",
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
"remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
+[[package]]
+name = "vergen"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "chrono 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "getset 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "version_check"
version = "0.1.4"
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
"checksum bufstream 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f2f382711e76b9de6c744cc00d0497baba02fb00a787f088c879f01d09468e32"
"checksum byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "74c0b906e9446b0a2e4f760cdb3fa4b2c48cdc6db8766a845c54b6ff063fd2e9"
+"checksum bytesize 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "716960a18f978640f25101b5cbf1c6f6b0d3192fab36a2d98ca96f0ecbe41010"
"checksum cargo_metadata 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d6809b327f87369e6f3651efd2c5a96c49847a3ed2559477ecba79014751ee1"
-"checksum cc 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)" = "4a6007c146fdd28d4512a794b07ffe9d8e89e6bf86e2e0c4ddff2e1fb54a0007"
+"checksum cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "f159dfd43363c4d08055a07703eb7a3406b0dac4d0584d96965a3262db3c9d16"
"checksum cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0c4e7bb64a8ebb0d856483e1e682ea3422f883c5f5615a90d51a2c82fe87fdd3"
"checksum chalk-engine 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "25ce2f28f55ed544a2a3756b7acf41dd7d6f27acffb2086439950925506af7d0"
"checksum chalk-macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "295635afd6853aa9f20baeb7f0204862440c0fe994c5a253d5f479dac41d047e"
"checksum crossbeam-utils 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ea52fab26a99d96cdff39d0ca75c9716125937f5dba2ab83923aaaf5928f684a"
"checksum crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "677d453a17e8bd2b913fa38e8b9cf04bcdbb5be790aa294f2389661d72036015"
"checksum crypto-hash 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "09de9ee0fc255ace04c7fa0763c9395a945c37c8292bb554f8d48361d1dcf1b4"
-"checksum curl 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)" = "444c2f9e71458b34e75471ed8d756947a0bb920b8b8b9bfc56dfcc4fc6819a13"
-"checksum curl-sys 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "981bd902fcd8b8b999cf71b81447e27d66c3493a7f62f1372866fd32986c0c82"
+"checksum curl 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)" = "c8172e96ecfb1a2bfe3843d9d7154099a15130cf4a2f658259c7aa9cc2b5d4ff"
+"checksum curl-sys 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "2edeedbbd9c7cdccb14bfb5dfbcc108901f99d3411eb5bab3758789377c5bec4"
"checksum datafrog 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "16d724bf4ffe77cdceeecd461009b5f8d9e23c5d645d68bedb4586bf43e7e142"
"checksum derive-new 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ceed73957c449214f8440eec8ad7fa282b67dc9eacbb24a3085b15d60397a17a"
"checksum derive_more 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46c7f14685a20f5dd08e7f754f2ea8cc064d8f4214ae21116c106a2768ba7b9b"
"checksum futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "1a70b146671de62ec8c8ed572219ca5d594d9b06c0b364d5e67b722fc559b48c"
"checksum fwdansi 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "34dd4c507af68d37ffef962063dfa1944ce0dd4d5b82043dbab1dabe088610c3"
"checksum getopts 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "b900c08c1939860ce8b54dc6a89e26e00c04c380fd0e09796799bd7f12861e05"
+"checksum getset 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "54c7f36a235738bb25904d6a2b3dbb28f6f5736cd3918c4bf80d6bb236200782"
"checksum git2 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)" = "591f8be1674b421644b6c030969520bc3fa12114d2eb467471982ed3e9584e71"
"checksum git2-curl 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b502f6b1b467957403d168f0039e0c46fa6a1220efa2adaef25d5b267b5fe024"
"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
"checksum lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca488b89a5657b0a2ecd45b95609b3e848cf1755da332a0da46e2b2b1cb371a7"
"checksum lazycell 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d33a48d0365c96081958cc663eef834975cb1e8d8bea3378513fc72bdbf11e50"
"checksum libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)" = "76e3a3ef172f1a0b9a9ff0dd1491ae5e6c948b94479a3021819ba7d860c8645d"
-"checksum libgit2-sys 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6ab62b46003ba97701554631fa570d9f7e7947e2480ae3d941e555a54a2c0f05"
-"checksum libssh2-sys 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "10dbc0957a27626444f5a3f523e6b97a70c3d702999bf1c7161cfbe7a25a9368"
-"checksum libz-sys 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)" = "f5f9aba969b3c45fe9c94bec65895868a9ceca9a600699f4054b75747a19c7c6"
+"checksum libgit2-sys 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)" = "93f2b22fce91fb820363cf88a849a8f8fdfd8be37774b6a9dd6cbda05cf940e6"
+"checksum libnghttp2-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ffbfb81475cc9f625e44f3a8f8b9cf7173815ae1c7cc2fa91853ec009e38198"
+"checksum libssh2-sys 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "126a1f4078368b163bfdee65fbab072af08a1b374a5551b21e87ade27b1fbf9d"
+"checksum libz-sys 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)" = "65ff614643d7635dfa2151913d95c4ee90ee1fe15d9e0980f4dcb1a7e5837c18"
"checksum lock_api 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "949826a5ccf18c1b3a7c3d57692778d21768b79e46eb9dd07bfc4c2160036c54"
"checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b"
"checksum log 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cba860f648db8e6f269df990180c2217f333472b4a6e901e97446858487971e2"
"checksum quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dd636425967c33af890042c483632d33fa7a18f19ad1d7ea72e8998c6ef8dea5"
"checksum racer 2.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1e4bc3847329b20ff5ba56c298938c179ae9911af15c9c10553f683b65164533"
"checksum rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8356f47b32624fef5b3301c1be97e5944ecdd595409cc5da11d05f211db6cfbd"
-"checksum rand 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "12397506224b2f93e6664ffc4f664b29be8208e5157d3d90b44f09b5fae470ea"
+"checksum rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e464cd887e869cddcae8792a4ee31d23c7edd516700695608f5b98c67ee0131c"
"checksum rand_core 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "edecf0f94da5551fc9b492093e30b041a891657db7940ee221f9d2f66e82eef2"
"checksum rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "80e811e76f1dbf68abf87a759083d34600017fc4e10b6bd5ad84a700f9dba4b1"
"checksum rayon-core 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9d24ad214285a7729b174ed6d3bcfcb80177807f959d95fafd5bfc5c4f201ac8"
"checksum utf8-ranges 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd70f467df6810094968e2fce0ee1bd0e87157aceb026a8c083bcf5e25b9efe4"
"checksum vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "def296d3eb3b12371b2c7d0e83bfe1403e4db2d7a0bba324a12b21c4ee13143d"
"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
+"checksum vergen 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9a16834fc61e1492c07dae49b6c14b55f8b1d43a5f5f9e9a2ecc063f47b9f93c"
"checksum version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7716c242968ee87e5542f8021178248f267f295a5c4803beae8b8b7fd9bc6051"
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
"checksum walkdir 2.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "af464bc7be7b785c7ac72e266a6b67c4c9070155606f51655a650a6686204e35"
) -> Command {
let mut cargo = Command::new(&self.initial_cargo);
let out_dir = self.stage_out(compiler, mode);
+
+ // command specific path, we call clear_if_dirty with this
+ let mut my_out = match cmd {
+ "build" => self.cargo_out(compiler, mode, target),
+
+ // This is the intended out directory for crate documentation.
+ "doc" => self.crate_doc_out(target),
+
+ _ => self.stage_out(compiler, mode),
+ };
+
+ // This is for the original compiler, but if we're forced to use stage 1, then
+ // std/test/rustc stamps won't exist in stage 2, so we need to get those from stage 1, since
+ // we copy the libs forward.
+ let cmp = if self.force_use_stage1(compiler, target) {
+ self.compiler(1, compiler.host)
+ } else {
+ compiler
+ };
+
+ let libstd_stamp = match cmd {
+ "check" => check::libstd_stamp(self, cmp, target),
+ _ => compile::libstd_stamp(self, cmp, target),
+ };
+
+ let libtest_stamp = match cmd {
+ "check" => check::libtest_stamp(self, cmp, target),
+ _ => compile::libstd_stamp(self, cmp, target),
+ };
+
+ let librustc_stamp = match cmd {
+ "check" => check::librustc_stamp(self, cmp, target),
+ _ => compile::librustc_stamp(self, cmp, target),
+ };
+
+ if cmd == "doc" {
+ if mode == Mode::Rustc || mode == Mode::ToolRustc || mode == Mode::Codegen {
+ // This is the intended out directory for compiler documentation.
+ my_out = self.compiler_doc_out(target);
+ }
+ let rustdoc = self.rustdoc(compiler.host);
+ self.clear_if_dirty(&my_out, &rustdoc);
+ } else if cmd != "test" {
+ match mode {
+ Mode::Std => {
+ self.clear_if_dirty(&my_out, &self.rustc(compiler));
+ },
+ Mode::Test => {
+ self.clear_if_dirty(&my_out, &libstd_stamp);
+ },
+ Mode::Rustc => {
+ self.clear_if_dirty(&my_out, &self.rustc(compiler));
+ self.clear_if_dirty(&my_out, &libstd_stamp);
+ self.clear_if_dirty(&my_out, &libtest_stamp);
+ },
+ Mode::Codegen => {
+ self.clear_if_dirty(&my_out, &librustc_stamp);
+ },
+ Mode::ToolBootstrap => { },
+ Mode::ToolStd => {
+ self.clear_if_dirty(&my_out, &libstd_stamp);
+ },
+ Mode::ToolTest => {
+ self.clear_if_dirty(&my_out, &libstd_stamp);
+ self.clear_if_dirty(&my_out, &libtest_stamp);
+ },
+ Mode::ToolRustc => {
+ self.clear_if_dirty(&my_out, &libstd_stamp);
+ self.clear_if_dirty(&my_out, &libtest_stamp);
+ self.clear_if_dirty(&my_out, &librustc_stamp);
+ },
+ }
+ }
+
cargo
.env("CARGO_TARGET_DIR", out_dir)
.arg(cmd);
use compile::{run_cargo, std_cargo, test_cargo, rustc_cargo, rustc_cargo_env, add_to_sysroot};
use builder::{RunConfig, Builder, ShouldRun, Step};
-use tool::{self, prepare_tool_cargo, SourceType};
+use tool::{prepare_tool_cargo, SourceType};
use {Compiler, Mode};
use cache::{INTERNER, Interned};
use std::path::PathBuf;
let target = self.target;
let compiler = builder.compiler(0, builder.config.build);
- let out_dir = builder.stage_out(compiler, Mode::Std);
- builder.clear_if_dirty(&out_dir, &builder.rustc(compiler));
-
let mut cargo = builder.cargo(compiler, Mode::Std, target, "check");
std_cargo(builder, &compiler, target, &mut cargo);
let _folder = builder.fold_output(|| format!("stage{}-std", compiler.stage));
- println!("Checking std artifacts ({} -> {})", &compiler.host, target);
+ builder.info(&format!("Checking std artifacts ({} -> {})", &compiler.host, target));
run_cargo(builder,
&mut cargo,
vec![],
let compiler = builder.compiler(0, builder.config.build);
let target = self.target;
- let stage_out = builder.stage_out(compiler, Mode::Rustc);
- builder.clear_if_dirty(&stage_out, &libstd_stamp(builder, compiler, target));
- builder.clear_if_dirty(&stage_out, &libtest_stamp(builder, compiler, target));
+ builder.ensure(Test { target });
let mut cargo = builder.cargo(compiler, Mode::Rustc, target, "check");
rustc_cargo(builder, &mut cargo);
let _folder = builder.fold_output(|| format!("stage{}-rustc", compiler.stage));
- println!("Checking compiler artifacts ({} -> {})", &compiler.host, target);
+ builder.info(&format!("Checking compiler artifacts ({} -> {})", &compiler.host, target));
run_cargo(builder,
&mut cargo,
vec![],
let target = self.target;
let backend = self.backend;
- let out_dir = builder.cargo_out(compiler, Mode::Codegen, target);
- builder.clear_if_dirty(&out_dir, &librustc_stamp(builder, compiler, target));
+ builder.ensure(Rustc { target });
let mut cargo = builder.cargo(compiler, Mode::Codegen, target, "check");
cargo.arg("--manifest-path").arg(builder.src.join("src/librustc_codegen_llvm/Cargo.toml"));
let compiler = builder.compiler(0, builder.config.build);
let target = self.target;
- let out_dir = builder.stage_out(compiler, Mode::Test);
- builder.clear_if_dirty(&out_dir, &libstd_stamp(builder, compiler, target));
+ builder.ensure(Std { target });
let mut cargo = builder.cargo(compiler, Mode::Test, target, "check");
test_cargo(builder, &compiler, target, &mut cargo);
let _folder = builder.fold_output(|| format!("stage{}-test", compiler.stage));
- println!("Checking test artifacts ({} -> {})", &compiler.host, target);
+ builder.info(&format!("Checking test artifacts ({} -> {})", &compiler.host, target));
run_cargo(builder,
&mut cargo,
vec![],
let compiler = builder.compiler(0, builder.config.build);
let target = self.target;
- let stage_out = builder.stage_out(compiler, Mode::ToolRustc);
- builder.clear_if_dirty(&stage_out, &libstd_stamp(builder, compiler, target));
- builder.clear_if_dirty(&stage_out, &libtest_stamp(builder, compiler, target));
- builder.clear_if_dirty(&stage_out, &librustc_stamp(builder, compiler, target));
+ builder.ensure(Rustc { target });
let mut cargo = prepare_tool_cargo(builder,
compiler,
let libdir = builder.sysroot_libdir(compiler, target);
add_to_sysroot(&builder, &libdir, &rustdoc_stamp(builder, compiler, target));
-
- builder.ensure(tool::CleanTools {
- compiler,
- target,
- cause: Mode::Rustc,
- });
+ builder.cargo(compiler, Mode::ToolRustc, target, "clean");
}
}
use util::{exe, libdir, is_dylib, CiEnv};
use {Compiler, Mode, GitRepo};
use native;
-use tool;
use cache::{INTERNER, Interned};
use builder::{Step, RunConfig, ShouldRun, Builder};
copy_musl_third_party_objects(builder, target, &libdir);
}
- let out_dir = builder.cargo_out(compiler, Mode::Std, target);
- builder.clear_if_dirty(&out_dir, &builder.rustc(compiler));
let mut cargo = builder.cargo(compiler, Mode::Std, target, "build");
std_cargo(builder, &compiler, target, &mut cargo);
copy_apple_sanitizer_dylibs(builder, &builder.native_dir(target), "osx", &libdir);
}
- builder.ensure(tool::CleanTools {
- compiler: target_compiler,
- target,
- cause: Mode::Std,
- });
+ builder.cargo(target_compiler, Mode::ToolStd, target, "clean");
}
}
return;
}
- let out_dir = builder.cargo_out(compiler, Mode::Test, target);
- builder.clear_if_dirty(&out_dir, &libstd_stamp(builder, compiler, target));
let mut cargo = builder.cargo(compiler, Mode::Test, target, "build");
test_cargo(builder, &compiler, target, &mut cargo);
target));
add_to_sysroot(builder, &builder.sysroot_libdir(target_compiler, target),
&libtest_stamp(builder, compiler, target));
- builder.ensure(tool::CleanTools {
- compiler: target_compiler,
- target,
- cause: Mode::Test,
- });
+
+ builder.cargo(target_compiler, Mode::ToolTest, target, "clean");
}
}
compiler: builder.compiler(self.compiler.stage, builder.config.build),
target: builder.config.build,
});
- let cargo_out = builder.cargo_out(compiler, Mode::Rustc, target);
- builder.clear_if_dirty(&cargo_out, &libstd_stamp(builder, compiler, target));
- builder.clear_if_dirty(&cargo_out, &libtest_stamp(builder, compiler, target));
let mut cargo = builder.cargo(compiler, Mode::Rustc, target, "build");
rustc_cargo(builder, &mut cargo);
target));
add_to_sysroot(builder, &builder.sysroot_libdir(target_compiler, target),
&librustc_stamp(builder, compiler, target));
- builder.ensure(tool::CleanTools {
- compiler: target_compiler,
- target,
- cause: Mode::Rustc,
- });
+ builder.cargo(target_compiler, Mode::ToolRustc, target, "clean");
}
}
}
let out_dir = builder.cargo_out(compiler, Mode::Codegen, target);
- builder.clear_if_dirty(&out_dir, &librustc_stamp(builder, compiler, target));
let mut cargo = builder.cargo(compiler, Mode::Codegen, target, "rustc");
cargo.arg("--manifest-path")
let out = builder.doc_out(target);
t!(fs::create_dir_all(&out));
let compiler = builder.compiler(stage, builder.config.build);
- let rustdoc = builder.rustdoc(compiler.host);
let compiler = if builder.force_use_stage1(compiler, target) {
builder.compiler(1, compiler.host)
} else {
// This way rustdoc generates output directly into the output, and rustdoc
// will also directly handle merging.
let my_out = builder.crate_doc_out(target);
- builder.clear_if_dirty(&my_out, &rustdoc);
t!(symlink_dir_force(&builder.config, &my_out, &out_dir));
let mut cargo = builder.cargo(compiler, Mode::Std, target, "doc");
let out = builder.doc_out(target);
t!(fs::create_dir_all(&out));
let compiler = builder.compiler(stage, builder.config.build);
- let rustdoc = builder.rustdoc(compiler.host);
let compiler = if builder.force_use_stage1(compiler, target) {
builder.compiler(1, compiler.host)
} else {
// See docs in std above for why we symlink
let my_out = builder.crate_doc_out(target);
- builder.clear_if_dirty(&my_out, &rustdoc);
t!(symlink_dir_force(&builder.config, &my_out, &out_dir));
let mut cargo = builder.cargo(compiler, Mode::Test, target, "doc");
let out = builder.doc_out(target);
t!(fs::create_dir_all(&out));
let compiler = builder.compiler(stage, builder.config.build);
- let rustdoc = builder.rustdoc(compiler.host);
let compiler = if builder.force_use_stage1(compiler, target) {
builder.compiler(1, compiler.host)
} else {
// See docs in std above for why we symlink
let my_out = builder.crate_doc_out(target);
- builder.clear_if_dirty(&my_out, &rustdoc);
t!(symlink_dir_force(&builder.config, &my_out, &out_dir));
let mut cargo = builder.cargo(compiler, Mode::Rustc, target, "doc");
// Get the correct compiler for this stage.
let compiler = builder.compiler(stage, builder.config.build);
- let rustdoc = builder.rustdoc(compiler.host);
let compiler = if builder.force_use_stage1(compiler, target) {
builder.compiler(1, compiler.host)
} else {
// We do not symlink to the same shared folder that already contains std library
// documentation from previous steps as we do not want to include that.
let out_dir = builder.stage_out(compiler, Mode::Rustc).join(target).join("doc");
- builder.clear_if_dirty(&out, &rustdoc);
t!(symlink_dir_force(&builder.config, &out, &out_dir));
// Build cargo command.
// Get the correct compiler for this stage.
let compiler = builder.compiler(stage, builder.config.build);
- let rustdoc = builder.rustdoc(compiler.host);
let compiler = if builder.force_use_stage1(compiler, target) {
builder.compiler(1, compiler.host)
} else {
.join(target)
.join("doc");
t!(fs::create_dir_all(&out_dir));
- builder.clear_if_dirty(&out, &rustdoc);
t!(symlink_dir_force(&builder.config, &out, &out_dir));
// Build cargo command.
/// Compile a tool which uses all libraries we compile (up to rustc).
/// Doesn't use the stage0 compiler libraries like "other", and includes
/// tools like rustdoc, cargo, rls, etc.
+ ToolTest,
ToolStd,
ToolRustc,
}
Mode::Codegen => "-codegen",
Mode::ToolBootstrap => "-bootstrap-tools",
Mode::ToolStd => "-tools",
+ Mode::ToolTest => "-tools",
Mode::ToolRustc => "-tools",
};
self.out.join(&*compiler.host)
compare_mode: "nll"
});
-default_test!(RunPass {
+default_test_with_compare_mode!(RunPass {
path: "src/test/run-pass",
mode: "run-pass",
- suite: "run-pass"
+ suite: "run-pass",
+ compare_mode: "nll"
});
default_test!(CompileFail {
use Compiler;
use builder::{Step, RunConfig, ShouldRun, Builder};
use util::{exe, add_lib_path};
-use compile::{self, libtest_stamp, libstd_stamp, librustc_stamp};
+use compile;
use native;
use channel::GitInfo;
use cache::Interned;
use toolstate::ToolState;
-#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
-pub struct CleanTools {
- pub compiler: Compiler,
- pub target: Interned<String>,
- pub cause: Mode,
-}
-
-impl Step for CleanTools {
- type Output = ();
-
- fn should_run(run: ShouldRun) -> ShouldRun {
- run.never()
- }
-
- fn run(self, builder: &Builder) {
- let compiler = self.compiler;
- let target = self.target;
- let cause = self.cause;
-
- // This is for the original compiler, but if we're forced to use stage 1, then
- // std/test/rustc stamps won't exist in stage 2, so we need to get those from stage 1, since
- // we copy the libs forward.
- let tools_dir = builder.stage_out(compiler, Mode::ToolRustc);
- let compiler = if builder.force_use_stage1(compiler, target) {
- builder.compiler(1, compiler.host)
- } else {
- compiler
- };
-
- for &cur_mode in &[Mode::Std, Mode::Test, Mode::Rustc] {
- let stamp = match cur_mode {
- Mode::Std => libstd_stamp(builder, compiler, target),
- Mode::Test => libtest_stamp(builder, compiler, target),
- Mode::Rustc => librustc_stamp(builder, compiler, target),
- _ => panic!(),
- };
-
- if builder.clear_if_dirty(&tools_dir, &stamp) {
- break;
- }
-
- // If we are a rustc tool, and std changed, we also need to clear ourselves out -- our
- // dependencies depend on std. Therefore, we iterate up until our own mode.
- if cause == cur_mode {
- break;
- }
- }
- }
-}
-
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub enum SourceType {
InTree,
+++ /dev/null
-# Rust documentations
-
-## Building
-
-To generate all the docs, follow the "Building Documentation" instructions in
-the README in the root of the repository. This will convert the distributed
-Markdown docs to HTML and generate HTML doc for the books, 'std' and 'extra'
-libraries.
-
-To generate HTML documentation from one source file/crate, do something like:
-
-~~~~text
-rustdoc --output html-doc/ --output-format html ../src/libstd/path.rs
-~~~~
-
-(This, of course, requires a working build of the `rustdoc` tool.)
-
-## Additional notes
-
-To generate an HTML version of a doc from Markdown manually, you can do
-something like:
-
-~~~~text
-rustdoc reference.md
-~~~~
-
-(`reference.md` being the Rust Reference Manual.)
-
-An overview of how to use the `rustdoc` command is available [in the docs][1].
-Further details are available from the command line by with `rustdoc --help`.
-
-[1]: https://github.com/rust-lang/rust/blob/master/src/doc/rustdoc/src/what-is-rustdoc.md
-Subproject commit cff0930664b688f1dd22aefb3d16944eb4cdbfd5
+Subproject commit fa91738b66367b6f70b078251868a071f1991ace
with explanations of how to use various things, as well as example code for
accomplishing various tasks.
+<div>
+ <form action="std/index.html" method="get">
+ <input type="search" name="search"/>
+ <button>Search</button>
+ </form>
+</div>
+
## The Rustc Book
[The Rustc Book](rustc/index.html) describes the Rust compiler, `rustc`.
+++ /dev/null
-# `crate_in_paths`
-
-The tracking issue for this feature is: [#44660]
-
-[#44660]: https://github.com/rust-lang/rust/issues/44660
-
-------------------------
-
-The `crate_in_paths` feature allows to explicitly refer to the crate root in absolute paths
-using keyword `crate`.
-
-This feature is required in `feature(extern_absolute_paths)` mode to refer to any absolute path
-in the local crate (absolute paths refer to extern crates by default in that mode), but can be
-used without `feature(extern_absolute_paths)` as well.
-
-```rust
-#![feature(crate_in_paths)]
-
-// Imports, `::` is added implicitly
-use crate::m::f;
-use crate as root;
-
-mod m {
- pub fn f() -> u8 { 1 }
- pub fn g() -> u8 { 2 }
- pub fn h() -> u8 { 3 }
-
- // OK, visibilities implicitly add starting `::` as well, like imports
- pub(in crate::m) struct S;
-}
-
-mod n
-{
- use crate::m::f;
- use crate as root;
- pub fn check() {
- assert_eq!(f(), 1);
- assert_eq!(crate::m::g(), 2);
- assert_eq!(root::m::h(), 3);
- }
-}
-
-fn main() {
- assert_eq!(f(), 1);
- assert_eq!(crate::m::g(), 2);
- assert_eq!(root::m::h(), 3);
- n::check();
-}
-```
+++ /dev/null
-# `extern_absolute_paths`
-
-The tracking issue for this feature is: [#44660]
-
-[#44660]: https://github.com/rust-lang/rust/issues/44660
-
-------------------------
-
-The `extern_absolute_paths` feature enables mode allowing to refer to names from other crates
-"inline", without introducing `extern crate` items, using absolute paths like `::my_crate::a::b`.
-
-`::my_crate::a::b` will resolve to path `a::b` in crate `my_crate`.
-
-`feature(crate_in_paths)` can be used in `feature(extern_absolute_paths)` mode for referring
-to absolute paths in the local crate (`crate::a::b`).
-
-`feature(extern_in_paths)` provides the same effect by using keyword `extern` to refer to
-paths from other crates (`extern::my_crate::a::b`).
-
-```rust,ignore
-#![feature(extern_absolute_paths)]
-
-// Suppose we have a dependency crate `xcrate` available through `Cargo.toml`, or `--extern`
-// options, or standard Rust distribution, or some other means.
-
-use xcrate::Z;
-
-fn f() {
- use xcrate;
- use xcrate as ycrate;
- let s = xcrate::S;
- assert_eq!(format!("{:?}", s), "S");
- let z = ycrate::Z;
- assert_eq!(format!("{:?}", z), "Z");
-}
-
-fn main() {
- let s = ::xcrate::S;
- assert_eq!(format!("{:?}", s), "S");
- let z = Z;
- assert_eq!(format!("{:?}", z), "Z");
-}
-```
use core::iter::FusedIterator;
use core::marker::{Unpin, Unsize};
use core::mem;
-use core::pin::PinMut;
+use core::pin::Pin;
use core::ops::{CoerceUnsized, Deref, DerefMut, Generator, GeneratorState};
use core::ptr::{self, NonNull, Unique};
use core::task::{Context, Poll, Spawn, SpawnErrorKind, SpawnObjError};
use raw_vec::RawVec;
-use pin::PinBox;
use str::from_boxed_utf8_unchecked;
/// A pointer type for heap allocation.
pub fn new(x: T) -> Box<T> {
box x
}
+
+ #[unstable(feature = "pin", issue = "49150")]
+ #[inline(always)]
+ pub fn pinned(x: T) -> Pin<Box<T>> {
+ (box x).into()
+ }
}
impl<T: ?Sized> Box<T> {
}
}
+#[unstable(feature = "pin", issue = "49150")]
+impl<T> From<Box<T>> for Pin<Box<T>> {
+ fn from(boxed: Box<T>) -> Self {
+ // It's not possible to move or replace the insides of a `Pin<Box<T>>`
+ // when `T: !Unpin`, so it's safe to pin it directly without any
+ // additional requirements.
+ unsafe { Pin::new_unchecked(boxed) }
+ }
+}
+
#[stable(feature = "box_from_slice", since = "1.17.0")]
impl<'a, T: Copy> From<&'a [T]> for Box<[T]> {
fn from(slice: &'a [T]) -> Box<[T]> {
impl<F: ?Sized + Future + Unpin> Future for Box<F> {
type Output = F::Output;
- fn poll(mut self: PinMut<Self>, cx: &mut Context) -> Poll<Self::Output> {
- PinMut::new(&mut **self).poll(cx)
+ fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
+ F::poll(Pin::new(&mut *self), cx)
}
}
unsafe fn poll(ptr: *mut (), cx: &mut Context) -> Poll<T> {
let ptr = ptr as *mut F;
- let pin: PinMut<F> = PinMut::new_unchecked(&mut *ptr);
- pin.poll(cx)
+ let pin: Pin<&mut F> = Pin::new_unchecked(&mut *ptr);
+ F::poll(pin, cx)
}
unsafe fn drop(ptr: *mut ()) {
}
}
-#[unstable(feature = "pin", issue = "49150")]
-impl<T: Unpin + ?Sized> From<PinBox<T>> for Box<T> {
- fn from(pinned: PinBox<T>) -> Box<T> {
- unsafe { PinBox::unpin(pinned) }
+#[unstable(feature = "futures_api", issue = "50547")]
+impl<'a, F: Future<Output = ()> + Send + 'a> From<Pin<Box<F>>> for FutureObj<'a, ()> {
+ fn from(boxed: Pin<Box<F>>) -> Self {
+ FutureObj::new(boxed)
+ }
+}
+
+#[unstable(feature = "futures_api", issue = "50547")]
+impl<'a, F: Future<Output = ()> + 'a> From<Pin<Box<F>>> for LocalFutureObj<'a, ()> {
+ fn from(boxed: Pin<Box<F>>) -> Self {
+ LocalFutureObj::new(boxed)
}
}
pub mod sync;
pub mod rc;
pub mod raw_vec;
-pub mod pin;
pub mod prelude;
pub mod borrow;
pub mod fmt;
+++ /dev/null
-//! Types which pin data to its location in memory
-//!
-//! It is sometimes useful to have objects that are guaranteed to not move,
-//! in the sense that their placement in memory does not change, and can thus be relied upon.
-//!
-//! A prime example of such a scenario would be building self-referencial structs,
-//! since moving an object with pointers to itself will invalidate them,
-//! which could cause undefined behavior.
-//!
-//! In order to prevent objects from moving, they must be *pinned*,
-//! by wrapping the data in pinning pointer types, such as [`PinMut`] and [`PinBox`],
-//! which are otherwise equivalent to `& mut` and [`Box`], respectively.
-//!
-//! First of all, these are pointer types because pinned data mustn't be passed around by value
-//! (that would change its location in memory).
-//! Secondly, since data can be moved out of `&mut` and [`Box`] with functions such as [`swap`],
-//! which causes their contents to swap places in memory,
-//! we need dedicated types that prohibit such operations.
-//!
-//! However, these restrictions are usually not necessary,
-//! so most types implement the [`Unpin`] auto-trait,
-//! which indicates that the type can be moved out safely.
-//! Doing so removes the limitations of pinning types,
-//! making them the same as their non-pinning counterparts.
-//!
-//! [`PinMut`]: struct.PinMut.html
-//! [`PinBox`]: struct.PinBox.html
-//! [`Unpin`]: trait.Unpin.html
-//! [`swap`]: ../../std/mem/fn.swap.html
-//! [`Box`]: ../boxed/struct.Box.html
-//!
-//! # Examples
-//!
-//! ```rust
-//! #![feature(pin)]
-//!
-//! use std::pin::PinBox;
-//! use std::marker::Pinned;
-//! use std::ptr::NonNull;
-//!
-//! // This is a self referencial struct since the slice field points to the data field.
-//! // We cannot inform the compiler about that with a normal reference,
-//! // since this pattern cannot be described with the usual borrowing rules.
-//! // Instead we use a raw pointer, though one which is known to not be null,
-//! // since we know it's pointing at the string.
-//! struct Unmovable {
-//! data: String,
-//! slice: NonNull<String>,
-//! _pin: Pinned,
-//! }
-//!
-//! impl Unmovable {
-//! // To ensure the data doesn't move when the function returns,
-//! // we place it in the heap where it will stay for the lifetime of the object,
-//! // and the only way to access it would be through a pointer to it.
-//! fn new(data: String) -> PinBox<Self> {
-//! let res = Unmovable {
-//! data,
-//! // we only create the pointer once the data is in place
-//! // otherwise it will have already moved before we even started
-//! slice: NonNull::dangling(),
-//! _pin: Pinned,
-//! };
-//! let mut boxed = PinBox::new(res);
-//!
-//! let slice = NonNull::from(&boxed.data);
-//! // we know this is safe because modifying a field doesn't move the whole struct
-//! unsafe { PinBox::get_mut(&mut boxed).slice = slice };
-//! boxed
-//! }
-//! }
-//!
-//! let unmoved = Unmovable::new("hello".to_string());
-//! // The pointer should point to the correct location,
-//! // so long as the struct hasn't moved.
-//! // Meanwhile, we are free to move the pointer around.
-//! # #[allow(unused_mut)]
-//! let mut still_unmoved = unmoved;
-//! assert_eq!(still_unmoved.slice, NonNull::from(&still_unmoved.data));
-//!
-//! // Since our type doesn't implement Unpin, this will fail to compile:
-//! // let new_unmoved = Unmovable::new("world".to_string());
-//! // std::mem::swap(&mut *still_unmoved, &mut *new_unmoved);
-//! ```
-
-#![unstable(feature = "pin", issue = "49150")]
-
-pub use core::pin::*;
-pub use core::marker::Unpin;
-
-use core::convert::From;
-use core::fmt;
-use core::future::{Future, FutureObj, LocalFutureObj, UnsafeFutureObj};
-use core::marker::Unsize;
-use core::ops::{CoerceUnsized, Deref, DerefMut};
-use core::task::{Context, Poll};
-
-use boxed::Box;
-
-/// A pinned, heap allocated reference.
-///
-/// This type is similar to [`Box`], except that it pins its value,
-/// which prevents it from moving out of the reference, unless it implements [`Unpin`].
-///
-/// See the [module documentation] for furthur explaination on pinning.
-///
-/// [`Box`]: ../boxed/struct.Box.html
-/// [`Unpin`]: ../../std/marker/trait.Unpin.html
-/// [module documentation]: index.html
-#[unstable(feature = "pin", issue = "49150")]
-#[fundamental]
-#[repr(transparent)]
-pub struct PinBox<T: ?Sized> {
- inner: Box<T>,
-}
-
-#[unstable(feature = "pin", issue = "49150")]
-impl<T> PinBox<T> {
- /// Allocate memory on the heap, move the data into it and pin it.
- #[unstable(feature = "pin", issue = "49150")]
- pub fn new(data: T) -> PinBox<T> {
- PinBox { inner: Box::new(data) }
- }
-}
-
-#[unstable(feature = "pin", issue = "49150")]
-impl<T: ?Sized> PinBox<T> {
- /// Get a pinned reference to the data in this PinBox.
- #[inline]
- pub fn as_pin_mut<'a>(&'a mut self) -> PinMut<'a, T> {
- unsafe { PinMut::new_unchecked(&mut *self.inner) }
- }
-
- /// Constructs a `PinBox` from a raw pointer.
- ///
- /// After calling this function, the raw pointer is owned by the
- /// resulting `PinBox`. Specifically, the `PinBox` destructor will call
- /// the destructor of `T` and free the allocated memory. Since the
- /// way `PinBox` allocates and releases memory is unspecified, the
- /// only valid pointer to pass to this function is the one taken
- /// from another `PinBox` via the [`PinBox::into_raw`] function.
- ///
- /// This function is unsafe because improper use may lead to
- /// memory problems. For example, a double-free may occur if the
- /// function is called twice on the same raw pointer.
- ///
- /// [`PinBox::into_raw`]: struct.PinBox.html#method.into_raw
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(pin)]
- /// use std::pin::PinBox;
- /// let x = PinBox::new(5);
- /// let ptr = PinBox::into_raw(x);
- /// let x = unsafe { PinBox::from_raw(ptr) };
- /// ```
- #[inline]
- pub unsafe fn from_raw(raw: *mut T) -> Self {
- PinBox { inner: Box::from_raw(raw) }
- }
-
- /// Consumes the `PinBox`, returning the wrapped raw pointer.
- ///
- /// After calling this function, the caller is responsible for the
- /// memory previously managed by the `PinBox`. In particular, the
- /// caller should properly destroy `T` and release the memory. The
- /// proper way to do so is to convert the raw pointer back into a
- /// `PinBox` with the [`PinBox::from_raw`] function.
- ///
- /// Note: this is an associated function, which means that you have
- /// to call it as `PinBox::into_raw(b)` instead of `b.into_raw()`. This
- /// is so that there is no conflict with a method on the inner type.
- ///
- /// [`PinBox::from_raw`]: struct.PinBox.html#method.from_raw
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(pin)]
- /// use std::pin::PinBox;
- /// let x = PinBox::new(5);
- /// let ptr = PinBox::into_raw(x);
- /// ```
- #[inline]
- pub fn into_raw(b: PinBox<T>) -> *mut T {
- Box::into_raw(b.inner)
- }
-
- /// Get a mutable reference to the data inside this PinBox.
- ///
- /// This function is unsafe. Users must guarantee that the data is never
- /// moved out of this reference.
- #[inline]
- pub unsafe fn get_mut<'a>(this: &'a mut PinBox<T>) -> &'a mut T {
- &mut *this.inner
- }
-
- /// Convert this PinBox into an unpinned Box.
- ///
- /// This function is unsafe. Users must guarantee that the data is never
- /// moved out of the box.
- #[inline]
- pub unsafe fn unpin(this: PinBox<T>) -> Box<T> {
- this.inner
- }
-}
-
-#[unstable(feature = "pin", issue = "49150")]
-impl<T: ?Sized> From<Box<T>> for PinBox<T> {
- fn from(boxed: Box<T>) -> PinBox<T> {
- PinBox { inner: boxed }
- }
-}
-
-#[unstable(feature = "pin", issue = "49150")]
-impl<T: ?Sized> Deref for PinBox<T> {
- type Target = T;
-
- fn deref(&self) -> &T {
- &*self.inner
- }
-}
-
-#[unstable(feature = "pin", issue = "49150")]
-impl<T: Unpin + ?Sized> DerefMut for PinBox<T> {
- fn deref_mut(&mut self) -> &mut T {
- &mut *self.inner
- }
-}
-
-#[unstable(feature = "pin", issue = "49150")]
-impl<T: fmt::Display + ?Sized> fmt::Display for PinBox<T> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- fmt::Display::fmt(&*self.inner, f)
- }
-}
-
-#[unstable(feature = "pin", issue = "49150")]
-impl<T: fmt::Debug + ?Sized> fmt::Debug for PinBox<T> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- fmt::Debug::fmt(&*self.inner, f)
- }
-}
-
-#[unstable(feature = "pin", issue = "49150")]
-impl<T: ?Sized> fmt::Pointer for PinBox<T> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- // It's not possible to extract the inner Uniq directly from the Box,
- // instead we cast it to a *const which aliases the Unique
- let ptr: *const T = &*self.inner;
- fmt::Pointer::fmt(&ptr, f)
- }
-}
-
-#[unstable(feature = "pin", issue = "49150")]
-impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<PinBox<U>> for PinBox<T> {}
-
-#[unstable(feature = "pin", issue = "49150")]
-impl<T: ?Sized> Unpin for PinBox<T> {}
-
-#[unstable(feature = "futures_api", issue = "50547")]
-impl<F: ?Sized + Future> Future for PinBox<F> {
- type Output = F::Output;
-
- fn poll(mut self: PinMut<Self>, cx: &mut Context) -> Poll<Self::Output> {
- self.as_pin_mut().poll(cx)
- }
-}
-
-#[unstable(feature = "futures_api", issue = "50547")]
-unsafe impl<'a, T, F> UnsafeFutureObj<'a, T> for PinBox<F>
- where F: Future<Output = T> + 'a
-{
- fn into_raw(self) -> *mut () {
- PinBox::into_raw(self) as *mut ()
- }
-
- unsafe fn poll(ptr: *mut (), cx: &mut Context) -> Poll<T> {
- let ptr = ptr as *mut F;
- let pin: PinMut<F> = PinMut::new_unchecked(&mut *ptr);
- pin.poll(cx)
- }
-
- unsafe fn drop(ptr: *mut ()) {
- drop(PinBox::from_raw(ptr as *mut F))
- }
-}
-
-#[unstable(feature = "futures_api", issue = "50547")]
-impl<'a, F: Future<Output = ()> + Send + 'a> From<PinBox<F>> for FutureObj<'a, ()> {
- fn from(boxed: PinBox<F>) -> Self {
- FutureObj::new(boxed)
- }
-}
-
-#[unstable(feature = "futures_api", issue = "50547")]
-impl<'a, F: Future<Output = ()> + 'a> From<PinBox<F>> for LocalFutureObj<'a, ()> {
- fn from(boxed: PinBox<F>) -> Self {
- LocalFutureObj::new(boxed)
- }
-}
use core::mem::{self, align_of_val, forget, size_of_val};
use core::ops::Deref;
use core::ops::CoerceUnsized;
+use core::pin::Pin;
use core::ptr::{self, NonNull};
use core::convert::From;
use core::usize;
}
}
+ #[unstable(feature = "pin", issue = "49150")]
+ pub fn pinned(value: T) -> Pin<Rc<T>> {
+ unsafe { Pin::new_unchecked(Rc::new(value)) }
+ }
+
/// Returns the contained value, if the `Rc` has exactly one strong reference.
///
/// Otherwise, an [`Err`][result] is returned with the same `Rc` that was
/// Creates a vector by repeating a slice `n` times.
///
+ /// # Panics
+ ///
+ /// This function will panic if the capacity would overflow.
+ ///
/// # Examples
///
/// Basic usage:
/// assert_eq!([1, 2].repeat(3), vec![1, 2, 1, 2, 1, 2]);
/// }
/// ```
+ ///
+ /// A panic upon overflow:
+ ///
+ /// ```should_panic
+ /// #![feature(repeat_generic_slice)]
+ /// fn main() {
+ /// // this will panic at runtime
+ /// b"0123456789abcdef".repeat(usize::max_value());
+ /// }
+ /// ```
#[unstable(feature = "repeat_generic_slice",
reason = "it's on str, why not on slice?",
issue = "48784")]
// and `rem` is the remaining part of `n`.
// Using `Vec` to access `set_len()`.
- let mut buf = Vec::with_capacity(self.len() * n);
+ let mut buf = Vec::with_capacity(self.len().checked_mul(n).expect("capacity overflow"));
// `2^expn` repetition is done by doubling `buf` `expn`-times.
buf.extend(self);
/// Creates a new [`String`] by repeating a string `n` times.
///
+ /// # Panics
+ ///
+ /// This function will panic if the capacity would overflow.
+ ///
/// [`String`]: string/struct.String.html
///
/// # Examples
/// ```
/// assert_eq!("abc".repeat(4), String::from("abcabcabcabc"));
/// ```
+ ///
+ /// A panic upon overflow:
+ ///
+ /// ```should_panic
+ /// fn main() {
+ /// // this will panic at runtime
+ /// "0123456789abcdef".repeat(usize::max_value());
+ /// }
+ /// ```
#[stable(feature = "repeat_str", since = "1.16.0")]
pub fn repeat(&self, n: usize) -> String {
unsafe { String::from_utf8_unchecked(self.as_bytes().repeat(n)) }
use core::mem::{self, align_of_val, size_of_val};
use core::ops::Deref;
use core::ops::CoerceUnsized;
+use core::pin::Pin;
use core::ptr::{self, NonNull};
use core::marker::{Unpin, Unsize, PhantomData};
use core::hash::{Hash, Hasher};
Arc { ptr: Box::into_raw_non_null(x), phantom: PhantomData }
}
+ #[unstable(feature = "pin", issue = "49150")]
+ pub fn pinned(data: T) -> Pin<Arc<T>> {
+ unsafe { Pin::new_unchecked(Arc::new(data)) }
+ }
+
/// Returns the contained value, if the `Arc` has exactly one strong reference.
///
/// Otherwise, an [`Err`][result] is returned with the same `Arc` that was
// same pointer.
self.ptr = arith_offset(self.ptr as *const i8, 1) as *mut T;
- // Use a non-null pointer value
- // (self.ptr might be null because of wrapping)
- Some(ptr::read(1 as *mut T))
+ // Make up a value of this ZST.
+ Some(mem::zeroed())
} else {
let old = self.ptr;
self.ptr = self.ptr.offset(1);
// See above for why 'ptr.offset' isn't used
self.end = arith_offset(self.end as *const i8, -1) as *mut T;
- // Use a non-null pointer value
- // (self.end might be null because of wrapping)
- Some(ptr::read(1 as *mut T))
+ // Make up a value of this ZST.
+ Some(mem::zeroed())
} else {
self.end = self.end.offset(-1);
--- /dev/null
+#![stable(feature = "", since = "1.30.0")]
+
+#![allow(non_camel_case_types)]
+
+//! Utilities related to FFI bindings.
+
+use ::fmt;
+
+/// Equivalent to C's `void` type when used as a [pointer].
+///
+/// In essence, `*const c_void` is equivalent to C's `const void*`
+/// and `*mut c_void` is equivalent to C's `void*`. That said, this is
+/// *not* the same as C's `void` return type, which is Rust's `()` type.
+///
+/// Ideally, this type would be equivalent to [`!`], but currently it may
+/// be more ideal to use `c_void` for FFI purposes.
+///
+/// [`!`]: ../../std/primitive.never.html
+/// [pointer]: ../../std/primitive.pointer.html
+// NB: For LLVM to recognize the void pointer type and by extension
+// functions like malloc(), we need to have it represented as i8* in
+// LLVM bitcode. The enum used here ensures this and prevents misuse
+// of the "raw" type by only having private variants.. We need two
+// variants, because the compiler complains about the repr attribute
+// otherwise.
+#[repr(u8)]
+#[stable(feature = "raw_os", since = "1.1.0")]
+pub enum c_void {
+ #[unstable(feature = "c_void_variant", reason = "should not have to exist",
+ issue = "0")]
+ #[doc(hidden)] __variant1,
+ #[unstable(feature = "c_void_variant", reason = "should not have to exist",
+ issue = "0")]
+ #[doc(hidden)] __variant2,
+}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl fmt::Debug for c_void {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.pad("c_void")
+ }
+}
reason = "futures in libcore are unstable",
issue = "50547")]
-use pin::PinMut;
use marker::Unpin;
+use ops;
+use pin::Pin;
use task::{self, Poll};
/// A future represents an asychronous computation.
/// [`Poll::Pending`]: ../task/enum.Poll.html#variant.Pending
/// [`Poll::Ready(val)`]: ../task/enum.Poll.html#variant.Ready
/// [`cx.waker()`]: ../task/struct.Context.html#method.waker
- fn poll(self: PinMut<Self>, cx: &mut task::Context) -> Poll<Self::Output>;
+ fn poll(self: Pin<&mut Self>, cx: &mut task::Context) -> Poll<Self::Output>;
}
impl<'a, F: ?Sized + Future + Unpin> Future for &'a mut F {
type Output = F::Output;
- fn poll(mut self: PinMut<Self>, cx: &mut task::Context) -> Poll<Self::Output> {
- F::poll(PinMut::new(&mut **self), cx)
+ fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context) -> Poll<Self::Output> {
+ F::poll(Pin::new(&mut **self), cx)
}
}
-impl<'a, F: ?Sized + Future> Future for PinMut<'a, F> {
- type Output = F::Output;
+impl<P> Future for Pin<P>
+where
+ P: ops::DerefMut,
+ P::Target: Future,
+{
+ type Output = <<P as ops::Deref>::Target as Future>::Output;
- fn poll(mut self: PinMut<Self>, cx: &mut task::Context) -> Poll<Self::Output> {
- F::poll((*self).reborrow(), cx)
+ fn poll(self: Pin<&mut Self>, cx: &mut task::Context) -> Poll<Self::Output> {
+ Pin::get_mut(self).as_mut().poll(cx)
}
}
use fmt;
use future::Future;
use marker::{PhantomData, Unpin};
-use pin::PinMut;
+use ops;
+use pin::Pin;
use task::{Context, Poll};
/// A custom trait object for polling futures, roughly akin to
type Output = T;
#[inline]
- fn poll(self: PinMut<Self>, cx: &mut Context) -> Poll<T> {
+ fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<T> {
unsafe {
- (self.poll_fn)(self.ptr, cx)
+ ((*self).poll_fn)((*self).ptr, cx)
}
}
}
type Output = T;
#[inline]
- fn poll(self: PinMut<Self>, cx: &mut Context) -> Poll<T> {
- let pinned_field = unsafe { PinMut::map_unchecked(self, |x| &mut x.0) };
- pinned_field.poll(cx)
+ fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<T> {
+ let pinned_field: Pin<&mut LocalFutureObj<'a, T>> = unsafe {
+ Pin::map_unchecked_mut(self, |x| &mut x.0)
+ };
+ LocalFutureObj::poll(pinned_field, cx)
}
}
}
unsafe fn poll(ptr: *mut (), cx: &mut Context) -> Poll<T> {
- PinMut::new_unchecked(&mut *(ptr as *mut F)).poll(cx)
+ let p: Pin<&mut F> = Pin::new_unchecked(&mut *(ptr as *mut F));
+ F::poll(p, cx)
+ }
+
+ unsafe fn drop(_ptr: *mut ()) {}
+}
+
+#[unstable(feature = "futures_api", issue = "50547")]
+unsafe impl<'a, T, P, F> UnsafeFutureObj<'a, T> for Pin<P> where
+ P: ops::DerefMut<Target = F> + 'a,
+ F: Future<Output = T> + 'a,
+{
+ fn into_raw(mut self) -> *mut () {
+ unsafe { Pin::get_mut_unchecked(Pin::as_mut(&mut self)) as *mut F as *mut () }
+ }
+
+ unsafe fn poll(ptr: *mut (), cx: &mut Context) -> Poll<T> {
+ let future: Pin<&mut F> = Pin::new_unchecked(&mut *(ptr as *mut F));
+ F::poll(future, cx)
}
unsafe fn drop(_ptr: *mut ()) {}
pub mod option;
pub mod raw;
pub mod result;
+pub mod ffi;
pub mod slice;
pub mod str;
/// this trait cannot prevent types from moving by itself.
///
/// Instead it can be used to prevent moves through the type system,
-/// by controlling the behavior of special pointer types like [`PinMut`],
+/// by controlling the behavior of pointers wrapped in the [`Pin`] wrapper,
/// which "pin" the type in place by not allowing it to be moved out of them.
/// See the [`pin module`] documentation for more information on pinning.
///
/// ```rust
/// #![feature(pin)]
/// use std::mem::replace;
-/// use std::pin::PinMut;
+/// use std::pin::Pin;
///
/// let mut string = "this".to_string();
-/// let mut pinned_string = PinMut::new(&mut string);
+/// let mut pinned_string = Pin::new(&mut string);
///
/// // dereferencing the pointer mutably is only possible because String implements Unpin
/// replace(&mut *pinned_string, "other".to_string());
/// This trait is automatically implemented for almost every type.
///
/// [`replace`]: ../../std/mem/fn.replace.html
-/// [`PinMut`]: ../pin/struct.PinMut.html
+/// [`Pin`]: ../pin/struct.Pin.html
/// [`pin module`]: ../../std/pin/index.html
#[unstable(feature = "pin", issue = "49150")]
pub auto trait Unpin {}
use iter::{FromIterator, FusedIterator, TrustedLen};
use {hint, mem, ops::{self, Deref}};
-use pin::PinMut;
+use pin::Pin;
// Note that this is not a lang item per se, but it has a hidden dependency on
// `Iterator`, which is one. The compiler assumes that the `next` method of
}
}
- /// Converts from `Option<T>` to `Option<PinMut<'_, T>>`
+
+ /// Converts from `Pin<&Option<T>>` to `Option<Pin<&T>>`
+ #[inline]
+ #[unstable(feature = "pin", issue = "49150")]
+ pub fn as_pin_ref<'a>(self: Pin<&'a Option<T>>) -> Option<Pin<&'a T>> {
+ unsafe {
+ Pin::get_ref(self).as_ref().map(|x| Pin::new_unchecked(x))
+ }
+ }
+
+ /// Converts from `Pin<&mut Option<T>>` to `Option<Pin<&mut T>>`
#[inline]
#[unstable(feature = "pin", issue = "49150")]
- pub fn as_pin_mut<'a>(self: PinMut<'a, Self>) -> Option<PinMut<'a, T>> {
+ pub fn as_pin_mut<'a>(self: Pin<&'a mut Option<T>>) -> Option<Pin<&'a mut T>> {
unsafe {
- PinMut::get_mut_unchecked(self).as_mut().map(|x| PinMut::new_unchecked(x))
+ Pin::get_mut_unchecked(self).as_mut().map(|x| Pin::new_unchecked(x))
}
}
//! Types which pin data to its location in memory
//!
-//! See the [standard library module] for more information.
+//! It is sometimes useful to have objects that are guaranteed to not move,
+//! in the sense that their placement in memory does not change, and can thus be relied upon.
//!
-//! [standard library module]: ../../std/pin/index.html
+//! A prime example of such a scenario would be building self-referencial structs,
+//! since moving an object with pointers to itself will invalidate them,
+//! which could cause undefined behavior.
+//!
+//! In order to prevent objects from moving, they must be pinned
+//! by wrapping a pointer to the data in the [`Pin`] type. A pointer wrapped
+//! in a `Pin` is otherwise equivalent to its normal version, e.g. `Pin<Box<T>>`
+//! and `Box<T>` work the same way except that the first is pinning the value
+//! of `T` in place.
+//!
+//! First of all, these are pointer types because pinned data mustn't be passed around by value
+//! (that would change its location in memory).
+//! Secondly, since data can be moved out of `&mut` and `Box` with functions such as [`swap`],
+//! which causes their contents to swap places in memory,
+//! we need dedicated types that prohibit such operations.
+//!
+//! However, these restrictions are usually not necessary,
+//! so most types implement the [`Unpin`] auto-trait,
+//! which indicates that the type can be moved out safely.
+//! Doing so removes the limitations of pinning types,
+//! making them the same as their non-pinning counterparts.
+//!
+//! [`Pin`]: struct.Pin.html
+//! [`Unpin`]: trait.Unpin.html
+//! [`swap`]: ../../std/mem/fn.swap.html
+//! [`Box`]: ../../std/boxed/struct.Box.html
+//!
+//! # Examples
+//!
+//! ```rust
+//! #![feature(pin)]
+//!
+//! use std::pin::Pin;
+//! use std::marker::Pinned;
+//! use std::ptr::NonNull;
+//!
+//! // This is a self referencial struct since the slice field points to the data field.
+//! // We cannot inform the compiler about that with a normal reference,
+//! // since this pattern cannot be described with the usual borrowing rules.
+//! // Instead we use a raw pointer, though one which is known to not be null,
+//! // since we know it's pointing at the string.
+//! struct Unmovable {
+//! data: String,
+//! slice: NonNull<String>,
+//! _pin: Pinned,
+//! }
+//!
+//! impl Unmovable {
+//! // To ensure the data doesn't move when the function returns,
+//! // we place it in the heap where it will stay for the lifetime of the object,
+//! // and the only way to access it would be through a pointer to it.
+//! fn new(data: String) -> Pin<Box<Self>> {
+//! let res = Unmovable {
+//! data,
+//! // we only create the pointer once the data is in place
+//! // otherwise it will have already moved before we even started
+//! slice: NonNull::dangling(),
+//! _pin: Pinned,
+//! };
+//! let mut boxed = Box::pinned(res);
+//!
+//! let slice = NonNull::from(&boxed.data);
+//! // we know this is safe because modifying a field doesn't move the whole struct
+//! unsafe {
+//! let mut_ref: Pin<&mut Self> = Pin::as_mut(&mut boxed);
+//! Pin::get_mut_unchecked(mut_ref).slice = slice;
+//! }
+//! boxed
+//! }
+//! }
+//!
+//! let unmoved = Unmovable::new("hello".to_string());
+//! // The pointer should point to the correct location,
+//! // so long as the struct hasn't moved.
+//! // Meanwhile, we are free to move the pointer around.
+//! # #[allow(unused_mut)]
+//! let mut still_unmoved = unmoved;
+//! assert_eq!(still_unmoved.slice, NonNull::from(&still_unmoved.data));
+//!
+//! // Since our type doesn't implement Unpin, this will fail to compile:
+//! // let new_unmoved = Unmovable::new("world".to_string());
+//! // std::mem::swap(&mut *still_unmoved, &mut *new_unmoved);
+//! ```
#![unstable(feature = "pin", issue = "49150")]
use fmt;
-use future::{Future, UnsafeFutureObj};
-use marker::{Sized, Unpin, Unsize};
-use task::{Context, Poll};
+use marker::Sized;
use ops::{Deref, DerefMut, CoerceUnsized};
-/// A pinned reference.
+#[doc(inline)]
+pub use marker::Unpin;
+
+/// A pinned pointer.
///
-/// This type is similar to a mutable reference, except that it pins its value,
-/// which prevents it from moving out of the reference, unless it implements [`Unpin`].
+/// This is a wrapper around a kind of pointer which makes that pointer "pin" its
+/// value in place, preventing the value referenced by that pointer from being moved
+/// unless it implements [`Unpin`].
///
/// See the [`pin` module] documentation for furthur explanation on pinning.
///
/// [`Unpin`]: ../../std/marker/trait.Unpin.html
/// [`pin` module]: ../../std/pin/index.html
+//
+// Note: the derives below are allowed because they all only use `&P`, so they
+// cannot move the value behind `pointer`.
#[unstable(feature = "pin", issue = "49150")]
#[fundamental]
-pub struct PinMut<'a, T: ?Sized + 'a> {
- inner: &'a mut T,
+#[derive(Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)]
+pub struct Pin<P> {
+ pointer: P,
}
-#[unstable(feature = "pin", issue = "49150")]
-impl<'a, T: ?Sized + Unpin> PinMut<'a, T> {
- /// Construct a new `PinMut` around a reference to some data of a type that
+impl<P: Deref> Pin<P>
+where
+ P::Target: Unpin,
+{
+ /// Construct a new `Pin` around a pointer to some data of a type that
/// implements `Unpin`.
#[unstable(feature = "pin", issue = "49150")]
- pub fn new(reference: &'a mut T) -> PinMut<'a, T> {
- PinMut { inner: reference }
+ #[inline(always)]
+ pub fn new(pointer: P) -> Pin<P> {
+ // Safety: the value pointed to is `Unpin`, and so has no requirements
+ // around pinning.
+ unsafe { Pin::new_unchecked(pointer) }
}
+}
- /// Get a mutable reference to the data inside of this `PinMut`.
+impl<P: Deref> Pin<P> {
+ /// Construct a new `Pin` around a reference to some data of a type that
+ /// may or may not implement `Unpin`.
+ ///
+ /// # Safety
+ ///
+ /// This constructor is unsafe because we cannot guarantee that the data
+ /// pointed to by `pointer` is pinned. If the constructed `Pin<P>` does
+ /// not guarantee that the data `P` points to is pinned, constructing a
+ /// `Pin<P>` is undefined behavior.
+ ///
+ /// If `pointer` dereferences to an `Unpin` type, `Pin::new` should be used
+ /// instead.
+ #[unstable(feature = "pin", issue = "49150")]
+ #[inline(always)]
+ pub unsafe fn new_unchecked(pointer: P) -> Pin<P> {
+ Pin { pointer }
+ }
+
+ /// Get a pinned shared reference from this pinned pointer.
#[unstable(feature = "pin", issue = "49150")]
- pub fn get_mut(this: PinMut<'a, T>) -> &'a mut T {
- this.inner
+ #[inline(always)]
+ pub fn as_ref(self: &Pin<P>) -> Pin<&P::Target> {
+ unsafe { Pin::new_unchecked(&*self.pointer) }
}
}
+impl<P: DerefMut> Pin<P> {
+ /// Get a pinned mutable reference from this pinned pointer.
+ #[unstable(feature = "pin", issue = "49150")]
+ #[inline(always)]
+ pub fn as_mut(self: &mut Pin<P>) -> Pin<&mut P::Target> {
+ unsafe { Pin::new_unchecked(&mut *self.pointer) }
+ }
-#[unstable(feature = "pin", issue = "49150")]
-impl<'a, T: ?Sized> PinMut<'a, T> {
- /// Construct a new `PinMut` around a reference to some data of a type that
- /// may or may not implement `Unpin`.
+ /// Assign a new value to the memory behind the pinned reference.
+ #[unstable(feature = "pin", issue = "49150")]
+ #[inline(always)]
+ pub fn set(mut self: Pin<P>, value: P::Target)
+ where
+ P::Target: Sized,
+ {
+ *self.pointer = value;
+ }
+}
+
+impl<'a, T: ?Sized> Pin<&'a T> {
+ /// Construct a new pin by mapping the interior value.
///
- /// This constructor is unsafe because we do not know what will happen with
- /// that data after the lifetime of the reference ends. If you cannot guarantee that the
- /// data will never move again, calling this constructor is invalid.
+ /// For example, if you wanted to get a `Pin` of a field of something,
+ /// you could use this to get access to that field in one line of code.
+ ///
+ /// # Safety
+ ///
+ /// This function is unsafe. You must guarantee that the data you return
+ /// will not move so long as the argument value does not move (for example,
+ /// because it is one of the fields of that value), and also that you do
+ /// not move out of the argument you receive to the interior function.
#[unstable(feature = "pin", issue = "49150")]
- pub unsafe fn new_unchecked(reference: &'a mut T) -> PinMut<'a, T> {
- PinMut { inner: reference }
+ pub unsafe fn map_unchecked<U, F>(this: Pin<&'a T>, func: F) -> Pin<&'a U> where
+ F: FnOnce(&T) -> &U,
+ {
+ let pointer = &*this.pointer;
+ let new_pointer = func(pointer);
+ Pin::new_unchecked(new_pointer)
}
- /// Reborrow a `PinMut` for a shorter lifetime.
+ /// Get a shared reference out of a pin.
///
- /// For example, `PinMut::get_mut(x.reborrow())` (unsafely) returns a
- /// short-lived mutable reference reborrowing from `x`.
+ /// Note: `Pin` also implements `Deref` to the target, which can be used
+ /// to access the inner value. However, `Deref` only provides a reference
+ /// that lives for as long as the borrow of the `Pin`, not the lifetime of
+ /// the `Pin` itself. This method allows turning the `Pin` into a reference
+ /// with the same lifetime as the original `Pin`.
#[unstable(feature = "pin", issue = "49150")]
- pub fn reborrow<'b>(&'b mut self) -> PinMut<'b, T> {
- PinMut { inner: self.inner }
+ #[inline(always)]
+ pub fn get_ref(this: Pin<&'a T>) -> &'a T {
+ this.pointer
+ }
+}
+
+impl<'a, T: ?Sized> Pin<&'a mut T> {
+ /// Convert this `Pin<&mut T>` into a `Pin<&T>` with the same lifetime.
+ #[unstable(feature = "pin", issue = "49150")]
+ #[inline(always)]
+ pub fn into_ref(this: Pin<&'a mut T>) -> Pin<&'a T> {
+ Pin { pointer: this.pointer }
+ }
+
+ /// Get a mutable reference to the data inside of this `Pin`.
+ ///
+ /// This requires that the data inside this `Pin` is `Unpin`.
+ ///
+ /// Note: `Pin` also implements `DerefMut` to the data, which can be used
+ /// to access the inner value. However, `DerefMut` only provides a reference
+ /// that lives for as long as the borrow of the `Pin`, not the lifetime of
+ /// the `Pin` itself. This method allows turning the `Pin` into a reference
+ /// with the same lifetime as the original `Pin`.
+ #[unstable(feature = "pin", issue = "49150")]
+ #[inline(always)]
+ pub fn get_mut(this: Pin<&'a mut T>) -> &'a mut T
+ where T: Unpin,
+ {
+ this.pointer
}
- /// Get a mutable reference to the data inside of this `PinMut`.
+ /// Get a mutable reference to the data inside of this `Pin`.
+ ///
+ /// # Safety
///
/// This function is unsafe. You must guarantee that you will never move
/// the data out of the mutable reference you receive when you call this
- /// function.
+ /// function, so that the invariants on the `Pin` type can be upheld.
+ ///
+ /// If the underlying data is `Unpin`, `Pin::get_mut` should be used
+ /// instead.
#[unstable(feature = "pin", issue = "49150")]
- pub unsafe fn get_mut_unchecked(this: PinMut<'a, T>) -> &'a mut T {
- this.inner
+ #[inline(always)]
+ pub unsafe fn get_mut_unchecked(this: Pin<&'a mut T>) -> &'a mut T {
+ this.pointer
}
/// Construct a new pin by mapping the interior value.
///
- /// For example, if you wanted to get a `PinMut` of a field of something,
+ /// For example, if you wanted to get a `Pin` of a field of something,
/// you could use this to get access to that field in one line of code.
///
+ /// # Safety
+ ///
/// This function is unsafe. You must guarantee that the data you return
/// will not move so long as the argument value does not move (for example,
/// because it is one of the fields of that value), and also that you do
/// not move out of the argument you receive to the interior function.
#[unstable(feature = "pin", issue = "49150")]
- pub unsafe fn map_unchecked<U, F>(this: PinMut<'a, T>, f: F) -> PinMut<'a, U> where
- F: FnOnce(&mut T) -> &mut U
+ pub unsafe fn map_unchecked_mut<U, F>(this: Pin<&'a mut T>, func: F) -> Pin<&'a mut U> where
+ F: FnOnce(&mut T) -> &mut U,
{
- PinMut { inner: f(this.inner) }
- }
-
- /// Assign a new value to the memory behind the pinned reference.
- #[unstable(feature = "pin", issue = "49150")]
- pub fn set(this: PinMut<'a, T>, value: T)
- where T: Sized,
- {
- *this.inner = value;
+ let pointer = Pin::get_mut_unchecked(this);
+ let new_pointer = func(pointer);
+ Pin::new_unchecked(new_pointer)
}
}
#[unstable(feature = "pin", issue = "49150")]
-impl<'a, T: ?Sized> Deref for PinMut<'a, T> {
- type Target = T;
-
- fn deref(&self) -> &T {
- &*self.inner
+impl<P: Deref> Deref for Pin<P> {
+ type Target = P::Target;
+ fn deref(&self) -> &P::Target {
+ Pin::get_ref(Pin::as_ref(self))
}
}
#[unstable(feature = "pin", issue = "49150")]
-impl<'a, T: ?Sized + Unpin> DerefMut for PinMut<'a, T> {
- fn deref_mut(&mut self) -> &mut T {
- self.inner
+impl<P: DerefMut> DerefMut for Pin<P>
+where
+ P::Target: Unpin
+{
+ fn deref_mut(&mut self) -> &mut P::Target {
+ Pin::get_mut(Pin::as_mut(self))
}
}
#[unstable(feature = "pin", issue = "49150")]
-impl<'a, T: fmt::Debug + ?Sized> fmt::Debug for PinMut<'a, T> {
+impl<'a, P: fmt::Debug> fmt::Debug for Pin<P> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- fmt::Debug::fmt(&**self, f)
+ fmt::Debug::fmt(&self.pointer, f)
}
}
#[unstable(feature = "pin", issue = "49150")]
-impl<'a, T: fmt::Display + ?Sized> fmt::Display for PinMut<'a, T> {
+impl<'a, P: fmt::Display> fmt::Display for Pin<P> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- fmt::Display::fmt(&**self, f)
+ fmt::Display::fmt(&self.pointer, f)
}
}
#[unstable(feature = "pin", issue = "49150")]
-impl<'a, T: ?Sized> fmt::Pointer for PinMut<'a, T> {
+impl<'a, P: fmt::Pointer> fmt::Pointer for Pin<P> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- fmt::Pointer::fmt(&(&*self.inner as *const T), f)
+ fmt::Pointer::fmt(&self.pointer, f)
}
}
+// Note: this means that any impl of `CoerceUnsized` that allows coercing from
+// a type that impls `Deref<Target=impl !Unpin>` to a type that impls
+// `Deref<Target=Unpin>` is unsound. Any such impl would probably be unsound
+// for other reasons, though, so we just need to take care not to allow such
+// impls to land in std.
#[unstable(feature = "pin", issue = "49150")]
-impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<PinMut<'a, U>> for PinMut<'a, T> {}
+impl<'a, P, U> CoerceUnsized<Pin<U>> for Pin<P>
+where
+ P: CoerceUnsized<U>,
+{}
#[unstable(feature = "pin", issue = "49150")]
-impl<'a, T: ?Sized> Unpin for PinMut<'a, T> {}
-
-#[unstable(feature = "futures_api", issue = "50547")]
-unsafe impl<'a, T, F> UnsafeFutureObj<'a, T> for PinMut<'a, F>
- where F: Future<Output = T> + 'a
-{
- fn into_raw(self) -> *mut () {
- unsafe { PinMut::get_mut_unchecked(self) as *mut F as *mut () }
- }
-
- unsafe fn poll(ptr: *mut (), cx: &mut Context) -> Poll<T> {
- PinMut::new_unchecked(&mut *(ptr as *mut F)).poll(cx)
- }
-
- unsafe fn drop(_ptr: *mut ()) {}
-}
+impl<'a, P> Unpin for Pin<P> {}
/// maintained.
///
/// This method splits the slice into three distinct slices: prefix, correctly aligned middle
- /// slice of a new type, and the suffix slice. The middle slice will have the greatest length
- /// possible for a given type and input slice.
+ /// slice of a new type, and the suffix slice. The method does a best effort to make the
+ /// middle slice the greatest length possible for a given type and input slice, but only
+ /// your algorithm's performance should depend on that, not its correctness.
///
/// This method has no purpose when either input element `T` or output element `U` are
/// zero-sized and will return the original slice without splitting anything.
/// Basic usage:
///
/// ```
- /// # #![feature(slice_align_to)]
/// unsafe {
/// let bytes: [u8; 7] = [1, 2, 3, 4, 5, 6, 7];
/// let (prefix, shorts, suffix) = bytes.align_to::<u16>();
/// // less_efficient_algorithm_for_bytes(suffix);
/// }
/// ```
- #[unstable(feature = "slice_align_to", issue = "44488")]
+ #[stable(feature = "slice_align_to", since = "1.30.0")]
pub unsafe fn align_to<U>(&self) -> (&[T], &[U], &[T]) {
// Note that most of this function will be constant-evaluated,
if ::mem::size_of::<U>() == 0 || ::mem::size_of::<T>() == 0 {
/// maintained.
///
/// This method splits the slice into three distinct slices: prefix, correctly aligned middle
- /// slice of a new type, and the suffix slice. The middle slice will have the greatest length
- /// possible for a given type and input slice.
+ /// slice of a new type, and the suffix slice. The method does a best effort to make the
+ /// middle slice the greatest length possible for a given type and input slice, but only
+ /// your algorithm's performance should depend on that, not its correctness.
///
/// This method has no purpose when either input element `T` or output element `U` are
/// zero-sized and will return the original slice without splitting anything.
/// Basic usage:
///
/// ```
- /// # #![feature(slice_align_to)]
/// unsafe {
/// let mut bytes: [u8; 7] = [1, 2, 3, 4, 5, 6, 7];
/// let (prefix, shorts, suffix) = bytes.align_to_mut::<u16>();
/// // less_efficient_algorithm_for_bytes(suffix);
/// }
/// ```
- #[unstable(feature = "slice_align_to", issue = "44488")]
+ #[stable(feature = "slice_align_to", since = "1.30.0")]
pub unsafe fn align_to_mut<U>(&mut self) -> (&mut [T], &mut [U], &mut [T]) {
// Note that most of this function will be constant-evaluated,
if ::mem::size_of::<U>() == 0 || ::mem::size_of::<T>() == 0 {
#![feature(try_from)]
#![feature(try_trait)]
#![feature(exact_chunks)]
-#![feature(slice_align_to)]
#![feature(align_offset)]
#![feature(reverse_bits)]
#![feature(inner_deref)]
//! assert_eq!(Duration::new(5, 0), Duration::from_secs(5));
//! ```
-use fmt;
+use {fmt, u64};
use iter::Sum;
use ops::{Add, Sub, Mul, Div, AddAssign, SubAssign, MulAssign, DivAssign};
const NANOS_PER_MICRO: u32 = 1_000;
const MILLIS_PER_SEC: u64 = 1_000;
const MICROS_PER_SEC: u64 = 1_000_000;
+const MAX_NANOS_F64: f64 = ((u64::MAX as u128 + 1)*(NANOS_PER_SEC as u128)) as f64;
/// A `Duration` type to represent a span of time, typically used for system
/// timeouts.
None
}
}
+
+ /// Returns the number of seconds contained by this `Duration` as `f64`.
+ ///
+ /// The returned value does include the fractional (nanosecond) part of the duration.
+ ///
+ /// # Examples
+ /// ```
+ /// #![feature(duration_float)]
+ /// use std::time::Duration;
+ ///
+ /// let dur = Duration::new(2, 700_000_000);
+ /// assert_eq!(dur.as_float_secs(), 2.7);
+ /// ```
+ #[unstable(feature = "duration_float", issue = "54361")]
+ #[inline]
+ pub fn as_float_secs(&self) -> f64 {
+ (self.secs as f64) + (self.nanos as f64) / (NANOS_PER_SEC as f64)
+ }
+
+ /// Creates a new `Duration` from the specified number of seconds.
+ ///
+ /// # Panics
+ /// This constructor will panic if `secs` is not finite, negative or overflows `Duration`.
+ ///
+ /// # Examples
+ /// ```
+ /// #![feature(duration_float)]
+ /// use std::time::Duration;
+ ///
+ /// let dur = Duration::from_float_secs(2.7);
+ /// assert_eq!(dur, Duration::new(2, 700_000_000));
+ /// ```
+ #[unstable(feature = "duration_float", issue = "54361")]
+ #[inline]
+ pub fn from_float_secs(secs: f64) -> Duration {
+ let nanos = secs * (NANOS_PER_SEC as f64);
+ if !nanos.is_finite() {
+ panic!("got non-finite value when converting float to duration");
+ }
+ if nanos >= MAX_NANOS_F64 {
+ panic!("overflow when converting float to duration");
+ }
+ if nanos < 0.0 {
+ panic!("underflow when converting float to duration");
+ }
+ let nanos = nanos as u128;
+ Duration {
+ secs: (nanos / (NANOS_PER_SEC as u128)) as u64,
+ nanos: (nanos % (NANOS_PER_SEC as u128)) as u32,
+ }
+ }
+
+ /// Multiply `Duration` by `f64`.
+ ///
+ /// # Panics
+ /// This method will panic if result is not finite, negative or overflows `Duration`.
+ ///
+ /// # Examples
+ /// ```
+ /// #![feature(duration_float)]
+ /// use std::time::Duration;
+ ///
+ /// let dur = Duration::new(2, 700_000_000);
+ /// assert_eq!(dur.mul_f64(3.14), Duration::new(8, 478_000_000));
+ /// assert_eq!(dur.mul_f64(3.14e5), Duration::new(847_800, 0));
+ /// ```
+ #[unstable(feature = "duration_float", issue = "54361")]
+ #[inline]
+ pub fn mul_f64(self, rhs: f64) -> Duration {
+ Duration::from_float_secs(rhs * self.as_float_secs())
+ }
+
+ /// Divide `Duration` by `f64`.
+ ///
+ /// # Panics
+ /// This method will panic if result is not finite, negative or overflows `Duration`.
+ ///
+ /// # Examples
+ /// ```
+ /// #![feature(duration_float)]
+ /// use std::time::Duration;
+ ///
+ /// let dur = Duration::new(2, 700_000_000);
+ /// assert_eq!(dur.div_f64(3.14), Duration::new(0, 859_872_611));
+ /// // note that truncation is used, not rounding
+ /// assert_eq!(dur.div_f64(3.14e5), Duration::new(0, 8_598));
+ /// ```
+ #[unstable(feature = "duration_float", issue = "54361")]
+ #[inline]
+ pub fn div_f64(self, rhs: f64) -> Duration {
+ Duration::from_float_secs(self.as_float_secs() / rhs)
+ }
+
+ /// Divide `Duration` by `Duration` and return `f64`.
+ ///
+ /// # Examples
+ /// ```
+ /// #![feature(duration_float)]
+ /// use std::time::Duration;
+ ///
+ /// let dur1 = Duration::new(2, 700_000_000);
+ /// let dur2 = Duration::new(5, 400_000_000);
+ /// assert_eq!(dur1.div_duration(dur2), 0.5);
+ /// ```
+ #[unstable(feature = "duration_float", issue = "54361")]
+ #[inline]
+ pub fn div_duration(self, rhs: Duration) -> f64 {
+ self.as_float_secs() / rhs.as_float_secs()
+ }
}
#[stable(feature = "duration", since = "1.3.0")]
}
}
+#[stable(feature = "symmetric_u32_duration_mul", since = "1.31.0")]
+impl Mul<Duration> for u32 {
+ type Output = Duration;
+
+ fn mul(self, rhs: Duration) -> Duration {
+ rhs * self
+ }
+}
+
#[stable(feature = "time_augmented_assignment", since = "1.9.0")]
impl MulAssign<u32> for Duration {
fn mul_assign(&mut self, rhs: u32) {
target_scope: region::Scope,
to_index: CFGIndex) {
let mut data = CFGEdgeData { exiting_scopes: vec![] };
- let mut scope = region::Scope::Node(from_expr.hir_id.local_id);
+ let mut scope = region::Scope {
+ id: from_expr.hir_id.local_id,
+ data: region::ScopeData::Node
+ };
let region_scope_tree = self.tcx.region_scope_tree(self.owner_def_id);
while scope != target_scope {
data.exiting_scopes.push(scope.item_local_id());
Ok(loop_id) => {
for b in &self.breakable_block_scopes {
if b.block_expr_id == self.tcx.hir.node_to_hir_id(loop_id).local_id {
- let scope_id = self.tcx.hir.node_to_hir_id(loop_id).local_id;
- return (region::Scope::Node(scope_id), match scope_cf_kind {
+ let scope = region::Scope {
+ id: self.tcx.hir.node_to_hir_id(loop_id).local_id,
+ data: region::ScopeData::Node
+ };
+ return (scope, match scope_cf_kind {
ScopeCfKind::Break => b.break_index,
ScopeCfKind::Continue => bug!("can't continue to block"),
});
}
for l in &self.loop_scopes {
if l.loop_id == self.tcx.hir.node_to_hir_id(loop_id).local_id {
- let scope_id = self.tcx.hir.node_to_hir_id(loop_id).local_id;
- return (region::Scope::Node(scope_id), match scope_cf_kind {
+ let scope = region::Scope {
+ id: self.tcx.hir.node_to_hir_id(loop_id).local_id,
+ data: region::ScopeData::Node
+ };
+ return (scope, match scope_cf_kind {
ScopeCfKind::Break => l.break_index,
ScopeCfKind::Continue => l.continue_index,
});
}
}
- /// Returns the NodeId of `id`'s nearest module parent, or `id` itself if no
+ /// Returns the DefId of `id`'s nearest module parent, or `id` itself if no
/// module parent is in this map.
pub fn get_module_parent(&self, id: NodeId) -> DefId {
- let id = match self.walk_parent_nodes(id, |node| match *node {
+ self.local_def_id(self.get_module_parent_node(id))
+ }
+
+ /// Returns the NodeId of `id`'s nearest module parent, or `id` itself if no
+ /// module parent is in this map.
+ pub fn get_module_parent_node(&self, id: NodeId) -> NodeId {
+ match self.walk_parent_nodes(id, |node| match *node {
Node::Item(&Item { node: ItemKind::Mod(_), .. }) => true,
_ => false,
}, |_| false) {
Ok(id) => id,
Err(id) => id,
- };
- self.local_def_id(id)
+ }
}
/// Returns the nearest enclosing scope. A scope is an item or block.
return;
}
};
- let scope_decorated_tag = match scope.data() {
+ let scope_decorated_tag = match scope.data {
region::ScopeData::Node => tag,
region::ScopeData::CallSite => "scope of call-site for function",
region::ScopeData::Arguments => "scope of function body",
let (span, sub, sup) = self.get_regions();
// Determine whether the sub and sup consist of both anonymous (elided) regions.
- let anon_reg_sup = self.is_suitable_region(sup)?;
+ let anon_reg_sup = self.tcx.is_suitable_region(sup)?;
- let anon_reg_sub = self.is_suitable_region(sub)?;
+ let anon_reg_sub = self.tcx.is_suitable_region(sub)?;
let scope_def_id_sup = anon_reg_sup.def_id;
let bregion_sup = anon_reg_sup.boundregion;
let scope_def_id_sub = anon_reg_sub.def_id;
region: Region<'tcx>,
br: &ty::BoundRegion,
) -> Option<(&hir::Ty, &hir::FnDecl)> {
- if let Some(anon_reg) = self.is_suitable_region(region) {
+ if let Some(anon_reg) = self.tcx.is_suitable_region(region) {
let def_id = anon_reg.def_id;
if let Some(node_id) = self.tcx.hir.as_local_node_id(def_id) {
let fndecl = match self.tcx.hir.get(node_id) {
use infer::error_reporting::nice_region_error::NiceRegionError;
use ty;
use util::common::ErrorReported;
+use errors::Applicability;
impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
/// When given a `ConcreteFailure` for a function with arguments containing a named region and
// version new_ty of its type where the anonymous region is replaced
// with the named one.//scope_def_id
let (named, anon, anon_arg_info, region_info) = if self.is_named_region(sub)
- && self.is_suitable_region(sup).is_some()
+ && self.tcx.is_suitable_region(sup).is_some()
&& self.find_arg_with_region(sup, sub).is_some()
{
(
sub,
sup,
self.find_arg_with_region(sup, sub).unwrap(),
- self.is_suitable_region(sup).unwrap(),
+ self.tcx.is_suitable_region(sup).unwrap(),
)
- } else if self.is_named_region(sup) && self.is_suitable_region(sub).is_some()
+ } else if self.is_named_region(sup) && self.tcx.is_suitable_region(sub).is_some()
&& self.find_arg_with_region(sub, sup).is_some()
{
(
sup,
sub,
self.find_arg_with_region(sub, sup).unwrap(),
- self.is_suitable_region(sub).unwrap(),
+ self.tcx.is_suitable_region(sub).unwrap(),
)
} else {
return None; // inapplicable
E0621,
"explicit lifetime required in {}",
error_var
- ).span_suggestion(
+ ).span_suggestion_with_applicability(
new_ty_span,
&format!("add explicit lifetime `{}` to {}", named, span_label_var),
- new_ty.to_string()
+ new_ty.to_string(),
+ Applicability::Unspecified,
)
- .span_label(span, format!("lifetime `{}` required", named))
- .emit();
+ .span_label(span, format!("lifetime `{}` required", named))
+ .emit();
return Some(ErrorReported);
}
use infer::lexical_region_resolve::RegionResolutionError;
use ty::{BoundRegion, FreeRegion, RegionKind};
use util::common::ErrorReported;
+use errors::Applicability;
impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
/// Print the error message for lifetime errors when the return type is a static impl Trait.
sup_origin,
sup_r,
) => {
- let anon_reg_sup = self.is_suitable_region(sup_r)?;
+ let anon_reg_sup = self.tcx.is_suitable_region(sup_r)?;
if sub_r == &RegionKind::ReStatic &&
- self.is_return_type_impl_trait(anon_reg_sup.def_id)
+ self.tcx.return_type_impl_trait(anon_reg_sup.def_id).is_some()
{
let sp = var_origin.span();
let return_sp = sub_origin.span();
_ => "'_".to_owned(),
};
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(return_sp) {
- err.span_suggestion(
+ err.span_suggestion_with_applicability(
return_sp,
&format!(
"you can add a constraint to the return type to make it last \
lifetime,
),
format!("{} + {}", snippet, lifetime_name),
+ Applicability::Unspecified,
);
}
err.emit();
use infer::error_reporting::nice_region_error::NiceRegionError;
use ty::{self, Region, Ty};
use hir::def_id::DefId;
-use hir::Node;
use syntax_pos::Span;
// The struct contains the information about the anonymous region
pub is_first: bool,
}
-// This struct contains information regarding the
-// Refree((FreeRegion) corresponding to lifetime conflict
-#[derive(Debug)]
-pub(super) struct FreeRegionInfo {
- // def id corresponding to FreeRegion
- pub def_id: DefId,
- // the bound region corresponding to FreeRegion
- pub boundregion: ty::BoundRegion,
- // checks if bound region is in Impl Item
- pub is_impl_item: bool,
-}
-
impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
// This method walks the Type of the function body arguments using
// `fold_regions()` function and returns the
}
}
- // This method returns the DefId and the BoundRegion corresponding to the given region.
- pub(super) fn is_suitable_region(&self, region: Region<'tcx>) -> Option<FreeRegionInfo> {
- let (suitable_region_binding_scope, bound_region) = match *region {
- ty::ReFree(ref free_region) => (free_region.scope, free_region.bound_region),
- ty::ReEarlyBound(ref ebr) => (
- self.tcx.parent_def_id(ebr.def_id).unwrap(),
- ty::BoundRegion::BrNamed(ebr.def_id, ebr.name),
- ),
- _ => return None, // not a free region
- };
-
- let node_id = self.tcx
- .hir
- .as_local_node_id(suitable_region_binding_scope)
- .unwrap();
- let is_impl_item = match self.tcx.hir.find(node_id) {
- Some(Node::Item(..)) | Some(Node::TraitItem(..)) => false,
- Some(Node::ImplItem(..)) => {
- self.is_bound_region_in_impl_item(suitable_region_binding_scope)
- }
- _ => return None,
- };
-
- return Some(FreeRegionInfo {
- def_id: suitable_region_binding_scope,
- boundregion: bound_region,
- is_impl_item: is_impl_item,
- });
- }
-
// Here, we check for the case where the anonymous region
// is in the return type.
// FIXME(#42703) - Need to handle certain cases here.
None
}
- pub(super) fn is_return_type_impl_trait(
- &self,
- scope_def_id: DefId,
- ) -> bool {
- let ret_ty = self.tcx.type_of(scope_def_id);
- match ret_ty.sty {
- ty::FnDef(_, _) => {
- let sig = ret_ty.fn_sig(self.tcx);
- let output = self.tcx.erase_late_bound_regions(&sig.output());
- return output.is_impl_trait();
- }
- _ => {}
- }
- false
- }
-
// Here we check for the case where anonymous region
// corresponds to self and if yes, we display E0312.
// FIXME(#42700) - Need to format self properly to
.map(|i| i.method_has_self_argument) == Some(true)
}
- // Here we check if the bound region is in Impl Item.
- pub(super) fn is_bound_region_in_impl_item(
- &self,
- suitable_region_binding_scope: DefId,
- ) -> bool {
- let container_id = self.tcx
- .associated_item(suitable_region_binding_scope)
- .container
- .id();
- if self.tcx.impl_trait_ref(container_id).is_some() {
- // For now, we do not try to target impls of traits. This is
- // because this message is going to suggest that the user
- // change the fn signature, but they may not be free to do so,
- // since the signature must match the trait.
- //
- // FIXME(#42706) -- in some cases, we could do better here.
- return true;
- }
- false
- }
}
#![cfg_attr(not(stage0), feature(impl_header_lifetime_elision))]
#![feature(in_band_lifetimes)]
#![feature(macro_at_most_once_rep)]
-#![feature(crate_in_paths)]
+#![cfg_attr(stage0, feature(crate_in_paths))]
#![feature(crate_visibility_modifier)]
#![recursion_limit="512"]
debug!("consume_body: arg_ty = {:?}", arg_ty);
let fn_body_scope_r =
- self.tcx().mk_region(ty::ReScope(region::Scope::Node(body.value.hir_id.local_id)));
+ self.tcx().mk_region(ty::ReScope(
+ region::Scope {
+ id: body.value.hir_id.local_id,
+ data: region::ScopeData::Node
+ }));
let arg_cmt = Rc::new(self.mc.cat_rvalue(
arg.hir_id,
arg.pat.span,
_ => {
if let Some(def) = self.mc.tables.type_dependent_defs().get(call.hir_id) {
let def_id = def.def_id();
- let call_scope = region::Scope::Node(call.hir_id.local_id);
+ let call_scope = region::Scope {
+ id: call.hir_id.local_id,
+ data: region::ScopeData::Node
+ };
match OverloadedCallType::from_method_id(self.tcx(), def_id) {
FnMutOverloadedCall => {
let call_scope_r = self.tcx().mk_region(ty::ReScope(call_scope));
// treated as borrowing it for the enclosing temporary
// scope.
let r = self.tcx().mk_region(ty::ReScope(
- region::Scope::Node(expr.hir_id.local_id)));
+ region::Scope {
+ id: expr.hir_id.local_id,
+ data: region::ScopeData::Node
+ }));
self.delegate.borrow(expr.id,
expr.span,
//! methods. It effectively does a reverse walk of the AST; whenever we
//! reach a loop node, we iterate until a fixed point is reached.
//!
-//! ## The `Users` struct
+//! ## The `users_*` fields
//!
//! At each live node `N`, we track three pieces of information for each
-//! variable `V` (these are encapsulated in the `Users` struct):
+//! variable `V` (these are in the `users_*` fields):
//!
//! - `reader`: the `LiveNode` ID of some node which will read the value
//! that `V` holds on entry to `N`. Formally: a node `M` such
// Actually we compute just a bit more than just liveness, but we use
// the same basic propagation framework in all cases.
-#[derive(Clone, Copy)]
-struct Users {
- reader: LiveNode,
- writer: LiveNode,
- used: bool
-}
-
-fn invalid_users() -> Users {
- Users {
- reader: invalid_node(),
- writer: invalid_node(),
- used: false
- }
-}
-
#[derive(Copy, Clone)]
struct Specials {
exit_ln: LiveNode,
tables: &'a ty::TypeckTables<'tcx>,
s: Specials,
successors: Vec<LiveNode>,
- users: Vec<Users>,
+
+ // We used to have a single `users: Vec<Users>` field here, where `Users`
+ // had `reader`, `writer` and `used` fields. But the number of users can
+ // get very large, and it's more compact to store the data in three
+ // separate `Vec`s so that no space is wasted for padding.
+ users_reader: Vec<LiveNode>,
+ users_writer: Vec<LiveNode>,
+ users_used: Vec<bool>,
// mappings from loop node ID to LiveNode
// ("break" label should map to loop node ID,
let num_live_nodes = ir.num_live_nodes;
let num_vars = ir.num_vars;
+ let num_users = num_live_nodes * num_vars;
Liveness {
ir,
tables,
s: specials,
successors: vec![invalid_node(); num_live_nodes],
- users: vec![invalid_users(); num_live_nodes * num_vars],
+ users_reader: vec![invalid_node(); num_users],
+ users_writer: vec![invalid_node(); num_users],
+ users_used: vec![false; num_users],
break_ln: NodeMap(),
cont_ln: NodeMap(),
}
fn live_on_entry(&self, ln: LiveNode, var: Variable)
-> Option<LiveNodeKind> {
assert!(ln.is_valid());
- let reader = self.users[self.idx(ln, var)].reader;
+ let reader = self.users_reader[self.idx(ln, var)];
if reader.is_valid() {Some(self.ir.lnk(reader))} else {None}
}
fn used_on_entry(&self, ln: LiveNode, var: Variable) -> bool {
assert!(ln.is_valid());
- self.users[self.idx(ln, var)].used
+ self.users_used[self.idx(ln, var)]
}
fn assigned_on_entry(&self, ln: LiveNode, var: Variable)
-> Option<LiveNodeKind> {
assert!(ln.is_valid());
- let writer = self.users[self.idx(ln, var)].writer;
+ let writer = self.users_writer[self.idx(ln, var)];
if writer.is_valid() {Some(self.ir.lnk(writer))} else {None}
}
{
let wr = &mut wr as &mut dyn Write;
write!(wr, "[ln({:?}) of kind {:?} reads", ln.get(), self.ir.lnk(ln));
- self.write_vars(wr, ln, |idx| self.users[idx].reader);
+ self.write_vars(wr, ln, |idx| self.users_reader[idx]);
write!(wr, " writes");
- self.write_vars(wr, ln, |idx| self.users[idx].writer);
+ self.write_vars(wr, ln, |idx| self.users_writer[idx]);
write!(wr, " precedes {:?}]", self.successors[ln.get()]);
}
String::from_utf8(wr).unwrap()
// only grow during iterations.
//
// self.indices(ln) { |idx|
- // self.users[idx] = invalid_users();
+ // self.users_reader[idx] = invalid_node();
+ // self.users_writer[idx] = invalid_node();
+ // self.users_used[idx] = false;
// }
}
self.successors[ln.get()] = succ_ln;
self.indices2(ln, succ_ln, |this, idx, succ_idx| {
- this.users[idx] = this.users[succ_idx]
+ this.users_reader[idx] = this.users_reader[succ_idx];
+ this.users_writer[idx] = this.users_writer[succ_idx];
+ this.users_used[idx] = this.users_used[succ_idx];
});
debug!("init_from_succ(ln={}, succ={})",
self.ln_str(ln), self.ln_str(succ_ln));
let mut changed = false;
self.indices2(ln, succ_ln, |this, idx, succ_idx| {
- changed |= copy_if_invalid(this.users[succ_idx].reader,
- &mut this.users[idx].reader);
- changed |= copy_if_invalid(this.users[succ_idx].writer,
- &mut this.users[idx].writer);
- if this.users[succ_idx].used && !this.users[idx].used {
- this.users[idx].used = true;
+ changed |= copy_if_invalid(this.users_reader[succ_idx], &mut this.users_reader[idx]);
+ changed |= copy_if_invalid(this.users_writer[succ_idx], &mut this.users_writer[idx]);
+ if this.users_used[succ_idx] && !this.users_used[idx] {
+ this.users_used[idx] = true;
changed = true;
}
});
// this) so we just clear out all the data.
fn define(&mut self, writer: LiveNode, var: Variable) {
let idx = self.idx(writer, var);
- self.users[idx].reader = invalid_node();
- self.users[idx].writer = invalid_node();
+ self.users_reader[idx] = invalid_node();
+ self.users_writer[idx] = invalid_node();
debug!("{:?} defines {:?} (idx={}): {}", writer, var,
idx, self.ln_str(writer));
ln, acc, var, self.ln_str(ln));
let idx = self.idx(ln, var);
- let user = &mut self.users[idx];
if (acc & ACC_WRITE) != 0 {
- user.reader = invalid_node();
- user.writer = ln;
+ self.users_reader[idx] = invalid_node();
+ self.users_writer[idx] = ln;
}
// Important: if we both read/write, must do read second
// or else the write will override.
if (acc & ACC_READ) != 0 {
- user.reader = ln;
+ self.users_reader[idx] = ln;
}
if (acc & ACC_USE) != 0 {
- user.used = true;
+ self.users_used[idx] = true;
}
}
/// generated via deriving here.
#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Copy, RustcEncodable, RustcDecodable)]
pub struct Scope {
- pub(crate) id: hir::ItemLocalId,
- pub(crate) data: ScopeData,
+ pub id: hir::ItemLocalId,
+ pub data: ScopeData,
}
impl fmt::Debug for Scope {
#[cfg(not(stage0))]
static ASSERT: () = [()][!(mem::size_of::<ScopeData>() == 4) as usize];
-#[allow(non_snake_case)]
-impl Scope {
- #[inline]
- pub fn data(self) -> ScopeData {
- self.data
- }
-
- #[inline]
- pub fn new(id: hir::ItemLocalId, data: ScopeData) -> Self {
- Scope { id, data }
- }
-
- #[inline]
- pub fn Node(id: hir::ItemLocalId) -> Self {
- Self::new(id, ScopeData::Node)
- }
-
- #[inline]
- pub fn CallSite(id: hir::ItemLocalId) -> Self {
- Self::new(id, ScopeData::CallSite)
- }
-
- #[inline]
- pub fn Arguments(id: hir::ItemLocalId) -> Self {
- Self::new(id, ScopeData::Arguments)
- }
-
- #[inline]
- pub fn Destruction(id: hir::ItemLocalId) -> Self {
- Self::new(id, ScopeData::Destruction)
- }
-
- #[inline]
- pub fn Remainder(
- id: hir::ItemLocalId,
- first: FirstStatementIndex,
- ) -> Self {
- Self::new(id, ScopeData::Remainder(first))
- }
-}
-
-
impl Scope {
/// Returns a item-local id associated with this scope.
///
return DUMMY_SP;
}
let span = tcx.hir.span(node_id);
- if let ScopeData::Remainder(first_statement_index) = self.data() {
+ if let ScopeData::Remainder(first_statement_index) = self.data {
if let Node::Block(ref blk) = tcx.hir.get(node_id) {
// Want span for scope starting after the
// indexed statement and ending at end of
}
// record the destruction scopes for later so we can query them
- if let ScopeData::Destruction = child.data() {
+ if let ScopeData::Destruction = child.data {
self.destruction_scopes.insert(child.item_local_id(), child);
}
}
// if there's one. Static items, for instance, won't
// have an enclosing scope, hence no scope will be
// returned.
- let mut id = Scope::Node(expr_id);
+ let mut id = Scope { id: expr_id, data: ScopeData::Node };
while let Some(&(p, _)) = self.parent_map.get(&id) {
- match p.data() {
+ match p.data {
ScopeData::Destruction => {
debug!("temporary_scope({:?}) = {:?} [enclosing]",
expr_id, id);
/// Returns the id of the innermost containing body
pub fn containing_body(&self, mut scope: Scope)-> Option<hir::ItemLocalId> {
loop {
- if let ScopeData::CallSite = scope.data() {
+ if let ScopeData::CallSite = scope.data {
return Some(scope.item_local_id());
}
self.root_body.unwrap().local_id
});
- Scope::CallSite(scope)
+ Scope { id: scope, data: ScopeData::CallSite }
}
/// Assuming that the provided region was defined within this `ScopeTree`,
let param_owner_id = tcx.hir.as_local_node_id(param_owner).unwrap();
let body_id = tcx.hir.body_owned_by(param_owner_id);
- Scope::CallSite(tcx.hir.body(body_id).value.hir_id.local_id)
+ Scope { id: tcx.hir.body(body_id).value.hir_id.local_id, data: ScopeData::CallSite }
}
/// Checks whether the given scope contains a `yield`. If so,
// except for the first such subscope, which has the
// block itself as a parent.
visitor.enter_scope(
- Scope::Remainder(blk.hir_id.local_id, FirstStatementIndex::new(i))
+ Scope {
+ id: blk.hir_id.local_id,
+ data: ScopeData::Remainder(FirstStatementIndex::new(i))
+ }
);
visitor.cx.var_parent = visitor.cx.parent;
}
}
fn resolve_pat<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, pat: &'tcx hir::Pat) {
- visitor.record_child_scope(Scope::Node(pat.hir_id.local_id));
+ visitor.record_child_scope(Scope { id: pat.hir_id.local_id, data: ScopeData::Node });
// If this is a binding then record the lifetime of that binding.
if let PatKind::Binding(..) = pat.node {
if let hir::ExprKind::Yield(..) = expr.node {
// Mark this expr's scope and all parent scopes as containing `yield`.
- let mut scope = Scope::Node(expr.hir_id.local_id);
+ let mut scope = Scope { id: expr.hir_id.local_id, data: ScopeData::Node };
loop {
visitor.scope_tree.yield_in_scope.insert(scope,
(expr.span, visitor.expr_and_pat_count));
// Keep traversing up while we can.
match visitor.scope_tree.parent_map.get(&scope) {
// Don't cross from closure bodies to their parent.
- Some(&(superscope, _)) => match superscope.data() {
+ Some(&(superscope, _)) => match superscope.data {
ScopeData::CallSite => break,
_ => scope = superscope
},
// account for the destruction scope representing the scope of
// the destructors that run immediately after it completes.
if self.terminating_scopes.contains(&id) {
- self.enter_scope(Scope::Destruction(id));
+ self.enter_scope(Scope { id, data: ScopeData::Destruction });
}
- self.enter_scope(Scope::Node(id));
+ self.enter_scope(Scope { id, data: ScopeData::Node });
}
}
}
self.cx.root_id = Some(body.value.hir_id.local_id);
- self.enter_scope(Scope::CallSite(body.value.hir_id.local_id));
- self.enter_scope(Scope::Arguments(body.value.hir_id.local_id));
+ self.enter_scope(Scope { id: body.value.hir_id.local_id, data: ScopeData::CallSite });
+ self.enter_scope(Scope { id: body.value.hir_id.local_id, data: ScopeData::Arguments });
// The arguments and `self` are parented to the fn.
self.cx.var_parent = self.cx.parent.take();
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use rustc_data_structures::bitvec::BitArray;
+use rustc_data_structures::bit_set::BitSet;
use super::*;
#[derive(Clone)]
pub struct Preorder<'a, 'tcx: 'a> {
mir: &'a Mir<'tcx>,
- visited: BitArray<BasicBlock>,
+ visited: BitSet<BasicBlock>,
worklist: Vec<BasicBlock>,
}
Preorder {
mir,
- visited: BitArray::new(mir.basic_blocks().len()),
+ visited: BitSet::new_empty(mir.basic_blocks().len()),
worklist,
}
}
/// A Postorder traversal of this graph is `D B C A` or `D C B A`
pub struct Postorder<'a, 'tcx: 'a> {
mir: &'a Mir<'tcx>,
- visited: BitArray<BasicBlock>,
+ visited: BitSet<BasicBlock>,
visit_stack: Vec<(BasicBlock, Successors<'a>)>
}
pub fn new(mir: &'a Mir<'tcx>, root: BasicBlock) -> Postorder<'a, 'tcx> {
let mut po = Postorder {
mir,
- visited: BitArray::new(mir.basic_blocks().len()),
+ visited: BitSet::new_empty(mir.basic_blocks().len()),
visit_stack: Vec::new()
};
// DO NOT switch BTreeMap or BTreeSet out for an unsorted container type! That
// would break dependency tracking for commandline arguments.
#[derive(Clone, Hash)]
-pub struct Externs(BTreeMap<String, BTreeSet<String>>);
+pub struct Externs(BTreeMap<String, BTreeSet<Option<String>>>);
impl Externs {
- pub fn new(data: BTreeMap<String, BTreeSet<String>>) -> Externs {
+ pub fn new(data: BTreeMap<String, BTreeSet<Option<String>>>) -> Externs {
Externs(data)
}
- pub fn get(&self, key: &str) -> Option<&BTreeSet<String>> {
+ pub fn get(&self, key: &str) -> Option<&BTreeSet<Option<String>>> {
self.0.get(key)
}
- pub fn iter<'a>(&'a self) -> BTreeMapIter<'a, String, BTreeSet<String>> {
+ pub fn iter<'a>(&'a self) -> BTreeMapIter<'a, String, BTreeSet<Option<String>>> {
self.0.iter()
}
}
"disable user provided type assertion in NLL"),
nll_dont_emit_read_for_match: bool = (false, parse_bool, [UNTRACKED],
"in match codegen, do not include ReadForMatch statements (used by mir-borrowck)"),
+ dont_buffer_diagnostics: bool = (false, parse_bool, [UNTRACKED],
+ "emit diagnostics rather than buffering (breaks NLL error downgrading, sorting)."),
polonius: bool = (false, parse_bool, [UNTRACKED],
"enable polonius-based borrow-checker"),
codegen_time_graph: bool = (false, parse_bool, [UNTRACKED],
let cfg = parse_cfgspecs(matches.opt_strs("cfg"));
let test = matches.opt_present("test");
+ let is_unstable_enabled = nightly_options::is_unstable_enabled(matches);
+
prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s {
"crate-name" => PrintRequest::CrateName,
"file-names" => PrintRequest::FileNames,
"tls-models" => PrintRequest::TlsModels,
"native-static-libs" => PrintRequest::NativeStaticLibs,
"target-spec-json" => {
- if nightly_options::is_unstable_enabled(matches) {
+ if is_unstable_enabled {
PrintRequest::TargetSpec
} else {
early_error(
error_format,
- &format!(
- "the `-Z unstable-options` flag must also be passed to \
- enable the target-spec-json print option"
- ),
+ "the `-Z unstable-options` flag must also be passed to \
+ enable the target-spec-json print option",
);
}
}
Some(s) => s,
None => early_error(error_format, "--extern value must not be empty"),
};
- let location = match parts.next() {
- Some(s) => s,
- None => early_error(
+ let location = parts.next().map(|s| s.to_string());
+ if location.is_none() && !is_unstable_enabled {
+ early_error(
error_format,
- "--extern value must be of the format `foo=bar`",
- ),
+ "the `-Z unstable-options` flag must also be passed to \
+ enable `--extern crate_name` without `=path`",
+ );
};
externs
.entry(name.to_string())
.or_default()
- .insert(location.to_string());
+ .insert(location);
}
let crate_name = matches.opt_str("crate-name");
v1.externs = Externs::new(mk_map(vec![
(
String::from("a"),
- mk_set(vec![String::from("b"), String::from("c")]),
+ mk_set(vec![Some(String::from("b")), Some(String::from("c"))]),
),
(
String::from("d"),
- mk_set(vec![String::from("e"), String::from("f")]),
+ mk_set(vec![Some(String::from("e")), Some(String::from("f"))]),
),
]));
v2.externs = Externs::new(mk_map(vec![
(
String::from("d"),
- mk_set(vec![String::from("e"), String::from("f")]),
+ mk_set(vec![Some(String::from("e")), Some(String::from("f"))]),
),
(
String::from("a"),
- mk_set(vec![String::from("b"), String::from("c")]),
+ mk_set(vec![Some(String::from("b")), Some(String::from("c"))]),
),
]));
v3.externs = Externs::new(mk_map(vec![
(
String::from("a"),
- mk_set(vec![String::from("b"), String::from("c")]),
+ mk_set(vec![Some(String::from("b")), Some(String::from("c"))]),
),
(
String::from("d"),
- mk_set(vec![String::from("f"), String::from("e")]),
+ mk_set(vec![Some(String::from("f")), Some(String::from("e"))]),
),
]));
use rustc_data_structures::sync::{self, Lrc, Lock, LockCell, OneThread, Once, RwLock};
use syntax::ast::NodeId;
-use errors::{self, DiagnosticBuilder, DiagnosticId};
+use errors::{self, DiagnosticBuilder, DiagnosticId, Applicability};
use errors::emitter::{Emitter, EmitterWriter};
use syntax::edition::Edition;
use syntax::json::JsonEmitter;
diag_builder.span_note(span, message);
}
DiagnosticBuilderMethod::SpanSuggestion(suggestion) => {
- let span = span_maybe.expect("span_suggestion needs a span");
- diag_builder.span_suggestion(span, message, suggestion);
+ let span = span_maybe.expect("span_suggestion_* needs a span");
+ diag_builder.span_suggestion_with_applicability(
+ span,
+ message,
+ suggestion,
+ Applicability::Unspecified,
+ );
}
}
}
let can_emit_warnings = !(warnings_allow || cap_lints_allow);
let treat_err_as_bug = sopts.debugging_opts.treat_err_as_bug;
+ let dont_buffer_diagnostics = sopts.debugging_opts.dont_buffer_diagnostics;
let report_delayed_bugs = sopts.debugging_opts.report_delayed_bugs;
let external_macro_backtrace = sopts.debugging_opts.external_macro_backtrace;
can_emit_warnings,
treat_err_as_bug,
report_delayed_bugs,
+ dont_buffer_diagnostics,
external_macro_backtrace,
..Default::default()
},
orig_params,
trait_pred.to_poly_trait_predicate(),
));
+
match result {
Ok(Some(Vtable::VtableImpl(_))) => {
debug!(
manual impl found, bailing out",
did, trait_did, generics
);
- return true;
+ true
}
- _ => return false,
- };
+ _ => false
+ }
});
// If an explicit impl exists, it always takes priority over an auto impl
if new_trait.def_id() == old_trait.def_id() {
let new_substs = new_trait.skip_binder().trait_ref.substs;
let old_substs = old_trait.skip_binder().trait_ref.substs;
+
if !new_substs.types().eq(old_substs.types()) {
// We can't compare lifetimes if the types are different,
// so skip checking old_pred
pub fn get_lifetime(&self, region: Region, names_map: &FxHashMap<String, String>) -> String {
self.region_name(region)
- .map(|name| {
- names_map.get(&name).unwrap_or_else(|| {
+ .map(|name|
+ names_map.get(&name).unwrap_or_else(||
panic!("Missing lifetime with name {:?} for {:?}", name, region)
- })
- })
- .unwrap_or(&"'static".to_string())
+ )
+ )
+ .unwrap_or(&"'static".to_owned())
.clone()
}
let trait_ref = ty.erase_regions(&trait_ref);
debug!("codegen_fulfill_obligation(trait_ref={:?}, def_id={:?})",
- (param_env, trait_ref), trait_ref.def_id());
+ (param_env, 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.
let obligation_cause = ObligationCause::dummy();
let obligation = Obligation::new(obligation_cause,
- param_env,
- trait_ref.to_poly_trait_predicate());
+ param_env,
+ trait_ref.to_poly_trait_predicate());
let selection = match selcx.select(&obligation) {
Ok(Some(selection)) => selection,
// overflow bug, since I believe this is the only case
// where ambiguity can result.
bug!("Encountered ambiguity selecting `{:?}` during codegen, \
- presuming due to overflow",
- trait_ref)
+ presuming due to overflow",
+ trait_ref)
}
Err(e) => {
- bug!("Encountered error `{:?}` selecting `{:?}` during codegen",
- e, trait_ref)
+ bug!("Encountered error `{:?}` selecting `{:?}` during codegen", e, trait_ref)
}
};
// In principle, we only need to do this so long as `result`
// contains unbound type parameters. It could be a slight
// optimization to stop iterating early.
- match fulfill_cx.select_all_or_error(self) {
- Ok(()) => { }
- Err(errors) => {
- span_bug!(span, "Encountered errors `{:?}` resolving bounds after type-checking",
- errors);
- }
+ if let Err(errors) = fulfill_cx.select_all_or_error(self) {
+ span_bug!(span, "Encountered errors `{:?}` resolving bounds after type-checking",
+ errors);
}
let result = self.resolve_type_vars_if_possible(result);
let result = self.tcx.erase_regions(&result);
- match self.tcx.lift_to_global(&result) {
- Some(result) => result,
- None => {
- span_bug!(span, "Uninferred types/regions in `{:?}`", result);
- }
- }
+ self.tcx.lift_to_global(&result).unwrap_or_else(||
+ span_bug!(span, "Uninferred types/regions in `{:?}`", result)
+ )
}
}
b_def_id: DefId)
-> Option<OverlapResult<'tcx>>
{
- debug!("overlap(a_def_id={:?}, b_def_id={:?})",
- a_def_id,
- b_def_id);
+ debug!("overlap(a_def_id={:?}, b_def_id={:?})", a_def_id, b_def_id);
// For the purposes of this check, we don't bring any skolemized
// types into scope; instead, we replace the generic types with
// Do `a` and `b` unify? If not, no overlap.
let obligations = match selcx.infcx().at(&ObligationCause::dummy(), param_env)
- .eq_impl_headers(&a_impl_header, &b_impl_header) {
- Ok(InferOk { obligations, value: () }) => {
- obligations
- }
+ .eq_impl_headers(&a_impl_header, &b_impl_header)
+ {
+ Ok(InferOk { obligations, value: () }) => obligations,
Err(_) => return None
};
return None
}
- let impl_header = selcx.infcx().resolve_type_vars_if_possible(&a_impl_header);
+ let impl_header = selcx.infcx().resolve_type_vars_if_possible(&a_impl_header);
let intercrate_ambiguity_causes = selcx.take_intercrate_ambiguity_causes();
debug!("overlap: intercrate_ambiguity_causes={:#?}", intercrate_ambiguity_causes);
Some(OverlapResult { impl_header, intercrate_ambiguity_causes })
ty::Foreign(did) => def_id_is_local(did, in_crate),
ty::Dynamic(ref tt, ..) => {
- tt.principal().map_or(false, |p| {
+ tt.principal().map_or(false, |p|
def_id_is_local(p.def_id(), in_crate)
- })
+ )
}
- ty::Error => {
- true
- }
+ ty::Error => true,
ty::Closure(..) |
ty::Generator(..) |
use infer::{self, InferCtxt};
use infer::type_variable::TypeVariableOrigin;
use std::fmt;
+use std::iter;
use syntax::ast;
use session::DiagnosticMessageId;
use ty::{self, AdtKind, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
index: Option<usize>, // None if this is an old error
}
- let mut error_map : FxHashMap<_, Vec<_>> =
+ let mut error_map: FxHashMap<_, Vec<_>> =
self.reported_trait_errors.borrow().iter().map(|(&span, predicates)| {
(span, predicates.iter().map(|predicate| ErrorDescriptor {
predicate: 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<bool> = errors.iter().map(|_| false).collect();
+ let mut is_suppressed = vec![false; errors.len()];
for (_, error_set) in error_map.iter() {
// We want to suppress "duplicate" errors with the same span.
for error in error_set {
_ => {
// this is a "direct", user-specified, rather than derived,
// obligation.
- flags.push(("direct".to_string(), None));
+ flags.push(("direct".to_owned(), None));
}
}
// Currently I'm leaving it for what I need for `try`.
if self.tcx.trait_of_item(item) == Some(trait_ref.def_id) {
let method = self.tcx.item_name(item);
- flags.push(("from_method".to_string(), None));
- flags.push(("from_method".to_string(), Some(method.to_string())));
+ flags.push(("from_method".to_owned(), None));
+ flags.push(("from_method".to_owned(), Some(method.to_string())));
}
}
if let Some(k) = obligation.cause.span.compiler_desugaring_kind() {
- flags.push(("from_desugaring".to_string(), None));
- flags.push(("from_desugaring".to_string(), Some(k.name().to_string())));
+ flags.push(("from_desugaring".to_owned(), None));
+ flags.push(("from_desugaring".to_owned(), Some(k.name().to_string())));
}
let generics = self.tcx.generics_of(def_id);
let self_ty = trait_ref.self_ty();
// This is also included through the generics list as `Self`,
// but the parser won't allow you to use it
- flags.push(("_Self".to_string(), Some(self_ty.to_string())));
+ flags.push(("_Self".to_owned(), Some(self_ty.to_string())));
if let Some(def) = self_ty.ty_adt_def() {
// We also want to be able to select self's original
// signature with no type arguments resolved
- flags.push(("_Self".to_string(), Some(self.tcx.type_of(def.did).to_string())));
+ flags.push(("_Self".to_owned(), Some(self.tcx.type_of(def.did).to_string())));
}
for param in generics.params.iter() {
}
if let Some(true) = self_ty.ty_adt_def().map(|def| def.did.is_local()) {
- flags.push(("crate_local".to_string(), None));
+ flags.push(("crate_local".to_owned(), None));
}
if let Ok(Some(command)) = OnUnimplementedDirective::of_item(
let simp = fast_reject::simplify_type(self.tcx,
trait_ref.skip_binder().self_ty(),
true);
- let mut impl_candidates = Vec::new();
+ let all_impls = self.tcx.all_impls(trait_ref.def_id());
match simp {
- Some(simp) => self.tcx.for_each_impl(trait_ref.def_id(), |def_id| {
+ Some(simp) => all_impls.iter().filter_map(|&def_id| {
let imp = self.tcx.impl_trait_ref(def_id).unwrap();
let imp_simp = fast_reject::simplify_type(self.tcx,
imp.self_ty(),
true);
if let Some(imp_simp) = imp_simp {
if simp != imp_simp {
- return;
+ return None
}
}
- impl_candidates.push(imp);
- }),
- None => self.tcx.for_each_impl(trait_ref.def_id(), |def_id| {
- impl_candidates.push(
- self.tcx.impl_trait_ref(def_id).unwrap());
- })
- };
- impl_candidates
+
+ Some(imp)
+ }).collect(),
+ None => all_impls.iter().map(|&def_id|
+ self.tcx.impl_trait_ref(def_id).unwrap()
+ ).collect()
+ }
}
fn report_similar_impl_candidates(&self,
span,
E0277,
"{}",
- message.unwrap_or_else(|| {
+ message.unwrap_or_else(||
format!("the trait bound `{}` is not satisfied{}",
trait_ref.to_predicate(), post_message)
- }));
+ ));
let explanation =
if obligation.cause.code == ObligationCauseCode::MainFunctionType {
// "the type `T` can't be frobnicated"
// which is somewhat confusing.
err.help(&format!("consider adding a `where {}` bound",
- trait_ref.to_predicate()));
+ trait_ref.to_predicate()));
} else if !have_alt_message {
// Can't show anything else useful, try to find similar impls.
let impl_candidates = self.find_similar_impl_candidates(trait_ref);
ty::Predicate::RegionOutlives(ref predicate) => {
let predicate = self.resolve_type_vars_if_possible(predicate);
let err = self.region_outlives_predicate(&obligation.cause,
- &predicate).err().unwrap();
+ &predicate).err().unwrap();
struct_span_err!(self.tcx.sess, span, E0279,
"the requirement `{}` is not satisfied (`{}`)",
predicate, err)
let mut err = struct_span_err!(
self.tcx.sess, closure_span, E0525,
"expected a closure that implements the `{}` trait, \
- but this closure only implements `{}`",
+ but this closure only implements `{}`",
kind,
found_kind);
OutputTypeParameterMismatch(ref found_trait_ref, ref expected_trait_ref, _) => {
let found_trait_ref = self.resolve_type_vars_if_possible(&*found_trait_ref);
let expected_trait_ref = self.resolve_type_vars_if_possible(&*expected_trait_ref);
+
if expected_trait_ref.self_ty().references_error() {
return;
}
+
let found_trait_ty = found_trait_ref.self_ty();
let found_did = match found_trait_ty.sty {
- ty::Closure(did, _) |
- ty::Foreign(did) |
- ty::FnDef(did, _) => Some(did),
+ ty::Closure(did, _) | ty::Foreign(did) | ty::FnDef(did, _) => Some(did),
ty::Adt(def, _) => Some(def.did),
_ => None,
};
- let found_span = found_did.and_then(|did| {
+
+ let found_span = found_did.and_then(|did|
self.tcx.hir.span_if_local(did)
- }).map(|sp| self.tcx.sess.source_map().def_span(sp)); // the sp could be an fn def
+ ).map(|sp| self.tcx.sess.source_map().def_span(sp)); // the sp could be an fn def
let found = match found_trait_ref.skip_binder().substs.type_at(1).sty {
- ty::Tuple(ref tys) => tys.iter()
- .map(|_| ArgKind::empty()).collect::<Vec<_>>(),
+ ty::Tuple(ref tys) => vec![ArgKind::empty(); tys.len()],
_ => vec![ArgKind::empty()],
};
+
let expected = match expected_trait_ref.skip_binder().substs.type_at(1).sty {
ty::Tuple(ref tys) => tys.iter()
- .map(|t| match t.sty {
- ty::Tuple(ref tys) => ArgKind::Tuple(
- Some(span),
- tys.iter()
- .map(|ty| ("_".to_owned(), ty.sty.to_string()))
- .collect::<Vec<_>>()
- ),
- _ => ArgKind::Arg("_".to_owned(), t.sty.to_string()),
- }).collect(),
+ .map(|t| ArgKind::from_expected_ty(t, Some(span))).collect(),
ref sty => vec![ArgKind::Arg("_".to_owned(), sty.to_string())],
};
+
if found.len() == expected.len() {
self.report_closure_arg_mismatch(span,
found_span,
TraitNotObjectSafe(did) => {
let violations = self.tcx.object_safety_violations(did);
- self.tcx.report_object_safety_error(span, did,
- violations)
+ self.tcx.report_object_safety_error(span, did, violations)
}
ConstEvalFailure(ref err) => {
"could not evaluate constant expression",
) {
Some(err) => err,
- None => return,
+ None => {
+ self.tcx.sess.delay_span_bug(span,
+ &format!("constant in type had an ignored error: {:?}", err));
+ return;
+ }
}
}
.map(|arg| match arg.clone().node {
hir::TyKind::Tup(ref tys) => ArgKind::Tuple(
Some(arg.span),
- tys.iter()
- .map(|_| ("_".to_owned(), "_".to_owned()))
- .collect::<Vec<_>>(),
+ vec![("_".to_owned(), "_".to_owned()); tys.len()]
),
- _ => ArgKind::Arg("_".to_owned(), "_".to_owned())
+ _ => ArgKind::empty()
}).collect::<Vec<ArgKind>>())
}
Node::Variant(&hir::Variant {
..
}) => {
(self.tcx.sess.source_map().def_span(span),
- fields.iter().map(|field| {
+ fields.iter().map(|field|
ArgKind::Arg(field.ident.to_string(), "_".to_string())
- }).collect::<Vec<_>>())
+ ).collect::<Vec<_>>())
}
Node::StructCtor(ref variant_data) => {
(self.tcx.sess.source_map().def_span(self.tcx.hir.span(variant_data.id())),
- variant_data.fields()
- .iter().map(|_| ArgKind::Arg("_".to_owned(), "_".to_owned()))
- .collect())
+ vec![ArgKind::empty(); variant_data.fields().len()])
}
_ => panic!("non-FnLike node found: {:?}", node),
}
found_str,
);
- err.span_label(span, format!( "expected {} that takes {}", kind, expected_str));
+ err.span_label(span, format!("expected {} that takes {}", kind, expected_str));
if let Some(found_span) = found_span {
err.span_label(found_span, format!("takes {}", found_str));
// found arguments is empty (assume the user just wants to ignore args in this case).
// For example, if `expected_args_length` is 2, suggest `|_, _|`.
if found_args.is_empty() && is_closure {
- let underscores = "_".repeat(expected_args.len())
- .split("")
- .filter(|s| !s.is_empty())
+ let underscores = iter::repeat("_")
+ .take(expected_args.len())
.collect::<Vec<_>>()
.join(", ");
err.span_suggestion_with_applicability(
if fields.len() == expected_args.len() {
let sugg = fields.iter()
.map(|(name, _)| name.to_owned())
- .collect::<Vec<String>>().join(", ");
+ .collect::<Vec<String>>()
+ .join(", ");
err.span_suggestion_with_applicability(found_span,
"change the closure to take multiple \
arguments instead of a single tuple",
let inputs = trait_ref.substs.type_at(1);
let sig = if let ty::Tuple(inputs) = inputs.sty {
tcx.mk_fn_sig(
- inputs.iter().map(|&x| x),
+ inputs.iter().cloned(),
tcx.mk_infer(ty::TyVar(ty::TyVid { index: 0 })),
false,
hir::Unsafety::Normal,
let mut reported_violations = FxHashSet();
for violation in violations {
- if !reported_violations.insert(violation.clone()) {
- continue;
+ if reported_violations.insert(violation.clone()) {
+ err.note(&violation.error_msg());
}
- err.note(&violation.error_msg());
}
err
}
self.need_type_info_err(body_id, span, self_ty).emit();
} else {
let mut err = struct_span_err!(self.tcx.sess,
- span, E0283,
- "type annotations required: \
+ span, E0283,
+ "type annotations required: \
cannot resolve `{}`",
- predicate);
+ predicate);
self.note_obligation_cause(&mut err, obligation);
err.emit();
}
ObligationCauseCode::ItemObligation(item_def_id) => {
let item_name = tcx.item_path_str(item_def_id);
let msg = format!("required by `{}`", item_name);
+
if let Some(sp) = tcx.hir.span_if_local(item_def_id) {
let sp = tcx.sess.source_map().def_span(sp);
err.span_note(sp, &msg);
parent_trait_ref.skip_binder().self_ty()));
let parent_predicate = parent_trait_ref.to_predicate();
self.note_obligation_cause_code(err,
- &parent_predicate,
- &data.parent_code,
- obligated_types);
+ &parent_predicate,
+ &data.parent_code,
+ obligated_types);
}
ObligationCauseCode::CompareImplMethodObligation { .. } => {
err.note(
}
fn is_recursive_obligation(&self,
- obligated_types: &mut Vec<&ty::TyS<'tcx>>,
- cause_code: &ObligationCauseCode<'tcx>) -> bool {
+ obligated_types: &mut Vec<&ty::TyS<'tcx>>,
+ cause_code: &ObligationCauseCode<'tcx>) -> bool {
if let ObligationCauseCode::BuiltinDerivedObligation(ref data) = cause_code {
let parent_trait_ref = self.resolve_type_vars_if_possible(&data.parent_trait_ref);
- for obligated_type in obligated_types {
- if obligated_type == &parent_trait_ref.skip_binder().self_ty() {
- return true;
- }
+
+ if obligated_types.iter().any(|ot| ot == &parent_trait_ref.skip_binder().self_ty()) {
+ return true;
}
}
- return false;
+ false
}
}
/// Summarizes information
+#[derive(Clone)]
pub enum ArgKind {
/// An argument of non-tuple type. Parameters are (name, ty)
Arg(String, String),
}
/// Creates an `ArgKind` from the expected type of an
- /// argument. This has no name (`_`) and no source spans..
- pub fn from_expected_ty(t: Ty<'_>) -> ArgKind {
+ /// argument. It has no name (`_`) and an optional source span.
+ pub fn from_expected_ty(t: Ty<'_>, span: Option<Span>) -> ArgKind {
match t.sty {
ty::Tuple(ref tys) => ArgKind::Tuple(
- None,
+ span,
tys.iter()
.map(|ty| ("_".to_owned(), ty.sty.to_string()))
.collect::<Vec<_>>()
if self.selcx.coinductive_match(cycle.clone().map(|s| s.obligation.predicate)) {
debug!("process_child_obligations: coinductive match");
} else {
- let cycle : Vec<_> = cycle.map(|c| c.obligation.clone()).collect();
+ let cycle: Vec<_> = cycle.map(|c| c.obligation.clone()).collect();
self.selcx.infcx().report_overflow_error_cycle(&cycle);
}
}
let predicates: Vec<_> =
util::elaborate_predicates(tcx, unnormalized_env.caller_bounds.to_vec())
- .collect();
+ .collect();
debug!("normalize_param_env_or_error: elaborated-predicates={:?}",
predicates);
};
debug!("normalize_param_env_or_error: normalized predicates={:?}",
- predicates);
+ predicates);
let region_scope_tree = region::ScopeTree::default();
// the method may have some early-bound lifetimes, add
// regions for those
- let substs = trait_ref.map_bound(|trait_ref| {
- Substs::for_item(tcx, def_id, |param, _| {
+ let substs = trait_ref.map_bound(|trait_ref|
+ Substs::for_item(tcx, def_id, |param, _|
match param.kind {
GenericParamDefKind::Lifetime => tcx.types.re_erased.into(),
GenericParamDefKind::Type {..} => {
trait_ref.substs[param.index as usize]
}
}
- })
- });
+ )
+ );
// the trait type may have higher-ranked lifetimes in it;
// so erase them if they appear, so that we get the type
// Check methods for violations.
let mut violations: Vec<_> = self.associated_items(trait_def_id)
.filter(|item| item.kind == ty::AssociatedKind::Method)
- .filter_map(|item| {
+ .filter_map(|item|
self.object_safety_violation_for_method(trait_def_id, &item)
.map(|code| ObjectSafetyViolation::Method(item.ident.name, code))
- }).filter(|violation| {
+ ).filter(|violation| {
if let ObjectSafetyViolation::Method(_,
- MethodViolationCode::WhereClauseReferencesSelf(span)) = violation {
- // Using`CRATE_NODE_ID` is wrong, but it's hard to get a more precise id.
+ MethodViolationCode::WhereClauseReferencesSelf(span)) = violation
+ {
+ // Using `CRATE_NODE_ID` is wrong, but it's hard to get a more precise id.
// It's also hard to get a use site span, so we use the method definition span.
self.lint_node_note(
lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY,
ast::CRATE_NODE_ID,
*span,
&format!("the trait `{}` cannot be made into an object",
- self.item_path_str(trait_def_id)),
+ self.item_path_str(trait_def_id)),
&violation.error_msg());
false
} else {
let predicates = self.predicates_of(def_id);
let predicates = predicates.instantiate_identity(self).predicates;
elaborate_predicates(self, predicates)
- .any(|predicate| {
- match predicate {
- ty::Predicate::Trait(ref trait_pred) if trait_pred.def_id() == sized_def_id => {
- trait_pred.skip_binder().self_ty().is_self()
- }
- ty::Predicate::Projection(..) |
- ty::Predicate::Trait(..) |
- ty::Predicate::Subtype(..) |
- ty::Predicate::RegionOutlives(..) |
- ty::Predicate::WellFormed(..) |
- ty::Predicate::ObjectSafe(..) |
- ty::Predicate::ClosureKind(..) |
- ty::Predicate::TypeOutlives(..) |
- ty::Predicate::ConstEvaluatable(..) => {
- false
- }
+ .any(|predicate| match predicate {
+ ty::Predicate::Trait(ref trait_pred) if trait_pred.def_id() == sized_def_id => {
+ trait_pred.skip_binder().self_ty().is_self()
}
- })
+ ty::Predicate::Projection(..) |
+ ty::Predicate::Trait(..) |
+ ty::Predicate::Subtype(..) |
+ ty::Predicate::RegionOutlives(..) |
+ ty::Predicate::WellFormed(..) |
+ ty::Predicate::ObjectSafe(..) |
+ ty::Predicate::ClosureKind(..) |
+ ty::Predicate::TypeOutlives(..) |
+ ty::Predicate::ConstEvaluatable(..) => {
+ false
+ }
+ }
+ )
}
/// Returns `Some(_)` if this method makes the containing trait not object safe.
let condition = if is_root {
None
} else {
- let cond = item_iter.next().ok_or_else(|| {
+ let cond = item_iter.next().ok_or_else(||
parse_error(tcx, span,
"empty `on`-clause in `#[rustc_on_unimplemented]`",
"empty on-clause here",
None)
- })?.meta_item().ok_or_else(|| {
+ )?.meta_item().ok_or_else(||
parse_error(tcx, span,
"invalid `on`-clause in `#[rustc_on_unimplemented]`",
"invalid on-clause here",
None)
- })?;
+ )?;
attr::eval_condition(cond, &tcx.sess.parse_sess, &mut |_| true);
Some(cond.clone())
};
// `{from_desugaring}` is allowed
Position::ArgumentNamed(s) if s == "from_desugaring" => (),
// So is `{A}` if A is a type parameter
- Position::ArgumentNamed(s) => match generics.params.iter().find(|param| {
+ Position::ArgumentNamed(s) => match generics.params.iter().find(|param|
param.name == s
- }) {
+ ) {
Some(_) => (),
None => {
span_err!(tcx.sess, span, E0230,
let empty_string = String::new();
let parser = Parser::new(&self.0, None);
- parser.map(|p| {
+ parser.map(|p|
match p {
Piece::String(s) => s,
Piece::NextArgument(a) => match a.position {
}
}
},
- _ => {
- bug!("broken on_unimplemented {:?} - bad format arg", self.0)
- }
+ _ => bug!("broken on_unimplemented {:?} - bad format arg", self.0)
}
}
- }).collect()
+ ).collect()
}
}
match (current, candidate) {
(ParamEnv(..), ParamEnv(..)) => convert_to_ambiguous = (),
(ParamEnv(..), _) => return false,
- (_, ParamEnv(..)) => { unreachable!(); }
+ (_, ParamEnv(..)) => unreachable!(),
(_, _) => convert_to_ambiguous = (),
}
}
normalized_ty
}
- _ => {
- ty
- }
+ _ => ty
}
}
instance,
promoted: None
};
- match tcx.const_eval(param_env.and(cid)) {
- Ok(evaluated) => {
- let evaluated = evaluated.subst(self.tcx(), substs);
- return self.fold_const(evaluated);
- }
- Err(_) => {}
+ if let Ok(evaluated) = tcx.const_eval(param_env.and(cid)) {
+ let evaluated = evaluated.subst(self.tcx(), substs);
+ return self.fold_const(evaluated);
}
}
} else {
instance,
promoted: None
};
- match tcx.const_eval(param_env.and(cid)) {
- Ok(evaluated) => return self.fold_const(evaluated),
- Err(_) => {}
+ if let Ok(evaluated) = tcx.const_eval(param_env.and(cid)) {
+ return self.fold_const(evaluated)
}
}
}
candidate_set.mark_ambiguous();
return;
}
- _ => { return; }
+ _ => return
};
// If so, extract what we know from the trait and try to come up with a good answer.
for predicate in env_predicates {
debug!("assemble_candidates_from_predicates: predicate={:?}",
predicate);
- match predicate {
- ty::Predicate::Projection(data) => {
- let same_def_id = data.projection_def_id() == obligation.predicate.item_def_id;
-
- let is_match = same_def_id && infcx.probe(|_| {
- let data_poly_trait_ref =
- data.to_poly_trait_ref(infcx.tcx);
- let obligation_poly_trait_ref =
- obligation_trait_ref.to_poly_trait_ref();
- infcx.at(&obligation.cause, obligation.param_env)
- .sup(obligation_poly_trait_ref, data_poly_trait_ref)
- .map(|InferOk { obligations: _, value: () }| {
- // FIXME(#32730) -- do we need to take obligations
- // into account in any way? At the moment, no.
- })
- .is_ok()
- });
-
- debug!("assemble_candidates_from_predicates: candidate={:?} \
- is_match={} same_def_id={}",
- data, is_match, same_def_id);
-
- if is_match {
- candidate_set.push_candidate(ctor(data));
- }
+ if let ty::Predicate::Projection(data) = predicate {
+ let same_def_id = data.projection_def_id() == obligation.predicate.item_def_id;
+
+ let is_match = same_def_id && infcx.probe(|_| {
+ let data_poly_trait_ref =
+ data.to_poly_trait_ref(infcx.tcx);
+ let obligation_poly_trait_ref =
+ obligation_trait_ref.to_poly_trait_ref();
+ infcx.at(&obligation.cause, obligation.param_env)
+ .sup(obligation_poly_trait_ref, data_poly_trait_ref)
+ .map(|InferOk { obligations: _, value: () }| {
+ // FIXME(#32730) -- do we need to take obligations
+ // into account in any way? At the moment, no.
+ })
+ .is_ok()
+ });
+
+ debug!("assemble_candidates_from_predicates: candidate={:?} \
+ is_match={} same_def_id={}",
+ data, is_match, same_def_id);
+
+ if is_match {
+ candidate_set.push_candidate(ctor(data));
}
- _ => {}
}
}
}
return Err(());
}
Err(e) => {
- debug!("assemble_candidates_from_impls: selection error {:?}",
- e);
+ debug!("assemble_candidates_from_impls: selection error {:?}", e);
candidate_set.mark_error(e);
return Err(());
}
let mut env_predicates = env_predicates.filter(|data| {
let data_poly_trait_ref = data.to_poly_trait_ref(selcx.tcx());
let obligation_poly_trait_ref = obligation_trait_ref.to_poly_trait_ref();
- selcx.infcx().probe(|_| {
+ selcx.infcx().probe(|_|
selcx.infcx().at(&obligation.cause, obligation.param_env)
.sup(obligation_poly_trait_ref, data_poly_trait_ref)
.is_ok()
- })
+ )
});
// select the first matching one; there really ought to be one or
obligation.predicate.self_ty(),
fn_sig,
flag)
- .map_bound(|(trait_ref, ret_type)| {
+ .map_bound(|(trait_ref, ret_type)|
ty::ProjectionPredicate {
projection_ty: ty::ProjectionTy::from_ref_and_name(
tcx,
),
ty: ret_type
}
- });
+ );
confirm_param_env_candidate(selcx, obligation, predicate)
}
debug!("c_ty = {:?}", c_ty);
match &gcx.dropck_outlives(c_ty) {
Ok(result) if result.is_proven() => {
- match self.infcx.instantiate_query_result_and_region_obligations(
+ if let Ok(InferOk { value, obligations }) =
+ self.infcx.instantiate_query_result_and_region_obligations(
self.cause,
self.param_env,
&orig_values,
- result,
- ) {
- Ok(InferOk { value, obligations }) => {
- let ty = self.infcx.resolve_type_vars_if_possible(&ty);
- let kinds = value.into_kinds_reporting_overflows(tcx, span, ty);
- return InferOk {
- value: kinds,
- obligations,
- };
- }
-
- Err(_) => { /* fallthrough to error-handling code below */ }
+ result)
+ {
+ let ty = self.infcx.resolve_type_vars_if_possible(&ty);
+ let kinds = value.into_kinds_reporting_overflows(tcx, span, ty);
+ return InferOk {
+ value: kinds,
+ obligations,
+ };
}
}
fn from_iter<I: IntoIterator<Item = DtorckConstraint<'tcx>>>(iter: I) -> Self {
let mut result = Self::empty();
- for DtorckConstraint {
- outlives,
- dtorck_types,
- overflows,
- } in iter
- {
+ for DtorckConstraint { outlives, dtorck_types, overflows } in iter {
result.outlives.extend(outlives);
result.dtorck_types.extend(dtorck_types);
result.overflows.extend(overflows);
}
}
- // The following *might* require a destructor: it would deeper inspection to tell.
+ // The following *might* require a destructor: needs deeper inspection.
ty::Dynamic(..)
| ty::Projection(..)
| ty::Param(_)
value,
self.param_env,
);
+ if !value.has_projections() {
+ return Ok(Normalized {
+ value: value.clone(),
+ obligations: vec![],
+ });
+ }
+
let mut normalizer = QueryNormalizer {
infcx: self.infcx,
cause: self.cause,
error: false,
anon_depth: 0,
};
- if !value.has_projections() {
- return Ok(Normalized {
- value: value.clone(),
- obligations: vec![],
- });
- }
let value1 = value.fold_with(&mut normalizer);
if normalizer.error {
let gcx = self.infcx.tcx.global_tcx();
let mut orig_values = SmallVec::new();
- let c_data = self.infcx
- .canonicalize_query(&self.param_env.and(*data), &mut orig_values);
+ let c_data = self.infcx.canonicalize_query(
+ &self.param_env.and(*data), &mut orig_values);
debug!("QueryNormalizer: c_data = {:#?}", c_data);
debug!("QueryNormalizer: orig_values = {:#?}", orig_values);
match gcx.normalize_projection_ty(c_data) {
self.cause,
self.param_env,
&orig_values,
- &result,
- ) {
- Ok(InferOk {
- value: result,
- obligations,
- }) => {
+ &result)
+ {
+ Ok(InferOk { value: result, obligations }) => {
debug!("QueryNormalizer: result = {:#?}", result);
debug!("QueryNormalizer: obligations = {:#?}", obligations);
self.obligations.extend(obligations);
instance,
promoted: None,
};
- match tcx.const_eval(param_env.and(cid)) {
- Ok(evaluated) => {
- let evaluated = evaluated.subst(self.tcx(), substs);
- return self.fold_const(evaluated);
- }
- Err(_) => {}
+ if let Ok(evaluated) = tcx.const_eval(param_env.and(cid)) {
+ let evaluated = evaluated.subst(self.tcx(), substs);
+ return self.fold_const(evaluated);
}
}
} else {
instance,
promoted: None,
};
- match tcx.const_eval(param_env.and(cid)) {
- Ok(evaluated) => return self.fold_const(evaluated),
- Err(_) => {}
+ if let Ok(evaluated) = tcx.const_eval(param_env.and(cid)) {
+ return self.fold_const(evaluated)
}
}
}
use middle::lang_items;
use mir::interpret::{GlobalId};
+use rustc_data_structures::bit_set::BitSet;
use rustc_data_structures::sync::Lock;
-use rustc_data_structures::bitvec::BitArray;
use std::iter;
use std::cmp;
use std::fmt;
use hir;
use util::nodemap::{FxHashMap, FxHashSet};
-
pub struct SelectionContext<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> {
infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
#[derive(Clone)]
pub struct SelectionCache<'tcx> {
hashmap: Lock<FxHashMap<ty::TraitRef<'tcx>,
- WithDepNode<SelectionResult<'tcx, SelectionCandidate<'tcx>>>>>,
+ WithDepNode<SelectionResult<'tcx, SelectionCandidate<'tcx>>>>>,
}
/// The selection process begins by considering all impls, where
obligation: &PredicateObligation<'tcx>)
-> Result<EvaluationResult, OverflowError>
{
- self.probe(|this, _| {
+ self.probe(|this, _|
this.evaluate_predicate_recursively(TraitObligationStackList::empty(), obligation)
- })
+ )
}
/// Evaluates the predicates in `predicates` recursively. Note that
self.infcx.projection_cache.borrow_mut().complete(key);
}
result
- }
- Ok(None) => {
- Ok(EvaluatedToAmbig)
- }
- Err(_) => {
- Ok(EvaluatedToErr)
- }
+ },
+ Ok(None) => Ok(EvaluatedToAmbig),
+ Err(_) => Ok(EvaluatedToErr)
}
}
} else {
Ok(EvaluatedToErr)
}
- }
- None => {
- Ok(EvaluatedToAmbig)
- }
+ },
+ None => Ok(EvaluatedToAmbig)
}
}
// same unbound type variable.
if let Some(rec_index) =
stack.iter()
- .skip(1) // skip top-most frame
- .position(|prev| stack.obligation.param_env == prev.obligation.param_env &&
- stack.fresh_trait_ref == prev.fresh_trait_ref)
+ .skip(1) // skip top-most frame
+ .position(|prev| stack.obligation.param_env == prev.obligation.param_env &&
+ stack.fresh_trait_ref == prev.fresh_trait_ref)
{
debug!("evaluate_stack({:?}) --> recursive",
stack.fresh_trait_ref);
- let cycle = stack.iter().skip(1).take(rec_index+1);
+ let cycle = stack.iter().skip(1).take(rec_index + 1);
let cycle = cycle.map(|stack| ty::Predicate::Trait(stack.obligation.predicate));
if self.coinductive_match(cycle) {
debug!("evaluate_stack({:?}) --> recursive, coinductive",
let result = match predicate {
ty::Predicate::Trait(ref data) => {
self.tcx().trait_is_auto(data.def_id())
- }
- _ => {
- false
- }
+ },
+ _ => false
};
debug!("coinductive_predicate({:?}) = {:?}", predicate, result);
result
}
// If no match, compute result and insert into cache.
- let (candidate, dep_node) = self.in_task(|this| {
+ let (candidate, dep_node) = self.in_task(|this|
this.candidate_from_obligation_no_cache(stack)
- });
+ );
debug!("CACHE MISS: SELECT({:?})={:?}",
cache_fresh_trait_pred, candidate);
fn in_task<OP, R>(&mut self, op: OP) -> (R, DepNodeIndex)
where OP: FnOnce(&mut Self) -> R
{
- let (result, dep_node) = self.tcx().dep_graph.with_anon_task(DepKind::TraitSelect, || {
+ let (result, dep_node) = self.tcx().dep_graph.with_anon_task(DepKind::TraitSelect, ||
op(self)
- });
+ );
self.tcx().dep_graph.read_index(dep_node);
(result, dep_node)
}
return Ok(None);
}
- match self.is_knowable(stack) {
- None => {}
- Some(conflict) => {
- debug!("coherence stage: not knowable");
- if self.intercrate_ambiguity_causes.is_some() {
- debug!("evaluate_stack: intercrate_ambiguity_causes is some");
- // Heuristics: show the diagnostics when there are no candidates in crate.
- if let Ok(candidate_set) = self.assemble_candidates(stack) {
- let no_candidates_apply =
- candidate_set
- .vec
- .iter()
- .map(|c| self.evaluate_candidate(stack, &c))
- .collect::<Result<Vec<_>, OverflowError>>()?
- .iter()
- .all(|r| !r.may_apply());
- if !candidate_set.ambiguous && no_candidates_apply {
- let trait_ref = stack.obligation.predicate.skip_binder().trait_ref;
- let self_ty = trait_ref.self_ty();
- let trait_desc = trait_ref.to_string();
- let self_desc = if self_ty.has_concrete_skeleton() {
- Some(self_ty.to_string())
- } else {
- None
- };
- let cause = if let Conflict::Upstream = conflict {
- IntercrateAmbiguityCause::UpstreamCrateUpdate {
- trait_desc,
- self_desc,
- }
- } else {
- IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc }
- };
- debug!("evaluate_stack: pushing cause = {:?}", cause);
- self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause);
+ if let Some(conflict) = self.is_knowable(stack) {
+ debug!("coherence stage: not knowable");
+ if self.intercrate_ambiguity_causes.is_some() {
+ debug!("evaluate_stack: intercrate_ambiguity_causes is some");
+ // Heuristics: show the diagnostics when there are no candidates in crate.
+ if let Ok(candidate_set) = self.assemble_candidates(stack) {
+ let mut no_candidates_apply = true;
+ {
+ let evaluated_candidates = candidate_set.vec.iter().map(|c|
+ self.evaluate_candidate(stack, &c));
+
+ for ec in evaluated_candidates {
+ match ec {
+ Ok(c) => {
+ if c.may_apply() {
+ no_candidates_apply = false;
+ break
+ }
+ },
+ Err(e) => return Err(e.into())
+ }
}
}
+
+ if !candidate_set.ambiguous && no_candidates_apply {
+ let trait_ref = stack.obligation.predicate.skip_binder().trait_ref;
+ let self_ty = trait_ref.self_ty();
+ let trait_desc = trait_ref.to_string();
+ let self_desc = if self_ty.has_concrete_skeleton() {
+ Some(self_ty.to_string())
+ } else {
+ None
+ };
+ let cause = if let Conflict::Upstream = conflict {
+ IntercrateAmbiguityCause::UpstreamCrateUpdate {
+ trait_desc,
+ self_desc,
+ }
+ } else {
+ IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc }
+ };
+ debug!("evaluate_stack: pushing cause = {:?}", cause);
+ self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause);
+ }
}
- return Ok(None);
}
+ return Ok(None);
}
let candidate_set = self.assemble_candidates(stack)?;
// Other bounds. Consider both in-scope bounds from fn decl
// and applicable impls. There is a certain set of precedence rules here.
-
let def_id = obligation.predicate.def_id();
let lang_items = self.tcx().lang_items();
+
if lang_items.copy_trait() == Some(def_id) {
debug!("obligation self ty is {:?}",
obligation.predicate.skip_binder().self_ty());
ty::Projection(_) | ty::Opaque(..) => {}
ty::Infer(ty::TyVar(_)) => {
span_bug!(obligation.cause.span,
- "Self=_ should have been handled by assemble_candidates");
+ "Self=_ should have been handled by assemble_candidates");
}
_ => return
}
- let result = self.probe(|this, snapshot| {
+ let result = self.probe(|this, snapshot|
this.match_projection_obligation_against_definition_bounds(obligation,
snapshot)
- });
+ );
if result {
candidates.vec.push(ProjectionCandidate);
span_bug!(
obligation.cause.span,
"match_projection_obligation_against_definition_bounds() called \
- but self-ty not a projection: {:?}",
+ but self-ty is not a projection: {:?}",
skol_trait_predicate.trait_ref.self_ty());
}
};
where_clause_trait_ref: ty::PolyTraitRef<'tcx>)
-> Result<EvaluationResult, OverflowError>
{
- self.probe(move |this, _| {
+ self.probe(move |this, _|
match this.match_where_clause_trait_ref(stack.obligation, where_clause_trait_ref) {
Ok(obligations) => {
this.evaluate_predicates_recursively(stack.list(), obligations.iter())
}
Err(()) => Ok(EvaluatedToErr)
}
- })
+ )
}
fn assemble_generator_candidates(&mut self,
obligation);
candidates.vec.push(GeneratorCandidate);
- Ok(())
}
ty::Infer(ty::TyVar(_)) => {
debug!("assemble_generator_candidates: ambiguous self-type");
candidates.ambiguous = true;
- return Ok(());
}
- _ => { return Ok(()); }
+ _ => {}
}
+
+ Ok(())
}
/// Check for the artificial impl that the compiler will create for an obligation like `X :
debug!("assemble_unboxed_candidates: closure_kind not yet known");
candidates.vec.push(ClosureCandidate);
}
- };
- Ok(())
+ }
}
ty::Infer(ty::TyVar(_)) => {
debug!("assemble_unboxed_closure_candidates: ambiguous self-type");
candidates.ambiguous = true;
- return Ok(());
}
- _ => { return Ok(()); }
+ _ => {}
}
+
+ Ok(())
}
/// Implement one of the `Fn()` family for a fn pointer.
debug!("assemble_fn_pointer_candidates: ambiguous self-type");
candidates.ambiguous = true; // could wind up being a fn() type
}
-
// provide an impl, but only for suitable `fn` pointers
ty::FnDef(..) | ty::FnPtr(_) => {
if let ty::FnSig {
candidates.vec.push(FnPointerCandidate);
}
}
-
- _ => { }
+ _ => {}
}
Ok(())
obligation.predicate.def_id(),
obligation.predicate.skip_binder().trait_ref.self_ty(),
|impl_def_id| {
- self.probe(|this, snapshot| { /* [1] */
- match this.match_impl(impl_def_id, obligation, snapshot) {
- Ok(skol_map) => {
- candidates.vec.push(ImplCandidate(impl_def_id));
-
- // NB: we can safely drop the skol map
- // since we are in a probe [1]
- mem::drop(skol_map);
- }
- Err(_) => { }
+ self.probe(|this, snapshot| /* [1] */
+ if let Ok(skol_map) = this.match_impl(impl_def_id, obligation, snapshot) {
+ candidates.vec.push(ImplCandidate(impl_def_id));
+
+ // NB: we can safely drop the skol map
+ // since we are in a probe [1]
+ mem::drop(skol_map);
}
- });
+ );
}
);
ty::Dynamic(ref data, ..) => {
if data.auto_traits().any(|did| did == obligation.predicate.def_id()) {
debug!("assemble_candidates_from_object_ty: matched builtin bound, \
- pushing candidate");
+ pushing candidate");
candidates.vec.push(BuiltinObjectCandidate);
return;
}
candidates.ambiguous = true; // could wind up being an object type
return;
}
- _ => {
- return;
- }
+ _ => return
};
debug!("assemble_candidates_from_object_ty: poly_trait_ref={:?}",
// but `Foo` is declared as `trait Foo : Bar<u32>`.
let upcast_trait_refs =
util::supertraits(this.tcx(), poly_trait_ref)
- .filter(|upcast_trait_ref| {
+ .filter(|upcast_trait_ref|
this.probe(|this, _| {
let upcast_trait_ref = upcast_trait_ref.clone();
this.match_poly_trait_ref(obligation, upcast_trait_ref).is_ok()
})
- })
+ )
.count();
if upcast_trait_refs > 1 {
other: &EvaluatedCandidate<'tcx>)
-> bool
{
+ if victim.candidate == other.candidate {
+ return true;
+ }
+
// Check if a bound would previously have been removed when normalizing
// the param_env so that it can be given the lowest priority. See
// #50825 for the motivation for this.
cand.is_global() && !cand.has_late_bound_regions()
};
- if victim.candidate == other.candidate {
- return true;
- }
-
match other.candidate {
// Prefer BuiltinCandidate { has_nested: false } to anything else.
// This is a fix for #53123 and prevents winnowing from accidentally extending the
BuiltinCandidate { has_nested: false } => true,
ParamCandidate(ref cand) => match victim.candidate {
AutoImplCandidate(..) => {
- bug!(
- "default implementations shouldn't be recorded \
- when there are other valid candidates");
+ bug!("default implementations shouldn't be recorded \
+ when there are other valid candidates");
}
// Prefer BuiltinCandidate { has_nested: false } to anything else.
// This is a fix for #53123 and prevents winnowing from accidentally extending the
ObjectCandidate |
ProjectionCandidate => match victim.candidate {
AutoImplCandidate(..) => {
- bug!(
- "default implementations shouldn't be recorded \
- when there are other valid candidates");
+ bug!("default implementations shouldn't be recorded \
+ when there are other valid candidates");
}
// Prefer BuiltinCandidate { has_nested: false } to anything else.
// This is a fix for #53123 and prevents winnowing from accidentally extending the
fn assemble_builtin_bound_candidates<'o>(&mut self,
conditions: BuiltinImplConditions<'tcx>,
candidates: &mut SelectionCandidateSet<'tcx>)
- -> Result<(),SelectionError<'tcx>>
+ -> Result<(), SelectionError<'tcx>>
{
match conditions {
BuiltinImplConditions::Where(nested) => {
candidates.vec.push(BuiltinCandidate {
has_nested: nested.skip_binder().len() > 0
});
- Ok(())
}
- BuiltinImplConditions::None => { Ok(()) }
+ BuiltinImplConditions::None => {}
BuiltinImplConditions::Ambiguous => {
debug!("assemble_builtin_bound_candidates: ambiguous builtin");
- Ok(candidates.ambiguous = true)
+ candidates.ambiguous = true;
}
}
+
+ Ok(())
}
- fn sized_conditions(&mut self, obligation: &TraitObligation<'tcx>)
- -> BuiltinImplConditions<'tcx>
+ fn sized_conditions(&mut self,
+ obligation: &TraitObligation<'tcx>)
+ -> BuiltinImplConditions<'tcx>
{
use self::BuiltinImplConditions::{Ambiguous, None, Where};
}
}
- fn copy_clone_conditions(&mut self, obligation: &TraitObligation<'tcx>)
- -> BuiltinImplConditions<'tcx>
+ fn copy_clone_conditions(&mut self,
+ obligation: &TraitObligation<'tcx>)
+ -> BuiltinImplConditions<'tcx>
{
// NOTE: binder moved to (*)
let self_ty = self.infcx.shallow_resolve(
let lang_items = self.tcx().lang_items();
let obligations = if has_nested {
let trait_def = obligation.predicate.def_id();
- let conditions = match trait_def {
- _ if Some(trait_def) == lang_items.sized_trait() => {
+ let conditions =
+ if Some(trait_def) == lang_items.sized_trait() {
self.sized_conditions(obligation)
- }
- _ if Some(trait_def) == lang_items.copy_trait() => {
+ } else if Some(trait_def) == lang_items.copy_trait() {
self.copy_clone_conditions(obligation)
- }
- _ if Some(trait_def) == lang_items.clone_trait() => {
+ } else if Some(trait_def) == lang_items.clone_trait() {
self.copy_clone_conditions(obligation)
- }
- _ => bug!("unexpected builtin trait {:?}", trait_def)
+ } else {
+ bug!("unexpected builtin trait {:?}", trait_def)
};
let nested = match conditions {
BuiltinImplConditions::Where(nested) => nested,
/// See `confirm_auto_impl_candidate`
fn vtable_auto_impl(&mut self,
- obligation: &TraitObligation<'tcx>,
- trait_def_id: DefId,
- nested: ty::Binder<Vec<Ty<'tcx>>>)
- -> VtableAutoImplData<PredicateObligation<'tcx>>
+ obligation: &TraitObligation<'tcx>,
+ trait_def_id: DefId,
+ nested: ty::Binder<Vec<Ty<'tcx>>>)
+ -> VtableAutoImplData<PredicateObligation<'tcx>>
{
debug!("vtable_auto_impl: nested={:?}", nested);
ty::Dynamic(ref data, ..) => {
data.principal().unwrap().with_self_ty(self.tcx(), self_ty)
}
- _ => {
- span_bug!(obligation.cause.span,
- "object candidate with non-object");
- }
+ _ => span_bug!(obligation.cause.span,
+ "object candidate with non-object")
};
let mut upcast_trait_ref = None;
// record it for later.)
let nonmatching =
util::supertraits(tcx, poly_trait_ref)
- .take_while(|&t| {
- match
- self.commit_if_ok(
- |this, _| this.match_poly_trait_ref(obligation, t))
+ .take_while(|&t|
+ match self.commit_if_ok(|this, _|
+ this.match_poly_trait_ref(obligation, t))
{
Ok(obligations) => {
upcast_trait_ref = Some(t);
}
Err(_) => { true }
}
- });
+ );
// Additionally, for each of the nonmatching predicates that
// we pass over, we sum up the set of number of vtable
// entries, so that we can compute the offset for the selected
// trait.
- vtable_base =
- nonmatching.map(|t| tcx.count_own_vtable_entries(t))
- .sum();
-
+ vtable_base = nonmatching.map(|t| tcx.count_own_vtable_entries(t)).sum();
}
VtableObjectData {
fn confirm_generator_candidate(&mut self,
obligation: &TraitObligation<'tcx>)
-> Result<VtableGeneratorData<'tcx, PredicateObligation<'tcx>>,
- SelectionError<'tcx>>
+ SelectionError<'tcx>>
{
// ok to skip binder because the substs on generator types never
// touch bound regions, they just capture the in-scope
{
debug!("confirm_closure_candidate({:?})", obligation);
- let kind = match self.tcx().lang_items().fn_trait_kind(obligation.predicate.def_id()) {
- Some(k) => k,
- None => bug!("closure candidate for non-fn trait {:?}", obligation)
- };
+ let kind = self.tcx()
+ .lang_items()
+ .fn_trait_kind(obligation.predicate.def_id())
+ .unwrap_or_else(|| bug!("closure candidate for non-fn trait {:?}",
+ obligation));
// ok to skip binder because the substs on closure types never
// touch bound regions, they just capture the in-scope
obligations.extend(
self.confirm_poly_trait_refs(obligation.cause.clone(),
- obligation.param_env,
- obligation.predicate.to_poly_trait_ref(),
- trait_ref)?);
+ obligation.param_env,
+ obligation.predicate.to_poly_trait_ref(),
+ trait_ref)?);
obligations.push(Obligation::new(
obligation.cause.clone(),
(_, &ty::Dynamic(ref data, r)) => {
let mut object_dids =
data.auto_traits().chain(data.principal().map(|p| p.def_id()));
- if let Some(did) = object_dids.find(|did| {
- !tcx.is_object_safe(*did)
- }) {
+ if let Some(did) = object_dids.find(|did| !tcx.is_object_safe(*did)) {
return Err(TraitNotObjectSafe(did))
}
let cause = ObligationCause::new(obligation.cause.span,
obligation.cause.body_id,
ObjectCastObligation(target));
- let mut push = |predicate| {
- nested.push(Obligation::with_depth(cause.clone(),
- obligation.recursion_depth + 1,
- obligation.param_env,
- predicate));
+
+ let predicate_to_obligation = |predicate| {
+ Obligation::with_depth(cause.clone(),
+ obligation.recursion_depth + 1,
+ obligation.param_env,
+ predicate)
};
// Create obligations:
// words, if the object type is Foo+Send, this would create an obligation for the
// Send check.)
// - Projection predicates
- for predicate in data.iter() {
- push(predicate.with_self_ty(tcx, source));
- }
+ nested.extend(data.iter().map(|d|
+ predicate_to_obligation(d.with_self_ty(tcx, source))
+ ));
// We can only make objects from sized types.
let tr = ty::TraitRef {
def_id: tcx.require_lang_item(lang_items::SizedTraitLangItem),
substs: tcx.mk_substs_trait(source, &[]),
};
- push(tr.to_predicate());
+ nested.push(predicate_to_obligation(tr.to_predicate()));
// If the type is `Foo+'a`, ensures that the type
// being cast to `Foo+'a` outlives `'a`:
let outlives = ty::OutlivesPredicate(source, r);
- push(ty::Binder::dummy(outlives).to_predicate());
+ nested.push(predicate_to_obligation(
+ ty::Binder::dummy(outlives).to_predicate()));
}
// [T; n] -> [T].
} else {
return Err(Unimplemented);
};
- let mut ty_params = BitArray::new(substs_a.types().count());
+ let mut ty_params = BitSet::new_empty(substs_a.types().count());
let mut found = false;
for ty in field.walk() {
if let ty::Param(p) = ty.sty {
// Check that the source struct with the target's
// unsized parameters is equal to the target.
- let params = substs_a.iter().enumerate().map(|(i, &k)| {
+ let params = substs_a.iter().enumerate().map(|(i, &k)|
if ty_params.contains(i) {
substs_b.type_at(i).into()
} else {
k
}
- });
+ );
let new_struct = tcx.mk_adt(def, tcx.mk_substs(params));
let InferOk { obligations, .. } =
self.infcx.at(&obligation.cause, obligation.param_env)
let InferOk { obligations, .. } =
self.infcx.at(&obligation.cause, obligation.param_env)
.eq(skol_obligation_trait_ref, impl_trait_ref)
- .map_err(|e| {
- debug!("match_impl: failed eq_trait_refs due to `{}`", e);
- ()
- })?;
+ .map_err(|e|
+ debug!("match_impl: failed eq_trait_refs due to `{}`", e)
+ )?;
nested_obligations.extend(obligations);
if let Err(e) = self.infcx.leak_check(false,
fn match_where_clause_trait_ref(&mut self,
obligation: &TraitObligation<'tcx>,
where_clause_trait_ref: ty::PolyTraitRef<'tcx>)
- -> Result<Vec<PredicateObligation<'tcx>>,()>
+ -> Result<Vec<PredicateObligation<'tcx>>, ()>
{
self.match_poly_trait_ref(obligation, where_clause_trait_ref)
}
fn match_poly_trait_ref(&mut self,
obligation: &TraitObligation<'tcx>,
poly_trait_ref: ty::PolyTraitRef<'tcx>)
- -> Result<Vec<PredicateObligation<'tcx>>,()>
+ -> Result<Vec<PredicateObligation<'tcx>>, ()>
{
debug!("match_poly_trait_ref: obligation={:?} poly_trait_ref={:?}",
obligation,
// in fact unparameterized (or at least does not reference any
// regions bound in the obligation). Still probably some
// refactoring could make this nicer.
-
self.tcx().closure_trait_ref_and_return_type(obligation.predicate.def_id(),
obligation.predicate
- .skip_binder().self_ty(), // (1)
+ .skip_binder()
+ .self_ty(), // (1)
closure_type,
util::TupleArgumentsFlag::No)
.map_bound(|(trait_ref, _)| trait_ref)
}
fn generator_trait_ref_unnormalized(&mut self,
- obligation: &TraitObligation<'tcx>,
- closure_def_id: DefId,
- substs: ty::GeneratorSubsts<'tcx>)
- -> ty::PolyTraitRef<'tcx>
+ obligation: &TraitObligation<'tcx>,
+ closure_def_id: DefId,
+ substs: ty::GeneratorSubsts<'tcx>)
+ -> ty::PolyTraitRef<'tcx>
{
let gen_sig = substs.poly_sig(closure_def_id, self.tcx());
self.tcx().generator_trait_ref_and_outputs(obligation.predicate.def_id(),
obligation.predicate
- .skip_binder().self_ty(), // (1)
+ .skip_binder()
+ .self_ty(), // (1)
gen_sig)
.map_bound(|(trait_ref, ..)| trait_ref)
}
impl<'tcx> TraitObligation<'tcx> {
#[allow(unused_comparisons)]
pub fn derived_cause(&self,
- variant: fn(DerivedObligationCause<'tcx>) -> ObligationCauseCode<'tcx>)
- -> ObligationCause<'tcx>
+ variant: fn(DerivedObligationCause<'tcx>) -> ObligationCauseCode<'tcx>)
+ -> ObligationCause<'tcx>
{
/*!
* Creates a cause for obligations that are derived from
}
fulfill_implication(infcx, param_env, source_trait_ref, target_impl)
- .unwrap_or_else(|_| {
+ .unwrap_or_else(|_|
bug!("When translating substitutions for specialization, the expected \
specialization failed to hold")
- })
+ )
}
specialization_graph::Node::Trait(..) => source_trait_ref.substs,
};
let substs = translate_substs(&infcx, param_env, impl_data.impl_def_id,
substs, node_item.node);
let substs = infcx.tcx.erase_regions(&substs);
- tcx.lift(&substs).unwrap_or_else(|| {
+ tcx.lift(&substs).unwrap_or_else(||
bug!("find_method: translate_substs \
returned {:?} which contains inference types/regions",
- substs);
- })
+ substs)
+ )
});
(node_item.item.def_id, substs)
}
- None => {
- bug!("{:?} not found in {:?}", item, impl_data.impl_def_id)
- }
+ None => bug!("{:?} not found in {:?}", item, impl_data.impl_def_id)
}
}
-> Lrc<specialization_graph::Graph> {
let mut sg = specialization_graph::Graph::new();
- let mut trait_impls = Vec::new();
- tcx.for_each_impl(trait_id, |impl_did| trait_impls.push(impl_did));
+ let mut trait_impls = tcx.all_impls(trait_id);
// The coherence checking implementation seems to rely on impls being
// iterated over (roughly) in definition order, so we are sorting by
"first implementation here".to_string());
err.span_label(impl_span,
format!("conflicting implementation{}",
- overlap.self_desc
- .map_or(String::new(),
- |ty| format!(" for `{}`", ty))));
+ overlap.self_desc
+ .map_or(String::new(),
+ |ty| format!(" for `{}`", ty))));
}
Err(cname) => {
let msg = match to_pretty_impl_header(tcx, overlap.with_impl) {
// The predicates will contain default bounds like `T: Sized`. We need to
// remove these bounds, and add `T: ?Sized` to any untouched type parameters.
let predicates = tcx.predicates_of(impl_def_id).predicates;
- let mut pretty_predicates = Vec::with_capacity(predicates.len());
+ let mut pretty_predicates = Vec::with_capacity(
+ predicates.len() + types_without_default_bounds.len());
+
for p in predicates {
if let Some(poly_trait_ref) = p.to_opt_poly_trait_ref() {
if Some(poly_trait_ref.def_id()) == sized_trait {
}
pretty_predicates.push(p.to_string());
}
+
pretty_predicates.extend(
types_without_default_bounds.iter().map(|ty| format!("{}: ?Sized", ty))
);
+
if !pretty_predicates.is_empty() {
write!(w, "\n where {}", pretty_predicates.join(", ")).unwrap();
}
let cur = self.current_source.take();
if let Some(Node::Impl(cur_impl)) = cur {
let parent = self.specialization_graph.parent(cur_impl);
- if parent == self.trait_def_id {
- self.current_source = Some(Node::Trait(parent));
+
+ self.current_source = if parent == self.trait_def_id {
+ Some(Node::Trait(parent))
} else {
- self.current_source = Some(Node::Impl(parent));
- }
+ Some(Node::Impl(parent))
+ };
}
cur
}
match *self {
super::Unimplemented => Some(super::Unimplemented),
super::OutputTypeParameterMismatch(a, b, ref err) => {
- tcx.lift(&(a, b)).and_then(|(a, b)| {
+ tcx.lift(&(a, b)).and_then(|(a, b)|
tcx.lift(err)
.map(|err| super::OutputTypeParameterMismatch(a, b, err))
- })
+ )
}
super::TraitNotObjectSafe(def_id) => Some(super::TraitNotObjectSafe(def_id)),
super::ConstEvalFailure(ref err) => tcx.lift(&**err).map(|err| super::ConstEvalFailure(
super::ReferenceOutlivesReferent(ty) => {
tcx.lift(&ty).map(super::ReferenceOutlivesReferent)
}
- super::ObjectTypeBound(ty, r) => tcx.lift(&ty).and_then(|ty| {
+ super::ObjectTypeBound(ty, r) => tcx.lift(&ty).and_then(|ty|
tcx.lift(&r)
- .and_then(|r| Some(super::ObjectTypeBound(ty, r)))
- }),
+ .and_then(|r| Some(super::ObjectTypeBound(ty, r)))
+ ),
super::ObjectCastObligation(ty) => tcx.lift(&ty).map(super::ObjectCastObligation),
super::AssignmentLhsSized => Some(super::AssignmentLhsSized),
super::TupleInitializerSized => Some(super::TupleInitializerSized),
impl<'a, 'tcx> Lift<'tcx> for traits::DerivedObligationCause<'a> {
type Lifted = traits::DerivedObligationCause<'tcx>;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
- tcx.lift(&self.parent_trait_ref).and_then(|trait_ref| {
+ tcx.lift(&self.parent_trait_ref).and_then(|trait_ref|
tcx.lift(&*self.parent_code)
- .map(|code| traits::DerivedObligationCause {
- parent_trait_ref: trait_ref,
- parent_code: Rc::new(code),
- })
- })
+ .map(|code| traits::DerivedObligationCause {
+ parent_trait_ref: trait_ref,
+ parent_code: Rc::new(code),
+ })
+ )
}
}
impl_def_id,
substs,
nested,
- }) => tcx.lift(&substs).map(|substs| {
+ }) => tcx.lift(&substs).map(|substs|
traits::VtableImpl(traits::VtableImplData {
impl_def_id,
substs,
nested,
})
- }),
+ ),
traits::VtableAutoImpl(t) => Some(traits::VtableAutoImpl(t)),
traits::VtableGenerator(traits::VtableGeneratorData {
generator_def_id,
substs,
nested,
- }) => tcx.lift(&substs).map(|substs| {
+ }) => tcx.lift(&substs).map(|substs|
traits::VtableGenerator(traits::VtableGeneratorData {
generator_def_id: generator_def_id,
substs: substs,
nested: nested,
})
- }),
+ ),
traits::VtableClosure(traits::VtableClosureData {
closure_def_id,
substs,
nested,
- }) => tcx.lift(&substs).map(|substs| {
+ }) => tcx.lift(&substs).map(|substs|
traits::VtableClosure(traits::VtableClosureData {
closure_def_id,
substs,
nested,
})
- }),
+ ),
traits::VtableFnPointer(traits::VtableFnPointerData { fn_ty, nested }) => {
- tcx.lift(&fn_ty).map(|fn_ty| {
+ tcx.lift(&fn_ty).map(|fn_ty|
traits::VtableFnPointer(traits::VtableFnPointerData { fn_ty, nested })
- })
+ )
}
traits::VtableParam(n) => Some(traits::VtableParam(n)),
traits::VtableBuiltin(n) => Some(traits::VtableBuiltin(n)),
upcast_trait_ref,
vtable_base,
nested,
- }) => tcx.lift(&upcast_trait_ref).map(|trait_ref| {
+ }) => tcx.lift(&upcast_trait_ref).map(|trait_ref|
traits::VtableObject(traits::VtableObjectData {
upcast_trait_ref: trait_ref,
vtable_base,
nested,
})
- }),
+ ),
}
}
}
Some(ty::Predicate::Trait(data)) => {
return Some(data.to_poly_trait_ref());
}
- Some(_) => {
- }
+ Some(_) => {}
}
}
}
use session::config::{BorrowckMode, OutputFilenames};
use session::config::CrateType;
use middle;
-use hir::{TraitCandidate, HirId, ItemLocalId};
+use hir::{TraitCandidate, HirId, ItemLocalId, Node};
use hir::def::{Def, Export};
use hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE};
use hir::map as hir_map;
}
}
+// This struct contains information regarding the `ReFree(FreeRegion)` corresponding to a lifetime
+// conflict.
+#[derive(Debug)]
+pub struct FreeRegionInfo {
+ // def id corresponding to FreeRegion
+ pub def_id: DefId,
+ // the bound region corresponding to FreeRegion
+ pub boundregion: ty::BoundRegion,
+ // checks if bound region is in Impl Item
+ pub is_impl_item: bool,
+}
+
/// The central data structure of the compiler. It stores references
/// to the various **arenas** and also houses the results of the
/// various **compiler queries** that have been performed. See the
.collect(),
hir,
def_path_hash_to_def_id,
- queries: query::Queries::new(providers, on_disk_query_result_cache),
+ queries: query::Queries::new(
+ providers,
+ extern_providers,
+ on_disk_query_result_cache,
+ ),
rcache: Lock::new(FxHashMap()),
selection_cache: traits::SelectionCache::new(),
evaluation_cache: traits::EvaluationCache::new(),
self.queries.on_disk_cache.serialize(self.global_tcx(), encoder)
}
+ /// This checks whether one is allowed to have pattern bindings
+ /// that bind-by-move on a match arm that has a guard, e.g.:
+ ///
+ /// ```rust
+ /// match foo { A(inner) if { /* something */ } => ..., ... }
+ /// ```
+ ///
+ /// It is separate from check_for_mutation_in_guard_via_ast_walk,
+ /// because that method has a narrower effect that can be toggled
+ /// off via a separate `-Z` flag, at least for the short term.
+ pub fn allow_bind_by_move_patterns_with_guards(self) -> bool {
+ self.features().bind_by_move_pattern_guards && self.use_mir_borrowck()
+ }
+
/// If true, we should use a naive AST walk to determine if match
/// guard could perform bad mutations (or mutable-borrows).
pub fn check_for_mutation_in_guard_via_ast_walk(self) -> bool {
- !self.sess.opts.debugging_opts.disable_ast_check_for_mutation_in_guard
+ // If someone passes the `-Z` flag, they're asking for the footgun.
+ if self.sess.opts.debugging_opts.disable_ast_check_for_mutation_in_guard {
+ return false;
+ }
+
+ // If someone requests the feature, then be a little more
+ // careful and ensure that MIR-borrowck is enabled (which can
+ // happen via edition selection, via `feature(nll)`, or via an
+ // appropriate `-Z` flag) before disabling the mutation check.
+ if self.allow_bind_by_move_patterns_with_guards() {
+ return false;
+ }
+
+ return true;
}
/// If true, we should use the AST-based borrowck (we may *also* use
}
})
}
+
+ // This method returns the DefId and the BoundRegion corresponding to the given region.
+ pub fn is_suitable_region(&self, region: Region<'tcx>) -> Option<FreeRegionInfo> {
+ let (suitable_region_binding_scope, bound_region) = match *region {
+ ty::ReFree(ref free_region) => (free_region.scope, free_region.bound_region),
+ ty::ReEarlyBound(ref ebr) => (
+ self.parent_def_id(ebr.def_id).unwrap(),
+ ty::BoundRegion::BrNamed(ebr.def_id, ebr.name),
+ ),
+ _ => return None, // not a free region
+ };
+
+ let node_id = self.hir
+ .as_local_node_id(suitable_region_binding_scope)
+ .unwrap();
+ let is_impl_item = match self.hir.find(node_id) {
+ Some(Node::Item(..)) | Some(Node::TraitItem(..)) => false,
+ Some(Node::ImplItem(..)) => {
+ self.is_bound_region_in_impl_item(suitable_region_binding_scope)
+ }
+ _ => return None,
+ };
+
+ return Some(FreeRegionInfo {
+ def_id: suitable_region_binding_scope,
+ boundregion: bound_region,
+ is_impl_item: is_impl_item,
+ });
+ }
+
+ pub fn return_type_impl_trait(
+ &self,
+ scope_def_id: DefId,
+ ) -> Option<Ty<'tcx>> {
+ let ret_ty = self.type_of(scope_def_id);
+ match ret_ty.sty {
+ ty::FnDef(_, _) => {
+ let sig = ret_ty.fn_sig(*self);
+ let output = self.erase_late_bound_regions(&sig.output());
+ if output.is_impl_trait() {
+ Some(output)
+ } else {
+ None
+ }
+ }
+ _ => None
+ }
+ }
+
+ // Here we check if the bound region is in Impl Item.
+ pub fn is_bound_region_in_impl_item(
+ &self,
+ suitable_region_binding_scope: DefId,
+ ) -> bool {
+ let container_id = self.associated_item(suitable_region_binding_scope)
+ .container
+ .id();
+ if self.impl_trait_ref(container_id).is_some() {
+ // For now, we do not try to target impls of traits. This is
+ // because this message is going to suggest that the user
+ // change the fn signature, but they may not be free to do so,
+ // since the signature must match the trait.
+ //
+ // FIXME(#42706) -- in some cases, we could do better here.
+ return true;
+ }
+ false
+ }
}
impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
pub use self::binding::BindingMode;
pub use self::binding::BindingMode::*;
-pub use self::context::{TyCtxt, GlobalArenas, AllArenas, tls, keep_local};
+pub use self::context::{TyCtxt, FreeRegionInfo, GlobalArenas, AllArenas, tls, keep_local};
pub use self::context::{Lift, TypeckTables};
pub use self::instance::{Instance, InstanceDef};
use util::common::{ErrorReported};
use util::profiling::ProfileCategory::*;
-use rustc_data_structures::indexed_set::IdxSet;
-use rustc_target::spec::PanicStrategy;
+use rustc_data_structures::bit_set::BitSet;
use rustc_data_structures::indexed_vec::IndexVec;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::stable_hasher::StableVec;
+use rustc_data_structures::sync::Lrc;
+use rustc_target::spec::PanicStrategy;
use std::ops::Deref;
-use rustc_data_structures::sync::Lrc;
use std::sync::Arc;
use syntax_pos::{Span, DUMMY_SP};
use syntax_pos::symbol::InternedString;
/// Maps DefId's that have an associated Mir to the result
/// of the MIR qualify_consts pass. The actual meaning of
/// the value isn't known except to the pass itself.
- [] fn mir_const_qualif: MirConstQualif(DefId) -> (u8, Lrc<IdxSet<mir::Local>>),
+ [] fn mir_const_qualif: MirConstQualif(DefId) -> (u8, Lrc<BitSet<mir::Local>>),
/// Fetch the MIR for a given def-id right after it's built - this includes
/// unreachable code.
impl<$tcx> Queries<$tcx> {
pub fn new(
providers: IndexVec<CrateNum, Providers<$tcx>>,
+ fallback_extern_providers: Providers<$tcx>,
on_disk_cache: OnDiskCache<'tcx>,
) -> Self {
Queries {
providers,
+ fallback_extern_providers: Box::new(fallback_extern_providers),
on_disk_cache,
$($name: Lock::new(QueryCache::new())),*
}
#[inline]
fn compute(tcx: TyCtxt<'_, 'tcx, '_>, key: Self::Key) -> Self::Value {
__query_compute::$name(move || {
- let provider = tcx.queries.providers[key.query_crate()].$name;
+ let provider = tcx.queries.providers.get(key.query_crate())
+ // HACK(eddyb) it's possible crates may be loaded after
+ // the query engine is created, and because crate loading
+ // is not yet integrated with the query engine, such crates
+ // would be be missing appropriate entries in `providers`.
+ .unwrap_or(&tcx.queries.fallback_extern_providers)
+ .$name;
provider(tcx.global_tcx(), key)
})
}
pub(crate) on_disk_cache: OnDiskCache<'tcx>,
providers: IndexVec<CrateNum, Providers<$tcx>>,
+ fallback_extern_providers: Box<Providers<$tcx>>,
$($(#[$attr])* $name: Lock<QueryCache<$tcx, queries::$name<$tcx>>>,)*
}
}
}
}
+
+ /// Return a vector containing all impls
+ pub fn all_impls(self, def_id: DefId) -> Vec<DefId> {
+ let impls = self.trait_impls_of(def_id);
+
+ impls.blanket_impls.iter().chain(
+ impls.non_blanket_impls.values().flatten()
+ ).cloned().collect()
+ }
}
// Query provider for `trait_impls_of`.
write!(f, "{}", br)
}
ty::ReScope(scope) if cx.identify_regions => {
- match scope.data() {
+ match scope.data {
region::ScopeData::Node =>
write!(f, "'{}s", scope.item_local_id().as_usize()),
region::ScopeData::CallSite =>
let mut ret = UseOk;
+ let scope = region::Scope {
+ id: expr_id,
+ data: region::ScopeData::Node
+ };
self.each_in_scope_loan_affecting_path(
- region::Scope::Node(expr_id), use_path, |loan| {
+ scope, use_path, |loan| {
if !compatible_borrow_kinds(loan.kind, borrow_kind) {
ret = UseWhileBorrowed(loan.loan_path.clone(), loan.span);
false
// Check that we don't invalidate any outstanding loans
if let Some(loan_path) = opt_loan_path(assignee_cmt) {
- let scope = region::Scope::Node(assignment_id);
+ let scope = region::Scope {
+ id: assignment_id,
+ data: region::ScopeData::Node
+ };
self.each_in_scope_loan_affecting_path(scope, &loan_path, |loan| {
self.report_illegal_mutation(assignment_span, &loan_path, loan);
false
let mut glcx = GatherLoanCtxt {
bccx,
all_loans: Vec::new(),
- item_ub: region::Scope::Node(bccx.tcx.hir.body(body).value.hir_id.local_id),
+ item_ub: region::Scope {
+ id: bccx.tcx.hir.body(body).value.hir_id.local_id,
+ data: region::ScopeData::Node
+ },
move_data: MoveData::default(),
move_error_collector: move_error::MoveErrorCollector::new(),
};
};
debug!("loan_scope = {:?}", loan_scope);
- let borrow_scope = region::Scope::Node(borrow_id);
+ let borrow_scope = region::Scope {
+ id: borrow_id,
+ data: region::ScopeData::Node
+ };
let gen_scope = self.compute_gen_scope(borrow_scope, loan_scope);
debug!("gen_scope = {:?}", gen_scope);
use std::hash::{Hash, Hasher};
use syntax::ast;
use syntax_pos::{MultiSpan, Span};
-use errors::{DiagnosticBuilder, DiagnosticId};
+use errors::{Applicability, DiagnosticBuilder, DiagnosticId};
use rustc::hir;
use rustc::hir::intravisit::{self, Visitor};
LpUpvar(upvar_id) => {
let block_id = closure_to_block(upvar_id.closure_expr_id, bccx.tcx);
let hir_id = bccx.tcx.hir.node_to_hir_id(block_id);
- region::Scope::Node(hir_id.local_id)
+ region::Scope { id: hir_id.local_id, data: region::ScopeData::Node }
}
LpDowncast(ref base, _) |
LpExtend(ref base, ..) => base.kill_scope(bccx),
}) = cmt.cat {
db.note(fn_closure_msg);
} else {
- db.span_suggestion(sp, msg, suggestion);
+ db.span_suggestion_with_applicability(
+ sp,
+ msg,
+ suggestion,
+ Applicability::Unspecified,
+ );
}
} else {
- db.span_suggestion(sp, msg, suggestion);
+ db.span_suggestion_with_applicability(
+ sp,
+ msg,
+ suggestion,
+ Applicability::Unspecified,
+ );
}
}
_ => {
let let_span = self.tcx.hir.span(node_id);
let suggestion = suggest_ref_mut(self.tcx, let_span);
if let Some(replace_str) = suggestion {
- db.span_suggestion(
+ db.span_suggestion_with_applicability(
let_span,
"use a mutable reference instead",
replace_str,
+ // I believe this can be machine applicable,
+ // but if there are multiple attempted uses of an immutable
+ // reference, I don't know how rustfix handles it, it might
+ // attempt fixing them multiple times.
+ // @estebank
+ Applicability::Unspecified,
);
}
}
)) = ty.map(|t| &t.node)
{
let borrow_expr_id = self.tcx.hir.get_parent_node(borrowed_node_id);
- db.span_suggestion(
+ db.span_suggestion_with_applicability(
self.tcx.hir.span(borrow_expr_id),
"consider removing the `&mut`, as it is an \
immutable binding to a mutable reference",
- snippet
+ snippet,
+ Applicability::MachineApplicable,
);
} else {
- db.span_label(
+ db.span_suggestion_with_applicability(
let_span,
- format!("consider changing this to `mut {}`", snippet),
+ "make this binding mutable",
+ format!("mut {}", snippet),
+ Applicability::MachineApplicable,
);
}
}
&cmt_path_or_string,
capture_span,
Origin::Ast)
- .span_suggestion(err.span,
- &format!("to force the closure to take ownership of {} \
- (and any other referenced variables), \
- use the `move` keyword",
- cmt_path_or_string),
- suggestion)
+ .span_suggestion_with_applicability(
+ err.span,
+ &format!("to force the closure to take ownership of {} \
+ (and any other referenced variables), \
+ use the `move` keyword",
+ cmt_path_or_string),
+ suggestion,
+ Applicability::MachineApplicable,
+ )
.emit();
self.signal_error();
}
// Make the default table accessible
self.cmd.arg("--export-table");
+ // Rust code should never have warnings, and warnings are often
+ // indicative of bugs, let's prevent them.
+ self.cmd.arg("--fatal-warnings");
+
let mut cmd = Command::new("");
::std::mem::swap(&mut cmd, &mut self.cmd);
cmd
use syntax_pos::Pos;
-use rustc_data_structures::bitvec::BitArray;
+use rustc_data_structures::bit_set::BitSet;
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
use syntax_pos::BytePos;
};
// Find all the scopes with variables defined in them.
- let mut has_variables = BitArray::new(mir.source_scopes.len());
+ let mut has_variables = BitSet::new_empty(mir.source_scopes.len());
for var in mir.vars_iter() {
let decl = &mir.local_decls[var];
has_variables.insert(decl.visibility_scope);
fn make_mir_scope(cx: &CodegenCx<'ll, '_>,
mir: &Mir,
- has_variables: &BitArray<SourceScope>,
+ has_variables: &BitSet<SourceScope>,
debug_context: &FunctionDebugContextData<'ll>,
scope: SourceScope,
scopes: &mut IndexVec<SourceScope, MirDebugScope<'ll>>) {
llvm::LLVMRustDIBuilderCreateStaticVariable(DIB(cx),
NO_SCOPE_METADATA,
name.as_ptr(),
- // LLVM 3.9
- // doesn't accept
- // null here, so
- // pass the name
- // as the linkage
- // name.
- name.as_ptr(),
+ ptr::null(),
unknown_file_metadata(cx),
UNKNOWN_LINE_NUMBER,
vtable_type,
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// FIXME: Rename 'DIGlobalVariable' to 'DIGlobalVariableExpression'
-// once support for LLVM 3.9 is dropped.
-//
-// This method was changed in this LLVM patch:
-// https://reviews.llvm.org/D26769
-
use super::debuginfo::{
DIBuilder, DIDescriptor, DIFile, DILexicalBlock, DISubprogram, DIType,
DIBasicType, DIDerivedType, DICompositeType, DIScope, DIVariable,
- DIGlobalVariable, DIArray, DISubrange, DITemplateTypeParameter, DIEnumerator,
+ DIGlobalVariableExpression, DIArray, DISubrange, DITemplateTypeParameter, DIEnumerator,
DINameSpace, DIFlags,
};
pub type DIDerivedType = DIType;
pub type DICompositeType = DIDerivedType;
pub type DIVariable = DIDescriptor;
- pub type DIGlobalVariable = DIDescriptor;
+ pub type DIGlobalVariableExpression = DIDescriptor;
pub type DIArray = DIDescriptor;
pub type DISubrange = DIDescriptor;
pub type DIEnumerator = DIDescriptor;
Val: &'a Value,
Decl: Option<&'a DIDescriptor>,
AlignInBits: u32)
- -> &'a DIGlobalVariable;
+ -> &'a DIGlobalVariableExpression;
pub fn LLVMRustDIBuilderCreateVariable(Builder: &DIBuilder<'a>,
Tag: c_uint,
//! An analysis to determine which locals require allocas and
//! which do not.
-use rustc_data_structures::bitvec::BitArray;
+use rustc_data_structures::bit_set::BitSet;
use rustc_data_structures::graph::dominators::Dominators;
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
use rustc::mir::{self, Location, TerminatorKind};
use type_of::LayoutLlvmExt;
use super::FunctionCx;
-pub fn non_ssa_locals(fx: &FunctionCx<'a, 'll, 'tcx>) -> BitArray<mir::Local> {
+pub fn non_ssa_locals(fx: &FunctionCx<'a, 'll, 'tcx>) -> BitSet<mir::Local> {
let mir = fx.mir;
let mut analyzer = LocalAnalyzer::new(fx);
struct LocalAnalyzer<'mir, 'a: 'mir, 'll: 'a, 'tcx: 'll> {
fx: &'mir FunctionCx<'a, 'll, 'tcx>,
dominators: Dominators<mir::BasicBlock>,
- non_ssa_locals: BitArray<mir::Local>,
+ non_ssa_locals: BitSet<mir::Local>,
// The location of the first visited direct assignment to each
// local, or an invalid location (out of bounds `block` index).
first_assignment: IndexVec<mir::Local, Location>
let mut analyzer = LocalAnalyzer {
fx,
dominators: fx.mir.dominators(),
- non_ssa_locals: BitArray::new(fx.mir.local_decls.len()),
+ non_ssa_locals: BitSet::new_empty(fx.mir.local_decls.len()),
first_assignment: IndexVec::from_elem(invalid_location, &fx.mir.local_decls)
};
use std::iter;
-use rustc_data_structures::bitvec::BitArray;
+use rustc_data_structures::bit_set::BitSet;
use rustc_data_structures::indexed_vec::IndexVec;
pub use self::constant::codegen_static_initializer;
debuginfo::start_emitting_source_locations(&fx.debug_context);
let rpo = traversal::reverse_postorder(&mir);
- let mut visited = BitArray::new(mir.basic_blocks().len());
+ let mut visited = BitSet::new_empty(mir.basic_blocks().len());
// Codegen the body of each block using reverse postorder
for (bb, _) in rpo {
bx: &Builder<'a, 'll, 'tcx>,
fx: &FunctionCx<'a, 'll, 'tcx>,
scopes: &IndexVec<mir::SourceScope, debuginfo::MirDebugScope<'ll>>,
- memory_locals: &BitArray<mir::Local>,
+ memory_locals: &BitSet<mir::Local>,
) -> Vec<LocalRef<'ll, 'tcx>> {
let mir = fx.mir;
let tcx = bx.tcx();
+++ /dev/null
-// 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! A stack-allocated vector, allowing storage of N elements on the stack.
-
-use std::marker::Unsize;
-use std::iter::Extend;
-use std::ptr::{self, drop_in_place, NonNull};
-use std::ops::{Deref, DerefMut, Range};
-use std::hash::{Hash, Hasher};
-use std::slice;
-use std::fmt;
-use std::mem;
-use std::mem::ManuallyDrop;
-use std::ops::Bound::{Excluded, Included, Unbounded};
-use std::ops::RangeBounds;
-
-pub unsafe trait Array {
- type Element;
- type PartialStorage: Unsize<[ManuallyDrop<Self::Element>]>;
- const LEN: usize;
-}
-
-unsafe impl<T> Array for [T; 1] {
- type Element = T;
- type PartialStorage = [ManuallyDrop<T>; 1];
- const LEN: usize = 1;
-}
-
-unsafe impl<T> Array for [T; 8] {
- type Element = T;
- type PartialStorage = [ManuallyDrop<T>; 8];
- const LEN: usize = 8;
-}
-
-unsafe impl<T> Array for [T; 32] {
- type Element = T;
- type PartialStorage = [ManuallyDrop<T>; 32];
- const LEN: usize = 32;
-}
-
-pub struct ArrayVec<A: Array> {
- count: usize,
- values: A::PartialStorage
-}
-
-impl<A> Hash for ArrayVec<A>
- where A: Array,
- A::Element: Hash {
- fn hash<H>(&self, state: &mut H) where H: Hasher {
- (&self[..]).hash(state);
- }
-}
-
-impl<A> Clone for ArrayVec<A>
- where A: Array,
- A::Element: Clone {
- fn clone(&self) -> Self {
- let mut v = ArrayVec::new();
- v.extend(self.iter().cloned());
- v
- }
-}
-
-impl<A: Array> ArrayVec<A> {
- pub fn new() -> Self {
- ArrayVec {
- count: 0,
- values: unsafe { ::std::mem::uninitialized() },
- }
- }
-
- pub fn len(&self) -> usize {
- self.count
- }
-
- pub unsafe fn set_len(&mut self, len: usize) {
- self.count = len;
- }
-
- /// Panics when the stack vector is full.
- pub fn push(&mut self, el: A::Element) {
- let arr = &mut self.values as &mut [ManuallyDrop<_>];
- arr[self.count] = ManuallyDrop::new(el);
- self.count += 1;
- }
-
- pub fn pop(&mut self) -> Option<A::Element> {
- if self.count > 0 {
- let arr = &mut self.values as &mut [ManuallyDrop<_>];
- self.count -= 1;
- unsafe {
- let value = ptr::read(&*arr[self.count]);
- Some(value)
- }
- } else {
- None
- }
- }
-
- pub fn drain<R>(&mut self, range: R) -> Drain<A>
- where R: RangeBounds<usize>
- {
- // Memory safety
- //
- // When the Drain is first created, it shortens the length of
- // the source vector to make sure no uninitialized or moved-from elements
- // are accessible at all if the Drain's destructor never gets to run.
- //
- // Drain will ptr::read out the values to remove.
- // When finished, remaining tail of the vec is copied back to cover
- // the hole, and the vector length is restored to the new length.
- //
- let len = self.len();
- let start = match range.start_bound() {
- Included(&n) => n,
- Excluded(&n) => n + 1,
- Unbounded => 0,
- };
- let end = match range.end_bound() {
- Included(&n) => n + 1,
- Excluded(&n) => n,
- Unbounded => len,
- };
- assert!(start <= end);
- assert!(end <= len);
-
- unsafe {
- // set self.vec length's to start, to be safe in case Drain is leaked
- self.set_len(start);
- // Use the borrow in the IterMut to indicate borrowing behavior of the
- // whole Drain iterator (like &mut T).
- let range_slice = {
- let arr = &mut self.values as &mut [ManuallyDrop<<A as Array>::Element>];
- slice::from_raw_parts_mut(arr.as_mut_ptr().add(start),
- end - start)
- };
- Drain {
- tail_start: end,
- tail_len: len - end,
- iter: range_slice.iter(),
- array_vec: NonNull::from(self),
- }
- }
- }
-}
-
-impl<A> Default for ArrayVec<A>
- where A: Array {
- fn default() -> Self {
- ArrayVec::new()
- }
-}
-
-impl<A> fmt::Debug for ArrayVec<A>
- where A: Array,
- A::Element: fmt::Debug {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- self[..].fmt(f)
- }
-}
-
-impl<A: Array> Deref for ArrayVec<A> {
- type Target = [A::Element];
- fn deref(&self) -> &Self::Target {
- unsafe {
- slice::from_raw_parts(&self.values as *const _ as *const A::Element, self.count)
- }
- }
-}
-
-impl<A: Array> DerefMut for ArrayVec<A> {
- fn deref_mut(&mut self) -> &mut [A::Element] {
- unsafe {
- slice::from_raw_parts_mut(&mut self.values as *mut _ as *mut A::Element, self.count)
- }
- }
-}
-
-impl<A: Array> Drop for ArrayVec<A> {
- fn drop(&mut self) {
- unsafe {
- drop_in_place(&mut self[..])
- }
- }
-}
-
-impl<A: Array> Extend<A::Element> for ArrayVec<A> {
- fn extend<I>(&mut self, iter: I) where I: IntoIterator<Item=A::Element> {
- for el in iter {
- self.push(el);
- }
- }
-}
-
-pub struct Iter<A: Array> {
- indices: Range<usize>,
- store: A::PartialStorage,
-}
-
-impl<A: Array> Drop for Iter<A> {
- fn drop(&mut self) {
- self.for_each(drop);
- }
-}
-
-impl<A: Array> Iterator for Iter<A> {
- type Item = A::Element;
-
- fn next(&mut self) -> Option<A::Element> {
- let arr = &self.store as &[ManuallyDrop<_>];
- unsafe {
- self.indices.next().map(|i| ptr::read(&*arr[i]))
- }
- }
-
- fn size_hint(&self) -> (usize, Option<usize>) {
- self.indices.size_hint()
- }
-}
-
-pub struct Drain<'a, A: Array>
- where A::Element: 'a
-{
- tail_start: usize,
- tail_len: usize,
- iter: slice::Iter<'a, ManuallyDrop<A::Element>>,
- array_vec: NonNull<ArrayVec<A>>,
-}
-
-impl<'a, A: Array> Iterator for Drain<'a, A> {
- type Item = A::Element;
-
- #[inline]
- fn next(&mut self) -> Option<A::Element> {
- self.iter.next().map(|elt| unsafe { ptr::read(&**elt) })
- }
-
- fn size_hint(&self) -> (usize, Option<usize>) {
- self.iter.size_hint()
- }
-}
-
-impl<'a, A: Array> Drop for Drain<'a, A> {
- fn drop(&mut self) {
- // exhaust self first
- self.for_each(drop);
-
- if self.tail_len > 0 {
- unsafe {
- let source_array_vec: &mut ArrayVec<A> = self.array_vec.as_mut();
- // memmove back untouched tail, update to new length
- let start = source_array_vec.len();
- let tail = self.tail_start;
- {
- let arr =
- &mut source_array_vec.values as &mut [ManuallyDrop<<A as Array>::Element>];
- let src = arr.as_ptr().add(tail);
- let dst = arr.as_mut_ptr().add(start);
- ptr::copy(src, dst, self.tail_len);
- };
- source_array_vec.set_len(start + self.tail_len);
- }
- }
- }
-}
-
-impl<A: Array> IntoIterator for ArrayVec<A> {
- type Item = A::Element;
- type IntoIter = Iter<A>;
- fn into_iter(self) -> Self::IntoIter {
- let store = unsafe {
- ptr::read(&self.values)
- };
- let indices = 0..self.count;
- mem::forget(self);
- Iter {
- indices,
- store,
- }
- }
-}
-
-impl<'a, A: Array> IntoIterator for &'a ArrayVec<A> {
- type Item = &'a A::Element;
- type IntoIter = slice::Iter<'a, A::Element>;
- fn into_iter(self) -> Self::IntoIter {
- self.iter()
- }
-}
-
-impl<'a, A: Array> IntoIterator for &'a mut ArrayVec<A> {
- type Item = &'a mut A::Element;
- type IntoIter = slice::IterMut<'a, A::Element>;
- fn into_iter(self) -> Self::IntoIter {
- self.iter_mut()
- }
-}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use indexed_vec::{Idx, IndexVec};
+use rustc_serialize;
+use smallvec::SmallVec;
+use std::fmt;
+use std::iter;
+use std::marker::PhantomData;
+use std::mem;
+use std::slice;
+
+pub type Word = u64;
+pub const WORD_BYTES: usize = mem::size_of::<Word>();
+pub const WORD_BITS: usize = WORD_BYTES * 8;
+
+/// A fixed-size bitset type with a dense representation. It does not support
+/// resizing after creation; use `GrowableBitSet` for that.
+///
+/// `T` is an index type, typically a newtyped `usize` wrapper, but it can also
+/// just be `usize`.
+#[derive(Clone, Eq, PartialEq)]
+pub struct BitSet<T: Idx> {
+ words: Vec<Word>,
+ marker: PhantomData<T>,
+}
+
+impl<T: Idx> BitSet<T> {
+ #[inline]
+ pub fn new_empty(domain_size: usize) -> BitSet<T> {
+ let num_words = num_words(domain_size);
+ BitSet {
+ words: vec![0; num_words],
+ marker: PhantomData,
+ }
+ }
+
+ #[inline]
+ pub fn new_filled(domain_size: usize) -> BitSet<T> {
+ let num_words = num_words(domain_size);
+ let mut result = BitSet {
+ words: vec![!0; num_words],
+ marker: PhantomData,
+ };
+ result.clear_above(domain_size);
+ result
+ }
+
+ #[inline]
+ pub fn clear(&mut self) {
+ for word in &mut self.words {
+ *word = 0;
+ }
+ }
+
+ /// Sets all elements up to and including `size`.
+ pub fn set_up_to(&mut self, elem: usize) {
+ for word in &mut self.words {
+ *word = !0;
+ }
+ self.clear_above(elem);
+ }
+
+ /// Clear all elements above `elem`.
+ fn clear_above(&mut self, elem: usize) {
+ let first_clear_block = elem / WORD_BITS;
+
+ if first_clear_block < self.words.len() {
+ // Within `first_clear_block`, the `elem % WORD_BITS` LSBs should
+ // remain.
+ let mask = (1 << (elem % WORD_BITS)) - 1;
+ self.words[first_clear_block] &= mask;
+
+ // All the blocks above `first_clear_block` are fully cleared.
+ for word in &mut self.words[first_clear_block + 1..] {
+ *word = 0;
+ }
+ }
+ }
+
+ /// Efficiently overwrite `self` with `other`. Panics if `self` and `other`
+ /// don't have the same length.
+ pub fn overwrite(&mut self, other: &BitSet<T>) {
+ self.words.clone_from_slice(&other.words);
+ }
+
+ /// Count the number of set bits in the set.
+ pub fn count(&self) -> usize {
+ self.words.iter().map(|e| e.count_ones() as usize).sum()
+ }
+
+ /// True if `self` contains `elem`.
+ #[inline]
+ pub fn contains(&self, elem: T) -> bool {
+ let (word_index, mask) = word_index_and_mask(elem);
+ (self.words[word_index] & mask) != 0
+ }
+
+ /// True if `self` is a (non-strict) superset of `other`.
+ ///
+ /// The two sets must have the same domain_size.
+ #[inline]
+ pub fn superset(&self, other: &BitSet<T>) -> bool {
+ assert_eq!(self.words.len(), other.words.len());
+ self.words.iter().zip(&other.words).all(|(a, b)| (a & b) == *b)
+ }
+
+ /// Is the set empty?
+ #[inline]
+ pub fn is_empty(&self) -> bool {
+ self.words.iter().all(|a| *a == 0)
+ }
+
+ /// Insert `elem`. Returns true if the set has changed.
+ #[inline]
+ pub fn insert(&mut self, elem: T) -> bool {
+ let (word_index, mask) = word_index_and_mask(elem);
+ let word_ref = &mut self.words[word_index];
+ let word = *word_ref;
+ let new_word = word | mask;
+ *word_ref = new_word;
+ new_word != word
+ }
+
+ /// Sets all bits to true.
+ pub fn insert_all(&mut self) {
+ for word in &mut self.words {
+ *word = !0;
+ }
+ }
+
+ /// Returns true if the set has changed.
+ #[inline]
+ pub fn remove(&mut self, elem: T) -> bool {
+ let (word_index, mask) = word_index_and_mask(elem);
+ let word_ref = &mut self.words[word_index];
+ let word = *word_ref;
+ let new_word = word & !mask;
+ *word_ref = new_word;
+ new_word != word
+ }
+
+ /// Set `self = self | other` and return true if `self` changed
+ /// (i.e., if new bits were added).
+ pub fn union(&mut self, other: &impl UnionIntoBitSet<T>) -> bool {
+ other.union_into(self)
+ }
+
+ /// Set `self = self - other` and return true if `self` changed.
+ /// (i.e., if any bits were removed).
+ pub fn subtract(&mut self, other: &impl SubtractFromBitSet<T>) -> bool {
+ other.subtract_from(self)
+ }
+
+ /// Set `self = self & other` and return true if `self` changed.
+ /// (i.e., if any bits were removed).
+ pub fn intersect(&mut self, other: &BitSet<T>) -> bool {
+ bitwise(&mut self.words, &other.words, |a, b| { a & b })
+ }
+
+ /// Get a slice of the underlying words.
+ pub fn words(&self) -> &[Word] {
+ &self.words
+ }
+
+ /// Iterates over the indices of set bits in a sorted order.
+ #[inline]
+ pub fn iter<'a>(&'a self) -> BitIter<'a, T> {
+ BitIter {
+ cur: None,
+ iter: self.words.iter().enumerate(),
+ marker: PhantomData,
+ }
+ }
+
+ /// Duplicates the set as a hybrid set.
+ pub fn to_hybrid(&self) -> HybridBitSet<T> {
+ // This domain_size may be slightly larger than the one specified
+ // upon creation, due to rounding up to a whole word. That's ok.
+ let domain_size = self.words.len() * WORD_BITS;
+
+ // Note: we currently don't bother trying to make a Sparse set.
+ HybridBitSet::Dense(self.to_owned(), domain_size)
+ }
+
+ pub fn to_string(&self, bits: usize) -> String {
+ let mut result = String::new();
+ let mut sep = '[';
+
+ // Note: this is a little endian printout of bytes.
+
+ // i tracks how many bits we have printed so far.
+ let mut i = 0;
+ for word in &self.words {
+ let mut word = *word;
+ for _ in 0..WORD_BYTES { // for each byte in `word`:
+ let remain = bits - i;
+ // If less than a byte remains, then mask just that many bits.
+ let mask = if remain <= 8 { (1 << remain) - 1 } else { 0xFF };
+ assert!(mask <= 0xFF);
+ let byte = word & mask;
+
+ result.push_str(&format!("{}{:02x}", sep, byte));
+
+ if remain <= 8 { break; }
+ word >>= 8;
+ i += 8;
+ sep = '-';
+ }
+ sep = '|';
+ }
+ result.push(']');
+
+ result
+ }
+}
+
+/// This is implemented by all the bitsets so that BitSet::union() can be
+/// passed any type of bitset.
+pub trait UnionIntoBitSet<T: Idx> {
+ // Performs `other = other | self`.
+ fn union_into(&self, other: &mut BitSet<T>) -> bool;
+}
+
+/// This is implemented by all the bitsets so that BitSet::subtract() can be
+/// passed any type of bitset.
+pub trait SubtractFromBitSet<T: Idx> {
+ // Performs `other = other - self`.
+ fn subtract_from(&self, other: &mut BitSet<T>) -> bool;
+}
+
+impl<T: Idx> UnionIntoBitSet<T> for BitSet<T> {
+ fn union_into(&self, other: &mut BitSet<T>) -> bool {
+ bitwise(&mut other.words, &self.words, |a, b| { a | b })
+ }
+}
+
+impl<T: Idx> SubtractFromBitSet<T> for BitSet<T> {
+ fn subtract_from(&self, other: &mut BitSet<T>) -> bool {
+ bitwise(&mut other.words, &self.words, |a, b| { a & !b })
+ }
+}
+
+impl<T: Idx> fmt::Debug for BitSet<T> {
+ fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
+ w.debug_list()
+ .entries(self.iter())
+ .finish()
+ }
+}
+
+impl<T: Idx> rustc_serialize::Encodable for BitSet<T> {
+ fn encode<E: rustc_serialize::Encoder>(&self, encoder: &mut E) -> Result<(), E::Error> {
+ self.words.encode(encoder)
+ }
+}
+
+impl<T: Idx> rustc_serialize::Decodable for BitSet<T> {
+ fn decode<D: rustc_serialize::Decoder>(d: &mut D) -> Result<BitSet<T>, D::Error> {
+ let words: Vec<Word> = rustc_serialize::Decodable::decode(d)?;
+ Ok(BitSet {
+ words,
+ marker: PhantomData,
+ })
+ }
+}
+
+pub struct BitIter<'a, T: Idx> {
+ cur: Option<(Word, usize)>,
+ iter: iter::Enumerate<slice::Iter<'a, Word>>,
+ marker: PhantomData<T>
+}
+
+impl<'a, T: Idx> Iterator for BitIter<'a, T> {
+ type Item = T;
+ fn next(&mut self) -> Option<T> {
+ loop {
+ if let Some((ref mut word, offset)) = self.cur {
+ let bit_pos = word.trailing_zeros() as usize;
+ if bit_pos != WORD_BITS {
+ let bit = 1 << bit_pos;
+ *word ^= bit;
+ return Some(T::new(bit_pos + offset))
+ }
+ }
+
+ let (i, word) = self.iter.next()?;
+ self.cur = Some((*word, WORD_BITS * i));
+ }
+ }
+}
+
+pub trait BitSetOperator {
+ /// Combine one bitset into another.
+ fn join<T: Idx>(&self, inout_set: &mut BitSet<T>, in_set: &BitSet<T>) -> bool;
+}
+
+#[inline]
+fn bitwise<Op>(out_vec: &mut [Word], in_vec: &[Word], op: Op) -> bool
+ where Op: Fn(Word, Word) -> Word
+{
+ assert_eq!(out_vec.len(), in_vec.len());
+ let mut changed = false;
+ for (out_elem, in_elem) in out_vec.iter_mut().zip(in_vec.iter()) {
+ let old_val = *out_elem;
+ let new_val = op(old_val, *in_elem);
+ *out_elem = new_val;
+ changed |= old_val != new_val;
+ }
+ changed
+}
+
+const SPARSE_MAX: usize = 8;
+
+/// A fixed-size bitset type with a sparse representation and a maximum of
+/// `SPARSE_MAX` elements. The elements are stored as a sorted `SmallVec` with
+/// no duplicates; although `SmallVec` can spill its elements to the heap, that
+/// never happens within this type because of the `SPARSE_MAX` limit.
+///
+/// This type is used by `HybridBitSet`; do not use directly.
+#[derive(Clone, Debug)]
+pub struct SparseBitSet<T: Idx>(SmallVec<[T; SPARSE_MAX]>);
+
+impl<T: Idx> SparseBitSet<T> {
+ fn new_empty() -> Self {
+ SparseBitSet(SmallVec::new())
+ }
+
+ fn len(&self) -> usize {
+ self.0.len()
+ }
+
+ fn is_empty(&self) -> bool {
+ self.0.len() == 0
+ }
+
+ fn contains(&self, elem: T) -> bool {
+ self.0.contains(&elem)
+ }
+
+ fn insert(&mut self, elem: T) -> bool {
+ assert!(self.len() < SPARSE_MAX);
+ if let Some(i) = self.0.iter().position(|&e| e >= elem) {
+ if self.0[i] == elem {
+ // `elem` is already in the set.
+ false
+ } else {
+ // `elem` is smaller than one or more existing elements.
+ self.0.insert(i, elem);
+ true
+ }
+ } else {
+ // `elem` is larger than all existing elements.
+ self.0.push(elem);
+ true
+ }
+ }
+
+ fn remove(&mut self, elem: T) -> bool {
+ if let Some(i) = self.0.iter().position(|&e| e == elem) {
+ self.0.remove(i);
+ true
+ } else {
+ false
+ }
+ }
+
+ fn to_dense(&self, domain_size: usize) -> BitSet<T> {
+ let mut dense = BitSet::new_empty(domain_size);
+ for elem in self.0.iter() {
+ dense.insert(*elem);
+ }
+ dense
+ }
+
+ fn iter(&self) -> slice::Iter<T> {
+ self.0.iter()
+ }
+}
+
+impl<T: Idx> UnionIntoBitSet<T> for SparseBitSet<T> {
+ fn union_into(&self, other: &mut BitSet<T>) -> bool {
+ let mut changed = false;
+ for elem in self.iter() {
+ changed |= other.insert(*elem);
+ }
+ changed
+ }
+}
+
+impl<T: Idx> SubtractFromBitSet<T> for SparseBitSet<T> {
+ fn subtract_from(&self, other: &mut BitSet<T>) -> bool {
+ let mut changed = false;
+ for elem in self.iter() {
+ changed |= other.remove(*elem);
+ }
+ changed
+ }
+}
+
+/// A fixed-size bitset type with a hybrid representation: sparse when there
+/// are up to a `SPARSE_MAX` elements in the set, but dense when there are more
+/// than `SPARSE_MAX`.
+///
+/// This type is especially efficient for sets that typically have a small
+/// number of elements, but a large `domain_size`, and are cleared frequently.
+///
+/// `T` is an index type, typically a newtyped `usize` wrapper, but it can also
+/// just be `usize`.
+#[derive(Clone, Debug)]
+pub enum HybridBitSet<T: Idx> {
+ Sparse(SparseBitSet<T>, usize),
+ Dense(BitSet<T>, usize),
+}
+
+impl<T: Idx> HybridBitSet<T> {
+ // FIXME: This function is used in conjunction with `mem::replace()` in
+ // several pieces of awful code below. I can't work out how else to appease
+ // the borrow checker.
+ fn dummy() -> Self {
+ // The cheapest HybridBitSet to construct, which is only used to get
+ // around the borrow checker.
+ HybridBitSet::Sparse(SparseBitSet::new_empty(), 0)
+ }
+
+ pub fn new_empty(domain_size: usize) -> Self {
+ HybridBitSet::Sparse(SparseBitSet::new_empty(), domain_size)
+ }
+
+ pub fn domain_size(&self) -> usize {
+ match *self {
+ HybridBitSet::Sparse(_, size) => size,
+ HybridBitSet::Dense(_, size) => size,
+ }
+ }
+
+ pub fn clear(&mut self) {
+ let domain_size = self.domain_size();
+ *self = HybridBitSet::new_empty(domain_size);
+ }
+
+ pub fn contains(&self, elem: T) -> bool {
+ match self {
+ HybridBitSet::Sparse(sparse, _) => sparse.contains(elem),
+ HybridBitSet::Dense(dense, _) => dense.contains(elem),
+ }
+ }
+
+ pub fn superset(&self, other: &HybridBitSet<T>) -> bool {
+ match (self, other) {
+ (HybridBitSet::Dense(self_dense, _), HybridBitSet::Dense(other_dense, _)) => {
+ self_dense.superset(other_dense)
+ }
+ _ => other.iter().all(|elem| self.contains(elem)),
+ }
+ }
+
+ pub fn is_empty(&self) -> bool {
+ match self {
+ HybridBitSet::Sparse(sparse, _) => sparse.is_empty(),
+ HybridBitSet::Dense(dense, _) => dense.is_empty(),
+ }
+ }
+
+ pub fn insert(&mut self, elem: T) -> bool {
+ match self {
+ HybridBitSet::Sparse(sparse, _) if sparse.len() < SPARSE_MAX => {
+ // The set is sparse and has space for `elem`.
+ sparse.insert(elem)
+ }
+ HybridBitSet::Sparse(sparse, _) if sparse.contains(elem) => {
+ // The set is sparse and does not have space for `elem`, but
+ // that doesn't matter because `elem` is already present.
+ false
+ }
+ HybridBitSet::Sparse(_, _) => {
+ // The set is sparse and full. Convert to a dense set.
+ match mem::replace(self, HybridBitSet::dummy()) {
+ HybridBitSet::Sparse(sparse, domain_size) => {
+ let mut dense = sparse.to_dense(domain_size);
+ let changed = dense.insert(elem);
+ assert!(changed);
+ *self = HybridBitSet::Dense(dense, domain_size);
+ changed
+ }
+ _ => unreachable!()
+ }
+ }
+
+ HybridBitSet::Dense(dense, _) => dense.insert(elem),
+ }
+ }
+
+ pub fn insert_all(&mut self) {
+ let domain_size = self.domain_size();
+ match self {
+ HybridBitSet::Sparse(_, _) => {
+ let dense = BitSet::new_filled(domain_size);
+ *self = HybridBitSet::Dense(dense, domain_size);
+ }
+ HybridBitSet::Dense(dense, _) => dense.insert_all(),
+ }
+ }
+
+ pub fn remove(&mut self, elem: T) -> bool {
+ // Note: we currently don't bother going from Dense back to Sparse.
+ match self {
+ HybridBitSet::Sparse(sparse, _) => sparse.remove(elem),
+ HybridBitSet::Dense(dense, _) => dense.remove(elem),
+ }
+ }
+
+ pub fn union(&mut self, other: &HybridBitSet<T>) -> bool {
+ match self {
+ HybridBitSet::Sparse(_, _) => {
+ match other {
+ HybridBitSet::Sparse(other_sparse, _) => {
+ // Both sets are sparse. Add the elements in
+ // `other_sparse` to `self_hybrid` one at a time. This
+ // may or may not cause `self_hybrid` to be densified.
+ let mut self_hybrid = mem::replace(self, HybridBitSet::dummy());
+ let mut changed = false;
+ for elem in other_sparse.iter() {
+ changed |= self_hybrid.insert(*elem);
+ }
+ *self = self_hybrid;
+ changed
+ }
+ HybridBitSet::Dense(other_dense, _) => {
+ // `self` is sparse and `other` is dense. Densify
+ // `self` and then do the bitwise union.
+ match mem::replace(self, HybridBitSet::dummy()) {
+ HybridBitSet::Sparse(self_sparse, self_domain_size) => {
+ let mut new_dense = self_sparse.to_dense(self_domain_size);
+ let changed = new_dense.union(other_dense);
+ *self = HybridBitSet::Dense(new_dense, self_domain_size);
+ changed
+ }
+ _ => unreachable!()
+ }
+ }
+ }
+ }
+
+ HybridBitSet::Dense(self_dense, _) => self_dense.union(other),
+ }
+ }
+
+ /// Converts to a dense set, consuming itself in the process.
+ pub fn to_dense(self) -> BitSet<T> {
+ match self {
+ HybridBitSet::Sparse(sparse, domain_size) => sparse.to_dense(domain_size),
+ HybridBitSet::Dense(dense, _) => dense,
+ }
+ }
+
+ pub fn iter(&self) -> HybridIter<T> {
+ match self {
+ HybridBitSet::Sparse(sparse, _) => HybridIter::Sparse(sparse.iter()),
+ HybridBitSet::Dense(dense, _) => HybridIter::Dense(dense.iter()),
+ }
+ }
+}
+
+impl<T: Idx> UnionIntoBitSet<T> for HybridBitSet<T> {
+ fn union_into(&self, other: &mut BitSet<T>) -> bool {
+ match self {
+ HybridBitSet::Sparse(sparse, _) => sparse.union_into(other),
+ HybridBitSet::Dense(dense, _) => dense.union_into(other),
+ }
+ }
+}
+
+impl<T: Idx> SubtractFromBitSet<T> for HybridBitSet<T> {
+ fn subtract_from(&self, other: &mut BitSet<T>) -> bool {
+ match self {
+ HybridBitSet::Sparse(sparse, _) => sparse.subtract_from(other),
+ HybridBitSet::Dense(dense, _) => dense.subtract_from(other),
+ }
+ }
+}
+
+pub enum HybridIter<'a, T: Idx> {
+ Sparse(slice::Iter<'a, T>),
+ Dense(BitIter<'a, T>),
+}
+
+impl<'a, T: Idx> Iterator for HybridIter<'a, T> {
+ type Item = T;
+
+ fn next(&mut self) -> Option<T> {
+ match self {
+ HybridIter::Sparse(sparse) => sparse.next().map(|e| *e),
+ HybridIter::Dense(dense) => dense.next(),
+ }
+ }
+}
+
+/// A resizable bitset type with a dense representation.
+///
+/// `T` is an index type, typically a newtyped `usize` wrapper, but it can also
+/// just be `usize`.
+#[derive(Clone, Debug, PartialEq)]
+pub struct GrowableBitSet<T: Idx> {
+ bit_set: BitSet<T>,
+}
+
+impl<T: Idx> GrowableBitSet<T> {
+ pub fn grow(&mut self, domain_size: T) {
+ let num_words = num_words(domain_size);
+ if self.bit_set.words.len() <= num_words {
+ self.bit_set.words.resize(num_words + 1, 0)
+ }
+ }
+
+ pub fn new_empty() -> GrowableBitSet<T> {
+ GrowableBitSet { bit_set: BitSet::new_empty(0) }
+ }
+
+ pub fn with_capacity(bits: usize) -> GrowableBitSet<T> {
+ GrowableBitSet { bit_set: BitSet::new_empty(bits) }
+ }
+
+ /// Returns true if the set has changed.
+ #[inline]
+ pub fn insert(&mut self, elem: T) -> bool {
+ self.grow(elem);
+ self.bit_set.insert(elem)
+ }
+
+ #[inline]
+ pub fn contains(&self, elem: T) -> bool {
+ let (word_index, mask) = word_index_and_mask(elem);
+ if let Some(word) = self.bit_set.words.get(word_index) {
+ (word & mask) != 0
+ } else {
+ false
+ }
+ }
+}
+
+/// A fixed-size 2D bit matrix type with a dense representation.
+///
+/// `R` and `C` are index types used to identify rows and columns respectively;
+/// typically newtyped `usize` wrappers, but they can also just be `usize`.
+///
+#[derive(Clone, Debug)]
+pub struct BitMatrix<R: Idx, C: Idx> {
+ columns: usize,
+ words: Vec<Word>,
+ marker: PhantomData<(R, C)>,
+}
+
+impl<R: Idx, C: Idx> BitMatrix<R, C> {
+ /// Create a new `rows x columns` matrix, initially empty.
+ pub fn new(rows: usize, columns: usize) -> BitMatrix<R, C> {
+ // For every element, we need one bit for every other
+ // element. Round up to an even number of words.
+ let words_per_row = num_words(columns);
+ BitMatrix {
+ columns,
+ words: vec![0; rows * words_per_row],
+ marker: PhantomData,
+ }
+ }
+
+ /// The range of bits for a given row.
+ fn range(&self, row: R) -> (usize, usize) {
+ let row = row.index();
+ let words_per_row = num_words(self.columns);
+ let start = row * words_per_row;
+ (start, start + words_per_row)
+ }
+
+ /// Sets the cell at `(row, column)` to true. Put another way, insert
+ /// `column` to the bitset for `row`.
+ ///
+ /// Returns true if this changed the matrix, and false otherwise.
+ pub fn insert(&mut self, row: R, column: R) -> bool {
+ let (start, _) = self.range(row);
+ let (word_index, mask) = word_index_and_mask(column);
+ let words = &mut self.words[..];
+ let word = words[start + word_index];
+ let new_word = word | mask;
+ words[start + word_index] = new_word;
+ word != new_word
+ }
+
+ /// Do the bits from `row` contain `column`? Put another way, is
+ /// the matrix cell at `(row, column)` true? Put yet another way,
+ /// if the matrix represents (transitive) reachability, can
+ /// `row` reach `column`?
+ pub fn contains(&self, row: R, column: R) -> bool {
+ let (start, _) = self.range(row);
+ let (word_index, mask) = word_index_and_mask(column);
+ (self.words[start + word_index] & mask) != 0
+ }
+
+ /// Returns those indices that are true in rows `a` and `b`. This
+ /// is an O(n) operation where `n` is the number of elements
+ /// (somewhat independent from the actual size of the
+ /// intersection, in particular).
+ pub fn intersect_rows(&self, a: R, b: R) -> Vec<C> {
+ let (a_start, a_end) = self.range(a);
+ let (b_start, b_end) = self.range(b);
+ let mut result = Vec::with_capacity(self.columns);
+ for (base, (i, j)) in (a_start..a_end).zip(b_start..b_end).enumerate() {
+ let mut v = self.words[i] & self.words[j];
+ for bit in 0..WORD_BITS {
+ if v == 0 {
+ break;
+ }
+ if v & 0x1 != 0 {
+ result.push(C::new(base * WORD_BITS + bit));
+ }
+ v >>= 1;
+ }
+ }
+ result
+ }
+
+ /// Add the bits from row `read` to the bits from row `write`,
+ /// return true if anything changed.
+ ///
+ /// This is used when computing transitive reachability because if
+ /// you have an edge `write -> read`, because in that case
+ /// `write` can reach everything that `read` can (and
+ /// potentially more).
+ pub fn union_rows(&mut self, read: R, write: R) -> bool {
+ let (read_start, read_end) = self.range(read);
+ let (write_start, write_end) = self.range(write);
+ let words = &mut self.words[..];
+ let mut changed = false;
+ for (read_index, write_index) in (read_start..read_end).zip(write_start..write_end) {
+ let word = words[write_index];
+ let new_word = word | words[read_index];
+ words[write_index] = new_word;
+ changed |= word != new_word;
+ }
+ changed
+ }
+
+ /// Iterates through all the columns set to true in a given row of
+ /// the matrix.
+ pub fn iter<'a>(&'a self, row: R) -> BitIter<'a, C> {
+ let (start, end) = self.range(row);
+ BitIter {
+ cur: None,
+ iter: self.words[start..end].iter().enumerate(),
+ marker: PhantomData,
+ }
+ }
+}
+
+/// A fixed-column-size, variable-row-size 2D bit matrix with a moderately
+/// sparse representation.
+///
+/// Initially, every row has no explicit representation. If any bit within a
+/// row is set, the entire row is instantiated as `Some(<HybridBitSet>)`.
+/// Furthermore, any previously uninstantiated rows prior to it will be
+/// instantiated as `None`. Those prior rows may themselves become fully
+/// instantiated later on if any of their bits are set.
+///
+/// `R` and `C` are index types used to identify rows and columns respectively;
+/// typically newtyped `usize` wrappers, but they can also just be `usize`.
+#[derive(Clone, Debug)]
+pub struct SparseBitMatrix<R, C>
+where
+ R: Idx,
+ C: Idx,
+{
+ num_columns: usize,
+ rows: IndexVec<R, Option<HybridBitSet<C>>>,
+}
+
+impl<R: Idx, C: Idx> SparseBitMatrix<R, C> {
+ /// Create a new empty sparse bit matrix with no rows or columns.
+ pub fn new(num_columns: usize) -> Self {
+ Self {
+ num_columns,
+ rows: IndexVec::new(),
+ }
+ }
+
+ fn ensure_row(&mut self, row: R) -> &mut HybridBitSet<C> {
+ // Instantiate any missing rows up to and including row `row` with an
+ // empty HybridBitSet.
+ self.rows.ensure_contains_elem(row, || None);
+
+ // Then replace row `row` with a full HybridBitSet if necessary.
+ let num_columns = self.num_columns;
+ self.rows[row].get_or_insert_with(|| HybridBitSet::new_empty(num_columns))
+ }
+
+ /// Sets the cell at `(row, column)` to true. Put another way, insert
+ /// `column` to the bitset for `row`.
+ ///
+ /// Returns true if this changed the matrix, and false otherwise.
+ pub fn insert(&mut self, row: R, column: C) -> bool {
+ self.ensure_row(row).insert(column)
+ }
+
+ /// Do the bits from `row` contain `column`? Put another way, is
+ /// the matrix cell at `(row, column)` true? Put yet another way,
+ /// if the matrix represents (transitive) reachability, can
+ /// `row` reach `column`?
+ pub fn contains(&self, row: R, column: C) -> bool {
+ self.row(row).map_or(false, |r| r.contains(column))
+ }
+
+ /// Add the bits from row `read` to the bits from row `write`,
+ /// return true if anything changed.
+ ///
+ /// This is used when computing transitive reachability because if
+ /// you have an edge `write -> read`, because in that case
+ /// `write` can reach everything that `read` can (and
+ /// potentially more).
+ pub fn union_rows(&mut self, read: R, write: R) -> bool {
+ if read == write || self.row(read).is_none() {
+ return false;
+ }
+
+ self.ensure_row(write);
+ if let (Some(read_row), Some(write_row)) = self.rows.pick2_mut(read, write) {
+ write_row.union(read_row)
+ } else {
+ unreachable!()
+ }
+ }
+
+ /// Union a row, `from`, into the `into` row.
+ pub fn union_into_row(&mut self, into: R, from: &HybridBitSet<C>) -> bool {
+ self.ensure_row(into).union(from)
+ }
+
+ /// Insert all bits in the given row.
+ pub fn insert_all_into_row(&mut self, row: R) {
+ self.ensure_row(row).insert_all();
+ }
+
+ pub fn rows(&self) -> impl Iterator<Item = R> {
+ self.rows.indices()
+ }
+
+ /// Iterates through all the columns set to true in a given row of
+ /// the matrix.
+ pub fn iter<'a>(&'a self, row: R) -> impl Iterator<Item = C> + 'a {
+ self.row(row).into_iter().flat_map(|r| r.iter())
+ }
+
+ pub fn row(&self, row: R) -> Option<&HybridBitSet<C>> {
+ if let Some(Some(row)) = self.rows.get(row) {
+ Some(row)
+ } else {
+ None
+ }
+ }
+}
+
+#[inline]
+fn num_words<T: Idx>(elements: T) -> usize {
+ (elements.index() + WORD_BITS - 1) / WORD_BITS
+}
+
+#[inline]
+fn word_index_and_mask<T: Idx>(index: T) -> (usize, Word) {
+ let index = index.index();
+ let word_index = index / WORD_BITS;
+ let mask = 1 << (index % WORD_BITS);
+ (word_index, mask)
+}
+
+#[test]
+fn test_clear_above() {
+ use std::cmp;
+
+ for i in 0..256 {
+ let mut idx_buf: BitSet<usize> = BitSet::new_filled(128);
+ idx_buf.clear_above(i);
+
+ let elems: Vec<usize> = idx_buf.iter().collect();
+ let expected: Vec<usize> = (0..cmp::min(i, 128)).collect();
+ assert_eq!(elems, expected);
+ }
+}
+
+#[test]
+fn test_set_up_to() {
+ for i in 0..128 {
+ for mut idx_buf in
+ vec![BitSet::new_empty(128), BitSet::new_filled(128)].into_iter()
+ {
+ idx_buf.set_up_to(i);
+
+ let elems: Vec<usize> = idx_buf.iter().collect();
+ let expected: Vec<usize> = (0..i).collect();
+ assert_eq!(elems, expected);
+ }
+ }
+}
+
+#[test]
+fn test_new_filled() {
+ for i in 0..128 {
+ let idx_buf = BitSet::new_filled(i);
+ let elems: Vec<usize> = idx_buf.iter().collect();
+ let expected: Vec<usize> = (0..i).collect();
+ assert_eq!(elems, expected);
+ }
+}
+
+#[test]
+fn bitset_iter_works() {
+ let mut bitset: BitSet<usize> = BitSet::new_empty(100);
+ bitset.insert(1);
+ bitset.insert(10);
+ bitset.insert(19);
+ bitset.insert(62);
+ bitset.insert(63);
+ bitset.insert(64);
+ bitset.insert(65);
+ bitset.insert(66);
+ bitset.insert(99);
+ assert_eq!(
+ bitset.iter().collect::<Vec<_>>(),
+ [1, 10, 19, 62, 63, 64, 65, 66, 99]
+ );
+}
+
+#[test]
+fn bitset_iter_works_2() {
+ let mut bitset: BitSet<usize> = BitSet::new_empty(319);
+ bitset.insert(0);
+ bitset.insert(127);
+ bitset.insert(191);
+ bitset.insert(255);
+ bitset.insert(319);
+ assert_eq!(bitset.iter().collect::<Vec<_>>(), [0, 127, 191, 255, 319]);
+}
+
+#[test]
+fn union_two_sets() {
+ let mut set1: BitSet<usize> = BitSet::new_empty(65);
+ let mut set2: BitSet<usize> = BitSet::new_empty(65);
+ assert!(set1.insert(3));
+ assert!(!set1.insert(3));
+ assert!(set2.insert(5));
+ assert!(set2.insert(64));
+ assert!(set1.union(&set2));
+ assert!(!set1.union(&set2));
+ assert!(set1.contains(3));
+ assert!(!set1.contains(4));
+ assert!(set1.contains(5));
+ assert!(!set1.contains(63));
+ assert!(set1.contains(64));
+}
+
+#[test]
+fn hybrid_bitset() {
+ let mut sparse038: HybridBitSet<usize> = HybridBitSet::new_empty(256);
+ assert!(sparse038.is_empty());
+ assert!(sparse038.insert(0));
+ assert!(sparse038.insert(1));
+ assert!(sparse038.insert(8));
+ assert!(sparse038.insert(3));
+ assert!(!sparse038.insert(3));
+ assert!(sparse038.remove(1));
+ assert!(!sparse038.is_empty());
+ assert_eq!(sparse038.iter().collect::<Vec<_>>(), [0, 3, 8]);
+
+ for i in 0..256 {
+ if i == 0 || i == 3 || i == 8 {
+ assert!(sparse038.contains(i));
+ } else {
+ assert!(!sparse038.contains(i));
+ }
+ }
+
+ let mut sparse01358 = sparse038.clone();
+ assert!(sparse01358.insert(1));
+ assert!(sparse01358.insert(5));
+ assert_eq!(sparse01358.iter().collect::<Vec<_>>(), [0, 1, 3, 5, 8]);
+
+ let mut dense10 = HybridBitSet::new_empty(256);
+ for i in 0..10 {
+ assert!(dense10.insert(i));
+ }
+ assert!(!dense10.is_empty());
+ assert_eq!(dense10.iter().collect::<Vec<_>>(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
+
+ let mut dense256 = HybridBitSet::new_empty(256);
+ assert!(dense256.is_empty());
+ dense256.insert_all();
+ assert!(!dense256.is_empty());
+ for i in 0..256 {
+ assert!(dense256.contains(i));
+ }
+
+ assert!(sparse038.superset(&sparse038)); // sparse + sparse (self)
+ assert!(sparse01358.superset(&sparse038)); // sparse + sparse
+ assert!(dense10.superset(&sparse038)); // dense + sparse
+ assert!(dense10.superset(&dense10)); // dense + dense (self)
+ assert!(dense256.superset(&dense10)); // dense + dense
+
+ let mut hybrid = sparse038;
+ assert!(!sparse01358.union(&hybrid)); // no change
+ assert!(hybrid.union(&sparse01358));
+ assert!(hybrid.superset(&sparse01358) && sparse01358.superset(&hybrid));
+ assert!(!dense10.union(&sparse01358));
+ assert!(!dense256.union(&dense10));
+ let mut dense = dense10;
+ assert!(dense.union(&dense256));
+ assert!(dense.superset(&dense256) && dense256.superset(&dense));
+ assert!(hybrid.union(&dense256));
+ assert!(hybrid.superset(&dense256) && dense256.superset(&hybrid));
+
+ assert_eq!(dense256.iter().count(), 256);
+ let mut dense0 = dense256;
+ for i in 0..256 {
+ assert!(dense0.remove(i));
+ }
+ assert!(!dense0.remove(0));
+ assert!(dense0.is_empty());
+}
+
+#[test]
+fn grow() {
+ let mut set: GrowableBitSet<usize> = GrowableBitSet::with_capacity(65);
+ for index in 0..65 {
+ assert!(set.insert(index));
+ assert!(!set.insert(index));
+ }
+ set.grow(128);
+
+ // Check if the bits set before growing are still set
+ for index in 0..65 {
+ assert!(set.contains(index));
+ }
+
+ // Check if the new bits are all un-set
+ for index in 65..128 {
+ assert!(!set.contains(index));
+ }
+
+ // Check that we can set all new bits without running out of bounds
+ for index in 65..128 {
+ assert!(set.insert(index));
+ assert!(!set.insert(index));
+ }
+}
+
+#[test]
+fn matrix_intersection() {
+ let mut matrix: BitMatrix<usize, usize> = BitMatrix::new(200, 200);
+
+ // (*) Elements reachable from both 2 and 65.
+
+ matrix.insert(2, 3);
+ matrix.insert(2, 6);
+ matrix.insert(2, 10); // (*)
+ matrix.insert(2, 64); // (*)
+ matrix.insert(2, 65);
+ matrix.insert(2, 130);
+ matrix.insert(2, 160); // (*)
+
+ matrix.insert(64, 133);
+
+ matrix.insert(65, 2);
+ matrix.insert(65, 8);
+ matrix.insert(65, 10); // (*)
+ matrix.insert(65, 64); // (*)
+ matrix.insert(65, 68);
+ matrix.insert(65, 133);
+ matrix.insert(65, 160); // (*)
+
+ let intersection = matrix.intersect_rows(2, 64);
+ assert!(intersection.is_empty());
+
+ let intersection = matrix.intersect_rows(2, 65);
+ assert_eq!(intersection, &[10, 64, 160]);
+}
+
+#[test]
+fn matrix_iter() {
+ let mut matrix: BitMatrix<usize, usize> = BitMatrix::new(64, 100);
+ matrix.insert(3, 22);
+ matrix.insert(3, 75);
+ matrix.insert(2, 99);
+ matrix.insert(4, 0);
+ matrix.union_rows(3, 5);
+
+ let expected = [99];
+ let mut iter = expected.iter();
+ for i in matrix.iter(2) {
+ let j = *iter.next().unwrap();
+ assert_eq!(i, j);
+ }
+ assert!(iter.next().is_none());
+
+ let expected = [22, 75];
+ let mut iter = expected.iter();
+ for i in matrix.iter(3) {
+ let j = *iter.next().unwrap();
+ assert_eq!(i, j);
+ }
+ assert!(iter.next().is_none());
+
+ let expected = [0];
+ let mut iter = expected.iter();
+ for i in matrix.iter(4) {
+ let j = *iter.next().unwrap();
+ assert_eq!(i, j);
+ }
+ assert!(iter.next().is_none());
+
+ let expected = [22, 75];
+ let mut iter = expected.iter();
+ for i in matrix.iter(5) {
+ let j = *iter.next().unwrap();
+ assert_eq!(i, j);
+ }
+ assert!(iter.next().is_none());
+}
+
+#[test]
+fn sparse_matrix_iter() {
+ let mut matrix: SparseBitMatrix<usize, usize> = SparseBitMatrix::new(100);
+ matrix.insert(3, 22);
+ matrix.insert(3, 75);
+ matrix.insert(2, 99);
+ matrix.insert(4, 0);
+ matrix.union_rows(3, 5);
+
+ let expected = [99];
+ let mut iter = expected.iter();
+ for i in matrix.iter(2) {
+ let j = *iter.next().unwrap();
+ assert_eq!(i, j);
+ }
+ assert!(iter.next().is_none());
+
+ let expected = [22, 75];
+ let mut iter = expected.iter();
+ for i in matrix.iter(3) {
+ let j = *iter.next().unwrap();
+ assert_eq!(i, j);
+ }
+ assert!(iter.next().is_none());
+
+ let expected = [0];
+ let mut iter = expected.iter();
+ for i in matrix.iter(4) {
+ let j = *iter.next().unwrap();
+ assert_eq!(i, j);
+ }
+ assert!(iter.next().is_none());
+
+ let expected = [22, 75];
+ let mut iter = expected.iter();
+ for i in matrix.iter(5) {
+ let j = *iter.next().unwrap();
+ assert_eq!(i, j);
+ }
+ assert!(iter.next().is_none());
+}
+++ /dev/null
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use indexed_vec::{Idx, IndexVec};
-use rustc_serialize;
-use std::iter;
-use std::marker::PhantomData;
-use std::slice;
-
-pub type Word = u64;
-pub const WORD_BYTES: usize = ::std::mem::size_of::<Word>();
-pub const WORD_BITS: usize = WORD_BYTES * 8;
-
-/// A very simple BitArray type.
-///
-/// It does not support resizing after creation; use `BitVector` for that.
-#[derive(Clone, Debug, Eq, PartialEq)]
-pub struct BitArray<C: Idx> {
- data: Vec<Word>,
- marker: PhantomData<C>,
-}
-
-impl<C: Idx> BitArray<C> {
- // Do not make this method public, instead switch your use case to BitVector.
- #[inline]
- fn grow(&mut self, num_bits: C) {
- let num_words = num_words(num_bits);
- if self.data.len() <= num_words {
- self.data.resize(num_words + 1, 0)
- }
- }
-
- #[inline]
- pub fn new(num_bits: usize) -> BitArray<C> {
- BitArray::new_empty(num_bits)
- }
-
- #[inline]
- pub fn new_empty(num_bits: usize) -> BitArray<C> {
- let num_words = num_words(num_bits);
- BitArray {
- data: vec![0; num_words],
- marker: PhantomData,
- }
- }
-
- #[inline]
- pub fn new_filled(num_bits: usize) -> BitArray<C> {
- let num_words = num_words(num_bits);
- let mut result = BitArray {
- data: vec![!0; num_words],
- marker: PhantomData,
- };
- result.clear_above(num_bits);
- result
- }
-
- #[inline]
- pub fn clear(&mut self) {
- for p in &mut self.data {
- *p = 0;
- }
- }
-
- /// Sets all elements up to `num_bits`.
- pub fn set_up_to(&mut self, num_bits: usize) {
- for p in &mut self.data {
- *p = !0;
- }
- self.clear_above(num_bits);
- }
-
- /// Clear all elements above `num_bits`.
- fn clear_above(&mut self, num_bits: usize) {
- let first_clear_block = num_bits / WORD_BITS;
-
- if first_clear_block < self.data.len() {
- // Within `first_clear_block`, the `num_bits % WORD_BITS` LSBs
- // should remain.
- let mask = (1 << (num_bits % WORD_BITS)) - 1;
- self.data[first_clear_block] &= mask;
-
- // All the blocks above `first_clear_block` are fully cleared.
- for b in &mut self.data[first_clear_block + 1..] {
- *b = 0;
- }
- }
- }
-
- pub fn count(&self) -> usize {
- self.data.iter().map(|e| e.count_ones() as usize).sum()
- }
-
- /// True if `self` contains the bit `bit`.
- #[inline]
- pub fn contains(&self, bit: C) -> bool {
- let (word, mask) = word_mask(bit);
- (self.data[word] & mask) != 0
- }
-
- /// True if `self` contains all the bits in `other`.
- ///
- /// The two vectors must have the same length.
- #[inline]
- pub fn contains_all(&self, other: &BitArray<C>) -> bool {
- assert_eq!(self.data.len(), other.data.len());
- self.data.iter().zip(&other.data).all(|(a, b)| (a & b) == *b)
- }
-
- #[inline]
- pub fn is_empty(&self) -> bool {
- self.data.iter().all(|a| *a == 0)
- }
-
- /// Returns true if the bit has changed.
- #[inline]
- pub fn insert(&mut self, bit: C) -> bool {
- let (word, mask) = word_mask(bit);
- let data = &mut self.data[word];
- let value = *data;
- let new_value = value | mask;
- *data = new_value;
- new_value != value
- }
-
- /// Sets all bits to true.
- pub fn insert_all(&mut self) {
- for data in &mut self.data {
- *data = !0;
- }
- }
-
- /// Returns true if the bit has changed.
- #[inline]
- pub fn remove(&mut self, bit: C) -> bool {
- let (word, mask) = word_mask(bit);
- let data = &mut self.data[word];
- let value = *data;
- let new_value = value & !mask;
- *data = new_value;
- new_value != value
- }
-
- #[inline]
- pub fn merge(&mut self, all: &BitArray<C>) -> bool {
- assert!(self.data.len() == all.data.len());
- let mut changed = false;
- for (i, j) in self.data.iter_mut().zip(&all.data) {
- let value = *i;
- *i = value | *j;
- if value != *i {
- changed = true;
- }
- }
- changed
- }
-
- pub fn words(&self) -> &[Word] {
- &self.data
- }
-
- pub fn words_mut(&mut self) -> &mut [Word] {
- &mut self.data
- }
-
- /// Iterates over indexes of set bits in a sorted order
- #[inline]
- pub fn iter<'a>(&'a self) -> BitIter<'a, C> {
- BitIter {
- cur: None,
- iter: self.data.iter().enumerate(),
- marker: PhantomData,
- }
- }
-}
-
-impl<T: Idx> rustc_serialize::Encodable for BitArray<T> {
- fn encode<E: rustc_serialize::Encoder>(&self, encoder: &mut E) -> Result<(), E::Error> {
- self.data.encode(encoder)
- }
-}
-
-impl<T: Idx> rustc_serialize::Decodable for BitArray<T> {
- fn decode<D: rustc_serialize::Decoder>(d: &mut D) -> Result<BitArray<T>, D::Error> {
- let words: Vec<Word> = rustc_serialize::Decodable::decode(d)?;
- Ok(BitArray {
- data: words,
- marker: PhantomData,
- })
- }
-}
-
-pub struct BitIter<'a, C: Idx> {
- cur: Option<(Word, usize)>,
- iter: iter::Enumerate<slice::Iter<'a, Word>>,
- marker: PhantomData<C>
-}
-
-impl<'a, C: Idx> Iterator for BitIter<'a, C> {
- type Item = C;
- fn next(&mut self) -> Option<C> {
- loop {
- if let Some((ref mut word, offset)) = self.cur {
- let bit_pos = word.trailing_zeros() as usize;
- if bit_pos != WORD_BITS {
- let bit = 1 << bit_pos;
- *word ^= bit;
- return Some(C::new(bit_pos + offset))
- }
- }
-
- let (i, word) = self.iter.next()?;
- self.cur = Some((*word, WORD_BITS * i));
- }
- }
-}
-
-pub trait BitwiseOperator {
- /// Applies some bit-operation pointwise to each of the bits in the two inputs.
- fn join(&self, pred1: Word, pred2: Word) -> Word;
-}
-
-#[inline]
-pub fn bitwise<Op: BitwiseOperator>(out_vec: &mut [Word], in_vec: &[Word], op: &Op) -> bool
-{
- assert_eq!(out_vec.len(), in_vec.len());
- let mut changed = false;
- for (out_elem, in_elem) in out_vec.iter_mut().zip(in_vec.iter()) {
- let old_val = *out_elem;
- let new_val = op.join(old_val, *in_elem);
- *out_elem = new_val;
- changed |= old_val != new_val;
- }
- changed
-}
-
-pub struct Intersect;
-impl BitwiseOperator for Intersect {
- #[inline]
- fn join(&self, a: Word, b: Word) -> Word { a & b }
-}
-
-pub struct Union;
-impl BitwiseOperator for Union {
- #[inline]
- fn join(&self, a: Word, b: Word) -> Word { a | b }
-}
-
-pub struct Subtract;
-impl BitwiseOperator for Subtract {
- #[inline]
- fn join(&self, a: Word, b: Word) -> Word { a & !b }
-}
-
-pub fn bits_to_string(words: &[Word], bits: usize) -> String {
- let mut result = String::new();
- let mut sep = '[';
-
- // Note: this is a little endian printout of bytes.
-
- // i tracks how many bits we have printed so far.
- let mut i = 0;
- for &word in words.iter() {
- let mut v = word;
- for _ in 0..WORD_BYTES { // for each byte in `v`:
- let remain = bits - i;
- // If less than a byte remains, then mask just that many bits.
- let mask = if remain <= 8 { (1 << remain) - 1 } else { 0xFF };
- assert!(mask <= 0xFF);
- let byte = v & mask;
-
- result.push_str(&format!("{}{:02x}", sep, byte));
-
- if remain <= 8 { break; }
- v >>= 8;
- i += 8;
- sep = '-';
- }
- sep = '|';
- }
- result.push(']');
-
- result
-}
-
-/// A resizable BitVector type.
-#[derive(Clone, Debug, PartialEq)]
-pub struct BitVector<C: Idx> {
- data: BitArray<C>,
-}
-
-impl<C: Idx> BitVector<C> {
- pub fn grow(&mut self, num_bits: C) {
- self.data.grow(num_bits)
- }
-
- pub fn new() -> BitVector<C> {
- BitVector { data: BitArray::new(0) }
- }
-
- pub fn with_capacity(bits: usize) -> BitVector<C> {
- BitVector { data: BitArray::new(bits) }
- }
-
- /// Returns true if the bit has changed.
- #[inline]
- pub fn insert(&mut self, bit: C) -> bool {
- self.grow(bit);
- self.data.insert(bit)
- }
-
- #[inline]
- pub fn contains(&self, bit: C) -> bool {
- let (word, mask) = word_mask(bit);
- if let Some(word) = self.data.data.get(word) {
- (word & mask) != 0
- } else {
- false
- }
- }
-}
-
-/// A "bit matrix" is basically a matrix of booleans represented as
-/// one gigantic bitvector. In other words, it is as if you have
-/// `rows` bitvectors, each of length `columns`.
-#[derive(Clone, Debug)]
-pub struct BitMatrix<R: Idx, C: Idx> {
- columns: usize,
- vector: Vec<Word>,
- phantom: PhantomData<(R, C)>,
-}
-
-impl<R: Idx, C: Idx> BitMatrix<R, C> {
- /// Create a new `rows x columns` matrix, initially empty.
- pub fn new(rows: usize, columns: usize) -> BitMatrix<R, C> {
- // For every element, we need one bit for every other
- // element. Round up to an even number of words.
- let words_per_row = num_words(columns);
- BitMatrix {
- columns,
- vector: vec![0; rows * words_per_row],
- phantom: PhantomData,
- }
- }
-
- /// The range of bits for a given row.
- fn range(&self, row: R) -> (usize, usize) {
- let row = row.index();
- let words_per_row = num_words(self.columns);
- let start = row * words_per_row;
- (start, start + words_per_row)
- }
-
- /// Sets the cell at `(row, column)` to true. Put another way, add
- /// `column` to the bitset for `row`.
- ///
- /// Returns true if this changed the matrix, and false otherwise.
- pub fn add(&mut self, row: R, column: R) -> bool {
- let (start, _) = self.range(row);
- let (word, mask) = word_mask(column);
- let vector = &mut self.vector[..];
- let v1 = vector[start + word];
- let v2 = v1 | mask;
- vector[start + word] = v2;
- v1 != v2
- }
-
- /// Do the bits from `row` contain `column`? Put another way, is
- /// the matrix cell at `(row, column)` true? Put yet another way,
- /// if the matrix represents (transitive) reachability, can
- /// `row` reach `column`?
- pub fn contains(&self, row: R, column: R) -> bool {
- let (start, _) = self.range(row);
- let (word, mask) = word_mask(column);
- (self.vector[start + word] & mask) != 0
- }
-
- /// Returns those indices that are true in rows `a` and `b`. This
- /// is an O(n) operation where `n` is the number of elements
- /// (somewhat independent from the actual size of the
- /// intersection, in particular).
- pub fn intersection(&self, a: R, b: R) -> Vec<C> {
- let (a_start, a_end) = self.range(a);
- let (b_start, b_end) = self.range(b);
- let mut result = Vec::with_capacity(self.columns);
- for (base, (i, j)) in (a_start..a_end).zip(b_start..b_end).enumerate() {
- let mut v = self.vector[i] & self.vector[j];
- for bit in 0..WORD_BITS {
- if v == 0 {
- break;
- }
- if v & 0x1 != 0 {
- result.push(C::new(base * WORD_BITS + bit));
- }
- v >>= 1;
- }
- }
- result
- }
-
- /// Add the bits from row `read` to the bits from row `write`,
- /// return true if anything changed.
- ///
- /// This is used when computing transitive reachability because if
- /// you have an edge `write -> read`, because in that case
- /// `write` can reach everything that `read` can (and
- /// potentially more).
- pub fn merge(&mut self, read: R, write: R) -> bool {
- let (read_start, read_end) = self.range(read);
- let (write_start, write_end) = self.range(write);
- let vector = &mut self.vector[..];
- let mut changed = false;
- for (read_index, write_index) in (read_start..read_end).zip(write_start..write_end) {
- let v1 = vector[write_index];
- let v2 = v1 | vector[read_index];
- vector[write_index] = v2;
- changed |= v1 != v2;
- }
- changed
- }
-
- /// Iterates through all the columns set to true in a given row of
- /// the matrix.
- pub fn iter<'a>(&'a self, row: R) -> BitIter<'a, C> {
- let (start, end) = self.range(row);
- BitIter {
- cur: None,
- iter: self.vector[start..end].iter().enumerate(),
- marker: PhantomData,
- }
- }
-}
-
-/// A moderately sparse bit matrix, in which rows are instantiated lazily.
-///
-/// Initially, every row has no explicit representation. If any bit within a
-/// row is set, the entire row is instantiated as
-/// `Some(<full-column-width-BitArray>)`. Furthermore, any previously
-/// uninstantiated rows prior to it will be instantiated as `None`. Those prior
-/// rows may themselves become fully instantiated later on if any of their bits
-/// are set.
-#[derive(Clone, Debug)]
-pub struct SparseBitMatrix<R, C>
-where
- R: Idx,
- C: Idx,
-{
- num_columns: usize,
- rows: IndexVec<R, Option<BitArray<C>>>,
-}
-
-impl<R: Idx, C: Idx> SparseBitMatrix<R, C> {
- /// Create a new empty sparse bit matrix with no rows or columns.
- pub fn new(num_columns: usize) -> Self {
- Self {
- num_columns,
- rows: IndexVec::new(),
- }
- }
-
- fn ensure_row(&mut self, row: R) -> &mut BitArray<C> {
- // Instantiate any missing rows up to and including row `row` with an
- // empty BitArray.
- self.rows.ensure_contains_elem(row, || None);
-
- // Then replace row `row` with a full BitArray if necessary.
- let num_columns = self.num_columns;
- self.rows[row].get_or_insert_with(|| BitArray::new(num_columns))
- }
-
- /// Sets the cell at `(row, column)` to true. Put another way, insert
- /// `column` to the bitset for `row`.
- ///
- /// Returns true if this changed the matrix, and false otherwise.
- pub fn add(&mut self, row: R, column: C) -> bool {
- self.ensure_row(row).insert(column)
- }
-
- /// Do the bits from `row` contain `column`? Put another way, is
- /// the matrix cell at `(row, column)` true? Put yet another way,
- /// if the matrix represents (transitive) reachability, can
- /// `row` reach `column`?
- pub fn contains(&self, row: R, column: C) -> bool {
- self.row(row).map_or(false, |r| r.contains(column))
- }
-
- /// Add the bits from row `read` to the bits from row `write`,
- /// return true if anything changed.
- ///
- /// This is used when computing transitive reachability because if
- /// you have an edge `write -> read`, because in that case
- /// `write` can reach everything that `read` can (and
- /// potentially more).
- pub fn merge(&mut self, read: R, write: R) -> bool {
- if read == write || self.row(read).is_none() {
- return false;
- }
-
- self.ensure_row(write);
- if let (Some(bitvec_read), Some(bitvec_write)) = self.rows.pick2_mut(read, write) {
- bitvec_write.merge(bitvec_read)
- } else {
- unreachable!()
- }
- }
-
- /// Merge a row, `from`, into the `into` row.
- pub fn merge_into(&mut self, into: R, from: &BitArray<C>) -> bool {
- self.ensure_row(into).merge(from)
- }
-
- /// Add all bits to the given row.
- pub fn add_all(&mut self, row: R) {
- self.ensure_row(row).insert_all();
- }
-
- pub fn rows(&self) -> impl Iterator<Item = R> {
- self.rows.indices()
- }
-
- /// Iterates through all the columns set to true in a given row of
- /// the matrix.
- pub fn iter<'a>(&'a self, row: R) -> impl Iterator<Item = C> + 'a {
- self.row(row).into_iter().flat_map(|r| r.iter())
- }
-
- pub fn row(&self, row: R) -> Option<&BitArray<C>> {
- if let Some(Some(row)) = self.rows.get(row) {
- Some(row)
- } else {
- None
- }
- }
-}
-
-#[inline]
-fn num_words<C: Idx>(elements: C) -> usize {
- (elements.index() + WORD_BITS - 1) / WORD_BITS
-}
-
-#[inline]
-fn word_mask<C: Idx>(index: C) -> (usize, Word) {
- let index = index.index();
- let word = index / WORD_BITS;
- let mask = 1 << (index % WORD_BITS);
- (word, mask)
-}
-
-#[test]
-fn test_clear_above() {
- use std::cmp;
-
- for i in 0..256 {
- let mut idx_buf: BitArray<usize> = BitArray::new_filled(128);
- idx_buf.clear_above(i);
-
- let elems: Vec<usize> = idx_buf.iter().collect();
- let expected: Vec<usize> = (0..cmp::min(i, 128)).collect();
- assert_eq!(elems, expected);
- }
-}
-
-#[test]
-fn test_set_up_to() {
- for i in 0..128 {
- for mut idx_buf in
- vec![BitArray::new_empty(128), BitArray::new_filled(128)]
- .into_iter()
- {
- idx_buf.set_up_to(i);
-
- let elems: Vec<usize> = idx_buf.iter().collect();
- let expected: Vec<usize> = (0..i).collect();
- assert_eq!(elems, expected);
- }
- }
-}
-
-#[test]
-fn test_new_filled() {
- for i in 0..128 {
- let idx_buf = BitArray::new_filled(i);
- let elems: Vec<usize> = idx_buf.iter().collect();
- let expected: Vec<usize> = (0..i).collect();
- assert_eq!(elems, expected);
- }
-}
-
-#[test]
-fn bitvec_iter_works() {
- let mut bitvec: BitArray<usize> = BitArray::new(100);
- bitvec.insert(1);
- bitvec.insert(10);
- bitvec.insert(19);
- bitvec.insert(62);
- bitvec.insert(63);
- bitvec.insert(64);
- bitvec.insert(65);
- bitvec.insert(66);
- bitvec.insert(99);
- assert_eq!(
- bitvec.iter().collect::<Vec<_>>(),
- [1, 10, 19, 62, 63, 64, 65, 66, 99]
- );
-}
-
-#[test]
-fn bitvec_iter_works_2() {
- let mut bitvec: BitArray<usize> = BitArray::new(319);
- bitvec.insert(0);
- bitvec.insert(127);
- bitvec.insert(191);
- bitvec.insert(255);
- bitvec.insert(319);
- assert_eq!(bitvec.iter().collect::<Vec<_>>(), [0, 127, 191, 255, 319]);
-}
-
-#[test]
-fn union_two_vecs() {
- let mut vec1: BitArray<usize> = BitArray::new(65);
- let mut vec2: BitArray<usize> = BitArray::new(65);
- assert!(vec1.insert(3));
- assert!(!vec1.insert(3));
- assert!(vec2.insert(5));
- assert!(vec2.insert(64));
- assert!(vec1.merge(&vec2));
- assert!(!vec1.merge(&vec2));
- assert!(vec1.contains(3));
- assert!(!vec1.contains(4));
- assert!(vec1.contains(5));
- assert!(!vec1.contains(63));
- assert!(vec1.contains(64));
-}
-
-#[test]
-fn grow() {
- let mut vec1: BitVector<usize> = BitVector::with_capacity(65);
- for index in 0..65 {
- assert!(vec1.insert(index));
- assert!(!vec1.insert(index));
- }
- vec1.grow(128);
-
- // Check if the bits set before growing are still set
- for index in 0..65 {
- assert!(vec1.contains(index));
- }
-
- // Check if the new bits are all un-set
- for index in 65..128 {
- assert!(!vec1.contains(index));
- }
-
- // Check that we can set all new bits without running out of bounds
- for index in 65..128 {
- assert!(vec1.insert(index));
- assert!(!vec1.insert(index));
- }
-}
-
-#[test]
-fn matrix_intersection() {
- let mut vec1: BitMatrix<usize, usize> = BitMatrix::new(200, 200);
-
- // (*) Elements reachable from both 2 and 65.
-
- vec1.add(2, 3);
- vec1.add(2, 6);
- vec1.add(2, 10); // (*)
- vec1.add(2, 64); // (*)
- vec1.add(2, 65);
- vec1.add(2, 130);
- vec1.add(2, 160); // (*)
-
- vec1.add(64, 133);
-
- vec1.add(65, 2);
- vec1.add(65, 8);
- vec1.add(65, 10); // (*)
- vec1.add(65, 64); // (*)
- vec1.add(65, 68);
- vec1.add(65, 133);
- vec1.add(65, 160); // (*)
-
- let intersection = vec1.intersection(2, 64);
- assert!(intersection.is_empty());
-
- let intersection = vec1.intersection(2, 65);
- assert_eq!(intersection, &[10, 64, 160]);
-}
-
-#[test]
-fn matrix_iter() {
- let mut matrix: BitMatrix<usize, usize> = BitMatrix::new(64, 100);
- matrix.add(3, 22);
- matrix.add(3, 75);
- matrix.add(2, 99);
- matrix.add(4, 0);
- matrix.merge(3, 5);
-
- let expected = [99];
- let mut iter = expected.iter();
- for i in matrix.iter(2) {
- let j = *iter.next().unwrap();
- assert_eq!(i, j);
- }
- assert!(iter.next().is_none());
-
- let expected = [22, 75];
- let mut iter = expected.iter();
- for i in matrix.iter(3) {
- let j = *iter.next().unwrap();
- assert_eq!(i, j);
- }
- assert!(iter.next().is_none());
-
- let expected = [0];
- let mut iter = expected.iter();
- for i in matrix.iter(4) {
- let j = *iter.next().unwrap();
- assert_eq!(i, j);
- }
- assert!(iter.next().is_none());
-
- let expected = [22, 75];
- let mut iter = expected.iter();
- for i in matrix.iter(5) {
- let j = *iter.next().unwrap();
- assert_eq!(i, j);
- }
- assert!(iter.next().is_none());
-}
-
-#[test]
-fn sparse_matrix_iter() {
- let mut matrix: SparseBitMatrix<usize, usize> = SparseBitMatrix::new(100);
- matrix.add(3, 22);
- matrix.add(3, 75);
- matrix.add(2, 99);
- matrix.add(4, 0);
- matrix.merge(3, 5);
-
- let expected = [99];
- let mut iter = expected.iter();
- for i in matrix.iter(2) {
- let j = *iter.next().unwrap();
- assert_eq!(i, j);
- }
- assert!(iter.next().is_none());
-
- let expected = [22, 75];
- let mut iter = expected.iter();
- for i in matrix.iter(3) {
- let j = *iter.next().unwrap();
- assert_eq!(i, j);
- }
- assert!(iter.next().is_none());
-
- let expected = [0];
- let mut iter = expected.iter();
- for i in matrix.iter(4) {
- let j = *iter.next().unwrap();
- assert_eq!(i, j);
- }
- assert!(iter.next().is_none());
-
- let expected = [22, 75];
- let mut iter = expected.iter();
- for i in matrix.iter(5) {
- let j = *iter.next().unwrap();
- assert_eq!(i, j);
- }
- assert!(iter.next().is_none());
-}
//! the field `next_edge`). Each of those fields is an array that should
//! be indexed by the direction (see the type `Direction`).
-use bitvec::BitArray;
+use bit_set::BitSet;
use std::fmt::Debug;
use std::usize;
use snapshot_vec::{SnapshotVec, SnapshotVecDelegate};
direction: Direction,
entry_node: NodeIndex,
) -> Vec<NodeIndex> {
- let mut visited = BitArray::new(self.len_nodes());
+ let mut visited = BitSet::new_empty(self.len_nodes());
let mut stack = vec![];
let mut result = Vec::with_capacity(self.len_nodes());
let mut push_node = |stack: &mut Vec<_>, node: NodeIndex| {
{
graph: &'g Graph<N, E>,
stack: Vec<NodeIndex>,
- visited: BitArray<usize>,
+ visited: BitSet<usize>,
direction: Direction,
}
start_node: NodeIndex,
direction: Direction,
) -> Self {
- let mut visited = BitArray::new(graph.len_nodes());
+ let mut visited = BitSet::new_empty(graph.len_nodes());
visited.insert(start_node.node_id());
DepthFirstTraversal {
graph,
+++ /dev/null
-// Copyright 2012-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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use array_vec::ArrayVec;
-use std::fmt;
-use std::mem;
-use std::slice;
-use bitvec::{bitwise, BitArray, BitIter, Intersect, Subtract, Union, Word, WORD_BITS};
-use indexed_vec::Idx;
-use rustc_serialize;
-
-/// This is implemented by all the index sets so that IdxSet::union() can be
-/// passed any type of index set.
-pub trait UnionIntoIdxSet<T: Idx> {
- // Performs `other = other | self`.
- fn union_into(&self, other: &mut IdxSet<T>) -> bool;
-}
-
-/// This is implemented by all the index sets so that IdxSet::subtract() can be
-/// passed any type of index set.
-pub trait SubtractFromIdxSet<T: Idx> {
- // Performs `other = other - self`.
- fn subtract_from(&self, other: &mut IdxSet<T>) -> bool;
-}
-
-/// Represents a set of some element type E, where each E is identified by some
-/// unique index type `T`.
-///
-/// In other words, `T` is the type used to index into the bitvector
-/// this type uses to represent the set of object it holds.
-///
-/// The representation is dense, using one bit per possible element.
-#[derive(Clone, Eq, PartialEq)]
-pub struct IdxSet<T: Idx>(BitArray<T>);
-
-impl<T: Idx> rustc_serialize::Encodable for IdxSet<T> {
- fn encode<E: rustc_serialize::Encoder>(&self, encoder: &mut E) -> Result<(), E::Error> {
- self.0.encode(encoder)
- }
-}
-
-impl<T: Idx> rustc_serialize::Decodable for IdxSet<T> {
- fn decode<D: rustc_serialize::Decoder>(d: &mut D) -> Result<IdxSet<T>, D::Error> {
- Ok(IdxSet(rustc_serialize::Decodable::decode(d)?))
- }
-}
-
-impl<T: Idx> fmt::Debug for IdxSet<T> {
- fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
- w.debug_list()
- .entries(self.iter())
- .finish()
- }
-}
-
-impl<T: Idx> IdxSet<T> {
- /// Creates set holding no elements.
- pub fn new_empty(domain_size: usize) -> Self {
- IdxSet(BitArray::new_empty(domain_size))
- }
-
- /// Creates set holding every element whose index falls in range 0..domain_size.
- pub fn new_filled(domain_size: usize) -> Self {
- IdxSet(BitArray::new_filled(domain_size))
- }
-
- /// Duplicates as a hybrid set.
- pub fn to_hybrid(&self) -> HybridIdxSet<T> {
- // This domain_size may be slightly larger than the one specified
- // upon creation, due to rounding up to a whole word. That's ok.
- let domain_size = self.words().len() * WORD_BITS;
-
- // Note: we currently don't bother trying to make a Sparse set.
- HybridIdxSet::Dense(self.to_owned(), domain_size)
- }
-
- /// Removes all elements
- pub fn clear(&mut self) {
- self.0.clear();
- }
-
- /// Sets all elements up to `domain_size`
- pub fn set_up_to(&mut self, domain_size: usize) {
- self.0.set_up_to(domain_size);
- }
-
- /// Removes `elem` from the set `self`; returns true iff this changed `self`.
- pub fn remove(&mut self, elem: &T) -> bool {
- self.0.remove(*elem)
- }
-
- /// Adds `elem` to the set `self`; returns true iff this changed `self`.
- pub fn add(&mut self, elem: &T) -> bool {
- self.0.insert(*elem)
- }
-
- /// Returns true iff set `self` contains `elem`.
- pub fn contains(&self, elem: &T) -> bool {
- self.0.contains(*elem)
- }
-
- pub fn words(&self) -> &[Word] {
- self.0.words()
- }
-
- pub fn words_mut(&mut self) -> &mut [Word] {
- self.0.words_mut()
- }
-
- /// Efficiently overwrite `self` with `other`. Panics if `self` and `other`
- /// don't have the same length.
- pub fn overwrite(&mut self, other: &IdxSet<T>) {
- self.words_mut().clone_from_slice(other.words());
- }
-
- /// Set `self = self | other` and return true if `self` changed
- /// (i.e., if new bits were added).
- pub fn union(&mut self, other: &impl UnionIntoIdxSet<T>) -> bool {
- other.union_into(self)
- }
-
- /// Set `self = self - other` and return true if `self` changed.
- /// (i.e., if any bits were removed).
- pub fn subtract(&mut self, other: &impl SubtractFromIdxSet<T>) -> bool {
- other.subtract_from(self)
- }
-
- /// Set `self = self & other` and return true if `self` changed.
- /// (i.e., if any bits were removed).
- pub fn intersect(&mut self, other: &IdxSet<T>) -> bool {
- bitwise(self.words_mut(), other.words(), &Intersect)
- }
-
- pub fn iter(&self) -> BitIter<T> {
- self.0.iter()
- }
-}
-
-impl<T: Idx> UnionIntoIdxSet<T> for IdxSet<T> {
- fn union_into(&self, other: &mut IdxSet<T>) -> bool {
- bitwise(other.words_mut(), self.words(), &Union)
- }
-}
-
-impl<T: Idx> SubtractFromIdxSet<T> for IdxSet<T> {
- fn subtract_from(&self, other: &mut IdxSet<T>) -> bool {
- bitwise(other.words_mut(), self.words(), &Subtract)
- }
-}
-
-const SPARSE_MAX: usize = 8;
-
-/// A sparse index set with a maximum of SPARSE_MAX elements. Used by
-/// HybridIdxSet; do not use directly.
-///
-/// The elements are stored as an unsorted vector with no duplicates.
-#[derive(Clone, Debug)]
-pub struct SparseIdxSet<T: Idx>(ArrayVec<[T; SPARSE_MAX]>);
-
-impl<T: Idx> SparseIdxSet<T> {
- fn new() -> Self {
- SparseIdxSet(ArrayVec::new())
- }
-
- fn len(&self) -> usize {
- self.0.len()
- }
-
- fn contains(&self, elem: &T) -> bool {
- self.0.contains(elem)
- }
-
- fn add(&mut self, elem: &T) -> bool {
- // Ensure there are no duplicates.
- if self.0.contains(elem) {
- false
- } else {
- self.0.push(*elem);
- true
- }
- }
-
- fn remove(&mut self, elem: &T) -> bool {
- if let Some(i) = self.0.iter().position(|e| e == elem) {
- // Swap the found element to the end, then pop it.
- let len = self.0.len();
- self.0.swap(i, len - 1);
- self.0.pop();
- true
- } else {
- false
- }
- }
-
- fn to_dense(&self, domain_size: usize) -> IdxSet<T> {
- let mut dense = IdxSet::new_empty(domain_size);
- for elem in self.0.iter() {
- dense.add(elem);
- }
- dense
- }
-
- fn iter(&self) -> slice::Iter<T> {
- self.0.iter()
- }
-}
-
-impl<T: Idx> UnionIntoIdxSet<T> for SparseIdxSet<T> {
- fn union_into(&self, other: &mut IdxSet<T>) -> bool {
- let mut changed = false;
- for elem in self.iter() {
- changed |= other.add(&elem);
- }
- changed
- }
-}
-
-impl<T: Idx> SubtractFromIdxSet<T> for SparseIdxSet<T> {
- fn subtract_from(&self, other: &mut IdxSet<T>) -> bool {
- let mut changed = false;
- for elem in self.iter() {
- changed |= other.remove(&elem);
- }
- changed
- }
-}
-
-/// Like IdxSet, but with a hybrid representation: sparse when there are few
-/// elements in the set, but dense when there are many. It's especially
-/// efficient for sets that typically have a small number of elements, but a
-/// large `domain_size`, and are cleared frequently.
-#[derive(Clone, Debug)]
-pub enum HybridIdxSet<T: Idx> {
- Sparse(SparseIdxSet<T>, usize),
- Dense(IdxSet<T>, usize),
-}
-
-impl<T: Idx> HybridIdxSet<T> {
- pub fn new_empty(domain_size: usize) -> Self {
- HybridIdxSet::Sparse(SparseIdxSet::new(), domain_size)
- }
-
- pub fn clear(&mut self) {
- let domain_size = match *self {
- HybridIdxSet::Sparse(_, size) => size,
- HybridIdxSet::Dense(_, size) => size,
- };
- *self = HybridIdxSet::new_empty(domain_size);
- }
-
- /// Returns true iff set `self` contains `elem`.
- pub fn contains(&self, elem: &T) -> bool {
- match self {
- HybridIdxSet::Sparse(sparse, _) => sparse.contains(elem),
- HybridIdxSet::Dense(dense, _) => dense.contains(elem),
- }
- }
-
- /// Adds `elem` to the set `self`.
- pub fn add(&mut self, elem: &T) -> bool {
- match self {
- HybridIdxSet::Sparse(sparse, _) if sparse.len() < SPARSE_MAX => {
- // The set is sparse and has space for `elem`.
- sparse.add(elem)
- }
- HybridIdxSet::Sparse(sparse, _) if sparse.contains(elem) => {
- // The set is sparse and does not have space for `elem`, but
- // that doesn't matter because `elem` is already present.
- false
- }
- HybridIdxSet::Sparse(_, _) => {
- // The set is sparse and full. Convert to a dense set.
- //
- // FIXME: This code is awful, but I can't work out how else to
- // appease the borrow checker.
- let dummy = HybridIdxSet::Sparse(SparseIdxSet::new(), 0);
- match mem::replace(self, dummy) {
- HybridIdxSet::Sparse(sparse, domain_size) => {
- let mut dense = sparse.to_dense(domain_size);
- let changed = dense.add(elem);
- assert!(changed);
- mem::replace(self, HybridIdxSet::Dense(dense, domain_size));
- changed
- }
- _ => panic!("impossible"),
- }
- }
-
- HybridIdxSet::Dense(dense, _) => dense.add(elem),
- }
- }
-
- /// Removes `elem` from the set `self`.
- pub fn remove(&mut self, elem: &T) -> bool {
- // Note: we currently don't bother going from Dense back to Sparse.
- match self {
- HybridIdxSet::Sparse(sparse, _) => sparse.remove(elem),
- HybridIdxSet::Dense(dense, _) => dense.remove(elem),
- }
- }
-
- /// Converts to a dense set, consuming itself in the process.
- pub fn to_dense(self) -> IdxSet<T> {
- match self {
- HybridIdxSet::Sparse(sparse, domain_size) => sparse.to_dense(domain_size),
- HybridIdxSet::Dense(dense, _) => dense,
- }
- }
-
- /// Iteration order is unspecified.
- pub fn iter(&self) -> HybridIter<T> {
- match self {
- HybridIdxSet::Sparse(sparse, _) => HybridIter::Sparse(sparse.iter()),
- HybridIdxSet::Dense(dense, _) => HybridIter::Dense(dense.iter()),
- }
- }
-}
-
-impl<T: Idx> UnionIntoIdxSet<T> for HybridIdxSet<T> {
- fn union_into(&self, other: &mut IdxSet<T>) -> bool {
- match self {
- HybridIdxSet::Sparse(sparse, _) => sparse.union_into(other),
- HybridIdxSet::Dense(dense, _) => dense.union_into(other),
- }
- }
-}
-
-impl<T: Idx> SubtractFromIdxSet<T> for HybridIdxSet<T> {
- fn subtract_from(&self, other: &mut IdxSet<T>) -> bool {
- match self {
- HybridIdxSet::Sparse(sparse, _) => sparse.subtract_from(other),
- HybridIdxSet::Dense(dense, _) => dense.subtract_from(other),
- }
- }
-}
-
-pub enum HybridIter<'a, T: Idx> {
- Sparse(slice::Iter<'a, T>),
- Dense(BitIter<'a, T>),
-}
-
-impl<'a, T: Idx> Iterator for HybridIter<'a, T> {
- type Item = T;
-
- fn next(&mut self) -> Option<T> {
- match self {
- HybridIter::Sparse(sparse) => sparse.next().map(|e| *e),
- HybridIter::Dense(dense) => dense.next(),
- }
- }
-}
pub use rustc_serialize::hex::ToHex;
pub mod svh;
-pub mod array_vec;
pub mod base_n;
-pub mod bitvec;
+pub mod bit_set;
pub mod const_cstr;
pub mod flock;
pub mod fx;
pub mod graph;
-pub mod indexed_set;
pub mod indexed_vec;
pub mod obligation_forest;
pub mod owning_ref;
}
-impl<I: ::indexed_vec::Idx, CTX> HashStable<CTX> for ::indexed_set::IdxSet<I>
+impl<I: ::indexed_vec::Idx, CTX> HashStable<CTX> for ::bit_set::BitSet<I>
{
fn hash_stable<W: StableHasherResult>(&self,
ctx: &mut CTX,
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use bitvec::BitMatrix;
+use bit_set::BitMatrix;
use fx::FxHashMap;
use sync::Lock;
use rustc_serialize::{Encodable, Encoder, Decodable, Decoder};
//
// This same algorithm is used in `parents` below.
- let mut candidates = closure.intersection(a.0, b.0); // (1)
+ let mut candidates = closure.intersect_rows(a.0, b.0); // (1)
pare_down(&mut candidates, closure); // (2)
candidates.reverse(); // (3a)
pare_down(&mut candidates, closure); // (3b)
// with a slight tweak. In the case where `a R a`, we remove
// that from the set of candidates.
let ancestors = self.with_closure(|closure| {
- let mut ancestors = closure.intersection(a.0, a.0);
+ let mut ancestors = closure.intersect_rows(a.0, a.0);
// Remove anything that can reach `a`. If this is a
// reflexive relation, this will include `a` itself.
changed = false;
for edge in &self.edges {
// add an edge from S -> T
- changed |= matrix.add(edge.source.0, edge.target.0);
+ changed |= matrix.insert(edge.source.0, edge.target.0);
// add all outgoing edges from T into S
- changed |= matrix.merge(edge.target.0, edge.source.0);
+ changed |= matrix.union_rows(edge.target.0, edge.source.0);
}
}
matrix
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use indexed_set::IdxSet;
+use bit_set::BitSet;
use indexed_vec::Idx;
use std::collections::VecDeque;
/// and also use a bit set to track occupancy.
pub struct WorkQueue<T: Idx> {
deque: VecDeque<T>,
- set: IdxSet<T>,
+ set: BitSet<T>,
}
impl<T: Idx> WorkQueue<T> {
pub fn with_all(len: usize) -> Self {
WorkQueue {
deque: (0..len).map(T::new).collect(),
- set: IdxSet::new_filled(len),
+ set: BitSet::new_filled(len),
}
}
pub fn with_none(len: usize) -> Self {
WorkQueue {
deque: VecDeque::with_capacity(len),
- set: IdxSet::new_empty(len),
+ set: BitSet::new_empty(len),
}
}
/// Attempt to enqueue `element` in the work queue. Returns false if it was already present.
#[inline]
pub fn insert(&mut self, element: T) -> bool {
- if self.set.add(&element) {
+ if self.set.insert(element) {
self.deque.push_back(element);
true
} else {
#[inline]
pub fn pop(&mut self) -> Option<T> {
if let Some(element) = self.deque.pop_front() {
- self.set.remove(&element);
+ self.set.remove(element);
Some(element)
} else {
None
pub fn create_region_hierarchy(&mut self, rh: &RH,
parent: (region::Scope, region::ScopeDepth)) {
- let me = region::Scope::Node(rh.id);
+ let me = region::Scope { id: rh.id, data: region::ScopeData::Node };
self.region_scope_tree.record_scope_parent(me, Some(parent));
for child_rh in rh.sub {
self.create_region_hierarchy(child_rh, (me, parent.1 + 1));
// creates a region hierarchy where 1 is root, 10 and 11 are
// children of 1, etc
- let dscope = region::Scope::Destruction(hir::ItemLocalId(1));
+ let dscope = region::Scope {
+ id: hir::ItemLocalId(1),
+ data: region::ScopeData::Destruction
+ };
self.region_scope_tree.record_scope_parent(dscope, None);
self.create_region_hierarchy(&RH {
id: hir::ItemLocalId(1),
}
pub fn t_rptr_scope(&self, id: u32) -> Ty<'tcx> {
- let r = ty::ReScope(region::Scope::Node(hir::ItemLocalId(id)));
+ let r = ty::ReScope(region::Scope {
+ id: hir::ItemLocalId(id),
+ data: region::ScopeData::Node
+ });
self.infcx.tcx.mk_imm_ref(self.infcx.tcx.mk_region(r), self.tcx().types.isize)
}
crate-type = ["dylib"]
[dependencies]
+log = "0.4"
serialize = { path = "../libserialize" }
syntax_pos = { path = "../libsyntax_pos" }
rustc_data_structures = { path = "../librustc_data_structures" }
/// inline it will only show the text message and not the text.
///
/// See `CodeSuggestion` for more information.
+ #[deprecated(note = "Use `span_suggestion_short_with_applicability`")]
pub fn span_suggestion_short(&mut self, sp: Span, msg: &str, suggestion: String) -> &mut Self {
self.suggestions.push(CodeSuggestion {
substitutions: vec![Substitution {
/// * may contain a name of a function, variable or type, but not whole expressions
///
/// See `CodeSuggestion` for more information.
+ #[deprecated(note = "Use `span_suggestion_with_applicability`")]
pub fn span_suggestion(&mut self, sp: Span, msg: &str, suggestion: String) -> &mut Self {
self.suggestions.push(CodeSuggestion {
substitutions: vec![Substitution {
self
}
- pub fn multipart_suggestion(
+ pub fn multipart_suggestion_with_applicability(
&mut self,
msg: &str,
suggestion: Vec<(Span, String)>,
+ applicability: Applicability,
) -> &mut Self {
self.suggestions.push(CodeSuggestion {
substitutions: vec![Substitution {
}],
msg: msg.to_owned(),
show_code_when_inline: true,
- applicability: Applicability::Unspecified,
+ applicability,
});
self
}
+ #[deprecated(note = "Use `multipart_suggestion_with_applicability`")]
+ pub fn multipart_suggestion(
+ &mut self,
+ msg: &str,
+ suggestion: Vec<(Span, String)>,
+ ) -> &mut Self {
+ self.multipart_suggestion_with_applicability(
+ msg,
+ suggestion,
+ Applicability::Unspecified,
+ )
+ }
+
/// Prints out a message with multiple suggested edits of the code.
+ #[deprecated(note = "Use `span_suggestions_with_applicability`")]
pub fn span_suggestions(&mut self, sp: Span, msg: &str, suggestions: Vec<String>) -> &mut Self {
self.suggestions.push(CodeSuggestion {
substitutions: suggestions.into_iter().map(|snippet| Substitution {
use syntax_pos::{MultiSpan, Span};
/// Used for emitting structured error messages and other diagnostic information.
+///
+/// If there is some state in a downstream crate you would like to
+/// access in the methods of `DiagnosticBuilder` here, consider
+/// extending `HandlerFlags`, accessed via `self.handler.flags`.
#[must_use]
#[derive(Clone)]
pub struct DiagnosticBuilder<'a> {
/// it easy to declare such methods on the builder.
macro_rules! forward {
// Forward pattern for &self -> &Self
- (pub fn $n:ident(&self, $($name:ident: $ty:ty),*) -> &Self) => {
+ (pub fn $n:ident(&self, $($name:ident: $ty:ty),* $(,)*) -> &Self) => {
pub fn $n(&self, $($name: $ty),*) -> &Self {
+ #[allow(deprecated)]
self.diagnostic.$n($($name),*);
self
}
};
// Forward pattern for &mut self -> &mut Self
- (pub fn $n:ident(&mut self, $($name:ident: $ty:ty),*) -> &mut Self) => {
+ (pub fn $n:ident(&mut self, $($name:ident: $ty:ty),* $(,)*) -> &mut Self) => {
pub fn $n(&mut self, $($name: $ty),*) -> &mut Self {
+ #[allow(deprecated)]
self.diagnostic.$n($($name),*);
self
}
// Forward pattern for &mut self -> &mut Self, with S: Into<MultiSpan>
// type parameter. No obvious way to make this more generic.
- (pub fn $n:ident<S: Into<MultiSpan>>(&mut self, $($name:ident: $ty:ty),*) -> &mut Self) => {
+ (pub fn $n:ident<S: Into<MultiSpan>>(
+ &mut self,
+ $($name:ident: $ty:ty),*
+ $(,)*) -> &mut Self) => {
pub fn $n<S: Into<MultiSpan>>(&mut self, $($name: $ty),*) -> &mut Self {
+ #[allow(deprecated)]
self.diagnostic.$n($($name),*);
self
}
self.cancel();
}
- /// Buffers the diagnostic for later emission.
- pub fn buffer(self, buffered_diagnostics: &mut Vec<Diagnostic>) {
+ /// Buffers the diagnostic for later emission, unless handler
+ /// has disabled such buffering.
+ pub fn buffer(mut self, buffered_diagnostics: &mut Vec<Diagnostic>) {
+ if self.handler.flags.dont_buffer_diagnostics || self.handler.flags.treat_err_as_bug {
+ self.emit();
+ return;
+ }
+
// We need to use `ptr::read` because `DiagnosticBuilder`
// implements `Drop`.
let diagnostic;
diagnostic = ::std::ptr::read(&self.diagnostic);
::std::mem::forget(self);
};
+ // Logging here is useful to help track down where in logs an error was
+ // actually emitted.
+ debug!("buffer: diagnostic={:?}", diagnostic);
buffered_diagnostics.push(diagnostic);
}
forward!(pub fn note_expected_found(&mut self,
label: &dyn fmt::Display,
expected: DiagnosticStyledString,
- found: DiagnosticStyledString)
- -> &mut Self);
+ found: DiagnosticStyledString,
+ ) -> &mut Self);
forward!(pub fn note_expected_found_extra(&mut self,
label: &dyn fmt::Display,
expected: DiagnosticStyledString,
found: DiagnosticStyledString,
expected_extra: &dyn fmt::Display,
- found_extra: &dyn fmt::Display)
- -> &mut Self);
+ found_extra: &dyn fmt::Display,
+ ) -> &mut Self);
forward!(pub fn note(&mut self, msg: &str) -> &mut Self);
forward!(pub fn span_note<S: Into<MultiSpan>>(&mut self,
sp: S,
- msg: &str)
- -> &mut Self);
+ msg: &str,
+ ) -> &mut Self);
forward!(pub fn warn(&mut self, msg: &str) -> &mut Self);
forward!(pub fn span_warn<S: Into<MultiSpan>>(&mut self, sp: S, msg: &str) -> &mut Self);
forward!(pub fn help(&mut self , msg: &str) -> &mut Self);
forward!(pub fn span_help<S: Into<MultiSpan>>(&mut self,
sp: S,
- msg: &str)
- -> &mut Self);
- forward!(pub fn span_suggestion_short(&mut self,
- sp: Span,
- msg: &str,
- suggestion: String)
- -> &mut Self);
+ msg: &str,
+ ) -> &mut Self);
+
+ #[deprecated(note = "Use `span_suggestion_short_with_applicability`")]
+ forward!(pub fn span_suggestion_short(
+ &mut self,
+ sp: Span,
+ msg: &str,
+ suggestion: String,
+ ) -> &mut Self);
+
+ #[deprecated(note = "Use `multipart_suggestion_with_applicability`")]
forward!(pub fn multipart_suggestion(
&mut self,
msg: &str,
- suggestion: Vec<(Span, String)>
+ suggestion: Vec<(Span, String)>,
) -> &mut Self);
+
+ #[deprecated(note = "Use `span_suggestion_with_applicability`")]
forward!(pub fn span_suggestion(&mut self,
sp: Span,
msg: &str,
- suggestion: String)
- -> &mut Self);
+ suggestion: String,
+ ) -> &mut Self);
+
+ #[deprecated(note = "Use `span_suggestions_with_applicability`")]
forward!(pub fn span_suggestions(&mut self,
sp: Span,
msg: &str,
- suggestions: Vec<String>)
- -> &mut Self);
+ suggestions: Vec<String>,
+ ) -> &mut Self);
+
+ pub fn multipart_suggestion_with_applicability(&mut self,
+ msg: &str,
+ suggestion: Vec<(Span, String)>,
+ applicability: Applicability,
+ ) -> &mut Self {
+ if !self.allow_suggestions {
+ return self
+ }
+ self.diagnostic.multipart_suggestion_with_applicability(
+ msg,
+ suggestion,
+ applicability,
+ );
+ self
+ }
+
pub fn span_suggestion_with_applicability(&mut self,
sp: Span,
msg: &str,
extern crate termcolor;
#[cfg(unix)]
extern crate libc;
+#[macro_use]
+extern crate log;
extern crate rustc_data_structures;
extern crate serialize as rustc_serialize;
extern crate syntax_pos;
#[derive(Default)]
pub struct HandlerFlags {
+ /// If false, warning-level lints are suppressed.
+ /// (rustc: see `--allow warnings` and `--cap-lints`)
pub can_emit_warnings: bool,
+ /// If true, error-level diagnostics are upgraded to bug-level.
+ /// (rustc: see `-Z treat-err-as-bug`)
pub treat_err_as_bug: bool,
+ /// If true, immediately emit diagnostics that would otherwise be buffered.
+ /// (rustc: see `-Z dont-buffer-diagnostics` and `-Z treat-err-as-bug`)
+ pub dont_buffer_diagnostics: bool,
+ /// If true, immediately print bugs registered with `delay_span_bug`.
+ /// (rustc: see `-Z report-delayed-bugs`)
pub report_delayed_bugs: bool,
+ /// show macro backtraces even for non-local macros.
+ /// (rustc: see `-Z external-macro-backtrace`)
pub external_macro_backtrace: bool,
}
fn check_attribute(&mut self, cx: &EarlyContext, attr: &ast::Attribute) {
for &&(n, _, ref g) in &self.depr_attrs {
if attr.name() == n {
- if let &AttributeGate::Gated(Stability::Deprecated(link),
+ if let &AttributeGate::Gated(Stability::Deprecated(link, suggestion),
ref name,
ref reason,
_) = g {
let mut err = cx.struct_span_lint(DEPRECATED, attr.span, &msg);
err.span_suggestion_short_with_applicability(
attr.span,
- "remove this attribute",
+ suggestion.unwrap_or("remove this attribute"),
String::new(),
Applicability::MachineApplicable
);
fn is_camel_case(name: ast::Name) -> bool {
let name = name.as_str();
+ let name = name.trim_matches('_');
if name.is_empty() {
return true;
}
- let name = name.trim_matches('_');
// start with a non-lowercase letter rather than non-uppercase
// ones (some scripts don't have a concept of upper/lowercase)
Loaded(Library),
}
+enum LoadError<'a> {
+ LocatorError(locator::Context<'a>),
+}
+
+impl<'a> LoadError<'a> {
+ fn report(self) -> ! {
+ match self {
+ LoadError::LocatorError(mut locate_ctxt) => locate_ctxt.report_errs(),
+ }
+ }
+}
+
impl<'a> CrateLoader<'a> {
pub fn new(sess: &'a Session, cstore: &'a CStore, local_crate_name: &str) -> Self {
CrateLoader {
// from the strings on the command line.
let source = &self.cstore.get_crate_data(cnum).source;
if let Some(locs) = self.sess.opts.externs.get(&*name.as_str()) {
- let found = locs.iter().any(|l| {
+ // Only use `--extern crate_name=path` here, not `--extern crate_name`.
+ let found = locs.iter().filter_map(|l| l.as_ref()).any(|l| {
let l = fs::canonicalize(l).ok();
source.dylib.as_ref().map(|p| &p.0) == l.as_ref() ||
source.rlib.as_ref().map(|p| &p.0) == l.as_ref()
(cnum, cmeta)
}
- fn resolve_crate(&mut self,
- root: &Option<CratePaths>,
- ident: Symbol,
- name: Symbol,
- hash: Option<&Svh>,
- extra_filename: Option<&str>,
- span: Span,
- path_kind: PathKind,
- mut dep_kind: DepKind)
- -> (CrateNum, Lrc<cstore::CrateMetadata>) {
+ fn resolve_crate<'b>(
+ &'b mut self,
+ root: &'b Option<CratePaths>,
+ ident: Symbol,
+ name: Symbol,
+ hash: Option<&'b Svh>,
+ extra_filename: Option<&'b str>,
+ span: Span,
+ path_kind: PathKind,
+ mut dep_kind: DepKind,
+ ) -> Result<(CrateNum, Lrc<cstore::CrateMetadata>), LoadError<'b>> {
info!("resolving crate `extern crate {} as {}`", name, ident);
let result = if let Some(cnum) = self.existing_match(name, hash, path_kind) {
LoadResult::Previous(cnum)
};
self.load(&mut proc_macro_locator)
- }).unwrap_or_else(|| locate_ctxt.report_errs())
+ }).ok_or_else(move || LoadError::LocatorError(locate_ctxt))?
};
match result {
data.dep_kind.with_lock(|data_dep_kind| {
*data_dep_kind = cmp::max(*data_dep_kind, dep_kind);
});
- (cnum, data)
+ Ok((cnum, data))
}
LoadResult::Loaded(library) => {
- self.register_crate(root, ident, span, library, dep_kind)
+ Ok(self.register_crate(root, ident, span, library, dep_kind))
}
}
}
let (local_cnum, ..) = self.resolve_crate(
root, dep.name, dep.name, Some(&dep.hash), Some(&dep.extra_filename), span,
PathKind::Dependency, dep_kind,
- );
+ ).unwrap_or_else(|err| err.report());
local_cnum
})).collect()
}
let dep_kind = DepKind::Implicit;
let (cnum, data) =
- self.resolve_crate(&None, name, name, None, None, DUMMY_SP, PathKind::Crate, dep_kind);
+ self.resolve_crate(&None, name, name, None, None, DUMMY_SP, PathKind::Crate, dep_kind)
+ .unwrap_or_else(|err| err.report());
// Sanity check the loaded crate to ensure it is indeed a panic runtime
// and the panic strategy is indeed what we thought it was.
let dep_kind = DepKind::Explicit;
let (_, data) =
self.resolve_crate(&None, symbol, symbol, None, None, DUMMY_SP,
- PathKind::Crate, dep_kind);
+ PathKind::Crate, dep_kind)
+ .unwrap_or_else(|err| err.report());
// Sanity check the loaded crate to ensure it is indeed a sanitizer runtime
if !data.root.sanitizer_runtime {
let dep_kind = DepKind::Implicit;
let (_, data) =
self.resolve_crate(&None, symbol, symbol, None, None, DUMMY_SP,
- PathKind::Crate, dep_kind);
+ PathKind::Crate, dep_kind)
+ .unwrap_or_else(|err| err.report());
// Sanity check the loaded crate to ensure it is indeed a profiler runtime
if !data.root.profiler_runtime {
None,
DUMMY_SP,
PathKind::Crate,
- DepKind::Implicit);
+ DepKind::Implicit)
+ .unwrap_or_else(|err| err.report());
self.sess.injected_allocator.set(Some(cnum));
data
})
let (cnum, ..) = self.resolve_crate(
&None, item.ident.name, orig_name, None, None,
item.span, PathKind::Crate, dep_kind,
- );
+ ).unwrap_or_else(|err| err.report());
let def_id = definitions.opt_local_def_id(item.id).unwrap();
let path_len = definitions.def_path(def_id.index).data.len();
) -> CrateNum {
let cnum = self.resolve_crate(
&None, name, name, None, None, span, PathKind::Crate, DepKind::Explicit
- ).0;
+ ).unwrap_or_else(|err| err.report()).0;
self.update_extern_crate(
cnum,
cnum
}
+
+ pub fn maybe_process_path_extern(
+ &mut self,
+ name: Symbol,
+ span: Span,
+ ) -> Option<CrateNum> {
+ let cnum = self.resolve_crate(
+ &None, name, name, None, None, span, PathKind::Crate, DepKind::Explicit
+ ).ok()?.0;
+
+ self.update_extern_crate(
+ cnum,
+ ExternCrate {
+ src: ExternCrateSource::Path,
+ span,
+ // to have the least priority in `update_extern_crate`
+ path_len: usize::max_value(),
+ direct: true,
+ },
+ &mut FxHashSet(),
+ );
+
+ Some(cnum)
+ }
}
use syntax::parse::source_file_to_stream;
use syntax::symbol::Symbol;
use syntax_pos::{Span, NO_EXPANSION, FileName};
-use rustc_data_structures::indexed_set::IdxSet;
+use rustc_data_structures::bit_set::BitSet;
use rustc::hir;
macro_rules! provide {
mir
}
mir_const_qualif => {
- (cdata.mir_const_qualif(def_id.index), Lrc::new(IdxSet::new_empty(0)))
+ (cdata.mir_const_qualif(def_id.index), Lrc::new(BitSet::new_empty(0)))
}
fn_sig => { cdata.fn_sig(def_id.index, tcx) }
inherent_impls => { Lrc::new(cdata.get_inherent_implementations_for_type(def_id.index)) }
if self.hash.is_none() {
self.should_match_name = false;
if let Some(s) = self.sess.opts.externs.get(&self.crate_name.as_str()) {
- return self.find_commandline_library(s.iter());
+ // Only use `--extern crate_name=path` here, not `--extern crate_name`.
+ if s.iter().any(|l| l.is_some()) {
+ return self.find_commandline_library(
+ s.iter().filter_map(|l| l.as_ref()),
+ );
+ }
}
self.should_match_name = true;
}
}
}
Err(err) => {
- info!("no metadata found: {}", err);
+ warn!("no metadata found: {}", err);
continue;
}
};
use rustc::ty::{Region, TyCtxt};
use rustc::util::nodemap::{FxHashMap, FxHashSet};
use rustc_data_structures::indexed_vec::IndexVec;
-use rustc_data_structures::bitvec::BitArray;
+use rustc_data_structures::bit_set::BitSet;
use std::fmt;
use std::hash::Hash;
use std::ops::Index;
crate enum LocalsStateAtExit {
AllAreInvalidated,
- SomeAreInvalidated { has_storage_dead_or_moved: BitArray<Local> }
+ SomeAreInvalidated { has_storage_dead_or_moved: BitSet<Local> }
}
impl LocalsStateAtExit {
mir: &Mir<'tcx>,
move_data: &MoveData<'tcx>
) -> Self {
- struct HasStorageDead(BitArray<Local>);
+ struct HasStorageDead(BitSet<Local>);
impl<'tcx> Visitor<'tcx> for HasStorageDead {
fn visit_local(&mut self, local: &Local, ctx: PlaceContext<'tcx>, _: Location) {
if locals_are_invalidated_at_exit {
LocalsStateAtExit::AllAreInvalidated
} else {
- let mut has_storage_dead = HasStorageDead(BitArray::new(mir.local_decls.len()));
+ let mut has_storage_dead = HasStorageDead(BitSet::new_empty(mir.local_decls.len()));
has_storage_dead.visit_mir(mir);
let mut has_storage_dead_or_moved = has_storage_dead.0;
for move_out in &move_data.moves {
use rustc::ty;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::sync::Lrc;
-use rustc_errors::DiagnosticBuilder;
+use rustc_errors::{Applicability, DiagnosticBuilder};
use syntax_pos::Span;
use super::borrow_set::BorrowData;
(place, span): (&Place<'tcx>, Span),
mpi: MovePathIndex,
) {
+ debug!(
+ "report_use_of_moved_or_uninitialized: context={:?} desired_action={:?} place={:?} \
+ span={:?} mpi={:?}",
+ context, desired_action, place, span, mpi
+ );
+
let use_spans = self
.move_spans(place, context.loc)
.or_else(|| self.borrow_spans(span, context.loc));
if mois.is_empty() {
let root_place = self.prefixes(&place, PrefixSet::All).last().unwrap();
- if self.moved_error_reported.contains(&root_place.clone()) {
+ if self.uninitialized_error_reported.contains(&root_place.clone()) {
debug!(
"report_use_of_moved_or_uninitialized place: error about {:?} suppressed",
root_place
return;
}
- self.moved_error_reported.insert(root_place.clone());
+ self.uninitialized_error_reported.insert(root_place.clone());
let item_msg = match self.describe_place_with_options(place, IncludingDowncast(true)) {
Some(name) => format!("`{}`", name),
err.buffer(&mut self.errors_buffer);
} else {
+ if let Some((reported_place, _)) = self.move_error_reported.get(&mois) {
+ if self.prefixes(&reported_place, PrefixSet::All).any(|p| p == place) {
+ debug!("report_use_of_moved_or_uninitialized place: error suppressed \
+ mois={:?}", mois);
+ return;
+ }
+ }
+
let msg = ""; //FIXME: add "partially " or "collaterally "
let mut err = self.tcx.cannot_act_on_moved_value(
}
}
- err.buffer(&mut self.errors_buffer);
+ if let Some((_, mut old_err)) = self.move_error_reported.insert(
+ mois,
+ (place.clone(), err)
+ ) {
+ // Cancel the old error so it doesn't ICE.
+ old_err.cancel();
+ }
}
}
// created by `StorageDead` and at the beginning
// of a function.
} else {
+ // If we are found a use of a.b.c which was in error, then we want to look for
+ // moves not only of a.b.c but also a.b and a.
+ //
+ // Note that the moves data already includes "parent" paths, so we don't have to
+ // worry about the other case: that is, if there is a move of a.b.c, it is already
+ // marked as a move of a.b and a as well, so we will generate the correct errors
+ // there.
+ let mut mpis = vec![mpi];
+ let move_paths = &self.move_data.move_paths;
+ mpis.extend(move_paths[mpi].parents(move_paths));
+
for moi in &self.move_data.loc_map[l] {
debug!("report_use_of_moved_or_uninitialized: moi={:?}", moi);
- if self.move_data.moves[*moi].path == mpi {
+ if mpis.contains(&self.move_data.moves[*moi].path) {
debug!("report_use_of_moved_or_uninitialized: found");
result.push(*moi);
if let Some(decl) = local_decl {
if let Some(name) = decl.name {
if decl.can_be_made_mutable() {
- err.span_label(
+ err.span_suggestion_with_applicability(
decl.source_info.span,
- format!("consider changing this to `mut {}`", name),
+ "make this binding mutable",
+ format!("mut {}", name),
+ Applicability::MachineApplicable,
);
}
}
use rustc::mir::{BasicBlock, Location};
use rustc::ty::RegionVid;
-use rustc_data_structures::bitvec::BitIter;
+use rustc_data_structures::bit_set::BitIter;
use borrow_check::location::LocationIndex;
use rustc::ty::{self, ParamEnv, TyCtxt, Ty};
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, Level};
-use rustc_data_structures::graph::dominators::Dominators;
+use rustc_data_structures::bit_set::BitSet;
use rustc_data_structures::fx::FxHashSet;
-use rustc_data_structures::indexed_set::IdxSet;
+use rustc_data_structures::graph::dominators::Dominators;
use rustc_data_structures::indexed_vec::Idx;
use smallvec::SmallVec;
use std::rc::Rc;
+use std::collections::BTreeMap;
use syntax_pos::Span;
use dataflow::indexes::BorrowIndex;
use dataflow::move_paths::{HasMoveData, LookupResult, MoveData, MoveError, MovePathIndex};
+use dataflow::move_paths::indexes::MoveOutIndex;
use dataflow::Borrows;
use dataflow::DataflowResultsConsumer;
use dataflow::FlowAtLocation;
_ => Some(tcx.hir.body_owned_by(id)),
};
- let dead_unwinds = IdxSet::new_empty(mir.basic_blocks().len());
+ let dead_unwinds = BitSet::new_empty(mir.basic_blocks().len());
let mut flow_inits = FlowAtLocation::new(do_dataflow(
tcx,
mir,
MaybeInitializedPlaces::new(tcx, mir, &mdpe),
|bd, i| DebugFormatted::new(&bd.move_data().move_paths[i]),
));
- let flow_uninits = FlowAtLocation::new(do_dataflow(
- tcx,
- mir,
- id,
- &attributes,
- &dead_unwinds,
- MaybeUninitializedPlaces::new(tcx, mir, &mdpe),
- |bd, i| DebugFormatted::new(&bd.move_data().move_paths[i]),
- ));
- let flow_ever_inits = FlowAtLocation::new(do_dataflow(
- tcx,
- mir,
- id,
- &attributes,
- &dead_unwinds,
- EverInitializedPlaces::new(tcx, mir, &mdpe),
- |bd, i| DebugFormatted::new(&bd.move_data().inits[i]),
- ));
let locals_are_invalidated_at_exit = match tcx.hir.body_owner_kind(id) {
hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => false,
&borrow_set,
&mut errors_buffer,
);
+
+ // The various `flow_*` structures can be large. We drop `flow_inits` here
+ // so it doesn't overlap with the others below. This reduces peak memory
+ // usage significantly on some benchmarks.
+ drop(flow_inits);
+
let regioncx = Rc::new(regioncx);
let flow_borrows = FlowAtLocation::new(do_dataflow(
Borrows::new(tcx, mir, regioncx.clone(), def_id, body_id, &borrow_set),
|rs, i| DebugFormatted::new(&rs.location(i)),
));
+ let flow_uninits = FlowAtLocation::new(do_dataflow(
+ tcx,
+ mir,
+ id,
+ &attributes,
+ &dead_unwinds,
+ MaybeUninitializedPlaces::new(tcx, mir, &mdpe),
+ |bd, i| DebugFormatted::new(&bd.move_data().move_paths[i]),
+ ));
+ let flow_ever_inits = FlowAtLocation::new(do_dataflow(
+ tcx,
+ mir,
+ id,
+ &attributes,
+ &dead_unwinds,
+ EverInitializedPlaces::new(tcx, mir, &mdpe),
+ |bd, i| DebugFormatted::new(&bd.move_data().inits[i]),
+ ));
let movable_generator = match tcx.hir.get(id) {
Node::Expr(&hir::Expr {
locals_are_invalidated_at_exit,
access_place_error_reported: FxHashSet(),
reservation_error_reported: FxHashSet(),
- moved_error_reported: FxHashSet(),
+ move_error_reported: BTreeMap::new(),
+ uninitialized_error_reported: FxHashSet(),
errors_buffer,
nonlexical_regioncx: regioncx,
used_mut: FxHashSet(),
}
}
+ // Buffer any move errors that we collected and de-duplicated.
+ for (_, (_, diag)) in mbcx.move_error_reported {
+ diag.buffer(&mut mbcx.errors_buffer);
+ }
+
if mbcx.errors_buffer.len() > 0 {
mbcx.errors_buffer.sort_by_key(|diag| diag.span.primary_span());
/// but it is currently inconvenient to track down the BorrowIndex
/// at the time we detect and report a reservation error.
reservation_error_reported: FxHashSet<Place<'tcx>>,
- /// This field keeps track of errors reported in the checking of moved variables,
+ /// This field keeps track of move errors that are to be reported for given move indicies.
+ ///
+ /// There are situations where many errors can be reported for a single move out (see #53807)
+ /// and we want only the best of those errors.
+ ///
+ /// The `report_use_of_moved_or_uninitialized` function checks this map and replaces the
+ /// diagnostic (if there is one) if the `Place` of the error being reported is a prefix of the
+ /// `Place` of the previous most diagnostic. This happens instead of buffering the error. Once
+ /// all move errors have been reported, any diagnostics in this map are added to the buffer
+ /// to be emitted.
+ ///
+ /// `BTreeMap` is used to preserve the order of insertions when iterating. This is necessary
+ /// when errors in the map are being re-added to the error buffer so that errors with the
+ /// same primary span come out in a consistent order.
+ move_error_reported: BTreeMap<Vec<MoveOutIndex>, (Place<'tcx>, DiagnosticBuilder<'cx>)>,
+ /// This field keeps track of errors reported in the checking of uninitialized variables,
/// so that we don't report seemingly duplicate errors.
- moved_error_reported: FxHashSet<Place<'tcx>>,
+ uninitialized_error_reported: FxHashSet<Place<'tcx>>,
/// Errors to be reported buffer
errors_buffer: Vec<Diagnostic>,
/// This field keeps track of all the local variables that are declared mut and are mutated.
No,
}
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Debug)]
enum InitializationRequiringAction {
Update,
Borrow,
// Check if any of the initializiations of `local` have happened yet:
let mpi = self.move_data.rev_lookup.find_local(local);
let init_indices = &self.move_data.init_path_map[mpi];
- let first_init_index = init_indices.iter().find(|ii| flow_state.ever_inits.contains(ii));
+ let first_init_index = init_indices.iter().find(|&ii| flow_state.ever_inits.contains(*ii));
if let Some(&init_index) = first_init_index {
// And, if so, report an error.
let init = &self.move_data.inits[init_index];
debug!("check_if_full_path_is_moved place: {:?}", place_span.0);
match self.move_path_closest_to(place_span.0) {
Ok(mpi) => {
- if maybe_uninits.contains(&mpi) {
+ if maybe_uninits.contains(mpi) {
self.report_use_of_moved_or_uninitialized(
context,
desired_action,
// keyword, since the mutation may be a possible reassignment.
let mpi = self.move_data.rev_lookup.find_local(*local);
let ii = &self.move_data.init_path_map[mpi];
- for index in ii {
+ for &index in ii {
if flow_state.ever_inits.contains(index) {
self.used_mut.insert(*local);
break;
use core::unicode::property::Pattern_White_Space;
use rustc::mir::*;
use rustc::ty;
-use rustc_errors::DiagnosticBuilder;
+use rustc_errors::{DiagnosticBuilder,Applicability};
use syntax_pos::Span;
use borrow_check::MirBorrowckCtxt;
// expressions `a[b]`, which roughly desugar to
// `*Index::index(&a, b)` or
// `*IndexMut::index_mut(&mut a, b)`.
- err.span_suggestion(
+ err.span_suggestion_with_applicability(
span,
"consider removing the `*`",
snippet[1..].to_owned(),
+ Applicability::Unspecified,
);
} else {
- err.span_suggestion(
+ err.span_suggestion_with_applicability(
span,
"consider borrowing here",
format!("&{}", snippet),
+ Applicability::Unspecified,
);
}
suggestions.sort_unstable_by_key(|&(span, _, _)| span);
suggestions.dedup_by_key(|&mut (span, _, _)| span);
for (span, to_remove, suggestion) in suggestions {
- err.span_suggestion(
+ err.span_suggestion_with_applicability(
span,
&format!("consider removing the `{}`", to_remove),
- suggestion
+ suggestion,
+ Applicability::MachineApplicable,
);
}
}
use util::borrowck_errors::{BorrowckErrors, Origin};
use util::collect_writes::FindAssignments;
use util::suggest_ref_mut;
+use rustc_errors::Applicability;
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub(super) enum AccessKind {
assert_eq!(local_decl.mutability, Mutability::Not);
err.span_label(span, format!("cannot {ACT}", ACT = act));
- err.span_suggestion(
+ err.span_suggestion_with_applicability(
local_decl.source_info.span,
"consider changing this to be mutable",
format!("mut {}", local_decl.name.unwrap()),
+ Applicability::MachineApplicable,
);
}
_,
) = pat.node
{
- err.span_suggestion(
+ err.span_suggestion_with_applicability(
upvar_ident.span,
"consider changing this to be mutable",
format!("mut {}", upvar_ident.name),
+ Applicability::MachineApplicable,
);
}
}
};
if let Some((err_help_span, suggested_code)) = suggestion {
- err.span_suggestion(
+ err.span_suggestion_with_applicability(
err_help_span,
&format!("consider changing this to be a mutable {}", pointer_desc),
suggested_code,
+ Applicability::MachineApplicable,
);
}
use rustc::infer::error_reporting::nice_region_error::NiceRegionError;
use rustc::infer::InferCtxt;
use rustc::mir::{self, Location, Mir, Place, Rvalue, StatementKind, TerminatorKind};
-use rustc::ty::{TyCtxt, RegionVid};
+use rustc::ty::{self, TyCtxt, RegionVid};
use rustc_data_structures::indexed_vec::IndexVec;
-use rustc_errors::Diagnostic;
+use rustc_errors::{Diagnostic, DiagnosticBuilder};
use std::collections::VecDeque;
use std::fmt;
+use syntax::symbol::keywords;
use syntax_pos::Span;
mod region_name;
mod var_name;
+use self::region_name::RegionName;
+
/// Constraints that are considered interesting can be categorized to
/// determine why they are interesting. Order of variants indicates
/// sort order of the category, thereby influencing diagnostic output.
self.universal_regions.is_local_free_region(fr),
self.universal_regions.is_local_free_region(outlived_fr),
);
+
debug!("report_error: fr_is_local={:?} outlived_fr_is_local={:?} category={:?}",
fr_is_local, outlived_fr_is_local, category);
-
match (category, fr_is_local, outlived_fr_is_local) {
(ConstraintCategory::Assignment, true, false) |
(ConstraintCategory::CallArgument, true, false) =>
},
}
+ self.add_static_impl_trait_suggestion(
+ infcx, &mut diag, fr, fr_name, outlived_fr,
+ );
+
diag.buffer(errors_buffer);
}
+ fn add_static_impl_trait_suggestion(
+ &self,
+ infcx: &InferCtxt<'_, '_, 'tcx>,
+ diag: &mut DiagnosticBuilder<'_>,
+ fr: RegionVid,
+ // We need to pass `fr_name` - computing it again will label it twice.
+ fr_name: RegionName,
+ outlived_fr: RegionVid,
+ ) {
+ if let (
+ Some(f),
+ Some(ty::RegionKind::ReStatic)
+ ) = (self.to_error_region(fr), self.to_error_region(outlived_fr)) {
+ if let Some(ty::TyS {
+ sty: ty::TyKind::Opaque(did, substs),
+ ..
+ }) = infcx.tcx.is_suitable_region(f)
+ .map(|r| r.def_id)
+ .map(|id| infcx.tcx.return_type_impl_trait(id))
+ .unwrap_or(None)
+ {
+ // Check whether or not the impl trait return type is intended to capture
+ // data with the static lifetime.
+ //
+ // eg. check for `impl Trait + 'static` instead of `impl Trait`.
+ let has_static_predicate = {
+ let predicates_of = infcx.tcx.predicates_of(*did);
+ let bounds = predicates_of.instantiate(infcx.tcx, substs);
+
+ let mut found = false;
+ for predicate in bounds.predicates {
+ if let ty::Predicate::TypeOutlives(binder) = predicate {
+ if let ty::OutlivesPredicate(
+ _,
+ ty::RegionKind::ReStatic
+ ) = binder.skip_binder() {
+ found = true;
+ break;
+ }
+ }
+ }
+
+ found
+ };
+
+ debug!("add_static_impl_trait_suggestion: has_static_predicate={:?}",
+ has_static_predicate);
+ let static_str = keywords::StaticLifetime.name();
+ // If there is a static predicate, then the only sensible suggestion is to replace
+ // fr with `'static`.
+ if has_static_predicate {
+ diag.help(
+ &format!(
+ "consider replacing `{}` with `{}`",
+ fr_name, static_str,
+ ),
+ );
+ } else {
+ // Otherwise, we should suggest adding a constraint on the return type.
+ let span = infcx.tcx.def_span(*did);
+ if let Ok(snippet) = infcx.tcx.sess.source_map().span_to_snippet(span) {
+ let suggestable_fr_name = match fr_name {
+ RegionName::Named(name) => format!("{}", name),
+ RegionName::Synthesized(_) => "'_".to_string(),
+ };
+ diag.span_suggestion(
+ span,
+ &format!(
+ "to allow this impl Trait to capture borrowed data with lifetime \
+ `{}`, add `{}` as a constraint",
+ fr_name, suggestable_fr_name,
+ ),
+ format!("{} + {}", snippet, suggestable_fr_name),
+ );
+ }
+ }
+ }
+ }
+ }
+
// Finds some region R such that `fr1: R` and `R` is live at
// `elem`.
crate fn find_sub_region_live_at(&self, fr1: RegionVid, elem: Location) -> RegionVid {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use std::fmt::{self, Display};
use borrow_check::nll::region_infer::RegionInferenceContext;
use borrow_check::nll::universal_regions::DefiningTy;
use borrow_check::nll::ToRegionVid;
use rustc_errors::DiagnosticBuilder;
use syntax::ast::{Name, DUMMY_NODE_ID};
use syntax::symbol::keywords;
+use syntax_pos::Span;
use syntax_pos::symbol::InternedString;
+/// Name of a region used in error reporting. Variants denote the source of the region name -
+/// whether it was synthesized for the error message and therefore should not be used in
+/// suggestions; or whether it was found from the region.
+#[derive(Debug)]
+pub(crate) enum RegionName {
+ Named(InternedString),
+ Synthesized(InternedString),
+}
+
+impl RegionName {
+ fn as_interned_string(&self) -> &InternedString {
+ match self {
+ RegionName::Named(name) | RegionName::Synthesized(name) => name,
+ }
+ }
+}
+
+impl Display for RegionName {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ RegionName::Named(name) | RegionName::Synthesized(name) =>
+ write!(f, "{}", name),
+ }
+ }
+}
+
impl<'tcx> RegionInferenceContext<'tcx> {
/// Maps from an internal MIR region vid to something that we can
/// report to the user. In some cases, the region vids will map
fr: RegionVid,
counter: &mut usize,
diag: &mut DiagnosticBuilder,
- ) -> InternedString {
+ ) -> RegionName {
debug!("give_region_a_name(fr={:?}, counter={})", fr, counter);
assert!(self.universal_regions.is_universal_region(fr));
fr: RegionVid,
counter: &mut usize,
diag: &mut DiagnosticBuilder<'_>,
- ) -> Option<InternedString> {
+ ) -> Option<RegionName> {
let error_region = self.to_error_region(fr)?;
debug!("give_region_a_name: error_region = {:?}", error_region);
match error_region {
ty::ReEarlyBound(ebr) => {
if ebr.has_name() {
- self.highlight_named_span(tcx, error_region, &ebr.name, diag);
- Some(ebr.name)
+ let name = RegionName::Named(ebr.name);
+ self.highlight_named_span(tcx, error_region, &name, diag);
+ Some(name)
} else {
None
}
}
- ty::ReStatic => Some(keywords::StaticLifetime.name().as_interned_str()),
+ ty::ReStatic => Some(RegionName::Named(
+ keywords::StaticLifetime.name().as_interned_str()
+ )),
ty::ReFree(free_region) => match free_region.bound_region {
ty::BoundRegion::BrNamed(_, name) => {
+ let name = RegionName::Named(name);
self.highlight_named_span(tcx, error_region, &name, diag);
Some(name)
- }
+ },
ty::BoundRegion::BrEnv => {
let mir_node_id = tcx.hir.as_local_node_id(mir_def_id).expect("non-local mir");
let region_name = self.synthesize_region_name(counter);
diag.span_label(
args_span,
- format!("lifetime `{}` represents this closure's body", region_name),
+ format!(
+ "lifetime `{}` represents this closure's body",
+ region_name
+ ),
);
let closure_kind_ty = substs.closure_kind_ty(def_id, tcx);
}
}
+ /// Get the span of a named region.
+ pub(super) fn get_span_of_named_region(
+ &self,
+ tcx: TyCtxt<'_, '_, 'tcx>,
+ error_region: &RegionKind,
+ name: &RegionName,
+ ) -> Span {
+ let scope = error_region.free_region_binding_scope(tcx);
+ let node = tcx.hir.as_local_node_id(scope).unwrap_or(DUMMY_NODE_ID);
+
+ let span = tcx.sess.source_map().def_span(tcx.hir.span(node));
+ if let Some(param) = tcx.hir.get_generics(scope).and_then(|generics| {
+ generics.get_named(name.as_interned_string())
+ }) {
+ param.span
+ } else {
+ span
+ }
+ }
+
/// Highlight a named span to provide context for error messages that
/// mention that span, for example:
///
&self,
tcx: TyCtxt<'_, '_, 'tcx>,
error_region: &RegionKind,
- name: &InternedString,
+ name: &RegionName,
diag: &mut DiagnosticBuilder<'_>,
) {
- let cm = tcx.sess.source_map();
+ let span = self.get_span_of_named_region(tcx, error_region, name);
- let scope = error_region.free_region_binding_scope(tcx);
- let node = tcx.hir.as_local_node_id(scope).unwrap_or(DUMMY_NODE_ID);
-
- let mut sp = cm.def_span(tcx.hir.span(node));
- if let Some(param) = tcx.hir
- .get_generics(scope)
- .and_then(|generics| generics.get_named(name))
- {
- sp = param.span;
- }
-
- diag.span_label(sp, format!("lifetime `{}` defined here", name));
+ diag.span_label(
+ span,
+ format!("lifetime `{}` defined here", name),
+ );
}
/// Find an argument that contains `fr` and label it with a fully
fr: RegionVid,
counter: &mut usize,
diag: &mut DiagnosticBuilder<'_>,
- ) -> Option<InternedString> {
+ ) -> Option<RegionName> {
let implicit_inputs = self.universal_regions.defining_ty.implicit_inputs();
let argument_index = self.get_argument_index_for_region(infcx.tcx, fr)?;
argument_index: usize,
counter: &mut usize,
diag: &mut DiagnosticBuilder<'_>,
- ) -> Option<InternedString> {
+ ) -> Option<RegionName> {
let mir_node_id = infcx.tcx.hir.as_local_node_id(mir_def_id)?;
let fn_decl = infcx.tcx.hir.fn_decl(mir_node_id)?;
let argument_hir_ty: &hir::Ty = &fn_decl.inputs[argument_index];
argument_ty: Ty<'tcx>,
counter: &mut usize,
diag: &mut DiagnosticBuilder<'_>,
- ) -> Option<InternedString> {
+ ) -> Option<RegionName> {
let type_name = with_highlight_region(needle_fr, *counter, || {
infcx.extract_type_name(&argument_ty)
});
argument_hir_ty: &hir::Ty,
counter: &mut usize,
diag: &mut DiagnosticBuilder<'_>,
- ) -> Option<InternedString> {
+ ) -> Option<RegionName> {
let search_stack: &mut Vec<(Ty<'tcx>, &hir::Ty)> = &mut Vec::new();
search_stack.push((argument_ty, argument_hir_ty));
counter: &mut usize,
diag: &mut DiagnosticBuilder<'_>,
search_stack: &mut Vec<(Ty<'tcx>, &'hir hir::Ty)>,
- ) -> Option<InternedString> {
+ ) -> Option<RegionName> {
// Did the user give explicit arguments? (e.g., `Foo<..>`)
let args = last_segment.args.as_ref()?;
let lifetime = self.try_match_adt_and_generic_args(substs, needle_fr, args, search_stack)?;
| hir::LifetimeName::Underscore => {
let region_name = self.synthesize_region_name(counter);
let ampersand_span = lifetime.span;
- diag.span_label(ampersand_span, format!("let's call this `{}`", region_name));
+ diag.span_label(
+ ampersand_span,
+ format!("let's call this `{}`", region_name)
+ );
return Some(region_name);
}
fr: RegionVid,
counter: &mut usize,
diag: &mut DiagnosticBuilder<'_>,
- ) -> Option<InternedString> {
+ ) -> Option<RegionName> {
let upvar_index = self.get_upvar_index_for_region(tcx, fr)?;
let (upvar_name, upvar_span) =
self.get_upvar_name_and_span_for_region(tcx, mir, upvar_index);
fr: RegionVid,
counter: &mut usize,
diag: &mut DiagnosticBuilder<'_>,
- ) -> Option<InternedString> {
+ ) -> Option<RegionName> {
let tcx = infcx.tcx;
let return_ty = self.universal_regions.unnormalized_output_ty;
/// Create a synthetic region named `'1`, incrementing the
/// counter.
- fn synthesize_region_name(&self, counter: &mut usize) -> InternedString {
+ fn synthesize_region_name(&self, counter: &mut usize) -> RegionName {
let c = *counter;
*counter += 1;
- Name::intern(&format!("'{:?}", c)).as_interned_str()
+ RegionName::Synthesized(Name::intern(&format!("'{:?}", c)).as_interned_str())
}
}
};
use rustc::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable};
use rustc::util::common;
+use rustc_data_structures::bit_set::BitSet;
use rustc_data_structures::graph::scc::Sccs;
-use rustc_data_structures::indexed_set::IdxSet;
use rustc_data_structures::indexed_vec::IndexVec;
use rustc_errors::{DiagnosticBuilder, Diagnostic};
// SCC. For each SCC, we visit its successors and compute
// their values, then we union all those values to get our
// own.
- let visited = &mut IdxSet::new_empty(self.constraint_sccs.num_sccs());
+ let visited = &mut BitSet::new_empty(self.constraint_sccs.num_sccs());
for scc_index in self.constraint_sccs.all_sccs() {
self.propagate_constraint_sccs_if_new(scc_index, visited);
}
fn propagate_constraint_sccs_if_new(
&mut self,
scc_a: ConstraintSccIndex,
- visited: &mut IdxSet<ConstraintSccIndex>,
+ visited: &mut BitSet<ConstraintSccIndex>,
) {
- if visited.add(&scc_a) {
+ if visited.insert(scc_a) {
self.propagate_constraint_sccs_new(scc_a, visited);
}
}
fn propagate_constraint_sccs_new(
&mut self,
scc_a: ConstraintSccIndex,
- visited: &mut IdxSet<ConstraintSccIndex>,
+ visited: &mut BitSet<ConstraintSccIndex>,
) {
let constraint_sccs = self.constraint_sccs.clone();
use rustc::mir::{BasicBlock, Location, Mir};
use rustc::ty::{self, RegionVid};
-use rustc_data_structures::bitvec::{BitArray, SparseBitMatrix};
+use rustc_data_structures::bit_set::{HybridBitSet, SparseBitMatrix};
use rustc_data_structures::indexed_vec::Idx;
use rustc_data_structures::indexed_vec::IndexVec;
use std::fmt::Debug;
crate fn add_element(&mut self, row: N, location: Location) -> bool {
debug!("LivenessValues::add(r={:?}, location={:?})", row, location);
let index = self.elements.point_from_location(location);
- self.points.add(row, index)
+ self.points.insert(row, index)
}
/// Adds all the elements in the given bit array into the given
/// region. Returns true if any of them are newly added.
- crate fn add_elements(&mut self, row: N, locations: &BitArray<PointIndex>) -> bool {
+ crate fn add_elements(&mut self, row: N, locations: &HybridBitSet<PointIndex>) -> bool {
debug!("LivenessValues::add_elements(row={:?}, locations={:?})", row, locations);
- self.points.merge_into(row, locations)
+ self.points.union_into_row(row, locations)
}
/// Adds all the control-flow points to the values for `r`.
crate fn add_all_points(&mut self, row: N) {
- self.points.add_all(row);
+ self.points.insert_all_into_row(row);
}
/// True if the region `r` contains the given element.
/// Adds all the control-flow points to the values for `r`.
crate fn add_all_points(&mut self, r: N) {
- self.points.add_all(r);
+ self.points.insert_all_into_row(r);
}
/// Add all elements in `r_from` to `r_to` (because e.g. `r_to:
/// r_from`).
crate fn add_region(&mut self, r_to: N, r_from: N) -> bool {
- self.points.merge(r_from, r_to)
- | self.free_regions.merge(r_from, r_to)
- | self.placeholders.merge(r_from, r_to)
+ self.points.union_rows(r_from, r_to)
+ | self.free_regions.union_rows(r_from, r_to)
+ | self.placeholders.union_rows(r_from, r_to)
}
/// True if the region `r` contains the given element.
/// the region `to` in `self`.
crate fn merge_liveness<M: Idx>(&mut self, to: N, from: M, values: &LivenessValues<M>) {
if let Some(set) = values.points.row(from) {
- self.points.merge_into(to, set);
+ self.points.union_into_row(to, set);
}
}
crate fn contains_points(&self, sup_region: N, sub_region: N) -> bool {
if let Some(sub_row) = self.points.row(sub_region) {
if let Some(sup_row) = self.points.row(sup_region) {
- sup_row.contains_all(sub_row)
+ sup_row.superset(sub_row)
} else {
// sup row is empty, so sub row must be empty
sub_row.is_empty()
impl ToElementIndex for Location {
fn add_to_row<N: Idx>(self, values: &mut RegionValues<N>, row: N) -> bool {
let index = values.elements.point_from_location(self);
- values.points.add(row, index)
+ values.points.insert(row, index)
}
fn contained_in_row<N: Idx>(self, values: &RegionValues<N>, row: N) -> bool {
impl ToElementIndex for RegionVid {
fn add_to_row<N: Idx>(self, values: &mut RegionValues<N>, row: N) -> bool {
- values.free_regions.add(row, self)
+ values.free_regions.insert(row, self)
}
fn contained_in_row<N: Idx>(self, values: &RegionValues<N>, row: N) -> bool {
impl ToElementIndex for ty::UniverseIndex {
fn add_to_row<N: Idx>(self, values: &mut RegionValues<N>, row: N) -> bool {
let index = PlaceholderIndex::new(self.as_usize() - 1);
- values.placeholders.add(row, index)
+ values.placeholders.insert(row, index)
}
fn contained_in_row<N: Idx>(self, values: &RegionValues<N>, row: N) -> bool {
use rustc::traits::query::type_op::outlives::DropckOutlives;
use rustc::traits::query::type_op::TypeOp;
use rustc::ty::{Ty, TypeFoldable};
-use rustc_data_structures::bitvec::BitArray;
+use rustc_data_structures::bit_set::HybridBitSet;
use rustc_data_structures::fx::FxHashMap;
use std::rc::Rc;
use util::liveness::LiveVariableMap;
cx: LivenessContext<'me, 'typeck, 'flow, 'gcx, 'tcx>,
/// Set of points that define the current local.
- defs: BitArray<PointIndex>,
+ defs: HybridBitSet<PointIndex>,
/// Points where the current variable is "use live" -- meaning
/// that there is a future "full use" that may use its value.
- use_live_at: BitArray<PointIndex>,
+ use_live_at: HybridBitSet<PointIndex>,
/// Points where the current variable is "drop live" -- meaning
/// that there is no future "full use" that may use its value, but
/// there is a future drop.
- drop_live_at: BitArray<PointIndex>,
+ drop_live_at: HybridBitSet<PointIndex>,
/// Locations where drops may occur.
drop_locations: Vec<Location>,
let num_points = cx.elements.num_points();
LivenessResults {
cx,
- defs: BitArray::new(num_points),
- use_live_at: BitArray::new(num_points),
- drop_live_at: BitArray::new(num_points),
+ defs: HybridBitSet::new_empty(num_points),
+ use_live_at: HybridBitSet::new_empty(num_points),
+ drop_live_at: HybridBitSet::new_empty(num_points),
drop_locations: vec![],
stack: vec![],
}
fn add_use_live_facts_for(
&mut self,
value: impl TypeFoldable<'tcx>,
- live_at: &BitArray<PointIndex>,
+ live_at: &HybridBitSet<PointIndex>,
) {
debug!("add_use_live_facts_for(value={:?})", value);
dropped_local: Local,
dropped_ty: Ty<'tcx>,
drop_locations: &[Location],
- live_at: &BitArray<PointIndex>,
+ live_at: &HybridBitSet<PointIndex>,
) {
debug!(
"add_drop_live_constraint(\
elements: &RegionValueElements,
typeck: &mut TypeChecker<'_, '_, 'tcx>,
value: impl TypeFoldable<'tcx>,
- live_at: &BitArray<PointIndex>,
+ live_at: &HybridBitSet<PointIndex>,
) {
debug!("make_all_regions_live(value={:?})", value);
debug!(
source_info: SourceInfo,
region_scope: region::Scope) {
if tcx.emit_end_regions() {
- if let region::ScopeData::CallSite = region_scope.data() {
+ if let region::ScopeData::CallSite = region_scope.data {
// The CallSite scope (aka the root scope) is sort of weird, in that it is
// supposed to "separate" the "interior" and "exterior" of a closure. Being
// that, it is not really a part of the region hierarchy, but for some
use rustc::hir;
use rustc::mir::*;
use rustc::ty::{self, CanonicalTy, Ty};
-use rustc_data_structures::bitvec::BitArray;
+use rustc_data_structures::bit_set::BitSet;
use rustc_data_structures::fx::FxHashMap;
use syntax::ast::{Name, NodeId};
use syntax_pos::Span;
// test the branches of enum
Switch {
adt_def: &'tcx ty::AdtDef,
- variants: BitArray<usize>,
+ variants: BitSet<usize>,
},
// test the branches of enum
use build::Builder;
use build::matches::{Candidate, MatchPair, Test, TestKind};
use hair::*;
+use rustc_data_structures::bit_set::BitSet;
use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::bitvec::BitArray;
use rustc::ty::{self, Ty};
use rustc::ty::util::IntTypeExt;
use rustc::mir::*;
span: match_pair.pattern.span,
kind: TestKind::Switch {
adt_def: adt_def.clone(),
- variants: BitArray::new(adt_def.variants.len()),
+ variants: BitSet::new_empty(adt_def.variants.len()),
},
}
}
pub fn add_variants_to_switch<'pat>(&mut self,
test_place: &Place<'tcx>,
candidate: &Candidate<'pat, 'tcx>,
- variants: &mut BitArray<usize>)
+ variants: &mut BitSet<usize>)
-> bool
{
let match_pair = match candidate.match_pairs.iter().find(|mp| mp.place == *test_place) {
upvar_decls);
let fn_def_id = tcx.hir.local_def_id(fn_id);
- let call_site_scope = region::Scope::CallSite(body.value.hir_id.local_id);
- let arg_scope = region::Scope::Arguments(body.value.hir_id.local_id);
+ let call_site_scope = region::Scope {
+ id: body.value.hir_id.local_id,
+ data: region::ScopeData::CallSite
+ };
+ let arg_scope = region::Scope {
+ id: body.value.hir_id.local_id,
+ data: region::ScopeData::Arguments
+ };
let mut block = START_BLOCK;
let source_info = builder.source_info(span);
let call_site_s = (call_site_scope, source_info);
// The outermost scope (`scopes[0]`) will be the `CallSiteScope`.
// We want `scopes[1]`, which is the `ParameterScope`.
assert!(self.scopes.len() >= 2);
- assert!(match self.scopes[1].region_scope.data() {
+ assert!(match self.scopes[1].region_scope.data {
region::ScopeData::Arguments => true,
_ => false,
});
//! locations.
use rustc::mir::{BasicBlock, Location};
-use rustc_data_structures::bitvec::BitIter;
-use rustc_data_structures::indexed_set::{HybridIdxSet, IdxSet};
+use rustc_data_structures::bit_set::{BitIter, BitSet, HybridBitSet};
use dataflow::{BitDenotation, BlockSets, DataflowResults};
use dataflow::move_paths::{HasMoveData, MovePathIndex};
BD: BitDenotation,
{
base_results: DataflowResults<BD>,
- curr_state: IdxSet<BD::Idx>,
- stmt_gen: HybridIdxSet<BD::Idx>,
- stmt_kill: HybridIdxSet<BD::Idx>,
+ curr_state: BitSet<BD::Idx>,
+ stmt_gen: HybridBitSet<BD::Idx>,
+ stmt_kill: HybridBitSet<BD::Idx>,
}
impl<BD> FlowAtLocation<BD>
pub fn new(results: DataflowResults<BD>) -> Self {
let bits_per_block = results.sets().bits_per_block();
- let curr_state = IdxSet::new_empty(bits_per_block);
- let stmt_gen = HybridIdxSet::new_empty(bits_per_block);
- let stmt_kill = HybridIdxSet::new_empty(bits_per_block);
+ let curr_state = BitSet::new_empty(bits_per_block);
+ let stmt_gen = HybridBitSet::new_empty(bits_per_block);
+ let stmt_kill = HybridBitSet::new_empty(bits_per_block);
FlowAtLocation {
base_results: results,
curr_state: curr_state,
self.base_results.operator()
}
- pub fn contains(&self, x: &BD::Idx) -> bool {
+ pub fn contains(&self, x: BD::Idx) -> bool {
self.curr_state.contains(x)
}
// siblings);
// - ~99% of the time the loop isn't reached, and this code is hot, so
// we don't want to allocate `todo` unnecessarily.
- if self.contains(&mpi) {
+ if self.contains(mpi) {
return Some(mpi);
}
let move_data = self.operator().move_data();
};
while let Some(mpi) = todo.pop() {
- if self.contains(&mpi) {
+ if self.contains(mpi) {
return Some(mpi);
}
let move_path = &move_data.move_paths[mpi];
use syntax::ast::NodeId;
use rustc::mir::{BasicBlock, Mir};
-use rustc_data_structures::bitvec::bits_to_string;
use dot;
use dot::IntoCow;
// Entry
let set = flow.sets.on_entry_set_for(i);
- write!(w, "<td>{:?}</td>", dot::escape_html(&bits_to_string(set.words(), bits_per_block)))?;
+ write!(w, "<td>{:?}</td>", dot::escape_html(&set.to_string(bits_per_block)))?;
// Terminator
write!(w, "<td>")?;
self.mir.local_decls.len()
}
- fn start_block_effect(&self, _sets: &mut IdxSet<Local>) {
+ fn start_block_effect(&self, _sets: &mut BitSet<Local>) {
// Nothing is borrowed on function entry
}
// StorageDead invalidates all borrows and raw pointers to a local
match stmt.kind {
- StatementKind::StorageDead(l) => sets.kill(&l),
+ StatementKind::StorageDead(l) => sets.kill(l),
_ => (),
}
}
}
fn propagate_call_return(&self,
- _in_out: &mut IdxSet<Local>,
+ _in_out: &mut BitSet<Local>,
_call_bb: mir::BasicBlock,
_dest_bb: mir::BasicBlock,
_dest_place: &mir::Place) {
}
}
-impl<'a, 'tcx> BitwiseOperator for HaveBeenBorrowedLocals<'a, 'tcx> {
+impl<'a, 'tcx> BitSetOperator for HaveBeenBorrowedLocals<'a, 'tcx> {
#[inline]
- fn join(&self, pred1: Word, pred2: Word) -> Word {
- pred1 | pred2 // "maybe" means we union effects of both preds
+ fn join<T: Idx>(&self, inout_set: &mut BitSet<T>, in_set: &BitSet<T>) -> bool {
+ inout_set.union(in_set) // "maybe" means we union effects of both preds
}
}
location: Location) {
if let Rvalue::Ref(_, _, ref place) = *rvalue {
if let Some(local) = find_local(place) {
- self.sets.gen(&local);
+ self.sets.gen(local);
}
}
use rustc::ty::{RegionKind, RegionVid};
use rustc::ty::RegionKind::ReScope;
-use rustc_data_structures::bitvec::{BitwiseOperator, Word};
+use rustc_data_structures::bit_set::{BitSet, BitSetOperator};
use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::indexed_set::IdxSet;
-use rustc_data_structures::indexed_vec::IndexVec;
+use rustc_data_structures::indexed_vec::{Idx, IndexVec};
use rustc_data_structures::sync::Lrc;
use dataflow::{BitDenotation, BlockSets, InitialFlow};
) -> Self {
let scope_tree = tcx.region_scope_tree(def_id);
let root_scope = body_id.map(|body_id| {
- region::Scope::CallSite(tcx.hir.body(body_id).value.hir_id.local_id)
+ region::Scope {
+ id: tcx.hir.body(body_id).value.hir_id.local_id,
+ data: region::ScopeData::CallSite
+ }
});
let mut borrows_out_of_scope_at_location = FxHashMap();
self.borrow_set.borrows.len() * 2
}
- fn start_block_effect(&self, _entry_set: &mut IdxSet<BorrowIndex>) {
+ fn start_block_effect(&self, _entry_set: &mut BitSet<BorrowIndex>) {
// no borrows of code region_scopes have been taken prior to
// function execution, so this method has no effect on
// `_sets`.
debug!("Borrows::statement_effect_on_borrows \
location: {:?} stmt: {:?} has empty region, killing {:?}",
location, stmt.kind, index);
- sets.kill(&index);
+ sets.kill(*index);
return
} else {
debug!("Borrows::statement_effect_on_borrows location: {:?} stmt: {:?}",
assert!(self.borrow_set.region_map.get(region).unwrap_or_else(|| {
panic!("could not find BorrowIndexs for region {:?}", region);
}).contains(&index));
- sets.gen(&index);
+ sets.gen(*index);
// Issue #46746: Two-phase borrows handles
// stmts of form `Tmp = &mut Borrow` ...
// e.g. `box (&mut _)`. Current
// conservative solution: force
// immediate activation here.
- sets.gen(&index);
+ sets.gen(*index);
}
}
}
if *scope != root_scope &&
self.scope_tree.is_subscope_of(*scope, root_scope)
{
- sets.kill(&borrow_index);
+ sets.kill(borrow_index);
}
}
}
}
fn propagate_call_return(&self,
- _in_out: &mut IdxSet<BorrowIndex>,
+ _in_out: &mut BitSet<BorrowIndex>,
_call_bb: mir::BasicBlock,
_dest_bb: mir::BasicBlock,
_dest_place: &mir::Place) {
}
}
-impl<'a, 'gcx, 'tcx> BitwiseOperator for Borrows<'a, 'gcx, 'tcx> {
+impl<'a, 'gcx, 'tcx> BitSetOperator for Borrows<'a, 'gcx, 'tcx> {
#[inline]
- fn join(&self, pred1: Word, pred2: Word) -> Word {
- pred1 | pred2 // union effects of preds when computing reservations
+ fn join<T: Idx>(&self, inout_set: &mut BitSet<T>, in_set: &BitSet<T>) -> bool {
+ inout_set.union(in_set) // "maybe" means we union effects of both preds
}
}
use rustc::ty::TyCtxt;
use rustc::mir::{self, Mir, Location};
-use rustc_data_structures::bitvec::{BitwiseOperator, Word};
-use rustc_data_structures::indexed_set::{IdxSet};
+use rustc_data_structures::bit_set::{BitSet, BitSetOperator};
use rustc_data_structures::indexed_vec::Idx;
use super::MoveDataParamEnv;
state: DropFlagState)
{
match state {
- DropFlagState::Absent => sets.kill(&path),
- DropFlagState::Present => sets.gen(&path),
+ DropFlagState::Absent => sets.kill(path),
+ DropFlagState::Present => sets.gen(path),
}
}
}
state: DropFlagState)
{
match state {
- DropFlagState::Absent => sets.gen(&path),
- DropFlagState::Present => sets.kill(&path),
+ DropFlagState::Absent => sets.gen(path),
+ DropFlagState::Present => sets.kill(path),
}
}
}
state: DropFlagState)
{
match state {
- DropFlagState::Absent => sets.kill(&path),
- DropFlagState::Present => sets.gen(&path),
+ DropFlagState::Absent => sets.kill(path),
+ DropFlagState::Present => sets.gen(path),
}
}
}
self.move_data().move_paths.len()
}
- fn start_block_effect(&self, entry_set: &mut IdxSet<MovePathIndex>) {
+ fn start_block_effect(&self, entry_set: &mut BitSet<MovePathIndex>) {
drop_flag_effects_for_function_entry(
self.tcx, self.mir, self.mdpe,
|path, s| {
assert!(s == DropFlagState::Present);
- entry_set.add(&path);
+ entry_set.insert(path);
});
}
}
fn propagate_call_return(&self,
- in_out: &mut IdxSet<MovePathIndex>,
+ in_out: &mut BitSet<MovePathIndex>,
_call_bb: mir::BasicBlock,
_dest_bb: mir::BasicBlock,
dest_place: &mir::Place) {
// the bits for that dest_place to 1 (initialized).
on_lookup_result_bits(self.tcx, self.mir, self.move_data(),
self.move_data().rev_lookup.find(dest_place),
- |mpi| { in_out.add(&mpi); });
+ |mpi| { in_out.insert(mpi); });
}
}
}
// sets on_entry bits for Arg places
- fn start_block_effect(&self, entry_set: &mut IdxSet<MovePathIndex>) {
+ fn start_block_effect(&self, entry_set: &mut BitSet<MovePathIndex>) {
// set all bits to 1 (uninit) before gathering counterevidence
entry_set.set_up_to(self.bits_per_block());
self.tcx, self.mir, self.mdpe,
|path, s| {
assert!(s == DropFlagState::Present);
- entry_set.remove(&path);
+ entry_set.remove(path);
});
}
}
fn propagate_call_return(&self,
- in_out: &mut IdxSet<MovePathIndex>,
+ in_out: &mut BitSet<MovePathIndex>,
_call_bb: mir::BasicBlock,
_dest_bb: mir::BasicBlock,
dest_place: &mir::Place) {
// the bits for that dest_place to 0 (initialized).
on_lookup_result_bits(self.tcx, self.mir, self.move_data(),
self.move_data().rev_lookup.find(dest_place),
- |mpi| { in_out.remove(&mpi); });
+ |mpi| { in_out.remove(mpi); });
}
}
}
// sets on_entry bits for Arg places
- fn start_block_effect(&self, entry_set: &mut IdxSet<MovePathIndex>) {
+ fn start_block_effect(&self, entry_set: &mut BitSet<MovePathIndex>) {
entry_set.clear();
drop_flag_effects_for_function_entry(
self.tcx, self.mir, self.mdpe,
|path, s| {
assert!(s == DropFlagState::Present);
- entry_set.add(&path);
+ entry_set.insert(path);
});
}
}
fn propagate_call_return(&self,
- in_out: &mut IdxSet<MovePathIndex>,
+ in_out: &mut BitSet<MovePathIndex>,
_call_bb: mir::BasicBlock,
_dest_bb: mir::BasicBlock,
dest_place: &mir::Place) {
// the bits for that dest_place to 1 (initialized).
on_lookup_result_bits(self.tcx, self.mir, self.move_data(),
self.move_data().rev_lookup.find(dest_place),
- |mpi| { in_out.add(&mpi); });
+ |mpi| { in_out.insert(mpi); });
}
}
self.move_data().inits.len()
}
- fn start_block_effect(&self, entry_set: &mut IdxSet<InitIndex>) {
+ fn start_block_effect(&self, entry_set: &mut BitSet<InitIndex>) {
for arg_init in 0..self.mir.arg_count {
- entry_set.add(&InitIndex::new(arg_init));
+ entry_set.insert(InitIndex::new(arg_init));
}
}
}
fn propagate_call_return(&self,
- in_out: &mut IdxSet<InitIndex>,
+ in_out: &mut BitSet<InitIndex>,
call_bb: mir::BasicBlock,
_dest_bb: mir::BasicBlock,
_dest_place: &mir::Place) {
};
for init_index in &init_loc_map[call_loc] {
assert!(init_index.index() < bits_per_block);
- in_out.add(init_index);
+ in_out.insert(*init_index);
}
}
}
-impl<'a, 'gcx, 'tcx> BitwiseOperator for MaybeInitializedPlaces<'a, 'gcx, 'tcx> {
+impl<'a, 'gcx, 'tcx> BitSetOperator for MaybeInitializedPlaces<'a, 'gcx, 'tcx> {
#[inline]
- fn join(&self, pred1: Word, pred2: Word) -> Word {
- pred1 | pred2 // "maybe" means we union effects of both preds
+ fn join<T: Idx>(&self, inout_set: &mut BitSet<T>, in_set: &BitSet<T>) -> bool {
+ inout_set.union(in_set) // "maybe" means we union effects of both preds
}
}
-impl<'a, 'gcx, 'tcx> BitwiseOperator for MaybeUninitializedPlaces<'a, 'gcx, 'tcx> {
+impl<'a, 'gcx, 'tcx> BitSetOperator for MaybeUninitializedPlaces<'a, 'gcx, 'tcx> {
#[inline]
- fn join(&self, pred1: Word, pred2: Word) -> Word {
- pred1 | pred2 // "maybe" means we union effects of both preds
+ fn join<T: Idx>(&self, inout_set: &mut BitSet<T>, in_set: &BitSet<T>) -> bool {
+ inout_set.union(in_set) // "maybe" means we union effects of both preds
}
}
-impl<'a, 'gcx, 'tcx> BitwiseOperator for DefinitelyInitializedPlaces<'a, 'gcx, 'tcx> {
+impl<'a, 'gcx, 'tcx> BitSetOperator for DefinitelyInitializedPlaces<'a, 'gcx, 'tcx> {
#[inline]
- fn join(&self, pred1: Word, pred2: Word) -> Word {
- pred1 & pred2 // "definitely" means we intersect effects of both preds
+ fn join<T: Idx>(&self, inout_set: &mut BitSet<T>, in_set: &BitSet<T>) -> bool {
+ inout_set.intersect(in_set) // "definitely" means we intersect effects of both preds
}
}
-impl<'a, 'gcx, 'tcx> BitwiseOperator for EverInitializedPlaces<'a, 'gcx, 'tcx> {
+impl<'a, 'gcx, 'tcx> BitSetOperator for EverInitializedPlaces<'a, 'gcx, 'tcx> {
#[inline]
- fn join(&self, pred1: Word, pred2: Word) -> Word {
- pred1 | pred2 // inits from both preds are in scope
+ fn join<T: Idx>(&self, inout_set: &mut BitSet<T>, in_set: &BitSet<T>) -> bool {
+ inout_set.union(in_set) // inits from both preds are in scope
}
}
self.mir.local_decls.len()
}
- fn start_block_effect(&self, _sets: &mut IdxSet<Local>) {
+ fn start_block_effect(&self, _sets: &mut BitSet<Local>) {
// Nothing is live on function entry
}
let stmt = &self.mir[loc.block].statements[loc.statement_index];
match stmt.kind {
- StatementKind::StorageLive(l) => sets.gen(&l),
- StatementKind::StorageDead(l) => sets.kill(&l),
+ StatementKind::StorageLive(l) => sets.gen(l),
+ StatementKind::StorageDead(l) => sets.kill(l),
_ => (),
}
}
}
fn propagate_call_return(&self,
- _in_out: &mut IdxSet<Local>,
+ _in_out: &mut BitSet<Local>,
_call_bb: mir::BasicBlock,
_dest_bb: mir::BasicBlock,
_dest_place: &mir::Place) {
}
}
-impl<'a, 'tcx> BitwiseOperator for MaybeStorageLive<'a, 'tcx> {
+impl<'a, 'tcx> BitSetOperator for MaybeStorageLive<'a, 'tcx> {
#[inline]
- fn join(&self, pred1: Word, pred2: Word) -> Word {
- pred1 | pred2 // "maybe" means we union effects of both preds
+ fn join<T: Idx>(&self, inout_set: &mut BitSet<T>, in_set: &BitSet<T>) -> bool {
+ inout_set.union(in_set) // "maybe" means we union effects of both preds
}
}
use syntax::ast::{self, MetaItem};
-use rustc_data_structures::bitvec::{bitwise, BitwiseOperator};
-use rustc_data_structures::indexed_set::{HybridIdxSet, IdxSet};
+use rustc_data_structures::bit_set::{BitSet, BitSetOperator, HybridBitSet};
use rustc_data_structures::indexed_vec::Idx;
use rustc_data_structures::work_queue::WorkQueue;
mir: &'a Mir<'tcx>,
node_id: ast::NodeId,
attributes: &[ast::Attribute],
- dead_unwinds: &IdxSet<BasicBlock>,
+ dead_unwinds: &BitSet<BasicBlock>,
bd: BD,
p: P)
-> DataflowResults<BD>
impl<'a, 'tcx: 'a, BD> DataflowAnalysis<'a, 'tcx, BD> where BD: BitDenotation
{
fn propagate(&mut self) {
- let mut temp = IdxSet::new_empty(self.flow_state.sets.bits_per_block);
+ let mut temp = BitSet::new_empty(self.flow_state.sets.bits_per_block);
let mut propcx = PropagationContext {
builder: self,
};
impl<'b, 'a: 'b, 'tcx: 'a, BD> PropagationContext<'b, 'a, 'tcx, BD> where BD: BitDenotation
{
- fn walk_cfg(&mut self, in_out: &mut IdxSet<BD::Idx>) {
+ fn walk_cfg(&mut self, in_out: &mut BitSet<BD::Idx>) {
let mut dirty_queue: WorkQueue<mir::BasicBlock> =
WorkQueue::with_all(self.builder.mir.basic_blocks().len());
let mir = self.builder.mir;
analysis: &T,
result: &DataflowResults<T>,
mir: &Mir<'tcx>)
- -> IdxSet<T::Idx> {
+ -> BitSet<T::Idx> {
let mut on_entry = result.sets().on_entry_set_for(loc.block.index()).to_owned();
let mut kill_set = on_entry.to_hybrid();
let mut gen_set = kill_set.clone();
pub struct DataflowAnalysis<'a, 'tcx: 'a, O> where O: BitDenotation
{
flow_state: DataflowState<O>,
- dead_unwinds: &'a IdxSet<mir::BasicBlock>,
+ dead_unwinds: &'a BitSet<mir::BasicBlock>,
mir: &'a Mir<'tcx>,
}
impl<O: BitDenotation> DataflowState<O> {
pub(crate) fn interpret_set<'c, P>(&self,
o: &'c O,
- set: &IdxSet<O::Idx>,
+ set: &BitSet<O::Idx>,
render_idx: &P)
-> Vec<DebugFormatted>
where P: Fn(&O, O::Idx) -> DebugFormatted
pub(crate) fn interpret_hybrid_set<'c, P>(&self,
o: &'c O,
- set: &HybridIdxSet<O::Idx>,
+ set: &HybridBitSet<O::Idx>,
render_idx: &P)
-> Vec<DebugFormatted>
where P: Fn(&O, O::Idx) -> DebugFormatted
bits_per_block: usize,
/// For each block, bits valid on entry to the block.
- on_entry_sets: Vec<IdxSet<E>>,
+ on_entry_sets: Vec<BitSet<E>>,
/// For each block, bits generated by executing the statements +
/// terminator in the block -- with one caveat. In particular, for
/// *call terminators*, the effect of storing the destination is
/// not included, since that only takes effect on the **success**
/// edge (and not the unwind edge).
- gen_sets: Vec<HybridIdxSet<E>>,
+ gen_sets: Vec<HybridBitSet<E>>,
/// For each block, bits killed by executing the statements +
/// terminator in the block -- with one caveat. In particular, for
/// *call terminators*, the effect of storing the destination is
/// not included, since that only takes effect on the **success**
/// edge (and not the unwind edge).
- kill_sets: Vec<HybridIdxSet<E>>,
+ kill_sets: Vec<HybridBitSet<E>>,
}
/// Triple of sets associated with a given block.
#[derive(Debug)]
pub struct BlockSets<'a, E: Idx> {
/// Dataflow state immediately before control flow enters the given block.
- pub(crate) on_entry: &'a mut IdxSet<E>,
+ pub(crate) on_entry: &'a mut BitSet<E>,
/// Bits that are set to 1 by the time we exit the given block. Hybrid
/// because it usually contains only 0 or 1 elements.
- pub(crate) gen_set: &'a mut HybridIdxSet<E>,
+ pub(crate) gen_set: &'a mut HybridBitSet<E>,
/// Bits that are set to 0 by the time we exit the given block. Hybrid
/// because it usually contains only 0 or 1 elements.
- pub(crate) kill_set: &'a mut HybridIdxSet<E>,
+ pub(crate) kill_set: &'a mut HybridBitSet<E>,
}
impl<'a, E:Idx> BlockSets<'a, E> {
- fn gen(&mut self, e: &E) {
- self.gen_set.add(e);
+ fn gen(&mut self, e: E) {
+ self.gen_set.insert(e);
self.kill_set.remove(e);
}
fn gen_all<I>(&mut self, i: I)
I::Item: Borrow<E>
{
for j in i {
- self.gen(j.borrow());
+ self.gen(*j.borrow());
}
}
- fn kill(&mut self, e: &E) {
+ fn kill(&mut self, e: E) {
self.gen_set.remove(e);
- self.kill_set.add(e);
+ self.kill_set.insert(e);
}
fn kill_all<I>(&mut self, i: I)
I::Item: Borrow<E>
{
for j in i {
- self.kill(j.borrow());
+ self.kill(*j.borrow());
}
}
}
}
- pub fn on_entry_set_for(&self, block_idx: usize) -> &IdxSet<E> {
+ pub fn on_entry_set_for(&self, block_idx: usize) -> &BitSet<E> {
&self.on_entry_sets[block_idx]
}
- pub fn gen_set_for(&self, block_idx: usize) -> &HybridIdxSet<E> {
+ pub fn gen_set_for(&self, block_idx: usize) -> &HybridBitSet<E> {
&self.gen_sets[block_idx]
}
- pub fn kill_set_for(&self, block_idx: usize) -> &HybridIdxSet<E> {
+ pub fn kill_set_for(&self, block_idx: usize) -> &HybridBitSet<E> {
&self.kill_sets[block_idx]
}
}
fn bottom_value() -> bool;
}
-pub trait BitDenotation: BitwiseOperator {
+pub trait BitDenotation: BitSetOperator {
/// Specifies what index type is used to access the bitvector.
type Idx: Idx;
/// these won't be accounted for correctly.
///
/// (For example, establishing the call arguments.)
- fn start_block_effect(&self, entry_set: &mut IdxSet<Self::Idx>);
+ fn start_block_effect(&self, entry_set: &mut BitSet<Self::Idx>);
/// Similar to `statement_effect`, except it applies
/// *just before* the statement rather than *just after* it.
/// kill-sets associated with each edge coming out of the basic
/// block.
fn propagate_call_return(&self,
- in_out: &mut IdxSet<Self::Idx>,
+ in_out: &mut BitSet<Self::Idx>,
call_bb: mir::BasicBlock,
dest_bb: mir::BasicBlock,
dest_place: &mir::Place);
impl<'a, 'tcx, D> DataflowAnalysis<'a, 'tcx, D> where D: BitDenotation
{
pub fn new(mir: &'a Mir<'tcx>,
- dead_unwinds: &'a IdxSet<mir::BasicBlock>,
+ dead_unwinds: &'a BitSet<mir::BasicBlock>,
denotation: D) -> Self where D: InitialFlow {
let bits_per_block = denotation.bits_per_block();
let num_blocks = mir.basic_blocks().len();
let on_entry_sets = if D::bottom_value() {
- vec![IdxSet::new_filled(bits_per_block); num_blocks]
+ vec![BitSet::new_filled(bits_per_block); num_blocks]
} else {
- vec![IdxSet::new_empty(bits_per_block); num_blocks]
+ vec![BitSet::new_empty(bits_per_block); num_blocks]
};
- let gen_sets = vec![HybridIdxSet::new_empty(bits_per_block); num_blocks];
+ let gen_sets = vec![HybridBitSet::new_empty(bits_per_block); num_blocks];
let kill_sets = gen_sets.clone();
DataflowAnalysis {
}
pub fn new_from_sets(mir: &'a Mir<'tcx>,
- dead_unwinds: &'a IdxSet<mir::BasicBlock>,
+ dead_unwinds: &'a BitSet<mir::BasicBlock>,
sets: AllSets<D::Idx>,
denotation: D) -> Self {
DataflowAnalysis {
/// unwind target).
fn propagate_bits_into_graph_successors_of(
&mut self,
- in_out: &mut IdxSet<D::Idx>,
+ in_out: &mut BitSet<D::Idx>,
(bb, bb_data): (mir::BasicBlock, &mir::BasicBlockData),
dirty_list: &mut WorkQueue<mir::BasicBlock>)
{
target, value: _, location: _, unwind: Some(unwind)
} => {
self.propagate_bits_into_entry_set_for(in_out, target, dirty_list);
- if !self.dead_unwinds.contains(&bb) {
+ if !self.dead_unwinds.contains(bb) {
self.propagate_bits_into_entry_set_for(in_out, unwind, dirty_list);
}
}
}
mir::TerminatorKind::Call { cleanup, ref destination, func: _, args: _ } => {
if let Some(unwind) = cleanup {
- if !self.dead_unwinds.contains(&bb) {
+ if !self.dead_unwinds.contains(bb) {
self.propagate_bits_into_entry_set_for(in_out, unwind, dirty_list);
}
}
mir::TerminatorKind::FalseUnwind { real_target, unwind } => {
self.propagate_bits_into_entry_set_for(in_out, real_target, dirty_list);
if let Some(unwind) = unwind {
- if !self.dead_unwinds.contains(&bb) {
+ if !self.dead_unwinds.contains(bb) {
self.propagate_bits_into_entry_set_for(in_out, unwind, dirty_list);
}
}
}
fn propagate_bits_into_entry_set_for(&mut self,
- in_out: &IdxSet<D::Idx>,
+ in_out: &BitSet<D::Idx>,
bb: mir::BasicBlock,
dirty_queue: &mut WorkQueue<mir::BasicBlock>) {
- let entry_set = self.flow_state.sets.for_block(bb.index()).on_entry;
- let set_changed = bitwise(entry_set.words_mut(),
- in_out.words(),
- &self.flow_state.operator);
+ let entry_set = &mut self.flow_state.sets.for_block(bb.index()).on_entry;
+ let set_changed = self.flow_state.operator.join(entry_set, &in_out);
if set_changed {
dirty_queue.insert(bb);
}
pub place: Place<'tcx>,
}
+impl<'tcx> MovePath<'tcx> {
+ pub fn parents(&self, move_paths: &IndexVec<MovePathIndex, MovePath>) -> Vec<MovePathIndex> {
+ let mut parents = Vec::new();
+
+ let mut curr_parent = self.parent;
+ while let Some(parent_mpi) = curr_parent {
+ parents.push(parent_mpi);
+ curr_parent = move_paths[parent_mpi].parent;
+ }
+
+ parents
+ }
+}
+
impl<'tcx> fmt::Debug for MovePath<'tcx> {
fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
write!(w, "MovePath {{")?;
cx.region_scope_tree.opt_destruction_scope(self.hir_id.local_id);
Block {
targeted_by_break: self.targeted_by_break,
- region_scope: region::Scope::Node(self.hir_id.local_id),
+ region_scope: region::Scope {
+ id: self.hir_id.local_id,
+ data: region::ScopeData::Node
+ },
opt_destruction_scope,
span: self.span,
stmts,
hir::StmtKind::Semi(ref expr, _) => {
result.push(StmtRef::Mirror(Box::new(Stmt {
kind: StmtKind::Expr {
- scope: region::Scope::Node(hir_id.local_id),
+ scope: region::Scope {
+ id: hir_id.local_id,
+ data: region::ScopeData::Node
+ },
expr: expr.to_ref(),
},
opt_destruction_scope: opt_dxn_ext,
// ignore for purposes of the MIR
}
hir::DeclKind::Local(ref local) => {
- let remainder_scope = region::Scope::Remainder(
- block_id,
- region::FirstStatementIndex::new(index),
- );
+ let remainder_scope = region::Scope {
+ id: block_id,
+ data: region::ScopeData::Remainder(
+ region::FirstStatementIndex::new(index)),
+ };
let mut pattern = cx.pattern_from_hir(&local.pat);
result.push(StmtRef::Mirror(Box::new(Stmt {
kind: StmtKind::Let {
remainder_scope: remainder_scope,
- init_scope: region::Scope::Node(hir_id.local_id),
+ init_scope: region::Scope {
+ id: hir_id.local_id,
+ data: region::ScopeData::Node
+ },
pattern,
initializer: local.init.to_ref(),
lint_level: cx.lint_level_of(local.id),
fn make_mirror<'a, 'gcx>(self, cx: &mut Cx<'a, 'gcx, 'tcx>) -> Expr<'tcx> {
let temp_lifetime = cx.region_scope_tree.temporary_scope(self.hir_id.local_id);
- let expr_scope = region::Scope::Node(self.hir_id.local_id);
+ let expr_scope = region::Scope {
+ id: self.hir_id.local_id,
+ data: region::ScopeData::Node
+ };
debug!("Expr::make_mirror(): id={}, span={:?}", self.id, self.span);
// Convert this to a suitable `&foo` and
// then an unsafe coercion. Limit the region to be just this
// expression.
- let region = ty::ReScope(region::Scope::Node(hir_expr.hir_id.local_id));
+ let region = ty::ReScope(region::Scope {
+ id: hir_expr.hir_id.local_id,
+ data: region::ScopeData::Node
+ });
let region = cx.tcx.mk_region(region);
expr = Expr {
temp_lifetime,
hir::ExprKind::Break(dest, ref value) => {
match dest.target_id {
Ok(target_id) => ExprKind::Break {
- label: region::Scope::Node(cx.tcx.hir.node_to_hir_id(target_id).local_id),
+ label: region::Scope {
+ id: cx.tcx.hir.node_to_hir_id(target_id).local_id,
+ data: region::ScopeData::Node
+ },
value: value.to_ref(),
},
Err(err) => bug!("invalid loop id for break: {}", err)
hir::ExprKind::Continue(dest) => {
match dest.target_id {
Ok(loop_id) => ExprKind::Continue {
- label: region::Scope::Node(cx.tcx.hir.node_to_hir_id(loop_id).local_id),
+ label: region::Scope {
+ id: cx.tcx.hir.node_to_hir_id(loop_id).local_id,
+ data: region::ScopeData::Node
+ },
},
Err(err) => bug!("invalid loop id for continue: {}", err)
}
"cannot bind by-move with sub-bindings")
.span_label(p.span, "binds an already bound by-move value by moving it")
.emit();
- } else if has_guard {
- struct_span_err!(cx.tcx.sess, p.span, E0008,
- "cannot bind by-move into a pattern guard")
- .span_label(p.span, "moves value into pattern guard")
- .emit();
+ } else if has_guard && !cx.tcx.allow_bind_by_move_patterns_with_guards() {
+ let mut err = struct_span_err!(cx.tcx.sess, p.span, E0008,
+ "cannot bind by-move into a pattern guard");
+ err.span_label(p.span, "moves value into pattern guard");
+ if cx.tcx.sess.opts.unstable_features.is_nightly_build() && cx.tcx.use_mir_borrowck() {
+ err.help("add #![feature(bind_by_move_pattern_guards)] to the \
+ crate attributes to enable");
+ }
+ err.emit();
} else if let Some(by_ref_span) = by_ref_span {
struct_span_err!(
cx.tcx.sess,
_: LoanCause) {
match kind {
ty::MutBorrow => {
- struct_span_err!(self.cx.tcx.sess, span, E0301,
- "cannot mutably borrow in a pattern guard")
- .span_label(span, "borrowed mutably in pattern guard")
- .emit();
+ let mut err = struct_span_err!(self.cx.tcx.sess, span, E0301,
+ "cannot mutably borrow in a pattern guard");
+ err.span_label(span, "borrowed mutably in pattern guard");
+ if self.cx.tcx.sess.opts.unstable_features.is_nightly_build() &&
+ self.cx.tcx.use_mir_borrowck()
+ {
+ err.help("add #![feature(bind_by_move_pattern_guards)] to the \
+ crate attributes to enable");
+ }
+ err.emit();
}
ty::ImmBorrow | ty::UniqueImmBorrow => {}
}
/// a static creates a copy here, in the machine.
alloc_map: FxHashMap<AllocId, (MemoryKind<M::MemoryKinds>, Allocation)>,
+ /// To be able to compare pointers with NULL, and to check alignment for accesses
+ /// to ZSTs (where pointers may dangle), we keep track of the size even for allocations
+ /// that do not exist any more.
+ dead_alloc_map: FxHashMap<AllocId, (Size, Align)>,
+
pub tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
}
Memory {
data,
alloc_map: FxHashMap::default(),
+ dead_alloc_map: FxHashMap::default(),
tcx,
}
}
size_and_align: Option<(Size, Align)>,
kind: MemoryKind<M::MemoryKinds>,
) -> EvalResult<'tcx> {
+ debug!("deallocating: {}", ptr.alloc_id);
+
if ptr.offset.bytes() != 0 {
return err!(DeallocateNonBasePtr);
}
}
}
- debug!("deallocated : {}", ptr.alloc_id);
+ // Don't forget to remember size and align of this now-dead allocation
+ let old = self.dead_alloc_map.insert(
+ ptr.alloc_id,
+ (Size::from_bytes(alloc.bytes.len() as u64), alloc.align)
+ );
+ if old.is_some() {
+ bug!("Nothing can be deallocated twice");
+ }
Ok(())
}
- /// Check that the pointer is aligned AND non-NULL. This supports scalars
- /// for the benefit of other parts of miri that need to check alignment even for ZST.
+ /// Check that the pointer is aligned AND non-NULL. This supports ZSTs in two ways:
+ /// You can pass a scalar, and a `Pointer` does not have to actually still be allocated.
pub fn check_align(&self, ptr: Scalar, required_align: Align) -> EvalResult<'tcx> {
// Check non-NULL/Undef, extract offset
let (offset, alloc_align) = match ptr {
Scalar::Ptr(ptr) => {
- let alloc = self.get(ptr.alloc_id)?;
- (ptr.offset.bytes(), alloc.align)
+ let (size, align) = self.get_size_and_align(ptr.alloc_id)?;
+ // check this is not NULL -- which we can ensure only if this is in-bounds
+ // of some (potentially dead) allocation.
+ if ptr.offset > size {
+ return err!(PointerOutOfBounds {
+ ptr,
+ access: true,
+ allocation_size: size,
+ });
+ };
+ // keep data for alignment check
+ (ptr.offset.bytes(), align)
}
Scalar::Bits { bits, size } => {
assert_eq!(size as u64, self.pointer_size().bytes());
assert!(bits < (1u128 << self.pointer_size().bits()));
+ // check this is not NULL
if bits == 0 {
return err!(InvalidNullPointerUsage);
}
}
}
+ pub fn get_size_and_align(&self, id: AllocId) -> EvalResult<'tcx, (Size, Align)> {
+ Ok(match self.get(id) {
+ Ok(alloc) => (Size::from_bytes(alloc.bytes.len() as u64), alloc.align),
+ Err(err) => match err.kind {
+ EvalErrorKind::DanglingPointerDeref =>
+ // This should be in the dead allocation map
+ *self.dead_alloc_map.get(&id).expect(
+ "allocation missing in dead_alloc_map"
+ ),
+ // E.g. a function ptr allocation
+ _ => return Err(err)
+ }
+ })
+ }
+
pub fn get_mut(
&mut self,
id: AllocId,
}
let (ptr, ptr_align) = mplace.to_scalar_ptr_align();
- if mplace.layout.size.bytes() == 0 {
+ if mplace.layout.is_zst() {
// Not all ZSTs have a layout we would handle below, so just short-circuit them
// all here.
self.memory.check_align(ptr, ptr_align)?;
})
}
- // Take an operand, representing a pointer, and dereference it -- that
+ // Take an operand, representing a pointer, and dereference it to a place -- that
// will always be a MemPlace.
pub(super) fn deref_operand(
&self,
src: OpTy<'tcx>,
) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
let val = self.read_value(src)?;
- trace!("deref to {} on {:?}", val.layout.ty, val);
+ trace!("deref to {} on {:?}", val.layout.ty, *val);
Ok(self.ref_to_mplace(val)?)
}
};
let ptr = base.ptr.ptr_offset(offset, self)?;
- let align = base.align.min(field_layout.align); // only use static information
+ let align = base.align
+ // We do not look at `base.layout.align` nor `field_layout.align`, unlike
+ // codegen -- mostly to see if we can get away with that
+ .restrict_for_offset(offset); // must be last thing that happens
Ok(MPlaceTy { mplace: MemPlace { ptr, align, extra }, layout: field_layout })
}
// wrong type.
// Nothing to do for ZSTs, other than checking alignment
- if dest.layout.size.bytes() == 0 {
+ if dest.layout.is_zst() {
self.memory.check_align(ptr, ptr_align)?;
return Ok(());
}
use monomorphize::item::{MonoItemExt, DefPathBasedNames, InstantiationMode};
-use rustc_data_structures::bitvec::BitVector;
+use rustc_data_structures::bit_set::GrowableBitSet;
use rustc_data_structures::sync::{MTRef, MTLock, ParallelIterator, par_iter};
#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)]
// Contains one bit per mono item in the `targets` field. That bit
// is true if that mono item needs to be inlined into every CGU.
- inlines: BitVector<usize>,
+ inlines: GrowableBitSet<usize>,
}
impl<'tcx> InliningMap<'tcx> {
InliningMap {
index: FxHashMap(),
targets: Vec::new(),
- inlines: BitVector::with_capacity(1024),
+ inlines: GrowableBitSet::with_capacity(1024),
}
}
use rustc::ty::{self, TyCtxt};
use rustc::mir::*;
use rustc::util::nodemap::FxHashMap;
-use rustc_data_structures::indexed_set::IdxSet;
+use rustc_data_structures::bit_set::BitSet;
+use std::fmt;
+use syntax::ast;
+use syntax_pos::Span;
use transform::{MirPass, MirSource};
use util::patch::MirPatch;
use util::elaborate_drops::{DropFlagState, Unwind, elaborate_drop};
use util::elaborate_drops::{DropElaborator, DropStyle, DropFlagMode};
-use syntax::ast;
-use syntax_pos::Span;
-
-use std::fmt;
pub struct ElaborateDrops;
mir: &Mir<'tcx>,
id: ast::NodeId,
env: &MoveDataParamEnv<'tcx, 'tcx>)
- -> IdxSet<BasicBlock>
+ -> BitSet<BasicBlock>
{
debug!("find_dead_unwinds({:?})", mir.span);
// We only need to do this pass once, because unwind edges can only
// reach cleanup blocks, which can't have unwind edges themselves.
- let mut dead_unwinds = IdxSet::new_empty(mir.basic_blocks().len());
+ let mut dead_unwinds = BitSet::new_empty(mir.basic_blocks().len());
let flow_inits =
do_dataflow(tcx, mir, id, &[], &dead_unwinds,
MaybeInitializedPlaces::new(tcx, mir, &env),
let mut init_data = InitializationData {
live: flow_inits.sets().on_entry_set_for(bb.index()).to_owned(),
- dead: IdxSet::new_empty(env.move_data.move_paths.len()),
+ dead: BitSet::new_empty(env.move_data.move_paths.len()),
};
debug!("find_dead_unwinds @ {:?}: {:?}; init_data={:?}",
bb, bb_data, init_data.live);
debug!("find_dead_unwinds @ {:?}: maybe_live={}", bb, maybe_live);
if !maybe_live {
- dead_unwinds.add(&bb);
+ dead_unwinds.insert(bb);
}
}
}
struct InitializationData {
- live: IdxSet<MovePathIndex>,
- dead: IdxSet<MovePathIndex>
+ live: BitSet<MovePathIndex>,
+ dead: BitSet<MovePathIndex>
}
impl InitializationData {
loc, path, df);
match df {
DropFlagState::Present => {
- self.live.add(&path);
- self.dead.remove(&path);
+ self.live.insert(path);
+ self.dead.remove(path);
}
DropFlagState::Absent => {
- self.dead.add(&path);
- self.live.remove(&path);
+ self.dead.insert(path);
+ self.live.remove(path);
}
}
});
}
fn state(&self, path: MovePathIndex) -> (bool, bool) {
- (self.live.contains(&path), self.dead.contains(&path))
+ (self.live.contains(path), self.dead.contains(path))
}
}
use util::liveness::{self, IdentityMap};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::indexed_vec::Idx;
-use rustc_data_structures::indexed_set::IdxSet;
+use rustc_data_structures::bit_set::BitSet;
use std::borrow::Cow;
use std::iter::once;
use std::mem;
_location: Location) {
match statement.kind {
StatementKind::StorageLive(l) |
- StatementKind::StorageDead(l) => { self.0.remove(&l); }
+ StatementKind::StorageDead(l) => { self.0.remove(l); }
_ => (),
}
}
fn mark_as_borrowed<'tcx>(place: &Place<'tcx>, locals: &mut BorrowedLocals) {
match *place {
- Place::Local(l) => { locals.0.add(&l); },
+ Place::Local(l) => { locals.0.insert(l); },
Place::Promoted(_) |
Place::Static(..) => (),
Place::Projection(ref proj) => {
liveness::LiveVarSet<Local>,
FxHashMap<BasicBlock, liveness::LiveVarSet<Local>>,
) {
- let dead_unwinds = IdxSet::new_empty(mir.basic_blocks().len());
+ let dead_unwinds = BitSet::new_empty(mir.basic_blocks().len());
let node_id = tcx.hir.as_local_node_id(source.def_id).unwrap();
// Calculate when MIR locals have live storage. This gives us an upper bound of their
// Find the MIR locals which do not use StorageLive/StorageDead statements.
// The storage of these locals are always live.
- let mut ignored = StorageIgnored(IdxSet::new_filled(mir.local_decls.len()));
+ let mut ignored = StorageIgnored(BitSet::new_filled(mir.local_decls.len()));
ignored.visit_mir(mir);
// Calculate the MIR locals which have been previously
}
// The generator argument is ignored
- set.remove(&self_arg());
+ set.remove(self_arg());
(set, storage_liveness_map)
}
for (local, decl) in mir.local_decls.iter_enumerated() {
// Ignore locals which are internal or not live
- if !live_locals.contains(&local) || decl.internal {
+ if !live_locals.contains(local) || decl.internal {
continue;
}
// Create StorageLive instructions for locals with live storage
for i in 0..(mir.local_decls.len()) {
let l = Local::new(i);
- if point.storage_liveness.contains(&l) && !transform.remap.contains_key(&l) {
+ if point.storage_liveness.contains(l) && !transform.remap.contains_key(&l) {
statements.push(Statement {
source_info,
kind: StatementKind::StorageLive(l),
use rustc::hir::CodegenFnAttrFlags;
use rustc::hir::def_id::DefId;
-use rustc_data_structures::bitvec::BitArray;
+use rustc_data_structures::bit_set::BitSet;
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
use rustc::mir::*;
// Traverse the MIR manually so we can account for the effects of
// inlining on the CFG.
let mut work_list = vec![START_BLOCK];
- let mut visited = BitArray::new(callee_mir.basic_blocks().len());
+ let mut visited = BitSet::new_empty(callee_mir.basic_blocks().len());
while let Some(bb) = work_list.pop() {
if !visited.insert(bb.index()) { continue; }
let blk = &callee_mir.basic_blocks()[bb];
//! The Qualif flags below can be used to also provide better
//! diagnostics as to why a constant rvalue wasn't promoted.
-use rustc_data_structures::bitvec::BitArray;
-use rustc_data_structures::indexed_set::IdxSet;
+use rustc_data_structures::bit_set::BitSet;
use rustc_data_structures::indexed_vec::IndexVec;
use rustc_data_structures::fx::FxHashSet;
use rustc::hir;
param_env: ty::ParamEnv<'tcx>,
local_qualif: IndexVec<Local, Option<Qualif>>,
qualif: Qualif,
- const_fn_arg_vars: BitArray<Local>,
+ const_fn_arg_vars: BitSet<Local>,
temp_promotion_state: IndexVec<Local, TempState>,
promotion_candidates: Vec<Candidate>
}
param_env,
local_qualif,
qualif: Qualif::empty(),
- const_fn_arg_vars: BitArray::new(mir.local_decls.len()),
+ const_fn_arg_vars: BitSet::new_empty(mir.local_decls.len()),
temp_promotion_state: temps,
promotion_candidates: vec![]
}
}
/// Qualify a whole const, static initializer or const fn.
- fn qualify_const(&mut self) -> (Qualif, Lrc<IdxSet<Local>>) {
+ fn qualify_const(&mut self) -> (Qualif, Lrc<BitSet<Local>>) {
debug!("qualifying {} {:?}", self.mode, self.def_id);
let mir = self.mir;
- let mut seen_blocks = BitArray::new(mir.basic_blocks().len());
+ let mut seen_blocks = BitSet::new_empty(mir.basic_blocks().len());
let mut bb = START_BLOCK;
loop {
seen_blocks.insert(bb.index());
// Collect all the temps we need to promote.
- let mut promoted_temps = IdxSet::new_empty(self.temp_promotion_state.len());
+ let mut promoted_temps = BitSet::new_empty(self.temp_promotion_state.len());
for candidate in &self.promotion_candidates {
match *candidate {
Candidate::Ref(Location { block: bb, statement_index: stmt_idx }) => {
match self.mir[bb].statements[stmt_idx].kind {
StatementKind::Assign(_, Rvalue::Ref(_, _, Place::Local(index))) => {
- promoted_temps.add(&index);
+ promoted_temps.insert(index);
}
_ => {}
}
fn mir_const_qualif<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId)
- -> (u8, Lrc<IdxSet<Local>>) {
+ -> (u8, Lrc<BitSet<Local>>) {
// NB: This `borrow()` is guaranteed to be valid (i.e., the value
// cannot yet be stolen), because `mir_validated()`, which steals
// from `mir_const(), forces this query to execute before
if mir.return_ty().references_error() {
tcx.sess.delay_span_bug(mir.span, "mir_const_qualif: Mir had errors");
- return (Qualif::NOT_CONST.bits(), Lrc::new(IdxSet::new_empty(0)));
+ return (Qualif::NOT_CONST.bits(), Lrc::new(BitSet::new_empty(0)));
}
let mut qualifier = Qualifier::new(tcx, def_id, mir, Mode::Const);
block.statements.retain(|statement| {
match statement.kind {
StatementKind::StorageDead(index) => {
- !promoted_temps.contains(&index)
+ !promoted_temps.contains(index)
}
_ => true
}
let terminator = block.terminator_mut();
match terminator.kind {
TerminatorKind::Drop { location: Place::Local(index), target, .. } => {
- if promoted_temps.contains(&index) {
+ if promoted_temps.contains(index) {
terminator.kind = TerminatorKind::Goto {
target,
};
use rustc::ty::TyCtxt;
use rustc::mir::*;
-use rustc_data_structures::bitvec::BitArray;
+use rustc_data_structures::bit_set::BitSet;
use transform::{MirPass, MirSource};
use util::patch::MirPatch;
&self,
bb: BasicBlock,
mir: &Mir,
- nop_landing_pads: &BitArray<BasicBlock>,
+ nop_landing_pads: &BitSet<BasicBlock>,
) -> bool {
for stmt in &mir[bb].statements {
match stmt.kind {
let mut jumps_folded = 0;
let mut landing_pads_removed = 0;
- let mut nop_landing_pads = BitArray::new(mir.basic_blocks().len());
+ let mut nop_landing_pads = BitSet::new_empty(mir.basic_blocks().len());
// This is a post-order traversal, so that if A post-dominates B
// then A will be visited before B.
use rustc::ty::{self, TyCtxt};
use rustc::mir::{self, Mir, Location};
-use rustc_data_structures::indexed_set::IdxSet;
+use rustc_data_structures::bit_set::BitSet;
use transform::{MirPass, MirSource};
use dataflow::{do_dataflow, DebugFormatted};
let param_env = tcx.param_env(def_id);
let move_data = MoveData::gather_moves(mir, tcx).unwrap();
let mdpe = MoveDataParamEnv { move_data: move_data, param_env: param_env };
- let dead_unwinds = IdxSet::new_empty(mir.basic_blocks().len());
+ let dead_unwinds = BitSet::new_empty(mir.basic_blocks().len());
let flow_inits =
do_dataflow(tcx, mir, id, &attributes, &dead_unwinds,
MaybeInitializedPlaces::new(tcx, mir, &mdpe),
// Okay, our search is over.
match move_data.rev_lookup.find(peeking_at_place) {
LookupResult::Exact(peek_mpi) => {
- let bit_state = sets.on_entry.contains(&peek_mpi);
+ let bit_state = sets.on_entry.contains(peek_mpi);
debug!("rustc_peek({:?} = &{:?}) bit_state: {}",
place, peeking_at_place, bit_state);
if !bit_state {
//! naively generate still contains the `_a = ()` write in the unreachable block "after" the
//! return.
-use rustc_data_structures::bitvec::BitArray;
+use rustc_data_structures::bit_set::BitSet;
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
use rustc::ty::TyCtxt;
use rustc::mir::*;
}
pub fn remove_dead_blocks(mir: &mut Mir) {
- let mut seen = BitArray::new(mir.basic_blocks().len());
+ let mut seen = BitSet::new_empty(mir.basic_blocks().len());
for (bb, _) in traversal::preorder(mir) {
seen.insert(bb.index());
}
tcx: TyCtxt<'a, 'tcx, 'tcx>,
_: MirSource,
mir: &mut Mir<'tcx>) {
- let mut marker = DeclMarker { locals: BitArray::new(mir.local_decls.len()) };
+ let mut marker = DeclMarker { locals: BitSet::new_empty(mir.local_decls.len()) };
marker.visit_mir(mir);
// Return pointer and arguments are always live
marker.locals.insert(RETURN_PLACE);
/// Construct the mapping while swapping out unused stuff out from the `vec`.
fn make_local_map<'tcx, V>(
vec: &mut IndexVec<Local, V>,
- mask: BitArray<Local>,
+ mask: BitSet<Local>,
) -> IndexVec<Local, Option<Local>> {
let mut map: IndexVec<Local, Option<Local>> = IndexVec::from_elem(None, &*vec);
let mut used = Local::new(0);
}
struct DeclMarker {
- pub locals: BitArray<Local>,
+ pub locals: BitSet<Local>,
}
impl<'tcx> Visitor<'tcx> for DeclMarker {
use rustc::mir::Local;
use rustc::mir::*;
use rustc::ty::{item_path, TyCtxt};
-use rustc_data_structures::indexed_set::IdxSet;
+use rustc_data_structures::bit_set::BitSet;
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
use rustc_data_structures::work_queue::WorkQueue;
use std::fs;
use transform::MirSource;
use util::pretty::{dump_enabled, write_basic_block, write_mir_intro};
-pub type LiveVarSet<V> = IdxSet<V>;
+pub type LiveVarSet<V> = BitSet<V>;
/// This gives the result of the liveness analysis at the boundary of
/// basic blocks.
// X = 5
// // Defs = {}, Uses = {X}
// use(X)
- self.uses.remove(&index);
- self.defs.add(&index);
+ self.uses.remove(index);
+ self.defs.insert(index);
}
fn add_use(&mut self, index: V) {
// X = 5
// // Defs = {}, Uses = {X}
// use(X)
- self.defs.remove(&index);
- self.uses.add(&index);
+ self.defs.remove(index);
+ self.uses.insert(index);
}
}
);
if let Ok(snippet) = self.session.source_map().span_to_snippet(span) {
- err.span_suggestion(
+ err.span_suggestion_with_applicability(
span, "consider adding parentheses", format!("({})", snippet),
+ Applicability::MachineApplicable,
);
}
use rustc::hir::{self, Node, Destination};
use syntax::ast;
use syntax_pos::Span;
+use errors::Applicability;
#[derive(Clone, Copy, Debug, PartialEq)]
enum LoopKind {
.span_label(e.span,
"can only break with a value inside \
`loop` or breakable block")
- .span_suggestion(e.span,
- &format!("instead, use `break` on its own \
- without a value inside this `{}` loop",
- kind.name()),
- "break".to_string())
+ .span_suggestion_with_applicability(
+ e.span,
+ &format!(
+ "instead, use `break` on its own \
+ without a value inside this `{}` loop",
+ kind.name()
+ ),
+ "break".to_string(),
+ Applicability::MaybeIncorrect,
+ )
.emit();
}
}
use syntax::ast::{Item, ItemKind, ImplItem, ImplItemKind};
use syntax::ast::{Label, Local, Mutability, Pat, PatKind, Path};
use syntax::ast::{QSelf, TraitItemKind, TraitRef, Ty, TyKind};
-use syntax::feature_gate::{feature_err, GateIssue};
use syntax::ptr::P;
use syntax_pos::{Span, DUMMY_SP, MultiSpan};
ambiguity_errors: Vec<AmbiguityError<'a>>,
/// `use` injections are delayed for better placement and deduplication
use_injections: Vec<UseError<'a>>,
- /// `use` injections for proc macros wrongly imported with #[macro_use]
- proc_mac_errors: Vec<macros::ProcMacError>,
/// crate-local macro expanded `macro_export` referred to by a module-relative path
macro_expanded_macro_export_errors: BTreeSet<(Span, Span)>,
/// Avoid duplicated errors for "name already defined".
name_already_seen: FxHashMap<Name, Span>,
- /// A set of procedural macros imported by `#[macro_use]` that have already been warned about
- warned_proc_macros: FxHashSet<Name>,
-
potentially_unused_imports: Vec<&'a ImportDirective<'a>>,
/// This table maps struct IDs into struct constructor IDs,
current_type_ascription: Vec<Span>,
injected_crate: Option<Module<'a>>,
-
- /// Only supposed to be used by rustdoc, otherwise should be false.
- pub ignore_extern_prelude_feature: bool,
}
/// Nothing really interesting here, it just provides memory for the rest of the crate.
let mut extern_prelude: FxHashSet<Name> =
session.opts.externs.iter().map(|kv| Symbol::intern(kv.0)).collect();
- if !attr::contains_name(&krate.attrs, "no_core") {
- if !attr::contains_name(&krate.attrs, "no_std") {
- extern_prelude.insert(Symbol::intern("std"));
- } else {
- extern_prelude.insert(Symbol::intern("core"));
- }
- }
+
+ // HACK(eddyb) this ignore the `no_{core,std}` attributes.
+ // FIXME(eddyb) warn (elsewhere) if core/std is used with `no_{core,std}`.
+ // if !attr::contains_name(&krate.attrs, "no_core") {
+ // if !attr::contains_name(&krate.attrs, "no_std") {
+ extern_prelude.insert(Symbol::intern("core"));
+ extern_prelude.insert(Symbol::intern("std"));
+ extern_prelude.insert(Symbol::intern("meta"));
let mut invocations = FxHashMap();
invocations.insert(Mark::root(),
privacy_errors: Vec::new(),
ambiguity_errors: Vec::new(),
use_injections: Vec::new(),
- proc_mac_errors: Vec::new(),
macro_expanded_macro_export_errors: BTreeSet::new(),
arenas,
local_macro_def_scopes: FxHashMap(),
name_already_seen: FxHashMap(),
whitelisted_legacy_custom_derives: Vec::new(),
- warned_proc_macros: FxHashSet(),
potentially_unused_imports: Vec::new(),
struct_constructors: DefIdMap(),
found_unresolved_macro: false,
unused_macros: FxHashSet(),
current_type_ascription: Vec::new(),
injected_crate: None,
- ignore_extern_prelude_feature: false,
}
}
if !module.no_implicit_prelude {
// `record_used` means that we don't try to load crates during speculative resolution
if record_used && ns == TypeNS && self.extern_prelude.contains(&ident.name) {
- if !self.session.features_untracked().extern_prelude &&
- !self.ignore_extern_prelude_feature {
- feature_err(&self.session.parse_sess, "extern_prelude",
- ident.span, GateIssue::Language,
- "access to extern crates through prelude is experimental").emit();
- }
-
- let crate_root = self.load_extern_prelude_crate_if_needed(ident);
+ let crate_id = self.crate_loader.process_path_extern(ident.name, ident.span);
+ let crate_root = self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX });
+ self.populate_module_if_necessary(&crate_root);
let binding = (crate_root, ty::Visibility::Public,
ident.span, Mark::root()).to_name_binding(self.arenas);
None
}
- fn load_extern_prelude_crate_if_needed(&mut self, ident: Ident) -> Module<'a> {
- let crate_id = self.crate_loader.process_path_extern(ident.name, ident.span);
- let crate_root = self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX });
- self.populate_module_if_necessary(&crate_root);
- crate_root
- }
-
fn hygienic_lexical_parent(&mut self, module: Module<'a>, span: &mut Span)
-> Option<Module<'a>> {
if !module.expansion.is_descendant_of(span.ctxt().outer()) {
err.span_label(base_span,
"expecting a type here because of type ascription");
if line_sp != line_base_sp {
- err.span_suggestion_short(sp,
- "did you mean to use `;` here instead?",
- ";".to_string());
+ err.span_suggestion_short_with_applicability(
+ sp,
+ "did you mean to use `;` here instead?",
+ ";".to_string(),
+ Applicability::MaybeIncorrect,
+ );
}
break;
} else if snippet.trim().len() != 0 {
}
if name == keywords::Extern.name() ||
name == keywords::CrateRoot.name() &&
- self.session.features_untracked().extern_absolute_paths &&
self.session.rust_2018() {
module = Some(ModuleOrUniformRoot::UniformRoot(name));
continue;
return
}
- // In the 2015 edition there's no use in emitting lints unless the
- // crate's already enabled the feature that we're going to suggest
- if !self.session.features_untracked().crate_in_paths {
- return
- }
-
let (diag_id, diag_span) = match crate_lint {
CrateLint::No => return,
CrateLint::SimplePath(id) => (id, path_span),
)
);
- if self.session.features_untracked().extern_prelude {
+ if self.session.rust_2018() {
let extern_prelude_names = self.extern_prelude.clone();
- for &krate_name in extern_prelude_names.iter() {
- let krate_ident = Ident::with_empty_ctxt(krate_name);
- let external_prelude_module = self.load_extern_prelude_crate_if_needed(krate_ident);
+ for &name in extern_prelude_names.iter() {
+ let ident = Ident::with_empty_ctxt(name);
+ match self.crate_loader.maybe_process_path_extern(name, ident.span) {
+ Some(crate_id) => {
+ let crate_root = self.get_module(DefId {
+ krate: crate_id,
+ index: CRATE_DEF_INDEX,
+ });
+ self.populate_module_if_necessary(&crate_root);
- suggestions.extend(
- self.lookup_import_candidates_from_module(
- lookup_name, namespace, external_prelude_module, krate_ident, &filter_fn
- )
- );
+ suggestions.extend(
+ self.lookup_import_candidates_from_module(
+ lookup_name, namespace, crate_root, ident, &filter_fn
+ )
+ );
+ }
+ None => {}
+ }
}
}
fn report_errors(&mut self, krate: &Crate) {
self.report_with_use_injections(krate);
- self.report_proc_macro_import(krate);
let mut reported_spans = FxHashSet();
for &(span_use, span_def) in &self.macro_expanded_macro_export_errors {
*candidate = format!("use {};\n{}", candidate, additional_newline);
}
- err.span_suggestions(span, &msg, path_strings);
+ err.span_suggestions_with_applicability(
+ span,
+ &msg,
+ path_strings,
+ Applicability::Unspecified,
+ );
} else {
let mut msg = msg;
msg.push(':');
use rustc::hir::def::{Def, NonMacroAttrKind};
use rustc::hir::map::{self, DefCollector};
use rustc::{ty, lint};
-use rustc::middle::cstore::CrateStore;
use syntax::ast::{self, Name, Ident};
use syntax::attr;
use syntax::errors::DiagnosticBuilder;
use syntax::ext::base::{self, Determinacy, MultiModifier, MultiDecorator};
use syntax::ext::base::{MacroKind, SyntaxExtension, Resolver as SyntaxResolver};
-use syntax::ext::expand::{AstFragment, Invocation, InvocationKind};
+use syntax::ext::expand::{AstFragment, Invocation, InvocationKind, TogetherWith};
use syntax::ext::hygiene::{self, Mark};
use syntax::ext::tt::macro_rules;
use syntax::feature_gate::{self, feature_err, emit_feature_err, is_builtin_attr_name, GateIssue};
crate derives: Vec<ast::Path>,
}
-pub struct ProcMacError {
- crate_name: Symbol,
- name: Symbol,
- module: ast::NodeId,
- use_span: Span,
- warn_msg: &'static str,
-}
-
// Macro namespace is separated into two sub-namespaces, one for bang macros and
// one for attribute-like macros (attributes, derives).
// We ignore resolutions from one sub-namespace when searching names in scope for another.
fn resolve_macro_invocation(&mut self, invoc: &Invocation, invoc_id: Mark, force: bool)
-> Result<Option<Lrc<SyntaxExtension>>, Determinacy> {
- let (path, kind, derives_in_scope) = match invoc.kind {
+ let (path, kind, derives_in_scope, together_with) = match invoc.kind {
InvocationKind::Attr { attr: None, .. } =>
return Ok(None),
- InvocationKind::Attr { attr: Some(ref attr), ref traits, .. } =>
- (&attr.path, MacroKind::Attr, traits.clone()),
+ InvocationKind::Attr { attr: Some(ref attr), ref traits, together_with, .. } =>
+ (&attr.path, MacroKind::Attr, traits.clone(), together_with),
InvocationKind::Bang { ref mac, .. } =>
- (&mac.node.path, MacroKind::Bang, Vec::new()),
+ (&mac.node.path, MacroKind::Bang, Vec::new(), TogetherWith::None),
InvocationKind::Derive { ref path, .. } =>
- (path, MacroKind::Derive, Vec::new()),
+ (path, MacroKind::Derive, Vec::new(), TogetherWith::None),
};
let parent_scope = self.invoc_parent_scope(invoc_id, derives_in_scope);
let (def, ext) = self.resolve_macro_to_def(path, kind, &parent_scope, force)?;
if let Def::Macro(def_id, _) = def {
+ match together_with {
+ TogetherWith::Derive =>
+ self.session.span_err(invoc.span(),
+ "macro attributes must be placed before `#[derive]`"),
+ TogetherWith::TestBench if !self.session.features_untracked().plugin =>
+ self.session.span_err(invoc.span(),
+ "macro attributes cannot be used together with `#[test]` or `#[bench]`"),
+ _ => {}
+ }
self.macro_defs.insert(invoc.expansion_data.mark, def_id);
let normal_module_def_id =
self.macro_def_scope(invoc.expansion_data.mark).normal_ancestor_id;
}
WhereToResolve::ExternPrelude => {
if use_prelude && self.extern_prelude.contains(&ident.name) {
- if !self.session.features_untracked().extern_prelude &&
- !self.ignore_extern_prelude_feature {
- feature_err(&self.session.parse_sess, "extern_prelude",
- ident.span, GateIssue::Language,
- "access to extern crates through prelude is experimental")
- .emit();
- }
-
let crate_id =
self.crate_loader.process_path_extern(ident.name, ident.span);
let crate_root =
check_consistency(self, binding.def_ignoring_ambiguity());
if from_prelude {
self.record_use(ident, MacroNS, binding);
- self.err_if_macro_use_proc_macro(ident.name, span, binding);
}
}
};
}
}
- /// Error if `ext` is a Macros 1.1 procedural macro being imported by `#[macro_use]`
- fn err_if_macro_use_proc_macro(&mut self, name: Name, use_span: Span,
- binding: &NameBinding<'a>) {
- let krate = match binding.def() {
- Def::NonMacroAttr(..) | Def::Err => return,
- Def::Macro(def_id, _) => def_id.krate,
- _ => unreachable!(),
- };
-
- // Plugin-based syntax extensions are exempt from this check
- if krate == CrateNum::BuiltinMacros { return; }
-
- let ext = binding.get_macro(self);
-
- match *ext {
- // If `ext` is a procedural macro, check if we've already warned about it
- SyntaxExtension::AttrProcMacro(..) | SyntaxExtension::ProcMacro { .. } =>
- if !self.warned_proc_macros.insert(name) { return; },
- _ => return,
- }
-
- let warn_msg = match *ext {
- SyntaxExtension::AttrProcMacro(..) =>
- "attribute procedural macros cannot be imported with `#[macro_use]`",
- SyntaxExtension::ProcMacro { .. } =>
- "procedural macros cannot be imported with `#[macro_use]`",
- _ => return,
- };
-
- let def_id = self.current_module.normal_ancestor_id;
- let node_id = self.definitions.as_local_node_id(def_id).unwrap();
-
- self.proc_mac_errors.push(ProcMacError {
- crate_name: self.cstore.crate_name_untracked(krate),
- name,
- module: node_id,
- use_span,
- warn_msg,
- });
- }
-
- pub fn report_proc_macro_import(&mut self, krate: &ast::Crate) {
- for err in self.proc_mac_errors.drain(..) {
- let (span, found_use) = ::UsePlacementFinder::check(krate, err.module);
-
- if let Some(span) = span {
- let found_use = if found_use { "" } else { "\n" };
- self.session.struct_span_err(err.use_span, err.warn_msg)
- .span_suggestion_with_applicability(
- span,
- "instead, import the procedural macro like any other item",
- format!("use {}::{};{}", err.crate_name, err.name, found_use),
- Applicability::MachineApplicable
- ).emit();
- } else {
- self.session.struct_span_err(err.use_span, err.warn_msg)
- .help(&format!("instead, import the procedural macro like any other item: \
- `use {}::{};`", err.crate_name, err.name))
- .emit();
- }
- }
- }
-
fn gate_legacy_custom_derive(&mut self, name: Symbol, span: Span) {
if !self.session.features_untracked().custom_derive {
let sess = &self.session.parse_sess;
}
// Fall back to resolving to an external crate.
- if !(ns == TypeNS && self.extern_prelude.contains(&ident.name)) {
+ if !(
+ ns == TypeNS &&
+ !ident.is_path_segment_keyword() &&
+ self.extern_prelude.contains(&ident.name)
+ ) {
// ... unless the crate name is not in the `extern_prelude`.
return binding;
}
)
{
self.resolve_crate_root(ident)
- } else if ns == TypeNS && !ident.is_path_segment_keyword() {
+ } else if
+ ns == TypeNS &&
+ !ident.is_path_segment_keyword() &&
+ self.extern_prelude.contains(&ident.name)
+ {
let crate_id =
self.crate_loader.process_path_extern(ident.name, ident.span);
self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX })
// Currently imports can't resolve in non-module scopes,
// we only have canaries in them for future-proofing.
if external_crate.is_none() && results.module_scope.is_none() {
- return;
+ continue;
}
{
let possible_resultions =
1 + all_results.filter(|&def| def != first).count();
if possible_resultions <= 1 {
- return;
+ continue;
}
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use spec::{LinkerFlavor, Target, TargetResult, PanicStrategy, LldFlavor};
+use spec::{LinkerFlavor, Target, TargetResult, PanicStrategy};
pub fn target() -> TargetResult {
let mut base = super::windows_msvc_base::opts();
// FIXME: this shouldn't be panic=abort, it should be panic=unwind
base.panic_strategy = PanicStrategy::Abort;
- base.linker = Some("rust-lld".to_owned());
Ok(Target {
llvm_target: "aarch64-pc-windows-msvc".to_string(),
target_os: "windows".to_string(),
target_env: "msvc".to_string(),
target_vendor: "pc".to_string(),
- linker_flavor: LinkerFlavor::Lld(LldFlavor::Link),
+ linker_flavor: LinkerFlavor::Msvc,
options: base,
})
}
//! New recursive solver modeled on Chalk's recursive solver. Most of
//! the guts are broken up into modules; see the comments in those modules.
-#![feature(crate_in_paths)]
+#![cfg_attr(stage0, feature(crate_in_paths))]
#![feature(crate_visibility_modifier)]
-#![feature(extern_prelude)]
+#![cfg_attr(stage0, feature(extern_prelude))]
#![feature(in_band_lifetimes)]
#![cfg_attr(not(stage0), feature(nll))]
use super::FnCtxt;
-use errors::DiagnosticBuilder;
+use errors::{DiagnosticBuilder,Applicability};
use hir::def_id::DefId;
use lint;
use rustc::hir;
err.note("The type information given here is insufficient to check whether \
the pointer cast is valid");
if unknown_cast_to {
- err.span_suggestion_short(self.cast_span,
- "consider giving more type information",
- String::new());
+ err.span_suggestion_short_with_applicability(
+ self.cast_span,
+ "consider giving more type information",
+ String::new(),
+ Applicability::Unspecified,
+ );
}
err.emit();
}
if self.cast_ty.is_trait() {
match fcx.tcx.sess.source_map().span_to_snippet(self.cast_span) {
Ok(s) => {
- err.span_suggestion(self.cast_span,
- "try casting to a reference instead",
- format!("&{}{}", mtstr, s));
+ err.span_suggestion_with_applicability(
+ self.cast_span,
+ "try casting to a reference instead",
+ format!("&{}{}", mtstr, s),
+ Applicability::MachineApplicable,
+ );
}
Err(_) => {
span_help!(err, self.cast_span, "did you mean `&{}{}`?", mtstr, tstr)
ty::Adt(def, ..) if def.is_box() => {
match fcx.tcx.sess.source_map().span_to_snippet(self.cast_span) {
Ok(s) => {
- err.span_suggestion(self.cast_span,
- "try casting to a `Box` instead",
- format!("Box<{}>", s));
+ err.span_suggestion_with_applicability(
+ self.cast_span,
+ "try casting to a `Box` instead",
+ format!("Box<{}>", s),
+ Applicability::MachineApplicable,
+ );
}
Err(_) => span_help!(err, self.cast_span, "did you mean `Box<{}>`?", tstr),
}
.sig
.inputs()
.iter()
- .map(|ty| ArgKind::from_expected_ty(ty))
+ .map(|ty| ArgKind::from_expected_ty(ty, None))
.collect();
let (closure_span, found_args) = self.get_fn_like_arguments(expr_map_node);
let expected_span = expected_sig.cause_span.unwrap_or(closure_span);
use rustc::ty::error::{ExpectedFound, TypeError};
use rustc::ty::subst::{Subst, Substs};
use rustc::util::common::ErrorReported;
+use errors::Applicability;
use syntax_pos::Span;
if let Some(trait_err_span) = trait_err_span {
if let Ok(trait_err_str) = tcx.sess.source_map().
span_to_snippet(trait_err_span) {
- diag.span_suggestion(
+ diag.span_suggestion_with_applicability(
impl_err_span,
"consider change the type to match the mutability in trait",
format!("{}", trait_err_str),
+ Applicability::MachineApplicable,
);
}
}
.span_to_snippet(trait_m.generics.span)
.ok()?;
- err.multipart_suggestion(
+ err.multipart_suggestion_with_applicability(
"try changing the `impl Trait` argument to a generic parameter",
vec![
// replace `impl Trait` with `T`
// of the generics, but it works for the common case
(generics_span, new_generics),
],
+ Applicability::MaybeIncorrect,
);
Some(())
})();
.span_to_snippet(bounds)
.ok()?;
- err.multipart_suggestion(
+ err.multipart_suggestion_with_applicability(
"try removing the generic parameter and using `impl Trait` instead",
vec![
// delete generic parameters
// replace param usage with `impl Trait`
(span, format!("impl {}", bounds)),
],
+ Applicability::MaybeIncorrect,
);
Some(())
})();
let expr_text = print::to_string(print::NO_ANN, |s| s.print_expr(expr));
let suggestions = compatible_variants.iter()
.map(|v| format!("{}({})", v, expr_text)).collect::<Vec<_>>();
- err.span_suggestions(expr.span,
- "try using a variant of the expected type",
- suggestions);
+ err.span_suggestions_with_applicability(
+ expr.span,
+ "try using a variant of the expected type",
+ suggestions,
+ Applicability::MaybeIncorrect,
+ );
}
}
src,
if needs_paren { ")" } else { "" },
expected_ty);
- let into_suggestion = format!("{}{}{}.into()",
- if needs_paren { "(" } else { "" },
- src,
- if needs_paren { ")" } else { "" });
+ let into_suggestion = format!(
+ "{}{}{}.into()",
+ if needs_paren { "(" } else { "" },
+ src,
+ if needs_paren { ")" } else { "" },
+ );
+ let literal_is_ty_suffixed = |expr: &hir::Expr| {
+ if let hir::ExprKind::Lit(lit) = &expr.node {
+ lit.node.is_suffixed()
+ } else {
+ false
+ }
+ };
+
+ let into_sugg = into_suggestion.clone();
+ let suggest_to_change_suffix_or_into = |err: &mut DiagnosticBuilder,
+ note: Option<&str>| {
+ let suggest_msg = if literal_is_ty_suffixed(expr) {
+ format!(
+ "change the type of the numeric literal from `{}` to `{}`",
+ checked_ty,
+ expected_ty,
+ )
+ } else {
+ match note {
+ Some(note) => format!("{}, which {}", msg, note),
+ _ => format!("{} in a lossless way", msg),
+ }
+ };
+
+ let suffix_suggestion = format!(
+ "{}{}{}{}",
+ if needs_paren { "(" } else { "" },
+ src.trim_right_matches(&checked_ty.to_string()),
+ expected_ty,
+ if needs_paren { ")" } else { "" },
+ );
+
+ err.span_suggestion_with_applicability(
+ expr.span,
+ &suggest_msg,
+ if literal_is_ty_suffixed(expr) {
+ suffix_suggestion
+ } else {
+ into_sugg
+ },
+ Applicability::MachineApplicable,
+ );
+ };
match (&expected_ty.sty, &checked_ty.sty) {
(&ty::Int(ref exp), &ty::Int(ref found)) => {
}
}
_ => {
- err.span_suggestion_with_applicability(
- expr.span,
- &format!("{}, which {}", msg, will_sign_extend),
- into_suggestion,
- Applicability::MachineApplicable
+ suggest_to_change_suffix_or_into(
+ err,
+ Some(will_sign_extend),
);
}
}
}
}
_ => {
- err.span_suggestion_with_applicability(
- expr.span,
- &format!("{}, which {}", msg, will_zero_extend),
- into_suggestion,
- Applicability::MachineApplicable
- );
+ suggest_to_change_suffix_or_into(
+ err,
+ Some(will_zero_extend),
+ );
}
}
true
}
(&ty::Float(ref exp), &ty::Float(ref found)) => {
if found.bit_width() < exp.bit_width() {
- err.span_suggestion_with_applicability(
- expr.span,
- &format!("{} in a lossless way", msg),
- into_suggestion,
- Applicability::MachineApplicable
- );
+ suggest_to_change_suffix_or_into(
+ err,
+ None,
+ );
} else if can_cast {
err.span_suggestion_with_applicability(
expr.span,
"a method with this name may be added to the standard library in the future",
);
- // FIXME: This should be a `span_suggestion` instead of `help`. However `self.span` only
+ // FIXME: This should be a `span_suggestion_with_applicability` instead of `help`
+ // However `self.span` only
// highlights the method name, so we can't use it. Also consider reusing the code from
// `report_method_error()`.
diag.help(&format!(
let snippet = tcx.sess.source_map().span_to_snippet(lit.span)
.unwrap_or("<numeric literal>".to_string());
- err.span_suggestion(lit.span,
+ err.span_suggestion_with_applicability(
+ lit.span,
&format!("you must specify a concrete type for \
this numeric value, like `{}`",
concrete_type),
format!("{}_{}",
snippet,
- concrete_type));
+ concrete_type),
+ Applicability::MaybeIncorrect,
+ );
}
hir::ExprKind::Path(ref qpath) => { // local binding
if let &hir::QPath::Resolved(_, ref path) = &qpath {
ty,
..
})) => {
- err.span_suggestion(
+ err.span_suggestion_with_applicability(
// account for `let x: _ = 42;`
// ^^^^
span.to(ty.as_ref().map(|ty| ty.span)
.unwrap_or(span)),
&msg,
format!("{}: {}", snippet, concrete_type),
+ Applicability::MaybeIncorrect,
);
}
_ => {
format!("use {};\n{}", self.tcx.item_path_str(*did), additional_newline)
}).collect();
- err.span_suggestions(span, &msg, path_strings);
+ err.span_suggestions_with_applicability(
+ span,
+ &msg,
+ path_strings,
+ Applicability::MaybeIncorrect,
+ );
} else {
let limit = if candidates.len() == 5 { 5 } else { 4 };
for (i, trait_did) in candidates.iter().take(limit).enumerate() {
let body_id = item_id.and_then(|id| tcx.hir.maybe_body_owned_by(id));
let implicit_region_bound = body_id.map(|body_id| {
let body = tcx.hir.body(body_id);
- tcx.mk_region(ty::ReScope(region::Scope::CallSite(body.value.hir_id.local_id)))
+ tcx.mk_region(ty::ReScope(region::Scope {
+ id: body.value.hir_id.local_id,
+ data: region::ScopeData::CallSite
+ }))
});
Inherited {
}
};
}
+ ty::Array(_, len) => {
+ if let (Some(len), Ok(user_index)) = (
+ len.assert_usize(self.tcx),
+ field.as_str().parse::<u64>()
+ ) {
+ let base = self.tcx.hir.node_to_pretty_string(base.id);
+ let help = "instead of using tuple indexing, use array indexing";
+ let suggestion = format!("{}[{}]", base, field);
+ let applicability = if len < user_index {
+ Applicability::MachineApplicable
+ } else {
+ Applicability::MaybeIncorrect
+ };
+ err.span_suggestion_with_applicability(
+ expr.span, help, suggestion, applicability
+ );
+ }
+ }
ty::RawPtr(..) => {
let base = self.tcx.hir.node_to_pretty_string(base.id);
let msg = format!("`{}` is a native pointer; try dereferencing it", base);
let suggestion = format!("(*{}).{}", base, field);
- err.span_suggestion(field.span, &msg, suggestion);
+ err.span_suggestion_with_applicability(
+ field.span,
+ &msg,
+ suggestion,
+ Applicability::MaybeIncorrect,
+ );
}
_ => {}
}
found: Ty<'tcx>,
) {
if let Some((sp, msg, suggestion)) = self.check_ref(expr, found, expected) {
- err.span_suggestion(sp, msg, suggestion);
+ err.span_suggestion_with_applicability(
+ sp,
+ msg,
+ suggestion,
+ Applicability::MachineApplicable,
+ );
} else if !self.check_for_cast(err, expr, found, expected) {
let methods = self.get_conversion_methods(expr.span, expected, found);
if let Ok(expr_text) = self.sess().source_map().span_to_snippet(expr.span) {
}
}) .collect::<Vec<_>>();
if !suggestions.is_empty() {
- err.span_suggestions(expr.span, "try using a conversion method", suggestions);
+ err.span_suggestions_with_applicability(
+ expr.span,
+ "try using a conversion method",
+ suggestions,
+ Applicability::MaybeIncorrect,
+ );
}
}
}
use rustc::ty::TyKind::{Ref, Adt, Str, Uint, Never, Tuple, Char, Array};
use rustc::ty::adjustment::{Adjustment, Adjust, AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
use rustc::infer::type_variable::TypeVariableOrigin;
-use errors;
+use errors::{self,Applicability};
use syntax_pos::Span;
use syntax::ast::Ident;
use rustc::hir;
err.span_label(expr.span,
"`+` can't be used to concatenate two `&str` strings");
match source_map.span_to_snippet(lhs_expr.span) {
- Ok(lstring) => err.span_suggestion(lhs_expr.span,
- msg,
- format!("{}.to_owned()", lstring)),
+ Ok(lstring) => err.span_suggestion_with_applicability(
+ lhs_expr.span,
+ msg,
+ format!("{}.to_owned()", lstring),
+ Applicability::MachineApplicable,
+ ),
_ => err.help(msg),
};
}
is_assign,
) {
(Ok(l), Ok(r), false) => {
- err.multipart_suggestion(msg, vec![
- (lhs_expr.span, format!("{}.to_owned()", l)),
- (rhs_expr.span, format!("&{}", r)),
- ]);
+ err.multipart_suggestion_with_applicability(
+ msg,
+ vec![
+ (lhs_expr.span, format!("{}.to_owned()", l)),
+ (rhs_expr.span, format!("&{}", r)),
+ ],
+ Applicability::MachineApplicable,
+ );
}
_ => {
err.help(msg);
let body_id = body.id();
self.body_id = body_id.node_id;
- let call_site = region::Scope::CallSite(body.value.hir_id.local_id);
+ let call_site = region::Scope {
+ id: body.value.hir_id.local_id,
+ data: region::ScopeData::CallSite
+ };
self.call_site_scope = Some(call_site);
let fn_sig = {
&fn_sig_tys[..],
body_id.node_id,
span);
- self.link_fn_args(region::Scope::Node(body.value.hir_id.local_id), &body.arguments);
+ self.link_fn_args(
+ region::Scope {
+ id: body.value.hir_id.local_id,
+ data: region::ScopeData::Node
+ },
+ &body.arguments);
self.visit_body(body);
self.visit_region_obligations(body_id.node_id);
let expr_ty = self.resolve_node_type(expr.hir_id);
// the region corresponding to this expression
let expr_region = self.tcx.mk_region(ty::ReScope(
- region::Scope::Node(expr.hir_id.local_id)));
+ region::Scope {
+ id: expr.hir_id.local_id,
+ data: region::ScopeData::Node
+ }));
self.type_must_outlive(infer::ExprTypeIsNotInScope(expr_ty, expr.span),
expr_ty, expr_region);
// call occurs.
//
// FIXME(#6268) to support nested method calls, should be callee_id
- let callee_scope = region::Scope::Node(call_expr.hir_id.local_id);
+ let callee_scope = region::Scope {
+ id: call_expr.hir_id.local_id,
+ data: region::ScopeData::Node
+ };
let callee_region = self.tcx.mk_region(ty::ReScope(callee_scope));
debug!("callee_region={:?}", callee_region);
self.check_safety_of_rvalue_destructor_if_necessary(&cmt, expr.span);
let expr_region = self.tcx.mk_region(ty::ReScope(
- region::Scope::Node(expr.hir_id.local_id)));
+ region::Scope {
+ id: expr.hir_id.local_id,
+ data: region::ScopeData::Node
+ }));
for adjustment in adjustments {
debug!("constrain_adjustments: adjustment={:?}, cmt={:?}",
adjustment, cmt);
debug!("constrain_index(index_expr=?, indexed_ty={}",
self.ty_to_string(indexed_ty));
- let r_index_expr = ty::ReScope(region::Scope::Node(index_expr.hir_id.local_id));
+ let r_index_expr = ty::ReScope(region::Scope {
+ id: index_expr.hir_id.local_id,
+ data: region::ScopeData::Node
+ });
if let ty::Ref(r_ptr, r_ty, _) = indexed_ty.sty {
match r_ty.sty {
ty::Slice(_) | ty::Str => {
}
adjustment::AutoBorrow::RawPtr(m) => {
- let r = self.tcx.mk_region(ty::ReScope(region::Scope::Node(expr.hir_id.local_id)));
+ let r = self.tcx.mk_region(ty::ReScope(region::Scope {
+ id: expr.hir_id.local_id,
+ data: region::ScopeData::Node
+ }));
self.link_region(expr.span, r, ty::BorrowKind::from_mutbl(m), expr_cmt);
}
}
pulldown-cmark = { version = "0.1.2", default-features = false }
minifier = "0.0.19"
tempfile = "3"
+parking_lot = "0.6.4"
let real_name = name.clone().map(|name| Ident::from_str(&name));
let param_env = self.cx.tcx.param_env(def_id);
for &trait_def_id in self.cx.all_traits.iter() {
- if !self.cx.access_levels.borrow().is_doc_reachable(trait_def_id) ||
+ if !self.cx.renderinfo.borrow().access_levels.is_doc_reachable(trait_def_id) ||
self.cx.generated_synthetics
.borrow_mut()
.get(&(def_id, trait_def_id))
self,
GetDefId,
ToSource,
- get_auto_traits_with_def_id,
- get_blanket_impls_with_def_id,
};
use super::Clean;
let inner = match def {
Def::Trait(did) => {
record_extern_fqn(cx, did, clean::TypeKind::Trait);
- ret.extend(build_impls(cx, did, false));
+ ret.extend(build_impls(cx, did));
clean::TraitItem(build_external_trait(cx, did))
}
Def::Fn(did) => {
}
Def::Struct(did) => {
record_extern_fqn(cx, did, clean::TypeKind::Struct);
- ret.extend(build_impls(cx, did, true));
+ ret.extend(build_impls(cx, did));
clean::StructItem(build_struct(cx, did))
}
Def::Union(did) => {
record_extern_fqn(cx, did, clean::TypeKind::Union);
- ret.extend(build_impls(cx, did, true));
+ ret.extend(build_impls(cx, did));
clean::UnionItem(build_union(cx, did))
}
Def::TyAlias(did) => {
record_extern_fqn(cx, did, clean::TypeKind::Typedef);
- ret.extend(build_impls(cx, did, false));
+ ret.extend(build_impls(cx, did));
clean::TypedefItem(build_type_alias(cx, did), false)
}
Def::Enum(did) => {
record_extern_fqn(cx, did, clean::TypeKind::Enum);
- ret.extend(build_impls(cx, did, true));
+ ret.extend(build_impls(cx, did));
clean::EnumItem(build_enum(cx, did))
}
Def::ForeignTy(did) => {
record_extern_fqn(cx, did, clean::TypeKind::Foreign);
- ret.extend(build_impls(cx, did, false));
+ ret.extend(build_impls(cx, did));
clean::ForeignTypeItem
}
// Never inline enum variants but leave them shown as re-exports.
/// These names are used later on by HTML rendering to generate things like
/// source links back to the original item.
pub fn record_extern_fqn(cx: &DocContext, did: DefId, kind: clean::TypeKind) {
+ let mut crate_name = cx.tcx.crate_name(did.krate).to_string();
if did.is_local() {
- debug!("record_extern_fqn(did={:?}, kind+{:?}): def_id is local, aborting", did, kind);
- return;
+ crate_name = cx.crate_name.clone().unwrap_or(crate_name);
}
- let crate_name = cx.tcx.crate_name(did.krate).to_string();
let relative = cx.tcx.def_path(did).data.into_iter().filter_map(|elem| {
// extern blocks have an empty name
let s = elem.data.to_string();
} else {
once(crate_name).chain(relative).collect()
};
- cx.renderinfo.borrow_mut().external_paths.insert(did, (fqn, kind));
+
+ if did.is_local() {
+ cx.renderinfo.borrow_mut().exact_paths.insert(did, fqn);
+ } else {
+ cx.renderinfo.borrow_mut().external_paths.insert(did, (fqn, kind));
+ }
}
pub fn build_external_trait(cx: &DocContext, did: DefId) -> clean::Trait {
}
}
-pub fn build_impls(cx: &DocContext, did: DefId, auto_traits: bool) -> Vec<clean::Item> {
+pub fn build_impls(cx: &DocContext, did: DefId) -> Vec<clean::Item> {
let tcx = cx.tcx;
let mut impls = Vec::new();
build_impl(cx, did, &mut impls);
}
- if auto_traits {
- let auto_impls = get_auto_traits_with_def_id(cx, did);
- {
- let mut renderinfo = cx.renderinfo.borrow_mut();
- let new_impls: Vec<clean::Item> = auto_impls.into_iter()
- .filter(|i| renderinfo.inlined.insert(i.def_id)).collect();
-
- impls.extend(new_impls);
- }
- impls.extend(get_blanket_impls_with_def_id(cx, did));
- }
-
- // If this is the first time we've inlined something from another crate, then
- // we inline *all* impls from all the crates into this crate. Note that there's
- // currently no way for us to filter this based on type, and we likely need
- // many impls for a variety of reasons.
- //
- // Primarily, the impls will be used to populate the documentation for this
- // type being inlined, but impls can also be used when generating
- // documentation for primitives (no way to find those specifically).
- if cx.populated_all_crate_impls.get() {
- return impls;
- }
-
- cx.populated_all_crate_impls.set(true);
-
- for &cnum in tcx.crates().iter() {
- for did in tcx.all_trait_implementations(cnum).iter() {
- build_impl(cx, *did, &mut impls);
- }
- }
-
- // Also try to inline primitive impls from other crates.
- let lang_items = tcx.lang_items();
- let primitive_impls = [
- lang_items.isize_impl(),
- lang_items.i8_impl(),
- lang_items.i16_impl(),
- lang_items.i32_impl(),
- lang_items.i64_impl(),
- lang_items.i128_impl(),
- lang_items.usize_impl(),
- lang_items.u8_impl(),
- lang_items.u16_impl(),
- lang_items.u32_impl(),
- lang_items.u64_impl(),
- lang_items.u128_impl(),
- lang_items.f32_impl(),
- lang_items.f64_impl(),
- lang_items.f32_runtime_impl(),
- lang_items.f64_runtime_impl(),
- lang_items.char_impl(),
- lang_items.str_impl(),
- lang_items.slice_impl(),
- lang_items.slice_u8_impl(),
- lang_items.str_alloc_impl(),
- lang_items.slice_alloc_impl(),
- lang_items.slice_u8_alloc_impl(),
- lang_items.const_ptr_impl(),
- lang_items.mut_ptr_impl(),
- ];
-
- for def_id in primitive_impls.iter().filter_map(|&def_id| def_id) {
- if !def_id.is_local() {
- build_impl(cx, def_id, &mut impls);
-
- let auto_impls = get_auto_traits_with_def_id(cx, def_id);
- let blanket_impls = get_blanket_impls_with_def_id(cx, def_id);
- let mut renderinfo = cx.renderinfo.borrow_mut();
-
- let new_impls: Vec<clean::Item> = auto_impls.into_iter()
- .chain(blanket_impls.into_iter())
- .filter(|i| renderinfo.inlined.insert(i.def_id))
- .collect();
-
- impls.extend(new_impls);
- }
- }
-
impls
}
// Only inline impl if the implemented trait is
// reachable in rustdoc generated documentation
- if let Some(traitref) = associated_trait {
- if !cx.access_levels.borrow().is_doc_reachable(traitref.def_id) {
- return
+ if !did.is_local() {
+ if let Some(traitref) = associated_trait {
+ if !cx.renderinfo.borrow().access_levels.is_doc_reachable(traitref.def_id) {
+ return
+ }
}
}
- let for_ = tcx.type_of(did).clean(cx);
+ let for_ = if let Some(nodeid) = tcx.hir.as_local_node_id(did) {
+ match tcx.hir.expect_item(nodeid).node {
+ hir::ItemKind::Impl(.., ref t, _) => {
+ t.clean(cx)
+ }
+ _ => panic!("did given to build_impl was not an impl"),
+ }
+ } else {
+ tcx.type_of(did).clean(cx)
+ };
// Only inline impl if the implementing type is
// reachable in rustdoc generated documentation
- if let Some(did) = for_.def_id() {
- if !cx.access_levels.borrow().is_doc_reachable(did) {
- return
+ if !did.is_local() {
+ if let Some(did) = for_.def_id() {
+ if !cx.renderinfo.borrow().access_levels.is_doc_reachable(did) {
+ return
+ }
}
}
let predicates = tcx.predicates_of(did);
- let trait_items = tcx.associated_items(did).filter_map(|item| {
- if associated_trait.is_some() || item.vis == ty::Visibility::Public {
- Some(item.clean(cx))
- } else {
- None
+ let (trait_items, generics) = if let Some(nodeid) = tcx.hir.as_local_node_id(did) {
+ match tcx.hir.expect_item(nodeid).node {
+ hir::ItemKind::Impl(.., ref gen, _, _, ref item_ids) => {
+ (
+ item_ids.iter()
+ .map(|ii| tcx.hir.impl_item(ii.id).clean(cx))
+ .collect::<Vec<_>>(),
+ gen.clean(cx),
+ )
+ }
+ _ => panic!("did given to build_impl was not an impl"),
}
- }).collect::<Vec<_>>();
+ } else {
+ (
+ tcx.associated_items(did).filter_map(|item| {
+ if associated_trait.is_some() || item.vis == ty::Visibility::Public {
+ Some(item.clean(cx))
+ } else {
+ None
+ }
+ }).collect::<Vec<_>>(),
+ (tcx.generics_of(did), &predicates).clean(cx),
+ )
+ };
let polarity = tcx.impl_polarity(did);
let trait_ = associated_trait.clean(cx).map(|bound| {
match bound {
.collect()
}).unwrap_or(FxHashSet());
+ debug!("build_impl: impl {:?} for {:?}", trait_.def_id(), for_.def_id());
+
ret.push(clean::Item {
inner: clean::ImplItem(clean::Impl {
unsafety: hir::Unsafety::Normal,
- generics: (tcx.generics_of(did), &predicates).clean(cx),
+ generics,
provided_trait_methods: provided,
trait_,
for_,
}
pub fn print_inlined_const(cx: &DocContext, did: DefId) -> String {
- cx.tcx.rendered_const(did)
+ if let Some(node_id) = cx.tcx.hir.as_local_node_id(did) {
+ cx.tcx.hir.node_to_pretty_string(node_id)
+ } else {
+ cx.tcx.rendered_const(did)
+ }
}
fn build_const(cx: &DocContext, did: DefId) -> clean::Constant {
}
pub fn record_extern_trait(cx: &DocContext, did: DefId) {
- if cx.external_traits.borrow().contains_key(&did) ||
- cx.active_extern_traits.borrow().contains(&did)
- {
+ if did.is_local() {
return;
}
+ {
+ let external_traits = cx.external_traits.lock();
+ if external_traits.borrow().contains_key(&did) ||
+ cx.active_extern_traits.borrow().contains(&did)
+ {
+ return;
+ }
+ }
+
cx.active_extern_traits.borrow_mut().push(did);
+ debug!("record_extern_trait: {:?}", did);
let trait_ = build_external_trait(cx, did);
- cx.external_traits.borrow_mut().insert(did, trait_);
+ {
+ let external_traits = cx.external_traits.lock();
+ external_traits.borrow_mut().insert(did, trait_);
+ }
cx.active_extern_traits.borrow_mut().remove_item(&did);
}
use syntax_pos::{self, DUMMY_SP, Pos, FileName};
use rustc::mir::interpret::ConstValue;
-use rustc::middle::privacy::AccessLevels;
use rustc::middle::resolve_lifetime as rl;
use rustc::ty::fold::TypeFolder;
use rustc::middle::lang_items;
use std::sync::Arc;
use std::u32;
+use parking_lot::ReentrantMutex;
+
use core::{self, DocContext};
use doctree;
use visit_ast;
pub module: Option<Item>,
pub externs: Vec<(CrateNum, ExternalCrate)>,
pub primitives: Vec<(DefId, PrimitiveType, Attributes)>,
- pub access_levels: Arc<AccessLevels<DefId>>,
// These are later on moved into `CACHEKEY`, leaving the map empty.
// Only here so that they can be filtered through the rustdoc passes.
- pub external_traits: FxHashMap<DefId, Trait>,
+ pub external_traits: Arc<ReentrantMutex<RefCell<FxHashMap<DefId, Trait>>>>,
pub masked_crates: FxHashSet<CrateNum>,
}
}));
}
- let mut access_levels = cx.access_levels.borrow_mut();
- let mut external_traits = cx.external_traits.borrow_mut();
-
Crate {
name,
version: None,
module: Some(module),
externs,
primitives,
- access_levels: Arc::new(mem::replace(&mut access_levels, Default::default())),
- external_traits: mem::replace(&mut external_traits, Default::default()),
+ external_traits: cx.external_traits.clone(),
masked_crates,
}
}
let mut items: Vec<Item> = vec![];
items.extend(self.extern_crates.iter().map(|x| x.clean(cx)));
items.extend(self.imports.iter().flat_map(|x| x.clean(cx)));
- items.extend(self.structs.iter().flat_map(|x| x.clean(cx)));
- items.extend(self.unions.iter().flat_map(|x| x.clean(cx)));
- items.extend(self.enums.iter().flat_map(|x| x.clean(cx)));
+ items.extend(self.structs.iter().map(|x| x.clean(cx)));
+ items.extend(self.unions.iter().map(|x| x.clean(cx)));
+ items.extend(self.enums.iter().map(|x| x.clean(cx)));
items.extend(self.fns.iter().map(|x| x.clean(cx)));
items.extend(self.foreigns.iter().flat_map(|x| x.clean(cx)));
items.extend(self.mods.iter().map(|x| x.clean(cx)));
if let Def::TyAlias(def_id) = path.def {
// Substitute private type aliases
if let Some(node_id) = cx.tcx.hir.as_local_node_id(def_id) {
- if !cx.access_levels.borrow().is_exported(def_id) {
+ if !cx.renderinfo.borrow().access_levels.is_exported(def_id) {
alias = Some(&cx.tcx.hir.expect_item(node_id).node);
}
}
pub fields_stripped: bool,
}
-impl Clean<Vec<Item>> for doctree::Struct {
- fn clean(&self, cx: &DocContext) -> Vec<Item> {
- let name = self.name.clean(cx);
- let mut ret = get_auto_traits_with_node_id(cx, self.id, name.clone());
- ret.extend(get_blanket_impls_with_node_id(cx, self.id, name.clone()));
-
- ret.push(Item {
- name: Some(name),
+impl Clean<Item> for doctree::Struct {
+ fn clean(&self, cx: &DocContext) -> Item {
+ Item {
+ name: Some(self.name.clean(cx)),
attrs: self.attrs.clean(cx),
source: self.whence.clean(cx),
def_id: cx.tcx.hir.local_def_id(self.id),
fields: self.fields.clean(cx),
fields_stripped: false,
}),
- });
-
- ret
+ }
}
}
-impl Clean<Vec<Item>> for doctree::Union {
- fn clean(&self, cx: &DocContext) -> Vec<Item> {
- let name = self.name.clean(cx);
- let mut ret = get_auto_traits_with_node_id(cx, self.id, name.clone());
- ret.extend(get_blanket_impls_with_node_id(cx, self.id, name.clone()));
-
- ret.push(Item {
- name: Some(name),
+impl Clean<Item> for doctree::Union {
+ fn clean(&self, cx: &DocContext) -> Item {
+ Item {
+ name: Some(self.name.clean(cx)),
attrs: self.attrs.clean(cx),
source: self.whence.clean(cx),
def_id: cx.tcx.hir.local_def_id(self.id),
fields: self.fields.clean(cx),
fields_stripped: false,
}),
- });
-
- ret
+ }
}
}
pub variants_stripped: bool,
}
-impl Clean<Vec<Item>> for doctree::Enum {
- fn clean(&self, cx: &DocContext) -> Vec<Item> {
- let name = self.name.clean(cx);
- let mut ret = get_auto_traits_with_node_id(cx, self.id, name.clone());
- ret.extend(get_blanket_impls_with_node_id(cx, self.id, name.clone()));
-
- ret.push(Item {
- name: Some(name),
+impl Clean<Item> for doctree::Enum {
+ fn clean(&self, cx: &DocContext) -> Item {
+ Item {
+ name: Some(self.name.clean(cx)),
attrs: self.attrs.clean(cx),
source: self.whence.clean(cx),
def_id: cx.tcx.hir.local_def_id(self.id),
generics: self.generics.clean(cx),
variants_stripped: false,
}),
- });
-
- ret
+ }
}
}
let primitive = match *target {
ResolvedPath { did, .. } if did.is_local() => continue,
ResolvedPath { did, .. } => {
- // We set the last parameter to false to avoid looking for auto-impls for traits
- // and therefore avoid an ICE.
- // The reason behind this is that auto-traits don't propagate through Deref so
- // we're not supposed to synthesise impls for them.
- ret.extend(inline::build_impls(cx, did, false));
+ ret.extend(inline::build_impls(cx, did));
continue
}
_ => match target.primitive_type() {
use rustc_metadata::cstore::CStore;
use rustc_target::spec::TargetTriple;
-use syntax::ast::{self, Ident};
+use syntax::ast::{self, Ident, NodeId};
use syntax::source_map;
use syntax::edition::Edition;
use syntax::feature_gate::UnstableFeatures;
use syntax_pos::DUMMY_SP;
use errors;
use errors::emitter::{Emitter, EmitterWriter};
+use parking_lot::ReentrantMutex;
-use std::cell::{RefCell, Cell};
+use std::cell::RefCell;
use std::mem;
use rustc_data_structures::sync::{self, Lrc};
use std::rc::Rc;
+use std::sync::Arc;
use std::path::PathBuf;
use visit_ast::RustdocVisitor;
/// The stack of module NodeIds up till this point
pub crate_name: Option<String>,
pub cstore: Rc<CStore>,
- pub populated_all_crate_impls: Cell<bool>,
// Note that external items for which `doc(hidden)` applies to are shown as
// non-reachable while local items aren't. This is because we're reusing
// the access levels from crateanalysis.
- /// Later on moved into `clean::Crate`
- pub access_levels: RefCell<AccessLevels<DefId>>,
/// Later on moved into `html::render::CACHE_KEY`
pub renderinfo: RefCell<RenderInfo>,
/// Later on moved through `clean::Crate` into `html::render::CACHE_KEY`
- pub external_traits: RefCell<FxHashMap<DefId, clean::Trait>>,
+ pub external_traits: Arc<ReentrantMutex<RefCell<FxHashMap<DefId, clean::Trait>>>>,
/// Used while populating `external_traits` to ensure we don't process the same trait twice at
/// the same time.
pub active_extern_traits: RefCell<Vec<DefId>>,
def_id.clone()
}
+ /// Like the function of the same name on the HIR map, but skips calling it on fake DefIds.
+ /// (This avoids a slice-index-out-of-bounds panic.)
+ pub fn as_local_node_id(&self, def_id: DefId) -> Option<NodeId> {
+ if self.all_fake_def_ids.borrow().contains(&def_id) {
+ None
+ } else {
+ self.tcx.hir.as_local_node_id(def_id)
+ }
+ }
+
pub fn get_real_ty<F>(&self,
def_id: DefId,
def_ctor: &F,
///
/// If the given `error_format` is `ErrorOutputType::Json` and no `SourceMap` is given, a new one
/// will be created for the handler.
-pub fn new_handler(error_format: ErrorOutputType, source_map: Option<Lrc<source_map::SourceMap>>)
- -> errors::Handler
-{
+pub fn new_handler(error_format: ErrorOutputType,
+ source_map: Option<Lrc<source_map::SourceMap>>,
+ treat_err_as_bug: bool,
+) -> errors::Handler {
// rustdoc doesn't override (or allow to override) anything from this that is relevant here, so
// stick to the defaults
let sessopts = Options::default();
emitter,
errors::HandlerFlags {
can_emit_warnings: true,
- treat_err_as_bug: false,
+ treat_err_as_bug,
report_delayed_bugs: false,
external_macro_backtrace: false,
..Default::default()
lint_cap: Option<lint::Level>,
describe_lints: bool,
mut manual_passes: Vec<String>,
- mut default_passes: passes::DefaultPassOption)
- -> (clean::Crate, RenderInfo, Vec<String>)
-{
+ mut default_passes: passes::DefaultPassOption,
+ treat_err_as_bug: bool,
+) -> (clean::Crate, RenderInfo, Vec<String>) {
// Parse, resolve, and typecheck the given crate.
let cpath = match input {
};
driver::spawn_thread_pool(sessopts, move |sessopts| {
let source_map = Lrc::new(source_map::SourceMap::new(sessopts.file_path_mapping()));
- let diagnostic_handler = new_handler(error_format, Some(source_map.clone()));
+ let diagnostic_handler = new_handler(error_format,
+ Some(source_map.clone()),
+ treat_err_as_bug);
let mut sess = session::build_session_(
sessopts, cpath, diagnostic_handler, source_map,
|_| Ok(()));
let driver::InnerExpansionResult {
mut hir_forest,
- mut resolver,
+ resolver,
..
} = abort_on_err(result, &sess);
- resolver.ignore_extern_prelude_feature = true;
-
// We need to hold on to the complete resolver, so we clone everything
// for the analysis passes to use. Suboptimal, but necessary in the
// current architecture.
clean::path_to_def(&tcx, &["core", "marker", "Send"])
};
+ let mut renderinfo = RenderInfo::default();
+ renderinfo.access_levels = access_levels;
+
let ctxt = DocContext {
tcx,
resolver: &resolver,
crate_name,
cstore: cstore.clone(),
- populated_all_crate_impls: Cell::new(false),
- access_levels: RefCell::new(access_levels),
external_traits: Default::default(),
active_extern_traits: Default::default(),
- renderinfo: Default::default(),
+ renderinfo: RefCell::new(renderinfo),
ty_substs: Default::default(),
lt_substs: Default::default(),
impl_trait_bounds: Default::default(),
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::mem;
-
use clean::*;
pub struct StripItem(pub Item);
fn fold_crate(&mut self, mut c: Crate) -> Crate {
c.module = c.module.take().and_then(|module| self.fold_item(module));
- let traits = mem::replace(&mut c.external_traits, Default::default());
- c.external_traits.extend(traits.into_iter().map(|(k, mut v)| {
- v.items = v.items.into_iter().filter_map(|i| self.fold_item(i)).collect();
- (k, v)
- }));
+ {
+ let guard = c.external_traits.lock();
+ let traits = guard.replace(Default::default());
+ guard.borrow_mut().extend(traits.into_iter().map(|(k, mut v)| {
+ v.items = v.items.into_iter().filter_map(|i| self.fold_item(i)).collect();
+ (k, v)
+ }));
+ }
c
}
}
// Note that external items for which `doc(hidden)` applies to are shown as
// non-reachable while local items aren't. This is because we're reusing
// the access levels from crateanalysis.
- pub access_levels: Arc<AccessLevels<DefId>>,
+ pub access_levels: AccessLevels<DefId>,
/// The version of the crate being documented, if given from the `--crate-version` flag.
pub crate_version: Option<String>,
// and their parent id here and indexes them at the end of crate parsing.
orphan_impl_items: Vec<(DefId, clean::Item)>,
+ // Similarly to `orphan_impl_items`, sometimes trait impls are picked up
+ // even though the trait itself is not exported. This can happen if a trait
+ // was defined in function/expression scope, since the impl will be picked
+ // up by `collect-trait-impls` but the trait won't be scraped out in the HIR
+ // crawl. In order to prevent crashes when looking for spotlight traits or
+ // when gathering trait documentation on a type, hold impls here while
+ // folding and add them to the cache later on if we find the trait.
+ orphan_trait_impls: Vec<(DefId, FxHashSet<DefId>, Impl)>,
+
/// Aliases added through `#[doc(alias = "...")]`. Since a few items can have the same alias,
/// we need the alias element to have an array of items.
aliases: FxHashMap<String, Vec<IndexItem>>,
pub external_paths: ::core::ExternalPaths,
pub external_typarams: FxHashMap<DefId, String>,
pub exact_paths: FxHashMap<DefId, Vec<String>>,
+ pub access_levels: AccessLevels<DefId>,
pub deref_trait_did: Option<DefId>,
pub deref_mut_trait_did: Option<DefId>,
pub owned_box_did: Option<DefId>,
external_paths,
external_typarams,
exact_paths,
+ access_levels,
deref_trait_did,
deref_mut_trait_did,
owned_box_did,
extern_locations: FxHashMap(),
primitive_locations: FxHashMap(),
stripped_mod: false,
- access_levels: krate.access_levels.clone(),
+ access_levels,
crate_version: krate.version.take(),
orphan_impl_items: Vec::new(),
- traits: mem::replace(&mut krate.external_traits, FxHashMap()),
+ orphan_trait_impls: Vec::new(),
+ traits: krate.external_traits.lock().replace(FxHashMap()),
deref_trait_did,
deref_mut_trait_did,
owned_box_did,
cache.stack.push(krate.name.clone());
krate = cache.fold_crate(krate);
+ for (trait_did, dids, impl_) in cache.orphan_trait_impls.drain(..) {
+ if cache.traits.contains_key(&trait_did) {
+ for did in dids {
+ cache.impls.entry(did).or_insert(vec![]).push(impl_.clone());
+ }
+ }
+ }
+
// Build our search index
let index = build_index(&krate, &mut cache);
impl DocFolder for Cache {
fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
+ if item.def_id.is_local() {
+ debug!("folding {} \"{:?}\", id {:?}", item.type_(), item.name, item.def_id);
+ }
+
// If this is a stripped module,
// we don't want it or its children in the search index.
let orig_stripped_mod = match item.inner {
} else {
unreachable!()
};
- for did in dids {
- self.impls.entry(did).or_default().push(Impl {
- impl_item: item.clone(),
- });
+ let impl_item = Impl {
+ impl_item: item,
+ };
+ if impl_item.trait_did().map_or(true, |d| self.traits.contains_key(&d)) {
+ for did in dids {
+ self.impls.entry(did).or_insert(vec![]).push(impl_item.clone());
+ }
+ } else {
+ let trait_did = impl_item.trait_did().unwrap();
+ self.orphan_trait_impls.push((trait_did, dids, impl_item));
}
None
} else {
*slot.borrow_mut() = self.current.clone();
});
- let mut title = if it.is_primitive() {
- // No need to include the namespace for primitive types
+ let mut title = if it.is_primitive() || it.is_keyword() {
+ // No need to include the namespace for primitive types and keywords
String::new()
} else {
self.current.join("::")
}
fn name_key(name: &str) -> (&str, u64, usize) {
+ let end = name.bytes()
+ .rposition(|b| b.is_ascii_digit()).map_or(name.len(), |i| i + 1);
+
// find number at end
- let split = name.bytes().rposition(|b| b < b'0' || b'9' < b).map_or(0, |s| s + 1);
+ let split = name[0..end].bytes()
+ .rposition(|b| !b.is_ascii_digit()).map_or(0, |i| i + 1);
// count leading zeroes
let after_zeroes =
- name[split..].bytes().position(|b| b != b'0').map_or(name.len(), |extra| split + extra);
+ name[split..end].bytes().position(|b| b != b'0').map_or(name.len(), |extra| split + extra);
// sort leading zeroes last
let num_zeroes = after_zeroes - split;
- match name[split..].parse() {
+ match name[split..end].parse() {
Ok(n) => (&name[..split], n, num_zeroes),
Err(_) => (name, 0, num_zeroes),
}
bounds
}
+fn compare_impl<'a, 'b>(lhs: &'a &&Impl, rhs: &'b &&Impl) -> Ordering {
+ let lhs = format!("{}", lhs.inner_impl());
+ let rhs = format!("{}", rhs.inner_impl());
+
+ // lhs and rhs are formatted as HTML, which may be unnecessary
+ name_key(&lhs).cmp(&name_key(&rhs))
+}
+
fn item_trait(
w: &mut fmt::Formatter,
cx: &Context,
.map_or(true, |d| cache.paths.contains_key(&d)));
- let (synthetic, concrete): (Vec<&&Impl>, Vec<&&Impl>) = local.iter()
+ let (mut synthetic, mut concrete): (Vec<&&Impl>, Vec<&&Impl>) = local.iter()
.partition(|i| i.inner_impl().synthetic);
+ synthetic.sort_by(compare_impl);
+ concrete.sort_by(compare_impl);
+
if !foreign.is_empty() {
write!(w, "
<h2 id='foreign-impls' class='small-section-header'>
"Fruit1", "Fruit01",
"Fruit2", "Fruit02",
"Fruit20",
+ "Fruit30x",
"Fruit100",
"Pear"];
let mut sorted = names.to_owned();
#![feature(ptr_offset_from)]
#![feature(crate_visibility_modifier)]
#![feature(const_fn)]
+#![feature(drain_filter)]
#![recursion_limit="256"]
extern crate pulldown_cmark;
extern crate tempfile;
extern crate minifier;
+extern crate parking_lot;
extern crate serialize as rustc_serialize; // used by deriving
`short` (instead was `{}`)", arg));
}
};
+ let treat_err_as_bug = matches.opt_strs("Z").iter().any(|x| {
+ *x == "treat-err-as-bug"
+ });
- let diag = core::new_handler(error_format, None);
+ let diag = core::new_handler(error_format, None, treat_err_as_bug);
// check for deprecated options
check_deprecated_options(&matches, &diag);
let res = acquire_input(PathBuf::from(input), externs, edition, cg, &matches, error_format,
move |out| {
let Output { krate, passes, renderinfo } = out;
- let diag = core::new_handler(error_format, None);
+ let diag = core::new_handler(error_format, None, treat_err_as_bug);
info!("going to format");
match output_format.as_ref().map(|s| &**s) {
Some("html") | None => {
/// Extracts `--extern CRATE=PATH` arguments from `matches` and
/// returns a map mapping crate names to their paths or else an
/// error message.
+// FIXME(eddyb) This shouldn't be duplicated with `rustc::session`.
fn parse_externs(matches: &getopts::Matches) -> Result<Externs, String> {
let mut externs: BTreeMap<_, BTreeSet<_>> = BTreeMap::new();
for arg in &matches.opt_strs("extern") {
let mut parts = arg.splitn(2, '=');
let name = parts.next().ok_or("--extern value must not be empty".to_string())?;
- let location = parts.next()
- .ok_or("--extern value must be of the format `foo=bar`"
- .to_string())?;
+ let location = parts.next().map(|s| s.to_string());
+ if location.is_none() && !nightly_options::is_unstable_enabled(matches) {
+ return Err("the `-Z unstable-options` flag must also be passed to \
+ enable `--extern crate_name` without `=path`".to_string());
+ }
let name = name.to_string();
- externs.entry(name).or_default().insert(location.to_string());
+ externs.entry(name).or_default().insert(location);
}
Ok(Externs::new(externs))
}
let force_unstable_if_unmarked = matches.opt_strs("Z").iter().any(|x| {
*x == "force-unstable-if-unmarked"
});
+ let treat_err_as_bug = matches.opt_strs("Z").iter().any(|x| {
+ *x == "treat-err-as-bug"
+ });
let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
core::run_core(paths, cfgs, externs, Input::File(cratefile), triple, maybe_sysroot,
display_warnings, crate_name.clone(),
force_unstable_if_unmarked, edition, cg, error_format,
- lint_opts, lint_cap, describe_lints, manual_passes, default_passes);
+ lint_opts, lint_cap, describe_lints, manual_passes, default_passes,
+ treat_err_as_bug);
info!("finished with rustc");
/// Resolve a given string as a path, along with whether or not it is
/// in the value namespace. Also returns an optional URL fragment in the case
/// of variants and methods
- fn resolve(&self, path_str: &str, is_val: bool, current_item: &Option<String>)
+ fn resolve(&self,
+ path_str: &str,
+ is_val: bool,
+ current_item: &Option<String>,
+ parent_id: Option<NodeId>)
-> Result<(Def, Option<String>), ()>
{
let cx = self.cx;
// In case we're in a module, try to resolve the relative
// path
- if let Some(id) = self.mod_ids.last() {
+ if let Some(id) = parent_id.or(self.mod_ids.last().cloned()) {
+ // FIXME: `with_scope` requires the NodeId of a module
let result = cx.resolver.borrow_mut()
- .with_scope(*id,
+ .with_scope(id,
|resolver| {
resolver.resolve_str_path_error(DUMMY_SP,
&path_str, is_val)
}
}
+ // FIXME: `with_scope` requires the NodeId of a module
let ty = cx.resolver.borrow_mut()
- .with_scope(*id,
+ .with_scope(id,
|resolver| {
resolver.resolve_str_path_error(DUMMY_SP, &path, false)
})?;
None
};
+ // FIXME: get the resolver to work with non-local resolve scopes
+ let parent_node = self.cx.as_local_node_id(item.def_id).and_then(|node_id| {
+ // FIXME: this fails hard for impls in non-module scope, but is necessary for the
+ // current resolve() implementation
+ match self.cx.tcx.hir.get_module_parent_node(node_id) {
+ id if id != node_id => Some(id),
+ _ => None,
+ }
+ });
+
+ if parent_node.is_some() {
+ debug!("got parent node for {} {:?}, id {:?}", item.type_(), item.name, item.def_id);
+ }
+
let current_item = match item.inner {
ModuleItem(..) => {
if item.attrs.inner_docs {
None
}
} else {
- match self.mod_ids.last() {
- Some(parent) if *parent != NodeId::new(0) => {
+ match parent_node.or(self.mod_ids.last().cloned()) {
+ Some(parent) if parent != NodeId::new(0) => {
//FIXME: can we pull the parent module's name from elsewhere?
- Some(self.cx.tcx.hir.name(*parent).to_string())
+ Some(self.cx.tcx.hir.name(parent).to_string())
}
_ => None,
}
match kind {
PathKind::Value => {
- if let Ok(def) = self.resolve(path_str, true, ¤t_item) {
+ if let Ok(def) = self.resolve(path_str, true, ¤t_item, parent_node) {
def
} else {
resolution_failure(cx, &item.attrs, path_str, &dox, link_range);
}
}
PathKind::Type => {
- if let Ok(def) = self.resolve(path_str, false, ¤t_item) {
+ if let Ok(def) = self.resolve(path_str, false, ¤t_item, parent_node) {
def
} else {
resolution_failure(cx, &item.attrs, path_str, &dox, link_range);
PathKind::Unknown => {
// try everything!
if let Some(macro_def) = macro_resolve(cx, path_str) {
- if let Ok(type_def) = self.resolve(path_str, false, ¤t_item) {
+ if let Ok(type_def) =
+ self.resolve(path_str, false, ¤t_item, parent_node)
+ {
let (type_kind, article, type_disambig)
= type_ns_kind(type_def.0, path_str);
ambiguity_error(cx, &item.attrs, path_str,
article, type_kind, &type_disambig,
"a", "macro", &format!("macro@{}", path_str));
continue;
- } else if let Ok(value_def) = self.resolve(path_str,
- true,
- ¤t_item) {
+ } else if let Ok(value_def) =
+ self.resolve(path_str, true, ¤t_item, parent_node)
+ {
let (value_kind, value_disambig)
= value_ns_kind(value_def.0, path_str)
.expect("struct and mod cases should have been \
"a", "macro", &format!("macro@{}", path_str));
}
(macro_def, None)
- } else if let Ok(type_def) = self.resolve(path_str, false, ¤t_item) {
+ } else if let Ok(type_def) =
+ self.resolve(path_str, false, ¤t_item, parent_node)
+ {
// It is imperative we search for not-a-value first
// Otherwise we will find struct ctors for when we are looking
// for structs, and the link won't work.
// if there is something in both namespaces
- if let Ok(value_def) = self.resolve(path_str, true, ¤t_item) {
+ if let Ok(value_def) =
+ self.resolve(path_str, true, ¤t_item, parent_node)
+ {
let kind = value_ns_kind(value_def.0, path_str);
if let Some((value_kind, value_disambig)) = kind {
let (type_kind, article, type_disambig)
}
}
type_def
- } else if let Ok(value_def) = self.resolve(path_str, true, ¤t_item) {
+ } else if let Ok(value_def) =
+ self.resolve(path_str, true, ¤t_item, parent_node)
+ {
value_def
} else {
resolution_failure(cx, &item.attrs, path_str, &dox, link_range);
--- /dev/null
+// Copyright 2018 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use clean::*;
+
+use rustc::util::nodemap::FxHashSet;
+use rustc::hir::def_id::DefId;
+
+use super::Pass;
+use core::DocContext;
+use fold::DocFolder;
+
+pub const COLLECT_TRAIT_IMPLS: Pass =
+ Pass::early("collect-trait-impls", collect_trait_impls,
+ "retrieves trait impls for items in the crate");
+
+pub fn collect_trait_impls(krate: Crate, cx: &DocContext) -> Crate {
+ let mut synth = SyntheticImplCollector::new(cx);
+ let mut krate = synth.fold_crate(krate);
+
+ let prims: FxHashSet<PrimitiveType> =
+ krate.primitives.iter().map(|p| p.1).collect();
+
+ let crate_items = {
+ let mut coll = ItemCollector::new();
+ krate = coll.fold_crate(krate);
+ coll.items
+ };
+
+ let mut new_items = Vec::new();
+
+ for &cnum in cx.tcx.crates().iter() {
+ for &did in cx.tcx.all_trait_implementations(cnum).iter() {
+ inline::build_impl(cx, did, &mut new_items);
+ }
+ }
+
+ // Also try to inline primitive impls from other crates.
+ let lang_items = cx.tcx.lang_items();
+ let primitive_impls = [
+ lang_items.isize_impl(),
+ lang_items.i8_impl(),
+ lang_items.i16_impl(),
+ lang_items.i32_impl(),
+ lang_items.i64_impl(),
+ lang_items.i128_impl(),
+ lang_items.usize_impl(),
+ lang_items.u8_impl(),
+ lang_items.u16_impl(),
+ lang_items.u32_impl(),
+ lang_items.u64_impl(),
+ lang_items.u128_impl(),
+ lang_items.f32_impl(),
+ lang_items.f64_impl(),
+ lang_items.f32_runtime_impl(),
+ lang_items.f64_runtime_impl(),
+ lang_items.char_impl(),
+ lang_items.str_impl(),
+ lang_items.slice_impl(),
+ lang_items.slice_u8_impl(),
+ lang_items.str_alloc_impl(),
+ lang_items.slice_alloc_impl(),
+ lang_items.slice_u8_alloc_impl(),
+ lang_items.const_ptr_impl(),
+ lang_items.mut_ptr_impl(),
+ ];
+
+ for def_id in primitive_impls.iter().filter_map(|&def_id| def_id) {
+ if !def_id.is_local() {
+ inline::build_impl(cx, def_id, &mut new_items);
+
+ let auto_impls = get_auto_traits_with_def_id(cx, def_id);
+ let blanket_impls = get_blanket_impls_with_def_id(cx, def_id);
+ let mut renderinfo = cx.renderinfo.borrow_mut();
+
+ let new_impls: Vec<Item> = auto_impls.into_iter()
+ .chain(blanket_impls.into_iter())
+ .filter(|i| renderinfo.inlined.insert(i.def_id))
+ .collect();
+
+ new_items.extend(new_impls);
+ }
+ }
+
+ let mut cleaner = BadImplStripper {
+ prims,
+ items: crate_items,
+ };
+
+ // scan through included items ahead of time to splice in Deref targets to the "valid" sets
+ for it in &new_items {
+ if let ImplItem(Impl { ref for_, ref trait_, ref items, .. }) = it.inner {
+ if cleaner.keep_item(for_) && trait_.def_id() == cx.tcx.lang_items().deref_trait() {
+ let target = items.iter().filter_map(|item| {
+ match item.inner {
+ TypedefItem(ref t, true) => Some(&t.type_),
+ _ => None,
+ }
+ }).next().expect("Deref impl without Target type");
+
+ if let Some(prim) = target.primitive_type() {
+ cleaner.prims.insert(prim);
+ } else if let Some(did) = target.def_id() {
+ cleaner.items.insert(did);
+ }
+ }
+ }
+ }
+
+ new_items.retain(|it| {
+ if let ImplItem(Impl { ref for_, ref trait_, ref blanket_impl, .. }) = it.inner {
+ cleaner.keep_item(for_) ||
+ trait_.as_ref().map_or(false, |t| cleaner.keep_item(t)) ||
+ blanket_impl.is_some()
+ } else {
+ true
+ }
+ });
+
+ // `tcx.crates()` doesn't include the local crate, and `tcx.all_trait_implementations`
+ // doesn't work with it anyway, so pull them from the HIR map instead
+ for &trait_did in cx.all_traits.iter() {
+ for &impl_node in cx.tcx.hir.trait_impls(trait_did) {
+ let impl_did = cx.tcx.hir.local_def_id(impl_node);
+ inline::build_impl(cx, impl_did, &mut new_items);
+ }
+ }
+
+ if let Some(ref mut it) = krate.module {
+ if let ModuleItem(Module { ref mut items, .. }) = it.inner {
+ items.extend(synth.impls);
+ items.extend(new_items);
+ } else {
+ panic!("collect-trait-impls can't run");
+ }
+ } else {
+ panic!("collect-trait-impls can't run");
+ }
+
+ krate
+}
+
+struct SyntheticImplCollector<'a, 'tcx: 'a, 'rcx: 'a, 'cstore: 'rcx> {
+ cx: &'a DocContext<'a, 'tcx, 'rcx, 'cstore>,
+ impls: Vec<Item>,
+}
+
+impl<'a, 'tcx, 'rcx, 'cstore> SyntheticImplCollector<'a, 'tcx, 'rcx, 'cstore> {
+ fn new(cx: &'a DocContext<'a, 'tcx, 'rcx, 'cstore>) -> Self {
+ SyntheticImplCollector {
+ cx,
+ impls: Vec::new(),
+ }
+ }
+}
+
+impl<'a, 'tcx, 'rcx, 'cstore> DocFolder for SyntheticImplCollector<'a, 'tcx, 'rcx, 'cstore> {
+ fn fold_item(&mut self, i: Item) -> Option<Item> {
+ if i.is_struct() || i.is_enum() || i.is_union() {
+ if let (Some(node_id), Some(name)) =
+ (self.cx.tcx.hir.as_local_node_id(i.def_id), i.name.clone())
+ {
+ self.impls.extend(get_auto_traits_with_node_id(self.cx, node_id, name.clone()));
+ self.impls.extend(get_blanket_impls_with_node_id(self.cx, node_id, name));
+ } else {
+ self.impls.extend(get_auto_traits_with_def_id(self.cx, i.def_id));
+ self.impls.extend(get_blanket_impls_with_def_id(self.cx, i.def_id));
+ }
+ }
+
+ self.fold_item_recur(i)
+ }
+}
+
+#[derive(Default)]
+struct ItemCollector {
+ items: FxHashSet<DefId>,
+}
+
+impl ItemCollector {
+ fn new() -> Self {
+ Self::default()
+ }
+}
+
+impl DocFolder for ItemCollector {
+ fn fold_item(&mut self, i: Item) -> Option<Item> {
+ self.items.insert(i.def_id);
+
+ self.fold_item_recur(i)
+ }
+}
+
+struct BadImplStripper {
+ prims: FxHashSet<PrimitiveType>,
+ items: FxHashSet<DefId>,
+}
+
+impl BadImplStripper {
+ fn keep_item(&self, ty: &Type) -> bool {
+ if let Generic(_) = ty {
+ // keep impls made on generics
+ true
+ } else if let Some(prim) = ty.primitive_type() {
+ self.prims.contains(&prim)
+ } else if let Some(did) = ty.def_id() {
+ self.items.contains(&did)
+ } else {
+ false
+ }
+ }
+}
mod collect_intra_doc_links;
pub use self::collect_intra_doc_links::COLLECT_INTRA_DOC_LINKS;
+mod collect_trait_impls;
+pub use self::collect_trait_impls::COLLECT_TRAIT_IMPLS;
+
/// Represents a single pass.
#[derive(Copy, Clone)]
pub enum Pass {
STRIP_PRIV_IMPORTS,
PROPAGATE_DOC_CFG,
COLLECT_INTRA_DOC_LINKS,
+ COLLECT_TRAIT_IMPLS,
];
/// The list of passes run by default.
pub const DEFAULT_PASSES: &'static [&'static str] = &[
+ "collect-trait-impls",
"strip-hidden",
"strip-private",
"collect-intra-doc-links",
/// The list of default passes run with `--document-private-items` is passed to rustdoc.
pub const DEFAULT_PRIVATE_PASSES: &'static [&'static str] = &[
+ "collect-trait-impls",
"strip-priv-imports",
"collect-intra-doc-links",
"collapse-docs",
// We need to recurse into stripped modules to strip things
// like impl methods but when doing so we must not add any
// items to the `retained` set.
+ debug!("Stripper: recursing into stripped {} {:?}", i.type_(), i.name);
let old = mem::replace(&mut self.update_retained, false);
let ret = self.fold_item_recur(i);
self.update_retained = old;
| clean::ForeignTypeItem => {
if i.def_id.is_local() {
if !self.access_levels.is_exported(i.def_id) {
+ debug!("Stripper: stripping {} {:?}", i.type_(), i.name);
return None;
}
}
clean::ModuleItem(..) => {
if i.def_id.is_local() && i.visibility != Some(clean::Public) {
+ debug!("Stripper: stripping module {:?}", i.name);
let old = mem::replace(&mut self.update_retained, false);
let ret = StripItem(self.fold_item_recur(i).unwrap()).strip();
self.update_retained = old;
}
if let Some(did) = imp.for_.def_id() {
if did.is_local() && !imp.for_.is_generic() && !self.retained.contains(&did) {
+ debug!("ImplStripper: impl item for stripped type; removing");
return None;
}
}
if let Some(did) = imp.trait_.def_id() {
if did.is_local() && !self.retained.contains(&did) {
+ debug!("ImplStripper: impl item for stripped trait; removing");
return None;
}
}
for typaram in generics {
if let Some(did) = typaram.def_id() {
if did.is_local() && !self.retained.contains(&did) {
+ debug!("ImplStripper: stripped item in trait's generics; \
+ removing impl");
return None;
}
}
// strip all impls referencing stripped items
let mut stripper = ImplStripper { retained: &retained };
- stripper.fold_crate(krate)
+ let krate = stripper.fold_crate(krate);
+
+ krate
}
struct Stripper<'a> {
impl<'a> fold::DocFolder for Stripper<'a> {
fn fold_item(&mut self, i: Item) -> Option<Item> {
if i.attrs.lists("doc").has_word("hidden") {
- debug!("found one in strip_hidden; removing");
+ debug!("strip_hidden: stripping {} {:?}", i.type_(), i.name);
// use a dedicated hidden item for given item type if any
match i.inner {
clean::StructFieldItem(..) | clean::ModuleItem(..) => {
/// Strip private items from the point of view of a crate or externally from a
/// crate, specified by the `xcrate` flag.
-pub fn strip_private(mut krate: clean::Crate, _: &DocContext) -> clean::Crate {
+pub fn strip_private(mut krate: clean::Crate, cx: &DocContext) -> clean::Crate {
// This stripper collects all *retained* nodes.
let mut retained = DefIdSet();
- let access_levels = krate.access_levels.clone();
+ let access_levels = cx.renderinfo.borrow().access_levels.clone();
// strip all private items
{
assert_eq!(2+2, 4);
}".to_string();
let output = make_test(input, None, false, &opts);
- assert_eq!(output, (expected.clone(), 2));
+ assert_eq!(output, (expected, 2));
}
#[test]
assert_eq!(2+2, 4);
}".to_string();
let output = make_test(input, None, false, &opts);
- assert_eq!(output, (expected.clone(), 2));
+ assert_eq!(output, (expected, 2));
}
#[test]
//Ceci n'est pas une `fn main`
assert_eq!(2+2, 4);".to_string();
let output = make_test(input, None, true, &opts);
- assert_eq!(output, (expected.clone(), 1));
+ assert_eq!(output, (expected, 1));
}
#[test]
assert_eq!(2+2, 4);
}".to_string();
let output = make_test(input, None, false, &opts);
- assert_eq!(output, (expected.clone(), 1));
+ assert_eq!(output, (expected, 1));
}
}
Def::Enum(did) |
Def::ForeignTy(did) |
Def::TyAlias(did) if !self_is_hidden => {
- self.cx.access_levels.borrow_mut().map.insert(did, AccessLevel::Public);
+ self.cx.renderinfo
+ .borrow_mut()
+ .access_levels.map
+ .insert(did, AccessLevel::Public);
},
Def::Mod(did) => if !self_is_hidden {
::visit_lib::LibEmbargoVisitor::new(self.cx).visit_mod(did);
Some(n) => n, None => return false
};
- let is_private = !self.cx.access_levels.borrow().is_public(def_did);
+ let is_private = !self.cx.renderinfo.borrow().access_levels.is_public(def_did);
let is_hidden = inherits_doc_hidden(self.cx, def_node_id);
// Only inline if requested or if the item would otherwise be stripped
ref tr,
ref ty,
ref item_ids) => {
- // Don't duplicate impls when inlining, we'll pick them up
- // regardless of where they're located.
- if !self.inlining {
+ // Don't duplicate impls when inlining or if it's implementing a trait, we'll pick
+ // them up regardless of where they're located.
+ if !self.inlining && tr.is_none() {
let items = item_ids.iter()
.map(|ii| self.cx.tcx.hir.impl_item(ii.id).clone())
.collect();
) -> LibEmbargoVisitor<'a, 'tcx, 'rcx, 'cstore> {
LibEmbargoVisitor {
cx,
- access_levels: cx.access_levels.borrow_mut(),
+ access_levels: RefMut::map(cx.renderinfo.borrow_mut(), |ri| &mut ri.access_levels),
prev_level: Some(AccessLevel::Public),
visited_mods: FxHashSet()
}
) -> Result<RawTable<K, V>, CollectionAllocErr> {
unsafe {
let ret = RawTable::new_uninitialized_internal(capacity, fallibility)?;
- ptr::write_bytes(ret.hashes.ptr(), 0, capacity);
+ if capacity > 0 {
+ ptr::write_bytes(ret.hashes.ptr(), 0, capacity);
+ }
Ok(ret)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::os_str::{OsString, OsStr};
+#[stable(feature = "raw_os", since = "1.1.0")]
+pub use core::ffi::c_void;
+
mod c_str;
mod os_str;
///
/// `OsString` and [`OsStr`] bridge this gap by simultaneously representing Rust
/// and platform-native string values, and in particular allowing a Rust string
-/// to be converted into an "OS" string with no cost if possible.
+/// to be converted into an "OS" string with no cost if possible. A consequence
+/// of this is that `OsString` instances are *not* `NUL` terminated; in order
+/// to pass to e.g. Unix system call, you should create a [`CStr`].
///
/// `OsString` is to [`&OsStr`] as [`String`] is to [`&str`]: the former
/// in each pair are owned strings; the latter are borrowed
///
/// [`OsStr`]: struct.OsStr.html
/// [`&OsStr`]: struct.OsStr.html
+/// [`CStr`]: struct.CStr.html
/// [`From`]: ../convert/trait.From.html
/// [`String`]: ../string/struct.String.html
/// [`&str`]: ../primitive.str.html
use core::cell::Cell;
use core::marker::Unpin;
-use core::pin::PinMut;
+use core::pin::Pin;
use core::option::Option;
use core::ptr::NonNull;
use core::task::{self, Poll};
#[unstable(feature = "gen_future", issue = "50547")]
impl<T: Generator<Yield = ()>> Future for GenFuture<T> {
type Output = T::Return;
- fn poll(self: PinMut<Self>, cx: &mut task::Context) -> Poll<Self::Output> {
- set_task_cx(cx, || match unsafe { PinMut::get_mut_unchecked(self).0.resume() } {
+ fn poll(self: Pin<&mut Self>, cx: &mut task::Context) -> Poll<Self::Output> {
+ set_task_cx(cx, || match unsafe { Pin::get_mut_unchecked(self).0.resume() } {
GeneratorState::Yielded(()) => Poll::Pending,
GeneratorState::Complete(x) => Poll::Ready(x),
})
#[unstable(feature = "gen_future", issue = "50547")]
/// Polls a future in the current thread-local task context.
-pub fn poll_in_task_cx<F>(f: PinMut<F>) -> Poll<F::Output>
+pub fn poll_in_task_cx<F>(f: Pin<&mut F>) -> Poll<F::Output>
where
F: Future
{
- get_task_cx(|cx| f.poll(cx))
+ get_task_cx(|cx| F::poll(f, cx))
}
#[stable(feature = "rust1", since = "1.0.0")]
pub use alloc_crate::format;
#[unstable(feature = "pin", issue = "49150")]
-pub use alloc_crate::pin;
+pub use core::pin;
#[stable(feature = "rust1", since = "1.0.0")]
pub use alloc_crate::slice;
#[stable(feature = "rust1", since = "1.0.0")]
loop {
if let $crate::task::Poll::Ready(x) =
$crate::future::poll_in_task_cx(unsafe {
- $crate::pin::PinMut::new_unchecked(&mut pinned)
+ $crate::pin::Pin::new_unchecked(&mut pinned)
})
{
break x;
#[stable(feature = "ip_from_ip", since = "1.16.0")]
impl From<SocketAddrV4> for SocketAddr {
+ /// Converts a [`SocketAddrV4`] into a [`SocketAddr::V4`].
fn from(sock4: SocketAddrV4) -> SocketAddr {
SocketAddr::V4(sock4)
}
#[stable(feature = "ip_from_ip", since = "1.16.0")]
impl From<SocketAddrV6> for SocketAddr {
+ /// Converts a [`SocketAddrV6`] into a [`SocketAddr::V6`].
fn from(sock6: SocketAddrV6) -> SocketAddr {
SocketAddr::V6(sock6)
}
#[stable(feature = "addr_from_into_ip", since = "1.17.0")]
impl<I: Into<IpAddr>> From<(I, u16)> for SocketAddr {
+ /// Converts a tuple struct (Into<[`IpAddr`]>, `u16`) into a [`SocketAddr`].
+ ///
+ /// This conversion creates a [`SocketAddr::V4`] for a [`IpAddr::V4`]
+ /// and creates a [`SocketAddr::V6`] for a [`IpAddr::V6`].
+ ///
+ /// `u16` is treated as port of the newly created [`SocketAddr`].
fn from(pieces: (I, u16)) -> SocketAddr {
SocketAddr::new(pieces.0.into(), pieces.1)
}
#![stable(feature = "raw_os", since = "1.1.0")]
-use fmt;
-
#[doc(include = "os/raw/char.md")]
#[cfg(any(all(target_os = "linux", any(target_arch = "aarch64",
target_arch = "arm",
#[doc(include = "os/raw/double.md")]
#[stable(feature = "raw_os", since = "1.1.0")] pub type c_double = f64;
-/// Equivalent to C's `void` type when used as a [pointer].
-///
-/// In essence, `*const c_void` is equivalent to C's `const void*`
-/// and `*mut c_void` is equivalent to C's `void*`. That said, this is
-/// *not* the same as C's `void` return type, which is Rust's `()` type.
-///
-/// Ideally, this type would be equivalent to [`!`], but currently it may
-/// be more ideal to use `c_void` for FFI purposes.
-///
-/// [`!`]: ../../primitive.never.html
-/// [pointer]: ../../primitive.pointer.html
-// NB: For LLVM to recognize the void pointer type and by extension
-// functions like malloc(), we need to have it represented as i8* in
-// LLVM bitcode. The enum used here ensures this and prevents misuse
-// of the "raw" type by only having private variants.. We need two
-// variants, because the compiler complains about the repr attribute
-// otherwise.
-#[repr(u8)]
#[stable(feature = "raw_os", since = "1.1.0")]
-pub enum c_void {
- #[unstable(feature = "c_void_variant", reason = "should not have to exist",
- issue = "0")]
- #[doc(hidden)] __variant1,
- #[unstable(feature = "c_void_variant", reason = "should not have to exist",
- issue = "0")]
- #[doc(hidden)] __variant2,
-}
-
-#[stable(feature = "std_debug", since = "1.16.0")]
-impl fmt::Debug for c_void {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- f.pad("c_void")
- }
-}
+#[doc(no_inline)]
+pub use core::ffi::c_void;
#[cfg(test)]
#[allow(unused_imports)]
use cell::UnsafeCell;
use fmt;
use future::Future;
-use pin::PinMut;
+use pin::Pin;
use ops::{Deref, DerefMut};
use panicking;
use ptr::{Unique, NonNull};
impl<'a, F: Future> Future for AssertUnwindSafe<F> {
type Output = F::Output;
- fn poll(self: PinMut<Self>, cx: &mut task::Context) -> Poll<Self::Output> {
- let pinned_field = unsafe { PinMut::map_unchecked(self, |x| &mut x.0) };
- pinned_field.poll(cx)
+ fn poll(self: Pin<&mut Self>, cx: &mut task::Context) -> Poll<Self::Output> {
+ let pinned_field = unsafe { Pin::map_unchecked_mut(self, |x| &mut x.0) };
+ F::poll(pinned_field, cx)
}
}
f64::tanh(n as f64) as f32
}
-// Right now all these functions, the f64 version of the functions above, all
-// shell out to random names. These names aren't actually defined anywhere, per
-// se, but we need this to compile somehow.
-//
-// The idea with this is that when you're using wasm then, for now, we have no
-// way of providing an implementation of these which delegates to a "correct"
-// implementation. For example most wasm applications probably just want to
-// delegate to the javascript `Math` object and its related functions, but wasm
-// doesn't currently have the ability to seamlessly do that (when you
-// instantiate a module you have to set that up).
-//
-// As a result these are just defined here with "hopefully helpful" names. The
-// symbols won't ever be needed or show up unless these functions are called,
-// and hopefully when they're called the errors are self-explanatory enough to
-// figure out what's going on.
-
+// These symbols are all defined in `compiler-builtins`
extern {
- #[link_name = "Math_acos"]
pub fn acos(n: f64) -> f64;
- #[link_name = "Math_asin"]
pub fn asin(n: f64) -> f64;
- #[link_name = "Math_atan"]
pub fn atan(n: f64) -> f64;
- #[link_name = "Math_atan2"]
pub fn atan2(a: f64, b: f64) -> f64;
- #[link_name = "Math_cbrt"]
pub fn cbrt(n: f64) -> f64;
- #[link_name = "Math_cosh"]
pub fn cosh(n: f64) -> f64;
- #[link_name = "Math_expm1"]
pub fn expm1(n: f64) -> f64;
pub fn fdim(a: f64, b: f64) -> f64;
- #[link_name = "Math_log1p"]
pub fn log1p(n: f64) -> f64;
- #[link_name = "Math_sinh"]
pub fn sinh(n: f64) -> f64;
- #[link_name = "Math_tan"]
pub fn tan(n: f64) -> f64;
- #[link_name = "Math_tanh"]
pub fn tanh(n: f64) -> f64;
- #[link_name = "Math_hypot"]
pub fn hypot(x: f64, y: f64) -> f64;
}
Ok(lh) => lh,
Err(e) => panic!("couldn't resolve `localhost': {}", e)
};
- let _na = lh.map(|sa| *addrs.entry(sa).or_insert(0) += 1).count();
- assert!(addrs.values().filter(|&&v| v > 1).count() == 0);
+ for sa in lh { *addrs.entry(sa).or_insert(0) += 1; };
+ assert_eq!(addrs.iter().filter(|&(_, &v)| v > 1).collect::<Vec<_>>(), vec![],
+ "There should be no duplicate localhost entries");
}
}
match thread.inner.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) {
Ok(_) => {}
Err(NOTIFIED) => {
- thread.inner.state.store(EMPTY, SeqCst);
+ // We must read here, even though we know it will be `NOTIFIED`.
+ // This is because `unpark` may have been called again since we read
+ // `NOTIFIED` in the `compare_exchange` above. We must perform an
+ // acquire operation that synchronizes with that `unpark` to observe
+ // any writes it made before the call to unpark. To do that we must
+ // read from the write it made to `state`.
+ let old = thread.inner.state.swap(EMPTY, SeqCst);
+ assert_eq!(old, NOTIFIED, "park state changed unexpectedly");
return;
} // should consume this notification, so prohibit spurious wakeups in next park.
Err(_) => panic!("inconsistent park state"),
match thread.inner.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) {
Ok(_) => {}
Err(NOTIFIED) => {
- thread.inner.state.store(EMPTY, SeqCst);
+ // We must read again here, see `park`.
+ let old = thread.inner.state.swap(EMPTY, SeqCst);
+ assert_eq!(old, NOTIFIED, "park state changed unexpectedly");
return;
} // should consume this notification, so prohibit spurious wakeups in next park.
Err(_) => panic!("inconsistent park_timeout state"),
/// [park]: fn.park.html
#[stable(feature = "rust1", since = "1.0.0")]
pub fn unpark(&self) {
- loop {
- match self.inner.state.compare_exchange(EMPTY, NOTIFIED, SeqCst, SeqCst) {
- Ok(_) => return, // no one was waiting
- Err(NOTIFIED) => return, // already unparked
- Err(PARKED) => {} // gotta go wake someone up
- _ => panic!("inconsistent state in unpark"),
- }
-
- // Coordinate wakeup through the mutex and a condvar notification
- let _lock = self.inner.lock.lock().unwrap();
- match self.inner.state.compare_exchange(PARKED, NOTIFIED, SeqCst, SeqCst) {
- Ok(_) => return self.inner.cvar.notify_one(),
- Err(NOTIFIED) => return, // a different thread unparked
- Err(EMPTY) => {} // parked thread went away, try again
- _ => panic!("inconsistent state in unpark"),
- }
+ // To ensure the unparked thread will observe any writes we made
+ // before this call, we must perform a release operation that `park`
+ // can synchronize with. To do that we must write `NOTIFIED` even if
+ // `state` is already `NOTIFIED`. That is why this must be a swap
+ // rather than a compare-and-swap that returns if it reads `NOTIFIED`
+ // on failure.
+ match self.inner.state.swap(NOTIFIED, SeqCst) {
+ EMPTY => return, // no one was waiting
+ NOTIFIED => return, // already unparked
+ PARKED => {} // gotta go wake someone up
+ _ => panic!("inconsistent state in unpark"),
}
+
+ // Coordinate wakeup through the mutex and a condvar notification
+ let _lock = self.inner.lock.lock().unwrap();
+ self.inner.cvar.notify_one()
}
/// Gets the thread's unique identifier.
use edition::Edition;
use parse::{token, ParseSess};
use OneVector;
+use errors::Applicability;
use ptr::P;
let error = |span, msg, suggestion: &str| {
let mut err = self.sess.span_diagnostic.struct_span_err(span, msg);
if !suggestion.is_empty() {
- err.span_suggestion(span, "expected syntax is", suggestion.into());
+ err.span_suggestion_with_applicability(
+ span,
+ "expected syntax is",
+ suggestion.into(),
+ Applicability::MaybeIncorrect,
+ );
}
err.emit();
true
pub expansion_data: ExpansionData,
}
+// Needed for feature-gating attributes used after derives or together with test/bench
+#[derive(Clone, Copy, PartialEq)]
+pub enum TogetherWith {
+ None,
+ Derive,
+ TestBench,
+}
+
pub enum InvocationKind {
Bang {
mac: ast::Mac,
attr: Option<ast::Attribute>,
traits: Vec<Path>,
item: Annotatable,
+ together_with: TogetherWith,
},
Derive {
path: Path,
let dummy = invoc.fragment_kind.dummy(invoc.span()).unwrap();
let fragment = self.expand_invoc(invoc, &*ext).unwrap_or(dummy);
self.collect_invocations(fragment, &[])
- } else if let InvocationKind::Attr { attr: None, traits, item } = invoc.kind {
+ } else if let InvocationKind::Attr { attr: None, traits, item, .. } = invoc.kind {
if !item.derive_allowed() {
let attr = attr::find_by_name(item.attrs(), "derive")
.expect("`derive` attribute should exist");
attr: Option<ast::Attribute>,
traits: Vec<Path>,
item: Annotatable,
- kind: AstFragmentKind)
+ kind: AstFragmentKind,
+ together_with: TogetherWith)
-> AstFragment {
- self.collect(kind, InvocationKind::Attr { attr, traits, item })
+ self.collect(kind, InvocationKind::Attr { attr, traits, item, together_with })
}
- fn find_attr_invoc(&self, attrs: &mut Vec<ast::Attribute>) -> Option<ast::Attribute> {
+ fn find_attr_invoc(&self, attrs: &mut Vec<ast::Attribute>, together_with: &mut TogetherWith)
+ -> Option<ast::Attribute> {
let attr = attrs.iter()
- .position(|a| !attr::is_known(a) && !is_builtin_attr(a))
+ .position(|a| {
+ if a.path == "derive" {
+ *together_with = TogetherWith::Derive
+ } else if a.path == "rustc_test_marker2" {
+ *together_with = TogetherWith::TestBench
+ }
+ !attr::is_known(a) && !is_builtin_attr(a)
+ })
.map(|i| attrs.remove(i));
if let Some(attr) = &attr {
if !self.cx.ecfg.enable_custom_inner_attributes() &&
"non-builtin inner attributes are unstable");
}
}
+ if together_with == &TogetherWith::None &&
+ attrs.iter().any(|a| a.path == "rustc_test_marker2") {
+ *together_with = TogetherWith::TestBench;
+ }
attr
}
/// If `item` is an attr invocation, remove and return the macro attribute and derive traits.
- fn classify_item<T>(&mut self, mut item: T) -> (Option<ast::Attribute>, Vec<Path>, T)
+ fn classify_item<T>(&mut self, mut item: T)
+ -> (Option<ast::Attribute>, Vec<Path>, T, TogetherWith)
where T: HasAttrs,
{
- let (mut attr, mut traits) = (None, Vec::new());
+ let (mut attr, mut traits, mut together_with) = (None, Vec::new(), TogetherWith::None);
item = item.map_attrs(|mut attrs| {
if let Some(legacy_attr_invoc) = self.cx.resolver.find_legacy_attr_invoc(&mut attrs,
return attrs;
}
- attr = self.find_attr_invoc(&mut attrs);
+ attr = self.find_attr_invoc(&mut attrs, &mut together_with);
traits = collect_derives(&mut self.cx, &mut attrs);
attrs
});
- (attr, traits, item)
+ (attr, traits, item, together_with)
}
/// Alternative of `classify_item()` that ignores `#[derive]` so invocations fallthrough
/// to the unused-attributes lint (making it an error on statements and expressions
/// is a breaking change)
- fn classify_nonitem<T: HasAttrs>(&mut self, mut item: T) -> (Option<ast::Attribute>, T) {
- let mut attr = None;
+ fn classify_nonitem<T: HasAttrs>(&mut self, mut item: T)
+ -> (Option<ast::Attribute>, T, TogetherWith) {
+ let (mut attr, mut together_with) = (None, TogetherWith::None);
item = item.map_attrs(|mut attrs| {
if let Some(legacy_attr_invoc) = self.cx.resolver.find_legacy_attr_invoc(&mut attrs,
return attrs;
}
- attr = self.find_attr_invoc(&mut attrs);
+ attr = self.find_attr_invoc(&mut attrs, &mut together_with);
attrs
});
- (attr, item)
+ (attr, item, together_with)
}
fn configure<T: HasAttrs>(&mut self, node: T) -> Option<T> {
expr.node = self.cfg.configure_expr_kind(expr.node);
// ignore derives so they remain unused
- let (attr, expr) = self.classify_nonitem(expr);
+ let (attr, expr, together_with) = self.classify_nonitem(expr);
if attr.is_some() {
// collect the invoc regardless of whether or not attributes are permitted here
// AstFragmentKind::Expr requires the macro to emit an expression
return self.collect_attr(attr, vec![], Annotatable::Expr(P(expr)),
- AstFragmentKind::Expr).make_expr();
+ AstFragmentKind::Expr, together_with).make_expr();
}
if let ast::ExprKind::Mac(mac) = expr.node {
expr.node = self.cfg.configure_expr_kind(expr.node);
// ignore derives so they remain unused
- let (attr, expr) = self.classify_nonitem(expr);
+ let (attr, expr, together_with) = self.classify_nonitem(expr);
if attr.is_some() {
attr.as_ref().map(|a| self.cfg.maybe_emit_expr_attr_err(a));
return self.collect_attr(attr, vec![], Annotatable::Expr(P(expr)),
- AstFragmentKind::OptExpr)
- .make_opt_expr();
+ AstFragmentKind::OptExpr, together_with).make_opt_expr();
}
if let ast::ExprKind::Mac(mac) = expr.node {
// we'll expand attributes on expressions separately
if !stmt.is_expr() {
- let (attr, derives, stmt_) = if stmt.is_item() {
+ let (attr, derives, stmt_, together_with) = if stmt.is_item() {
self.classify_item(stmt)
} else {
// ignore derives on non-item statements so it falls through
// to the unused-attributes lint
- let (attr, stmt) = self.classify_nonitem(stmt);
- (attr, vec![], stmt)
+ let (attr, stmt, together_with) = self.classify_nonitem(stmt);
+ (attr, vec![], stmt, together_with)
};
if attr.is_some() || !derives.is_empty() {
- return self.collect_attr(attr, derives,
- Annotatable::Stmt(P(stmt_)), AstFragmentKind::Stmts)
- .make_stmts();
+ return self.collect_attr(attr, derives, Annotatable::Stmt(P(stmt_)),
+ AstFragmentKind::Stmts, together_with).make_stmts();
}
stmt = stmt_;
fn fold_item(&mut self, item: P<ast::Item>) -> OneVector<P<ast::Item>> {
let item = configure!(self, item);
- let (attr, traits, item) = self.classify_item(item);
+ let (attr, traits, item, together_with) = self.classify_item(item);
if attr.is_some() || !traits.is_empty() {
- let item = Annotatable::Item(item);
- return self.collect_attr(attr, traits, item, AstFragmentKind::Items).make_items();
+ return self.collect_attr(attr, traits, Annotatable::Item(item),
+ AstFragmentKind::Items, together_with).make_items();
}
match item.node {
fn fold_trait_item(&mut self, item: ast::TraitItem) -> OneVector<ast::TraitItem> {
let item = configure!(self, item);
- let (attr, traits, item) = self.classify_item(item);
+ let (attr, traits, item, together_with) = self.classify_item(item);
if attr.is_some() || !traits.is_empty() {
- let item = Annotatable::TraitItem(P(item));
- return self.collect_attr(attr, traits, item, AstFragmentKind::TraitItems)
- .make_trait_items()
+ return self.collect_attr(attr, traits, Annotatable::TraitItem(P(item)),
+ AstFragmentKind::TraitItems, together_with).make_trait_items()
}
match item.node {
fn fold_impl_item(&mut self, item: ast::ImplItem) -> OneVector<ast::ImplItem> {
let item = configure!(self, item);
- let (attr, traits, item) = self.classify_item(item);
+ let (attr, traits, item, together_with) = self.classify_item(item);
if attr.is_some() || !traits.is_empty() {
- let item = Annotatable::ImplItem(P(item));
- return self.collect_attr(attr, traits, item, AstFragmentKind::ImplItems)
- .make_impl_items();
+ return self.collect_attr(attr, traits, Annotatable::ImplItem(P(item)),
+ AstFragmentKind::ImplItems, together_with).make_impl_items();
}
match item.node {
fn fold_foreign_item(&mut self,
foreign_item: ast::ForeignItem) -> OneVector<ast::ForeignItem> {
- let (attr, traits, foreign_item) = self.classify_item(foreign_item);
+ let (attr, traits, foreign_item, together_with) = self.classify_item(foreign_item);
if attr.is_some() || !traits.is_empty() {
- let item = Annotatable::ForeignItem(P(foreign_item));
- return self.collect_attr(attr, traits, item, AstFragmentKind::ForeignItems)
- .make_foreign_items();
+ return self.collect_attr(attr, traits, Annotatable::ForeignItem(P(foreign_item)),
+ AstFragmentKind::ForeignItems, together_with)
+ .make_foreign_items();
}
if let ast::ForeignItemKind::Macro(mac) = foreign_item.node {
use std::collections::hash_map::Entry;
use rustc_data_structures::sync::Lrc;
+use errors::Applicability;
pub struct ParserAnyMacro<'a> {
parser: Parser<'a>,
if comma_span == DUMMY_SP {
err.note("you might be missing a comma");
} else {
- err.span_suggestion_short(
+ err.span_suggestion_short_with_applicability(
comma_span,
"missing comma here",
", ".to_string(),
+ Applicability::MachineApplicable,
);
}
}
// Allows trait methods with arbitrary self types
(active, arbitrary_self_types, "1.23.0", Some(44874), None),
- // `crate` in paths
- (active, crate_in_paths, "1.23.0", Some(45477), Some(Edition::Edition2018)),
-
// In-band lifetime bindings (e.g. `fn foo(x: &'a u8) -> &'a u8`)
(active, in_band_lifetimes, "1.23.0", Some(44524), None),
// Generic associated types (RFC 1598)
(active, generic_associated_types, "1.23.0", Some(44265), None),
- // Resolve absolute paths as paths from other crates
- (active, extern_absolute_paths, "1.24.0", Some(44660), Some(Edition::Edition2018)),
-
// `extern` in paths
(active, extern_in_paths, "1.23.0", Some(44660), None),
// #[doc(alias = "...")]
(active, doc_alias, "1.27.0", Some(50146), None),
- // Access to crate names passed via `--extern` through prelude
- (active, extern_prelude, "1.27.0", Some(44660), Some(Edition::Edition2018)),
-
// Scoped lints
(active, tool_lints, "1.28.0", Some(44690), None),
// Self struct constructor (RFC 2302)
(active, self_struct_ctor, "1.31.0", Some(51994), None),
+
+ // allow mixing of bind-by-move in patterns and references to
+ // those identifiers in guards, *if* we are using MIR-borrowck
+ // (aka NLL). Essentially this means you need to be on
+ // edition:2018 or later.
+ (active, bind_by_move_pattern_guards, "1.30.0", Some(15287), None),
);
declare_features! (
(accepted, panic_handler, "1.30.0", Some(44489), None),
// Used to preserve symbols (see llvm.used)
(accepted, used, "1.30.0", Some(40289), None),
-
+ // `crate` in paths
+ (accepted, crate_in_paths, "1.30.0", Some(45477), None),
+ // Resolve absolute paths as paths from other crates
+ (accepted, extern_absolute_paths, "1.30.0", Some(44660), None),
+ // Access to crate names passed via `--extern` through prelude
+ (accepted, extern_prelude, "1.30.0", Some(44660), None),
);
// If you change this, please modify src/doc/unstable-book as well. You must
impl AttributeGate {
fn is_deprecated(&self) -> bool {
match *self {
- Gated(Stability::Deprecated(_), ..) => true,
+ Gated(Stability::Deprecated(_, _), ..) => true,
_ => false,
}
}
#[derive(Copy, Clone, Debug)]
pub enum Stability {
Unstable,
- // Argument is tracking issue link.
- Deprecated(&'static str),
+ // First argument is tracking issue link; second argument is an optional
+ // help message, which defaults to "remove this attribute"
+ Deprecated(&'static str, Option<&'static str>),
}
// fn() is not Debug
"the `#[rustc_test_marker]` attribute \
is used internally to track tests",
cfg_fn!(rustc_attrs))),
+ ("rustc_test_marker2", Normal, Gated(Stability::Unstable,
+ "rustc_attrs",
+ "temporarily used by rustc to report some errors",
+ cfg_fn!(rustc_attrs))),
("rustc_transparent_macro", Whitelisted, Gated(Stability::Unstable,
"rustc_attrs",
"used internally for testing macro hygiene",
("no_builtins", Whitelisted, Ungated),
("no_mangle", Whitelisted, Ungated),
("no_debug", Whitelisted, Gated(
- Stability::Deprecated("https://github.com/rust-lang/rust/issues/29721"),
+ Stability::Deprecated("https://github.com/rust-lang/rust/issues/29721", None),
"no_debug",
"the `#[no_debug]` attribute was an experimental feature that has been \
deprecated due to lack of demand",
cfg_fn!(omit_gdb_pretty_printer_section))),
("unsafe_destructor_blind_to_params",
Normal,
- Gated(Stability::Deprecated("https://github.com/rust-lang/rust/issues/34761"),
+ Gated(Stability::Deprecated("https://github.com/rust-lang/rust/issues/34761",
+ Some("replace this attribute with `#[may_dangle]`")),
"dropck_parametricity",
"unsafe_destructor_blind_to_params has been replaced by \
may_dangle and will be removed in the future",
("panic_implementation",
Normal,
Gated(Stability::Deprecated("https://github.com/rust-lang/rust/issues/44489\
- #issuecomment-415140224"),
+ #issuecomment-415140224",
+ Some("replace this attribute with `#[panic_handler]`")),
"panic_implementation",
- "This attribute was renamed to `panic_handler`",
+ "this attribute was renamed to `panic_handler`",
cfg_fn!(panic_implementation))),
// RFC 2070
// cannot be kept in identifiers, so it's kept in paths instead and we take it from
// there while keeping location info from the ident span.
let span = segment.ident.span.with_ctxt(path.span.ctxt());
- if segment.ident.name == keywords::Crate.name() {
- gate_feature_post!(&self, crate_in_paths, span,
- "`crate` in paths is experimental");
- } else if segment.ident.name == keywords::Extern.name() {
+ if segment.ident.name == keywords::Extern.name() {
gate_feature_post!(&self, extern_in_paths, span,
"`extern` in paths is experimental");
}
extern crate serialize as rustc_serialize; // used by deriving
use rustc_data_structures::sync::Lock;
-use rustc_data_structures::bitvec::BitVector;
+use rustc_data_structures::bit_set::GrowableBitSet;
pub use rustc_data_structures::small_vec::OneVector;
pub use rustc_data_structures::thin_vec::ThinVec;
use ast::AttrId;
}
pub struct Globals {
- used_attrs: Lock<BitVector<AttrId>>,
- known_attrs: Lock<BitVector<AttrId>>,
+ used_attrs: Lock<GrowableBitSet<AttrId>>,
+ known_attrs: Lock<GrowableBitSet<AttrId>>,
syntax_pos_globals: syntax_pos::Globals,
}
Globals {
// We have no idea how many attributes their will be, so just
// initiate the vectors with 0 bits. We'll grow them as necessary.
- used_attrs: Lock::new(BitVector::new()),
- known_attrs: Lock::new(BitVector::new()),
+ used_attrs: Lock::new(GrowableBitSet::new_empty()),
+ known_attrs: Lock::new(GrowableBitSet::new_empty()),
syntax_pos_globals: syntax_pos::Globals::new(),
}
}
format!("expected {} here", expect)))
};
let mut err = self.fatal(&msg_exp);
+ if self.token.is_ident_named("and") {
+ err.span_suggestion_short_with_applicability(
+ self.span,
+ "use `&&` instead of `and` for the boolean operator",
+ "&&".to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ if self.token.is_ident_named("or") {
+ err.span_suggestion_short_with_applicability(
+ self.span,
+ "use `||` instead of `or` for the boolean operator",
+ "||".to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ }
let sp = if self.token == token::Token::Eof {
// This is EOF, don't want to point at the following char, but rather the last token
self.prev_span
if self.token == token::CloseDelim(token::Brace) {
// If the struct looks otherwise well formed, recover and continue.
if let Some(sp) = comma_sp {
- err.span_suggestion_short(sp, "remove this comma", String::new());
+ err.span_suggestion_short_with_applicability(
+ sp,
+ "remove this comma",
+ String::new(),
+ Applicability::MachineApplicable,
+ );
}
err.emit();
break;
e.span_label(sp, "expected `{`");
}
+ if self.token.is_ident_named("and") {
+ e.span_suggestion_short_with_applicability(
+ self.span,
+ "use `&&` instead of `and` for the boolean operator",
+ "&&".to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ if self.token.is_ident_named("or") {
+ e.span_suggestion_short_with_applicability(
+ self.span,
+ "use `||` instead of `or` for the boolean operator",
+ "||".to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ }
+
// Check to see if the user has written something like
//
// if (cond)
use std::fmt::{self, Display, Debug};
use std::iter::FromIterator;
-use std::ops::Deref;
+use std::ops::{Deref, DerefMut};
use std::{mem, ptr, slice, vec};
use serialize::{Encodable, Decodable, Encoder, Decoder};
}
}
+impl<T: ?Sized> DerefMut for P<T> {
+ fn deref_mut(&mut self) -> &mut T {
+ &mut self.ptr
+ }
+}
+
impl<T: 'static + Clone> Clone for P<T> {
fn clone(&self) -> P<T> {
P((**self).clone())
));
}
if suggestions.len() > 0 {
- diag.multipart_suggestion(
+ diag.multipart_suggestion_with_applicability(
"format specifiers use curly braces",
suggestions,
+ Applicability::MachineApplicable,
);
}
}};
// If we're not in test configuration, remove the annotated item
if !cx.ecfg.should_test { return vec![]; }
- let item =
+ let mut item =
if let Annotatable::Item(i) = item { i }
else {
cx.parse_sess.span_diagnostic.span_fatal(item.span(),
debug!("Synthetic test item:\n{}\n", pprust::item_to_string(&test_const));
+ // Temporarily add another marker to the original item for error reporting
+ let marker2 = cx.attribute(
+ attr_sp, cx.meta_word(attr_sp, Symbol::intern("rustc_test_marker2"))
+ );
+ item.attrs.push(marker2);
+
vec![
// Access to libtest under a gensymed name
Annotatable::Item(test_extern),
-Subproject commit 5a081f0363340dd895d0958955d0c84661f60f05
+Subproject commit caddcd9b9dc9479a20908d93c3e47c49b021379e
# 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.
-2018-09-11
+2018-09-16
+++ /dev/null
-// 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// force-host
-// no-prefer-dynamic
-
-#![crate_type = "proc-macro"]
-
-extern crate proc_macro;
-
-use proc_macro::TokenStream;
-
-#[proc_macro_attribute]
-pub fn attr_proc_macro(_: TokenStream, input: TokenStream) -> TokenStream {
- input
-}
+++ /dev/null
-// 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// force-host
-// no-prefer-dynamic
-
-#![crate_type = "proc-macro"]
-
-extern crate proc_macro;
-
-use proc_macro::TokenStream;
-
-#[proc_macro]
-pub fn bang_proc_macro(input: TokenStream) -> TokenStream {
- input
-}
+++ /dev/null
-// 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// aux-build:attr_proc_macro.rs
-
-#[macro_use] extern crate attr_proc_macro;
-
-#[attr_proc_macro]
-//~^ ERROR: attribute procedural macros cannot be imported with `#[macro_use]`
-struct Foo;
-
-fn main() {
- let _ = Foo;
-}
+++ /dev/null
-// 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// aux-build:bang_proc_macro.rs
-
-#![feature(proc_macro_non_items)]
-
-#[macro_use]
-extern crate bang_proc_macro;
-
-fn main() {
- bang_proc_macro!(println!("Hello, world!"));
- //~^ ERROR: procedural macros cannot be imported with `#[macro_use]`
-}
#[macro_use]
extern crate derive_b;
-#[derive(B)]
#[B] //~ ERROR `B` is a derive mode
#[C]
#[B(D)]
#[B(E = "foo")]
#[B(arbitrary tokens)]
+#[derive(B)]
struct B;
fn main() {}
$(RUSTC) basic.rs --extern ep_lib=$(TMPDIR)/libep_lib.rlib
$(RUSTC) shadow-mod.rs --extern ep_lib=$(TMPDIR)/libep_lib.rlib
$(RUSTC) shadow-prelude.rs --extern Vec=$(TMPDIR)/libep_vec.rlib
- $(RUSTC) feature-gate.rs --extern ep_lib=$(TMPDIR)/libep_lib.rlib 2>&1 | $(CGREP) "access to extern crates through prelude is experimental"
$(RUSTC) relative-only.rs --extern ep_lib=$(TMPDIR)/libep_lib.rlib 2>&1 | $(CGREP) "unresolved import"
$(RUSTC) relative-only.rs --extern ep_lib=$(TMPDIR)/libep_lib.rlib 2>&1 | $(CGREP) "failed to resolve"
+++ /dev/null
-// Copyright 2018 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-fn main() {
- let s = ep_lib::S; // Feature error
-}
-include ../tools.mk
all: extern_absolute_paths.rs extern_in_paths.rs krate2
- $(RUSTC) extern_absolute_paths.rs -Zsave-analysis --edition=2018
+ $(RUSTC) extern_absolute_paths.rs -Zsave-analysis --edition=2018 \
+ -Z unstable-options --extern krate2
cat $(TMPDIR)/save-analysis/extern_absolute_paths.json | "$(PYTHON)" validate_json.py
- $(RUSTC) extern_in_paths.rs -Zsave-analysis --edition=2018
+ $(RUSTC) extern_in_paths.rs -Zsave-analysis --edition=2018 \
+ -Z unstable-options --extern krate2
cat $(TMPDIR)/save-analysis/extern_in_paths.json | "$(PYTHON)" validate_json.py
krate2: krate2.rs
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_imports)]
// ignore-cross-compile
#![feature(rustc_private)]
--- /dev/null
+warning: `#[derive]` for custom traits is deprecated and will be removed in the future. Prefer using procedural macro custom derive.
+ --> $DIR/custom-derive-partial-eq.rs:17:10
+ |
+LL | #[derive(CustomPartialEq)] // Check that this is not a stability error.
+ | ^^^^^^^^^^^^^^^
+
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
#![feature(rustc_private)]
#![no_std]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_imports)]
#![feature(box_syntax)]
#![feature(rustc_private)]
extern crate serialize;
+use serialize as rustc_serialize;
use serialize::{Encodable, Decodable};
use serialize::json;
-#[derive(Encodable, Decodable)]
+#[derive(RustcEncodable, RustcDecodable)]
struct A {
foo: Box<[bool]>,
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_imports)]
// This briefly tests the capability of `Cell` and `RefCell` to implement the
// `Encodable` and `Decodable` traits via `#[derive(Encodable, Decodable)]`
#![feature(rustc_private)]
extern crate serialize;
+use serialize as rustc_serialize;
use std::cell::{Cell, RefCell};
use serialize::{Encodable, Decodable};
use serialize::json;
-#[derive(Encodable, Decodable)]
+#[derive(RustcEncodable, RustcDecodable)]
struct A {
baz: isize
}
-#[derive(Encodable, Decodable)]
+#[derive(RustcEncodable, RustcDecodable)]
struct B {
foo: Cell<bool>,
bar: RefCell<A>,
#![feature(rustc_private)]
extern crate serialize;
+use serialize as rustc_serialize;
mod submod {
// if any of these are implemented without global calls for any
Hash,
Clone,
Debug,
- Encodable, Decodable)]
+ RustcEncodable, RustcDecodable)]
enum A { A1(usize), A2(isize) }
#[derive(PartialEq, PartialOrd, Eq, Ord,
Hash,
Clone,
Debug,
- Encodable, Decodable)]
+ RustcEncodable, RustcDecodable)]
struct B { x: usize, y: isize }
#[derive(PartialEq, PartialOrd, Eq, Ord,
Hash,
Clone,
Debug,
- Encodable, Decodable)]
+ RustcEncodable, RustcDecodable)]
struct C(usize, isize);
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(non_upper_case_globals)]
#![feature(rustc_private)]
extern crate serialize;
+use serialize as rustc_serialize;
pub const other: u8 = 1;
pub const f: u8 = 1;
pub const state: u8 = 1;
pub const cmp: u8 = 1;
-#[derive(Ord,Eq,PartialOrd,PartialEq,Debug,Decodable,Encodable,Hash)]
+#[derive(Ord,Eq,PartialOrd,PartialEq,Debug,RustcDecodable,RustcEncodable,Hash)]
struct Foo {}
fn main() {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unknown_lints)]
// Check that an arena (TypedArena) can carry elements whose drop
// methods might access borrowed data, as long as the borrowed data
// has lifetime that strictly outlives the arena itself.
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_must_use)]
+#![allow(dead_code)]
+#![allow(unused_imports)]
#![feature(rustc_private)]
extern crate serialize;
+use serialize as rustc_serialize;
use std::io::Cursor;
use std::io::prelude::*;
use serialize::json;
use serialize::opaque;
-#[derive(Encodable)]
+#[derive(RustcEncodable)]
struct Foo {
baz: bool,
}
-#[derive(Encodable)]
+#[derive(RustcEncodable)]
struct Bar {
froboz: usize,
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_mut)]
+#![allow(unused_imports)]
#![feature(rustc_private)]
extern crate serialize;
+extern crate serialize as rustc_serialize;
use serialize::{Encodable, Decodable};
use serialize::json;
-#[derive(Encodable, Decodable, PartialEq, Debug)]
+#[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)]
struct UnitLikeStruct;
pub fn main() {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_variables)]
// no-prefer-dynamic
// ignore-cross-compile
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_imports)]
+#![allow(unused_must_use)]
// pretty-expanded FIXME #23616
#![feature(rustc_private)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
+#![allow(unused_imports)]
// ignore-cross-compile
#![feature(quote, rustc_private)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
#![feature(rustc_private)]
extern crate serialize;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(non_camel_case_types)]
+#![allow(dead_code)]
#![feature(rustc_private)]
extern crate serialize;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
#![feature(rustc_private)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
// aux-build:custom_derive_plugin.rs
// ignore-stage1
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(plugin_as_library)]
+#![allow(unused_imports)]
// aux-build:macro_crate_test.rs
// ignore-stage1
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(plugin_as_library)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+#![allow(unused_imports)]
// aux-build:macro_crate_test.rs
// ignore-stage1
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(plugin_as_library)]
+#![allow(dead_code)]
// aux-build:macro_crate_test.rs
// ignore-stage1
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_parens)]
// aux-build:cond_plugin.rs
// ignore-stage1
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_variables)]
+#![allow(unused_imports)]
// aux-build:call-site.rs
// ignore-stage1
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
// aux-build:derive-attr-cfg.rs
// ignore-stage1
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(path_statements)]
+#![allow(dead_code)]
// aux-build:derive-same-struct.rs
// ignore-stage1
--- /dev/null
+input1: "struct A;"
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
// aux-build:derive-two-attrs.rs
extern crate derive_two_attrs as foo;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_variables)]
// aux-build:derive-union.rs
// ignore-stage1
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_imports)]
// aux-build:empty-crate.rs
// ignore-stage1
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_macros)]
// aux-build:hygiene_example_codegen.rs
// aux-build:hygiene_example.rs
// ignore-stage1
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
// aux-build:issue-39889.rs
// ignore-stage1
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(path_statements)]
// aux-build:issue-50061.rs
// ignore-stage1
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_variables)]
// aux-build:lifetimes.rs
// ignore-stage1
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(path_statements)]
+#![allow(dead_code)]
// aux-build:derive-atob.rs
// aux-build:derive-ctod.rs
// ignore-stage1
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_must_use)]
+#![allow(path_statements)]
// aux-build:derive-a.rs
// ignore-stage1
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
// aux-build:derive-nothing.rs
// ignore-stage1
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_imports)]
// ignore-cross-compile
#![feature(quote, rustc_private)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
+#![allow(unused_variables)]
+#![allow(unused_imports)]
// ignore-cross-compile
#![feature(quote, rustc_private)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
// ignore-cross-compile
#![feature(quote, rustc_private)]
#![deny(unused_variables)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
+#![allow(unused_imports)]
// Test a sample usage pattern for regions. Makes use of the
// following features:
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_must_use)]
+#![allow(unused_imports)]
// This test can't be a unit test in std,
// because it needs TempDir, which is in extra
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_must_use)]
// Since we mark some ABIs as "nounwind" to LLVM, we must make sure that
// we never unwind through them.
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(non_camel_case_types)]
+#![allow(dead_code)]
+
// Regression test for issue #374
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(stable_features)]
+#![allow(unused_variables)]
+
// #45662
#![feature(repr_align)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(non_camel_case_types)]
+#![allow(dead_code)]
+
#![feature(box_syntax)]
struct pair<A,B> {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(non_camel_case_types)]
+#![allow(dead_code)]
+
// pretty-expanded FIXME #23616
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(stable_features)]
+
#![feature(allocator_api, nonnull)]
use std::alloc::{Alloc, Global, Layout, handle_alloc_error};
//[mir]compile-flags: -Z borrowck=mir
#![feature(asm)]
+#![allow(dead_code)]
use std::cell::Cell;
#![feature(arbitrary_self_types, async_await, await_macro, futures_api, pin)]
-use std::pin::PinBox;
-use std::pin::PinMut;
+use std::pin::Pin;
use std::future::Future;
use std::sync::{
Arc,
impl Future for WakeOnceThenComplete {
type Output = ();
- fn poll(mut self: PinMut<Self>, cx: &mut Context) -> Poll<()> {
+ fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<()> {
if self.0 {
Poll::Ready(())
} else {
F: FnOnce(u8) -> Fut,
Fut: Future<Output = u8>,
{
- let mut fut = PinBox::new(f(9));
+ let mut fut = Box::pinned(f(9));
let counter = Arc::new(Counter { wakes: AtomicUsize::new(0) });
let waker = local_waker_from_nonlocal(counter.clone());
let spawner = &mut NoopSpawner;
let cx = &mut Context::new(&waker, spawner);
assert_eq!(0, counter.wakes.load(atomic::Ordering::SeqCst));
- assert_eq!(Poll::Pending, fut.as_pin_mut().poll(cx));
+ assert_eq!(Poll::Pending, fut.as_mut().poll(cx));
assert_eq!(1, counter.wakes.load(atomic::Ordering::SeqCst));
- assert_eq!(Poll::Ready(9), fut.as_pin_mut().poll(cx));
+ assert_eq!(Poll::Ready(9), fut.as_mut().poll(cx));
}
fn main() {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(stable_features)]
#![feature(atomic_access)]
use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT};
use std::sync::atomic::Ordering::*;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(stable_features)]
+
#![feature(extended_compare_and_swap)]
use std::sync::atomic::{AtomicIsize, ATOMIC_ISIZE_INIT};
use std::sync::atomic::Ordering::*;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_must_use)]
+#![allow(deprecated)]
// ignore-cloudabi no process support
// ignore-emscripten no threads support
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_attributes)]
+
// pretty-expanded FIXME #23616
#![feature(custom_attribute, test)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_attributes)]
+
// pretty-expanded FIXME #23616
#![feature(custom_attribute, test)]
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+
+#![allow(unused_attributes)]
+#![allow(unknown_lints)]
+
// pretty-expanded FIXME #23616
#![allow(unused_attribute)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_attributes)]
+
// This test ensures we can attach attributes to the formals in all
// places where generic parameter lists occur, assuming appropriate
// feature gates are enabled.
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_imports)]
#![deny(unused_assignments)]
use std::mem;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
#[derive(Debug)]
struct Pair<T, U> { a: T, b: U }
struct Triple { x: isize, y: isize, z: isize }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(path_statements)]
+#![allow(dead_code)]
macro_rules! auto {
() => (struct S;)
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(non_camel_case_types)]
// Binop corner cases
fn test_nil() {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
+#![allow(unused_imports)]
mod bar {
pub fn foo() -> bool { true }
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(non_snake_case)]
fn asBlock<F>(f: F) -> usize where F: FnOnce() -> usize {
return f();
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_must_use)]
+#![allow(unused_parens)]
// This test has some extra semis in it that the pretty-printer won't
// reproduce so we don't want to automatically reformat it
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_variables)]
+#![allow(unused_imports)]
// ignore-wasm32-bare compiled with panic=abort by default
// Test that builtin implementations of `Clone` cleanup everything
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_imports)]
// aux-build:trait_superkinds_in_metadata.rs
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
// Tests that even when a type parameter doesn't implement a required
// super-builtin-kind of a trait, if the type parameter is never used,
// the type can implement the trait anyway.
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_assignments)]
+#![allow(unused_variables)]
pub fn main() {
let i: isize = 'Q' as isize;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
use std::cell::Cell;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
// Static recursion check shouldn't fail when given a foreign item (#18279)
// aux-build:check_static_recursion_foreign_helper.rs
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(stable_features)]
+#![allow(unused_imports)]
// Test that cleanup scope for temporaries created in a match
// arm is confined to the match arm itself.
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(non_snake_case)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
// Test that the lifetime of rvalues in for loops is extended
// to the for loop itself.
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(non_snake_case)]
+#![allow(unused_variables)]
// Test that destructors for rvalue temporaries run either at end of
// statement or end of block, as appropriate given the temporary
// lifetime rules.
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_must_use)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
// Test cleanup of rvalue temporary that occurs while `box` construction
// is in progress. This scenario revealed a rather terrible bug. The
// ingredients are:
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_must_use)]
// ignore-emscripten no threads support
#![feature(box_syntax)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
// If we use GEPi rather than GEP_tup_like when
// storing closure data (as we used to do), the u64 would
// overwrite the u16.
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
// Test several functions can be used for constants
// 1. Vec::new()
// 2. String::new()
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(stable_features)]
// ignore-windows - this is a unix-specific test
// ignore-cloudabi no processes
// ignore-emscripten no processes
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(stable_features)]
// ignore-windows - this is a unix-specific test
// ignore-pretty issue #37199
// ignore-cloudabi no processes
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unconditional_recursion)]
+#![allow(non_camel_case_types)]
+#![allow(dead_code)]
+#![allow(unused_mut)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_must_use)]
+#![allow(stable_features)]
+#![allow(deprecated)]
+#![allow(unused_imports)]
// compile-flags:--test
// ignore-cloudabi no processes
// ignore-emscripten no processes
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(stable_features)]
// compile-flags:-C target-feature=-crt-static -Z unstable-options
// ignore-musl - requires changing the linker which is hard
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(stable_features)]
// compile-flags:-C target-feature=+crt-static -Z unstable-options
#![feature(cfg_target_feature)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
trait Foo {
fn f(&self) {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
trait Trait<T> {}
struct Foo<U, V=i32>(U, V) where U: Trait<V>;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(stable_features)]
#![feature(core, core_intrinsics)]
extern crate core;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
+#![allow(unused_assignments)]
+#![allow(unused_variables)]
+#![allow(unreachable_code)]
// Test various cases where we permit an unconstrained variable
// to fallback based on control-flow.
//
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_imports)]
// Test a regression found when building compiler. The `produce()`
// error type `T` winds up getting unified with result of `x.parse()`;
// the type of the closure given to `unwrap_or_else` needs to be
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
// pretty-expanded FIXME #23616
fn check_expr() {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
+#![allow(unreachable_code)]
// pretty-expanded FIXME #23616
use std::ops::Add;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(non_camel_case_types)]
+#![allow(dead_code)]
// pretty-expanded FIXME #23616
trait thing<A> {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_mut)]
+#![allow(unused_assignments)]
+#![allow(unused_variables)]
// edition:2015
// aux-build:edition-kw-macro-2015.rs
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_mut)]
+#![allow(unused_assignments)]
+#![allow(unused_variables)]
// edition:2015
// aux-build:edition-kw-macro-2018.rs
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_assignments)]
// edition:2018
// aux-build:edition-kw-macro-2015.rs
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_assignments)]
// edition:2018
// aux-build:edition-kw-macro-2018.rs
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_variables)]
// pretty-expanded FIXME #23616
pub fn main() {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_variables)]
+#![allow(deprecated)]
// ignore-cloudabi no environment variables present
// ignore-emscripten env vars don't work?
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_imports)]
+
// ignore-windows
// ignore-wasm32-bare no libc to test ffi with
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
+#![allow(unused_variables)]
// Checks if the correct registers are being used to pass arguments
// when the sysv64 ABI is specified.
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_assignments)]
+#![allow(unknown_lints)]
#![allow(dead_assignment)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
+#![allow(unused_assignments)]
+#![allow(unused_variables)]
#![feature(existential_type)]
fn main() {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_must_use)]
// pretty-expanded FIXME #23616
pub fn main() {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(non_upper_case_globals)]
+#![allow(dead_code)]
// Test that a glob-export functions as an import
// when referenced within its own local scope.
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
// Issue #521
// pretty-expanded FIXME #23616
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
use std::cell::Cell;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
// pretty-expanded FIXME #23616
use std::ops::{Deref, DerefMut};
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(non_upper_case_globals)]
pub const arg0: u8 = 1;
pub fn main() {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(non_camel_case_types)]
+#![allow(stable_features)]
// Issue 4691: Ensure that functional-struct-updates operates
// correctly and moves rather than copy when appropriate.
#![feature(arbitrary_self_types, futures_api, pin)]
#![allow(unused)]
-use std::pin::PinBox;
use std::future::Future;
-use std::pin::PinMut;
+use std::pin::Pin;
use std::rc::Rc;
use std::sync::{
Arc,
impl Future for MyFuture {
type Output = ();
- fn poll(self: PinMut<Self>, cx: &mut Context) -> Poll<Self::Output> {
+ fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
// Ensure all the methods work appropriately
cx.waker().wake();
cx.waker().wake();
cx.local_waker().wake();
- cx.spawner().spawn_obj(PinBox::new(MyFuture).into()).unwrap();
+ cx.spawner().spawn_obj(Box::pinned(MyFuture).into()).unwrap();
Poll::Ready(())
}
}
let waker = unsafe { local_waker(counter.clone()) };
let spawner = &mut NoopSpawner;
let cx = &mut Context::new(&waker, spawner);
- assert_eq!(Poll::Ready(()), PinMut::new(&mut MyFuture).poll(cx));
+ assert_eq!(Poll::Ready(()), Pin::new(&mut MyFuture).poll(cx));
assert_eq!(1, counter.local_wakes.load(atomic::Ordering::SeqCst));
assert_eq!(2, counter.nonlocal_wakes.load(atomic::Ordering::SeqCst));
}
let waker: LocalWaker = local_waker_from_nonlocal(counter.clone());
let spawner = &mut NoopSpawner;
let cx = &mut Context::new(&waker, spawner);
- assert_eq!(Poll::Ready(()), PinMut::new(&mut MyFuture).poll(cx));
+ assert_eq!(Poll::Ready(()), Pin::new(&mut MyFuture).poll(cx));
assert_eq!(0, counter.local_wakes.load(atomic::Ordering::SeqCst));
assert_eq!(3, counter.nonlocal_wakes.load(atomic::Ordering::SeqCst));
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(non_snake_case)]
#[derive(Copy, Clone)]
enum Q { R(Option<usize>) }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(non_shorthand_field_patterns)]
#[derive(Copy, Clone)]
struct Pair { x: isize, y: isize }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(non_camel_case_types)]
+#![allow(dead_code)]
+#![allow(unused_mut)]
// ignore-emscripten No support for threads
/**
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(non_camel_case_types)]
// A test of the macro system. Can we do HTML literals?
/*
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_parens)]
// pretty-expanded FIXME #23616
fn foo() { if (return) { } }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(non_shorthand_field_patterns)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
// pretty-expanded FIXME #23616
#![feature(slice_patterns)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
// issue #680
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_must_use)]
// Makes sure that zero-initializing large types is reasonably fast,
// Doing it incorrectly causes massive slowdown in LLVM during
// optimisation.
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(non_camel_case_types)]
+#![allow(dead_code)]
#![feature(box_syntax)]
use std::cell::Cell;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(non_camel_case_types)]
+#![allow(dead_code)]
// pretty-expanded FIXME #23616
use std::ptr;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_mut)]
// ignore-wasm32
// ignore-emscripten
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
#[repr(u16)]
enum DeviceKind {
Nil = 0,
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(non_camel_case_types)]
+#![allow(non_upper_case_globals)]
+#![allow(unused_attributes)]
+#![allow(dead_code)]
+#![allow(unknown_lints)]
// These are attributes of the implicit crate. Really this just needs to parse
// for completeness since .rs files linked from .rc files support this
// notation to specify their module's attributes
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
// return -> return
// mod -> module
// match -> match
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_must_use)]
+#![allow(dead_code)]
use std::thread;
fn user(_i: isize) {}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_mut)]
// This should typecheck even though the type of e is not fully
// resolved when we finish typechecking the ||.
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
+#![allow(unused_parens)]
// Issue #1818
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
// Make sure #1399 stays fixed
struct A { a: Box<isize> }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
// Make sure #1399 stays fixed
#![feature(box_syntax)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_mut)]
fn foo(x: isize) { println!("{}", x); }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// dont-check-compiler-stderr (rust-lang/rust#54222)
+
// ignore-wasm32-bare no libc to test ffi with
// compile-flags: -lrust_test_helpers
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(non_upper_case_globals)]
#[cfg(not(target_os = "macos"))]
#[link_section=".moretext"]
fn i_live_in_more_text() -> &'static str {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//
+#![allow(dead_code)]
#![forbid(non_camel_case_types)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
// This is ok because we often use the trailing underscore to mean 'prime'
// pretty-expanded FIXME #23616
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(non_camel_case_types)]
// pretty-expanded FIXME #23616
#![feature(box_syntax)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unreachable_code)]
// pretty-expanded FIXME #23616
#![allow(dead_code)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(non_camel_case_types)]
+#![allow(dead_code)]
#[derive(Clone, Debug)]
enum foo {
a(usize),
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(non_camel_case_types)]
+#![allow(dead_code)]
#[derive(Debug)]
enum foo {
a(usize),
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(non_snake_case)]
trait Product {
fn product(&self) -> isize;
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
// pretty-expanded FIXME #23616
struct S<T> {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(non_camel_case_types)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(non_upper_case_globals)]
/*!
* On x86_64-linux-gnu and possibly other platforms, structs get 8-byte "preferred" alignment,
* but their "ABI" alignment (i.e., what actually matters for data layout) is the largest alignment
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
use std::mem::{size_of, align_of};
use std::os::raw::c_int;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(non_camel_case_types)]
+#![allow(dead_code)]
// pretty-expanded FIXME #23616
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(non_camel_case_types)]
pub fn main() {
struct b {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_variables)]
+#![allow(unreachable_code)]
// Test that we can extract a ! through pattern matching then use it as several different types.
#![feature(never_type)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
// Test that the lambda kind is inferred correctly as a return
// expression
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
// Test that the lambda kind is inferred correctly as a return
// expression
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(non_camel_case_types)]
#[derive(Clone)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(non_camel_case_types)]
#[derive(Copy, Clone)]
struct mytype(Mytype);
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(improper_ctypes)]
+#![allow(dead_code)]
// Issue #901
// pretty-expanded FIXME #23616
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(stable_features)]
#![feature(no_core, core)]
#![no_core]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
use std::mem;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_variables)]
use std::cmp;
use std::ops;
--- /dev/null
+optimization-fuel-exhausted: Reorder fields of "S1"
--- /dev/null
+optimization-fuel-exhausted: Reorder fields of "S2"
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(non_camel_case_types)]
use std::cell::Cell;
struct dtor<'a> {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_must_use)]
+#![allow(unconditional_recursion)]
// ignore-android: FIXME (#20004)
// ignore-musl
// ignore-cloudabi no processes
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
+#![allow(unused_assignments)]
+#![allow(unknown_lints)]
// pretty-expanded FIXME #23616
#![allow(dead_assignment)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_must_use)]
// Regression test for issue #152.
pub fn main() {
let mut b: usize = 1_usize;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
#![allow(unreachable_code)]
fn dont_call_me() { panic!(); println!("{}", 1); }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(deprecated)]
// ignore-cloudabi no files or I/O
// ignore-wasm32-bare no files or I/O
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
// Regression test for #37154: the problem here was that the cache
// results in a false error because it was caching skolemized results
// even after those skolemized regions had been popped.
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
+#![allow(unused_variables)]
+#![allow(unreachable_code)]
// A regression test extracted from image-0.3.11. The point of
// failure was in `index_colors` below.
-> ImageBuffer<Luma<u8>, Vec<u8>>
where Pix: Pixel<Subpixel=u8> + 'static,
{
+ // When NLL-enabled, `let mut` below is deemed unnecessary (due to
+ // the remaining code being unreachable); so ignore that lint.
+ #![allow(unused_mut)]
+
let mut indices: ImageBuffer<_,Vec<_>> = loop { };
for (pixel, idx) in image.pixels().zip(indices.pixels_mut()) {
// failured occurred here ^^ because we were requiring that we
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_variables)]
// Test coercions between pointers which don't do anything fancy like unsizing.
// pretty-expanded FIXME #23616
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
// Check that functions can modify local state.
// pretty-expanded FIXME #23616
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_must_use)]
// Make sure the type inference for the new range expression work as
// good as the old one. Check out issue #21672, #21595 and #21649 for
// more details.
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_comparisons)]
+#![allow(dead_code)]
+#![allow(unused_mut)]
// Test range syntax.
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_comparisons)]
// Test that you only need the syntax gate if you don't mention the structs.
// (Obsoleted since both features are stabilized)
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(non_camel_case_types)]
#![feature(box_syntax)]
trait get {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(non_camel_case_types)]
+#![allow(non_upper_case_globals)]
const foo: isize = 4 >> 1;
enum bs { thing = foo }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(non_camel_case_types)]
use std::cell::Cell;
#[derive(Debug)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(non_camel_case_types)]
use std::cell::Cell;
struct shrinky_pointer<'a> {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(non_camel_case_types)]
+#![allow(dead_code)]
// pretty-expanded FIXME #23616
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// This test is just checking that we won't ICE if logging is turned
+// on; don't bother trying to compare that (copious) output. (Note
+// also that this test potentially silly, since we do not build+test
+// debug versions of rustc as part of our continuous integration
+// process...)
+//
+// dont-check-compiler-stdout
+// dont-check-compiler-stderr
+
// rustc-env:RUST_LOG=debug
fn main() {}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_imports)]
// ignore-cloudabi can't run commands
// ignore-emscripten can't run commands
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_must_use)]
pub fn main() {
// Test that lambdas behave as unary expressions with block-like expressions
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(non_camel_case_types)]
+#![allow(dead_code)]
fn foo(c: Vec<isize> ) {
let a: isize = 5;
let mut b: Vec<isize> = Vec::new();
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_imports)]
mod foo {
pub fn f() {}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_must_use)]
// Be sure that when a SIGPIPE would have been received that the entire process
// doesn't die in a ball of fire, but rather it's gracefully handled.
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_mut)]
pub fn main() { let mut n; n = 1; println!("{}", n); }
#![feature(global_asm)]
#![feature(naked_functions)]
+#![allow(dead_code)]
#[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
global_asm!(r#"
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(non_camel_case_types)]
enum clam<T> { a(T, isize), b, }
fn uhoh<T>(v: Vec<clam<T>> ) {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
// Possibly-dynamic size of typaram should be cleared at pointer boundary.
// pretty-expanded FIXME #23616
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
// Possibly-dynamic size of typaram should be cleared at pointer boundary.
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
// pretty-expanded FIXME #23616
#![feature(non_ascii_idents)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(stable_features)]
// min-llvm-version 6.0
// ^ needs MCSubtargetInfo::checkFeatures()
// ignore-cloudabi no std::env
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(non_camel_case_types)]
#[derive(Copy, Clone, Debug)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(non_upper_case_globals)]
+#![allow(dead_code)]
// exec-env:RUST_MIN_STACK=16000000
// rustc-env:RUST_MIN_STACK=16000000
//
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
// pretty-expanded FIXME #23616
pub mod a {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
// Issue #5041 - avoid overlapping memcpy when src and dest of a swap are the same
// pretty-expanded FIXME #23616
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_must_use)]
/*
This is about the simplest program that can successfully send a
message.
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(non_camel_case_types)]
+#![allow(dead_code)]
// compile-flags: --edition 2018
#![feature(try_blocks)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(non_camel_case_types)]
// compile-flags: --edition 2015
fn main() {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(non_upper_case_globals)]
+#![allow(dead_code)]
// `expr?` expands to:
//
// match expr {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
// ignore-cloudabi no std::fs
use std::fs::File;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(stable_features)]
// ignore-cloudabi no processes
// ignore-emscripten no processes
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(non_camel_case_types)]
type point = (isize, isize);
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
#![feature(core_intrinsics)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
+#![allow(unused_variables)]
// Type ascription doesn't lead to unsoundness
#![feature(type_ascription)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(non_camel_case_types)]
+#![allow(dead_code)]
// pretty-expanded FIXME #23616
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(non_upper_case_globals)]
+#![allow(dead_code)]
+#![allow(unused_assignments)]
+#![allow(unused_variables)]
// Test a scenario where we generate a constraint like `?1 <: &?2`.
// In such a case, it is important that we instantiate `?1` with `&?3`
// where `?3 <: ?2`, and not with `&?2`. This is a regression test for
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(non_camel_case_types)]
+#![allow(dead_code)]
// pretty-expanded FIXME #23616
#![feature(box_syntax)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(non_camel_case_types)]
+#![allow(dead_code)]
// pretty-expanded FIXME #23616
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
// pretty-expanded FIXME #23616
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
// pretty-expanded FIXME #23616
fn f(a: *const isize) -> *const isize { return a; }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(non_camel_case_types)]
+#![allow(dead_code)]
#![feature(never_type)]
use std::mem::size_of;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
// This test checks that the `_` type placeholder works
// correctly for enabling type inference.
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(non_camel_case_types)]
+#![allow(non_snake_case)]
+#![allow(dead_code)]
#![feature(box_syntax)]
// Example from lkuper's intern talk, August 2012 -- now with static
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(non_camel_case_types)]
+#![allow(non_snake_case)]
+#![allow(dead_code)]
#![feature(box_syntax)]
// Example from lkuper's intern talk, August 2012.
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(deprecated)]
// aux-build:typeid-intrinsic-aux1.rs
// aux-build:typeid-intrinsic-aux2.rs
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
+#![allow(unused_assignments)]
+#![allow(unknown_lints)]
// pretty-expanded FIXME #23616
#![allow(dead_assignment)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
struct Foo<'a>(&'a u8);
fn foo(x: &u8) -> Foo<'_> {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_assignments)]
+#![allow(unknown_lints)]
// pretty-expanded FIXME #23616
#![allow(unused_variables)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_must_use)]
+#![allow(unreachable_code)]
#![allow(unused_variables)]
#![allow(dead_code)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_must_use)]
+#![allow(dead_code)]
#![allow(path_statements)]
#![allow(unreachable_code)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
//
// See also: compile-fail/unsafe-fn-called-from-safe.rs
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
//
// See also: compile-fail/unsafe-fn-called-from-safe.rs
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(type_alias_bounds)]
+#![allow(dead_code)]
// Test syntax checks for `?Sized` syntax.
use std::marker::PhantomData;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unconditional_recursion)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+#![allow(unused_imports)]
#![feature(box_syntax)]
// Test sized-ness checking in substitution.
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(non_camel_case_types)]
// ignore-emscripten no threads support
use std::sync::mpsc::{channel, Sender};
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_variables)]
pub struct A;
mod test {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_imports)]
// pretty-expanded FIXME #23616
pub use foo::bar::{self, First};
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(stable_features)]
// pretty-expanded FIXME #23616
#![allow(unused_imports)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//
+#![allow(non_snake_case)]
#![feature(non_ascii_idents)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_attributes)]
+#![allow(non_camel_case_types)]
+#![allow(dead_code)]
// pp-exact - Make sure we actually print the attributes
// pretty-expanded FIXME #23616
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(stable_features)]
#![feature(volatile)]
use std::ptr::{read_volatile, write_volatile};
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
// compile-flags:-D improper-ctypes
// pretty-expanded FIXME #23616
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(non_camel_case_types)]
+#![allow(dead_code)]
+#![allow(unreachable_code)]
+#![allow(unused_parens)]
// compile-flags: -Z borrowck=compare
#![recursion_limit = "128"]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
+#![allow(unused_variables)]
// Test that the `wf` checker properly handles bound regions in object
// types. Compiling this code used to trigger an ICE.
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
use std::sync::Mutex;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//
+#![allow(dead_code)]
// compile-flags: -O
use std::collections::HashSet;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(non_camel_case_types)]
pub type HANDLE = usize;
pub type DWORD = u32;
pub type SIZE_T = u32;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_must_use)]
+#![allow(unused_mut)]
// ignore-emscripten no threads support
use std::thread;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(unused_must_use)]
+#![allow(unused_mut)]
// ignore-emscripten no threads support
use std::thread;
+++ /dev/null
-// Copyright 2018 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// exact-check
-
-const QUERY = 'pinbox::new';
-
-const EXPECTED = {
- 'others': [
- { 'path': 'std::pin::PinBox', 'name': 'new' },
- { 'path': 'alloc::pin::PinBox', 'name': 'new' },
- ],
-};
'others': [
{ 'path': 'std::vec::Vec', 'name': 'new' },
{ 'path': 'std::vec::Vec', 'name': 'ne' },
- { 'path': 'std::pin::PinBox', 'name': 'new' },
],
};
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// ignore-stage1
+
// Issue #52129: ICE when trying to document the `quote` proc-macro from proc_macro
// As of this writing, we don't currently attempt to document proc-macros. However, we shouldn't
--- /dev/null
+// Copyright 2018 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_name = "inner"]
+
+pub struct SomeStruct;
+
+fn asdf() {
+ const _FOO: () = {
+ impl Clone for SomeStruct {
+ fn clone(&self) -> Self {
+ SomeStruct
+ }
+ }
+ };
+}
--- /dev/null
+// Copyright 2018 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:trait-vis.rs
+
+extern crate inner;
+
+// @has trait_vis/struct.SomeStruct.html
+// @has - '//code' 'impl Clone for SomeStruct'
+pub use inner::SomeStruct;
--- /dev/null
+// Copyright 2018 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub trait ThisTrait {}
+
+mod asdf {
+ use ThisTrait;
+
+ pub struct SomeStruct;
+
+ impl ThisTrait for SomeStruct {}
+
+ trait PrivateTrait {}
+
+ impl PrivateTrait for SomeStruct {}
+}
+
+// @has trait_vis/struct.SomeStruct.html
+// @has - '//code' 'impl ThisTrait for SomeStruct'
+// !@has - '//code' 'impl PrivateTrait for SomeStruct'
+pub use asdf::SomeStruct;
--- /dev/null
+// Copyright 2018 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// we need to make sure that intra-doc links on trait impls get resolved in the right scope
+
+#![deny(intra_doc_link_resolution_failure)]
+
+pub mod inner {
+ pub struct SomethingOutOfScope;
+}
+
+pub mod other {
+ use inner::SomethingOutOfScope;
+ use SomeTrait;
+
+ pub struct OtherStruct;
+
+ /// Let's link to [SomethingOutOfScope] while we're at it.
+ impl SomeTrait for OtherStruct {}
+}
+
+pub trait SomeTrait {}
+
+pub struct SomeStruct;
+
+fn __implementation_details() {
+ use inner::SomethingOutOfScope;
+
+ // FIXME: intra-links resolve in their nearest module scope, not their actual scope in cases
+ // like this
+ // Let's link to [SomethingOutOfScope] while we're at it.
+ impl SomeTrait for SomeStruct {}
+}
--- /dev/null
+// Copyright 2018 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub trait MyIterator {
+}
+
+pub struct MyStruct<T>(T);
+
+macro_rules! array_impls {
+ ($($N:expr)+) => {
+ $(
+ impl<'a, T> MyIterator for &'a MyStruct<[T; $N]> {
+ }
+ )+
+ }
+}
+
+// @has issue_53812/trait.MyIterator.html '//*[@id="implementors-list"]//h3[1]' 'MyStruct<[T; 0]>'
+// @has - '//*[@id="implementors-list"]//h3[2]' 'MyStruct<[T; 1]>'
+// @has - '//*[@id="implementors-list"]//h3[3]' 'MyStruct<[T; 2]>'
+// @has - '//*[@id="implementors-list"]//h3[4]' 'MyStruct<[T; 3]>'
+// @has - '//*[@id="implementors-list"]//h3[5]' 'MyStruct<[T; 10]>'
+array_impls! { 10 3 2 1 0 }
// @has foo/index.html '//h2[@id="keywords"]' 'Keywords'
// @has foo/index.html '//a[@href="keyword.match.html"]' 'match'
// @has foo/keyword.match.html '//a[@class="keyword"]' 'match'
+// @has foo/keyword.match.html '//span[@class="in-band"]' 'Keyword match'
// @has foo/keyword.match.html '//section[@id="main"]//div[@class="docblock"]//p' 'this is a test!'
// @!has foo/index.html '//a/@href' 'foo/index.html'
// @!has foo/foo/index.html
#![crate_name = "foo"]
-// we need to reexport something from libstd so that `all_trait_implementations` is called.
-pub use std::string::String;
-
include!("primitive/primitive-generic-impl.rs");
// @has foo/primitive.i32.html '//h3[@id="impl-ToString"]//code' 'impl<T> ToString for T'
--- /dev/null
+// Copyright 2018 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// when implementing the fix for traits-in-bodies, there was an ICE when documenting private items
+// and a trait was defined in non-module scope
+
+// compile-flags:--document-private-items
+
+// @has traits_in_bodies_private/struct.SomeStruct.html
+// @!has - '//code' 'impl HiddenTrait for SomeStruct'
+pub struct SomeStruct;
+
+fn __implementation_details() {
+ trait HiddenTrait {}
+ impl HiddenTrait for SomeStruct {}
+}
//prior to fixing `everybody_loops` to preserve items, rustdoc would crash on this file, as it
//didn't see that `SomeStruct` implemented `Clone`
-//FIXME(misdreavus): whenever rustdoc shows traits impl'd inside bodies, make sure this test
-//reflects that
-
pub struct Bounded<T: Clone>(T);
+// @has traits_in_bodies/struct.SomeStruct.html
+// @has - '//code' 'impl Clone for SomeStruct'
pub struct SomeStruct;
fn asdf() -> Bounded<SomeStruct> {
Bounded(SomeStruct)
}
+
+// @has traits_in_bodies/struct.Point.html
+// @has - '//code' 'impl Copy for Point'
+#[derive(Clone)]
+pub struct Point {
+ x: i32,
+ y: i32,
+}
+
+const _FOO: () = {
+ impl Copy for Point {}
+ ()
+};
+
+// @has traits_in_bodies/struct.Inception.html
+// @has - '//code' 'impl Clone for Inception'
+pub struct Inception;
+
+static _BAR: usize = {
+ trait HiddenTrait {
+ fn hidden_fn(&self) {
+ for _ in 0..5 {
+ impl Clone for Inception {
+ fn clone(&self) -> Self {
+ // we need to go deeper
+ Inception
+ }
+ }
+ }
+ }
+ }
+
+ 5
+};
--- /dev/null
+// aux-build:attr_proc_macro.rs
+// compile-flags:--test
+
+#![feature(test)]
+
+extern crate test;
+extern crate attr_proc_macro;
+use attr_proc_macro::*;
+
+#[attr_proc_macro] // OK
+#[derive(Clone)]
+struct Before;
+
+#[derive(Clone)]
+#[attr_proc_macro] //~ ERROR macro attributes must be placed before `#[derive]`
+struct After;
+
+#[attr_proc_macro] //~ ERROR macro attributes cannot be used together with `#[test]` or `#[bench]`
+#[test]
+fn test_before() {}
+
+#[test]
+#[attr_proc_macro] //~ ERROR macro attributes cannot be used together with `#[test]` or `#[bench]`
+fn test_after() {}
+
+#[attr_proc_macro] //~ ERROR macro attributes cannot be used together with `#[test]` or `#[bench]`
+#[bench]
+fn bench_before(b: &mut test::Bencher) {}
+
+#[bench]
+#[attr_proc_macro] //~ ERROR macro attributes cannot be used together with `#[test]` or `#[bench]`
+fn bench_after(b: &mut test::Bencher) {}
--- /dev/null
+error: macro attributes must be placed before `#[derive]`
+ --> $DIR/attribute-order-restricted.rs:15:1
+ |
+LL | #[attr_proc_macro] //~ ERROR macro attributes must be placed before `#[derive]`
+ | ^^^^^^^^^^^^^^^^^^
+
+error: macro attributes cannot be used together with `#[test]` or `#[bench]`
+ --> $DIR/attribute-order-restricted.rs:18:1
+ |
+LL | #[attr_proc_macro] //~ ERROR macro attributes cannot be used together with `#[test]` or `#[bench]`
+ | ^^^^^^^^^^^^^^^^^^
+
+error: macro attributes cannot be used together with `#[test]` or `#[bench]`
+ --> $DIR/attribute-order-restricted.rs:23:1
+ |
+LL | #[attr_proc_macro] //~ ERROR macro attributes cannot be used together with `#[test]` or `#[bench]`
+ | ^^^^^^^^^^^^^^^^^^
+
+error: macro attributes cannot be used together with `#[test]` or `#[bench]`
+ --> $DIR/attribute-order-restricted.rs:26:1
+ |
+LL | #[attr_proc_macro] //~ ERROR macro attributes cannot be used together with `#[test]` or `#[bench]`
+ | ^^^^^^^^^^^^^^^^^^
+
+error: macro attributes cannot be used together with `#[test]` or `#[bench]`
+ --> $DIR/attribute-order-restricted.rs:31:1
+ |
+LL | #[attr_proc_macro] //~ ERROR macro attributes cannot be used together with `#[test]` or `#[bench]`
+ | ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 5 previous errors
+
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro_attribute]
+pub fn attr_proc_macro(_: TokenStream, input: TokenStream) -> TokenStream {
+ input
+}
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro]
+pub fn bang_proc_macro(input: TokenStream) -> TokenStream {
+ input
+}
extern crate derive_helper_shadowing;
use derive_helper_shadowing::*;
-#[derive(MyTrait)]
#[my_attr] //~ ERROR `my_attr` is ambiguous
+#[derive(MyTrait)]
struct S;
fn main() {}
error[E0659]: `my_attr` is ambiguous
- --> $DIR/derive-helper-shadowing.rs:7:3
+ --> $DIR/derive-helper-shadowing.rs:6:3
|
LL | #[my_attr] //~ ERROR `my_attr` is ambiguous
| ^^^^^^^ ambiguous name
LL | use derive_helper_shadowing::*;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
note: `my_attr` could also refer to the name defined here
- --> $DIR/derive-helper-shadowing.rs:6:10
+ --> $DIR/derive-helper-shadowing.rs:7:10
|
LL | #[derive(MyTrait)]
| ^^^^^^^
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-pass
+// aux-build:attr_proc_macro.rs
+
+#[macro_use] extern crate attr_proc_macro;
+
+#[attr_proc_macro]
+struct Foo;
+
+fn main() {
+ let _ = Foo;
+}
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-pass
+// aux-build:bang_proc_macro.rs
+
+#![feature(proc_macro_non_items)]
+
+#[macro_use]
+extern crate bang_proc_macro;
+
+fn main() {
+ bang_proc_macro!(println!("Hello, world!"));
+}
--> $DIR/E0596.rs:16:18
|
LL | let x = 1;
- | - consider changing this to `mut x`
+ | - help: make this binding mutable: `mut x`
LL | let y = &mut x; //[ast]~ ERROR [E0596]
| ^ cannot borrow mutably
--> $DIR/asm-out-assign-imm.rs:34:9
|
LL | let x: isize;
- | - consider changing this to `mut x`
+ | - help: make this binding mutable: `mut x`
LL | x = 1;
| ----- first assignment to `x`
...
error[E0384]: cannot assign twice to immutable variable `v`
- --> $DIR/assign-imm-local-twice.rs:20:5
+ --> $DIR/assign-imm-local-twice.rs:21:5
|
LL | let v: isize;
- | - consider changing this to `mut v`
-LL | //[mir]~^ NOTE consider changing this to `mut v`
+ | - help: make this binding mutable: `mut v`
+...
LL | v = 1; //[ast]~ NOTE first assignment
| ----- first assignment to `v`
...
error[E0384]: cannot assign twice to immutable variable `v`
- --> $DIR/assign-imm-local-twice.rs:20:5
+ --> $DIR/assign-imm-local-twice.rs:21:5
|
LL | v = 1; //[ast]~ NOTE first assignment
| ----- first assignment to `v`
error[E0384]: cannot assign twice to immutable variable `v`
- --> $DIR/assign-imm-local-twice.rs:20:5
+ --> $DIR/assign-imm-local-twice.rs:21:5
|
LL | let v: isize;
- | - consider changing this to `mut v`
-LL | //[mir]~^ NOTE consider changing this to `mut v`
+ | - help: make this binding mutable: `mut v`
+...
LL | v = 1; //[ast]~ NOTE first assignment
| ----- first assignment to `v`
...
fn test() {
let v: isize;
- //[mir]~^ NOTE consider changing this to `mut v`
+ //[mir]~^ HELP make this binding mutable
+ //[mir]~| SUGGESTION mut v
v = 1; //[ast]~ NOTE first assignment
//[mir]~^ NOTE first assignment
println!("v={}", v);
| borrow later used here
error[E0596]: cannot borrow `y` as mutable, as it is not declared as mutable
- --> $DIR/augmented-assignments.rs:30:5
+ --> $DIR/augmented-assignments.rs:31:5
|
LL | let y = Int(2);
| - help: consider changing this to be mutable: `mut y`
-LL | //~^ consider changing this to `mut y`
+...
LL | y //~ error: cannot borrow immutable local variable `y` as mutable
| ^ cannot borrow as mutable
x; //~ value moved here
let y = Int(2);
- //~^ consider changing this to `mut y`
+ //~^ HELP make this binding mutable
+ //~| SUGGESTION mut y
y //~ error: cannot borrow immutable local variable `y` as mutable
//~| cannot borrow
+=
error[E0596]: cannot borrow immutable local variable `y` as mutable
- --> $DIR/augmented-assignments.rs:30:5
+ --> $DIR/augmented-assignments.rs:31:5
|
LL | let y = Int(2);
- | - consider changing this to `mut y`
-LL | //~^ consider changing this to `mut y`
+ | - help: make this binding mutable: `mut y`
+...
LL | y //~ error: cannot borrow immutable local variable `y` as mutable
| ^ cannot borrow mutably
--- /dev/null
+error[E0008]: cannot bind by-move into a pattern guard
+ --> $DIR/bind-by-move-no-guards.rs:8:14
+ |
+LL | Some(z) if z.recv().unwrap() => { panic!() },
+ | ^ moves value into pattern guard
+ |
+ = help: add #![feature(bind_by_move_pattern_guards)] to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0008`.
-// 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
use std::sync::mpsc::channel;
fn main() {
error[E0008]: cannot bind by-move into a pattern guard
- --> $DIR/bind-by-move-no-guards.rs:18:14
+ --> $DIR/bind-by-move-no-guards.rs:8:14
|
LL | Some(z) if z.recv().unwrap() => { panic!() },
| ^ moves value into pattern guard
--> $DIR/borrowck-access-permissions.rs:22:24
|
LL | let x = 1;
- | - consider changing this to `mut x`
+ | - help: make this binding mutable: `mut x`
...
LL | let _y1 = &mut x; //[ast]~ ERROR [E0596]
| ^ cannot borrow mutably
--> $DIR/borrowck-access-permissions.rs:37:24
|
LL | let box_x = Box::new(1);
- | ----- consider changing this to `mut box_x`
+ | ----- help: make this binding mutable: `mut box_x`
...
LL | let _y1 = &mut *box_x; //[ast]~ ERROR [E0596]
| ^^^^^^ cannot borrow as mutable
--> $DIR/borrowck-argument.rs:20:5
|
LL | fn func(arg: S) {
- | --- consider changing this to `mut arg`
+ | --- help: make this binding mutable: `mut arg`
LL | arg.mutate(); //~ ERROR: cannot borrow immutable argument
| ^^^ cannot borrow mutably
--> $DIR/borrowck-argument.rs:25:9
|
LL | fn method(&self, arg: S) {
- | --- consider changing this to `mut arg`
+ | --- help: make this binding mutable: `mut arg`
LL | arg.mutate(); //~ ERROR: cannot borrow immutable argument
| ^^^ cannot borrow mutably
--> $DIR/borrowck-argument.rs:31:9
|
LL | fn default(&self, arg: S) {
- | --- consider changing this to `mut arg`
+ | --- help: make this binding mutable: `mut arg`
LL | arg.mutate(); //~ ERROR: cannot borrow immutable argument
| ^^^ cannot borrow mutably
LL | (|arg: S| { arg.mutate() })(s); //~ ERROR: cannot borrow immutable argument
| --- ^^^ cannot borrow mutably
| |
- | consider changing this to `mut arg`
+ | help: make this binding mutable: `mut arg`
error: aborting due to 4 previous errors
| -
| |
| first assignment to `x`
- | consider changing this to `mut x`
+ | help: make this binding mutable: `mut x`
LL | unsafe {
LL | asm!("nop" : "=r"(x)); //[ast]~ ERROR cannot assign twice
| ^^^^^^^^^^^^^^^^^^^^^^ cannot assign twice to immutable variable
| -
| |
| first assignment to `x`
- | consider changing this to `mut x`
+ | help: make this binding mutable: `mut x`
LL | unsafe {
LL | asm!("nop" : "+r"(x)); //[ast]~ ERROR cannot assign twice
| ^^^^^^^^^^^^^^^^^^^^^^ cannot assign twice to immutable variable
| -
| |
| first assignment to `x`
- | consider changing this to `mut x`
+ | help: make this binding mutable: `mut x`
LL | unsafe {
LL | asm!("nop" : "=r"(x)); //[ast]~ ERROR cannot assign twice
| ^^^^^^^^^^^^^^^^^^^^^^ cannot assign twice to immutable variable
| -
| |
| first assignment to `x`
- | consider changing this to `mut x`
+ | help: make this binding mutable: `mut x`
LL | unsafe {
LL | asm!("nop" : "+r"(x)); //[ast]~ ERROR cannot assign twice
| ^^^^^^^^^^^^^^^^^^^^^^ cannot assign twice to immutable variable
--> $DIR/borrowck-auto-mut-ref-to-immut-var.rs:25:5
|
LL | let x = Foo { x: 3 };
- | - consider changing this to `mut x`
+ | - help: make this binding mutable: `mut x`
LL | x.printme(); //~ ERROR cannot borrow
| ^ cannot borrow mutably
--> $DIR/borrowck-borrow-from-owned-ptr.rs:132:21
|
LL | let foo = make_foo();
- | --- consider changing this to `mut foo`
+ | --- help: make this binding mutable: `mut foo`
LL | let bar1 = &mut foo.bar1; //~ ERROR cannot borrow
| ^^^^^^^^ cannot mutably borrow field of immutable binding
--> $DIR/borrowck-borrow-from-stack-variable.rs:130:21
|
LL | let foo = make_foo();
- | --- consider changing this to `mut foo`
+ | --- help: make this binding mutable: `mut foo`
LL | let bar1 = &mut foo.bar1; //~ ERROR cannot borrow
| ^^^^^^^^ cannot mutably borrow field of immutable binding
--> $DIR/borrowck-borrow-immut-deref-of-box-as-mut.rs:22:5
|
LL | let a: Box<_> = box A;
- | - consider changing this to `mut a`
+ | - help: make this binding mutable: `mut a`
LL | a.foo();
| ^ cannot borrow as mutable
| -
| |
| first assignment to `x`
- | consider changing this to `mut x`
+ | help: make this binding mutable: `mut x`
LL | x += 1; //[ast]~ ERROR cannot assign twice to immutable variable `x`
| ^^^^^^ cannot assign twice to immutable variable
| -
| |
| first assignment to `x`
- | consider changing this to `mut x`
+ | help: make this binding mutable: `mut x`
LL | x += 1; //[ast]~ ERROR cannot assign twice to immutable variable `x`
| ^^^^^^ cannot assign twice to immutable variable
| -
| |
| first assignment to `x`
- | consider changing this to `mut x`
+ | help: make this binding mutable: `mut x`
LL | x += 1; //[ast]~ ERROR cannot assign twice to immutable variable `x`
| ^^^^^^ cannot assign twice to immutable variable
| -
| |
| first assignment to `x`
- | consider changing this to `mut x`
+ | help: make this binding mutable: `mut x`
LL | x += 1; //[ast]~ ERROR cannot assign twice to immutable variable `x`
| ^^^^^^ cannot assign twice to immutable variable
| -
| |
| first assignment to `x`
- | consider changing this to `mut x`
+ | help: make this binding mutable: `mut x`
LL | x += 1; //[ast]~ ERROR cannot assign twice to immutable variable `x`
| ^^^^^^ cannot assign twice to immutable variable
| -
| |
| first assignment to `x`
- | consider changing this to `mut x`
+ | help: make this binding mutable: `mut x`
LL | x += 1; //[ast]~ ERROR cannot assign twice to immutable variable `x`
| ^^^^^^ cannot assign twice to immutable variable
| -
| |
| first assignment to `x`
- | consider changing this to `mut x`
+ | help: make this binding mutable: `mut x`
LL | x += 1; //[ast]~ ERROR cannot assign twice to immutable variable `x`
| ^^^^^^ cannot assign twice to immutable variable
| -
| |
| first assignment to `x`
- | consider changing this to `mut x`
+ | help: make this binding mutable: `mut x`
LL | x += 1; //[ast]~ ERROR cannot assign twice to immutable variable `x`
| ^^^^^^ cannot assign twice to immutable variable
| -
| |
| first assignment to `x`
- | consider changing this to `mut x`
+ | help: make this binding mutable: `mut x`
LL | x += 1; //[ast]~ ERROR cannot assign twice to immutable variable `x`
| ^^^^^^ cannot assign twice to immutable variable
| -
| |
| first assignment to `x`
- | consider changing this to `mut x`
+ | help: make this binding mutable: `mut x`
LL | x += 1; //[ast]~ ERROR cannot assign twice to immutable variable `x`
| ^^^^^^ cannot assign twice to immutable variable
--> $DIR/borrowck-mut-addr-of-imm-var.rs:13:30
|
LL | let x: isize = 3;
- | - consider changing this to `mut x`
+ | - help: make this binding mutable: `mut x`
LL | let y: &mut isize = &mut x; //~ ERROR cannot borrow
| ^ cannot borrow mutably
--> $DIR/borrowck-mut-slice-of-imm-vec.rs:17:16
|
LL | let v = vec![1, 2, 3];
- | - consider changing this to `mut v`
+ | - help: make this binding mutable: `mut v`
LL | write(&mut v); //~ ERROR cannot borrow
| ^ cannot borrow mutably
--- /dev/null
+error[E0302]: cannot assign in a pattern guard
+ --> $DIR/borrowck-mutate-in-guard.rs:20:25
+ |
+LL | Enum::A(_) if { x = Enum::B(false); false } => 1,
+ | ^^^^^^^^^^^^^^^^^^ assignment in pattern guard
+
+error[E0301]: cannot mutably borrow in a pattern guard
+ --> $DIR/borrowck-mutate-in-guard.rs:22:38
+ |
+LL | Enum::A(_) if { let y = &mut x; *y = Enum::B(false); false } => 1,
+ | ^ borrowed mutably in pattern guard
+ |
+ = help: add #![feature(bind_by_move_pattern_guards)] to the crate attributes to enable
+
+error[E0302]: cannot assign in a pattern guard
+ --> $DIR/borrowck-mutate-in-guard.rs:22:41
+ |
+LL | Enum::A(_) if { let y = &mut x; *y = Enum::B(false); false } => 1,
+ | ^^^^^^^^^^^^^^^^^^^ assignment in pattern guard
+
+error: aborting due to 3 previous errors
+
+Some errors occurred: E0301, E0302.
+For more information about an error, try `rustc --explain E0301`.
--> $DIR/borrowck-overloaded-call.rs:77:5
|
LL | let s = SFnMut {
- | - consider changing this to `mut s`
+ | - help: make this binding mutable: `mut s`
...
LL | s(3); //~ ERROR cannot borrow immutable local variable `s` as mutable
| ^ cannot borrow mutably
--> $DIR/borrowck-ref-mut-of-imm.rs:14:12
|
LL | fn destructure(x: Option<isize>) -> isize {
- | - consider changing this to `mut x`
+ | - help: make this binding mutable: `mut x`
...
LL | Some(ref mut v) => *v //~ ERROR cannot borrow
| ^^^^^^^^^ cannot mutably borrow field of immutable binding
--> $DIR/borrowck-unboxed-closures.rs:17:5
|
LL | fn b<F:FnMut(isize, isize) -> isize>(f: F) {
- | - consider changing this to `mut f`
+ | - help: make this binding mutable: `mut f`
LL | f(1, 2); //~ ERROR cannot borrow immutable argument
| ^ cannot borrow mutably
--> $DIR/immutable-arg.rs:14:5
|
LL | fn foo(_x: u32) {
- | -- consider changing this to `mut _x`
+ | -- help: make this binding mutable: `mut _x`
LL | _x = 4;
| ^^^^^^ cannot assign to immutable argument
}
//~^^ ERROR use of partially moved value: `maybe` (Ast) [E0382]
//~| ERROR use of moved value: `(maybe as std::prelude::v1::Some).0` (Ast) [E0382]
- //~| ERROR use of moved value: `maybe` (Mir) [E0382]
- //~| ERROR use of moved value: `maybe` (Mir) [E0382]
//~| ERROR use of moved value (Mir) [E0382]
- //~| ERROR borrow of moved value: `maybe` (Mir) [E0382]
}
}
|
= note: move occurs because the value has type `std::vec::Vec<bool>`, which does not implement the `Copy` trait
-error[E0382]: use of moved value: `maybe` (Mir)
- --> $DIR/issue-41962.rs:17:16
- |
-LL | if let Some(thing) = maybe {
- | ^^^^^-----^
- | | |
- | | value moved here
- | value used here after move
- |
- = note: move occurs because value has type `std::vec::Vec<bool>`, which does not implement the `Copy` trait
-
error[E0382]: use of moved value (Mir)
--> $DIR/issue-41962.rs:17:21
|
|
= note: move occurs because value has type `std::vec::Vec<bool>`, which does not implement the `Copy` trait
-error[E0382]: use of moved value: `maybe` (Mir)
- --> $DIR/issue-41962.rs:17:30
- |
-LL | if let Some(thing) = maybe {
- | ----- ^^^^^ value used here after move
- | |
- | value moved here
- |
- = note: move occurs because value has type `std::vec::Vec<bool>`, which does not implement the `Copy` trait
-
-error[E0382]: borrow of moved value: `maybe` (Mir)
- --> $DIR/issue-41962.rs:17:30
- |
-LL | if let Some(thing) = maybe {
- | ----- ^^^^^ value borrowed here after move
- | |
- | value moved here
- |
- = note: move occurs because value has type `std::vec::Vec<bool>`, which does not implement the `Copy` trait
-
-error: aborting due to 6 previous errors
+error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0382`.
--> $DIR/mutability-errors.rs:64:10
|
LL | fn imm_local(x: (i32,)) {
- | - consider changing this to `mut x`
+ | - help: make this binding mutable: `mut x`
LL | &mut x; //~ ERROR
| ^ cannot borrow mutably
--> $DIR/mutability-errors.rs:65:10
|
LL | fn imm_local(x: (i32,)) {
- | - consider changing this to `mut x`
+ | - help: make this binding mutable: `mut x`
LL | &mut x; //~ ERROR
LL | &mut x.0; //~ ERROR
| ^^^ cannot mutably borrow field of immutable binding
--> $DIR/mutability-errors.rs:69:5
|
LL | fn imm_capture(x: (i32,)) {
- | - consider changing this to `mut x`
+ | - help: make this binding mutable: `mut x`
LL | || { //~ ERROR
| ^^ cannot borrow mutably
--> $DIR/reassignment_immutable_fields.rs:17:5
|
LL | let x: (u32, u32);
- | - consider changing this to `mut x`
+ | - help: make this binding mutable: `mut x`
LL | x.0 = 1; //~ ERROR
| ^^^^^^^ cannot mutably borrow field of immutable binding
--> $DIR/reassignment_immutable_fields.rs:18:5
|
LL | let x: (u32, u32);
- | - consider changing this to `mut x`
+ | - help: make this binding mutable: `mut x`
LL | x.0 = 1; //~ ERROR
LL | x.1 = 22; //~ ERROR
| ^^^^^^^^ cannot mutably borrow field of immutable binding
--> $DIR/reassignment_immutable_fields.rs:25:5
|
LL | let x: (u32, u32);
- | - consider changing this to `mut x`
+ | - help: make this binding mutable: `mut x`
LL | x.0 = 1; //~ ERROR
| ^^^^^^^ cannot mutably borrow field of immutable binding
--> $DIR/reassignment_immutable_fields.rs:26:5
|
LL | let x: (u32, u32);
- | - consider changing this to `mut x`
+ | - help: make this binding mutable: `mut x`
LL | x.0 = 1; //~ ERROR
LL | x.1 = 22; //~ ERROR
| ^^^^^^^^ cannot mutably borrow field of immutable binding
--> $DIR/reassignment_immutable_fields_overlapping.rs:22:5
|
LL | let x: Foo;
- | - consider changing this to `mut x`
+ | - help: make this binding mutable: `mut x`
LL | x.a = 1; //~ ERROR
| ^^^^^^^ cannot mutably borrow field of immutable binding
--> $DIR/reassignment_immutable_fields_overlapping.rs:23:5
|
LL | let x: Foo;
- | - consider changing this to `mut x`
+ | - help: make this binding mutable: `mut x`
LL | x.a = 1; //~ ERROR
LL | x.b = 22; //~ ERROR
| ^^^^^^^^ cannot mutably borrow field of immutable binding
--> $DIR/reassignment_immutable_fields_twice.rs:17:5
|
LL | let x: (u32, u32);
- | - consider changing this to `mut x`
+ | - help: make this binding mutable: `mut x`
LL | x = (22, 44);
LL | x.0 = 1; //~ ERROR
| ^^^^^^^ cannot mutably borrow field of immutable binding
--> $DIR/reassignment_immutable_fields_twice.rs:22:5
|
LL | let x: (u32, u32);
- | - consider changing this to `mut x`
+ | - help: make this binding mutable: `mut x`
LL | x.0 = 1; //~ ERROR
| ^^^^^^^ cannot mutably borrow field of immutable binding
--> $DIR/reassignment_immutable_fields_twice.rs:23:5
|
LL | let x: (u32, u32);
- | - consider changing this to `mut x`
+ | - help: make this binding mutable: `mut x`
LL | x.0 = 1; //~ ERROR
LL | x.0 = 22; //~ ERROR
| ^^^^^^^^ cannot mutably borrow field of immutable binding
--> $DIR/reassignment_immutable_fields_twice.rs:24:5
|
LL | let x: (u32, u32);
- | - consider changing this to `mut x`
+ | - help: make this binding mutable: `mut x`
...
LL | x.1 = 44; //~ ERROR
| ^^^^^^^^ cannot mutably borrow field of immutable binding
--> $DIR/huge_multispan_highlight.rs:100:18
|
LL | let x = "foo";
- | - consider changing this to `mut x`
+ | - help: make this binding mutable: `mut x`
...
LL | let y = &mut x; //~ ERROR cannot borrow
| ^ cannot borrow mutably
| -
| |
| first assignment to `x`
- | consider changing this to `mut x`
+ | help: make this binding mutable: `mut x`
LL | x = 43;
| ^^^^^^ cannot assign twice to immutable variable
--> $DIR/issue-35937.rs:17:5
|
LL | let f = Foo { v: Vec::new() };
- | - consider changing this to `mut f`
+ | - help: make this binding mutable: `mut f`
LL | f.v.push("cat".to_string()); //~ ERROR cannot borrow
| ^^^ cannot mutably borrow field of immutable binding
--> $DIR/issue-35937.rs:26:5
|
LL | let s = S { x: 42 };
- | - consider changing this to `mut s`
+ | - help: make this binding mutable: `mut s`
LL | s.x += 1; //~ ERROR cannot assign
| ^^^^^^^^ cannot mutably borrow field of immutable binding
--> $DIR/issue-35937.rs:30:5
|
LL | fn bar(s: S) {
- | - consider changing this to `mut s`
+ | - help: make this binding mutable: `mut s`
LL | s.x += 1; //~ ERROR cannot assign
| ^^^^^^^^ cannot mutably borrow field of immutable binding
--> $DIR/issue-39544.rs:21:18
|
LL | let z = Z { x: X::Y };
- | - consider changing this to `mut z`
+ | - help: make this binding mutable: `mut z`
LL | let _ = &mut z.x; //~ ERROR cannot borrow
| ^^^ cannot mutably borrow field of immutable binding
--> $DIR/issue-39544.rs:51:18
|
LL | pub fn with_arg(z: Z, w: &Z) {
- | - consider changing this to `mut z`
+ | - help: make this binding mutable: `mut z`
LL | let _ = &mut z.x; //~ ERROR cannot borrow
| ^^^ cannot mutably borrow field of immutable binding
--- /dev/null
+// Copyright 2018 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn test_and() {
+ let a = true;
+ let b = false;
+ if a and b {
+ //~^ ERROR expected `{`, found `and`
+ println!("both");
+ }
+}
+
+fn test_or() {
+ let a = true;
+ let b = false;
+ if a or b {
+ //~^ ERROR expected `{`, found `or`
+ println!("both");
+ }
+}
+
+fn test_and_par() {
+ let a = true;
+ let b = false;
+ if (a and b) {
+ //~^ ERROR expected one of `!`, `)`, `,`, `.`, `::`, `?`, `{`, or an operator, found `and`
+ println!("both");
+ }
+}
+
+fn test_or_par() {
+ let a = true;
+ let b = false;
+ if (a or b) {
+ //~^ ERROR expected one of `!`, `)`, `,`, `.`, `::`, `?`, `{`, or an operator, found `or`
+ println!("both");
+ }
+}
+
+fn test_while_and() {
+ let a = true;
+ let b = false;
+ while a and b {
+ //~^ ERROR expected one of `!`, `.`, `::`, `?`, `{`, or an operator, found `and`
+ println!("both");
+ }
+}
+
+fn test_while_or() {
+ let a = true;
+ let b = false;
+ while a or b {
+ //~^ ERROR expected one of `!`, `.`, `::`, `?`, `{`, or an operator, found `or`
+ println!("both");
+ }
+}
+
+fn main() {
+}
--- /dev/null
+error: expected `{`, found `and`
+ --> $DIR/issue-54109-and_instead_of_ampersands.rs:14:10
+ |
+LL | if a and b {
+ | -- ^^^ help: use `&&` instead of `and` for the boolean operator
+ | |
+ | this `if` statement has a condition, but no block
+
+error: expected `{`, found `or`
+ --> $DIR/issue-54109-and_instead_of_ampersands.rs:23:10
+ |
+LL | if a or b {
+ | -- ^^ help: use `||` instead of `or` for the boolean operator
+ | |
+ | this `if` statement has a condition, but no block
+
+error: expected one of `!`, `)`, `,`, `.`, `::`, `?`, `{`, or an operator, found `and`
+ --> $DIR/issue-54109-and_instead_of_ampersands.rs:32:11
+ |
+LL | if (a and b) {
+ | ^^^
+ | |
+ | expected one of 8 possible tokens here
+ | help: use `&&` instead of `and` for the boolean operator
+
+error: expected one of `!`, `)`, `,`, `.`, `::`, `?`, `{`, or an operator, found `or`
+ --> $DIR/issue-54109-and_instead_of_ampersands.rs:41:11
+ |
+LL | if (a or b) {
+ | ^^
+ | |
+ | expected one of 8 possible tokens here
+ | help: use `||` instead of `or` for the boolean operator
+
+error: expected one of `!`, `.`, `::`, `?`, `{`, or an operator, found `and`
+ --> $DIR/issue-54109-and_instead_of_ampersands.rs:50:13
+ |
+LL | while a and b {
+ | ^^^
+ | |
+ | expected one of `!`, `.`, `::`, `?`, `{`, or an operator here
+ | help: use `&&` instead of `and` for the boolean operator
+
+error: expected one of `!`, `.`, `::`, `?`, `{`, or an operator, found `or`
+ --> $DIR/issue-54109-and_instead_of_ampersands.rs:59:13
+ |
+LL | while a or b {
+ | ^^
+ | |
+ | expected one of `!`, `.`, `::`, `?`, `{`, or an operator here
+ | help: use `||` instead of `or` for the boolean operator
+
+error: aborting due to 6 previous errors
+
--- /dev/null
+error[E0008]: cannot bind by-move into a pattern guard
+ --> $DIR/E0008.rs:13:14
+ |
+LL | Some(s) if s.len() == 0 => {},
+ | ^ moves value into pattern guard
+ |
+ = help: add #![feature(bind_by_move_pattern_guards)] to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0008`.
--- /dev/null
+error[E0301]: cannot mutably borrow in a pattern guard
+ --> $DIR/E0301.rs:14:19
+ |
+LL | option if option.take().is_none() => {}, //~ ERROR E0301
+ | ^^^^^^ borrowed mutably in pattern guard
+ |
+ = help: add #![feature(bind_by_move_pattern_guards)] to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0301`.
+++ /dev/null
-// 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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-struct S;
-
-fn main() {
- let _ = crate::S; //~ ERROR `crate` in paths is experimental
-}
+++ /dev/null
-error[E0658]: `crate` in paths is experimental (see issue #45477)
- --> $DIR/feature-gate-crate_in_paths.rs:14:13
- |
-LL | let _ = crate::S; //~ ERROR `crate` in paths is experimental
- | ^^^^^
- |
- = help: add #![feature(crate_in_paths)] to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
--> $DIR/feature-gate-dropck-ugeh-2.rs:17:5
|
LL | #[unsafe_destructor_blind_to_params]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace this attribute with `#[may_dangle]`
|
note: lint level defined here
--> $DIR/feature-gate-dropck-ugeh-2.rs:11:9
use core::panic::PanicInfo;
-#[panic_implementation] //~ ERROR This attribute was renamed to `panic_handler` (see issue #44489)
+#[panic_implementation] //~ ERROR this attribute was renamed to `panic_handler` (see issue #44489)
fn panic(info: &PanicInfo) -> ! {
loop {}
}
-error[E0658]: This attribute was renamed to `panic_handler` (see issue #44489)
+error[E0658]: this attribute was renamed to `panic_handler` (see issue #44489)
--> $DIR/feature-gate-panic-implementation.rs:18:1
|
-LL | #[panic_implementation] //~ ERROR This attribute was renamed to `panic_handler` (see issue #44489)
+LL | #[panic_implementation] //~ ERROR this attribute was renamed to `panic_handler` (see issue #44489)
| ^^^^^^^^^^^^^^^^^^^^^^^
|
= help: add #![feature(panic_implementation)] to the crate attributes to enable
--- /dev/null
+warning: the feature `crate_in_paths` has been stable since 1.30.0 and no longer requires an attribute to enable
+ --> $DIR/dollar-crate-modern.rs:16:24
+ |
+LL | #![feature(decl_macro, crate_in_paths)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: #[warn(stable_features)] on by default
+
--> $DIR/immut-function-arguments.rs:15:5
|
LL | fn f(y: Box<isize>) {
- | - consider changing this to `mut y`
+ | - help: make this binding mutable: `mut y`
LL | *y = 5; //[ast]~ ERROR cannot assign
| ^^^^^^ cannot borrow as mutable
LL | let _frob = |q: Box<isize>| { *q = 2; }; //[ast]~ ERROR cannot assign
| - ^^^^^^ cannot borrow as mutable
| |
- | consider changing this to `mut q`
+ | help: make this binding mutable: `mut q`
error: aborting due to 2 previous errors
|
LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x }
| -- lifetime `'a` defined here ^ returning this value requires that `'a` must outlive `'static`
+help: to allow this impl Trait to capture borrowed data with lifetime `'a`, add `'a` as a constraint
+ |
+LL | fn explicit<'a>(x: &'a i32) -> impl Copy + 'a { x }
+ | ^^^^^^^^^^^^^^
error: unsatisfied lifetime constraints
--> $DIR/must_outlive_least_region_or_bound.rs:22:69
|
LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
| -- lifetime `'a` defined here ^ returning this value requires that `'a` must outlive `'static`
+ |
+ = help: consider replacing `'a` with `'static`
error: unsatisfied lifetime constraints
--> $DIR/must_outlive_least_region_or_bound.rs:29:5
| - let's call the lifetime of this reference `'1`
LL | self.x.iter().map(|a| a.0)
| ^^^^^^ cast requires that `'1` must outlive `'static`
+help: to allow this impl Trait to capture borrowed data with lifetime `'1`, add `'_` as a constraint
+ |
+LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> + '_ {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: unsatisfied lifetime constraints
--> $DIR/static-return-lifetime-infered.rs:21:9
| -- lifetime `'a` defined here
LL | self.x.iter().map(|a| a.0)
| ^^^^^^ cast requires that `'a` must outlive `'static`
+help: to allow this impl Trait to capture borrowed data with lifetime `'a`, add `'a` as a constraint
+ |
+LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> + 'a {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 2 previous errors
-error[E0382]: use of moved value: `foo`
- --> $DIR/issue-17385.rs:28:11
- |
-LL | drop(foo);
- | --- value moved here
-LL | match foo { //~ ERROR use of moved value
- | ^^^ value used here after move
- |
- = note: move occurs because `foo` has type `X`, which does not implement the `Copy` trait
-
-error[E0382]: borrow of moved value: `foo`
- --> $DIR/issue-17385.rs:28:11
- |
-LL | drop(foo);
- | --- value moved here
-LL | match foo { //~ ERROR use of moved value
- | ^^^ value borrowed here after move
- |
- = note: move occurs because `foo` has type `X`, which does not implement the `Copy` trait
-
error[E0382]: use of moved value: `foo.0`
--> $DIR/issue-17385.rs:29:11
|
|
= note: move occurs because `e` has type `Enum`, which does not implement the `Copy` trait
-error[E0382]: borrow of moved value: `e`
- --> $DIR/issue-17385.rs:35:11
- |
-LL | drop(e);
- | - value moved here
-LL | match e { //~ ERROR use of moved value
- | ^ value borrowed here after move
- |
- = note: move occurs because `e` has type `Enum`, which does not implement the `Copy` trait
-
-error[E0382]: use of moved value: `e`
- --> $DIR/issue-17385.rs:36:9
- |
-LL | drop(e);
- | - value moved here
-LL | match e { //~ ERROR use of moved value
-LL | Enum::Variant1 => unreachable!(),
- | ^^^^^^^^^^^^^^ value used here after move
- |
- = note: move occurs because `e` has type `Enum`, which does not implement the `Copy` trait
-
-error: aborting due to 6 previous errors
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0382`.
--> $DIR/issue-36400.rs:15:12
|
LL | let x = Box::new(3);
- | - consider changing this to `mut x`
+ | - help: make this binding mutable: `mut x`
LL | f(&mut *x); //~ ERROR cannot borrow immutable
| ^^ cannot borrow as mutable
error[E0384]: cannot assign twice to immutable variable `b`
- --> $DIR/issue-45199.rs:19:5
+ --> $DIR/issue-45199.rs:20:5
|
LL | let b: Box<isize>;
- | - consider changing this to `mut b`
-LL | //[mir]~^ NOTE consider changing this to `mut b`
+ | - help: make this binding mutable: `mut b`
+...
LL | b = Box::new(1); //[ast]~ NOTE first assignment
| - first assignment to `b`
LL | //[mir]~^ NOTE first assignment
| ^ cannot assign twice to immutable variable
error[E0384]: cannot assign twice to immutable variable `b`
- --> $DIR/issue-45199.rs:29:5
+ --> $DIR/issue-45199.rs:31:5
|
LL | let b = Box::new(1); //[ast]~ NOTE first assignment
| -
| |
| first assignment to `b`
- | consider changing this to `mut b`
+ | help: make this binding mutable: `mut b`
...
LL | b = Box::new(2); //[ast]~ ERROR cannot assign twice to immutable variable
| ^ cannot assign twice to immutable variable
error[E0384]: cannot assign to immutable argument `b`
- --> $DIR/issue-45199.rs:37:5
+ --> $DIR/issue-45199.rs:40:5
|
LL | fn test_args(b: Box<i32>) { //[ast]~ NOTE first assignment
- | - consider changing this to `mut b`
-LL | //[mir]~^ NOTE consider changing this to `mut b`
+ | - help: make this binding mutable: `mut b`
+...
LL | b = Box::new(2); //[ast]~ ERROR cannot assign twice to immutable variable
| ^ cannot assign to immutable argument
error[E0384]: cannot assign twice to immutable variable `b`
- --> $DIR/issue-45199.rs:19:5
+ --> $DIR/issue-45199.rs:20:5
|
LL | b = Box::new(1); //[ast]~ NOTE first assignment
| --------------- first assignment to `b`
| ^^^^^^^^^^^^^^^ cannot assign twice to immutable variable
error[E0384]: cannot assign twice to immutable variable `b`
- --> $DIR/issue-45199.rs:29:5
+ --> $DIR/issue-45199.rs:31:5
|
LL | let b = Box::new(1); //[ast]~ NOTE first assignment
| - first assignment to `b`
| ^^^^^^^^^^^^^^^ cannot assign twice to immutable variable
error[E0384]: cannot assign twice to immutable variable `b`
- --> $DIR/issue-45199.rs:37:5
+ --> $DIR/issue-45199.rs:40:5
|
LL | fn test_args(b: Box<i32>) { //[ast]~ NOTE first assignment
| - first assignment to `b`
-LL | //[mir]~^ NOTE consider changing this to `mut b`
+...
LL | b = Box::new(2); //[ast]~ ERROR cannot assign twice to immutable variable
| ^^^^^^^^^^^^^^^ cannot assign twice to immutable variable
error[E0384]: cannot assign twice to immutable variable `b`
- --> $DIR/issue-45199.rs:19:5
+ --> $DIR/issue-45199.rs:20:5
|
LL | let b: Box<isize>;
- | - consider changing this to `mut b`
-LL | //[mir]~^ NOTE consider changing this to `mut b`
+ | - help: make this binding mutable: `mut b`
+...
LL | b = Box::new(1); //[ast]~ NOTE first assignment
| - first assignment to `b`
LL | //[mir]~^ NOTE first assignment
| ^ cannot assign twice to immutable variable
error[E0384]: cannot assign twice to immutable variable `b`
- --> $DIR/issue-45199.rs:29:5
+ --> $DIR/issue-45199.rs:31:5
|
LL | let b = Box::new(1); //[ast]~ NOTE first assignment
| -
| |
| first assignment to `b`
- | consider changing this to `mut b`
+ | help: make this binding mutable: `mut b`
...
LL | b = Box::new(2); //[ast]~ ERROR cannot assign twice to immutable variable
| ^ cannot assign twice to immutable variable
error[E0384]: cannot assign to immutable argument `b`
- --> $DIR/issue-45199.rs:37:5
+ --> $DIR/issue-45199.rs:40:5
|
LL | fn test_args(b: Box<i32>) { //[ast]~ NOTE first assignment
- | - consider changing this to `mut b`
-LL | //[mir]~^ NOTE consider changing this to `mut b`
+ | - help: make this binding mutable: `mut b`
+...
LL | b = Box::new(2); //[ast]~ ERROR cannot assign twice to immutable variable
| ^ cannot assign to immutable argument
fn test_drop_replace() {
let b: Box<isize>;
- //[mir]~^ NOTE consider changing this to `mut b`
+ //[mir]~^ HELP make this binding mutable
+ //[mir]~| SUGGESTION mut b
b = Box::new(1); //[ast]~ NOTE first assignment
//[mir]~^ NOTE first assignment
b = Box::new(2); //[ast]~ ERROR cannot assign twice to immutable variable
fn test_call() {
let b = Box::new(1); //[ast]~ NOTE first assignment
//[mir]~^ NOTE first assignment
- //[mir]~| NOTE consider changing this to `mut b`
+ //[mir]~| HELP make this binding mutable
+ //[mir]~| SUGGESTION mut b
b = Box::new(2); //[ast]~ ERROR cannot assign twice to immutable variable
//[mir]~^ ERROR cannot assign twice to immutable variable `b`
//[ast]~| NOTE cannot assign twice to immutable
}
fn test_args(b: Box<i32>) { //[ast]~ NOTE first assignment
- //[mir]~^ NOTE consider changing this to `mut b`
+ //[mir]~^ HELP make this binding mutable
+ //[mir]~| SUGGESTION mut b
b = Box::new(2); //[ast]~ ERROR cannot assign twice to immutable variable
//[mir]~^ ERROR cannot assign to immutable argument `b`
//[ast]~| NOTE cannot assign twice to immutable
// edition:2018
// aux-build:issue-52489.rs
+// compile-flags:--extern issue_52489
use issue_52489;
//~^ ERROR use of unstable library feature 'issue_52489_unstable'
error[E0658]: use of unstable library feature 'issue_52489_unstable'
- --> $DIR/issue-52489.rs:14:5
+ --> $DIR/issue-52489.rs:15:5
|
LL | use issue_52489;
| ^^^^^^^^^^^
--- /dev/null
+// rust-lang/rust#53675: At one point the compiler errored when a test
+// named `panic` used the `assert!` macro in expression position.
+
+// compile-pass
+// compile-flags: --test
+
+mod in_expression_position {
+ #[test]
+ fn panic() {
+ assert!(true)
+ }
+}
+
+mod in_statement_position {
+ #[test]
+ fn panic() {
+ assert!(true);
+ }
+}
+
+mod what_if_we_use_panic_directly_in_expr {
+ #[test]
+ #[should_panic]
+ fn panic() {
+ panic!("in expr")
+ }
+}
+
+
+mod what_if_we_use_panic_directly_in_stmt {
+ #[test]
+ #[should_panic]
+ fn panic() {
+ panic!("in stmt");
+ }
+}
--- /dev/null
+// issue #53712: make the error generated by using tuple indexing on an array more specific
+
+fn main() {
+ let arr = [10, 20, 30, 40, 50];
+ arr.0;
+ //~^ ERROR no field `0` on type `[{integer}; 5]` [E0609]
+ //~| HELP instead of using tuple indexing, use array indexing
+ //~| SUGGESTION arr[0]
+}
--- /dev/null
+error[E0609]: no field `0` on type `[{integer}; 5]`
+ --> $DIR/issue-53712.rs:5:9
+ |
+LL | arr.0;
+ | ----^
+ | |
+ | help: instead of using tuple indexing, use array indexing: `arr[0]`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0609`.
--> $DIR/issue-5500-1.rs:22:5
|
LL | let _iter = TrieMapIterator{node: &a};
- | ----- consider changing this to `mut _iter`
+ | ----- help: make this binding mutable: `mut _iter`
LL | / _iter.node = & //[ast]~ ERROR cannot assign to field `_iter.node` of immutable binding
LL | | //[mir]~^ ERROR cannot assign to field `_iter.node` of immutable binding (Ast)
LL | | // MIR doesn't generate an error because the code isn't reachable. This is OK
--> $DIR/issue-5500-1.rs:22:5
|
LL | let _iter = TrieMapIterator{node: &a};
- | ----- consider changing this to `mut _iter`
+ | ----- help: make this binding mutable: `mut _iter`
LL | / _iter.node = & //[ast]~ ERROR cannot assign to field `_iter.node` of immutable binding
LL | | //[mir]~^ ERROR cannot assign to field `_iter.node` of immutable binding (Ast)
LL | | // MIR doesn't generate an error because the code isn't reachable. This is OK
--> $DIR/ex3-both-anon-regions-one-is-struct-2.rs:14:5
|
LL | fn foo(mut x: Ref, y: &u32) {
- | - consider changing this to `mut y`
+ | - help: make this binding mutable: `mut y`
LL | y = x.b; //~ ERROR lifetime mismatch
| ^^^^^^^ cannot assign to immutable argument
--> $DIR/liveness-assign-imm-local-notes.rs:23:9
|
LL | let x;
- | - consider changing this to `mut x`
+ | - help: make this binding mutable: `mut x`
...
LL | x = 2;
| ----- first assignment to `x`
--> $DIR/liveness-assign-imm-local-notes.rs:35:13
|
LL | let x;
- | - consider changing this to `mut x`
+ | - help: make this binding mutable: `mut x`
...
LL | x = 2;
| ----- first assignment to `x`
--> $DIR/liveness-assign-imm-local-notes.rs:45:13
|
LL | let x;
- | - consider changing this to `mut x`
+ | - help: make this binding mutable: `mut x`
...
LL | x = 1; //~ ERROR (Ast) [E0384]
| ^^^^^ cannot assign twice to immutable variable
--> $DIR/liveness-assign-imm-local-notes.rs:48:13
|
LL | let x;
- | - consider changing this to `mut x`
+ | - help: make this binding mutable: `mut x`
...
LL | x = 1; //~ ERROR (Ast) [E0384]
| ----- first assignment to `x`
--- /dev/null
+// compile-pass
+
+#![forbid(non_camel_case_types)]
+#![allow(dead_code)]
+
+// None of the following types should generate a warning
+struct _X {}
+struct __X {}
+struct __ {}
+struct X_ {}
+struct X__ {}
+struct X___ {}
+
+fn main() { }
bar: isize,
}
-type __ = isize; //~ ERROR type `__` should have a camel case name such as `CamelCase`
-
struct X86_64;
struct X86__64; //~ ERROR type `X86__64` should have a camel case name such as `X86_64`
LL | fn f<ty>(_: ty) {} //~ ERROR type parameter `ty` should have a camel case name such as `Ty`
| ^^
-error: type `__` should have a camel case name such as `CamelCase`
- --> $DIR/lint-non-camel-case-types.rs:46:1
- |
-LL | type __ = isize; //~ ERROR type `__` should have a camel case name such as `CamelCase`
- | ^^^^^^^^^^^^^^^^
-
error: type `X86__64` should have a camel case name such as `X86_64`
- --> $DIR/lint-non-camel-case-types.rs:50:1
+ --> $DIR/lint-non-camel-case-types.rs:48:1
|
LL | struct X86__64; //~ ERROR type `X86__64` should have a camel case name such as `X86_64`
| ^^^^^^^^^^^^^^^
error: type `Abc_123` should have a camel case name such as `Abc123`
- --> $DIR/lint-non-camel-case-types.rs:52:1
+ --> $DIR/lint-non-camel-case-types.rs:50:1
|
LL | struct Abc_123; //~ ERROR type `Abc_123` should have a camel case name such as `Abc123`
| ^^^^^^^^^^^^^^^
error: type `A1_b2_c3` should have a camel case name such as `A1B2C3`
- --> $DIR/lint-non-camel-case-types.rs:54:1
+ --> $DIR/lint-non-camel-case-types.rs:52:1
|
LL | struct A1_b2_c3; //~ ERROR type `A1_b2_c3` should have a camel case name such as `A1B2C3`
| ^^^^^^^^^^^^^^^^
-error: aborting due to 12 previous errors
+error: aborting due to 11 previous errors
error[E0384]: cannot assign twice to immutable variable `v`
- --> $DIR/liveness-assign-imm-local-in-loop.rs:18:9
+ --> $DIR/liveness-assign-imm-local-in-loop.rs:19:9
|
LL | let v: isize;
- | - consider changing this to `mut v`
+ | - help: make this binding mutable: `mut v`
...
LL | v = 1; //[ast]~ ERROR cannot assign twice to immutable variable
| ^^^^^ cannot assign twice to immutable variable
error[E0384]: cannot assign twice to immutable variable `v`
- --> $DIR/liveness-assign-imm-local-in-loop.rs:18:9
+ --> $DIR/liveness-assign-imm-local-in-loop.rs:19:9
|
LL | v = 1; //[ast]~ ERROR cannot assign twice to immutable variable
| ^^^^^ cannot assign twice to immutable variable
error[E0384]: cannot assign twice to immutable variable `v`
- --> $DIR/liveness-assign-imm-local-in-loop.rs:18:9
+ --> $DIR/liveness-assign-imm-local-in-loop.rs:19:9
|
LL | let v: isize;
- | - consider changing this to `mut v`
+ | - help: make this binding mutable: `mut v`
...
LL | v = 1; //[ast]~ ERROR cannot assign twice to immutable variable
| ^^^^^ cannot assign twice to immutable variable
fn test() {
let v: isize;
- //[mir]~^ NOTE consider changing this to `mut v`
+ //[mir]~^ HELP make this binding mutable
+ //[mir]~| SUGGESTION mut v
loop {
v = 1; //[ast]~ ERROR cannot assign twice to immutable variable
//[mir]~^ ERROR cannot assign twice to immutable variable `v`
error[E0384]: cannot assign twice to immutable variable `v`
- --> $DIR/liveness-assign-imm-local-in-op-eq.rs:19:5
+ --> $DIR/liveness-assign-imm-local-in-op-eq.rs:20:5
|
LL | let v: isize;
- | - consider changing this to `mut v`
-LL | //[mir]~^ NOTE consider changing this to `mut v`
+ | - help: make this binding mutable: `mut v`
+...
LL | v = 2; //[ast]~ NOTE first assignment
| ----- first assignment to `v`
LL | //[mir]~^ NOTE first assignment
error[E0384]: cannot assign twice to immutable variable `v`
- --> $DIR/liveness-assign-imm-local-in-op-eq.rs:19:5
+ --> $DIR/liveness-assign-imm-local-in-op-eq.rs:20:5
|
LL | v = 2; //[ast]~ NOTE first assignment
| ----- first assignment to `v`
error[E0384]: cannot assign twice to immutable variable `v`
- --> $DIR/liveness-assign-imm-local-in-op-eq.rs:19:5
+ --> $DIR/liveness-assign-imm-local-in-op-eq.rs:20:5
|
LL | let v: isize;
- | - consider changing this to `mut v`
-LL | //[mir]~^ NOTE consider changing this to `mut v`
+ | - help: make this binding mutable: `mut v`
+...
LL | v = 2; //[ast]~ NOTE first assignment
| ----- first assignment to `v`
LL | //[mir]~^ NOTE first assignment
fn test() {
let v: isize;
- //[mir]~^ NOTE consider changing this to `mut v`
+ //[mir]~^ HELP make this binding mutable
+ //[mir]~| SUGGESTION mut v
v = 2; //[ast]~ NOTE first assignment
//[mir]~^ NOTE first assignment
v += 1; //[ast]~ ERROR cannot assign twice to immutable variable
error[E0384]: cannot assign twice to immutable variable `b`
- --> $DIR/liveness-assign-imm-local-with-drop.rs:19:5
+ --> $DIR/liveness-assign-imm-local-with-drop.rs:20:5
|
LL | let b = Box::new(1); //[ast]~ NOTE first assignment
| -
| |
| first assignment to `b`
- | consider changing this to `mut b`
+ | help: make this binding mutable: `mut b`
...
LL | b = Box::new(2); //[ast]~ ERROR cannot assign twice to immutable variable
| ^ cannot assign twice to immutable variable
error[E0384]: cannot assign twice to immutable variable `b`
- --> $DIR/liveness-assign-imm-local-with-drop.rs:19:5
+ --> $DIR/liveness-assign-imm-local-with-drop.rs:20:5
|
LL | let b = Box::new(1); //[ast]~ NOTE first assignment
| - first assignment to `b`
error[E0384]: cannot assign twice to immutable variable `b`
- --> $DIR/liveness-assign-imm-local-with-drop.rs:19:5
+ --> $DIR/liveness-assign-imm-local-with-drop.rs:20:5
|
LL | let b = Box::new(1); //[ast]~ NOTE first assignment
| -
| |
| first assignment to `b`
- | consider changing this to `mut b`
+ | help: make this binding mutable: `mut b`
...
LL | b = Box::new(2); //[ast]~ ERROR cannot assign twice to immutable variable
| ^ cannot assign twice to immutable variable
fn test() {
let b = Box::new(1); //[ast]~ NOTE first assignment
//[mir]~^ NOTE first assignment
- //[mir]~| NOTE consider changing this to `mut b`
+ //[mir]~| HELP make this binding mutable
+ //[mir]~| SUGGESTION mut b
drop(b);
b = Box::new(2); //[ast]~ ERROR cannot assign twice to immutable variable
//[mir]~^ ERROR cannot assign twice to immutable variable `b`
error[E0384]: cannot assign twice to immutable variable `v`
- --> $DIR/liveness-assign-imm-local-with-init.rs:19:5
+ --> $DIR/liveness-assign-imm-local-with-init.rs:20:5
|
LL | let v: isize = 1; //[ast]~ NOTE first assignment
| -
| |
| first assignment to `v`
- | consider changing this to `mut v`
+ | help: make this binding mutable: `mut v`
...
LL | v = 2; //[ast]~ ERROR cannot assign twice to immutable variable
| ^^^^^ cannot assign twice to immutable variable
error[E0384]: cannot assign twice to immutable variable `v`
- --> $DIR/liveness-assign-imm-local-with-init.rs:19:5
+ --> $DIR/liveness-assign-imm-local-with-init.rs:20:5
|
LL | let v: isize = 1; //[ast]~ NOTE first assignment
| - first assignment to `v`
error[E0384]: cannot assign twice to immutable variable `v`
- --> $DIR/liveness-assign-imm-local-with-init.rs:19:5
+ --> $DIR/liveness-assign-imm-local-with-init.rs:20:5
|
LL | let v: isize = 1; //[ast]~ NOTE first assignment
| -
| |
| first assignment to `v`
- | consider changing this to `mut v`
+ | help: make this binding mutable: `mut v`
...
LL | v = 2; //[ast]~ ERROR cannot assign twice to immutable variable
| ^^^^^ cannot assign twice to immutable variable
fn test() {
let v: isize = 1; //[ast]~ NOTE first assignment
//[mir]~^ NOTE first assignment
- //[mir]~| NOTE consider changing this to `mut v`
+ //[mir]~| HELP make this binding mutable
+ //[mir]~| SUGGESTION mut v
v.clone();
v = 2; //[ast]~ ERROR cannot assign twice to immutable variable
//[mir]~^ ERROR cannot assign twice to immutable variable `v`
|
= note: move occurs because `y` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
-error[E0382]: use of moved value: `y`
- --> $DIR/liveness-move-in-while.rs:18:52
- |
-LL | while true { while true { while true { x = y; x.clone(); } } }
- | ^ value moved here in previous iteration of loop
- |
- = note: move occurs because `y` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
For more information about this error, try `rustc --explain E0382`.
--- /dev/null
+warning: the feature `extern_prelude` has been stable since 1.30.0 and no longer requires an attribute to enable
+ --> $DIR/macro-path-prelude-pass.rs:13:12
+ |
+LL | #![feature(extern_prelude)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: #[warn(stable_features)] on by default
+
--> $DIR/span-covering-argument-1.rs:15:19
|
LL | let $s = 0;
- | -- consider changing this to `mut $s`
+ | -- help: make this binding mutable: `mut $s`
LL | *&mut $s = 0;
| ^^ cannot borrow mutably
...
--- /dev/null
+// Copyright 2018 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn foo(_: u16) {}
+fn foo1(_: f64) {}
+fn foo2(_: i32) {}
+
+fn main() {
+ foo(1u8);
+ foo1(2f32);
+ foo2(3i16);
+}
+
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/numeric-literal-cast.rs:16:9
+ |
+LL | foo(1u8);
+ | ^^^ expected u16, found u8
+help: change the type of the numeric literal from `u8` to `u16`
+ |
+LL | foo(1u16);
+ | ^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-literal-cast.rs:17:10
+ |
+LL | foo1(2f32);
+ | ^^^^ expected f64, found f32
+help: change the type of the numeric literal from `f32` to `f64`
+ |
+LL | foo1(2f64);
+ | ^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/numeric-literal-cast.rs:18:10
+ |
+LL | foo2(3i16);
+ | ^^^^ expected i32, found i16
+help: change the type of the numeric literal from `i16` to `i32`
+ |
+LL | foo2(3i32);
+ | ^^^^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
| -
| |
| first assignment to `x`
- | consider changing this to `mut x`
+ | help: make this binding mutable: `mut x`
LL | x += 1; //[ast]~ ERROR cannot assign twice to immutable variable
| ^^^^^^ cannot assign twice to immutable variable
| -
| |
| first assignment to `x`
- | consider changing this to `mut x`
+ | help: make this binding mutable: `mut x`
LL | x += 1; //[ast]~ ERROR cannot assign twice to immutable variable
| ^^^^^^ cannot assign twice to immutable variable
error[E0596]: cannot borrow `arg` as mutable, as it is not declared as mutable
- --> $DIR/mut-suggestion.rs:21:5
+ --> $DIR/mut-suggestion.rs:22:5
|
LL | fn func(arg: S) {
| --- help: consider changing this to be mutable: `mut arg`
-LL | //~^ consider changing this to `mut arg`
+...
LL | arg.mutate();
| ^^^ cannot borrow as mutable
error[E0596]: cannot borrow `local` as mutable, as it is not declared as mutable
- --> $DIR/mut-suggestion.rs:29:5
+ --> $DIR/mut-suggestion.rs:31:5
|
LL | let local = S;
| ----- help: consider changing this to be mutable: `mut local`
-LL | //~^ consider changing this to `mut local`
+...
LL | local.mutate();
| ^^^^^ cannot borrow as mutable
}
fn func(arg: S) {
- //~^ consider changing this to `mut arg`
+ //~^ HELP make this binding mutable
+ //~| SUGGESTION mut arg
arg.mutate();
//~^ ERROR cannot borrow immutable argument
//~| cannot borrow mutably
fn main() {
let local = S;
- //~^ consider changing this to `mut local`
+ //~^ HELP make this binding mutable
+ //~| SUGGESTION mut local
local.mutate();
//~^ ERROR cannot borrow immutable local variable
//~| cannot borrow mutably
error[E0596]: cannot borrow immutable argument `arg` as mutable
- --> $DIR/mut-suggestion.rs:21:5
+ --> $DIR/mut-suggestion.rs:22:5
|
LL | fn func(arg: S) {
- | --- consider changing this to `mut arg`
-LL | //~^ consider changing this to `mut arg`
+ | --- help: make this binding mutable: `mut arg`
+...
LL | arg.mutate();
| ^^^ cannot borrow mutably
error[E0596]: cannot borrow immutable local variable `local` as mutable
- --> $DIR/mut-suggestion.rs:29:5
+ --> $DIR/mut-suggestion.rs:31:5
|
LL | let local = S;
- | ----- consider changing this to `mut local`
-LL | //~^ consider changing this to `mut local`
+ | ----- help: make this binding mutable: `mut local`
+...
LL | local.mutate();
| ^^^^^ cannot borrow mutably
--> $DIR/mutable-class-fields.rs:28:3
|
LL | let nyan : cat = cat(52, 99);
- | ---- consider changing this to `mut nyan`
+ | ---- help: make this binding mutable: `mut nyan`
LL | nyan.how_hungry = 0; //[ast]~ ERROR cannot assign
| ^^^^^^^^^^^^^^^^^^^ cannot mutably borrow field of immutable binding
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+//
+// run-pass
+//
+// FIXME(#54366) - We probably shouldn't allow #[thread_local] static mut to get a 'static lifetime.
+
+#![feature(nll)]
+#![feature(thread_local)]
+
+#[thread_local]
+static mut X1: u64 = 0;
+
+struct S1 {
+ a: &'static mut u64,
+}
+
+impl S1 {
+ fn new(_x: u64) -> S1 {
+ S1 {
+ a: unsafe { &mut X1 },
+ }
+ }
+}
+
+fn main() {
+ S1::new(0).a;
+}
--- /dev/null
+// Copyright 2018 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(nll)]
+
+struct A {
+ b: B,
+}
+
+#[derive(Clone)]
+struct B;
+
+fn foo(_: A) {}
+
+fn bar(mut a: A) -> B {
+ a.b = B;
+ foo(a);
+ a.b.clone()
+}
+
+fn main() {}
--- /dev/null
+error[E0382]: borrow of moved value: `a.b`
+ --> $DIR/issue-52669.rs:25:5
+ |
+LL | foo(a);
+ | - value moved here
+LL | a.b.clone()
+ | ^^^ value borrowed here after move
+ |
+ = note: move occurs because `a` has type `A`, which does not implement the `Copy` trait
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
--- /dev/null
+error[E0382]: use of moved value
+ --> $DIR/issue-53807.rs:14:21
+ |
+LL | if let Some(thing) = maybe {
+ | ^^^^^ value moved here in previous iteration of loop
+ |
+ = note: move occurs because value has type `std::vec::Vec<bool>`, which does not implement the `Copy` trait
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
--- /dev/null
+// Copyright 2018 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub fn main(){
+ let maybe = Some(vec![true, true]);
+ loop {
+ if let Some(thing) = maybe {
+ }
+ }
+}
--- /dev/null
+error[E0382]: use of partially moved value: `maybe`
+ --> $DIR/issue-53807.rs:14:30
+ |
+LL | if let Some(thing) = maybe {
+ | ----- ^^^^^ value used here after move
+ | |
+ | value moved here
+ |
+ = note: move occurs because the value has type `std::vec::Vec<bool>`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `(maybe as std::prelude::v1::Some).0`
+ --> $DIR/issue-53807.rs:14:21
+ |
+LL | if let Some(thing) = maybe {
+ | ^^^^^ value moved here in previous iteration of loop
+ |
+ = note: move occurs because the value has type `std::vec::Vec<bool>`, which does not implement the `Copy` trait
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
--- /dev/null
+// Copyright 2018 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(nll)]
+
+fn main() {
+ let x = (vec![1, 2, 3], );
+ drop(x.0);
+ drop(x);
+}
--- /dev/null
+error[E0382]: use of moved value: `x`
+ --> $DIR/move-subpaths-moves-root.rs:16:10
+ |
+LL | drop(x.0);
+ | --- value moved here
+LL | drop(x);
+ | ^ value used here after move
+ |
+ = note: move occurs because `x.0` has type `std::vec::Vec<i32>`, which does not implement the `Copy` trait
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
|
= note: move occurs because `arc_v` has type `std::sync::Arc<std::vec::Vec<i32>>`, which does not implement the `Copy` trait
-error[E0382]: borrow of moved value: `arc_v`
- --> $DIR/no-capture-arc.rs:26:23
- |
-LL | thread::spawn(move|| {
- | ------ value moved into closure here
-LL | assert_eq!((*arc_v)[3], 4);
- | ----- variable moved due to use in closure
-...
-LL | println!("{:?}", *arc_v);
- | ^^^^^ value borrowed here after move
- |
- = note: move occurs because `arc_v` has type `std::sync::Arc<std::vec::Vec<i32>>`, which does not implement the `Copy` trait
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
For more information about this error, try `rustc --explain E0382`.
|
= note: move occurs because `arc_v` has type `std::sync::Arc<std::vec::Vec<i32>>`, which does not implement the `Copy` trait
-error[E0382]: borrow of moved value: `arc_v`
- --> $DIR/no-reuse-move-arc.rs:24:23
- |
-LL | thread::spawn(move|| {
- | ------ value moved into closure here
-LL | assert_eq!((*arc_v)[3], 4);
- | ----- variable moved due to use in closure
-...
-LL | println!("{:?}", *arc_v); //~ ERROR use of moved value: `arc_v`
- | ^^^^^ value borrowed here after move
- |
- = note: move occurs because `arc_v` has type `std::sync::Arc<std::vec::Vec<i32>>`, which does not implement the `Copy` trait
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
For more information about this error, try `rustc --explain E0382`.
-error: use of deprecated attribute `panic_implementation`: This attribute was renamed to `panic_handler`. See https://github.com/rust-lang/rust/issues/44489#issuecomment-415140224
+error: use of deprecated attribute `panic_implementation`: this attribute was renamed to `panic_handler`. See https://github.com/rust-lang/rust/issues/44489#issuecomment-415140224
--> $DIR/panic-implementation-deprecated.rs:19:1
|
LL | #[panic_implementation]
- | ^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+ | ^^^^^^^^^^^^^^^^^^^^^^^ help: replace this attribute with `#[panic_handler]`
|
note: lint level defined here
--> $DIR/panic-implementation-deprecated.rs:13:9
--- /dev/null
+// Adaptation of existing ui test (from way back in
+// rust-lang/rust#2329), that starts passing with this feature in
+// place.
+
+// compile-pass
+
+#![feature(nll)]
+#![feature(bind_by_move_pattern_guards)]
+
+use std::sync::mpsc::channel;
+
+fn main() {
+ let (tx, rx) = channel();
+ let x = Some(rx);
+ tx.send(false);
+ match x {
+ Some(z) if z.recv().unwrap() => { panic!() },
+ Some(z) => { assert!(!z.recv().unwrap()); },
+ None => panic!()
+ }
+}
--- /dev/null
+error[E0008]: cannot bind by-move into a pattern guard
+ --> $DIR/feature-gate.rs:33:16
+ |
+LL | A { a: v } if *v == 42 => v,
+ | ^ moves value into pattern guard
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0008`.
--- /dev/null
+error: compilation successful
+ --> $DIR/feature-gate.rs:42:1
+ |
+LL | / fn main() {
+LL | | foo(107)
+LL | | }
+ | |_^
+
+error: aborting due to previous error
+
--- /dev/null
+error: compilation successful
+ --> $DIR/feature-gate.rs:42:1
+ |
+LL | / fn main() {
+LL | | foo(107)
+LL | | }
+ | |_^
+
+error: aborting due to previous error
+
--- /dev/null
+error: compilation successful
+ --> $DIR/feature-gate.rs:42:1
+ |
+LL | / fn main() {
+LL | | foo(107)
+LL | | }
+ | |_^
+
+error: aborting due to previous error
+
--- /dev/null
+error[E0008]: cannot bind by-move into a pattern guard
+ --> $DIR/feature-gate.rs:33:16
+ |
+LL | A { a: v } if *v == 42 => v,
+ | ^ moves value into pattern guard
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0008`.
--- /dev/null
+// Check that pattern-guards with move-bound variables is only allowed
+// with the appropriate set of feature gates. (Note that we require
+// the code to opt into MIR-borrowck in *some* way before the feature
+// will work; we use the revision system here to enumerate a number of
+// ways that opt-in could occur.)
+
+// gate-test-bind_by_move_pattern_guards
+
+// revisions: no_gate gate_and_2015 gate_and_2018 gate_and_znll gate_and_feature_nll
+
+// (We're already testing NLL behavior quite explicitly, no need for compare-mode=nll.)
+// ignore-compare-mode-nll
+
+#![feature(rustc_attrs)]
+
+#![cfg_attr(gate_and_2015, feature(bind_by_move_pattern_guards))]
+#![cfg_attr(gate_and_2018, feature(bind_by_move_pattern_guards))]
+#![cfg_attr(gate_and_znll, feature(bind_by_move_pattern_guards))]
+#![cfg_attr(gate_and_feature_nll, feature(bind_by_move_pattern_guards))]
+
+#![cfg_attr(gate_and_feature_nll, feature(nll))]
+
+//[gate_and_2015] edition:2015
+//[gate_and_2018] edition:2018
+//[gate_and_znll] compile-flags: -Z borrowck=mir
+
+struct A { a: Box<i32> }
+
+fn foo(n: i32) {
+ let x = A { a: Box::new(n) };
+ let _y = match x {
+
+ A { a: v } if *v == 42 => v,
+ //[no_gate]~^ ERROR cannot bind by-move into a pattern guard
+ //[gate_and_2015]~^^ ERROR cannot bind by-move into a pattern guard
+
+ _ => Box::new(0)
+ };
+}
+
+#[rustc_error]
+fn main() {
+ foo(107)
+}
+//[gate_and_2018]~^^^ ERROR compilation successful
+//[gate_and_znll]~^^^^ ERROR compilation successful
+//[gate_and_feature_nll]~^^^^^ ERROR compilation successful
--- /dev/null
+#![feature(nll)]
+#![feature(bind_by_move_pattern_guards)]
+
+// compile-pass
+
+struct A { a: Box<i32> }
+
+impl A {
+ fn get(&self) -> i32 { *self.a }
+}
+
+fn foo(n: i32) {
+ let x = A { a: Box::new(n) };
+ let y = match x {
+ A { a: v } if *v == 42 => v,
+ _ => Box::new(0),
+ };
+}
+
+fn bar(n: i32) {
+ let x = A { a: Box::new(n) };
+ let y = match x {
+ A { a: v } if x.get() == 42 => v,
+ _ => Box::new(0),
+ };
+}
+
+fn baz(n: i32) {
+ let x = A { a: Box::new(n) };
+ let y = match x {
+ A { a: v } if *v.clone() == 42 => v,
+ _ => Box::new(0),
+ };
+}
+
+fn main() {
+ foo(107);
+ bar(107);
+ baz(107);
+}
--- /dev/null
+#![feature(nll)]
+#![feature(bind_by_move_pattern_guards)]
+
+enum VecWrapper { A(Vec<i32>) }
+
+fn foo(x: VecWrapper) -> usize {
+ match x {
+ VecWrapper::A(v) if { drop(v); false } => 1,
+ //~^ ERROR cannot move out of borrowed content
+ VecWrapper::A(v) => v.len()
+ }
+}
+
+fn main() {
+ foo(VecWrapper::A(vec![107]));
+}
--- /dev/null
+error[E0507]: cannot move out of borrowed content
+ --> $DIR/rfc-reject-double-move-across-arms.rs:8:36
+ |
+LL | VecWrapper::A(v) if { drop(v); false } => 1,
+ | ^ cannot move out of borrowed content
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0507`.
--- /dev/null
+#![feature(nll)]
+#![feature(bind_by_move_pattern_guards)]
+
+struct A { a: Box<i32> }
+
+fn foo(n: i32) {
+ let x = A { a: Box::new(n) };
+ let _y = match x {
+ A { a: v } if { drop(v); true } => v,
+ //~^ ERROR cannot move out of borrowed content
+ _ => Box::new(0),
+ };
+}
+
+fn main() {
+ foo(107);
+}
--- /dev/null
+error[E0507]: cannot move out of borrowed content
+ --> $DIR/rfc-reject-double-move-in-first-arm.rs:9:30
+ |
+LL | A { a: v } if { drop(v); true } => v,
+ | ^ cannot move out of borrowed content
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0507`.
--- /dev/null
+// Copyright 2018 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// edition:2018
+
+// Tests that `meta` is whitelisted, even if the crate doesn't exist
+// yet (i.e. it causes a different error than `not-whitelisted.rs`).
+use meta; //~ ERROR can't find crate for `meta`
+
+fn main() {}
--- /dev/null
+error[E0463]: can't find crate for `meta`
+ --> $DIR/meta.rs:15:5
+ |
+LL | use meta; //~ ERROR can't find crate for `meta`
+ | ^^^^ can't find crate
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0463`.
// edition:2018
-use xcrate::S; //~ ERROR can't find crate for `xcrate`
+use xcrate::S; //~ ERROR unresolved import `xcrate`
fn main() {}
-error[E0463]: can't find crate for `xcrate`
+error[E0432]: unresolved import `xcrate`
--> $DIR/non-existent-1.rs:13:5
|
-LL | use xcrate::S; //~ ERROR can't find crate for `xcrate`
- | ^^^^^^ can't find crate
+LL | use xcrate::S; //~ ERROR unresolved import `xcrate`
+ | ^^^^^^ Could not find `xcrate` in `{{root}}`
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0463`.
+For more information about this error, try `rustc --explain E0432`.
// edition:2018
fn main() {
- let s = ::xcrate::S; //~ ERROR can't find crate for `xcrate`
+ let s = ::xcrate::S;
+ //~^ ERROR failed to resolve. Could not find `xcrate` in `{{root}}`
}
-error[E0463]: can't find crate for `xcrate`
+error[E0433]: failed to resolve. Could not find `xcrate` in `{{root}}`
--> $DIR/non-existent-2.rs:14:15
|
-LL | let s = ::xcrate::S; //~ ERROR can't find crate for `xcrate`
- | ^^^^^^ can't find crate
+LL | let s = ::xcrate::S;
+ | ^^^^^^ Could not find `xcrate` in `{{root}}`
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0463`.
+For more information about this error, try `rustc --explain E0433`.
// edition:2018
-use ycrate; //~ ERROR can't find crate for `ycrate`
+use ycrate; //~ ERROR unresolved import `ycrate`
fn main() {}
-error[E0463]: can't find crate for `ycrate`
+error[E0432]: unresolved import `ycrate`
--> $DIR/non-existent-3.rs:13:5
|
-LL | use ycrate; //~ ERROR can't find crate for `ycrate`
- | ^^^^^^ can't find crate
+LL | use ycrate; //~ ERROR unresolved import `ycrate`
+ | ^^^^^^ no `ycrate` external crate
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0463`.
+For more information about this error, try `rustc --explain E0432`.
--- /dev/null
+// Copyright 2018 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// edition:2018
+
+// Tests that arbitrary crates (other than `core`, `std` and `meta`)
+// aren't allowed without `--extern`, even if they're in the sysroot.
+use alloc; //~ ERROR unresolved import `alloc`
+use test; //~ ERROR unresolved import `test`
+use proc_macro; //~ ERROR unresolved import `proc_macro`
+
+fn main() {}
--- /dev/null
+error[E0432]: unresolved import `alloc`
+ --> $DIR/not-whitelisted.rs:15:5
+ |
+LL | use alloc; //~ ERROR unresolved import `alloc`
+ | ^^^^^ no `alloc` external crate
+
+error[E0432]: unresolved import `test`
+ --> $DIR/not-whitelisted.rs:16:5
+ |
+LL | use test; //~ ERROR unresolved import `test`
+ | ^^^^ no `test` external crate
+
+error[E0432]: unresolved import `proc_macro`
+ --> $DIR/not-whitelisted.rs:17:5
+ |
+LL | use proc_macro; //~ ERROR unresolved import `proc_macro`
+ | ^^^^^^^^^^ no `proc_macro` external crate
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0432`.
// except according to those terms.
// aux-build:xcrate.rs
+// compile-flags:--extern xcrate
// edition:2018
use crate; //~ ERROR crate root imports need to be explicitly named: `use crate as name;`
error: crate root imports need to be explicitly named: `use crate as name;`
- --> $DIR/single-segment.rs:14:5
+ --> $DIR/single-segment.rs:15:5
|
LL | use crate; //~ ERROR crate root imports need to be explicitly named: `use crate as name;`
| ^^^^^
error: cannot glob-import all possible crates
- --> $DIR/single-segment.rs:15:5
+ --> $DIR/single-segment.rs:16:5
|
LL | use *; //~ ERROR cannot glob-import all possible crates
| ^
error[E0423]: expected value, found module `xcrate`
- --> $DIR/single-segment.rs:18:13
+ --> $DIR/single-segment.rs:19:13
|
LL | let s = ::xcrate; //~ ERROR expected value, found module `xcrate`
| ^^^^^^^^ not a value
#![feature(extern_in_paths)]
-use extern::xcrate::S; //~ ERROR can't find crate for `xcrate`
+use extern::xcrate::S; //~ ERROR unresolved import `extern::xcrate`
fn main() {}
-error[E0463]: can't find crate for `xcrate`
+error[E0432]: unresolved import `extern::xcrate`
--> $DIR/non-existent-1.rs:13:13
|
-LL | use extern::xcrate::S; //~ ERROR can't find crate for `xcrate`
- | ^^^^^^ can't find crate
+LL | use extern::xcrate::S; //~ ERROR unresolved import `extern::xcrate`
+ | ^^^^^^ Could not find `xcrate` in `extern`
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0463`.
+For more information about this error, try `rustc --explain E0432`.
#![feature(extern_in_paths)]
fn main() {
- let s = extern::xcrate::S; //~ ERROR can't find crate for `xcrate`
+ let s = extern::xcrate::S;
+ //~^ ERROR failed to resolve. Could not find `xcrate` in `extern`
}
-error[E0463]: can't find crate for `xcrate`
+error[E0433]: failed to resolve. Could not find `xcrate` in `extern`
--> $DIR/non-existent-2.rs:14:21
|
-LL | let s = extern::xcrate::S; //~ ERROR can't find crate for `xcrate`
- | ^^^^^^ can't find crate
+LL | let s = extern::xcrate::S;
+ | ^^^^^^ Could not find `xcrate` in `extern`
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0463`.
+For more information about this error, try `rustc --explain E0433`.
#![feature(extern_in_paths)]
-use extern::ycrate; //~ ERROR can't find crate for `ycrate`
+use extern::ycrate; //~ ERROR unresolved import `extern::ycrate`
fn main() {}
-error[E0463]: can't find crate for `ycrate`
- --> $DIR/non-existent-3.rs:13:13
+error[E0432]: unresolved import `extern::ycrate`
+ --> $DIR/non-existent-3.rs:13:5
|
-LL | use extern::ycrate; //~ ERROR can't find crate for `ycrate`
- | ^^^^^^ can't find crate
+LL | use extern::ycrate; //~ ERROR unresolved import `extern::ycrate`
+ | ^^^^^^^^^^^^^^ no `ycrate` external crate
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0463`.
+For more information about this error, try `rustc --explain E0432`.
// except according to those terms.
// aux-build:xcrate.rs
+// compile-flags:--extern xcrate
#![feature(extern_in_paths)]
error: cannot glob-import all possible crates
- --> $DIR/single-segment.rs:17:5
+ --> $DIR/single-segment.rs:18:5
|
LL | use extern::*; //~ ERROR cannot glob-import all possible crates
| ^^^^^^^^^
error[E0432]: unresolved import `extern`
- --> $DIR/single-segment.rs:15:5
+ --> $DIR/single-segment.rs:16:5
|
LL | use extern; //~ ERROR unresolved import `extern`
| ^^^^^^ no `extern` in the root
error[E0423]: expected value, found module `extern::xcrate`
- --> $DIR/single-segment.rs:20:13
+ --> $DIR/single-segment.rs:21:13
|
LL | let s = extern::xcrate; //~ ERROR expected value, found module `extern::xcrate`
| ^^^^^^^^^^^^^^ not a value
--- /dev/null
+warning: the feature `extern_prelude` has been stable since 1.30.0 and no longer requires an attribute to enable
+ --> $DIR/extern-prelude-core.rs:12:12
+ |
+LL | #![feature(extern_prelude, lang_items, start, alloc)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: #[warn(stable_features)] on by default
+
--- /dev/null
+warning: the feature `extern_prelude` has been stable since 1.30.0 and no longer requires an attribute to enable
+ --> $DIR/extern-prelude-std.rs:12:12
+ |
+LL | #![feature(extern_prelude)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: #[warn(stable_features)] on by default
+
// run-pass
// aux-build:some_crate.rs
+// compile-flags:--extern some_crate
// edition:2018
mod foo {
// run-pass
// aux-build:some_crate.rs
+// compile-flags:--extern some_crate
// edition:2018
use some_crate as some_name;
// run-pass
// aux-build:png2.rs
+// compile-flags:--extern png2
// edition:2018
mod png {
#[test]
fn cfg() {
- cfg!(pants);
- cfg!(pants,);
- cfg!(pants = "pants");
- cfg!(pants = "pants",);
- cfg!(all(pants));
- cfg!(all(pants),);
- cfg!(all(pants,));
- cfg!(all(pants,),);
+ let _ = cfg!(pants);
+ let _ = cfg!(pants,);
+ let _ = cfg!(pants = "pants");
+ let _ = cfg!(pants = "pants",);
+ let _ = cfg!(all(pants));
+ let _ = cfg!(all(pants),);
+ let _ = cfg!(all(pants,));
+ let _ = cfg!(all(pants,),);
}
#[test]
fn column() {
- column!();
+ let _ = column!();
}
// compile_error! is in a companion to this test in compile-fail
#[test]
fn concat() {
- concat!();
- concat!("hello");
- concat!("hello",);
- concat!("hello", " world");
- concat!("hello", " world",);
+ let _ = concat!();
+ let _ = concat!("hello");
+ let _ = concat!("hello",);
+ let _ = concat!("hello", " world");
+ let _ = concat!("hello", " world",);
}
#[test]
#[test]
fn env() {
- env!("PATH");
- env!("PATH",);
- env!("PATH", "not found");
- env!("PATH", "not found",);
+ let _ = env!("PATH");
+ let _ = env!("PATH",);
+ let _ = env!("PATH", "not found");
+ let _ = env!("PATH", "not found",);
}
#[cfg(std)]
#[test]
fn file() {
- file!();
+ let _ = file!();
}
#[cfg(std)]
#[test]
fn format() {
- format!("hello");
- format!("hello",);
- format!("hello {}", "world");
- format!("hello {}", "world",);
+ let _ = format!("hello");
+ let _ = format!("hello",);
+ let _ = format!("hello {}", "world");
+ let _ = format!("hello {}", "world",);
}
#[test]
fn format_args() {
- format_args!("hello");
- format_args!("hello",);
- format_args!("hello {}", "world");
- format_args!("hello {}", "world",);
+ let _ = format_args!("hello");
+ let _ = format_args!("hello",);
+ let _ = format_args!("hello {}", "world");
+ let _ = format_args!("hello {}", "world",);
}
#[test]
fn include() {
- include!("auxiliary/macro-comma-support.rs");
- include!("auxiliary/macro-comma-support.rs",);
+ let _ = include!("auxiliary/macro-comma-support.rs");
+ let _ = include!("auxiliary/macro-comma-support.rs",);
}
#[test]
fn include_bytes() {
- include_bytes!("auxiliary/macro-comma-support.rs");
- include_bytes!("auxiliary/macro-comma-support.rs",);
+ let _ = include_bytes!("auxiliary/macro-comma-support.rs");
+ let _ = include_bytes!("auxiliary/macro-comma-support.rs",);
}
#[test]
fn include_str() {
- include_str!("auxiliary/macro-comma-support.rs");
- include_str!("auxiliary/macro-comma-support.rs",);
+ let _ = include_str!("auxiliary/macro-comma-support.rs");
+ let _ = include_str!("auxiliary/macro-comma-support.rs",);
}
#[test]
fn line() {
- line!();
+ let _ = line!();
}
#[test]
fn module_path() {
- module_path!();
+ let _ = module_path!();
}
#[test]
fn option_env() {
- option_env!("PATH");
- option_env!("PATH",);
+ let _ = option_env!("PATH");
+ let _ = option_env!("PATH",);
}
#[test]
#[test]
fn vec() {
let _: Vec<()> = vec![];
- vec![0];
- vec![0,];
- vec![0, 1];
- vec![0, 1,];
+ let _ = vec![0];
+ let _ = vec![0,];
+ let _ = vec![0, 1];
+ let _ = vec![0, 1,];
}
// give a test body access to a fmt::Formatter, which seems
test_with_formatter! {
#[test]
fn write(f: &mut fmt::Formatter) {
- write!(f, "hello");
- write!(f, "hello",);
- write!(f, "hello {}", "world");
- write!(f, "hello {}", "world",);
+ let _ = write!(f, "hello");
+ let _ = write!(f, "hello",);
+ let _ = write!(f, "hello {}", "world");
+ let _ = write!(f, "hello {}", "world",);
}
}
test_with_formatter! {
#[test]
fn writeln(f: &mut fmt::Formatter) {
- writeln!(f);
- writeln!(f,);
- writeln!(f, "hello");
- writeln!(f, "hello",);
- writeln!(f, "hello {}", "world");
- writeln!(f, "hello {}", "world",);
+ let _ = writeln!(f);
+ let _ = writeln!(f,);
+ let _ = writeln!(f, "hello");
+ let _ = writeln!(f, "hello",);
+ let _ = writeln!(f, "hello {}", "world");
+ let _ = writeln!(f, "hello {}", "world",);
}
}
--- /dev/null
+warning: the feature `crate_in_paths` has been stable since 1.30.0 and no longer requires an attribute to enable
+ --> $DIR/crate-path-absolute.rs:12:12
+ |
+LL | #![feature(crate_in_paths)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: #[warn(stable_features)] on by default
+
--- /dev/null
+warning: the feature `crate_in_paths` has been stable since 1.30.0 and no longer requires an attribute to enable
+ --> $DIR/crate-path-visibility-ambiguity.rs:12:12
+ |
+LL | #![feature(crate_in_paths)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: #[warn(stable_features)] on by default
+
// run-pass
// aux-build:xcrate.rs
+// compile-flags:--extern xcrate
// edition:2018
use xcrate::Z;
// run-pass
// aux-build:xcrate.rs
+// compile-flags:--extern xcrate
#![feature(extern_in_paths)]
--- /dev/null
+// Copyright 2018 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// run-pass
+// edition:2018
+
+// Tests that `core` and `std` are always available.
+use core::iter;
+use std::io;
+// FIXME(eddyb) Add a `meta` crate to the distribution.
+// use meta;
+
+fn main() {
+ for _ in iter::once(()) {
+ io::stdout();
+ }
+}
{
// Test that having `std_io` in a module scope and a non-module
// scope is allowed, when both resolve to the same definition.
- use std::io as std_io;
+ use ::std::io as std_io;
use std_io::stdout;
stdout();
}
// aux-build:edition-lint-paths.rs
// run-rustfix
+// compile-flags:--extern edition_lint_paths
// edition:2018
// The "normal case". Ideally we would remove the `extern crate` here,
// aux-build:edition-lint-paths.rs
// run-rustfix
+// compile-flags:--extern edition_lint_paths
// edition:2018
// The "normal case". Ideally we would remove the `extern crate` here,
error: unused extern crate
- --> $DIR/extern-crate-idiomatic-in-2018.rs:21:1
+ --> $DIR/extern-crate-idiomatic-in-2018.rs:22:1
|
LL | extern crate edition_lint_paths;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove it
|
note: lint level defined here
- --> $DIR/extern-crate-idiomatic-in-2018.rs:18:9
+ --> $DIR/extern-crate-idiomatic-in-2018.rs:19:9
|
LL | #![deny(rust_2018_idioms)]
| ^^^^^^^^^^^^^^^^
= note: #[deny(unused_extern_crates)] implied by #[deny(rust_2018_idioms)]
error: `extern crate` is not idiomatic in the new edition
- --> $DIR/extern-crate-idiomatic-in-2018.rs:24:1
+ --> $DIR/extern-crate-idiomatic-in-2018.rs:25:1
|
LL | extern crate edition_lint_paths as bar;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: convert it to a `use`
// run-pass
// aux-build:edition-lint-paths.rs
+// compile-flags:--extern edition_lint_paths
// run-rustfix
// The "normal case". Ideally we would remove the `extern crate` here,
// run-pass
// aux-build:edition-lint-paths.rs
+// compile-flags:--extern edition_lint_paths
// run-rustfix
// The "normal case". Ideally we would remove the `extern crate` here,
--- /dev/null
+// Copyright 2018 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// edition:2018
+
+#![no_std]
+#![crate_type = "lib"]
+
+use alloc::vec;
+//~^ ERROR unresolved import `alloc`
+
+pub fn foo() {
+ let mut xs = vec![];
+ //~^ ERROR cannot determine resolution for the macro `vec`
+ xs.push(0);
+}
--- /dev/null
+error[E0432]: unresolved import `alloc`
+ --> $DIR/issue-54006.rs:16:5
+ |
+LL | use alloc::vec;
+ | ^^^^^ Could not find `alloc` in `{{root}}`
+
+error: cannot determine resolution for the macro `vec`
+ --> $DIR/issue-54006.rs:20:18
+ |
+LL | let mut xs = vec![];
+ | ^^^
+ |
+ = note: import resolution is stuck, try simplifying macro imports
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0432`.
// edition:2018
// compile-pass
// aux-build:remove-extern-crate.rs
+// compile-flags:--extern remove_extern_crate
#![warn(rust_2018_idioms)]
// edition:2018
// compile-pass
// aux-build:remove-extern-crate.rs
+// compile-flags:--extern remove_extern_crate
#![warn(rust_2018_idioms)]
warning: unused extern crate
- --> $DIR/remove-extern-crate.rs:18:1
+ --> $DIR/remove-extern-crate.rs:19:1
|
LL | extern crate core;
| ^^^^^^^^^^^^^^^^^^ help: remove it
|
note: lint level defined here
- --> $DIR/remove-extern-crate.rs:16:9
+ --> $DIR/remove-extern-crate.rs:17:9
|
LL | #![warn(rust_2018_idioms)]
| ^^^^^^^^^^^^^^^^
= note: #[warn(unused_extern_crates)] implied by #[warn(rust_2018_idioms)]
warning: `extern crate` is not idiomatic in the new edition
- --> $DIR/remove-extern-crate.rs:19:1
+ --> $DIR/remove-extern-crate.rs:20:1
|
LL | extern crate core as another_name;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: convert it to a `use`
warning: `extern crate` is not idiomatic in the new edition
- --> $DIR/remove-extern-crate.rs:32:5
+ --> $DIR/remove-extern-crate.rs:33:5
|
LL | extern crate core;
| ^^^^^^^^^^^^^^^^^^ help: convert it to a `use`
--- /dev/null
+// Copyright 2018 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// edition:2018
+
+// Dummy import to introduce `uniform_paths` canaries.
+use std;
+
+// fn version() -> &'static str {""}
+
+mod foo {
+ // Error wasn't reported, despite `version` being commented out above.
+ use crate::version; //~ ERROR unresolved import `crate::version`
+
+ fn bar() {
+ version();
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0432]: unresolved import `crate::version`
+ --> $DIR/issue-54253.rs:20:9
+ |
+LL | use crate::version; //~ ERROR unresolved import `crate::version`
+ | ^^^^^^^^^^^^^^ no `version` in the root
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0432`.
--- /dev/null
+// Copyright 2018 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// edition:2018
+
+#![feature(uniform_paths)]
+
+// Dummy import to introduce `uniform_paths` canaries.
+use std;
+
+// fn version() -> &'static str {""}
+
+mod foo {
+ // Error wasn't reported, despite `version` being commented out above.
+ use crate::version; //~ ERROR unresolved import `crate::version`
+
+ fn bar() {
+ version();
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0432]: unresolved import `crate::version`
+ --> $DIR/issue-54253.rs:22:9
+ |
+LL | use crate::version; //~ ERROR unresolved import `crate::version`
+ | ^^^^^^^^^^^^^^ no `version` in the root
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0432`.
--> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:63:24
|
LL | fn deref_mut_field1(x: Own<Point>) {
- | - consider changing this to `mut x`
+ | - help: make this binding mutable: `mut x`
LL | let __isize = &mut x.y; //~ ERROR cannot borrow
| ^ cannot borrow mutably
--> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:98:5
|
LL | fn assign_field1<'a>(x: Own<Point>) {
- | - consider changing this to `mut x`
+ | - help: make this binding mutable: `mut x`
LL | x.y = 3; //~ ERROR cannot borrow
| ^ cannot borrow mutably
--> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:119:5
|
LL | fn deref_mut_method1(x: Own<Point>) {
- | - consider changing this to `mut x`
+ | - help: make this binding mutable: `mut x`
LL | x.set(0, 0); //~ ERROR cannot borrow
| ^ cannot borrow mutably
--> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:139:6
|
LL | fn assign_method1<'a>(x: Own<Point>) {
- | - consider changing this to `mut x`
+ | - help: make this binding mutable: `mut x`
LL | *x.y_mut() = 3; //~ ERROR cannot borrow
| ^ cannot borrow mutably
--> $DIR/borrowck-borrow-overloaded-deref-mut.rs:39:25
|
LL | fn deref_mut1(x: Own<isize>) {
- | - consider changing this to `mut x`
+ | - help: make this binding mutable: `mut x`
LL | let __isize = &mut *x; //~ ERROR cannot borrow
| ^ cannot borrow mutably
--> $DIR/borrowck-borrow-overloaded-deref-mut.rs:59:6
|
LL | fn assign1<'a>(x: Own<isize>) {
- | - consider changing this to `mut x`
+ | - help: make this binding mutable: `mut x`
LL | *x = 3; //~ ERROR cannot borrow
| ^ cannot borrow mutably
--> $DIR/borrowck-object-mutability.rs:29:5
|
LL | fn owned_receiver(x: Box<Foo>) {
- | - consider changing this to `mut x`
+ | - help: make this binding mutable: `mut x`
LL | x.borrowed();
LL | x.borrowed_mut(); //~ ERROR cannot borrow
| ^ cannot borrow as mutable
--> $DIR/unboxed-closure-immutable-capture.rs:23:5
|
LL | let x = 0;
- | - consider changing this to `mut x`
+ | - help: make this binding mutable: `mut x`
...
LL | || x = 1; //~ ERROR cannot assign
| ^^ cannot borrow mutably
--> $DIR/unboxed-closure-immutable-capture.rs:25:5
|
LL | let x = 0;
- | - consider changing this to `mut x`
+ | - help: make this binding mutable: `mut x`
...
LL | || set(&mut x); //~ ERROR cannot assign
| ^^ cannot borrow mutably
--> $DIR/unboxed-closure-immutable-capture.rs:26:5
|
LL | let x = 0;
- | - consider changing this to `mut x`
+ | - help: make this binding mutable: `mut x`
...
LL | || x = 1; //~ ERROR cannot assign
| ^^ cannot borrow mutably
--> $DIR/unboxed-closure-immutable-capture.rs:28:5
|
LL | let x = 0;
- | - consider changing this to `mut x`
+ | - help: make this binding mutable: `mut x`
...
LL | || set(&mut x); //~ ERROR cannot assign
| ^^ cannot borrow mutably
--> $DIR/unboxed-closures-infer-fnmut-calling-fnmut-no-mut.rs:26:17
|
LL | let tick1 = || {
- | ----- consider changing this to `mut tick1`
+ | ----- help: make this binding mutable: `mut tick1`
...
LL | let tick2 = || { //~ ERROR closure cannot assign to immutable local variable `tick1`
| ^^ cannot borrow mutably
--> $DIR/unboxed-closures-infer-fnmut-calling-fnmut-no-mut.rs:30:5
|
LL | let tick2 = || { //~ ERROR closure cannot assign to immutable local variable `tick1`
- | ----- consider changing this to `mut tick2`
+ | ----- help: make this binding mutable: `mut tick2`
...
LL | tick2(); //~ ERROR cannot borrow
| ^^^^^ cannot borrow mutably
--> $DIR/unboxed-closures-infer-fnmut-missing-mut.rs:17:5
|
LL | let tick = || counter += 1;
- | ---- consider changing this to `mut tick`
+ | ---- help: make this binding mutable: `mut tick`
LL | tick(); //~ ERROR cannot borrow immutable local variable `tick` as mutable
| ^^^^ cannot borrow mutably
--> $DIR/unboxed-closures-infer-fnmut-move-missing-mut.rs:17:5
|
LL | let tick = move || counter += 1;
- | ---- consider changing this to `mut tick`
+ | ---- help: make this binding mutable: `mut tick`
LL | tick(); //~ ERROR cannot borrow immutable local variable `tick` as mutable
| ^^^^ cannot borrow mutably
--> $DIR/unboxed-closures-mutate-upvar.rs:24:27
|
LL | let n = 0;
- | - consider changing this to `mut n`
+ | - help: make this binding mutable: `mut n`
LL | let mut f = to_fn_mut(|| { //~ ERROR closure cannot assign
| ^^ cannot borrow mutably
--> $DIR/writing-to-immutable-vec.rs:14:5
|
LL | let v: Vec<isize> = vec![1, 2, 3];
- | - consider changing this to `mut v`
+ | - help: make this binding mutable: `mut v`
LL | v[1] = 4; //~ ERROR cannot borrow immutable local variable `v` as mutable
| ^ cannot borrow mutably
-Subproject commit a5d82949485802abb45f888d5b8b7f23927f031d
+Subproject commit de314a8b2d45bce4958fc23939c5e4286e31621c
-Subproject commit daa922393c7417dcee930a880c80668cda3e308a
+Subproject commit 125907ad08853b92d35e86aecebcf0f784f348d5
CompileFail,
ParseFail,
RunFail,
+ /// This now behaves like a `ui` test that has an implict `// run-pass`.
RunPass,
RunPassValgrind,
Pretty,
pub force_host: bool,
// Check stdout for error-pattern output as well as stderr
pub check_stdout: bool,
+ // For UI tests, allows compiler to generate arbitrary output to stdout
+ pub dont_check_compiler_stdout: bool,
+ // For UI tests, allows compiler to generate arbitrary output to stderr
+ pub dont_check_compiler_stderr: bool,
// Don't force a --crate-type=dylib flag on the command line
pub no_prefer_dynamic: bool,
// Run --pretty expanded when running pretty printing tests
build_aux_docs: false,
force_host: false,
check_stdout: false,
+ dont_check_compiler_stdout: false,
+ dont_check_compiler_stderr: false,
no_prefer_dynamic: false,
pretty_expanded: false,
pretty_mode: "normal".to_string(),
self.check_stdout = config.parse_check_stdout(ln);
}
+ if !self.dont_check_compiler_stdout {
+ self.dont_check_compiler_stdout = config.parse_dont_check_compiler_stdout(ln);
+ }
+
+ if !self.dont_check_compiler_stderr {
+ self.dont_check_compiler_stderr = config.parse_dont_check_compiler_stderr(ln);
+ }
+
if !self.no_prefer_dynamic {
self.no_prefer_dynamic = config.parse_no_prefer_dynamic(ln);
}
self.parse_name_directive(line, "check-stdout")
}
+ fn parse_dont_check_compiler_stdout(&self, line: &str) -> bool {
+ self.parse_name_directive(line, "dont-check-compiler-stdout")
+ }
+
+ fn parse_dont_check_compiler_stderr(&self, line: &str) -> bool {
+ self.parse_name_directive(line, "dont-check-compiler-stderr")
+ }
+
fn parse_no_prefer_dynamic(&self, line: &str) -> bool {
self.parse_name_directive(line, "no-prefer-dynamic")
}
match self.config.mode {
CompileFail | ParseFail => self.run_cfail_test(),
RunFail => self.run_rfail_test(),
- RunPass => self.run_rpass_test(),
RunPassValgrind => self.run_valgrind_test(),
Pretty => self.run_pretty_test(),
DebugInfoGdb => self.run_debuginfo_gdb_test(),
CodegenUnits => self.run_codegen_units_test(),
Incremental => self.run_incremental_test(),
RunMake => self.run_rmake_test(),
- Ui => self.run_ui_test(),
+ RunPass | Ui => self.run_ui_test(),
MirOpt => self.run_mir_opt_test(),
}
}
+ fn should_run_successfully(&self) -> bool {
+ let run_pass = match self.config.mode {
+ RunPass => true,
+ Ui => self.props.run_pass,
+ _ => unimplemented!(),
+ };
+ return run_pass && !self.props.skip_codegen;
+ }
+
+ fn should_compile_successfully(&self) -> bool {
+ match self.config.mode {
+ ParseFail | CompileFail => self.props.compile_pass,
+ RunPass => true,
+ Ui => self.props.compile_pass,
+ Incremental => {
+ let revision = self.revision
+ .expect("incremental tests require a list of revisions");
+ if revision.starts_with("rpass") || revision.starts_with("rfail") {
+ true
+ } else if revision.starts_with("cfail") {
+ // FIXME: would be nice if incremental revs could start with "cpass"
+ self.props.compile_pass
+ } else {
+ panic!("revision name must begin with rpass, rfail, or cfail");
+ }
+ }
+ mode => panic!("unimplemented for mode {:?}", mode),
+ }
+ }
+
fn check_if_test_should_compile(&self, proc_res: &ProcRes) {
- if self.props.compile_pass {
+ if self.should_compile_successfully() {
if !proc_res.status.success() {
self.fatal_proc_rec("test compilation failed although it shouldn't!", proc_res);
}
rustc.arg("-Zui-testing");
}
}
- Ui => {
+ RunPass | Ui => {
if !self
.props
.compile_flags
rustc.arg(dir_opt);
}
- RunPass | RunFail | RunPassValgrind | Pretty | DebugInfoGdb | DebugInfoLldb
+ RunFail | RunPassValgrind | Pretty | DebugInfoGdb | DebugInfoLldb
| Codegen | Rustdoc | RunMake | CodegenUnits => {
// do not use JSON output
}
let normalized_stderr = self.normalize_output(&stderr, &self.props.normalize_stderr);
let mut errors = 0;
- errors += self.compare_output("stdout", &normalized_stdout, &expected_stdout);
- errors += self.compare_output("stderr", &normalized_stderr, &expected_stderr);
+ if !self.props.dont_check_compiler_stdout {
+ errors += self.compare_output("stdout", &normalized_stdout, &expected_stdout);
+ }
+ if !self.props.dont_check_compiler_stderr {
+ errors += self.compare_output("stderr", &normalized_stderr, &expected_stderr);
+ }
let modes_to_prune = vec![CompareMode::Nll];
self.prune_duplicate_outputs(&modes_to_prune);
let expected_errors = errors::load_errors(&self.testpaths.file, self.revision);
- if self.props.run_pass {
+ if self.should_run_successfully() {
let proc_res = self.exec_compiled_test();
if !proc_res.status.success() {
-Subproject commit e6f1e15676c26fdc7c4713647fe007b26f361a8e
+Subproject commit 130d803b3243a92f5c2d9230935cba7fa88e263e
-Subproject commit fa922de1e5e1f02b576b7a5aa6ded16935693ec5
+Subproject commit 2b21611d38a16a775f55ea102d8f442dfc51cf6d
"ordslice", // Apache-2.0, rls
"cloudabi", // BSD-2-Clause, (rls -> crossbeam-channel 0.2 -> rand 0.5)
"ryu", // Apache-2.0, rls/cargo/... (b/c of serde)
+ "bytesize", // Apache-2.0, cargo
];
/// Which crates to check against the whitelist?