diff options
780 files changed, 17550 insertions, 7955 deletions
diff --git a/Cargo.lock b/Cargo.lock index 2bf8d81f1aa..1ad9dbd4ea5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,7 +17,7 @@ dependencies = [ name = "alloc" version = "0.0.0" dependencies = [ - "compiler_builtins 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xorshift 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -54,6 +54,7 @@ name = "arena" version = "0.0.0" dependencies = [ "rustc_data_structures 0.0.0", + "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -105,8 +106,8 @@ name = "backtrace-sys" version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", - "compiler_builtins 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-std-workspace-core 1.0.0", ] @@ -157,8 +158,8 @@ name = "bootstrap" version = "0.0.0" dependencies = [ "build_helper 0.1.0", - "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", - "cmake 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "cmake 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -317,7 +318,7 @@ version = "0.1.0" [[package]] name = "cc" -version = "1.0.28" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -373,9 +374,8 @@ version = "0.0.212" dependencies = [ "cargo_metadata 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "clippy-mini-macro-test 0.2.0", - "clippy_dev 0.0.1", "clippy_lints 0.0.212", - "compiletest_rs 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", + "compiletest_rs 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)", "derive-new 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -391,17 +391,6 @@ name = "clippy-mini-macro-test" version = "0.2.0" [[package]] -name = "clippy_dev" -version = "0.0.1" -dependencies = [ - "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", - "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] name = "clippy_lints" version = "0.0.212" dependencies = [ @@ -432,10 +421,10 @@ dependencies = [ [[package]] name = "cmake" -version = "0.1.33" +version = "0.1.38" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -464,10 +453,10 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.8" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-std-workspace-core 1.0.0", ] @@ -494,7 +483,7 @@ dependencies = [ [[package]] name = "compiletest_rs" -version = "0.3.19" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -672,7 +661,7 @@ name = "curl-sys" version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "libnghttp2-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "libz-sys 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", @@ -750,7 +739,7 @@ name = "dlmalloc" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "compiler_builtins 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-std-workspace-core 1.0.0", ] @@ -916,7 +905,7 @@ name = "fortanix-sgx-abi" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "compiler_builtins 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-std-workspace-core 1.0.0", ] @@ -1218,7 +1207,7 @@ name = "jemalloc-sys" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", "fs_extra 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1287,7 +1276,7 @@ name = "libgit2-sys" version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", "curl-sys 0.4.15 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "libssh2-sys 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1301,7 +1290,7 @@ name = "libnghttp2-sys" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1310,7 +1299,7 @@ name = "libssh2-sys" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "libz-sys 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", "openssl-sys 0.9.40 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1319,20 +1308,11 @@ dependencies = [ ] [[package]] -name = "libtest" -version = "0.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "getopts 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_term 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] name = "libz-sys" version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1397,7 +1377,7 @@ name = "lzma-sys" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1495,6 +1475,16 @@ dependencies = [ ] [[package]] +name = "measureme" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "memchr" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1520,7 +1510,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "minifier" -version = "0.0.28" +version = "0.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "macro-utils 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1531,7 +1521,7 @@ name = "miniz-sys" version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1548,7 +1538,7 @@ name = "miniz_oxide_c_api" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", "crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "miniz_oxide 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1620,10 +1610,12 @@ dependencies = [ "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "cargo_metadata 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "colored 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "compiletest_rs 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", + "compiletest_rs 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)", "directories 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-workspace-hack 1.0.0", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1723,7 +1715,7 @@ name = "openssl-src" version = "111.1.0+1.1.1a" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1731,7 +1723,7 @@ name = "openssl-sys" version = "0.9.40" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "openssl-src 111.1.0+1.1.1a (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1768,7 +1760,7 @@ dependencies = [ name = "panic_abort" version = "0.0.0" dependencies = [ - "compiler_builtins 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1778,7 +1770,7 @@ name = "panic_unwind" version = "0.0.0" dependencies = [ "alloc 0.0.0", - "compiler_builtins 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "unwind 0.0.0", @@ -1962,8 +1954,8 @@ version = "0.0.0" name = "profiler_builtins" version = "0.0.0" dependencies = [ - "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", - "compiler_builtins 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", ] @@ -2055,18 +2047,6 @@ dependencies = [ [[package]] name = "rand" -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)", - "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ @@ -2094,14 +2074,6 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_core" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2283,7 +2255,7 @@ dependencies = [ "tokio 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-process 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-timer 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2366,6 +2338,7 @@ dependencies = [ "jobserver 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "measureme 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "polonius-engine 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2498,7 +2471,7 @@ name = "rustc-demangle" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "compiler_builtins 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-std-workspace-core 1.0.0", ] @@ -2559,7 +2532,7 @@ version = "1.0.0" dependencies = [ "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2597,8 +2570,8 @@ version = "0.0.0" dependencies = [ "alloc 0.0.0", "build_helper 0.1.0", - "cmake 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", - "compiler_builtins 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cmake 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", ] @@ -2620,7 +2593,7 @@ dependencies = [ name = "rustc_codegen_llvm" version = "0.0.0" dependencies = [ - "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", "memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-demangle 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2632,7 +2605,7 @@ name = "rustc_codegen_ssa" version = "0.0.0" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", "jobserver 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2815,7 +2788,7 @@ name = "rustc_llvm" version = "0.0.0" dependencies = [ "build_helper 0.1.0", - "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2824,8 +2797,8 @@ version = "0.0.0" dependencies = [ "alloc 0.0.0", "build_helper 0.1.0", - "cmake 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", - "compiler_builtins 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cmake 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", ] @@ -2886,8 +2859,8 @@ version = "0.0.0" dependencies = [ "alloc 0.0.0", "build_helper 0.1.0", - "cmake 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", - "compiler_builtins 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cmake 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", ] @@ -2972,11 +2945,6 @@ dependencies = [ ] [[package]] -name = "rustc_term" -version = "0.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] name = "rustc_tools_util" version = "0.1.1" @@ -3007,8 +2975,8 @@ version = "0.0.0" dependencies = [ "alloc 0.0.0", "build_helper 0.1.0", - "cmake 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", - "compiler_builtins 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cmake 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", ] @@ -3039,7 +3007,7 @@ dependencies = [ name = "rustdoc" version = "0.0.0" dependencies = [ - "minifier 0.0.28 (registry+https://github.com/rust-lang/crates.io-index)", + "minifier 0.0.29 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3274,8 +3242,8 @@ version = "0.0.0" dependencies = [ "alloc 0.0.0", "backtrace-sys 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", - "compiler_builtins 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", "dlmalloc 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "fortanix-sgx-abi 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3460,6 +3428,10 @@ dependencies = [ [[package]] name = "term" +version = "0.0.0" + +[[package]] +name = "term" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ @@ -3498,8 +3470,9 @@ dependencies = [ name = "test" version = "0.0.0" dependencies = [ - "libtest 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "getopts 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)", "proc_macro 0.0.0", + "term 0.0.0", ] [[package]] @@ -3848,7 +3821,8 @@ dependencies = [ name = "unwind" version = "0.0.0" dependencies = [ - "compiler_builtins 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -4033,19 +4007,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum bytesize 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "716960a18f978640f25101b5cbf1c6f6b0d3192fab36a2d98ca96f0ecbe41010" "checksum cargo_metadata 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d8dfe3adeb30f7938e6c1dd5327f29235d8ada3e898aeb08c343005ec2915a2" "checksum cargo_metadata 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "585784cac9b05c93a53b17a0b24a5cdd1dfdda5256f030e089b549d2390cc720" -"checksum cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4a8b715cb4597106ea87c7c84b2f1d452c7492033765df7f32651e66fcf749" +"checksum cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)" = "5e5f3fee5eeb60324c2781f1e41286bdee933850fff9b3c672587fed5ec58c83" "checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4" "checksum chalk-engine 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17ec698a6f053a23bfbe646d9f2fde4b02abc19125595270a99e6f44ae0bdd1a" "checksum chalk-macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "295635afd6853aa9f20baeb7f0204862440c0fe994c5a253d5f479dac41d047e" "checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878" "checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -"checksum cmake 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)" = "704fbf3bb5149daab0afb255dbea24a1f08d2f4099cedb9baab6d470d4c5eefb" +"checksum cmake 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "96210eec534fc3fbfc0452a63769424eaa80205fda6cea98e5b61cb3d97bcec8" "checksum colored 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b0aa3473e85a3161b59845d6096b289bb577874cafeaf75ea1b1beaa6572c7fc" "checksum commoncrypto 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d056a8586ba25a1e4d61cb090900e495952c7886786fc55f909ab2f819b69007" "checksum commoncrypto-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1fed34f46747aa73dfaa578069fd8279d2818ade2b55f38f22a9401c7f4083e2" -"checksum compiler_builtins 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "a28c3898d0c57b26fa6f92de141ba665fa5ac5179f795db06db408be84302395" -"checksum compiletest_rs 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)" = "56c799b1f7142badf3b047b4c1f2074cc96b6b784fb2432f2ed9c87da0a03749" +"checksum compiler_builtins 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4ada53ac629568219809178f988ca2aac9889e9a847379588c097d30ce185145" +"checksum compiletest_rs 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)" = "17a60483b7d4d1534db7b77458a03d5d8a93a707432a04978dfe87ea43bb61b1" "checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e" "checksum core-foundation 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4e2640d6d0bf22e82bed1b73c6aef8d5dd31e5abe6666c57e6d45e2649f4f887" "checksum core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b" @@ -4131,7 +4105,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum libgit2-sys 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)" = "48441cb35dc255da8ae72825689a95368bf510659ae1ad55dc4aa88cb1789bf1" "checksum libnghttp2-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d75d7966bda4730b722d1eab8e668df445368a24394bae9fc1e8dc0ab3dbe4f4" "checksum libssh2-sys 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "126a1f4078368b163bfdee65fbab072af08a1b374a5551b21e87ade27b1fbf9d" -"checksum libtest 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1a51ac59582b915cdfc426dada72c6d9eba95818a6b481ca340f5c7152166837" "checksum libz-sys 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "2eb5e43362e38e2bca2fd5f5134c4d4564a23a5c28e9b95411652021a8675ebe" "checksum lock_api 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "949826a5ccf18c1b3a7c3d57692778d21768b79e46eb9dd07bfc4c2160036c54" "checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" @@ -4146,10 +4119,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" "checksum mdbook 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "90b5a8d7e341ceee5db3882a06078d42661ddcfa2b3687319cc5da76ec4e782f" "checksum mdbook 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0ba0d44cb4089c741b9a91f3e5218298a40699c2f3a070a85014eed290c60819" +"checksum measureme 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "36bb2b263a6795d352035024d6b30ce465bb79a5e5280d74c3b5f8464c657bcc" "checksum memchr 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0a3eb002f0535929f1199681417029ebea04aadc0c7a4224b46be99c7f5d6a16" "checksum memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff" "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" -"checksum minifier 0.0.28 (registry+https://github.com/rust-lang/crates.io-index)" = "3a2898502751dcc9d66b6fff57f3cf63cc91605e83e1a33515396f5027f8e4ca" +"checksum minifier 0.0.29 (registry+https://github.com/rust-lang/crates.io-index)" = "1f4950cb2617b1933e2da0446e864dfe0d6a22c22ff72297996c46e6a63b210b" "checksum miniz-sys 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "0300eafb20369952951699b68243ab4334f4b10a88f411c221d444b36c40e649" "checksum miniz_oxide 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5ad30a47319c16cde58d0314f5d98202a80c9083b5f61178457403dfb14e509c" "checksum miniz_oxide_c_api 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "28edaef377517fd9fe3e085c37d892ce7acd1fbeab9239c5a36eec352d8a8b7e" @@ -4204,10 +4178,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "53fa22a1994bd0f9372d7a816207d8a2677ad0325b073f5c5332760f0fb62b5c" "checksum racer 2.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "37c88638777cc178684cf648ca0e1dad56646ce105b8593dfe665c436300adc3" "checksum rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8356f47b32624fef5b3301c1be97e5944ecdd595409cc5da11d05f211db6cfbd" -"checksum rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e464cd887e869cddcae8792a4ee31d23c7edd516700695608f5b98c67ee0131c" "checksum rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ae9d223d52ae411a33cf7e54ec6034ec165df296ccd23533d671a28252b6f66a" "checksum rand_chacha 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "771b009e3a508cb67e8823dda454aaa5368c7bc1c16829fb77d3e980440dd34a" -"checksum rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1961a422c4d189dfb50ffa9320bf1f2a9bd54ecb92792fb9477f99a1045f3372" "checksum rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0905b6b7079ec73b314d4c748701f6931eb79fd97c668caa3f1899b22b32c6db" "checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" "checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" @@ -4242,7 +4214,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rustc-rayon 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8d98c51d9cbbe810c8b6693236d3412d8cd60513ff27a3e1b6af483dca0af544" "checksum rustc-rayon-core 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "526e7b6d2707a5b9bec3927d424ad70fa3cfc68e0ac1b75e46cdbbc95adc5108" "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" -"checksum rustc_term 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9c69abe7f181d2ea8d2f7b44a4aa86f4b4a567444bcfcf51ed45ede957fbf064" "checksum rustc_tools_util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c5a95edfa0c893236ae4778bb7c4752760e4c0d245e19b5eff33c5aa5eb9dc" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum rustfix 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "af7c21531a91512a4a51b490be6ba1c8eff34fdda0dc5bf87dc28d86748aac56" diff --git a/RELEASES.md b/RELEASES.md index a49e072e9ea..fcaaa73bdc0 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,149 @@ +Version 1.34.0 (2019-04-11) +========================== + +Language +-------- +- [You can now use `#[deprecated = "reason"]`][58166] as a shorthand for + `#[deprecated(note = "reason")]`. This was previously allowed by mistake + but had no effect. +- [You can now accept token streams in `#[attr()]`,`#[attr[]]`, and + `#[attr{}]` procedural macros.][57367] +- [You can now write `extern crate self as foo;`][57407] to import your + crate's root into the extern prelude. + + +Compiler +-------- +- [You can now target `riscv64imac-unknown-none-elf` and + `riscv64gc-unknown-none-elf`.][58406] +- [You can now enable linker plugin LTO optimisations with + `-C linker-plugin-lto`.][58057] This allows rustc to compile your Rust code + into LLVM bitcode allowing LLVM to perform LTO optimisations across C/C++ FFI + boundaries. +- [You can now target `powerpc64-unknown-freebsd`.][57809] + + +Libraries +--------- +- [The trait bounds have been removed on some of `HashMap<K, V, S>`'s and + `HashSet<T, S>`'s basic methods.][58370] Most notably you no longer require + the `Hash` trait to create an iterator. +- [The `Ord` trait bounds have been removed on some of `BinaryHeap<T>`'s basic + methods.][58421] Most notably you no longer require the `Ord` trait to create + an iterator. +- [The methods `overflowing_neg` and `wrapping_neg` are now `const` functions + for all numeric types.][58044] +- [Indexing a `str` is now generic over all types that + implement `SliceIndex<str>`.][57604] +- [`str::trim`, `str::trim_matches`, `str::trim_{start, end}`, and + `str::trim_{start, end}_matches` are now `#[must_use]`][57106] and will + produce a warning if their returning type is unused. +- [The methods `checked_pow`, `saturating_pow`, `wrapping_pow`, and + `overflowing_pow` are now available for all numeric types.][57873] These are + equivalvent to methods such as `wrapping_add` for the `pow` operation. + + +Stabilized APIs +--------------- + +#### std & core +* [`Any::type_id`] +* [`Error::type_id`] +* [`atomic::AtomicI16`] +* [`atomic::AtomicI32`] +* [`atomic::AtomicI64`] +* [`atomic::AtomicI8`] +* [`atomic::AtomicU16`] +* [`atomic::AtomicU32`] +* [`atomic::AtomicU64`] +* [`atomic::AtomicU8`] +* [`convert::Infallible`] +* [`convert::TryFrom`] +* [`convert::TryInto`] +* [`iter::from_fn`] +* [`iter::successors`] +* [`num::NonZeroI128`] +* [`num::NonZeroI16`] +* [`num::NonZeroI32`] +* [`num::NonZeroI64`] +* [`num::NonZeroI8`] +* [`num::NonZeroIsize`] +* [`slice::sort_by_cached_key`] +* [`str::escape_debug`] +* [`str::escape_default`] +* [`str::escape_unicode`] +* [`str::split_ascii_whitespace`] + +#### std +* [`Instant::checked_add`] +* [`Instant::checked_sub`] +* [`SystemTime::checked_add`] +* [`SystemTime::checked_sub`] + +Cargo +----- +- [You can now use alternative registries to crates.io.][cargo/6654] + +Misc +---- +- [You can now use the `?` operator in your documentation tests without manually + adding `fn main() -> Result<(), _> {}`.][56470] + +Compatibility Notes +------------------- +- [`Command::before_exec` is now deprecated in favor of the + unsafe method `Command::pre_exec`.][58059] +- [Use of `ATOMIC_{BOOL, ISIZE, USIZE}_INIT` is now deprecated.][57425] As you + can now use `const` functions in `static` variables. + +[58370]: https://github.com/rust-lang/rust/pull/58370/ +[58406]: https://github.com/rust-lang/rust/pull/58406/ +[58421]: https://github.com/rust-lang/rust/pull/58421/ +[58166]: https://github.com/rust-lang/rust/pull/58166/ +[58044]: https://github.com/rust-lang/rust/pull/58044/ +[58057]: https://github.com/rust-lang/rust/pull/58057/ +[58059]: https://github.com/rust-lang/rust/pull/58059/ +[57809]: https://github.com/rust-lang/rust/pull/57809/ +[57873]: https://github.com/rust-lang/rust/pull/57873/ +[57604]: https://github.com/rust-lang/rust/pull/57604/ +[57367]: https://github.com/rust-lang/rust/pull/57367/ +[57407]: https://github.com/rust-lang/rust/pull/57407/ +[57425]: https://github.com/rust-lang/rust/pull/57425/ +[57106]: https://github.com/rust-lang/rust/pull/57106/ +[56470]: https://github.com/rust-lang/rust/pull/56470/ +[cargo/6654]: https://github.com/rust-lang/cargo/pull/6654/ +[`Any::type_id`]: https://doc.rust-lang.org/std/any/trait.Any.html#tymethod.type_id +[`Error::type_id`]: https://doc.rust-lang.org/std/error/trait.Error.html#tymethod.type_id +[`atomic::AtomicI16`]: https://doc.rust-lang.org/std/atomic/struct.AtomicI16.html +[`atomic::AtomicI32`]: https://doc.rust-lang.org/std/atomic/struct.AtomicI32.html +[`atomic::AtomicI64`]: https://doc.rust-lang.org/std/atomic/struct.AtomicI64.html +[`atomic::AtomicI8`]: https://doc.rust-lang.org/std/atomic/struct.AtomicI8.html +[`atomic::AtomicU16`]: https://doc.rust-lang.org/std/atomic/struct.AtomicU16.html +[`atomic::AtomicU32`]: https://doc.rust-lang.org/std/atomic/struct.AtomicU32.html +[`atomic::AtomicU64`]: https://doc.rust-lang.org/std/atomic/struct.AtomicU64.html +[`atomic::AtomicU8`]: https://doc.rust-lang.org/std/atomic/struct.AtomicU8.html +[`convert::Infallible`]: https://doc.rust-lang.org/std/convert/enum.Infallible.html +[`convert::TryFrom`]: https://doc.rust-lang.org/std/convert/trait.TryFrom.html +[`convert::TryInto`]: https://doc.rust-lang.org/std/convert/trait.TryInto.html +[`iter::from_fn`]: https://doc.rust-lang.org/std/iter/fn.from_fn.html +[`iter::successors`]: https://doc.rust-lang.org/std/iter/fn.successors.html +[`num::NonZeroI128`]: https://doc.rust-lang.org/std/num/struct.NonZeroI128.html +[`num::NonZeroI16`]: https://doc.rust-lang.org/std/num/struct.NonZeroI16.html +[`num::NonZeroI32`]: https://doc.rust-lang.org/std/num/struct.NonZeroI32.html +[`num::NonZeroI64`]: https://doc.rust-lang.org/std/num/struct.NonZeroI64.html +[`num::NonZeroI8`]: https://doc.rust-lang.org/std/num/struct.NonZeroI8.html +[`num::NonZeroIsize`]: https://doc.rust-lang.org/std/num/struct.NonZeroIsize.html +[`slice::sort_by_cached_key`]: https://doc.rust-lang.org/std/primitive.slice.html#method.sort_by_cached_key +[`str::escape_debug`]: https://doc.rust-lang.org/std/primitive.str.html#method.escape_debug +[`str::escape_default`]: https://doc.rust-lang.org/std/primitive.str.html#method.escape_default +[`str::escape_unicode`]: https://doc.rust-lang.org/std/primitive.str.html#method.escape_unicode +[`str::split_ascii_whitespace`]: https://doc.rust-lang.org/std/primitive.str.html#method.split_ascii_whitespace +[`Instant::checked_add`]: https://doc.rust-lang.org/std/time/struct.Instant.html#method.checked_add +[`Instant::checked_sub`]: https://doc.rust-lang.org/std/time/struct.Instant.html#method.checked_sub +[`SystemTime::checked_add`]: https://doc.rust-lang.org/std/time/struct.SystemTime.html#method.checked_add +[`SystemTime::checked_sub`]: https://doc.rust-lang.org/std/time/struct.SystemTime.html#method.checked_sub + + Version 1.33.0 (2019-02-28) ========================== @@ -99,6 +245,8 @@ Stabilized APIs Cargo ----- +- [You can now publish crates that require a feature flag to compile with + `cargo publish --features` or `cargo publish --all-features`.][cargo/6453] - [Cargo should now rebuild a crate if a file was modified during the initial build.][cargo/6484] @@ -135,6 +283,7 @@ Compatibility Notes [57535]: https://github.com/rust-lang/rust/pull/57535/ [57566]: https://github.com/rust-lang/rust/pull/57566/ [57615]: https://github.com/rust-lang/rust/pull/57615/ +[cargo/6453]: https://github.com/rust-lang/cargo/pull/6453/ [cargo/6484]: https://github.com/rust-lang/cargo/pull/6484/ [`unix::FileExt::read_exact_at`]: https://doc.rust-lang.org/std/os/unix/fs/trait.FileExt.html#method.read_exact_at [`unix::FileExt::write_all_at`]: https://doc.rust-lang.org/std/os/unix/fs/trait.FileExt.html#method.write_all_at diff --git a/appveyor.yml b/appveyor.yml index 6aac5f07172..be960dc13af 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -14,6 +14,9 @@ environment: MSYS_BITS: 64 RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-profiler SCRIPT: python x.py test + # FIXME(#59637) + NO_DEBUG_ASSERTIONS: 1 + NO_LLVM_ASSERTIONS: 1 - CI_JOB_NAME: i686-msvc-1 MSYS_BITS: 32 RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc @@ -59,6 +62,9 @@ environment: MINGW_URL: https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror MINGW_ARCHIVE: i686-6.3.0-release-posix-dwarf-rt_v5-rev2.7z MINGW_DIR: mingw32 + # FIXME(#59637) + NO_DEBUG_ASSERTIONS: 1 + NO_LLVM_ASSERTIONS: 1 - CI_JOB_NAME: i686-mingw-2 MSYS_BITS: 32 RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu @@ -73,6 +79,9 @@ environment: MINGW_URL: https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror MINGW_ARCHIVE: x86_64-6.3.0-release-posix-seh-rt_v5-rev2.7z MINGW_DIR: mingw64 + # FIXME(#59637) + NO_DEBUG_ASSERTIONS: 1 + NO_LLVM_ASSERTIONS: 1 # 32/64 bit MSVC and GNU deployment - CI_JOB_NAME: dist-x86_64-msvc diff --git a/config.toml.example b/config.toml.example index 5e0a2fbf0d3..8b2153cd2e6 100644 --- a/config.toml.example +++ b/config.toml.example @@ -421,6 +421,9 @@ # development of NLL #test-compare-mode = false +# Use LLVM libunwind as the implementation for Rust's unwinder. +#llvm-libunwind = false + # ============================================================================= # Options for specific targets # diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index 0f7b6c22e1c..d4ffd4ad396 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -36,11 +36,11 @@ test = false [dependencies] build_helper = { path = "../build_helper" } -cmake = "0.1.23" +cmake = "0.1.38" filetime = "0.2" num_cpus = "1.0" getopts = "0.2" -cc = "1.0.1" +cc = "1.0.35" libc = "0.2" serde = "1.0.8" serde_derive = "1.0.8" diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index 7429492f914..a76584093fc 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -187,33 +187,6 @@ fn main() { cmd.arg("-C").arg(format!("debug-assertions={}", debug_assertions)); } - // Build all crates in the `std` facade with `-Z emit-stack-sizes` to add stack usage - // information. - // - // When you use this `-Z` flag with Cargo you get stack usage information on all crates - // compiled from source, and when you are using LTO you also get information on pre-compiled - // crates like `core` and `std`, even if they were not compiled with `-Z emit-stack-sizes`. - // However, there's an exception: `compiler_builtins`. This crate is special and doesn't - // participate in LTO because it's always linked as a separate object file. For this reason - // it's impossible to get stack usage information about `compiler-builtins` using - // `RUSTFLAGS` + Cargo, or `cargo rustc`. - // - // To make the stack usage information of all crates under the `std` facade available to - // Cargo based stack usage analysis tools, in both LTO and non-LTO mode, we compile them - // with the `-Z emit-stack-sizes` flag. The `RUSTC_EMIT_STACK_SIZES` var helps us apply this - // flag only to the crates in the `std` facade. The `-Z` flag is known to currently work - // with targets that produce ELF files so we limit its use flag to those targets. - // - // NOTE(japaric) if this ever causes problem with an LLVM upgrade or any PR feel free to - // remove it or comment it out - if env::var_os("RUSTC_EMIT_STACK_SIZES").is_some() - && (target.contains("-linux-") - || target.contains("-none-eabi") - || target.ends_with("-none-elf")) - { - cmd.arg("-Zemit-stack-sizes"); - } - if let Ok(s) = env::var("RUSTC_CODEGEN_UNITS") { cmd.arg("-C").arg(format!("codegen-units={}", s)); } @@ -316,6 +289,11 @@ fn main() { } } + // This is required for internal lints. + if stage != "0" { + cmd.arg("-Zunstable-options"); + } + // Force all crates compiled by this compiler to (a) be unstable and (b) // allow the `rustc_private` feature to link to other unstable crates // also in the sysroot. We also do this for host crates, since those diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 8d3c8fc435c..522466314d6 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -634,7 +634,28 @@ impl<'a> Builder<'a> { if compiler.is_snapshot(self) { self.rustc_snapshot_libdir() } else { - self.sysroot(compiler).join(libdir(&compiler.host)) + match self.config.libdir_relative() { + Some(relative_libdir) if compiler.stage >= 1 + => self.sysroot(compiler).join(relative_libdir), + _ => self.sysroot(compiler).join(libdir(&compiler.host)) + } + } + } + + /// Returns the compiler's relative libdir where it stores the dynamic libraries that + /// it itself links against. + /// + /// For example this returns `lib` on Unix and `bin` on + /// Windows. + pub fn libdir_relative(&self, compiler: Compiler) -> &Path { + if compiler.is_snapshot(self) { + libdir(&self.config.build).as_ref() + } else { + match self.config.libdir_relative() { + Some(relative_libdir) if compiler.stage >= 1 + => relative_libdir, + _ => libdir(&compiler.host).as_ref() + } } } diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 237f5c0ea2f..66443d472d3 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -20,7 +20,7 @@ use filetime::FileTime; use serde_json; use crate::dist; -use crate::util::{exe, libdir, is_dylib}; +use crate::util::{exe, is_dylib}; use crate::{Compiler, Mode, GitRepo}; use crate::native; @@ -97,8 +97,6 @@ impl Step for Std { let _folder = builder.fold_output(|| format!("stage{}-std", compiler.stage)); builder.info(&format!("Building stage{} std artifacts ({} -> {})", compiler.stage, &compiler.host, target)); - // compile with `-Z emit-stack-sizes`; see bootstrap/src/rustc.rs for more details - cargo.env("RUSTC_EMIT_STACK_SIZES", "1"); run_cargo(builder, &mut cargo, &libstd_stamp(builder, compiler, target), @@ -397,8 +395,6 @@ impl Step for Test { let _folder = builder.fold_output(|| format!("stage{}-test", compiler.stage)); builder.info(&format!("Building stage{} test artifacts ({} -> {})", compiler.stage, &compiler.host, target)); - // compile with `-Z emit-stack-sizes`; see bootstrap/src/rustc.rs for more details - cargo.env("RUSTC_EMIT_STACK_SIZES", "1"); run_cargo(builder, &mut cargo, &libtest_stamp(builder, compiler, target), @@ -1005,13 +1001,13 @@ impl Step for Assemble { // Link in all dylibs to the libdir let sysroot = builder.sysroot(target_compiler); - let sysroot_libdir = sysroot.join(libdir(&*host)); - t!(fs::create_dir_all(&sysroot_libdir)); + let rustc_libdir = builder.rustc_libdir(target_compiler); + t!(fs::create_dir_all(&rustc_libdir)); let src_libdir = builder.sysroot_libdir(build_compiler, host); for f in builder.read_dir(&src_libdir) { let filename = f.file_name().into_string().unwrap(); if is_dylib(&filename) { - builder.copy(&f.path(), &sysroot_libdir.join(&filename)); + builder.copy(&f.path(), &rustc_libdir.join(&filename)); } } diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index cb71550c12d..0c31c41ceda 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -48,6 +48,7 @@ pub struct Config { pub exclude: Vec<PathBuf>, pub rustc_error_format: Option<String>, pub test_compare_mode: bool, + pub llvm_libunwind: bool, pub run_host_only: bool, @@ -329,6 +330,7 @@ struct Rust { remap_debuginfo: Option<bool>, jemalloc: Option<bool>, test_compare_mode: Option<bool>, + llvm_libunwind: Option<bool>, } /// TOML representation of how each build target is configured. @@ -548,6 +550,7 @@ impl Config { set(&mut config.rust_rpath, rust.rpath); set(&mut config.jemalloc, rust.jemalloc); set(&mut config.test_compare_mode, rust.test_compare_mode); + set(&mut config.llvm_libunwind, rust.llvm_libunwind); set(&mut config.backtrace, rust.backtrace); set(&mut config.channel, rust.channel.clone()); set(&mut config.rust_dist_src, rust.dist_src); diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py index b2d8f2d8ebf..ade8afee7c1 100755 --- a/src/bootstrap/configure.py +++ b/src/bootstrap/configure.py @@ -68,6 +68,8 @@ o("cflags", "llvm.cflags", "build LLVM with these extra compiler flags") o("cxxflags", "llvm.cxxflags", "build LLVM with these extra compiler flags") o("ldflags", "llvm.ldflags", "build LLVM with these extra linker flags") +o("llvm-libunwind", "rust.llvm_libunwind", "use LLVM libunwind") + # Optimization and debugging options. These may be overridden by the release # channel, etc. o("optimize", "rust.optimize", "build optimized rust code") diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index d982330a616..61a7705bd6c 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -18,7 +18,7 @@ use build_helper::output; use crate::{Compiler, Mode, LLVM_TOOLS}; use crate::channel; -use crate::util::{libdir, is_dylib, exe}; +use crate::util::{is_dylib, exe}; use crate::builder::{Builder, RunConfig, ShouldRun, Step}; use crate::compile; use crate::tool::{self, Tool}; @@ -473,7 +473,7 @@ impl Step for Rustc { fn prepare_image(builder: &Builder<'_>, compiler: Compiler, image: &Path) { let host = compiler.host; let src = builder.sysroot(compiler); - let libdir = libdir(&host); + let libdir = builder.rustc_libdir(compiler); // Copy rustc/rustdoc binaries t!(fs::create_dir_all(image.join("bin"))); @@ -481,13 +481,15 @@ impl Step for Rustc { builder.install(&builder.rustdoc(compiler), &image.join("bin"), 0o755); + let libdir_relative = builder.libdir_relative(compiler); + // Copy runtime DLLs needed by the compiler - if libdir != "bin" { - for entry in builder.read_dir(&src.join(libdir)) { + if libdir_relative.to_str() != Some("bin") { + for entry in builder.read_dir(&libdir) { let name = entry.file_name(); if let Some(s) = name.to_str() { if is_dylib(s) { - builder.install(&entry.path(), &image.join(libdir), 0o644); + builder.install(&entry.path(), &image.join(&libdir_relative), 0o644); } } } @@ -899,6 +901,7 @@ impl Step for Src { "src/libstd", "src/libunwind", "src/libtest", + "src/libterm", "src/libprofiler_builtins", "src/stdsimd", "src/libproc_macro", diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index d831d2f1af2..330f66c1df0 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -277,7 +277,7 @@ impl Step for TheBook { builder.ensure(Rustbook { target, name: INTERNER.intern_string(name.to_string()), - version: RustbookVersion::MdBook1, + version: RustbookVersion::MdBook2, }); // building older edition redirects @@ -286,21 +286,21 @@ impl Step for TheBook { builder.ensure(Rustbook { target, name: INTERNER.intern_string(source_name), - version: RustbookVersion::MdBook1, + version: RustbookVersion::MdBook2, }); let source_name = format!("{}/second-edition", name); builder.ensure(Rustbook { target, name: INTERNER.intern_string(source_name), - version: RustbookVersion::MdBook1, + version: RustbookVersion::MdBook2, }); let source_name = format!("{}/2018-edition", name); builder.ensure(Rustbook { target, name: INTERNER.intern_string(source_name), - version: RustbookVersion::MdBook1, + version: RustbookVersion::MdBook2, }); // build the version info page and CSS diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 2394ae7fb79..bcd28e9cf5e 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -506,6 +506,9 @@ impl Build { fn std_features(&self) -> String { let mut features = "panic-unwind".to_string(); + if self.config.llvm_libunwind { + features.push_str(" llvm-libunwind"); + } if self.config.backtrace { features.push_str(" backtrace"); } @@ -1275,6 +1278,7 @@ impl Build { fn install(&self, src: &Path, dstdir: &Path, perms: u32) { if self.config.dry_run { return; } let dst = dstdir.join(src.file_name().unwrap()); + self.verbose_than(1, &format!("Install {:?} to {:?}", src, dst)); t!(fs::create_dir_all(dstdir)); drop(fs::remove_file(&dst)); { diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index b9f456e9100..fa6857cdc11 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -131,6 +131,11 @@ pub fn check(build: &mut Build) { continue; } + // We don't use a C compiler on wasm32 + if target.contains("wasm32") { + continue; + } + if !build.config.dry_run { cmd_finder.must_have(build.cc(*target)); if let Some(ar) = build.ar(*target) { diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 881bea5d97e..c552f607960 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -1016,7 +1016,10 @@ impl Step for Compiletest { // Also provide `rust_test_helpers` for the host. builder.ensure(native::TestHelpers { target: compiler.host }); - builder.ensure(native::TestHelpers { target }); + // wasm32 can't build the test helpers + if !target.contains("wasm32") { + builder.ensure(native::TestHelpers { target }); + } builder.ensure(RemoteCopyLibs { compiler, target }); let mut cmd = builder.tool_cmd(Tool::Compiletest); diff --git a/src/ci/docker/arm-android/Dockerfile b/src/ci/docker/arm-android/Dockerfile index e10ccd56a4a..bbf700ae233 100644 --- a/src/ci/docker/arm-android/Dockerfile +++ b/src/ci/docker/arm-android/Dockerfile @@ -23,7 +23,7 @@ RUN dpkg --add-architecture i386 && \ COPY scripts/android-sdk.sh /scripts/ RUN . /scripts/android-sdk.sh && \ - download_and_create_avd 4333796 armeabi-v7a 18 + download_and_create_avd 4333796 armeabi-v7a 18 5264690 ENV PATH=$PATH:/android/sdk/emulator ENV PATH=$PATH:/android/sdk/tools diff --git a/src/ci/docker/dist-various-1/Dockerfile b/src/ci/docker/dist-various-1/Dockerfile index f80293b182e..a722a418391 100644 --- a/src/ci/docker/dist-various-1/Dockerfile +++ b/src/ci/docker/dist-various-1/Dockerfile @@ -109,7 +109,9 @@ ENV TARGETS=$TARGETS,thumbv6m-none-eabi ENV TARGETS=$TARGETS,thumbv7m-none-eabi ENV TARGETS=$TARGETS,thumbv7em-none-eabi ENV TARGETS=$TARGETS,thumbv7em-none-eabihf +ENV TARGETS=$TARGETS,thumbv8m.base-none-eabi ENV TARGETS=$TARGETS,thumbv8m.main-none-eabi +ENV TARGETS=$TARGETS,thumbv8m.main-none-eabihf ENV TARGETS=$TARGETS,riscv32imc-unknown-none-elf ENV TARGETS=$TARGETS,riscv32imac-unknown-none-elf ENV TARGETS=$TARGETS,riscv64imac-unknown-none-elf diff --git a/src/ci/docker/dist-various-2/build-wasi-toolchain.sh b/src/ci/docker/dist-various-2/build-wasi-toolchain.sh index a15fb8cae25..965286e5bcf 100755 --- a/src/ci/docker/dist-various-2/build-wasi-toolchain.sh +++ b/src/ci/docker/dist-various-2/build-wasi-toolchain.sh @@ -12,7 +12,7 @@ export PATH=`pwd`/clang+llvm-8.0.0-x86_64-linux-gnu-ubuntu-14.04/bin:$PATH git clone https://github.com/CraneStation/wasi-sysroot cd wasi-sysroot -git reset --hard 320054e84f8f2440def3b1c8700cedb8fd697bf8 +git reset --hard e5f14be38362f1ab83302895a6e74b2ffd0e2302 make -j$(nproc) INSTALL_DIR=/wasm32-unknown-wasi install cd .. diff --git a/src/ci/docker/dist-x86_64-musl/Dockerfile b/src/ci/docker/dist-x86_64-musl/Dockerfile index 560df2f3a57..21a9023a458 100644 --- a/src/ci/docker/dist-x86_64-musl/Dockerfile +++ b/src/ci/docker/dist-x86_64-musl/Dockerfile @@ -21,8 +21,8 @@ WORKDIR /build/ COPY scripts/musl-toolchain.sh /build/ # We need to mitigate rust-lang/rust#34978 when compiling musl itself as well -RUN CFLAGS="-Wa,-mrelax-relocations=no" \ - CXXFLAGS="-Wa,-mrelax-relocations=no" \ +RUN CFLAGS="-Wa,-mrelax-relocations=no -Wa,--compress-debug-sections=none -Wl,--compress-debug-sections=none" \ + CXXFLAGS="-Wa,-mrelax-relocations=no -Wa,--compress-debug-sections=none -Wl,--compress-debug-sections=none" \ bash musl-toolchain.sh x86_64 && rm -rf build COPY scripts/sccache.sh /scripts/ @@ -38,7 +38,9 @@ ENV RUST_CONFIGURE_ARGS \ # way to produce "super compatible" binaries. # # See: https://github.com/rust-lang/rust/issues/34978 -ENV CFLAGS_x86_64_unknown_linux_musl=-Wa,-mrelax-relocations=no +# And: https://github.com/rust-lang/rust/issues/59411 +ENV CFLAGS_x86_64_unknown_linux_musl="-Wa,-mrelax-relocations=no -Wa,--compress-debug-sections=none \ + -Wl,--compress-debug-sections=none" ENV HOSTS=x86_64-unknown-linux-musl \ CC_x86_64_unknown_linux_musl=x86_64-linux-musl-gcc \ diff --git a/src/ci/docker/scripts/android-sdk.sh b/src/ci/docker/scripts/android-sdk.sh index 179f63fc830..e78e3795c04 100644 --- a/src/ci/docker/scripts/android-sdk.sh +++ b/src/ci/docker/scripts/android-sdk.sh @@ -20,11 +20,19 @@ download_sysimage() { # The output from sdkmanager is so noisy that it will occupy all of the 4 MB # log extremely quickly. Thus we must silence all output. yes | sdkmanager --licenses > /dev/null - yes | sdkmanager platform-tools emulator \ + yes | sdkmanager platform-tools \ "platforms;android-$api" \ "system-images;android-$api;default;$abi" > /dev/null } +download_emulator() { + # Download a pinned version of the emulator since upgrades can cause issues + curl -fo emulator.zip "https://dl.google.com/android/repository/emulator-linux-$1.zip" + rm -rf "${ANDROID_HOME}/emulator" + unzip -q emulator.zip -d "${ANDROID_HOME}" + rm -f emulator.zip +} + create_avd() { abi=$1 api=$2 @@ -40,11 +48,12 @@ download_and_create_avd() { download_sdk $1 download_sysimage $2 $3 create_avd $2 $3 + download_emulator $4 } # Usage: # -# setup_android_sdk 4333796 armeabi-v7a 18 +# download_and_create_avd 4333796 armeabi-v7a 18 5264690 # # 4333796 => # SDK tool version. @@ -53,3 +62,6 @@ download_and_create_avd() { # System image ABI # 18 => # Android API Level (18 = Android 4.3 = Jelly Bean MR2) +# 5264690 => +# Android Emulator version. +# Copy from the "build_id" in the `/android/sdk/emulator/emulator -version` output diff --git a/src/ci/docker/scripts/freebsd-toolchain.sh b/src/ci/docker/scripts/freebsd-toolchain.sh index 04483e24925..b1ac490a878 100755 --- a/src/ci/docker/scripts/freebsd-toolchain.sh +++ b/src/ci/docker/scripts/freebsd-toolchain.sh @@ -1,4 +1,6 @@ #!/bin/bash +# ignore-tidy-linelength + set -eux arch=$1 @@ -55,7 +57,9 @@ for lib in c++ c_nonshared compiler_rt execinfo gcc pthread rt ssp_nonshared; do files_to_extract=("${files_to_extract[@]}" "./usr/lib/lib${lib}.*") done -URL=https://download.freebsd.org/ftp/releases/${freebsd_arch}/${freebsd_version}-RELEASE/base.txz +# Originally downloaded from: +# https://download.freebsd.org/ftp/releases/${freebsd_arch}/${freebsd_version}-RELEASE/base.txz +URL=https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror/2019-04-04-freebsd-${freebsd_arch}-${freebsd_version}-RELEASE-base.txz curl "$URL" | tar xJf - -C "$sysroot" --wildcards "${files_to_extract[@]}" # Fix up absolute symlinks from the system image. This can be removed diff --git a/src/doc/embedded-book b/src/doc/embedded-book -Subproject 07fd3880ea0874d82b1d9ed30ad3427ec98b4e8 +Subproject 7989c723607ef5b13b57208022259e6c771e11d diff --git a/src/doc/man/rustc.1 b/src/doc/man/rustc.1 index 8f611063dbe..3788e3c864e 100644 --- a/src/doc/man/rustc.1 +++ b/src/doc/man/rustc.1 @@ -261,12 +261,12 @@ full debug info with variable and type information. .RE .TP \fBopt\-level\fR=\fIVAL\fR -Optimize with possible levels 0\[en]3 +Optimize with possible levels 0\[en]3, s (optimize for size), or z (for minimal size) .SH ENVIRONMENT -Some of these affect the output of the compiler, while others affect programs -which link to the standard library. +Some of these affect only test harness programs (generated via rustc --test); +others affect all programs which link to the Rust standard library. .TP \fBRUST_TEST_THREADS\fR diff --git a/src/doc/nomicon b/src/doc/nomicon -Subproject f1ff93b66844493a7b03101c7df66ac958c6241 +Subproject c02e0e7754a76886e55b976a3a4fac20100cd35 diff --git a/src/doc/reference b/src/doc/reference -Subproject 27ad493a10364e907ec476e2ad61e8a1614b57e +Subproject 98f90ff4de8e588f651f0fb493b5c7496551cd5 diff --git a/src/doc/robots.txt b/src/doc/robots.txt index a54ec508c1b..61ee12739fb 100644 --- a/src/doc/robots.txt +++ b/src/doc/robots.txt @@ -17,3 +17,11 @@ Disallow: /1.0.0-beta.2/ Disallow: /1.0.0-beta.3/ Disallow: /1.0.0-beta.4/ Disallow: /1.0.0-beta.5/ +Disallow: /book/first-edition/ +Disallow: /book/second-edition/ +Disallow: /stable/book/first-edition/ +Disallow: /stable/book/second-edition/ +Disallow: /beta/book/first-edition/ +Disallow: /beta/book/second-edition/ +Disallow: /nightly/book/first-edition/ +Disallow: /nightly/book/second-edition/ diff --git a/src/doc/rustc/src/command-line-arguments.md b/src/doc/rustc/src/command-line-arguments.md index d7e789b5a11..dfb40284ef6 100644 --- a/src/doc/rustc/src/command-line-arguments.md +++ b/src/doc/rustc/src/command-line-arguments.md @@ -86,6 +86,13 @@ This flag will set which lints should be set to the [deny level](lints/levels.ht This flag will set which lints should be set to the [forbid level](lints/levels.html#forbid). +## `-Z`: set unstable options + +This flag will allow you to set unstable options of rustc. In order to set multiple options, +the -Z flag can be used multiple times. For example: `rustc -Z verbose -Z time`. +Specifying options with -Z is only available on nightly. To view all available options +run: `rustc -Z help`. + ## `--cap-lints`: set the most restrictive lint level This flag lets you 'cap' lints, for more, [see here](lints/levels.html#capping-lints). diff --git a/src/doc/unstable-book/book.toml b/src/doc/unstable-book/book.toml index 5534340f0db..5b2e19bd7aa 100644 --- a/src/doc/unstable-book/book.toml +++ b/src/doc/unstable-book/book.toml @@ -1,2 +1,3 @@ [book] title = "The Rust Unstable Book" +author = "The Rust Community" diff --git a/src/doc/unstable-book/src/library-features/borrow-state.md b/src/doc/unstable-book/src/library-features/borrow-state.md new file mode 100644 index 00000000000..304b8dffe98 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/borrow-state.md @@ -0,0 +1,7 @@ +# `borrow_state` + +The tracking issue for this feature is: [#27733] + +[#27733]: https://github.com/rust-lang/rust/issues/27733 + +------------------------ diff --git a/src/doc/unstable-book/src/library-features/fnbox.md b/src/doc/unstable-book/src/library-features/fnbox.md new file mode 100644 index 00000000000..cb3386b7152 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/fnbox.md @@ -0,0 +1,32 @@ +# `fnbox` + +The tracking issue for this feature is [#28796] + +[#28796]: https://github.com/rust-lang/rust/issues/28796 + +------------------------ + +This had been a temporary alternative to the following impls: + +```rust,ignore +impl<A, F> FnOnce for Box<F> where F: FnOnce<A> + ?Sized {} +impl<A, F> FnMut for Box<F> where F: FnMut<A> + ?Sized {} +impl<A, F> Fn for Box<F> where F: Fn<A> + ?Sized {} +``` + +The impls are parallel to these (relatively old) impls: + +```rust,ignore +impl<A, F> FnOnce for &mut F where F: FnMut<A> + ?Sized {} +impl<A, F> FnMut for &mut F where F: FnMut<A> + ?Sized {} +impl<A, F> Fn for &mut F where F: Fn<A> + ?Sized {} +impl<A, F> FnOnce for &F where F: Fn<A> + ?Sized {} +impl<A, F> FnMut for &F where F: Fn<A> + ?Sized {} +impl<A, F> Fn for &F where F: Fn<A> + ?Sized {} +``` + +Before the introduction of [`unsized_locals`][unsized_locals], we had been unable to provide the former impls. That means, unlike `&dyn Fn()` or `&mut dyn FnMut()` we could not use `Box<dyn FnOnce()>` at that time. + +[unsized_locals]: language-features/unsized-locals.html + +`FnBox()` is an alternative approach to `Box<dyn FnBox()>` is delegated to `FnBox::call_box` which doesn't need unsized locals. As we now have `Box<dyn FnOnce()>` working, the `fnbox` feature is going to be removed. diff --git a/src/liballoc/Cargo.toml b/src/liballoc/Cargo.toml index f6d6c1de8f5..ddf0044c506 100644 --- a/src/liballoc/Cargo.toml +++ b/src/liballoc/Cargo.toml @@ -12,7 +12,7 @@ path = "lib.rs" [dependencies] core = { path = "../libcore" } -compiler_builtins = { version = "0.1.0", features = ['rustc-dep-of-std'] } +compiler_builtins = { version = "0.1.10", features = ['rustc-dep-of-std'] } [dev-dependencies] rand = "0.6" diff --git a/src/liballoc/benches/btree/set.rs b/src/liballoc/benches/btree/set.rs index 08e1db5fbb7..6357ea3ea11 100644 --- a/src/liballoc/benches/btree/set.rs +++ b/src/liballoc/benches/btree/set.rs @@ -3,59 +3,49 @@ use std::collections::BTreeSet; use rand::{thread_rng, Rng}; use test::{black_box, Bencher}; -fn random(n1: u32, n2: u32) -> [BTreeSet<usize>; 2] { +fn random(n: usize) -> BTreeSet<usize> { let mut rng = thread_rng(); - let mut set1 = BTreeSet::new(); - let mut set2 = BTreeSet::new(); - for _ in 0..n1 { - let i = rng.gen::<usize>(); - set1.insert(i); + let mut set = BTreeSet::new(); + while set.len() < n { + set.insert(rng.gen()); } - for _ in 0..n2 { - let i = rng.gen::<usize>(); - set2.insert(i); - } - [set1, set2] + assert_eq!(set.len(), n); + set } -fn staggered(n1: u32, n2: u32) -> [BTreeSet<u32>; 2] { - let mut even = BTreeSet::new(); - let mut odd = BTreeSet::new(); - for i in 0..n1 { - even.insert(i * 2); - } - for i in 0..n2 { - odd.insert(i * 2 + 1); +fn neg(n: usize) -> BTreeSet<i32> { + let mut set = BTreeSet::new(); + for i in -(n as i32)..=-1 { + set.insert(i); } - [even, odd] + assert_eq!(set.len(), n); + set } -fn neg_vs_pos(n1: u32, n2: u32) -> [BTreeSet<i32>; 2] { - let mut neg = BTreeSet::new(); - let mut pos = BTreeSet::new(); - for i in -(n1 as i32)..=-1 { - neg.insert(i); - } - for i in 1..=(n2 as i32) { - pos.insert(i); +fn pos(n: usize) -> BTreeSet<i32> { + let mut set = BTreeSet::new(); + for i in 1..=(n as i32) { + set.insert(i); } - [neg, pos] + assert_eq!(set.len(), n); + set } -fn pos_vs_neg(n1: u32, n2: u32) -> [BTreeSet<i32>; 2] { - let mut neg = BTreeSet::new(); - let mut pos = BTreeSet::new(); - for i in -(n1 as i32)..=-1 { - neg.insert(i); - } - for i in 1..=(n2 as i32) { - pos.insert(i); + +fn stagger(n1: usize, factor: usize) -> [BTreeSet<u32>; 2] { + let n2 = n1 * factor; + let mut sets = [BTreeSet::new(), BTreeSet::new()]; + for i in 0..(n1 + n2) { + let b = i % (factor + 1) != 0; + sets[b as usize].insert(i as u32); } - [pos, neg] + assert_eq!(sets[0].len(), n1); + assert_eq!(sets[1].len(), n2); + sets } -macro_rules! set_intersection_bench { - ($name: ident, $sets: expr) => { +macro_rules! set_bench { + ($name: ident, $set_func: ident, $result_func: ident, $sets: expr) => { #[bench] pub fn $name(b: &mut Bencher) { // setup @@ -63,26 +53,36 @@ macro_rules! set_intersection_bench { // measure b.iter(|| { - let x = sets[0].intersection(&sets[1]).count(); + let x = sets[0].$set_func(&sets[1]).$result_func(); black_box(x); }) } }; } -set_intersection_bench! {intersect_random_100, random(100, 100)} -set_intersection_bench! {intersect_random_10k, random(10_000, 10_000)} -set_intersection_bench! {intersect_random_10_vs_10k, random(10, 10_000)} -set_intersection_bench! {intersect_random_10k_vs_10, random(10_000, 10)} -set_intersection_bench! {intersect_staggered_100, staggered(100, 100)} -set_intersection_bench! {intersect_staggered_10k, staggered(10_000, 10_000)} -set_intersection_bench! {intersect_staggered_10_vs_10k, staggered(10, 10_000)} -set_intersection_bench! {intersect_staggered_10k_vs_10, staggered(10_000, 10)} -set_intersection_bench! {intersect_neg_vs_pos_100, neg_vs_pos(100, 100)} -set_intersection_bench! {intersect_neg_vs_pos_10k, neg_vs_pos(10_000, 10_000)} -set_intersection_bench! {intersect_neg_vs_pos_10_vs_10k,neg_vs_pos(10, 10_000)} -set_intersection_bench! {intersect_neg_vs_pos_10k_vs_10,neg_vs_pos(10_000, 10)} -set_intersection_bench! {intersect_pos_vs_neg_100, pos_vs_neg(100, 100)} -set_intersection_bench! {intersect_pos_vs_neg_10k, pos_vs_neg(10_000, 10_000)} -set_intersection_bench! {intersect_pos_vs_neg_10_vs_10k,pos_vs_neg(10, 10_000)} -set_intersection_bench! {intersect_pos_vs_neg_10k_vs_10,pos_vs_neg(10_000, 10)} +set_bench! {intersection_100_neg_vs_100_pos, intersection, count, [neg(100), pos(100)]} +set_bench! {intersection_100_neg_vs_10k_pos, intersection, count, [neg(100), pos(10_000)]} +set_bench! {intersection_100_pos_vs_100_neg, intersection, count, [pos(100), neg(100)]} +set_bench! {intersection_100_pos_vs_10k_neg, intersection, count, [pos(100), neg(10_000)]} +set_bench! {intersection_10k_neg_vs_100_pos, intersection, count, [neg(10_000), pos(100)]} +set_bench! {intersection_10k_neg_vs_10k_pos, intersection, count, [neg(10_000), pos(10_000)]} +set_bench! {intersection_10k_pos_vs_100_neg, intersection, count, [pos(10_000), neg(100)]} +set_bench! {intersection_10k_pos_vs_10k_neg, intersection, count, [pos(10_000), neg(10_000)]} +set_bench! {intersection_random_100_vs_100, intersection, count, [random(100), random(100)]} +set_bench! {intersection_random_100_vs_10k, intersection, count, [random(100), random(10_000)]} +set_bench! {intersection_random_10k_vs_100, intersection, count, [random(10_000), random(100)]} +set_bench! {intersection_random_10k_vs_10k, intersection, count, [random(10_000), random(10_000)]} +set_bench! {intersection_staggered_100_vs_100, intersection, count, stagger(100, 1)} +set_bench! {intersection_staggered_10k_vs_10k, intersection, count, stagger(10_000, 1)} +set_bench! {intersection_staggered_100_vs_10k, intersection, count, stagger(100, 100)} +set_bench! {difference_random_100_vs_100, difference, count, [random(100), random(100)]} +set_bench! {difference_random_100_vs_10k, difference, count, [random(100), random(10_000)]} +set_bench! {difference_random_10k_vs_100, difference, count, [random(10_000), random(100)]} +set_bench! {difference_random_10k_vs_10k, difference, count, [random(10_000), random(10_000)]} +set_bench! {difference_staggered_100_vs_100, difference, count, stagger(100, 1)} +set_bench! {difference_staggered_10k_vs_10k, difference, count, stagger(10_000, 1)} +set_bench! {difference_staggered_100_vs_10k, difference, count, stagger(100, 100)} +set_bench! {is_subset_100_vs_100, is_subset, clone, [pos(100), pos(100)]} +set_bench! {is_subset_100_vs_10k, is_subset, clone, [pos(100), pos(10_000)]} +set_bench! {is_subset_10k_vs_100, is_subset, clone, [pos(10_000), pos(100)]} +set_bench! {is_subset_10k_vs_10k, is_subset, clone, [pos(10_000), pos(10_000)]} diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index b2315c6a739..6a6a9146e24 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -63,6 +63,8 @@ //! //! [dereferencing]: ../../std/ops/trait.Deref.html //! [`Box`]: struct.Box.html +//! [`Global`]: ../alloc/struct.Global.html +//! [`Layout`]: ../alloc/struct.Layout.html #![stable(feature = "rust1", since = "1.0.0")] @@ -81,7 +83,7 @@ use core::ops::{ CoerceUnsized, DispatchFromDyn, Deref, DerefMut, Receiver, Generator, GeneratorState }; use core::ptr::{self, NonNull, Unique}; -use core::task::{Waker, Poll}; +use core::task::{Context, Poll}; use crate::vec::Vec; use crate::raw_vec::RawVec; @@ -694,6 +696,28 @@ impl<I: ExactSizeIterator + ?Sized> ExactSizeIterator for Box<I> { #[stable(feature = "fused", since = "1.26.0")] impl<I: FusedIterator + ?Sized> FusedIterator for Box<I> {} +#[stable(feature = "boxed_closure_impls", since = "1.35.0")] +impl<A, F: FnOnce<A> + ?Sized> FnOnce<A> for Box<F> { + type Output = <F as FnOnce<A>>::Output; + + extern "rust-call" fn call_once(self, args: A) -> Self::Output { + <F as FnOnce<A>>::call_once(*self, args) + } +} + +#[stable(feature = "boxed_closure_impls", since = "1.35.0")] +impl<A, F: FnMut<A> + ?Sized> FnMut<A> for Box<F> { + extern "rust-call" fn call_mut(&mut self, args: A) -> Self::Output { + <F as FnMut<A>>::call_mut(self, args) + } +} + +#[stable(feature = "boxed_closure_impls", since = "1.35.0")] +impl<A, F: Fn<A> + ?Sized> Fn<A> for Box<F> { + extern "rust-call" fn call(&self, args: A) -> Self::Output { + <F as Fn<A>>::call(self, args) + } +} /// `FnBox` is a version of the `FnOnce` intended for use with boxed /// closure objects. The idea is that where one would normally store a @@ -735,9 +759,7 @@ impl<I: FusedIterator + ?Sized> FusedIterator for Box<I> {} #[rustc_paren_sugar] #[unstable(feature = "fnbox", reason = "will be deprecated if and when `Box<FnOnce>` becomes usable", issue = "28796")] -pub trait FnBox<A> { - type Output; - +pub trait FnBox<A>: FnOnce<A> { fn call_box(self: Box<Self>, args: A) -> Self::Output; } @@ -746,33 +768,11 @@ pub trait FnBox<A> { impl<A, F> FnBox<A> for F where F: FnOnce<A> { - type Output = F::Output; - fn call_box(self: Box<F>, args: A) -> F::Output { self.call_once(args) } } -#[unstable(feature = "fnbox", - reason = "will be deprecated if and when `Box<FnOnce>` becomes usable", issue = "28796")] -impl<A, R> FnOnce<A> for Box<dyn FnBox<A, Output = R> + '_> { - type Output = R; - - extern "rust-call" fn call_once(self, args: A) -> R { - self.call_box(args) - } -} - -#[unstable(feature = "fnbox", - reason = "will be deprecated if and when `Box<FnOnce>` becomes usable", issue = "28796")] -impl<A, R> FnOnce<A> for Box<dyn FnBox<A, Output = R> + Send + '_> { - type Output = R; - - extern "rust-call" fn call_once(self, args: A) -> R { - self.call_box(args) - } -} - #[unstable(feature = "coerce_unsized", issue = "27732")] impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Box<U>> for Box<T> {} @@ -914,7 +914,7 @@ impl<G: ?Sized + Generator> Generator for Pin<Box<G>> { impl<F: ?Sized + Future + Unpin> Future for Box<F> { type Output = F::Output; - fn poll(mut self: Pin<&mut Self>, waker: &Waker) -> Poll<Self::Output> { - F::poll(Pin::new(&mut *self), waker) + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { + F::poll(Pin::new(&mut *self), cx) } } diff --git a/src/liballoc/collections/binary_heap.rs b/src/liballoc/collections/binary_heap.rs index a171f128c24..8c142a3d317 100644 --- a/src/liballoc/collections/binary_heap.rs +++ b/src/liballoc/collections/binary_heap.rs @@ -1177,9 +1177,7 @@ impl<T: Ord> BinaryHeap<T> { self.reserve(lower); - for elem in iterator { - self.push(elem); - } + iterator.for_each(move |elem| self.push(elem)); } } diff --git a/src/liballoc/collections/btree/map.rs b/src/liballoc/collections/btree/map.rs index ce29978856f..6b079fc87cc 100644 --- a/src/liballoc/collections/btree/map.rs +++ b/src/liballoc/collections/btree/map.rs @@ -1727,9 +1727,9 @@ impl<K: Ord, V> FromIterator<(K, V)> for BTreeMap<K, V> { impl<K: Ord, V> Extend<(K, V)> for BTreeMap<K, V> { #[inline] fn extend<T: IntoIterator<Item = (K, V)>>(&mut self, iter: T) { - for (k, v) in iter { + iter.into_iter().for_each(move |(k, v)| { self.insert(k, v); - } + }); } } diff --git a/src/liballoc/collections/btree/set.rs b/src/liballoc/collections/btree/set.rs index 2be6455ad59..16a96ca19b8 100644 --- a/src/liballoc/collections/btree/set.rs +++ b/src/liballoc/collections/btree/set.rs @@ -3,7 +3,7 @@ use core::borrow::Borrow; use core::cmp::Ordering::{self, Less, Greater, Equal}; -use core::cmp::{min, max}; +use core::cmp::max; use core::fmt::{self, Debug}; use core::iter::{Peekable, FromIterator, FusedIterator}; use core::ops::{BitOr, BitAnd, BitXor, Sub, RangeBounds}; @@ -118,17 +118,36 @@ pub struct Range<'a, T: 'a> { /// [`difference`]: struct.BTreeSet.html#method.difference #[stable(feature = "rust1", since = "1.0.0")] pub struct Difference<'a, T: 'a> { - a: Peekable<Iter<'a, T>>, - b: Peekable<Iter<'a, T>>, + inner: DifferenceInner<'a, T>, +} +enum DifferenceInner<'a, T: 'a> { + Stitch { + self_iter: Iter<'a, T>, + other_iter: Peekable<Iter<'a, T>>, + }, + Search { + self_iter: Iter<'a, T>, + other_set: &'a BTreeSet<T>, + }, } #[stable(feature = "collection_debug", since = "1.17.0")] impl<T: fmt::Debug> fmt::Debug for Difference<'_, T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("Difference") - .field(&self.a) - .field(&self.b) - .finish() + match &self.inner { + DifferenceInner::Stitch { + self_iter, + other_iter, + } => f + .debug_tuple("Difference") + .field(&self_iter) + .field(&other_iter) + .finish(), + DifferenceInner::Search { + self_iter, + other_set: _, + } => f.debug_tuple("Difference").field(&self_iter).finish(), + } } } @@ -164,17 +183,36 @@ impl<T: fmt::Debug> fmt::Debug for SymmetricDifference<'_, T> { /// [`intersection`]: struct.BTreeSet.html#method.intersection #[stable(feature = "rust1", since = "1.0.0")] pub struct Intersection<'a, T: 'a> { - a: Peekable<Iter<'a, T>>, - b: Peekable<Iter<'a, T>>, + inner: IntersectionInner<'a, T>, +} +enum IntersectionInner<'a, T: 'a> { + Stitch { + small_iter: Iter<'a, T>, // for size_hint, should be the smaller of the sets + other_iter: Iter<'a, T>, + }, + Search { + small_iter: Iter<'a, T>, + large_set: &'a BTreeSet<T>, + }, } #[stable(feature = "collection_debug", since = "1.17.0")] impl<T: fmt::Debug> fmt::Debug for Intersection<'_, T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("Intersection") - .field(&self.a) - .field(&self.b) - .finish() + match &self.inner { + IntersectionInner::Stitch { + small_iter, + other_iter, + } => f + .debug_tuple("Intersection") + .field(&small_iter) + .field(&other_iter) + .finish(), + IntersectionInner::Search { + small_iter, + large_set: _, + } => f.debug_tuple("Intersection").field(&small_iter).finish(), + } } } @@ -201,6 +239,14 @@ impl<T: fmt::Debug> fmt::Debug for Union<'_, T> { } } +// This constant is used by functions that compare two sets. +// It estimates the relative size at which searching performs better +// than iterating, based on the benchmarks in +// https://github.com/ssomers/rust_bench_btreeset_intersection; +// It's used to divide rather than multiply sizes, to rule out overflow, +// and it's a power of two to make that division cheap. +const ITER_PERFORMANCE_TIPPING_SIZE_DIFF: usize = 16; + impl<T: Ord> BTreeSet<T> { /// Makes a new `BTreeSet` with a reasonable choice of B. /// @@ -268,9 +314,24 @@ impl<T: Ord> BTreeSet<T> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn difference<'a>(&'a self, other: &'a BTreeSet<T>) -> Difference<'a, T> { - Difference { - a: self.iter().peekable(), - b: other.iter().peekable(), + if self.len() > other.len() / ITER_PERFORMANCE_TIPPING_SIZE_DIFF { + // Self is bigger than or not much smaller than other set. + // Iterate both sets jointly, spotting matches along the way. + Difference { + inner: DifferenceInner::Stitch { + self_iter: self.iter(), + other_iter: other.iter().peekable(), + }, + } + } else { + // Self is much smaller than other set, or both sets are empty. + // Iterate the small set, searching for matches in the large set. + Difference { + inner: DifferenceInner::Search { + self_iter: self.iter(), + other_set: other, + }, + } } } @@ -326,9 +387,29 @@ impl<T: Ord> BTreeSet<T> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn intersection<'a>(&'a self, other: &'a BTreeSet<T>) -> Intersection<'a, T> { - Intersection { - a: self.iter().peekable(), - b: other.iter().peekable(), + let (small, other) = if self.len() <= other.len() { + (self, other) + } else { + (other, self) + }; + if small.len() > other.len() / ITER_PERFORMANCE_TIPPING_SIZE_DIFF { + // Small set is not much smaller than other set. + // Iterate both sets jointly, spotting matches along the way. + Intersection { + inner: IntersectionInner::Stitch { + small_iter: small.iter(), + other_iter: other.iter(), + }, + } + } else { + // Big difference in number of elements, or both sets are empty. + // Iterate the small set, searching for matches in the large set. + Intersection { + inner: IntersectionInner::Search { + small_iter: small.iter(), + large_set: other, + }, + } } } @@ -462,28 +543,44 @@ impl<T: Ord> BTreeSet<T> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn is_subset(&self, other: &BTreeSet<T>) -> bool { - // Stolen from TreeMap - let mut x = self.iter(); - let mut y = other.iter(); - let mut a = x.next(); - let mut b = y.next(); - while a.is_some() { - if b.is_none() { - return false; - } + // Same result as self.difference(other).next().is_none() + // but the 3 paths below are faster (in order: hugely, 20%, 5%). + if self.len() > other.len() { + false + } else if self.len() > other.len() / ITER_PERFORMANCE_TIPPING_SIZE_DIFF { + // Self is not much smaller than other set. + // Stolen from TreeMap + let mut x = self.iter(); + let mut y = other.iter(); + let mut a = x.next(); + let mut b = y.next(); + while a.is_some() { + if b.is_none() { + return false; + } - let a1 = a.unwrap(); - let b1 = b.unwrap(); + let a1 = a.unwrap(); + let b1 = b.unwrap(); - match b1.cmp(a1) { - Less => (), - Greater => return false, - Equal => a = x.next(), - } + match b1.cmp(a1) { + Less => (), + Greater => return false, + Equal => a = x.next(), + } - b = y.next(); + b = y.next(); + } + true + } else { + // Big difference in number of elements, or both sets are empty. + // Iterate the small set, searching for matches in the large set. + for next in self { + if !other.contains(next) { + return false; + } + } + true } - true } /// Returns `true` if the set is a superset of another, @@ -786,9 +883,9 @@ impl<'a, T> IntoIterator for &'a BTreeSet<T> { impl<T: Ord> Extend<T> for BTreeSet<T> { #[inline] fn extend<Iter: IntoIterator<Item = T>>(&mut self, iter: Iter) { - for elem in iter { + iter.into_iter().for_each(move |elem| { self.insert(elem); - } + }); } } @@ -1001,8 +1098,22 @@ fn cmp_opt<T: Ord>(x: Option<&T>, y: Option<&T>, short: Ordering, long: Ordering impl<T> Clone for Difference<'_, T> { fn clone(&self) -> Self { Difference { - a: self.a.clone(), - b: self.b.clone(), + inner: match &self.inner { + DifferenceInner::Stitch { + self_iter, + other_iter, + } => DifferenceInner::Stitch { + self_iter: self_iter.clone(), + other_iter: other_iter.clone(), + }, + DifferenceInner::Search { + self_iter, + other_set, + } => DifferenceInner::Search { + self_iter: self_iter.clone(), + other_set, + }, + }, } } } @@ -1011,24 +1122,52 @@ impl<'a, T: Ord> Iterator for Difference<'a, T> { type Item = &'a T; fn next(&mut self) -> Option<&'a T> { - loop { - match cmp_opt(self.a.peek(), self.b.peek(), Less, Less) { - Less => return self.a.next(), - Equal => { - self.a.next(); - self.b.next(); - } - Greater => { - self.b.next(); + match &mut self.inner { + DifferenceInner::Stitch { + self_iter, + other_iter, + } => { + let mut self_next = self_iter.next()?; + loop { + match other_iter + .peek() + .map_or(Less, |other_next| Ord::cmp(self_next, other_next)) + { + Less => return Some(self_next), + Equal => { + self_next = self_iter.next()?; + other_iter.next(); + } + Greater => { + other_iter.next(); + } + } } } + DifferenceInner::Search { + self_iter, + other_set, + } => loop { + let self_next = self_iter.next()?; + if !other_set.contains(&self_next) { + return Some(self_next); + } + }, } } fn size_hint(&self) -> (usize, Option<usize>) { - let a_len = self.a.len(); - let b_len = self.b.len(); - (a_len.saturating_sub(b_len), Some(a_len)) + let (self_len, other_len) = match &self.inner { + DifferenceInner::Stitch { + self_iter, + other_iter + } => (self_iter.len(), other_iter.len()), + DifferenceInner::Search { + self_iter, + other_set + } => (self_iter.len(), other_set.len()), + }; + (self_len.saturating_sub(other_len), Some(self_len)) } } @@ -1073,8 +1212,22 @@ impl<T: Ord> FusedIterator for SymmetricDifference<'_, T> {} impl<T> Clone for Intersection<'_, T> { fn clone(&self) -> Self { Intersection { - a: self.a.clone(), - b: self.b.clone(), + inner: match &self.inner { + IntersectionInner::Stitch { + small_iter, + other_iter, + } => IntersectionInner::Stitch { + small_iter: small_iter.clone(), + other_iter: other_iter.clone(), + }, + IntersectionInner::Search { + small_iter, + large_set, + } => IntersectionInner::Search { + small_iter: small_iter.clone(), + large_set, + }, + }, } } } @@ -1083,24 +1236,39 @@ impl<'a, T: Ord> Iterator for Intersection<'a, T> { type Item = &'a T; fn next(&mut self) -> Option<&'a T> { - loop { - match Ord::cmp(self.a.peek()?, self.b.peek()?) { - Less => { - self.a.next(); - } - Equal => { - self.b.next(); - return self.a.next(); - } - Greater => { - self.b.next(); + match &mut self.inner { + IntersectionInner::Stitch { + small_iter, + other_iter, + } => { + let mut small_next = small_iter.next()?; + let mut other_next = other_iter.next()?; + loop { + match Ord::cmp(small_next, other_next) { + Less => small_next = small_iter.next()?, + Greater => other_next = other_iter.next()?, + Equal => return Some(small_next), + } } } + IntersectionInner::Search { + small_iter, + large_set, + } => loop { + let small_next = small_iter.next()?; + if large_set.contains(&small_next) { + return Some(small_next); + } + }, } } fn size_hint(&self) -> (usize, Option<usize>) { - (0, Some(min(self.a.len(), self.b.len()))) + let min_len = match &self.inner { + IntersectionInner::Stitch { small_iter, .. } => small_iter.len(), + IntersectionInner::Search { small_iter, .. } => small_iter.len(), + }; + (0, Some(min_len)) } } diff --git a/src/liballoc/collections/linked_list.rs b/src/liballoc/collections/linked_list.rs index c2ee2e63156..d6d84a4f083 100644 --- a/src/liballoc/collections/linked_list.rs +++ b/src/liballoc/collections/linked_list.rs @@ -1107,9 +1107,7 @@ impl<T> Extend<T> for LinkedList<T> { impl<I: IntoIterator> SpecExtend<I> for LinkedList<I::Item> { default fn spec_extend(&mut self, iter: I) { - for elt in iter { - self.push_back(elt); - } + iter.into_iter().for_each(move |elt| self.push_back(elt)); } } diff --git a/src/liballoc/collections/vec_deque.rs b/src/liballoc/collections/vec_deque.rs index 4e90f783ec6..4bea615ab86 100644 --- a/src/liballoc/collections/vec_deque.rs +++ b/src/liballoc/collections/vec_deque.rs @@ -2677,9 +2677,7 @@ impl<'a, T> IntoIterator for &'a mut VecDeque<T> { #[stable(feature = "rust1", since = "1.0.0")] impl<A> Extend<A> for VecDeque<A> { fn extend<T: IntoIterator<Item = A>>(&mut self, iter: T) { - for elt in iter { - self.push_back(elt); - } + iter.into_iter().for_each(move |elt| self.push_back(elt)); } } diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 90ff56814fb..7f3acc933d4 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -51,10 +51,7 @@ //! default global allocator. It is not compatible with the libc allocator API. #![allow(unused_attributes)] -#![unstable(feature = "alloc", - reason = "this library is unlikely to be stabilized in its current \ - form or name", - issue = "27783")] +#![stable(feature = "alloc", since = "1.36.0")] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/", issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/", test(no_crate_inject, attr(allow(unused_variables), deny(warnings))))] @@ -107,6 +104,7 @@ #![feature(unboxed_closures)] #![feature(unicode_internals)] #![feature(unsize)] +#![feature(unsized_locals)] #![feature(allocator_internals)] #![feature(on_unimplemented)] #![feature(rustc_const_unstable)] diff --git a/src/liballoc/prelude/mod.rs b/src/liballoc/prelude/mod.rs index 33cc51d1732..0534ad3edc7 100644 --- a/src/liballoc/prelude/mod.rs +++ b/src/liballoc/prelude/mod.rs @@ -5,7 +5,6 @@ //! //! ``` //! # #![allow(unused_imports)] -//! # #![feature(alloc)] //! #![feature(alloc_prelude)] //! extern crate alloc; //! use alloc::prelude::v1::*; diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index fe28fe5095c..d1fc5ac3b30 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -256,7 +256,7 @@ impl<T, A: Alloc> RawVec<T, A> { /// # Examples /// /// ``` - /// # #![feature(alloc, raw_vec_internals)] + /// # #![feature(raw_vec_internals)] /// # extern crate alloc; /// # use std::ptr; /// # use alloc::raw_vec::RawVec; @@ -460,7 +460,7 @@ impl<T, A: Alloc> RawVec<T, A> { /// # Examples /// /// ``` - /// # #![feature(alloc, raw_vec_internals)] + /// # #![feature(raw_vec_internals)] /// # extern crate alloc; /// # use std::ptr; /// # use alloc::raw_vec::RawVec; diff --git a/src/liballoc/tests/btree/set.rs b/src/liballoc/tests/btree/set.rs index 4f5168f1ce5..d52814118b3 100644 --- a/src/liballoc/tests/btree/set.rs +++ b/src/liballoc/tests/btree/set.rs @@ -69,6 +69,20 @@ fn test_intersection() { check_intersection(&[11, 1, 3, 77, 103, 5, -5], &[2, 11, 77, -9, -42, 5, 3], &[3, 5, 11, 77]); + let large = (0..1000).collect::<Vec<_>>(); + check_intersection(&[], &large, &[]); + check_intersection(&large, &[], &[]); + check_intersection(&[-1], &large, &[]); + check_intersection(&large, &[-1], &[]); + check_intersection(&[0], &large, &[0]); + check_intersection(&large, &[0], &[0]); + check_intersection(&[999], &large, &[999]); + check_intersection(&large, &[999], &[999]); + check_intersection(&[1000], &large, &[]); + check_intersection(&large, &[1000], &[]); + check_intersection(&[11, 5000, 1, 3, 77, 8924, 103], + &large, + &[1, 3, 11, 77, 103]); } #[test] @@ -84,6 +98,18 @@ fn test_difference() { check_difference(&[-5, 11, 22, 33, 40, 42], &[-12, -5, 14, 23, 34, 38, 39, 50], &[11, 22, 33, 40, 42]); + let large = (0..1000).collect::<Vec<_>>(); + check_difference(&[], &large, &[]); + check_difference(&[-1], &large, &[-1]); + check_difference(&[0], &large, &[]); + check_difference(&[999], &large, &[]); + check_difference(&[1000], &large, &[1000]); + check_difference(&[11, 5000, 1, 3, 77, 8924, 103], + &large, + &[5000, 8924]); + check_difference(&large, &[], &large); + check_difference(&large, &[-1], &large); + check_difference(&large, &[1000], &large); } #[test] @@ -115,6 +141,41 @@ fn test_union() { } #[test] +// Only tests the simple function definition with respect to intersection +fn test_is_disjoint() { + let one = [1].into_iter().collect::<BTreeSet<_>>(); + let two = [2].into_iter().collect::<BTreeSet<_>>(); + assert!(one.is_disjoint(&two)); +} + +#[test] +// Also tests the trivial function definition of is_superset +fn test_is_subset() { + fn is_subset(a: &[i32], b: &[i32]) -> bool { + let set_a = a.iter().collect::<BTreeSet<_>>(); + let set_b = b.iter().collect::<BTreeSet<_>>(); + set_a.is_subset(&set_b) + } + + assert_eq!(is_subset(&[], &[]), true); + assert_eq!(is_subset(&[], &[1, 2]), true); + assert_eq!(is_subset(&[0], &[1, 2]), false); + assert_eq!(is_subset(&[1], &[1, 2]), true); + assert_eq!(is_subset(&[2], &[1, 2]), true); + assert_eq!(is_subset(&[3], &[1, 2]), false); + assert_eq!(is_subset(&[1, 2], &[1]), false); + assert_eq!(is_subset(&[1, 2], &[1, 2]), true); + assert_eq!(is_subset(&[1, 2], &[2, 3]), false); + let large = (0..1000).collect::<Vec<_>>(); + assert_eq!(is_subset(&[], &large), true); + assert_eq!(is_subset(&large, &[]), false); + assert_eq!(is_subset(&[-1], &large), false); + assert_eq!(is_subset(&[0], &large), true); + assert_eq!(is_subset(&[1, 2], &large), true); + assert_eq!(is_subset(&[999, 1000], &large), false); +} + +#[test] fn test_zip() { let mut x = BTreeSet::new(); x.insert(5); diff --git a/src/libarena/Cargo.toml b/src/libarena/Cargo.toml index 82fc64ba64e..aa1bf38b995 100644 --- a/src/libarena/Cargo.toml +++ b/src/libarena/Cargo.toml @@ -11,3 +11,4 @@ crate-type = ["dylib"] [dependencies] rustc_data_structures = { path = "../librustc_data_structures" } +smallvec = { version = "0.6.7", features = ["union", "may_dangle"] } diff --git a/src/libarena/lib.rs b/src/libarena/lib.rs index 8ae046c0796..cfe317a00f9 100644 --- a/src/libarena/lib.rs +++ b/src/libarena/lib.rs @@ -12,8 +12,8 @@ test(no_crate_inject, attr(deny(warnings))))] #![deny(rust_2018_idioms)] +#![cfg_attr(not(stage0), deny(internal))] -#![feature(alloc)] #![feature(core_intrinsics)] #![feature(dropck_eyepatch)] #![feature(raw_vec_internals)] @@ -23,7 +23,9 @@ extern crate alloc; +use rustc_data_structures::cold_path; use rustc_data_structures::sync::MTLock; +use smallvec::SmallVec; use std::cell::{Cell, RefCell}; use std::cmp; @@ -55,6 +57,8 @@ pub struct TypedArena<T> { struct TypedArenaChunk<T> { /// The raw storage for the arena chunk. storage: RawVec<T>, + /// The number of valid entries in the chunk. + entries: usize, } impl<T> TypedArenaChunk<T> { @@ -62,6 +66,7 @@ impl<T> TypedArenaChunk<T> { unsafe fn new(capacity: usize) -> TypedArenaChunk<T> { TypedArenaChunk { storage: RawVec::with_capacity(capacity), + entries: 0, } } @@ -149,6 +154,34 @@ impl<T> TypedArena<T> { } } + #[inline] + fn can_allocate(&self, len: usize) -> bool { + let available_capacity_bytes = self.end.get() as usize - self.ptr.get() as usize; + let at_least_bytes = len.checked_mul(mem::size_of::<T>()).unwrap(); + available_capacity_bytes >= at_least_bytes + } + + /// Ensures there's enough space in the current chunk to fit `len` objects. + #[inline] + fn ensure_capacity(&self, len: usize) { + if !self.can_allocate(len) { + self.grow(len); + debug_assert!(self.can_allocate(len)); + } + } + + #[inline] + unsafe fn alloc_raw_slice(&self, len: usize) -> *mut T { + assert!(mem::size_of::<T>() != 0); + assert!(len != 0); + + self.ensure_capacity(len); + + let start_ptr = self.ptr.get(); + self.ptr.set(start_ptr.add(len)); + start_ptr + } + /// Allocates a slice of objects that are copied into the `TypedArena`, returning a mutable /// reference to it. Will panic if passed a zero-sized types. /// @@ -161,21 +194,64 @@ impl<T> TypedArena<T> { where T: Copy, { + unsafe { + let len = slice.len(); + let start_ptr = self.alloc_raw_slice(len); + slice.as_ptr().copy_to_nonoverlapping(start_ptr, len); + slice::from_raw_parts_mut(start_ptr, len) + } + } + + #[inline] + pub fn alloc_from_iter<I: IntoIterator<Item = T>>(&self, iter: I) -> &mut [T] { assert!(mem::size_of::<T>() != 0); - assert!(slice.len() != 0); + let mut iter = iter.into_iter(); + let size_hint = iter.size_hint(); - let available_capacity_bytes = self.end.get() as usize - self.ptr.get() as usize; - let at_least_bytes = slice.len() * mem::size_of::<T>(); - if available_capacity_bytes < at_least_bytes { - self.grow(slice.len()); - } + match size_hint { + (min, Some(max)) if min == max => { + // We know the exact number of elements the iterator will produce here + let len = min; - unsafe { - let start_ptr = self.ptr.get(); - let arena_slice = slice::from_raw_parts_mut(start_ptr, slice.len()); - self.ptr.set(start_ptr.add(arena_slice.len())); - arena_slice.copy_from_slice(slice); - arena_slice + if len == 0 { + return &mut []; + } + + self.ensure_capacity(len); + + let slice = self.ptr.get(); + + unsafe { + let mut ptr = self.ptr.get(); + for _ in 0..len { + // Write into uninitialized memory. + ptr::write(ptr, iter.next().unwrap()); + // Advance the pointer. + ptr = ptr.offset(1); + // Update the pointer per iteration so if `iter.next()` panics + // we destroy the correct amount + self.ptr.set(ptr); + } + slice::from_raw_parts_mut(slice, len) + } + } + _ => { + cold_path(move || -> &mut [T] { + let mut vec: SmallVec<[_; 8]> = iter.collect(); + if vec.is_empty() { + return &mut []; + } + // Move the content to the arena by copying it and then forgetting + // the content of the SmallVec + unsafe { + let len = vec.len(); + let start_ptr = self.alloc_raw_slice(len); + vec.as_ptr().copy_to_nonoverlapping(start_ptr, len); + vec.set_len(0); + slice::from_raw_parts_mut(start_ptr, len) + } + }) + } } } @@ -189,6 +265,7 @@ impl<T> TypedArena<T> { if let Some(last_chunk) = chunks.last_mut() { let used_bytes = self.ptr.get() as usize - last_chunk.start() as usize; let currently_used_cap = used_bytes / mem::size_of::<T>(); + last_chunk.entries = currently_used_cap; if last_chunk.storage.reserve_in_place(currently_used_cap, n) { self.end.set(last_chunk.end()); return; @@ -222,8 +299,7 @@ impl<T> TypedArena<T> { let len = chunks_borrow.len(); // If `T` is ZST, code below has no effect. for mut chunk in chunks_borrow.drain(..len-1) { - let cap = chunk.storage.cap(); - chunk.destroy(cap); + chunk.destroy(chunk.entries); } } } @@ -265,8 +341,7 @@ unsafe impl<#[may_dangle] T> Drop for TypedArena<T> { self.clear_last_chunk(&mut last_chunk); // The last chunk will be dropped. Destroy all other chunks. for chunk in chunks_borrow.iter_mut() { - let cap = chunk.storage.cap(); - chunk.destroy(cap); + chunk.destroy(chunk.entries); } } // RawVec handles deallocation of `last_chunk` and `self.chunks`. @@ -410,6 +485,54 @@ impl DroplessArena { arena_slice } } + + #[inline] + pub fn alloc_from_iter<T, I: IntoIterator<Item = T>>(&self, iter: I) -> &mut [T] { + let mut iter = iter.into_iter(); + assert!(mem::size_of::<T>() != 0); + assert!(!mem::needs_drop::<T>()); + + let size_hint = iter.size_hint(); + + match size_hint { + (min, Some(max)) if min == max => { + // We know the exact number of elements the iterator will produce here + let len = min; + + if len == 0 { + return &mut [] + } + let size = len.checked_mul(mem::size_of::<T>()).unwrap(); + let mem = self.alloc_raw(size, mem::align_of::<T>()) as *mut _ as *mut T; + unsafe { + for i in 0..len { + ptr::write(mem.offset(i as isize), iter.next().unwrap()) + } + slice::from_raw_parts_mut(mem, len) + } + } + (_, _) => { + cold_path(move || -> &mut [T] { + let mut vec: SmallVec<[_; 8]> = iter.collect(); + if vec.is_empty() { + return &mut []; + } + // Move the content to the arena by copying it and then forgetting + // the content of the SmallVec + unsafe { + let len = vec.len(); + let start_ptr = self.alloc_raw( + len * mem::size_of::<T>(), + mem::align_of::<T>() + ) as *mut _ as *mut T; + vec.as_ptr().copy_to_nonoverlapping(start_ptr, len); + vec.set_len(0); + slice::from_raw_parts_mut(start_ptr, len) + } + }) + } + } + } } #[derive(Default)] diff --git a/src/libcore/benches/ascii.rs b/src/libcore/benches/ascii.rs index 635537e3121..10b6cc61d99 100644 --- a/src/libcore/benches/ascii.rs +++ b/src/libcore/benches/ascii.rs @@ -2,7 +2,7 @@ // after wrap-adding 0x1F: // // b'a' + 0x1F == 0x80 == 0b1000_0000 -// b'z' + 0x1F == 0x98 == 0b10011000 +// b'z' + 0x1F == 0x98 == 0b1001_1000 // // Lower-case ASCII 'z' is the last byte that has its highest bit unset // after wrap-adding 0x05: diff --git a/src/libcore/benches/iter.rs b/src/libcore/benches/iter.rs index 825bd368bdf..7dcfad8306f 100644 --- a/src/libcore/benches/iter.rs +++ b/src/libcore/benches/iter.rs @@ -334,3 +334,13 @@ fn bench_filter_chain_ref_count(b: &mut Bencher) { (0i64..1000000).chain(0..1000000).map(black_box).by_ref().filter(|x| x % 3 == 0).count() }) } + +#[bench] +fn bench_partial_cmp(b: &mut Bencher) { + b.iter(|| (0..100000).map(black_box).partial_cmp((0..100000).map(black_box))) +} + +#[bench] +fn bench_lt(b: &mut Bencher) { + b.iter(|| (0..100000).map(black_box).lt((0..100000).map(black_box))) +} diff --git a/src/libcore/borrow.rs b/src/libcore/borrow.rs index 89668dc0650..4d58aaca941 100644 --- a/src/libcore/borrow.rs +++ b/src/libcore/borrow.rs @@ -32,6 +32,10 @@ /// on the identical behavior of these additional trait implementations. /// These traits will likely appear as additional trait bounds. /// +/// In particular `Eq`, `Ord` and `Hash` must be equivalent for +/// borrowed and owned values: `x.borrow() == y.borrow()` should give the +/// same result as `x == y`. +/// /// If generic code merely needs to work for all types that can /// provide a reference to related type `T`, it is often better to use /// [`AsRef<T>`] as more types can safely implement it. diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 80dd51acc9e..5325b339151 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -955,6 +955,44 @@ impl<T: ?Sized> RefCell<T> { &mut *self.value.get() } } + + /// Immutably borrows the wrapped value, returning an error if the value is + /// currently mutably borrowed. + /// + /// # Safety + /// + /// Unlike `RefCell::borrow`, this method is unsafe because it does not + /// return a `Ref`, thus leaving the borrow flag untouched. Mutably + /// borrowing the `RefCell` while the reference returned by this method + /// is alive is undefined behaviour. + /// + /// # Examples + /// + /// ``` + /// #![feature(borrow_state)] + /// use std::cell::RefCell; + /// + /// let c = RefCell::new(5); + /// + /// { + /// let m = c.borrow_mut(); + /// assert!(unsafe { c.try_borrow_unguarded() }.is_err()); + /// } + /// + /// { + /// let m = c.borrow(); + /// assert!(unsafe { c.try_borrow_unguarded() }.is_ok()); + /// } + /// ``` + #[unstable(feature = "borrow_state", issue = "27733")] + #[inline] + pub unsafe fn try_borrow_unguarded(&self) -> Result<&T, BorrowError> { + if !is_writing(self.borrow.get()) { + Ok(&*self.value.get()) + } else { + Err(BorrowError { _private: () }) + } + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index 807b35e1af1..14908108fc5 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -286,13 +286,13 @@ pub struct AssertParamIsEq<T: Eq + ?Sized> { _field: ::marker::PhantomData<T> } #[derive(Clone, Copy, PartialEq, Debug, Hash)] #[stable(feature = "rust1", since = "1.0.0")] pub enum Ordering { - /// An ordering where a compared value is less [than another]. + /// An ordering where a compared value is less than another. #[stable(feature = "rust1", since = "1.0.0")] Less = -1, - /// An ordering where a compared value is equal [to another]. + /// An ordering where a compared value is equal to another. #[stable(feature = "rust1", since = "1.0.0")] Equal = 0, - /// An ordering where a compared value is greater [than another]. + /// An ordering where a compared value is greater than another. #[stable(feature = "rust1", since = "1.0.0")] Greater = 1, } diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs index a6c65e890a5..e903bd936c4 100644 --- a/src/libcore/convert.rs +++ b/src/libcore/convert.rs @@ -105,11 +105,13 @@ pub const fn identity<T>(x: T) -> T { x } /// `&T` or write a custom function. /// /// -/// `AsRef` is very similar to, but serves a slightly different purpose than [`Borrow`]: +/// `AsRef` has the same signature as [`Borrow`], but `Borrow` is different in few aspects: /// -/// - Use `AsRef` when the goal is to simply convert into a reference -/// - Use `Borrow` when the goal is related to writing code that is agnostic to -/// the type of borrow and whether it is a reference or value +/// - Unlike `AsRef`, `Borrow` has a blanket impl for any `T`, and can be used to accept either +/// a reference or a value. +/// - `Borrow` also requires that `Hash`, `Eq` and `Ord` for borrowed value are +/// equivalent to those of the owned value. For this reason, if you want to +/// borrow only a single field of a struct you can implement `AsRef`, but not `Borrow`. /// /// [`Borrow`]: ../../std/borrow/trait.Borrow.html /// @@ -427,6 +429,26 @@ pub trait TryInto<T>: Sized { /// When the `!` type is stablized `Infallible` and `!` will be /// equivalent. /// +/// `TryFrom<T>` can be implemented as follows: +/// +/// ``` +/// use std::convert::TryFrom; +/// +/// struct SuperiorThanZero(i32); +/// +/// impl TryFrom<i32> for SuperiorThanZero { +/// type Error = &'static str; +/// +/// fn try_from(value: i32) -> Result<Self, Self::Error> { +/// if value < 0 { +/// Err("SuperiorThanZero only accepts value superior than zero!") +/// } else { +/// Ok(SuperiorThanZero(value)) +/// } +/// } +/// } +/// ``` +/// /// # Examples /// /// As described, [`i32`] implements `TryFrom<i64>`: diff --git a/src/libcore/fmt/builders.rs b/src/libcore/fmt/builders.rs index 45994c2b4f0..df3852973b8 100644 --- a/src/libcore/fmt/builders.rs +++ b/src/libcore/fmt/builders.rs @@ -11,7 +11,7 @@ impl<'a> PadAdapter<'a> { fmt.wrap_buf(move |buf| { *slot = Some(PadAdapter { buf, - on_newline: false, + on_newline: true, }); slot.as_mut().unwrap() }) @@ -128,22 +128,21 @@ impl<'a, 'b: 'a> DebugStruct<'a, 'b> { #[stable(feature = "debug_builders", since = "1.2.0")] pub fn field(&mut self, name: &str, value: &dyn fmt::Debug) -> &mut DebugStruct<'a, 'b> { self.result = self.result.and_then(|_| { - let prefix = if self.has_fields { - "," - } else { - " {" - }; - if self.is_pretty() { + if !self.has_fields { + self.fmt.write_str(" {\n")?; + } let mut slot = None; let mut writer = PadAdapter::wrap(&mut self.fmt, &mut slot); - writer.write_str(prefix)?; - writer.write_str("\n")?; writer.write_str(name)?; writer.write_str(": ")?; - value.fmt(&mut writer) + value.fmt(&mut writer)?; + writer.write_str(",\n") } else { - write!(self.fmt, "{} {}: ", prefix, name)?; + let prefix = if self.has_fields { ", " } else { " { " }; + self.fmt.write_str(prefix)?; + self.fmt.write_str(name)?; + self.fmt.write_str(": ")?; value.fmt(self.fmt) } }); @@ -184,7 +183,7 @@ impl<'a, 'b: 'a> DebugStruct<'a, 'b> { if self.has_fields { self.result = self.result.and_then(|_| { if self.is_pretty() { - self.fmt.write_str("\n}") + self.fmt.write_str("}") } else { self.fmt.write_str(" }") } @@ -275,21 +274,17 @@ impl<'a, 'b: 'a> DebugTuple<'a, 'b> { #[stable(feature = "debug_builders", since = "1.2.0")] pub fn field(&mut self, value: &dyn fmt::Debug) -> &mut DebugTuple<'a, 'b> { self.result = self.result.and_then(|_| { - let (prefix, space) = if self.fields > 0 { - (",", " ") - } else { - ("(", "") - }; - if self.is_pretty() { + if self.fields == 0 { + self.fmt.write_str("(\n")?; + } let mut slot = None; let mut writer = PadAdapter::wrap(&mut self.fmt, &mut slot); - writer.write_str(prefix)?; - writer.write_str("\n")?; - value.fmt(&mut writer) + value.fmt(&mut writer)?; + writer.write_str(",\n") } else { + let prefix = if self.fields == 0 { "(" } else { ", " }; self.fmt.write_str(prefix)?; - self.fmt.write_str(space)?; value.fmt(self.fmt) } }); @@ -326,10 +321,7 @@ impl<'a, 'b: 'a> DebugTuple<'a, 'b> { pub fn finish(&mut self) -> fmt::Result { if self.fields > 0 { self.result = self.result.and_then(|_| { - if self.is_pretty() { - self.fmt.write_str("\n")?; - } - if self.fields == 1 && self.empty_name { + if self.fields == 1 && self.empty_name && !self.is_pretty() { self.fmt.write_str(",")?; } self.fmt.write_str(")") @@ -353,14 +345,13 @@ impl<'a, 'b: 'a> DebugInner<'a, 'b> { fn entry(&mut self, entry: &dyn fmt::Debug) { self.result = self.result.and_then(|_| { if self.is_pretty() { + if !self.has_fields { + self.fmt.write_str("\n")?; + } let mut slot = None; let mut writer = PadAdapter::wrap(&mut self.fmt, &mut slot); - writer.write_str(if self.has_fields { - ",\n" - } else { - "\n" - })?; - entry.fmt(&mut writer) + entry.fmt(&mut writer)?; + writer.write_str(",\n") } else { if self.has_fields { self.fmt.write_str(", ")? @@ -372,15 +363,6 @@ impl<'a, 'b: 'a> DebugInner<'a, 'b> { self.has_fields = true; } - pub fn finish(&mut self) { - let prefix = if self.is_pretty() && self.has_fields { - "\n" - } else { - "" - }; - self.result = self.result.and_then(|_| self.fmt.write_str(prefix)); - } - fn is_pretty(&self) -> bool { self.fmt.alternate() } @@ -421,7 +403,7 @@ pub struct DebugSet<'a, 'b: 'a> { } pub fn debug_set_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>) -> DebugSet<'a, 'b> { - let result = write!(fmt, "{{"); + let result = fmt.write_str("{"); DebugSet { inner: DebugInner { fmt, @@ -519,7 +501,6 @@ impl<'a, 'b: 'a> DebugSet<'a, 'b> { /// ``` #[stable(feature = "debug_builders", since = "1.2.0")] pub fn finish(&mut self) -> fmt::Result { - self.inner.finish(); self.inner.result.and_then(|_| self.inner.fmt.write_str("}")) } } @@ -559,7 +540,7 @@ pub struct DebugList<'a, 'b: 'a> { } pub fn debug_list_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>) -> DebugList<'a, 'b> { - let result = write!(fmt, "["); + let result = fmt.write_str("["); DebugList { inner: DebugInner { fmt, @@ -657,7 +638,6 @@ impl<'a, 'b: 'a> DebugList<'a, 'b> { /// ``` #[stable(feature = "debug_builders", since = "1.2.0")] pub fn finish(&mut self) -> fmt::Result { - self.inner.finish(); self.inner.result.and_then(|_| self.inner.fmt.write_str("]")) } } @@ -699,7 +679,7 @@ pub struct DebugMap<'a, 'b: 'a> { } pub fn debug_map_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>) -> DebugMap<'a, 'b> { - let result = write!(fmt, "{{"); + let result = fmt.write_str("{"); DebugMap { fmt, result, @@ -734,16 +714,15 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> { pub fn entry(&mut self, key: &dyn fmt::Debug, value: &dyn fmt::Debug) -> &mut DebugMap<'a, 'b> { self.result = self.result.and_then(|_| { if self.is_pretty() { + if !self.has_fields { + self.fmt.write_str("\n")?; + } let mut slot = None; let mut writer = PadAdapter::wrap(&mut self.fmt, &mut slot); - writer.write_str(if self.has_fields { - ",\n" - } else { - "\n" - })?; key.fmt(&mut writer)?; writer.write_str(": ")?; - value.fmt(&mut writer) + value.fmt(&mut writer)?; + writer.write_str(",\n") } else { if self.has_fields { self.fmt.write_str(", ")? @@ -818,12 +797,7 @@ impl<'a, 'b: 'a> DebugMap<'a, 'b> { /// ``` #[stable(feature = "debug_builders", since = "1.2.0")] pub fn finish(&mut self) -> fmt::Result { - let prefix = if self.is_pretty() && self.has_fields { - "\n" - } else { - "" - }; - self.result.and_then(|_| write!(self.fmt, "{}}}", prefix)) + self.result.and_then(|_| self.fmt.write_str("}")) } fn is_pretty(&self) -> bool { diff --git a/src/libcore/future/future.rs b/src/libcore/future/future.rs index a143b54a61f..114a6b93367 100644 --- a/src/libcore/future/future.rs +++ b/src/libcore/future/future.rs @@ -5,7 +5,7 @@ use marker::Unpin; use ops; use pin::Pin; -use task::{Poll, Waker}; +use task::{Context, Poll}; /// A future represents an asynchronous computation. /// @@ -44,8 +44,9 @@ pub trait Future { /// Once a future has finished, clients should not `poll` it again. /// /// When a future is not ready yet, `poll` returns `Poll::Pending` and - /// stores a clone of the [`Waker`] to be woken once the future can - /// make progress. For example, a future waiting for a socket to become + /// stores a clone of the [`Waker`] copied from the current [`Context`]. + /// This [`Waker`] is then woken once the future can make progress. + /// For example, a future waiting for a socket to become /// readable would call `.clone()` on the [`Waker`] and store it. /// When a signal arrives elsewhere indicating that the socket is readable, /// `[Waker::wake]` is called and the socket future's task is awoken. @@ -88,16 +89,17 @@ pub trait Future { /// /// [`Poll::Pending`]: ../task/enum.Poll.html#variant.Pending /// [`Poll::Ready(val)`]: ../task/enum.Poll.html#variant.Ready + /// [`Context`]: ../task/struct.Context.html /// [`Waker`]: ../task/struct.Waker.html /// [`Waker::wake`]: ../task/struct.Waker.html#method.wake - fn poll(self: Pin<&mut Self>, waker: &Waker) -> Poll<Self::Output>; + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>; } impl<F: ?Sized + Future + Unpin> Future for &mut F { type Output = F::Output; - fn poll(mut self: Pin<&mut Self>, waker: &Waker) -> Poll<Self::Output> { - F::poll(Pin::new(&mut **self), waker) + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { + F::poll(Pin::new(&mut **self), cx) } } @@ -108,7 +110,7 @@ where { type Output = <<P as ops::Deref>::Target as Future>::Output; - fn poll(self: Pin<&mut Self>, waker: &Waker) -> Poll<Self::Output> { - Pin::get_mut(self).as_mut().poll(waker) + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { + Pin::get_mut(self).as_mut().poll(cx) } } diff --git a/src/libcore/hint.rs b/src/libcore/hint.rs index d1ccc148654..d43e6c49f4c 100644 --- a/src/libcore/hint.rs +++ b/src/libcore/hint.rs @@ -50,15 +50,28 @@ pub unsafe fn unreachable_unchecked() -> ! { intrinsics::unreachable() } -/// Save power or switch hyperthreads in a busy-wait spin-loop. +/// Signals the processor that it is entering a busy-wait spin-loop. /// -/// This function is deliberately more primitive than -/// [`std::thread::yield_now`](../../std/thread/fn.yield_now.html) and -/// does not directly yield to the system's scheduler. -/// In some cases it might be useful to use a combination of both functions. -/// Careful benchmarking is advised. +/// Upon receiving spin-loop signal the processor can optimize its behavior by, for example, saving +/// power or switching hyper-threads. /// -/// On some platforms this function may not do anything at all. +/// This function is different than [`std::thread::yield_now`] which directly yields to the +/// system's scheduler, whereas `spin_loop` only signals the processor that it is entering a +/// busy-wait spin-loop without yielding control to the system's scheduler. +/// +/// Using a busy-wait spin-loop with `spin_loop` is ideally used in situations where a +/// contended lock is held by another thread executed on a different CPU and where the waiting +/// times are relatively small. Because entering busy-wait spin-loop does not trigger the system's +/// scheduler, no overhead for switching threads occurs. However, if the thread holding the +/// contended lock is running on the same CPU, the spin-loop is likely to occupy an entire CPU slice +/// before switching to the thread that holds the lock. If the contending lock is held by a thread +/// on the same CPU or if the waiting times for acquiring the lock are longer, it is often better to +/// use [`std::thread::yield_now`]. +/// +/// **Note**: On platforms that do not support receiving spin-loop hints this function does not +/// do anything at all. +/// +/// [`std::thread::yield_now`]: ../../std/thread/fn.yield_now.html #[inline] #[unstable(feature = "renamed_spin_loop", issue = "55002")] pub fn spin_loop() { diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 75a33394e3d..05acd7bd011 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -737,16 +737,6 @@ extern "rust-intrinsic" { /// /// There are a few things that `transmute` is really useful for. /// - /// Getting the bitpattern of a floating point type (or, more generally, - /// type punning, when `T` and `U` aren't pointers): - /// - /// ``` - /// let bitpattern = unsafe { - /// std::mem::transmute::<f32, u32>(1.0) - /// }; - /// assert_eq!(bitpattern, 0x3F800000); - /// ``` - /// /// Turning a pointer into a function pointer. This is *not* portable to /// machines where function pointers and data pointers have different sizes. /// diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs index e7efd9728b9..aefed1890fe 100644 --- a/src/libcore/iter/range.rs +++ b/src/libcore/iter/range.rs @@ -68,11 +68,9 @@ macro_rules! step_impl_unsigned { issue = "42168")] impl Step for $t { #[inline] - #[allow(trivial_numeric_casts)] fn steps_between(start: &$t, end: &$t) -> Option<usize> { if *start < *end { - // Note: We assume $t <= usize here - Some((*end - *start) as usize) + usize::try_from(*end - *start).ok() } else { Some(0) } @@ -98,13 +96,11 @@ macro_rules! step_impl_signed { issue = "42168")] impl Step for $t { #[inline] - #[allow(trivial_numeric_casts)] fn steps_between(start: &$t, end: &$t) -> Option<usize> { if *start < *end { - // Note: We assume $t <= isize here - // Use .wrapping_sub and cast to usize to compute the - // difference that may not fit inside the range of isize. - Some((*end as isize).wrapping_sub(*start as isize) as usize) + // Use .wrapping_sub and cast to unsigned to compute the + // difference that may not fit inside the range of $t. + usize::try_from(end.wrapping_sub(*start) as $unsigned).ok() } else { Some(0) } @@ -134,46 +130,9 @@ macro_rules! step_impl_signed { )*) } -macro_rules! step_impl_no_between { - ($($t:ty)*) => ($( - #[unstable(feature = "step_trait", - reason = "likely to be replaced by finer-grained traits", - issue = "42168")] - impl Step for $t { - #[inline] - fn steps_between(_start: &Self, _end: &Self) -> Option<usize> { - None - } - - #[inline] - fn add_usize(&self, n: usize) -> Option<Self> { - self.checked_add(n as $t) - } - - step_identical_methods!(); - } - )*) -} - -step_impl_unsigned!(usize u8 u16); -#[cfg(not(target_pointer_width = "16"))] -step_impl_unsigned!(u32); -#[cfg(target_pointer_width = "16")] -step_impl_no_between!(u32); +step_impl_unsigned!(usize u8 u16 u32 u64 u128); step_impl_signed!([isize: usize] [i8: u8] [i16: u16]); -#[cfg(not(target_pointer_width = "16"))] -step_impl_signed!([i32: u32]); -#[cfg(target_pointer_width = "16")] -step_impl_no_between!(i32); -#[cfg(target_pointer_width = "64")] -step_impl_unsigned!(u64); -#[cfg(target_pointer_width = "64")] -step_impl_signed!([i64: u64]); -// If the target pointer width is not 64-bits, we -// assume here that it is less than 64-bits. -#[cfg(not(target_pointer_width = "64"))] -step_impl_no_between!(u64 i64); -step_impl_no_between!(u128 i128); +step_impl_signed!([i32: u32] [i64: u64] [i128: u128]); macro_rules! range_exact_iter_impl { ($($t:ty)*) => ($( @@ -229,7 +188,7 @@ impl<A: Step> Iterator for ops::Range<A> { fn size_hint(&self) -> (usize, Option<usize>) { match Step::steps_between(&self.start, &self.end) { Some(hint) => (hint, Some(hint)), - None => (0, None) + None => (usize::MAX, None) } } @@ -273,8 +232,8 @@ range_incl_exact_iter_impl!(u8 u16 i8 i16); // // They need to guarantee that .size_hint() is either exact, or that // the upper bound is None when it does not fit the type limits. -range_trusted_len_impl!(usize isize u8 i8 u16 i16 u32 i32 i64 u64); -range_incl_trusted_len_impl!(usize isize u8 i8 u16 i16 u32 i32 i64 u64); +range_trusted_len_impl!(usize isize u8 i8 u16 i16 u32 i32 u64 i64 u128 i128); +range_incl_trusted_len_impl!(usize isize u8 i8 u16 i16 u32 i32 u64 i64 u128 i128); #[stable(feature = "rust1", since = "1.0.0")] impl<A: Step> DoubleEndedIterator for ops::Range<A> { @@ -350,7 +309,7 @@ impl<A: Step> Iterator for ops::RangeInclusive<A> { match Step::steps_between(&self.start, &self.end) { Some(hint) => (hint.saturating_add(1), hint.checked_add(1)), - None => (0, None), + None => (usize::MAX, None), } } diff --git a/src/libcore/iter/traits/iterator.rs b/src/libcore/iter/traits/iterator.rs index ca7feed0712..6df4a457655 100644 --- a/src/libcore/iter/traits/iterator.rs +++ b/src/libcore/iter/traits/iterator.rs @@ -2435,145 +2435,61 @@ pub trait Iterator { /// Determines if the elements of this `Iterator` are unequal to those of /// another. #[stable(feature = "iter_order", since = "1.5.0")] - fn ne<I>(mut self, other: I) -> bool where + fn ne<I>(self, other: I) -> bool where I: IntoIterator, Self::Item: PartialEq<I::Item>, Self: Sized, { - let mut other = other.into_iter(); - - loop { - let x = match self.next() { - None => return other.next().is_some(), - Some(val) => val, - }; - - let y = match other.next() { - None => return true, - Some(val) => val, - }; - - if x != y { return true } - } + !self.eq(other) } /// Determines if the elements of this `Iterator` are lexicographically /// less than those of another. #[stable(feature = "iter_order", since = "1.5.0")] - fn lt<I>(mut self, other: I) -> bool where + fn lt<I>(self, other: I) -> bool where I: IntoIterator, Self::Item: PartialOrd<I::Item>, Self: Sized, { - let mut other = other.into_iter(); - - loop { - let x = match self.next() { - None => return other.next().is_some(), - Some(val) => val, - }; - - let y = match other.next() { - None => return false, - Some(val) => val, - }; - - match x.partial_cmp(&y) { - Some(Ordering::Less) => return true, - Some(Ordering::Equal) => (), - Some(Ordering::Greater) => return false, - None => return false, - } - } + self.partial_cmp(other) == Some(Ordering::Less) } /// Determines if the elements of this `Iterator` are lexicographically /// less or equal to those of another. #[stable(feature = "iter_order", since = "1.5.0")] - fn le<I>(mut self, other: I) -> bool where + fn le<I>(self, other: I) -> bool where I: IntoIterator, Self::Item: PartialOrd<I::Item>, Self: Sized, { - let mut other = other.into_iter(); - - loop { - let x = match self.next() { - None => { other.next(); return true; }, - Some(val) => val, - }; - - let y = match other.next() { - None => return false, - Some(val) => val, - }; - - match x.partial_cmp(&y) { - Some(Ordering::Less) => return true, - Some(Ordering::Equal) => (), - Some(Ordering::Greater) => return false, - None => return false, - } + match self.partial_cmp(other) { + Some(Ordering::Less) | Some(Ordering::Equal) => true, + _ => false, } } /// Determines if the elements of this `Iterator` are lexicographically /// greater than those of another. #[stable(feature = "iter_order", since = "1.5.0")] - fn gt<I>(mut self, other: I) -> bool where + fn gt<I>(self, other: I) -> bool where I: IntoIterator, Self::Item: PartialOrd<I::Item>, Self: Sized, { - let mut other = other.into_iter(); - - loop { - let x = match self.next() { - None => { other.next(); return false; }, - Some(val) => val, - }; - - let y = match other.next() { - None => return true, - Some(val) => val, - }; - - match x.partial_cmp(&y) { - Some(Ordering::Less) => return false, - Some(Ordering::Equal) => (), - Some(Ordering::Greater) => return true, - None => return false, - } - } + self.partial_cmp(other) == Some(Ordering::Greater) } /// Determines if the elements of this `Iterator` are lexicographically /// greater than or equal to those of another. #[stable(feature = "iter_order", since = "1.5.0")] - fn ge<I>(mut self, other: I) -> bool where + fn ge<I>(self, other: I) -> bool where I: IntoIterator, Self::Item: PartialOrd<I::Item>, Self: Sized, { - let mut other = other.into_iter(); - - loop { - let x = match self.next() { - None => return other.next().is_none(), - Some(val) => val, - }; - - let y = match other.next() { - None => return true, - Some(val) => val, - }; - - match x.partial_cmp(&y) { - Some(Ordering::Less) => return false, - Some(Ordering::Equal) => (), - Some(Ordering::Greater) => return true, - None => return false, - } + match self.partial_cmp(other) { + Some(Ordering::Greater) | Some(Ordering::Equal) => true, + _ => false, } } diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 66bcf1f7d01..e8874265547 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -1152,15 +1152,6 @@ impl<T> MaybeUninit<T> { MaybeUninit { uninit: () } } - /// Deprecated before stabilization. - #[unstable(feature = "maybe_uninit", issue = "53491")] - #[inline(always)] - // FIXME: still used by stdsimd - // #[rustc_deprecated(since = "1.35.0", reason = "use `uninit` instead")] - pub const fn uninitialized() -> MaybeUninit<T> { - Self::uninit() - } - /// Creates a new `MaybeUninit<T>` in an uninitialized state, with the memory being /// filled with `0` bytes. It depends on `T` whether that already makes for /// proper initialization. For example, `MaybeUninit<usize>::zeroed()` is initialized, @@ -1221,14 +1212,6 @@ impl<T> MaybeUninit<T> { } } - /// Deprecated before stabilization. - #[unstable(feature = "maybe_uninit", issue = "53491")] - #[inline(always)] - #[rustc_deprecated(since = "1.35.0", reason = "use `write` instead")] - pub fn set(&mut self, val: T) -> &mut T { - self.write(val) - } - /// Gets a pointer to the contained value. Reading from this pointer or turning it /// into a reference is undefined behavior unless the `MaybeUninit<T>` is initialized. /// @@ -1346,15 +1329,6 @@ impl<T> MaybeUninit<T> { ManuallyDrop::into_inner(self.value) } - /// Deprecated before stabilization. - #[unstable(feature = "maybe_uninit", issue = "53491")] - #[inline(always)] - // FIXME: still used by stdsimd - // #[rustc_deprecated(since = "1.35.0", reason = "use `assume_init` instead")] - pub unsafe fn into_initialized(self) -> T { - self.assume_init() - } - /// Reads the value from the `MaybeUninit<T>` container. The resulting `T` is subject /// to the usual drop handling. /// @@ -1417,14 +1391,6 @@ impl<T> MaybeUninit<T> { self.as_ptr().read() } - /// Deprecated before stabilization. - #[unstable(feature = "maybe_uninit", issue = "53491")] - #[inline(always)] - #[rustc_deprecated(since = "1.35.0", reason = "use `read` instead")] - pub unsafe fn read_initialized(&self) -> T { - self.read() - } - /// Gets a reference to the contained value. /// /// # Safety diff --git a/src/libcore/ops/arith.rs b/src/libcore/ops/arith.rs index 28c9ff94dee..8139305f530 100644 --- a/src/libcore/ops/arith.rs +++ b/src/libcore/ops/arith.rs @@ -220,21 +220,21 @@ sub_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// // derive `Eq` and `PartialEq`. /// #[derive(Debug, Eq, PartialEq)] /// struct Rational { -/// nominator: usize, +/// numerator: usize, /// denominator: usize, /// } /// /// impl Rational { -/// fn new(nominator: usize, denominator: usize) -> Self { +/// fn new(numerator: usize, denominator: usize) -> Self { /// if denominator == 0 { /// panic!("Zero is an invalid denominator!"); /// } /// /// // Reduce to lowest terms by dividing by the greatest common /// // divisor. -/// let gcd = gcd(nominator, denominator); +/// let gcd = gcd(numerator, denominator); /// Rational { -/// nominator: nominator / gcd, +/// numerator: numerator / gcd, /// denominator: denominator / gcd, /// } /// } @@ -245,9 +245,9 @@ sub_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// type Output = Self; /// /// fn mul(self, rhs: Self) -> Self { -/// let nominator = self.nominator * rhs.nominator; +/// let numerator = self.numerator * rhs.numerator; /// let denominator = self.denominator * rhs.denominator; -/// Rational::new(nominator, denominator) +/// Rational::new(numerator, denominator) /// } /// } /// @@ -340,21 +340,21 @@ mul_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// // derive `Eq` and `PartialEq`. /// #[derive(Debug, Eq, PartialEq)] /// struct Rational { -/// nominator: usize, +/// numerator: usize, /// denominator: usize, /// } /// /// impl Rational { -/// fn new(nominator: usize, denominator: usize) -> Self { +/// fn new(numerator: usize, denominator: usize) -> Self { /// if denominator == 0 { /// panic!("Zero is an invalid denominator!"); /// } /// /// // Reduce to lowest terms by dividing by the greatest common /// // divisor. -/// let gcd = gcd(nominator, denominator); +/// let gcd = gcd(numerator, denominator); /// Rational { -/// nominator: nominator / gcd, +/// numerator: numerator / gcd, /// denominator: denominator / gcd, /// } /// } @@ -365,13 +365,13 @@ mul_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// type Output = Self; /// /// fn div(self, rhs: Self) -> Self::Output { -/// if rhs.nominator == 0 { +/// if rhs.numerator == 0 { /// panic!("Cannot divide by zero-valued `Rational`!"); /// } /// -/// let nominator = self.nominator * rhs.denominator; -/// let denominator = self.denominator * rhs.nominator; -/// Rational::new(nominator, denominator) +/// let numerator = self.numerator * rhs.denominator; +/// let denominator = self.denominator * rhs.numerator; +/// Rational::new(numerator, denominator) /// } /// } /// @@ -537,6 +537,21 @@ rem_impl_integer! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } macro_rules! rem_impl_float { ($($t:ty)*) => ($( + + /// The remainder from the division of two floats. + /// + /// The remainder has the same sign as the dividend and is computed as: + /// `x - (x / y).trunc() * y`. + /// + /// # Examples + /// ``` + /// let x: f32 = 50.50; + /// let y: f32 = 8.125; + /// let remainder = x - (x / y).trunc() * y; + /// + /// // The answer to both operations is 1.75 + /// assert_eq!(x % y, remainder); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] impl Rem for $t { type Output = $t; diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index 4f71c8e7949..5b6023f2e2c 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -85,7 +85,10 @@ pub struct Range<Idx> { #[stable(feature = "rust1", since = "1.0.0")] impl<Idx: fmt::Debug> fmt::Debug for Range<Idx> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "{:?}..{:?}", self.start, self.end) + self.start.fmt(fmt)?; + write!(fmt, "..")?; + self.end.fmt(fmt)?; + Ok(()) } } @@ -184,7 +187,9 @@ pub struct RangeFrom<Idx> { #[stable(feature = "rust1", since = "1.0.0")] impl<Idx: fmt::Debug> fmt::Debug for RangeFrom<Idx> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "{:?}..", self.start) + self.start.fmt(fmt)?; + write!(fmt, "..")?; + Ok(()) } } @@ -266,7 +271,9 @@ pub struct RangeTo<Idx> { #[stable(feature = "rust1", since = "1.0.0")] impl<Idx: fmt::Debug> fmt::Debug for RangeTo<Idx> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "..{:?}", self.end) + write!(fmt, "..")?; + self.end.fmt(fmt)?; + Ok(()) } } @@ -467,7 +474,10 @@ impl<Idx> RangeInclusive<Idx> { #[stable(feature = "inclusive_range", since = "1.26.0")] impl<Idx: fmt::Debug> fmt::Debug for RangeInclusive<Idx> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "{:?}..={:?}", self.start, self.end) + self.start.fmt(fmt)?; + write!(fmt, "..=")?; + self.end.fmt(fmt)?; + Ok(()) } } @@ -602,7 +612,9 @@ pub struct RangeToInclusive<Idx> { #[stable(feature = "inclusive_range", since = "1.26.0")] impl<Idx: fmt::Debug> fmt::Debug for RangeToInclusive<Idx> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "..={:?}", self.end) + write!(fmt, "..=")?; + self.end.fmt(fmt)?; + Ok(()) } } diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 4eb5bddb5d2..122ef9c79c2 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -1585,6 +1585,153 @@ impl<T> [T] { sort::quicksort(self, |a, b| f(a).lt(&f(b))); } + /// Reorder the slice such that the element at `index` is at its final sorted position. + /// + /// This reordering has the additional property that any value at position `i < index` will be + /// less than or equal to any value at a position `j > index`. Additionally, this reordering is + /// unstable (i.e. any number of equal elements may end up at position `index`), in-place + /// (i.e. does not allocate), and `O(n)` worst-case. This function is also/ known as "kth + /// element" in other libraries. It returns a triplet of the following values: all elements less + /// than the one at the given index, the value at the given index, and all elements greater than + /// the one at the given index. + /// + /// # Current implementation + /// + /// The current algorithm is based on the quickselect portion of the same quicksort algorithm + /// used for [`sort_unstable`]. + /// + /// [`sort_unstable`]: #method.sort_unstable + /// + /// # Panics + /// + /// Panics when `index >= len()`, meaning it always panics on empty slices. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_partition_at_index)] + /// + /// let mut v = [-5i32, 4, 1, -3, 2]; + /// + /// // Find the median + /// v.partition_at_index(2); + /// + /// // We are only guaranteed the slice will be one of the following, based on the way we sort + /// // about the specified index. + /// assert!(v == [-3, -5, 1, 2, 4] || + /// v == [-5, -3, 1, 2, 4] || + /// v == [-3, -5, 1, 4, 2] || + /// v == [-5, -3, 1, 4, 2]); + /// ``` + #[unstable(feature = "slice_partition_at_index", issue = "55300")] + #[inline] + pub fn partition_at_index(&mut self, index: usize) -> (&mut [T], &mut T, &mut [T]) + where T: Ord + { + let mut f = |a: &T, b: &T| a.lt(b); + sort::partition_at_index(self, index, &mut f) + } + + /// Reorder the slice with a comparator function such that the element at `index` is at its + /// final sorted position. + /// + /// This reordering has the additional property that any value at position `i < index` will be + /// less than or equal to any value at a position `j > index` using the comparator function. + /// Additionally, this reordering is unstable (i.e. any number of equal elements may end up at + /// position `index`), in-place (i.e. does not allocate), and `O(n)` worst-case. This function + /// is also known as "kth element" in other libraries. It returns a triplet of the following + /// values: all elements less than the one at the given index, the value at the given index, + /// and all elements greater than the one at the given index, using the provided comparator + /// function. + /// + /// # Current implementation + /// + /// The current algorithm is based on the quickselect portion of the same quicksort algorithm + /// used for [`sort_unstable`]. + /// + /// [`sort_unstable`]: #method.sort_unstable + /// + /// # Panics + /// + /// Panics when `index >= len()`, meaning it always panics on empty slices. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_partition_at_index)] + /// + /// let mut v = [-5i32, 4, 1, -3, 2]; + /// + /// // Find the median as if the slice were sorted in descending order. + /// v.partition_at_index_by(2, |a, b| b.cmp(a)); + /// + /// // We are only guaranteed the slice will be one of the following, based on the way we sort + /// // about the specified index. + /// assert!(v == [2, 4, 1, -5, -3] || + /// v == [2, 4, 1, -3, -5] || + /// v == [4, 2, 1, -5, -3] || + /// v == [4, 2, 1, -3, -5]); + /// ``` + #[unstable(feature = "slice_partition_at_index", issue = "55300")] + #[inline] + pub fn partition_at_index_by<F>(&mut self, index: usize, mut compare: F) + -> (&mut [T], &mut T, &mut [T]) + where F: FnMut(&T, &T) -> Ordering + { + let mut f = |a: &T, b: &T| compare(a, b) == Less; + sort::partition_at_index(self, index, &mut f) + } + + /// Reorder the slice with a key extraction function such that the element at `index` is at its + /// final sorted position. + /// + /// This reordering has the additional property that any value at position `i < index` will be + /// less than or equal to any value at a position `j > index` using the key extraction function. + /// Additionally, this reordering is unstable (i.e. any number of equal elements may end up at + /// position `index`), in-place (i.e. does not allocate), and `O(n)` worst-case. This function + /// is also known as "kth element" in other libraries. It returns a triplet of the following + /// values: all elements less than the one at the given index, the value at the given index, and + /// all elements greater than the one at the given index, using the provided key extraction + /// function. + /// + /// # Current implementation + /// + /// The current algorithm is based on the quickselect portion of the same quicksort algorithm + /// used for [`sort_unstable`]. + /// + /// [`sort_unstable`]: #method.sort_unstable + /// + /// # Panics + /// + /// Panics when `index >= len()`, meaning it always panics on empty slices. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_partition_at_index)] + /// + /// let mut v = [-5i32, 4, 1, -3, 2]; + /// + /// // Return the median as if the array were sorted according to absolute value. + /// v.partition_at_index_by_key(2, |a| a.abs()); + /// + /// // We are only guaranteed the slice will be one of the following, based on the way we sort + /// // about the specified index. + /// assert!(v == [1, 2, -3, 4, -5] || + /// v == [1, 2, -3, -5, 4] || + /// v == [2, 1, -3, 4, -5] || + /// v == [2, 1, -3, -5, 4]); + /// ``` + #[unstable(feature = "slice_partition_at_index", issue = "55300")] + #[inline] + pub fn partition_at_index_by_key<K, F>(&mut self, index: usize, mut f: F) + -> (&mut [T], &mut T, &mut [T]) + where F: FnMut(&T) -> K, K: Ord + { + let mut g = |a: &T, b: &T| f(a).lt(&f(b)); + sort::partition_at_index(self, index, &mut g) + } + /// Moves all consecutive repeated elements to the end of the slice according to the /// [`PartialEq`] trait implementation. /// diff --git a/src/libcore/slice/sort.rs b/src/libcore/slice/sort.rs index 3f84faa0499..68f1fb4b526 100644 --- a/src/libcore/slice/sort.rs +++ b/src/libcore/slice/sort.rs @@ -691,3 +691,92 @@ pub fn quicksort<T, F>(v: &mut [T], mut is_less: F) recurse(v, &mut is_less, None, limit); } + +fn partition_at_index_loop<'a, T, F>( mut v: &'a mut [T], mut index: usize, is_less: &mut F + , mut pred: Option<&'a T>) where F: FnMut(&T, &T) -> bool +{ + loop { + // For slices of up to this length it's probably faster to simply sort them. + const MAX_INSERTION: usize = 10; + if v.len() <= MAX_INSERTION { + insertion_sort(v, is_less); + return; + } + + // Choose a pivot + let (pivot, _) = choose_pivot(v, is_less); + + // If the chosen pivot is equal to the predecessor, then it's the smallest element in the + // slice. Partition the slice into elements equal to and elements greater than the pivot. + // This case is usually hit when the slice contains many duplicate elements. + if let Some(p) = pred { + if !is_less(p, &v[pivot]) { + let mid = partition_equal(v, pivot, is_less); + + // If we've passed our index, then we're good. + if mid > index { + return; + } + + // Otherwise, continue sorting elements greater than the pivot. + v = &mut v[mid..]; + index = index - mid; + pred = None; + continue; + } + } + + let (mid, _) = partition(v, pivot, is_less); + + // Split the slice into `left`, `pivot`, and `right`. + let (left, right) = {v}.split_at_mut(mid); + let (pivot, right) = right.split_at_mut(1); + let pivot = &pivot[0]; + + if mid < index { + v = right; + index = index - mid - 1; + pred = Some(pivot); + } else if mid > index { + v = left; + } else { + // If mid == index, then we're done, since partition() guaranteed that all elements + // after mid are greater than or equal to mid. + return; + } + } +} + +pub fn partition_at_index<T, F>(v: &mut [T], index: usize, mut is_less: F) + -> (&mut [T], &mut T, &mut [T]) where F: FnMut(&T, &T) -> bool +{ + use cmp::Ordering::Less; + use cmp::Ordering::Greater; + + if index >= v.len() { + panic!("partition_at_index index {} greater than length of slice {}", index, v.len()); + } + + if mem::size_of::<T>() == 0 { + // Sorting has no meaningful behavior on zero-sized types. Do nothing. + } else if index == v.len() - 1 { + // Find max element and place it in the last position of the array. We're free to use + // `unwrap()` here because we know v must not be empty. + let (max_index, _) = v.iter().enumerate().max_by( + |&(_, x), &(_, y)| if is_less(x, y) { Less } else { Greater }).unwrap(); + v.swap(max_index, index); + } else if index == 0 { + // Find min element and place it in the first position of the array. We're free to use + // `unwrap()` here because we know v must not be empty. + let (min_index, _) = v.iter().enumerate().min_by( + |&(_, x), &(_, y)| if is_less(x, y) { Less } else { Greater }).unwrap(); + v.swap(min_index, index); + } else { + partition_at_index_loop(v, index, &mut is_less, None); + } + + let (left, right) = v.split_at_mut(index); + let (pivot, right) = right.split_at_mut(1); + let pivot = &mut pivot[0]; + (left, pivot, right) +} diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index f54d7badc3a..8d28be621d6 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -2712,7 +2712,7 @@ impl str { /// All kinds of ASCII whitespace are considered: /// /// ``` - /// let mut iter = " Mary had\ta little \n\t lamb".split_whitespace(); + /// let mut iter = " Mary had\ta little \n\t lamb".split_ascii_whitespace(); /// assert_eq!(Some("Mary"), iter.next()); /// assert_eq!(Some("had"), iter.next()); /// assert_eq!(Some("a"), iter.next()); diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index 04a49d25301..26b59969e18 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -124,15 +124,28 @@ use fmt; use hint::spin_loop; -/// Save power or switch hyperthreads in a busy-wait spin-loop. +/// Signals the processor that it is entering a busy-wait spin-loop. /// -/// This function is deliberately more primitive than -/// [`std::thread::yield_now`](../../../std/thread/fn.yield_now.html) and -/// does not directly yield to the system's scheduler. -/// In some cases it might be useful to use a combination of both functions. -/// Careful benchmarking is advised. +/// Upon receiving spin-loop signal the processor can optimize its behavior by, for example, saving +/// power or switching hyper-threads. /// -/// On some platforms this function may not do anything at all. +/// This function is different than [`std::thread::yield_now`] which directly yields to the +/// system's scheduler, whereas `spin_loop_hint` only signals the processor that it is entering a +/// busy-wait spin-loop without yielding control to the system's scheduler. +/// +/// Using a busy-wait spin-loop with `spin_loop_hint` is ideally used in situations where a +/// contended lock is held by another thread executed on a different CPU and where the waiting +/// times are relatively small. Because entering busy-wait spin-loop does not trigger the system's +/// scheduler, no overhead for switching threads occurs. However, if the thread holding the +/// contended lock is running on the same CPU, the spin-loop is likely to occupy an entire CPU slice +/// before switching to the thread that holds the lock. If the contending lock is held by a thread +/// on the same CPU or if the waiting times for acquiring the lock are longer, it is often better to +/// use [`std::thread::yield_now`]. +/// +/// **Note**: On platforms that do not support receiving spin-loop hints this function does not +/// do anything at all. +/// +/// [`std::thread::yield_now`]: ../../../std/thread/fn.yield_now.html #[inline] #[stable(feature = "spin_loop_hint", since = "1.24.0")] pub fn spin_loop_hint() { diff --git a/src/libcore/task/mod.rs b/src/libcore/task/mod.rs index 9b8f5981162..29bae69ea83 100644 --- a/src/libcore/task/mod.rs +++ b/src/libcore/task/mod.rs @@ -8,4 +8,4 @@ mod poll; pub use self::poll::Poll; mod wake; -pub use self::wake::{Waker, RawWaker, RawWakerVTable}; +pub use self::wake::{Context, Waker, RawWaker, RawWakerVTable}; diff --git a/src/libcore/task/wake.rs b/src/libcore/task/wake.rs index 12f812d3bed..006cbbb6ce6 100644 --- a/src/libcore/task/wake.rs +++ b/src/libcore/task/wake.rs @@ -3,7 +3,7 @@ issue = "50547")] use fmt; -use marker::Unpin; +use marker::{PhantomData, Unpin}; /// A `RawWaker` allows the implementor of a task executor to create a [`Waker`] /// which provides customized wakeup behavior. @@ -36,6 +36,10 @@ impl RawWaker { /// The `vtable` customizes the behavior of a `Waker` which gets created /// from a `RawWaker`. For each operation on the `Waker`, the associated /// function in the `vtable` of the underlying `RawWaker` will be called. + #[rustc_promotable] + #[unstable(feature = "futures_api", + reason = "futures in libcore are unstable", + issue = "50547")] pub const fn new(data: *const (), vtable: &'static RawWakerVTable) -> RawWaker { RawWaker { data, @@ -63,21 +67,124 @@ pub struct RawWakerVTable { /// required for this additional instance of a [`RawWaker`] and associated /// task. Calling `wake` on the resulting [`RawWaker`] should result in a wakeup /// of the same task that would have been awoken by the original [`RawWaker`]. - pub clone: unsafe fn(*const ()) -> RawWaker, + clone: unsafe fn(*const ()) -> RawWaker, /// This function will be called when `wake` is called on the [`Waker`]. /// It must wake up the task associated with this [`RawWaker`]. /// - /// The implemention of this function must not consume the provided data + /// The implementation of this function must make sure to release any + /// resources that are associated with this instance of a [`RawWaker`] and + /// associated task. + wake: unsafe fn(*const ()), + + /// This function will be called when `wake_by_ref` is called on the [`Waker`]. + /// It must wake up the task associated with this [`RawWaker`]. + /// + /// This function is similar to `wake`, but must not consume the provided data /// pointer. - pub wake: unsafe fn(*const ()), + wake_by_ref: unsafe fn(*const ()), /// This function gets called when a [`RawWaker`] gets dropped. /// /// The implementation of this function must make sure to release any /// resources that are associated with this instance of a [`RawWaker`] and /// associated task. - pub drop: unsafe fn(*const ()), + drop: unsafe fn(*const ()), +} + +impl RawWakerVTable { + /// Creates a new `RawWakerVTable` from the provided `clone`, `wake`, + /// `wake_by_ref`, and `drop` functions. + /// + /// # `clone` + /// + /// This function will be called when the [`RawWaker`] gets cloned, e.g. when + /// the [`Waker`] in which the [`RawWaker`] is stored gets cloned. + /// + /// The implementation of this function must retain all resources that are + /// required for this additional instance of a [`RawWaker`] and associated + /// task. Calling `wake` on the resulting [`RawWaker`] should result in a wakeup + /// of the same task that would have been awoken by the original [`RawWaker`]. + /// + /// # `wake` + /// + /// This function will be called when `wake` is called on the [`Waker`]. + /// It must wake up the task associated with this [`RawWaker`]. + /// + /// The implementation of this function must make sure to release any + /// resources that are associated with this instance of a [`RawWaker`] and + /// associated task. + /// + /// # `wake_by_ref` + /// + /// This function will be called when `wake_by_ref` is called on the [`Waker`]. + /// It must wake up the task associated with this [`RawWaker`]. + /// + /// This function is similar to `wake`, but must not consume the provided data + /// pointer. + /// + /// # `drop` + /// + /// This function gets called when a [`RawWaker`] gets dropped. + /// + /// The implementation of this function must make sure to release any + /// resources that are associated with this instance of a [`RawWaker`] and + /// associated task. + #[rustc_promotable] + #[unstable(feature = "futures_api", + reason = "futures in libcore are unstable", + issue = "50547")] + pub const fn new( + clone: unsafe fn(*const ()) -> RawWaker, + wake: unsafe fn(*const ()), + wake_by_ref: unsafe fn(*const ()), + drop: unsafe fn(*const ()), + ) -> Self { + Self { + clone, + wake, + wake_by_ref, + drop, + } + } +} + +/// The `Context` of an asynchronous task. +/// +/// Currently, `Context` only serves to provide access to a `&Waker` +/// which can be used to wake the current task. +pub struct Context<'a> { + waker: &'a Waker, + // Ensure we future-proof against variance changes by forcing + // the lifetime to be invariant (argument-position lifetimes + // are contravariant while return-position lifetimes are + // covariant). + _marker: PhantomData<fn(&'a ()) -> &'a ()>, +} + +impl<'a> Context<'a> { + /// Create a new `Context` from a `&Waker`. + #[inline] + pub fn from_waker(waker: &'a Waker) -> Self { + Context { + waker, + _marker: PhantomData, + } + } + + /// Returns a reference to the `Waker` for the current task. + #[inline] + pub fn waker(&self) -> &'a Waker { + &self.waker + } +} + +impl fmt::Debug for Context<'_> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Context") + .field("waker", &self.waker) + .finish() + } } /// A `Waker` is a handle for waking up a task by notifying its executor that it @@ -98,14 +205,34 @@ unsafe impl Sync for Waker {} impl Waker { /// Wake up the task associated with this `Waker`. - pub fn wake(&self) { + #[inline] + pub fn wake(self) { // The actual wakeup call is delegated through a virtual function call // to the implementation which is defined by the executor. + let wake = self.waker.vtable.wake; + let data = self.waker.data; + + // Don't call `drop` -- the waker will be consumed by `wake`. + crate::mem::forget(self); - // SAFETY: This is safe because `Waker::new_unchecked` is the only way + // SAFETY: This is safe because `Waker::from_raw` is the only way // to initialize `wake` and `data` requiring the user to acknowledge // that the contract of `RawWaker` is upheld. - unsafe { (self.waker.vtable.wake)(self.waker.data) } + unsafe { (wake)(data) }; + } + + /// Wake up the task associated with this `Waker` without consuming the `Waker`. + /// + /// This is similar to `wake`, but may be slightly less efficient in the case + /// where an owned `Waker` is available. This method should be preferred to + /// calling `waker.clone().wake()`. + #[inline] + pub fn wake_by_ref(&self) { + // The actual wakeup call is delegated through a virtual function call + // to the implementation which is defined by the executor. + + // SAFETY: see `wake` + unsafe { (self.waker.vtable.wake_by_ref)(self.waker.data) } } /// Returns `true` if this `Waker` and another `Waker` have awoken the same task. @@ -115,6 +242,7 @@ impl Waker { /// returns `true`, it is guaranteed that the `Waker`s will awaken the same task. /// /// This function is primarily used for optimization purposes. + #[inline] pub fn will_wake(&self, other: &Waker) -> bool { self.waker == other.waker } @@ -124,7 +252,8 @@ impl Waker { /// The behavior of the returned `Waker` is undefined if the contract defined /// in [`RawWaker`]'s and [`RawWakerVTable`]'s documentation is not upheld. /// Therefore this method is unsafe. - pub unsafe fn new_unchecked(waker: RawWaker) -> Waker { + #[inline] + pub unsafe fn from_raw(waker: RawWaker) -> Waker { Waker { waker, } @@ -132,9 +261,10 @@ impl Waker { } impl Clone for Waker { + #[inline] fn clone(&self) -> Self { Waker { - // SAFETY: This is safe because `Waker::new_unchecked` is the only way + // SAFETY: This is safe because `Waker::from_raw` is the only way // to initialize `clone` and `data` requiring the user to acknowledge // that the contract of [`RawWaker`] is upheld. waker: unsafe { (self.waker.vtable.clone)(self.waker.data) }, @@ -143,8 +273,9 @@ impl Clone for Waker { } impl Drop for Waker { + #[inline] fn drop(&mut self) { - // SAFETY: This is safe because `Waker::new_unchecked` is the only way + // SAFETY: This is safe because `Waker::from_raw` is the only way // to initialize `drop` and `data` requiring the user to acknowledge // that the contract of `RawWaker` is upheld. unsafe { (self.waker.vtable.drop)(self.waker.data) } diff --git a/src/libcore/tests/fmt/builders.rs b/src/libcore/tests/fmt/builders.rs index fd7192cc151..e4b75fe1fa2 100644 --- a/src/libcore/tests/fmt/builders.rs +++ b/src/libcore/tests/fmt/builders.rs @@ -30,7 +30,7 @@ mod debug_struct { assert_eq!("Foo { bar: true }", format!("{:?}", Foo)); assert_eq!( "Foo { - bar: true + bar: true, }", format!("{:#?}", Foo)); } @@ -52,7 +52,7 @@ mod debug_struct { assert_eq!( "Foo { bar: true, - baz: 10/20 + baz: 10/20, }", format!("{:#?}", Foo)); } @@ -87,9 +87,9 @@ mod debug_struct { "Bar { foo: Foo { bar: true, - baz: 10/20 + baz: 10/20, }, - hello: \"world\" + hello: \"world\", }", format!("{:#?}", Bar)); } @@ -127,7 +127,7 @@ mod debug_tuple { assert_eq!("Foo(true)", format!("{:?}", Foo)); assert_eq!( "Foo( - true + true, )", format!("{:#?}", Foo)); } @@ -149,7 +149,7 @@ mod debug_tuple { assert_eq!( "Foo( true, - 10/20 + 10/20, )", format!("{:#?}", Foo)); } @@ -184,9 +184,9 @@ mod debug_tuple { "Bar( Foo( true, - 10/20 + 10/20, ), - \"world\" + \"world\", )", format!("{:#?}", Bar)); } @@ -224,7 +224,7 @@ mod debug_map { assert_eq!("{\"bar\": true}", format!("{:?}", Foo)); assert_eq!( "{ - \"bar\": true + \"bar\": true, }", format!("{:#?}", Foo)); } @@ -246,7 +246,7 @@ mod debug_map { assert_eq!( "{ \"bar\": true, - 10: 10/20 + 10: 10/20, }", format!("{:#?}", Foo)); } @@ -282,12 +282,12 @@ mod debug_map { "{ \"foo\": { \"bar\": true, - 10: 10/20 + 10: 10/20, }, { \"bar\": true, - 10: 10/20 - }: \"world\" + 10: 10/20, + }: \"world\", }", format!("{:#?}", Bar)); } @@ -325,7 +325,7 @@ mod debug_set { assert_eq!("{true}", format!("{:?}", Foo)); assert_eq!( "{ - true + true, }", format!("{:#?}", Foo)); } @@ -347,7 +347,7 @@ mod debug_set { assert_eq!( "{ true, - 10/20 + 10/20, }", format!("{:#?}", Foo)); } @@ -382,9 +382,9 @@ mod debug_set { "{ { true, - 10/20 + 10/20, }, - \"world\" + \"world\", }", format!("{:#?}", Bar)); } @@ -422,7 +422,7 @@ mod debug_list { assert_eq!("[true]", format!("{:?}", Foo)); assert_eq!( "[ - true + true, ]", format!("{:#?}", Foo)); } @@ -444,7 +444,7 @@ mod debug_list { assert_eq!( "[ true, - 10/20 + 10/20, ]", format!("{:#?}", Foo)); } @@ -479,9 +479,9 @@ mod debug_list { "[ [ true, - 10/20 + 10/20, ], - \"world\" + \"world\", ]", format!("{:#?}", Bar)); } @@ -513,31 +513,31 @@ fn test_formatting_parameters_are_forwarded() { assert_eq!(format!("{:#03?}", struct_), " Foo { bar: 1024, - baz: 007 + baz: 007, } ".trim()); assert_eq!(format!("{:#03?}", tuple), " ( 1024, - 007 + 007, ) ".trim()); assert_eq!(format!("{:#03?}", list), " [ 1024, - 007 + 007, ] ".trim()); assert_eq!(format!("{:#03?}", map), r#" { "bar": 1024, - "baz": 007 + "baz": 007, } "#.trim()); assert_eq!(format!("{:#03?}", set), " { 007, - 1024 + 1024, } ".trim()); } diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index a3f0b02e2fe..d5b581d336d 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -1,4 +1,5 @@ use core::cell::Cell; +use core::convert::TryFrom; use core::iter::*; use core::{i8, i16, isize}; use core::usize; @@ -1801,6 +1802,66 @@ fn test_range_inclusive_folds() { } #[test] +fn test_range_size_hint() { + use core::usize::MAX as UMAX; + assert_eq!((0..0usize).size_hint(), (0, Some(0))); + assert_eq!((0..100usize).size_hint(), (100, Some(100))); + assert_eq!((0..UMAX).size_hint(), (UMAX, Some(UMAX))); + + let umax = u128::try_from(UMAX).unwrap(); + assert_eq!((0..0u128).size_hint(), (0, Some(0))); + assert_eq!((0..100u128).size_hint(), (100, Some(100))); + assert_eq!((0..umax).size_hint(), (UMAX, Some(UMAX))); + assert_eq!((0..umax + 1).size_hint(), (UMAX, None)); + + use core::isize::{MAX as IMAX, MIN as IMIN}; + assert_eq!((0..0isize).size_hint(), (0, Some(0))); + assert_eq!((-100..100isize).size_hint(), (200, Some(200))); + assert_eq!((IMIN..IMAX).size_hint(), (UMAX, Some(UMAX))); + + let imin = i128::try_from(IMIN).unwrap(); + let imax = i128::try_from(IMAX).unwrap(); + assert_eq!((0..0i128).size_hint(), (0, Some(0))); + assert_eq!((-100..100i128).size_hint(), (200, Some(200))); + assert_eq!((imin..imax).size_hint(), (UMAX, Some(UMAX))); + assert_eq!((imin..imax + 1).size_hint(), (UMAX, None)); +} + +#[test] +fn test_range_inclusive_size_hint() { + use core::usize::MAX as UMAX; + assert_eq!((1..=0usize).size_hint(), (0, Some(0))); + assert_eq!((0..=0usize).size_hint(), (1, Some(1))); + assert_eq!((0..=100usize).size_hint(), (101, Some(101))); + assert_eq!((0..=UMAX - 1).size_hint(), (UMAX, Some(UMAX))); + assert_eq!((0..=UMAX).size_hint(), (UMAX, None)); + + let umax = u128::try_from(UMAX).unwrap(); + assert_eq!((1..=0u128).size_hint(), (0, Some(0))); + assert_eq!((0..=0u128).size_hint(), (1, Some(1))); + assert_eq!((0..=100u128).size_hint(), (101, Some(101))); + assert_eq!((0..=umax - 1).size_hint(), (UMAX, Some(UMAX))); + assert_eq!((0..=umax).size_hint(), (UMAX, None)); + assert_eq!((0..=umax + 1).size_hint(), (UMAX, None)); + + use core::isize::{MAX as IMAX, MIN as IMIN}; + assert_eq!((0..=-1isize).size_hint(), (0, Some(0))); + assert_eq!((0..=0isize).size_hint(), (1, Some(1))); + assert_eq!((-100..=100isize).size_hint(), (201, Some(201))); + assert_eq!((IMIN..=IMAX - 1).size_hint(), (UMAX, Some(UMAX))); + assert_eq!((IMIN..=IMAX).size_hint(), (UMAX, None)); + + let imin = i128::try_from(IMIN).unwrap(); + let imax = i128::try_from(IMAX).unwrap(); + assert_eq!((0..=-1i128).size_hint(), (0, Some(0))); + assert_eq!((0..=0i128).size_hint(), (1, Some(1))); + assert_eq!((-100..=100i128).size_hint(), (201, Some(201))); + assert_eq!((imin..=imax - 1).size_hint(), (UMAX, Some(UMAX))); + assert_eq!((imin..=imax).size_hint(), (UMAX, None)); + assert_eq!((imin..=imax + 1).size_hint(), (UMAX, None)); +} + +#[test] fn test_repeat() { let mut it = repeat(42); assert_eq!(it.next(), Some(42)); diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 5e0dbb7ab2f..392a0ffabe3 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -18,6 +18,7 @@ #![feature(raw)] #![feature(slice_patterns)] #![feature(sort_internals)] +#![feature(slice_partition_at_index)] #![feature(specialization)] #![feature(step_trait)] #![feature(str_internals)] diff --git a/src/libcore/tests/slice.rs b/src/libcore/tests/slice.rs index 4946fd52a7e..007283b5f69 100644 --- a/src/libcore/tests/slice.rs +++ b/src/libcore/tests/slice.rs @@ -1093,6 +1093,124 @@ fn sort_unstable() { assert!(v == [0xDEADBEEF]); } +#[test] +#[cfg(not(target_arch = "wasm32"))] +#[cfg(not(miri))] // Miri does not support entropy +fn partition_at_index() { + use core::cmp::Ordering::{Equal, Greater, Less}; + use rand::rngs::SmallRng; + use rand::seq::SliceRandom; + use rand::{FromEntropy, Rng}; + + let mut rng = SmallRng::from_entropy(); + + for len in (2..21).chain(500..501) { + let mut orig = vec![0; len]; + + for &modulus in &[5, 10, 1000] { + for _ in 0..10 { + for i in 0..len { + orig[i] = rng.gen::<i32>() % modulus; + } + + let v_sorted = { + let mut v = orig.clone(); + v.sort(); + v + }; + + // Sort in default order. + for pivot in 0..len { + let mut v = orig.clone(); + v.partition_at_index(pivot); + + assert_eq!(v_sorted[pivot], v[pivot]); + for i in 0..pivot { + for j in pivot..len { + assert!(v[i] <= v[j]); + } + } + } + + // Sort in ascending order. + for pivot in 0..len { + let mut v = orig.clone(); + let (left, pivot, right) = v.partition_at_index_by(pivot, |a, b| a.cmp(b)); + + assert_eq!(left.len() + right.len(), len - 1); + + for l in left { + assert!(l <= pivot); + for r in right.iter_mut() { + assert!(l <= r); + assert!(pivot <= r); + } + } + } + + // Sort in descending order. + let sort_descending_comparator = |a: &i32, b: &i32| b.cmp(a); + let v_sorted_descending = { + let mut v = orig.clone(); + v.sort_by(sort_descending_comparator); + v + }; + + for pivot in 0..len { + let mut v = orig.clone(); + v.partition_at_index_by(pivot, sort_descending_comparator); + + assert_eq!(v_sorted_descending[pivot], v[pivot]); + for i in 0..pivot { + for j in pivot..len { + assert!(v[j] <= v[i]); + } + } + } + } + } + } + + // Sort at index using a completely random comparison function. + // This will reorder the elements *somehow*, but won't panic. + let mut v = [0; 500]; + for i in 0..v.len() { + v[i] = i as i32; + } + + for pivot in 0..v.len() { + v.partition_at_index_by(pivot, |_, _| *[Less, Equal, Greater].choose(&mut rng).unwrap()); + v.sort(); + for i in 0..v.len() { + assert_eq!(v[i], i as i32); + } + } + + // Should not panic. + [(); 10].partition_at_index(0); + [(); 10].partition_at_index(5); + [(); 10].partition_at_index(9); + [(); 100].partition_at_index(0); + [(); 100].partition_at_index(50); + [(); 100].partition_at_index(99); + + let mut v = [0xDEADBEEFu64]; + v.partition_at_index(0); + assert!(v == [0xDEADBEEF]); +} + +#[test] +#[should_panic(expected = "index 0 greater than length of slice")] +fn partition_at_index_zero_length() { + [0i32; 0].partition_at_index(0); +} + +#[test] +#[should_panic(expected = "index 20 greater than length of slice")] +fn partition_at_index_past_length() { + [0i32; 10].partition_at_index(20); +} + pub mod memchr { use core::slice::memchr::{memchr, memrchr}; diff --git a/src/libfmt_macros/lib.rs b/src/libfmt_macros/lib.rs index aacd6cec565..2536121c7a3 100644 --- a/src/libfmt_macros/lib.rs +++ b/src/libfmt_macros/lib.rs @@ -9,6 +9,7 @@ test(attr(deny(warnings))))] #![deny(rust_2018_idioms)] +#![cfg_attr(not(stage0), deny(internal))] #![feature(nll)] #![feature(rustc_private)] diff --git a/src/libpanic_unwind/lib.rs b/src/libpanic_unwind/lib.rs index 9d3d8f6185b..72ddafb420c 100644 --- a/src/libpanic_unwind/lib.rs +++ b/src/libpanic_unwind/lib.rs @@ -19,8 +19,6 @@ #![deny(rust_2018_idioms)] -#![feature(allocator_api)] -#![feature(alloc)] #![feature(core_intrinsics)] #![feature(lang_items)] #![feature(libc)] diff --git a/src/libproc_macro/bridge/rpc.rs b/src/libproc_macro/bridge/rpc.rs index 4289f33ffd5..5018be74f89 100644 --- a/src/libproc_macro/bridge/rpc.rs +++ b/src/libproc_macro/bridge/rpc.rs @@ -24,32 +24,22 @@ pub(super) trait DecodeMut<'a, 's, S>: Sized { } macro_rules! rpc_encode_decode { - (uleb128 $ty:ty) => { + (le $ty:ty) => { impl<S> Encode<S> for $ty { - fn encode(mut self, w: &mut Writer, s: &mut S) { - let mut byte = 0x80; - while byte & 0x80 != 0 { - byte = (self & 0x7f) as u8; - self >>= 7; - if self != 0 { - byte |= 0x80; - } - byte.encode(w, s); - } + fn encode(self, w: &mut Writer, _: &mut S) { + w.write_all(&self.to_le_bytes()).unwrap(); } } impl<S> DecodeMut<'_, '_, S> for $ty { - fn decode(r: &mut Reader<'_>, s: &mut S) -> Self { - let mut byte = 0x80; - let mut v = 0; - let mut shift = 0; - while byte & 0x80 != 0 { - byte = u8::decode(r, s); - v |= ((byte & 0x7f) as Self) << shift; - shift += 7; - } - v + fn decode(r: &mut Reader<'_>, _: &mut S) -> Self { + const N: usize = ::std::mem::size_of::<$ty>(); + + let mut bytes = [0; N]; + bytes.copy_from_slice(&r[..N]); + *r = &r[N..]; + + Self::from_le_bytes(bytes) } } }; @@ -136,8 +126,8 @@ impl<S> DecodeMut<'_, '_, S> for u8 { } } -rpc_encode_decode!(uleb128 u32); -rpc_encode_decode!(uleb128 usize); +rpc_encode_decode!(le u32); +rpc_encode_decode!(le usize); impl<S> Encode<S> for bool { fn encode(self, w: &mut Writer, s: &mut S) { diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs index 03905f3e705..1e0f1ed578a 100644 --- a/src/libproc_macro/lib.rs +++ b/src/libproc_macro/lib.rs @@ -160,9 +160,7 @@ impl iter::FromIterator<TokenTree> for TokenStream { impl iter::FromIterator<TokenStream> for TokenStream { fn from_iter<I: IntoIterator<Item = TokenStream>>(streams: I) -> Self { let mut builder = bridge::client::TokenStreamBuilder::new(); - for stream in streams { - builder.push(stream.0); - } + streams.into_iter().for_each(|stream| builder.push(stream.0)); TokenStream(builder.build()) } } diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml index f07111ef647..2876024beb1 100644 --- a/src/librustc/Cargo.toml +++ b/src/librustc/Cargo.toml @@ -36,6 +36,7 @@ byteorder = { version = "1.1", features = ["i128"]} chalk-engine = { version = "0.9.0", default-features=false } rustc_fs_util = { path = "../librustc_fs_util" } smallvec = { version = "0.6.7", features = ["union", "may_dangle"] } +measureme = "0.2.1" # Note that these dependencies are a lie, they're just here to get linkage to # work. diff --git a/src/librustc/arena.rs b/src/librustc/arena.rs new file mode 100644 index 00000000000..e9751a23f12 --- /dev/null +++ b/src/librustc/arena.rs @@ -0,0 +1,206 @@ +use arena::{TypedArena, DroplessArena}; +use std::mem; +use std::ptr; +use std::slice; +use std::cell::RefCell; +use std::marker::PhantomData; +use smallvec::SmallVec; + +#[macro_export] +macro_rules! arena_types { + ($macro:path, $args:tt, $tcx:lifetime) => ( + $macro!($args, [ + [] vtable_method: Option<( + rustc::hir::def_id::DefId, + rustc::ty::subst::SubstsRef<$tcx> + )>, + [few] mir_keys: rustc::util::nodemap::DefIdSet, + [decode] specialization_graph: rustc::traits::specialization_graph::Graph, + ], $tcx); + ) +} + +macro_rules! arena_for_type { + ([][$ty:ty]) => { + TypedArena<$ty> + }; + ([few $(, $attrs:ident)*][$ty:ty]) => { + PhantomData<$ty> + }; + ([$ignore:ident $(, $attrs:ident)*]$args:tt) => { + arena_for_type!([$($attrs),*]$args) + }; +} + +macro_rules! declare_arena { + ([], [$($a:tt $name:ident: $ty:ty,)*], $tcx:lifetime) => { + #[derive(Default)] + pub struct Arena<$tcx> { + dropless: DroplessArena, + drop: DropArena, + $($name: arena_for_type!($a[$ty]),)* + } + } +} + +macro_rules! which_arena_for_type { + ([][$arena:expr]) => { + Some($arena) + }; + ([few$(, $attrs:ident)*][$arena:expr]) => { + None + }; + ([$ignore:ident$(, $attrs:ident)*]$args:tt) => { + which_arena_for_type!([$($attrs),*]$args) + }; +} + +macro_rules! impl_arena_allocatable { + ([], [$($a:tt $name:ident: $ty:ty,)*], $tcx:lifetime) => { + $( + impl ArenaAllocatable for $ty {} + unsafe impl<$tcx> ArenaField<$tcx> for $ty { + #[inline] + fn arena<'a>(_arena: &'a Arena<$tcx>) -> Option<&'a TypedArena<Self>> { + which_arena_for_type!($a[&_arena.$name]) + } + } + )* + } +} + +arena_types!(declare_arena, [], 'tcx); + +arena_types!(impl_arena_allocatable, [], 'tcx); + +pub trait ArenaAllocatable {} + +impl<T: Copy> ArenaAllocatable for T {} + +pub unsafe trait ArenaField<'tcx>: Sized { + /// Returns a specific arena to allocate from. + /// If None is returned, the DropArena will be used. + fn arena<'a>(arena: &'a Arena<'tcx>) -> Option<&'a TypedArena<Self>>; +} + +unsafe impl<'tcx, T> ArenaField<'tcx> for T { + #[inline] + default fn arena<'a>(_: &'a Arena<'tcx>) -> Option<&'a TypedArena<Self>> { + panic!() + } +} + +impl<'tcx> Arena<'tcx> { + #[inline] + pub fn alloc<T: ArenaAllocatable>(&self, value: T) -> &mut T { + if !mem::needs_drop::<T>() { + return self.dropless.alloc(value); + } + match <T as ArenaField<'tcx>>::arena(self) { + Some(arena) => arena.alloc(value), + None => unsafe { self.drop.alloc(value) }, + } + } + + pub fn alloc_from_iter< + T: ArenaAllocatable, + I: IntoIterator<Item = T> + >( + &'a self, + iter: I + ) -> &'a mut [T] { + if !mem::needs_drop::<T>() { + return self.dropless.alloc_from_iter(iter); + } + match <T as ArenaField<'tcx>>::arena(self) { + Some(arena) => arena.alloc_from_iter(iter), + None => unsafe { self.drop.alloc_from_iter(iter) }, + } + } +} + +/// Calls the destructor for an object when dropped. +struct DropType { + drop_fn: unsafe fn(*mut u8), + obj: *mut u8, +} + +unsafe fn drop_for_type<T>(to_drop: *mut u8) { + std::ptr::drop_in_place(to_drop as *mut T) +} + +impl Drop for DropType { + fn drop(&mut self) { + unsafe { + (self.drop_fn)(self.obj) + } + } +} + +/// An arena which can be used to allocate any type. +/// Allocating in this arena is unsafe since the type system +/// doesn't know which types it contains. In order to +/// allocate safely, you must store a PhantomData<T> +/// alongside this arena for each type T you allocate. +#[derive(Default)] +struct DropArena { + /// A list of destructors to run when the arena drops. + /// Ordered so `destructors` gets dropped before the arena + /// since its destructor can reference memory in the arena. + destructors: RefCell<Vec<DropType>>, + arena: DroplessArena, +} + +impl DropArena { + #[inline] + unsafe fn alloc<T>(&self, object: T) -> &mut T { + let mem = self.arena.alloc_raw( + mem::size_of::<T>(), + mem::align_of::<T>() + ) as *mut _ as *mut T; + // Write into uninitialized memory. + ptr::write(mem, object); + let result = &mut *mem; + // Record the destructor after doing the allocation as that may panic + // and would cause `object`'s destuctor to run twice if it was recorded before + self.destructors.borrow_mut().push(DropType { + drop_fn: drop_for_type::<T>, + obj: result as *mut T as *mut u8, + }); + result + } + + #[inline] + unsafe fn alloc_from_iter<T, I: IntoIterator<Item = T>>(&self, iter: I) -> &mut [T] { + let mut vec: SmallVec<[_; 8]> = iter.into_iter().collect(); + if vec.is_empty() { + return &mut []; + } + let len = vec.len(); + + let start_ptr = self.arena.alloc_raw( + len.checked_mul(mem::size_of::<T>()).unwrap(), + mem::align_of::<T>() + ) as *mut _ as *mut T; + + let mut destructors = self.destructors.borrow_mut(); + // Reserve space for the destructors so we can't panic while adding them + destructors.reserve(len); + + // Move the content to the arena by copying it and then forgetting + // the content of the SmallVec + vec.as_ptr().copy_to_nonoverlapping(start_ptr, len); + mem::forget(vec.drain()); + + // Record the destructors after doing the allocation as that may panic + // and would cause `object`'s destuctor to run twice if it was recorded before + for i in 0..len { + destructors.push(DropType { + drop_fn: drop_for_type::<T>, + obj: start_ptr.offset(i as isize) as *mut u8, + }); + } + + slice::from_raw_parts_mut(start_ptr, len) + } +} diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 03fa5c04ec7..e5bf9a27ab0 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -65,8 +65,7 @@ use crate::traits::query::{ CanonicalTypeOpEqGoal, CanonicalTypeOpSubtypeGoal, CanonicalPredicateGoal, CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpNormalizeGoal, }; -use crate::ty::{TyCtxt, FnSig, Instance, InstanceDef, - ParamEnv, ParamEnvAnd, Predicate, PolyFnSig, PolyTraitRef, Ty}; +use crate::ty::{self, TyCtxt, ParamEnvAnd, Ty}; use crate::ty::subst::SubstsRef; // erase!() just makes tokens go away. It's used to specify which macro argument @@ -432,211 +431,13 @@ rustc_dep_node_append!([define_dep_nodes!][ <'tcx> // Represents metadata from an extern crate. [eval_always] CrateMetadata(CrateNum), - // Represents different phases in the compiler. - [] RegionScopeTree(DefId), - [eval_always] Coherence, - [eval_always] CoherenceInherentImplOverlapCheck, - [] CoherenceCheckTrait(DefId), - [eval_always] PrivacyAccessLevels(CrateNum), - [eval_always] CheckPrivateInPublic(CrateNum), - [eval_always] Analysis(CrateNum), - - // Represents the MIR for a fn; also used as the task node for - // things read/modify that MIR. - [] MirShim { instance_def: InstanceDef<'tcx> }, - - [] BorrowCheckKrate, - [] BorrowCheck(DefId), - [] MirBorrowCheck(DefId), - [] UnsafetyCheckResult(DefId), - [] UnsafeDeriveOnReprPacked(DefId), - - [] LintMod(DefId), - [] CheckModAttrs(DefId), - [] CheckModLoops(DefId), - [] CheckModUnstableApiUsage(DefId), - [] CheckModItemTypes(DefId), - [] CheckModPrivacy(DefId), - [] CheckModIntrinsics(DefId), - [] CheckModLiveness(DefId), - [] CheckModImplWf(DefId), - [] CollectModItemTypes(DefId), - - [] Reachability, - [] CrateVariances, - - // Nodes representing bits of computed IR in the tcx. Each shared - // table in the tcx (or elsewhere) maps to one of these - // nodes. - [] AssociatedItems(DefId), - [] ExplicitPredicatesOfItem(DefId), - [] PredicatesDefinedOnItem(DefId), - [] InferredOutlivesOf(DefId), - [] InferredOutlivesCrate(CrateNum), - [] SuperPredicatesOfItem(DefId), - [] TraitDefOfItem(DefId), - [] AdtDefOfItem(DefId), - [] ImplTraitRef(DefId), - [] ImplPolarity(DefId), - [] Issue33140SelfTy(DefId), - [] FnSignature(DefId), - [] CoerceUnsizedInfo(DefId), - - [] ItemVarianceConstraints(DefId), - [] ItemVariances(DefId), - [] IsConstFn(DefId), - [] IsPromotableConstFn(DefId), - [] IsForeignItem(DefId), - [] TypeParamPredicates { item_id: DefId, param_id: DefId }, - [] SizedConstraint(DefId), - [] DtorckConstraint(DefId), - [] AdtDestructor(DefId), - [] AssociatedItemDefIds(DefId), - [eval_always] InherentImpls(DefId), - [] TypeckBodiesKrate, - [] TypeckTables(DefId), - [] UsedTraitImports(DefId), - [] HasTypeckTables(DefId), - [] ConstEval { param_env: ParamEnvAnd<'tcx, GlobalId<'tcx>> }, - [] ConstEvalRaw { param_env: ParamEnvAnd<'tcx, GlobalId<'tcx>> }, - [] CheckMatch(DefId), - [] SymbolName { instance: Instance<'tcx> }, - [] SpecializationGraph(DefId), - [] ObjectSafety(DefId), - [] FulfillObligation { param_env: ParamEnv<'tcx>, trait_ref: PolyTraitRef<'tcx> }, - [] VtableMethods { trait_ref: PolyTraitRef<'tcx> }, - - [] IsCopy { param_env: ParamEnvAnd<'tcx, Ty<'tcx>> }, - [] IsSized { param_env: ParamEnvAnd<'tcx, Ty<'tcx>> }, - [] IsFreeze { param_env: ParamEnvAnd<'tcx, Ty<'tcx>> }, - [] NeedsDrop { param_env: ParamEnvAnd<'tcx, Ty<'tcx>> }, - [] Layout { param_env: ParamEnvAnd<'tcx, Ty<'tcx>> }, - - // The set of impls for a given trait. - [] TraitImpls(DefId), - [eval_always] AllLocalTraitImpls, [anon] TraitSelect, - [] ParamEnv(DefId), - [] DescribeDef(DefId), - - // FIXME(mw): DefSpans are not really inputs since they are derived from - // HIR. But at the moment HIR hashing still contains some hacks that allow - // to make type debuginfo to be source location independent. Declaring - // DefSpan an input makes sure that changes to these are always detected - // regardless of HIR hashing. - [eval_always] DefSpan(DefId), - [] LookupStability(DefId), - [] LookupDeprecationEntry(DefId), - [] ConstIsRvaluePromotableToStatic(DefId), - [] RvaluePromotableMap(DefId), - [] ImplParent(DefId), - [] TraitOfItem(DefId), - [] IsReachableNonGeneric(DefId), - [] IsUnreachableLocalDefinition(DefId), - [] IsMirAvailable(DefId), - [] ItemAttrs(DefId), - [] CodegenFnAttrs(DefId), - [] FnArgNames(DefId), - [] RenderedConst(DefId), - [] DylibDepFormats(CrateNum), - [] IsCompilerBuiltins(CrateNum), - [] HasGlobalAllocator(CrateNum), - [] HasPanicHandler(CrateNum), - [eval_always] ExternCrate(DefId), - [] Specializes { impl1: DefId, impl2: DefId }, - [eval_always] InScopeTraits(DefIndex), - [eval_always] ModuleExports(DefId), - [] IsSanitizerRuntime(CrateNum), - [] IsProfilerRuntime(CrateNum), - [] GetPanicStrategy(CrateNum), - [] IsNoBuiltins(CrateNum), - [] ImplDefaultness(DefId), - [] CheckItemWellFormed(DefId), - [] CheckTraitItemWellFormed(DefId), - [] CheckImplItemWellFormed(DefId), - [] ReachableNonGenerics(CrateNum), - [] EntryFn(CrateNum), - [] PluginRegistrarFn(CrateNum), - [] ProcMacroDeclsStatic(CrateNum), - [eval_always] CrateDisambiguator(CrateNum), - [eval_always] CrateHash(CrateNum), - [eval_always] OriginalCrateName(CrateNum), - [eval_always] ExtraFileName(CrateNum), - - [] ImplementationsOfTrait { krate: CrateNum, trait_id: DefId }, - [] AllTraitImplementations(CrateNum), - - [] DllimportForeignItems(CrateNum), - [] IsDllimportForeignItem(DefId), - [] IsStaticallyIncludedForeignItem(DefId), - [] NativeLibraryKind(DefId), - [eval_always] LinkArgs, - - [] ResolveLifetimes(CrateNum), - [] NamedRegion(DefIndex), - [] IsLateBound(DefIndex), - [] ObjectLifetimeDefaults(DefIndex), - - [] Visibility(DefId), - [eval_always] DepKind(CrateNum), - [eval_always] CrateName(CrateNum), - [] ItemChildren(DefId), - [] ExternModStmtCnum(DefId), - [eval_always] GetLibFeatures, - [] DefinedLibFeatures(CrateNum), - [eval_always] GetLangItems, - [] DefinedLangItems(CrateNum), - [] MissingLangItems(CrateNum), - [] VisibleParentMap, - [eval_always] MissingExternCrateItem(CrateNum), - [eval_always] UsedCrateSource(CrateNum), - [eval_always] PostorderCnums, - - [eval_always] Freevars(DefId), - [eval_always] MaybeUnusedTraitImport(DefId), - [eval_always] MaybeUnusedExternCrates, - [eval_always] NamesImportedByGlobUse(DefId), - [eval_always] StabilityIndex, - [eval_always] AllTraits, - [eval_always] AllCrateNums, - [] ExportedSymbols(CrateNum), - [eval_always] CollectAndPartitionMonoItems, - [] IsCodegenedItem(DefId), - [] CodegenUnit(InternedString), - [] BackendOptimizationLevel(CrateNum), [] CompileCodegenUnit(InternedString), - [eval_always] OutputFilenames, - [] NormalizeProjectionTy(CanonicalProjectionGoal<'tcx>), - [] NormalizeTyAfterErasingRegions(ParamEnvAnd<'tcx, Ty<'tcx>>), - [] ImpliedOutlivesBounds(CanonicalTyGoal<'tcx>), - [] DropckOutlives(CanonicalTyGoal<'tcx>), - [] EvaluateObligation(CanonicalPredicateGoal<'tcx>), - [] EvaluateGoal(traits::ChalkCanonicalGoal<'tcx>), - [] TypeOpAscribeUserType(CanonicalTypeOpAscribeUserTypeGoal<'tcx>), - [] TypeOpEq(CanonicalTypeOpEqGoal<'tcx>), - [] TypeOpSubtype(CanonicalTypeOpSubtypeGoal<'tcx>), - [] TypeOpProvePredicate(CanonicalTypeOpProvePredicateGoal<'tcx>), - [] TypeOpNormalizeTy(CanonicalTypeOpNormalizeGoal<'tcx, Ty<'tcx>>), - [] TypeOpNormalizePredicate(CanonicalTypeOpNormalizeGoal<'tcx, Predicate<'tcx>>), - [] TypeOpNormalizePolyFnSig(CanonicalTypeOpNormalizeGoal<'tcx, PolyFnSig<'tcx>>), - [] TypeOpNormalizeFnSig(CanonicalTypeOpNormalizeGoal<'tcx, FnSig<'tcx>>), - - [] SubstituteNormalizeAndTestPredicates { key: (DefId, SubstsRef<'tcx>) }, - [] MethodAutoderefSteps(CanonicalTyGoal<'tcx>), - - [eval_always] TargetFeaturesWhitelist, - - [] InstanceDefSizeEstimate { instance_def: InstanceDef<'tcx> }, - - [eval_always] Features, - - [] ForeignModules(CrateNum), - - [] UpstreamMonomorphizations(CrateNum), - [] UpstreamMonomorphizationsFor(DefId), + + [eval_always] Analysis(CrateNum), ]); pub trait RecoverKey<'tcx>: Sized { @@ -655,6 +456,12 @@ impl RecoverKey<'tcx> for DefId { } } +impl RecoverKey<'tcx> for DefIndex { + fn recover(tcx: TyCtxt<'_, 'tcx, 'tcx>, dep_node: &DepNode) -> Option<Self> { + dep_node.extract_def_id(tcx).map(|id| id.index) + } +} + trait DepNodeParams<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> : fmt::Debug { const CAN_RECONSTRUCT_QUERY_KEY: bool; diff --git a/src/librustc/hir/def_id.rs b/src/librustc/hir/def_id.rs index 397843fd75a..8536f38e48c 100644 --- a/src/librustc/hir/def_id.rs +++ b/src/librustc/hir/def_id.rs @@ -1,5 +1,4 @@ -use crate::ty; -use crate::ty::TyCtxt; +use crate::ty::{self, TyCtxt}; use crate::hir::map::definitions::FIRST_FREE_HIGH_DEF_INDEX; use rustc_data_structures::indexed_vec::Idx; use serialize; diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 6689b0c26fb..c2265eeb30d 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -490,7 +490,11 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { visitor.visit_ty(ty); visitor.visit_generics(generics) } - ItemKind::Existential(ExistTy { ref generics, ref bounds, impl_trait_fn: _ }) => { + ItemKind::Existential(ExistTy { + ref generics, + ref bounds, + .. + }) => { visitor.visit_id(item.hir_id); walk_generics(visitor, generics); walk_list!(visitor, visit_param_bound, bounds); diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 7dfb16602a3..2a255523676 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -66,7 +66,7 @@ use syntax::symbol::{keywords, Symbol}; use syntax::tokenstream::{TokenStream, TokenTree}; use syntax::parse::token::Token; use syntax::visit::{self, Visitor}; -use syntax_pos::{Span, MultiSpan}; +use syntax_pos::Span; const HIR_ID_COUNTER_LOCKED: u32 = 0xFFFFFFFF; @@ -318,6 +318,49 @@ enum AnonymousLifetimeMode { /// Pass responsibility to `resolve_lifetime` code for all cases. PassThrough, + + /// Used in the return types of `async fn` where there exists + /// exactly one argument-position elided lifetime. + /// + /// In `async fn`, we lower the arguments types using the `CreateParameter` + /// mode, meaning that non-`dyn` elided lifetimes are assigned a fresh name. + /// If any corresponding elided lifetimes appear in the output, we need to + /// replace them with references to the fresh name assigned to the corresponding + /// elided lifetime in the arguments. + /// + /// For **Modern cases**, replace the anonymous parameter with a + /// reference to a specific freshly-named lifetime that was + /// introduced in argument + /// + /// For **Dyn Bound** cases, pass responsibility to + /// `resole_lifetime` code. + Replace(LtReplacement), +} + +/// The type of elided lifetime replacement to perform on `async fn` return types. +#[derive(Copy, Clone)] +enum LtReplacement { + /// Fresh name introduced by the single non-dyn elided lifetime + /// in the arguments of the async fn. + Some(ParamName), + + /// There is no single non-dyn elided lifetime because no lifetimes + /// appeared in the arguments. + NoLifetimes, + + /// There is no single non-dyn elided lifetime because multiple + /// lifetimes appeared in the arguments. + MultipleLifetimes, +} + +/// Calculates the `LtReplacement` to use for elided lifetimes in the return +/// type based on the fresh elided lifetimes introduced in argument position. +fn get_elided_lt_replacement(arg_position_lifetimes: &[(Span, ParamName)]) -> LtReplacement { + match arg_position_lifetimes { + [] => LtReplacement::NoLifetimes, + [(_span, param)] => LtReplacement::Some(*param), + _ => LtReplacement::MultipleLifetimes, + } } struct ImplTraitTypeIdVisitor<'a> { ids: &'a mut SmallVec<[NodeId; 1]> } @@ -778,53 +821,63 @@ impl<'a> LoweringContext<'a> { let params = lifetimes_to_define .into_iter() - .map(|(span, hir_name)| { - let LoweredNodeId { node_id, hir_id } = self.next_id(); - - // Get the name we'll use to make the def-path. Note - // that collisions are ok here and this shouldn't - // really show up for end-user. - let (str_name, kind) = match hir_name { - ParamName::Plain(ident) => ( - ident.as_interned_str(), - hir::LifetimeParamKind::InBand, - ), - ParamName::Fresh(_) => ( - keywords::UnderscoreLifetime.name().as_interned_str(), - hir::LifetimeParamKind::Elided, - ), - ParamName::Error => ( - keywords::UnderscoreLifetime.name().as_interned_str(), - hir::LifetimeParamKind::Error, - ), - }; - - // Add a definition for the in-band lifetime def. - self.resolver.definitions().create_def_with_parent( - parent_id.index, - node_id, - DefPathData::LifetimeParam(str_name), - DefIndexAddressSpace::High, - Mark::root(), - span, - ); - - hir::GenericParam { - hir_id, - name: hir_name, - attrs: hir_vec![], - bounds: hir_vec![], - span, - pure_wrt_drop: false, - kind: hir::GenericParamKind::Lifetime { kind } - } - }) + .map(|(span, hir_name)| self.lifetime_to_generic_param( + span, hir_name, parent_id.index, + )) .chain(in_band_ty_params.into_iter()) .collect(); (params, res) } + /// Converts a lifetime into a new generic parameter. + fn lifetime_to_generic_param( + &mut self, + span: Span, + hir_name: ParamName, + parent_index: DefIndex, + ) -> hir::GenericParam { + let LoweredNodeId { node_id, hir_id } = self.next_id(); + + // Get the name we'll use to make the def-path. Note + // that collisions are ok here and this shouldn't + // really show up for end-user. + let (str_name, kind) = match hir_name { + ParamName::Plain(ident) => ( + ident.as_interned_str(), + hir::LifetimeParamKind::InBand, + ), + ParamName::Fresh(_) => ( + keywords::UnderscoreLifetime.name().as_interned_str(), + hir::LifetimeParamKind::Elided, + ), + ParamName::Error => ( + keywords::UnderscoreLifetime.name().as_interned_str(), + hir::LifetimeParamKind::Error, + ), + }; + + // Add a definition for the in-band lifetime def. + self.resolver.definitions().create_def_with_parent( + parent_index, + node_id, + DefPathData::LifetimeParam(str_name), + DefIndexAddressSpace::High, + Mark::root(), + span, + ); + + hir::GenericParam { + hir_id, + name: hir_name, + attrs: hir_vec![], + bounds: hir_vec![], + span, + pure_wrt_drop: false, + kind: hir::GenericParamKind::Lifetime { kind } + } + } + /// When there is a reference to some lifetime `'a`, and in-band /// lifetimes are enabled, then we want to push that lifetime into /// the vector of names to define later. In that case, it will get @@ -928,6 +981,13 @@ impl<'a> LoweringContext<'a> { |this| { this.collect_in_band_defs(parent_id, anonymous_lifetime_mode, |this| { let mut params = Vec::new(); + // Note: it is necessary to lower generics *before* calling `f`. + // When lowering `async fn`, there's a final step when lowering + // the return type that assumes that all in-scope lifetimes have + // already been added to either `in_scope_lifetimes` or + // `lifetimes_to_define`. If we swapped the order of these two, + // in-band-lifetimes introduced by generics or where-clauses + // wouldn't have been added yet. let generics = this.lower_generics( generics, ImplTraitContext::Universal(&mut params), @@ -1426,42 +1486,62 @@ impl<'a> LoweringContext<'a> { self.with_hir_id_owner(exist_ty_node_id, |lctx| { let LoweredNodeId { node_id: _, hir_id } = lctx.next_id(); - let exist_ty_item_kind = hir::ItemKind::Existential(hir::ExistTy { + let exist_ty_item = hir::ExistTy { generics: hir::Generics { params: lifetime_defs, where_clause: hir::WhereClause { hir_id, - predicates: Vec::new().into(), + predicates: hir_vec![], }, span, }, bounds: hir_bounds, impl_trait_fn: fn_def_id, - }); - let exist_ty_id = lctx.lower_node_id(exist_ty_node_id); - // Generate an `existential type Foo: Trait;` declaration. - trace!("creating existential type with id {:#?}", exist_ty_id); - - trace!("exist ty def index: {:#?}", exist_ty_def_index); - let exist_ty_item = hir::Item { - hir_id: exist_ty_id.hir_id, - ident: keywords::Invalid.ident(), - attrs: Default::default(), - node: exist_ty_item_kind, - vis: respan(span.shrink_to_lo(), hir::VisibilityKind::Inherited), - span: exist_ty_span, + origin: hir::ExistTyOrigin::ReturnImplTrait, }; - // Insert the item into the global list. This usually happens - // automatically for all AST items. But this existential type item - // does not actually exist in the AST. - lctx.insert_item(exist_ty_item); + trace!("exist ty from impl trait def index: {:#?}", exist_ty_def_index); + let exist_ty_id = lctx.generate_existential_type( + exist_ty_node_id, + exist_ty_item, + span, + exist_ty_span, + ); // `impl Trait` now just becomes `Foo<'a, 'b, ..>`. hir::TyKind::Def(hir::ItemId { id: exist_ty_id.hir_id }, lifetimes) }) } + /// Registers a new existential type with the proper NodeIds and + /// returns the lowered node ID for the existential type. + fn generate_existential_type( + &mut self, + exist_ty_node_id: NodeId, + exist_ty_item: hir::ExistTy, + span: Span, + exist_ty_span: Span, + ) -> LoweredNodeId { + let exist_ty_item_kind = hir::ItemKind::Existential(exist_ty_item); + let exist_ty_id = self.lower_node_id(exist_ty_node_id); + // Generate an `existential type Foo: Trait;` declaration. + trace!("registering existential type with id {:#?}", exist_ty_id); + let exist_ty_item = hir::Item { + hir_id: exist_ty_id.hir_id, + ident: keywords::Invalid.ident(), + attrs: Default::default(), + node: exist_ty_item_kind, + vis: respan(span.shrink_to_lo(), hir::VisibilityKind::Inherited), + span: exist_ty_span, + }; + + // Insert the item into the global item list. This usually happens + // automatically for all AST items. But this existential type item + // does not actually exist in the AST. + self.insert_item(exist_ty_item); + exist_ty_id + } + fn lifetimes_from_impl_trait_bounds( &mut self, exist_ty_id: NodeId, @@ -1569,9 +1649,6 @@ impl<'a> LoweringContext<'a> { name, })); - // We need to manually create the ids here, because the - // definitions will go into the explicit `existential type` - // declaration and thus need to have their owner set to that item let def_node_id = self.context.sess.next_node_id(); let LoweredNodeId { node_id: _, hir_id } = self.context.lower_node_id_with_owner(def_node_id, self.exist_ty_id); @@ -2108,23 +2185,42 @@ impl<'a> LoweringContext<'a> { impl_trait_return_allow: bool, make_ret_async: Option<NodeId>, ) -> P<hir::FnDecl> { - let inputs = decl.inputs - .iter() - .map(|arg| { - if let Some((_, ref mut ibty)) = in_band_ty_params { - self.lower_ty_direct(&arg.ty, ImplTraitContext::Universal(ibty)) - } else { - self.lower_ty_direct(&arg.ty, ImplTraitContext::disallowed()) - } - }) - .collect::<HirVec<_>>(); + let lt_mode = if make_ret_async.is_some() { + // In `async fn`, argument-position elided lifetimes + // must be transformed into fresh generic parameters so that + // they can be applied to the existential return type. + AnonymousLifetimeMode::CreateParameter + } else { + self.anonymous_lifetime_mode + }; + + // Remember how many lifetimes were already around so that we can + // only look at the lifetime parameters introduced by the arguments. + let lifetime_count_before_args = self.lifetimes_to_define.len(); + let inputs = self.with_anonymous_lifetime_mode(lt_mode, |this| { + decl.inputs + .iter() + .map(|arg| { + if let Some((_, ibty)) = &mut in_band_ty_params { + this.lower_ty_direct(&arg.ty, ImplTraitContext::Universal(ibty)) + } else { + this.lower_ty_direct(&arg.ty, ImplTraitContext::disallowed()) + } + }) + .collect::<HirVec<_>>() + }); let output = if let Some(ret_id) = make_ret_async { + // Calculate the `LtReplacement` to use for any return-position elided + // lifetimes based on the elided lifetime parameters introduced in the args. + let lt_replacement = get_elided_lt_replacement( + &self.lifetimes_to_define[lifetime_count_before_args..] + ); self.lower_async_fn_ret_ty( - &inputs, &decl.output, in_band_ty_params.expect("make_ret_async but no fn_def_id").0, ret_id, + lt_replacement, ) } else { match decl.output { @@ -2173,233 +2269,171 @@ impl<'a> LoweringContext<'a> { }) } - // Transform `-> T` into `-> impl Future<Output = T>` for `async fn` + // Transform `-> T` for `async fn` into -> ExistTy { .. } + // combined with the following definition of `ExistTy`: + // + // existential type ExistTy<generics_from_parent_fn>: Future<Output = T>; // - // fn_span: the span of the async function declaration. Used for error reporting. // inputs: lowered types of arguments to the function. Used to collect lifetimes. // output: unlowered output type (`T` in `-> T`) // fn_def_id: DefId of the parent function. Used to create child impl trait definition. + // exist_ty_node_id: NodeId of the existential type that should be created. + // elided_lt_replacement: replacement for elided lifetimes in the return type fn lower_async_fn_ret_ty( &mut self, - inputs: &[hir::Ty], output: &FunctionRetTy, fn_def_id: DefId, - return_impl_trait_id: NodeId, + exist_ty_node_id: NodeId, + elided_lt_replacement: LtReplacement, ) -> hir::FunctionRetTy { - // Get lifetimes used in the input arguments to the function. Our output type must also - // have the same lifetime. - // FIXME(cramertj): multiple different lifetimes are not allowed because - // `impl Trait + 'a + 'b` doesn't allow for capture `'a` and `'b` where neither is a subset - // of the other. We really want some new lifetime that is a subset of all input lifetimes, - // but that doesn't exist at the moment. - - struct AsyncFnLifetimeCollector<'r, 'a: 'r> { - context: &'r mut LoweringContext<'a>, - // Lifetimes bound by HRTB. - currently_bound_lifetimes: Vec<hir::LifetimeName>, - // Whether to count elided lifetimes. - // Disabled inside of `Fn` or `fn` syntax. - collect_elided_lifetimes: bool, - // The lifetime found. - // Multiple different or elided lifetimes cannot appear in async fn for now. - output_lifetime: Option<(hir::LifetimeName, Span)>, - } - - impl<'r, 'a: 'r, 'v> hir::intravisit::Visitor<'v> for AsyncFnLifetimeCollector<'r, 'a> { - fn nested_visit_map<'this>( - &'this mut self, - ) -> hir::intravisit::NestedVisitorMap<'this, 'v> { - hir::intravisit::NestedVisitorMap::None - } + let span = output.span(); - fn visit_generic_args(&mut self, span: Span, parameters: &'v hir::GenericArgs) { - // Don't collect elided lifetimes used inside of `Fn()` syntax. - if parameters.parenthesized { - let old_collect_elided_lifetimes = self.collect_elided_lifetimes; - self.collect_elided_lifetimes = false; - hir::intravisit::walk_generic_args(self, span, parameters); - self.collect_elided_lifetimes = old_collect_elided_lifetimes; - } else { - hir::intravisit::walk_generic_args(self, span, parameters); - } - } - - fn visit_ty(&mut self, t: &'v hir::Ty) { - // Don't collect elided lifetimes used inside of `fn()` syntax. - if let &hir::TyKind::BareFn(_) = &t.node { - let old_collect_elided_lifetimes = self.collect_elided_lifetimes; - self.collect_elided_lifetimes = false; - - // Record the "stack height" of `for<'a>` lifetime bindings - // to be able to later fully undo their introduction. - let old_len = self.currently_bound_lifetimes.len(); - hir::intravisit::walk_ty(self, t); - self.currently_bound_lifetimes.truncate(old_len); - - self.collect_elided_lifetimes = old_collect_elided_lifetimes; - } else { - hir::intravisit::walk_ty(self, t); - } - } + let exist_ty_span = self.mark_span_with_reason( + CompilerDesugaringKind::Async, + span, + None, + ); - fn visit_poly_trait_ref( - &mut self, - trait_ref: &'v hir::PolyTraitRef, - modifier: hir::TraitBoundModifier, - ) { - // Record the "stack height" of `for<'a>` lifetime bindings - // to be able to later fully undo their introduction. - let old_len = self.currently_bound_lifetimes.len(); - hir::intravisit::walk_poly_trait_ref(self, trait_ref, modifier); - self.currently_bound_lifetimes.truncate(old_len); - } + let exist_ty_def_index = self + .resolver + .definitions() + .opt_def_index(exist_ty_node_id) + .unwrap(); - fn visit_generic_param(&mut self, param: &'v hir::GenericParam) { - // Record the introduction of 'a in `for<'a> ...` - if let hir::GenericParamKind::Lifetime { .. } = param.kind { - // Introduce lifetimes one at a time so that we can handle - // cases like `fn foo<'d>() -> impl for<'a, 'b: 'a, 'c: 'b + 'd>` - let lt_name = hir::LifetimeName::Param(param.name); - self.currently_bound_lifetimes.push(lt_name); - } + self.allocate_hir_id_counter(exist_ty_node_id); - hir::intravisit::walk_generic_param(self, param); - } + let (exist_ty_node_id, lifetime_params) = self.with_hir_id_owner(exist_ty_node_id, |this| { + let future_bound = this.with_anonymous_lifetime_mode( + AnonymousLifetimeMode::Replace(elided_lt_replacement), + |this| this.lower_async_fn_output_type_to_future_bound( + output, + fn_def_id, + span, + ), + ); - fn visit_lifetime(&mut self, lifetime: &'v hir::Lifetime) { - let name = match lifetime.name { - hir::LifetimeName::Implicit | hir::LifetimeName::Underscore => { - if self.collect_elided_lifetimes { - // Use `'_` for both implicit and underscore lifetimes in - // `abstract type Foo<'_>: SomeTrait<'_>;` - hir::LifetimeName::Underscore - } else { - return; - } - } - hir::LifetimeName::Param(_) => lifetime.name, - hir::LifetimeName::Error | hir::LifetimeName::Static => return, - }; + // Calculate all the lifetimes that should be captured + // by the existential type. This should include all in-scope + // lifetime parameters, including those defined in-band. + // + // Note: this must be done after lowering the output type, + // as the output type may introduce new in-band lifetimes. + let lifetime_params: Vec<(Span, ParamName)> = + this.in_scope_lifetimes + .iter().cloned() + .map(|ident| (ident.span, ParamName::Plain(ident))) + .chain(this.lifetimes_to_define.iter().cloned()) + .collect(); - if !self.currently_bound_lifetimes.contains(&name) { - if let Some((current_lt_name, current_lt_span)) = self.output_lifetime { - // We don't currently have a reliable way to desugar `async fn` with - // multiple potentially unrelated input lifetimes into - // `-> impl Trait + 'lt`, so we report an error in this case. - if current_lt_name != name { - struct_span_err!( - self.context.sess, - MultiSpan::from_spans(vec![current_lt_span, lifetime.span]), - E0709, - "multiple different lifetimes used in arguments of `async fn`", - ) - .span_label(current_lt_span, "first lifetime here") - .span_label(lifetime.span, "different lifetime here") - .help("`async fn` can only accept borrowed values \ - with identical lifetimes") - .emit() - } else if current_lt_name.is_elided() && name.is_elided() { - struct_span_err!( - self.context.sess, - MultiSpan::from_spans(vec![current_lt_span, lifetime.span]), - E0707, - "multiple elided lifetimes used in arguments of `async fn`", - ) - .span_label(current_lt_span, "first lifetime here") - .span_label(lifetime.span, "different lifetime here") - .help("consider giving these arguments named lifetimes") - .emit() - } - } else { - self.output_lifetime = Some((name, lifetime.span)); - } - } - } - } + let generic_params = + lifetime_params + .iter().cloned() + .map(|(span, hir_name)| { + this.lifetime_to_generic_param(span, hir_name, exist_ty_def_index) + }) + .collect(); - let bound_lifetime = { - let mut lifetime_collector = AsyncFnLifetimeCollector { - context: self, - currently_bound_lifetimes: Vec::new(), - collect_elided_lifetimes: true, - output_lifetime: None, + let LoweredNodeId { node_id: _, hir_id } = this.next_id(); + let exist_ty_item = hir::ExistTy { + generics: hir::Generics { + params: generic_params, + where_clause: hir::WhereClause { + hir_id, + predicates: hir_vec![], + }, + span, + }, + bounds: hir_vec![future_bound], + impl_trait_fn: Some(fn_def_id), + origin: hir::ExistTyOrigin::AsyncFn, }; - for arg in inputs { - hir::intravisit::walk_ty(&mut lifetime_collector, arg); - } - lifetime_collector.output_lifetime - }; + trace!("exist ty from async fn def index: {:#?}", exist_ty_def_index); + let exist_ty_id = this.generate_existential_type( + exist_ty_node_id, + exist_ty_item, + span, + exist_ty_span, + ); - let span = match output { - FunctionRetTy::Ty(ty) => ty.span, - FunctionRetTy::Default(span) => *span, - }; + (exist_ty_id.node_id, lifetime_params) + }); - let impl_trait_ty = self.lower_existential_impl_trait( - span, Some(fn_def_id), return_impl_trait_id, |this| { - let output_ty = match output { - FunctionRetTy::Ty(ty) => { - this.lower_ty(ty, ImplTraitContext::Existential(Some(fn_def_id))) - } - FunctionRetTy::Default(span) => { - let LoweredNodeId { node_id: _, hir_id } = this.next_id(); - P(hir::Ty { + let generic_args = + lifetime_params + .iter().cloned() + .map(|(span, hir_name)| { + let LoweredNodeId { node_id: _, hir_id } = self.next_id(); + GenericArg::Lifetime(hir::Lifetime { hir_id, - node: hir::TyKind::Tup(hir_vec![]), - span: *span, + span, + name: hir::LifetimeName::Param(hir_name), }) - } - }; - - // "<Output = T>" - let LoweredNodeId { node_id: _, hir_id } = this.next_id(); - let future_params = P(hir::GenericArgs { - args: hir_vec![], - bindings: hir_vec![hir::TypeBinding { - ident: Ident::from_str(FN_OUTPUT_NAME), - ty: output_ty, - hir_id, - span, - }], - parenthesized: false, - }); + }) + .collect(); - let future_path = - this.std_path(span, &["future", "Future"], Some(future_params), false); + let exist_ty_hir_id = self.lower_node_id(exist_ty_node_id).hir_id; + let exist_ty_ref = hir::TyKind::Def(hir::ItemId { id: exist_ty_hir_id }, generic_args); - let LoweredNodeId { node_id: _, hir_id } = this.next_id(); - let mut bounds = vec![ - hir::GenericBound::Trait( - hir::PolyTraitRef { - trait_ref: hir::TraitRef { - path: future_path, - hir_ref_id: hir_id, - }, - bound_generic_params: hir_vec![], - span, - }, - hir::TraitBoundModifier::None - ), - ]; + let LoweredNodeId { node_id: _, hir_id } = self.next_id(); + hir::FunctionRetTy::Return(P(hir::Ty { + node: exist_ty_ref, + span, + hir_id, + })) + } - if let Some((name, span)) = bound_lifetime { - let LoweredNodeId { node_id: _, hir_id } = this.next_id(); - bounds.push(hir::GenericBound::Outlives( - hir::Lifetime { hir_id, name, span })); + /// Turns `-> T` into `Future<Output = T>` + fn lower_async_fn_output_type_to_future_bound( + &mut self, + output: &FunctionRetTy, + fn_def_id: DefId, + span: Span, + ) -> hir::GenericBound { + // Compute the `T` in `Future<Output = T>` from the return type. + let output_ty = match output { + FunctionRetTy::Ty(ty) => { + self.lower_ty(ty, ImplTraitContext::Existential(Some(fn_def_id))) } + FunctionRetTy::Default(ret_ty_span) => { + let LoweredNodeId { node_id: _, hir_id } = self.next_id(); + P(hir::Ty { + hir_id, + node: hir::TyKind::Tup(hir_vec![]), + span: *ret_ty_span, + }) + } + }; - hir::HirVec::from(bounds) - }); - + // "<Output = T>" let LoweredNodeId { node_id: _, hir_id } = self.next_id(); - let impl_trait_ty = P(hir::Ty { - node: impl_trait_ty, - span, - hir_id, + let future_params = P(hir::GenericArgs { + args: hir_vec![], + bindings: hir_vec![hir::TypeBinding { + ident: Ident::from_str(FN_OUTPUT_NAME), + ty: output_ty, + hir_id, + span, + }], + parenthesized: false, }); - hir::FunctionRetTy::Return(impl_trait_ty) + // ::std::future::Future<future_params> + let future_path = + self.std_path(span, &["future", "Future"], Some(future_params), false); + + let LoweredNodeId { node_id: _, hir_id } = self.next_id(); + hir::GenericBound::Trait( + hir::PolyTraitRef { + trait_ref: hir::TraitRef { + path: future_path, + hir_ref_id: hir_id, + }, + bound_generic_params: hir_vec![], + span, + }, + hir::TraitBoundModifier::None, + ) } fn lower_param_bound( @@ -2437,6 +2471,11 @@ impl<'a> LoweringContext<'a> { } AnonymousLifetimeMode::ReportError => self.new_error_lifetime(Some(l.id), span), + + AnonymousLifetimeMode::Replace(replacement) => { + let LoweredNodeId { node_id: _, hir_id } = self.lower_node_id(l.id); + self.replace_elided_lifetime(hir_id, span, replacement) + } }, ident => { self.maybe_collect_in_band_lifetime(ident); @@ -2461,6 +2500,39 @@ impl<'a> LoweringContext<'a> { } } + /// Replace a return-position elided lifetime with the elided lifetime + /// from the arguments. + fn replace_elided_lifetime( + &mut self, + hir_id: hir::HirId, + span: Span, + replacement: LtReplacement, + ) -> hir::Lifetime { + let multiple_or_none = match replacement { + LtReplacement::Some(name) => { + return hir::Lifetime { + hir_id, + span, + name: hir::LifetimeName::Param(name), + }; + } + LtReplacement::MultipleLifetimes => "multiple", + LtReplacement::NoLifetimes => "none", + }; + + let mut err = crate::middle::resolve_lifetime::report_missing_lifetime_specifiers( + self.sess, + span, + 1, + ); + err.note(&format!( + "return-position elided lifetimes require exactly one \ + input-position elided lifetime, found {}.", multiple_or_none)); + err.emit(); + + hir::Lifetime { hir_id, span, name: hir::LifetimeName::Error } + } + fn lower_generic_params( &mut self, params: &[GenericParam], @@ -2941,6 +3013,7 @@ impl<'a> LoweringContext<'a> { generics: self.lower_generics(generics, ImplTraitContext::disallowed()), bounds: self.lower_param_bounds(b, ImplTraitContext::disallowed()), impl_trait_fn: None, + origin: hir::ExistTyOrigin::ExistentialType, }), ItemKind::Enum(ref enum_definition, ref generics) => hir::ItemKind::Enum( hir::EnumDef { @@ -5083,7 +5156,8 @@ impl<'a> LoweringContext<'a> { /// with no explicit lifetime. fn elided_ref_lifetime(&mut self, span: Span) -> hir::Lifetime { match self.anonymous_lifetime_mode { - // Intercept when we are in an impl header and introduce an in-band lifetime. + // Intercept when we are in an impl header or async fn and introduce an in-band + // lifetime. // Hence `impl Foo for &u32` becomes `impl<'f> Foo for &'f u32` for some fresh // `'f`. AnonymousLifetimeMode::CreateParameter => { @@ -5099,6 +5173,10 @@ impl<'a> LoweringContext<'a> { AnonymousLifetimeMode::ReportError => self.new_error_lifetime(None, span), AnonymousLifetimeMode::PassThrough => self.new_implicit_lifetime(span), + + AnonymousLifetimeMode::Replace(replacement) => { + self.new_replacement_lifetime(replacement, span) + } } } @@ -5133,6 +5211,12 @@ impl<'a> LoweringContext<'a> { /// sorts of cases are deprecated. This may therefore report a warning or an /// error, depending on the mode. fn elided_path_lifetimes(&mut self, span: Span, count: usize) -> P<[hir::Lifetime]> { + (0..count) + .map(|_| self.elided_path_lifetime(span)) + .collect() + } + + fn elided_path_lifetime(&mut self, span: Span) -> hir::Lifetime { match self.anonymous_lifetime_mode { // N.B., We intentionally ignore the create-parameter mode here // and instead "pass through" to resolve-lifetimes, which will then @@ -5140,21 +5224,16 @@ impl<'a> LoweringContext<'a> { // impl elision for deprecated forms like // // impl Foo for std::cell::Ref<u32> // note lack of '_ - AnonymousLifetimeMode::CreateParameter => {} + AnonymousLifetimeMode::CreateParameter | + // This is the normal case. + AnonymousLifetimeMode::PassThrough => self.new_implicit_lifetime(span), - AnonymousLifetimeMode::ReportError => { - return (0..count) - .map(|_| self.new_error_lifetime(None, span)) - .collect(); + AnonymousLifetimeMode::Replace(replacement) => { + self.new_replacement_lifetime(replacement, span) } - // This is the normal case. - AnonymousLifetimeMode::PassThrough => {} + AnonymousLifetimeMode::ReportError => self.new_error_lifetime(None, span), } - - (0..count) - .map(|_| self.new_implicit_lifetime(span)) - .collect() } /// Invoked to create the lifetime argument(s) for an elided trait object @@ -5184,11 +5263,25 @@ impl<'a> LoweringContext<'a> { // This is the normal case. AnonymousLifetimeMode::PassThrough => {} + + // We don't need to do any replacement here as this lifetime + // doesn't refer to an elided lifetime elsewhere in the function + // signature. + AnonymousLifetimeMode::Replace(_) => {} } self.new_implicit_lifetime(span) } + fn new_replacement_lifetime( + &mut self, + replacement: LtReplacement, + span: Span, + ) -> hir::Lifetime { + let LoweredNodeId { node_id: _, hir_id } = self.next_id(); + self.replace_elided_lifetime(hir_id, span, replacement) + } + fn new_implicit_lifetime(&mut self, span: Span) -> hir::Lifetime { let LoweredNodeId { node_id: _, hir_id } = self.next_id(); diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 8509ddaccf7..58a27d3f78e 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1799,6 +1799,18 @@ pub struct ExistTy { pub generics: Generics, pub bounds: GenericBounds, pub impl_trait_fn: Option<DefId>, + pub origin: ExistTyOrigin, +} + +/// Where the existential type came from +#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, HashStable)] +pub enum ExistTyOrigin { + /// `existential type Foo: Trait;` + ExistentialType, + /// `-> impl Trait` + ReturnImplTrait, + /// `async fn` + AsyncFn, } /// The various kinds of types recognized by the compiler. diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 0a65473de8f..d1020a2d151 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -622,7 +622,7 @@ impl<'a> State<'a> { } hir::ItemKind::GlobalAsm(ref ga) => { self.head(visibility_qualified(&item.vis, "global asm"))?; - self.s.word(ga.asm.as_str().get())?; + self.s.word(ga.asm.as_str().to_string())?; self.end()? } hir::ItemKind::Ty(ref ty, ref generics) => { @@ -1591,7 +1591,7 @@ impl<'a> State<'a> { if ident.is_raw_guess() { self.s.word(format!("r#{}", ident.name))?; } else { - self.s.word(ident.as_str().get())?; + self.s.word(ident.as_str().to_string())?; } self.ann.post(self, AnnNode::Name(&ident.name)) } @@ -1998,7 +1998,7 @@ impl<'a> State<'a> { self.commasep(Inconsistent, &decl.inputs, |s, ty| { s.ibox(indent_unit)?; if let Some(arg_name) = arg_names.get(i) { - s.s.word(arg_name.as_str().get())?; + s.s.word(arg_name.as_str().to_string())?; s.s.word(":")?; s.s.space()?; } else if let Some(body_id) = body_id { diff --git a/src/librustc/ich/hcx.rs b/src/librustc/ich/hcx.rs index e60fdd62deb..a8e5db26ead 100644 --- a/src/librustc/ich/hcx.rs +++ b/src/librustc/ich/hcx.rs @@ -9,7 +9,6 @@ use crate::session::Session; use std::cmp::Ord; use std::hash as std_hash; -use std::collections::HashMap; use std::cell::RefCell; use syntax::ast; @@ -394,13 +393,12 @@ impl<'a> HashStable<StableHashingContext<'a>> for DelimSpan { } } -pub fn hash_stable_trait_impls<'a, 'gcx, W, R>( +pub fn hash_stable_trait_impls<'a, 'gcx, W>( hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher<W>, blanket_impls: &[DefId], - non_blanket_impls: &HashMap<fast_reject::SimplifiedType, Vec<DefId>, R>) - where W: StableHasherResult, - R: std_hash::BuildHasher, + non_blanket_impls: &FxHashMap<fast_reject::SimplifiedType, Vec<DefId>>) + where W: StableHasherResult { { let mut blanket_impls: SmallVec<[_; 8]> = blanket_impls diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 2810b5a8e6a..6b2b0c24c77 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -56,7 +56,7 @@ use crate::hir::Node; use crate::middle::region; use crate::traits::{ObligationCause, ObligationCauseCode}; use crate::ty::error::TypeError; -use crate::ty::{self, subst::{Subst, SubstsRef}, Region, Ty, TyCtxt, TyKind, TypeFoldable}; +use crate::ty::{self, subst::{Subst, SubstsRef}, Region, Ty, TyCtxt, TypeFoldable}; use errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString}; use std::{cmp, fmt}; use syntax_pos::{Pos, Span}; @@ -278,7 +278,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } fn explain_span(self, heading: &str, span: Span) -> (String, Option<Span>) { - let lo = self.sess.source_map().lookup_char_pos_adj(span.lo()); + let lo = self.sess.source_map().lookup_char_pos(span.lo()); ( format!("the {} at {}:{}", heading, lo.line, lo.col.to_usize() + 1), Some(span), @@ -604,13 +604,39 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { source, ref prior_arms, last_ty, + discrim_hir_id, .. } => match source { hir::MatchSource::IfLetDesugar { .. } => { let msg = "`if let` arms have incompatible types"; err.span_label(cause.span, msg); } - hir::MatchSource::TryDesugar => {} + hir::MatchSource::TryDesugar => { + if let Some(ty::error::ExpectedFound { expected, .. }) = exp_found { + let discrim_expr = self.tcx.hir().expect_expr_by_hir_id(discrim_hir_id); + let discrim_ty = if let hir::ExprKind::Call(_, args) = &discrim_expr.node { + let arg_expr = args.first().expect("try desugaring call w/out arg"); + self.in_progress_tables.and_then(|tables| { + tables.borrow().expr_ty_opt(arg_expr) + }) + } else { + bug!("try desugaring w/out call expr as discriminant"); + }; + + match discrim_ty { + Some(ty) if expected == ty => { + let source_map = self.tcx.sess.source_map(); + err.span_suggestion( + source_map.end_point(cause.span), + "try removing this `?`", + "".to_string(), + Applicability::MachineApplicable, + ); + }, + _ => {}, + } + } + } _ => { let msg = "`match` arms have incompatible types"; err.span_label(cause.span, msg); @@ -1094,14 +1120,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { (_, false, _) => { if let Some(exp_found) = exp_found { let (def_id, ret_ty) = match exp_found.found.sty { - TyKind::FnDef(def, _) => { + ty::FnDef(def, _) => { (Some(def), Some(self.tcx.fn_sig(def).output())) } _ => (None, None), }; let exp_is_struct = match exp_found.expected.sty { - TyKind::Adt(def, _) => def.is_struct(), + ty::Adt(def, _) => def.is_struct(), _ => false, }; @@ -1140,8 +1166,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { diag: &mut DiagnosticBuilder<'tcx>, ) { match (&exp_found.expected.sty, &exp_found.found.sty) { - (TyKind::Adt(exp_def, exp_substs), TyKind::Ref(_, found_ty, _)) => { - if let TyKind::Adt(found_def, found_substs) = found_ty.sty { + (ty::Adt(exp_def, exp_substs), ty::Ref(_, found_ty, _)) => { + if let ty::Adt(found_def, found_substs) = found_ty.sty { let path_str = format!("{:?}", exp_def); if exp_def == &found_def { let opt_msg = "you can convert from `&Option<T>` to `Option<&T>` using \ @@ -1164,17 +1190,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let mut show_suggestion = true; for (exp_ty, found_ty) in exp_substs.types().zip(found_substs.types()) { match exp_ty.sty { - TyKind::Ref(_, exp_ty, _) => { + ty::Ref(_, exp_ty, _) => { match (&exp_ty.sty, &found_ty.sty) { - (_, TyKind::Param(_)) | - (_, TyKind::Infer(_)) | - (TyKind::Param(_), _) | - (TyKind::Infer(_), _) => {} + (_, ty::Param(_)) | + (_, ty::Infer(_)) | + (ty::Param(_), _) | + (ty::Infer(_), _) => {} _ if ty::TyS::same_type(exp_ty, found_ty) => {} _ => show_suggestion = false, }; } - TyKind::Param(_) | TyKind::Infer(_) => {} + ty::Param(_) | ty::Infer(_) => {} _ => show_suggestion = false, } } diff --git a/src/librustc/infer/opaque_types/mod.rs b/src/librustc/infer/opaque_types/mod.rs index 8bd20843163..be9460ad86f 100644 --- a/src/librustc/infer/opaque_types/mod.rs +++ b/src/librustc/infer/opaque_types/mod.rs @@ -67,6 +67,9 @@ pub struct OpaqueTypeDecl<'tcx> { /// the fn body). (Ultimately, writeback is responsible for this /// check.) pub has_required_region_bounds: bool, + + /// The origin of the existential type + pub origin: hir::ExistTyOrigin, } impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { @@ -326,14 +329,39 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // There are two regions (`lr` and // `subst_arg`) which are not relatable. We can't // find a best choice. - self.tcx + let context_name = match opaque_defn.origin { + hir::ExistTyOrigin::ExistentialType => "existential type", + hir::ExistTyOrigin::ReturnImplTrait => "impl Trait", + hir::ExistTyOrigin::AsyncFn => "async fn", + }; + let msg = format!("ambiguous lifetime bound in `{}`", context_name); + let mut err = self.tcx .sess - .struct_span_err(span, "ambiguous lifetime bound in `impl Trait`") - .span_label( - span, - format!("neither `{}` nor `{}` outlives the other", lr, subst_arg), - ) - .emit(); + .struct_span_err(span, &msg); + + let lr_name = lr.to_string(); + let subst_arg_name = subst_arg.to_string(); + let label_owned; + let label = match (&*lr_name, &*subst_arg_name) { + ("'_", "'_") => "the elided lifetimes here do not outlive one another", + _ => { + label_owned = format!( + "neither `{}` nor `{}` outlives the other", + lr_name, + subst_arg_name, + ); + &label_owned + } + }; + err.span_label(span, label); + + if let hir::ExistTyOrigin::AsyncFn = opaque_defn.origin { + err.note("multiple unrelated lifetimes are not allowed in \ + `async fn`."); + err.note("if you're using argument-position elided lifetimes, consider \ + switching to a single named lifetime."); + } + err.emit(); least_region = Some(self.tcx.mk_region(ty::ReEmpty)); break; @@ -692,31 +720,41 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> { parent_def_id == tcx.hir() .local_def_id_from_hir_id(opaque_parent_hir_id) }; - let in_definition_scope = match tcx.hir().find_by_hir_id(opaque_hir_id) { + let (in_definition_scope, origin) = + match tcx.hir().find_by_hir_id(opaque_hir_id) + { Some(Node::Item(item)) => match item.node { // impl trait hir::ItemKind::Existential(hir::ExistTy { impl_trait_fn: Some(parent), + origin, .. - }) => parent == self.parent_def_id, + }) => (parent == self.parent_def_id, origin), // named existential types hir::ItemKind::Existential(hir::ExistTy { impl_trait_fn: None, + origin, .. - }) => may_define_existential_type( - tcx, - self.parent_def_id, - opaque_hir_id, + }) => ( + may_define_existential_type( + tcx, + self.parent_def_id, + opaque_hir_id, + ), + origin, ), - _ => def_scope_default(), + _ => (def_scope_default(), hir::ExistTyOrigin::ExistentialType), }, Some(Node::ImplItem(item)) => match item.node { - hir::ImplItemKind::Existential(_) => may_define_existential_type( - tcx, - self.parent_def_id, - opaque_hir_id, + hir::ImplItemKind::Existential(_) => ( + may_define_existential_type( + tcx, + self.parent_def_id, + opaque_hir_id, + ), + hir::ExistTyOrigin::ExistentialType, ), - _ => def_scope_default(), + _ => (def_scope_default(), hir::ExistTyOrigin::ExistentialType), }, _ => bug!( "expected (impl) item, found {}", @@ -724,7 +762,7 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> { ), }; if in_definition_scope { - return self.fold_opaque_ty(ty, def_id, substs); + return self.fold_opaque_ty(ty, def_id, substs, origin); } debug!( @@ -746,6 +784,7 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> { ty: Ty<'tcx>, def_id: DefId, substs: SubstsRef<'tcx>, + origin: hir::ExistTyOrigin, ) -> Ty<'tcx> { let infcx = self.infcx; let tcx = infcx.tcx; @@ -795,6 +834,7 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> { substs, concrete_ty: ty_var, has_required_region_bounds: !required_region_bounds.is_empty(), + origin, }, ); debug!("instantiate_opaque_types: ty_var={:?}", ty_var); diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index b87343b43c9..c5c2cbfcb89 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -29,6 +29,7 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] #![deny(rust_2018_idioms)] +#![cfg_attr(not(stage0), deny(internal))] #![allow(explicit_outlives_requirements)] #![feature(arbitrary_self_types)] @@ -39,6 +40,7 @@ #![cfg_attr(windows, feature(libc))] #![feature(never_type)] #![feature(exhaustive_patterns)] +#![feature(overlapping_marker_traits)] #![feature(extern_types)] #![feature(nll)] #![feature(non_exhaustive)] @@ -102,6 +104,8 @@ pub mod diagnostics; #[macro_use] pub mod query; +#[macro_use] +pub mod arena; pub mod cfg; pub mod dep_graph; pub mod hir; diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 2d8a2c6321f..28a2a1eaf6b 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -352,12 +352,6 @@ declare_lint! { "outlives requirements can be inferred" } -declare_lint! { - pub DUPLICATE_MATCHER_BINDING_NAME, - Deny, - "duplicate macro matcher binding name" -} - /// Some lints that are buffered from `libsyntax`. See `syntax::early_buffered_lints`. pub mod parser { declare_lint! { @@ -392,81 +386,78 @@ declare_lint! { "nested occurrence of `impl Trait` type" } -/// Does nothing as a lint pass, but registers some `Lint`s -/// that are used by other parts of the compiler. -#[derive(Copy, Clone)] -pub struct HardwiredLints; - -impl LintPass for HardwiredLints { - fn name(&self) -> &'static str { - "HardwiredLints" - } - - fn get_lints(&self) -> LintArray { - lint_array!( - ILLEGAL_FLOATING_POINT_LITERAL_PATTERN, - EXCEEDING_BITSHIFTS, - UNUSED_IMPORTS, - UNUSED_EXTERN_CRATES, - UNUSED_QUALIFICATIONS, - UNKNOWN_LINTS, - UNUSED_VARIABLES, - UNUSED_ASSIGNMENTS, - DEAD_CODE, - UNREACHABLE_CODE, - UNREACHABLE_PATTERNS, - UNUSED_MACROS, - WARNINGS, - UNUSED_FEATURES, - STABLE_FEATURES, - UNKNOWN_CRATE_TYPES, - TRIVIAL_CASTS, - TRIVIAL_NUMERIC_CASTS, - PRIVATE_IN_PUBLIC, - EXPORTED_PRIVATE_DEPENDENCIES, - PUB_USE_OF_PRIVATE_EXTERN_CRATE, - INVALID_TYPE_PARAM_DEFAULT, - CONST_ERR, - RENAMED_AND_REMOVED_LINTS, - SAFE_EXTERN_STATICS, - SAFE_PACKED_BORROWS, - PATTERNS_IN_FNS_WITHOUT_BODY, - LEGACY_DIRECTORY_OWNERSHIP, - LEGACY_CONSTRUCTOR_VISIBILITY, - MISSING_FRAGMENT_SPECIFIER, - PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES, - LATE_BOUND_LIFETIME_ARGUMENTS, - INCOHERENT_FUNDAMENTAL_IMPLS, - ORDER_DEPENDENT_TRAIT_OBJECTS, - DEPRECATED, - UNUSED_UNSAFE, - UNUSED_MUT, - UNCONDITIONAL_RECURSION, - SINGLE_USE_LIFETIMES, - UNUSED_LIFETIMES, - UNUSED_LABELS, - TYVAR_BEHIND_RAW_POINTER, - ELIDED_LIFETIMES_IN_PATHS, - BARE_TRAIT_OBJECTS, - ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, - UNSTABLE_NAME_COLLISIONS, - IRREFUTABLE_LET_PATTERNS, - DUPLICATE_MACRO_EXPORTS, - INTRA_DOC_LINK_RESOLUTION_FAILURE, - MISSING_DOC_CODE_EXAMPLES, - PRIVATE_DOC_TESTS, - WHERE_CLAUSES_OBJECT_SAFETY, - PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, - MACRO_USE_EXTERN_CRATE, - MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS, - parser::QUESTION_MARK_MACRO_SEP, - parser::ILL_FORMED_ATTRIBUTE_INPUT, - DEPRECATED_IN_FUTURE, - AMBIGUOUS_ASSOCIATED_ITEMS, - NESTED_IMPL_TRAIT, - DUPLICATE_MATCHER_BINDING_NAME, - ) - } +declare_lint! { + pub MUTABLE_BORROW_RESERVATION_CONFLICT, + Warn, + "reservation of a two-phased borrow conflicts with other shared borrows" +} + +declare_lint_pass! { + /// Does nothing as a lint pass, but registers some `Lint`s + /// that are used by other parts of the compiler. + HardwiredLints => [ + ILLEGAL_FLOATING_POINT_LITERAL_PATTERN, + EXCEEDING_BITSHIFTS, + UNUSED_IMPORTS, + UNUSED_EXTERN_CRATES, + UNUSED_QUALIFICATIONS, + UNKNOWN_LINTS, + UNUSED_VARIABLES, + UNUSED_ASSIGNMENTS, + DEAD_CODE, + UNREACHABLE_CODE, + UNREACHABLE_PATTERNS, + UNUSED_MACROS, + WARNINGS, + UNUSED_FEATURES, + STABLE_FEATURES, + UNKNOWN_CRATE_TYPES, + TRIVIAL_CASTS, + TRIVIAL_NUMERIC_CASTS, + PRIVATE_IN_PUBLIC, + EXPORTED_PRIVATE_DEPENDENCIES, + PUB_USE_OF_PRIVATE_EXTERN_CRATE, + INVALID_TYPE_PARAM_DEFAULT, + CONST_ERR, + RENAMED_AND_REMOVED_LINTS, + SAFE_EXTERN_STATICS, + SAFE_PACKED_BORROWS, + PATTERNS_IN_FNS_WITHOUT_BODY, + LEGACY_DIRECTORY_OWNERSHIP, + LEGACY_CONSTRUCTOR_VISIBILITY, + MISSING_FRAGMENT_SPECIFIER, + PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES, + LATE_BOUND_LIFETIME_ARGUMENTS, + INCOHERENT_FUNDAMENTAL_IMPLS, + ORDER_DEPENDENT_TRAIT_OBJECTS, + DEPRECATED, + UNUSED_UNSAFE, + UNUSED_MUT, + UNCONDITIONAL_RECURSION, + SINGLE_USE_LIFETIMES, + UNUSED_LIFETIMES, + UNUSED_LABELS, + TYVAR_BEHIND_RAW_POINTER, + ELIDED_LIFETIMES_IN_PATHS, + BARE_TRAIT_OBJECTS, + ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, + UNSTABLE_NAME_COLLISIONS, + IRREFUTABLE_LET_PATTERNS, + DUPLICATE_MACRO_EXPORTS, + INTRA_DOC_LINK_RESOLUTION_FAILURE, + MISSING_DOC_CODE_EXAMPLES, + PRIVATE_DOC_TESTS, + WHERE_CLAUSES_OBJECT_SAFETY, + PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, + MACRO_USE_EXTERN_CRATE, + MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS, + parser::QUESTION_MARK_MACRO_SEP, + parser::ILL_FORMED_ATTRIBUTE_INPUT, + DEPRECATED_IN_FUTURE, + AMBIGUOUS_ASSOCIATED_ITEMS, + NESTED_IMPL_TRAIT, + MUTABLE_BORROW_RESERVATION_CONFLICT, + ] } // this could be a closure, but then implementing derive traits diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index e5eafd768bb..15ea6403e38 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -25,7 +25,7 @@ use crate::lint::levels::{LintLevelSets, LintLevelsBuilder}; use crate::middle::privacy::AccessLevels; use crate::rustc_serialize::{Decoder, Decodable, Encoder, Encodable}; use crate::session::{config, early_error, Session}; -use crate::ty::{self, TyCtxt, Ty}; +use crate::ty::{self, print::Printer, subst::Kind, TyCtxt, Ty}; use crate::ty::layout::{LayoutError, LayoutOf, TyLayout}; use crate::util::nodemap::FxHashMap; use crate::util::common::time; @@ -36,9 +36,10 @@ use syntax::edition; use syntax_pos::{MultiSpan, Span, symbol::{LocalInternedString, Symbol}}; use errors::DiagnosticBuilder; use crate::hir; -use crate::hir::def_id::{DefId, LOCAL_CRATE}; +use crate::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use crate::hir::intravisit as hir_visit; use crate::hir::intravisit::Visitor; +use crate::hir::map::{definitions::DisambiguatedDefPathData, DefPathData}; use syntax::util::lev_distance::find_best_match_for_name; use syntax::visit as ast_visit; @@ -752,6 +753,114 @@ impl<'a, 'tcx> LateContext<'a, 'tcx> { pub fn current_lint_root(&self) -> hir::HirId { self.last_node_with_lint_attrs } + + /// Check if a `DefId`'s path matches the given absolute type path usage. + // Uplifted from rust-lang/rust-clippy + pub fn match_path(&self, def_id: DefId, path: &[&str]) -> bool { + pub struct AbsolutePathPrinter<'a, 'tcx> { + pub tcx: TyCtxt<'a, 'tcx, 'tcx>, + } + + impl<'tcx> Printer<'tcx, 'tcx> for AbsolutePathPrinter<'_, 'tcx> { + type Error = !; + + type Path = Vec<LocalInternedString>; + type Region = (); + type Type = (); + type DynExistential = (); + + fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx> { + self.tcx + } + + fn print_region(self, _region: ty::Region<'_>) -> Result<Self::Region, Self::Error> { + Ok(()) + } + + fn print_type(self, _ty: Ty<'tcx>) -> Result<Self::Type, Self::Error> { + Ok(()) + } + + fn print_dyn_existential( + self, + _predicates: &'tcx ty::List<ty::ExistentialPredicate<'tcx>>, + ) -> Result<Self::DynExistential, Self::Error> { + Ok(()) + } + + fn path_crate(self, cnum: CrateNum) -> Result<Self::Path, Self::Error> { + Ok(vec![self.tcx.original_crate_name(cnum).as_str()]) + } + + fn path_qualified( + self, + self_ty: Ty<'tcx>, + trait_ref: Option<ty::TraitRef<'tcx>>, + ) -> Result<Self::Path, Self::Error> { + if trait_ref.is_none() { + if let ty::Adt(def, substs) = self_ty.sty { + return self.print_def_path(def.did, substs); + } + } + + // This shouldn't ever be needed, but just in case: + Ok(vec![match trait_ref { + Some(trait_ref) => Symbol::intern(&format!("{:?}", trait_ref)).as_str(), + None => Symbol::intern(&format!("<{}>", self_ty)).as_str(), + }]) + } + + fn path_append_impl( + self, + print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, + _disambiguated_data: &DisambiguatedDefPathData, + self_ty: Ty<'tcx>, + trait_ref: Option<ty::TraitRef<'tcx>>, + ) -> Result<Self::Path, Self::Error> { + let mut path = print_prefix(self)?; + + // This shouldn't ever be needed, but just in case: + path.push(match trait_ref { + Some(trait_ref) => { + Symbol::intern(&format!("<impl {} for {}>", trait_ref, self_ty)).as_str() + }, + None => Symbol::intern(&format!("<impl {}>", self_ty)).as_str(), + }); + + Ok(path) + } + + fn path_append( + self, + print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, + disambiguated_data: &DisambiguatedDefPathData, + ) -> Result<Self::Path, Self::Error> { + let mut path = print_prefix(self)?; + + // Skip `::{{constructor}}` on tuple/unit structs. + match disambiguated_data.data { + DefPathData::Ctor => return Ok(path), + _ => {} + } + + path.push(disambiguated_data.data.as_interned_str().as_str()); + Ok(path) + } + + fn path_generic_args( + self, + print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, + _args: &[Kind<'tcx>], + ) -> Result<Self::Path, Self::Error> { + print_prefix(self) + } + } + + let names = AbsolutePathPrinter { tcx: self.tcx }.print_def_path(def_id, &[]).unwrap(); + + names.len() == path.len() + && names.into_iter().zip(path.iter()).all(|(a, &b)| *a == *b) + } } impl<'a, 'tcx> LayoutOf for LateContext<'a, 'tcx> { diff --git a/src/librustc/lint/internal.rs b/src/librustc/lint/internal.rs new file mode 100644 index 00000000000..0bafa93011e --- /dev/null +++ b/src/librustc/lint/internal.rs @@ -0,0 +1,109 @@ +//! Some lints that are only useful in the compiler or crates that use compiler internals, such as +//! Clippy. + +use crate::hir::{HirId, Path, PathSegment, QPath, Ty, TyKind}; +use crate::lint::{ + EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintArray, LintContext, LintPass, +}; +use errors::Applicability; +use rustc_data_structures::fx::FxHashMap; +use syntax::ast::Ident; + +declare_lint! { + pub DEFAULT_HASH_TYPES, + Allow, + "forbid HashMap and HashSet and suggest the FxHash* variants" +} + +pub struct DefaultHashTypes { + map: FxHashMap<String, String>, +} + +impl DefaultHashTypes { + pub fn new() -> Self { + let mut map = FxHashMap::default(); + map.insert("HashMap".to_string(), "FxHashMap".to_string()); + map.insert("HashSet".to_string(), "FxHashSet".to_string()); + Self { map } + } +} + +impl_lint_pass!(DefaultHashTypes => [DEFAULT_HASH_TYPES]); + +impl EarlyLintPass for DefaultHashTypes { + fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: Ident) { + let ident_string = ident.to_string(); + if let Some(replace) = self.map.get(&ident_string) { + let msg = format!( + "Prefer {} over {}, it has better performance", + replace, ident_string + ); + let mut db = cx.struct_span_lint(DEFAULT_HASH_TYPES, ident.span, &msg); + db.span_suggestion( + ident.span, + "use", + replace.to_string(), + Applicability::MaybeIncorrect, // FxHashMap, ... needs another import + ); + db.note(&format!( + "a `use rustc_data_structures::fx::{}` may be necessary", + replace + )) + .emit(); + } + } +} + +declare_lint! { + pub USAGE_OF_TY_TYKIND, + Allow, + "Usage of `ty::TyKind` outside of the `ty::sty` module" +} + +declare_lint_pass!(TyKindUsage => [USAGE_OF_TY_TYKIND]); + +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TyKindUsage { + fn check_path(&mut self, cx: &LateContext<'_, '_>, path: &'tcx Path, _: HirId) { + let segments = path.segments.iter().rev().skip(1).rev(); + + if let Some(last) = segments.last() { + let span = path.span.with_hi(last.ident.span.hi()); + if lint_ty_kind_usage(cx, last) { + cx.struct_span_lint(USAGE_OF_TY_TYKIND, span, "usage of `ty::TyKind::<kind>`") + .span_suggestion( + span, + "try using ty::<kind> directly", + "ty".to_string(), + Applicability::MaybeIncorrect, // ty maybe needs an import + ) + .emit(); + } + } + } + + fn check_ty(&mut self, cx: &LateContext<'_, '_>, ty: &'tcx Ty) { + if let TyKind::Path(qpath) = &ty.node { + if let QPath::Resolved(_, path) = qpath { + if let Some(last) = path.segments.iter().last() { + if lint_ty_kind_usage(cx, last) { + cx.struct_span_lint(USAGE_OF_TY_TYKIND, path.span, "usage of `ty::TyKind`") + .help("try using `ty::Ty` instead") + .emit(); + } + } + } + } + } +} + +fn lint_ty_kind_usage(cx: &LateContext<'_, '_>, segment: &PathSegment) -> bool { + if segment.ident.as_str() == "TyKind" { + if let Some(def) = segment.def { + if let Some(did) = def.opt_def_id() { + return cx.match_path(did, &["rustc", "ty", "sty", "TyKind"]); + } + } + } + + false +} diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index a5506bb8f59..112c247d4d6 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -26,7 +26,7 @@ use rustc_data_structures::sync::{self, Lrc}; use crate::hir::def_id::{CrateNum, LOCAL_CRATE}; use crate::hir::intravisit; use crate::hir; -use crate::lint::builtin::{BuiltinLintDiagnostics, DUPLICATE_MATCHER_BINDING_NAME}; +use crate::lint::builtin::BuiltinLintDiagnostics; use crate::lint::builtin::parser::{QUESTION_MARK_MACRO_SEP, ILL_FORMED_ATTRIBUTE_INPUT}; use crate::session::{Session, DiagnosticMessageId}; use crate::ty::TyCtxt; @@ -82,7 +82,6 @@ impl Lint { match lint_id { BufferedEarlyLintId::QuestionMarkMacroSep => QUESTION_MARK_MACRO_SEP, BufferedEarlyLintId::IllFormedAttributeInput => ILL_FORMED_ATTRIBUTE_INPUT, - BufferedEarlyLintId::DuplicateMacroMatcherBindingName => DUPLICATE_MATCHER_BINDING_NAME, } } @@ -181,6 +180,27 @@ pub trait LintPass { fn get_lints(&self) -> LintArray; } +/// Implements `LintPass for $name` with the given list of `Lint` statics. +#[macro_export] +macro_rules! impl_lint_pass { + ($name:ident => [$($lint:expr),* $(,)?]) => { + impl LintPass for $name { + fn name(&self) -> &'static str { stringify!($name) } + fn get_lints(&self) -> LintArray { $crate::lint_array!($($lint),*) } + } + }; +} + +/// Declares a type named `$name` which implements `LintPass`. +/// To the right of `=>` a comma separated list of `Lint` statics is given. +#[macro_export] +macro_rules! declare_lint_pass { + ($(#[$m:meta])* $name:ident => [$($lint:expr),* $(,)?]) => { + $(#[$m])* #[derive(Copy, Clone)] pub struct $name; + $crate::impl_lint_pass!($name => [$($lint),*]); + }; +} + #[macro_export] macro_rules! late_lint_methods { ($macro:path, $args:tt, [$hir:tt]) => ( @@ -574,6 +594,7 @@ impl_stable_hash_for!(enum self::LintSource { pub type LevelSource = (Level, LintSource); pub mod builtin; +pub mod internal; mod context; mod levels; @@ -690,10 +711,14 @@ pub fn struct_lint_level<'a>(sess: &'a Session, "this was previously accepted by the compiler but is being phased out; \ it will become a hard error"; - let explanation = if lint_id == LintId::of(crate::lint::builtin::UNSTABLE_NAME_COLLISIONS) { + let explanation = if lint_id == LintId::of(builtin::UNSTABLE_NAME_COLLISIONS) { "once this method is added to the standard library, \ the ambiguity may cause an error or change in behavior!" .to_owned() + } else if lint_id == LintId::of(builtin::MUTABLE_BORROW_RESERVATION_CONFLICT) { + "this borrowing pattern was not meant to be accepted, \ + and may become a hard error in the future" + .to_owned() } else if let Some(edition) = future_incompatible.edition { format!("{} in the {} edition!", STANDARD_MESSAGE, edition) } else { diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 73e232a6a4f..3306bcae212 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -2891,7 +2891,7 @@ fn insert_late_bound_lifetimes( } } -fn report_missing_lifetime_specifiers( +pub fn report_missing_lifetime_specifiers( sess: &Session, span: Span, count: usize, diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index fc04c7672db..b9c4d312adb 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -43,7 +43,7 @@ pub type ConstEvalResult<'tcx> = Result<ty::Const<'tcx>, ErrorHandled>; #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] pub struct ConstEvalErr<'tcx> { pub span: Span, - pub error: crate::mir::interpret::EvalErrorKind<'tcx, u64>, + pub error: crate::mir::interpret::InterpError<'tcx, u64>, pub stacktrace: Vec<FrameInfo<'tcx>>, } @@ -65,8 +65,8 @@ impl<'tcx> fmt::Display for FrameInfo<'tcx> { write!(f, "inside call to `{}`", self.instance)?; } if !self.call_site.is_dummy() { - let lo = tcx.sess.source_map().lookup_char_pos_adj(self.call_site.lo()); - write!(f, " at {}:{}:{}", lo.filename, lo.line, lo.col.to_usize() + 1)?; + let lo = tcx.sess.source_map().lookup_char_pos(self.call_site.lo()); + write!(f, " at {}:{}:{}", lo.file.name, lo.line, lo.col.to_usize() + 1)?; } Ok(()) }) @@ -135,10 +135,10 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> { lint_root: Option<hir::HirId>, ) -> Result<DiagnosticBuilder<'tcx>, ErrorHandled> { match self.error { - EvalErrorKind::Layout(LayoutError::Unknown(_)) | - EvalErrorKind::TooGeneric => return Err(ErrorHandled::TooGeneric), - EvalErrorKind::Layout(LayoutError::SizeOverflow(_)) | - EvalErrorKind::TypeckError => return Err(ErrorHandled::Reported), + InterpError::Layout(LayoutError::Unknown(_)) | + InterpError::TooGeneric => return Err(ErrorHandled::TooGeneric), + InterpError::Layout(LayoutError::SizeOverflow(_)) | + InterpError::TypeckError => return Err(ErrorHandled::Reported), _ => {}, } trace!("reporting const eval failure at {:?}", self.span); @@ -180,7 +180,7 @@ pub fn struct_error<'a, 'gcx, 'tcx>( #[derive(Debug, Clone)] pub struct EvalError<'tcx> { - pub kind: EvalErrorKind<'tcx, u64>, + pub kind: InterpError<'tcx, u64>, pub backtrace: Option<Box<Backtrace>>, } @@ -197,8 +197,8 @@ fn print_backtrace(backtrace: &mut Backtrace) { eprintln!("\n\nAn error occurred in miri:\n{:?}", backtrace); } -impl<'tcx> From<EvalErrorKind<'tcx, u64>> for EvalError<'tcx> { - fn from(kind: EvalErrorKind<'tcx, u64>) -> Self { +impl<'tcx> From<InterpError<'tcx, u64>> for EvalError<'tcx> { + fn from(kind: InterpError<'tcx, u64>) -> Self { let backtrace = match env::var("RUST_CTFE_BACKTRACE") { // matching RUST_BACKTRACE, we treat "0" the same as "not present". Ok(ref val) if val != "0" => { @@ -221,10 +221,10 @@ impl<'tcx> From<EvalErrorKind<'tcx, u64>> for EvalError<'tcx> { } } -pub type AssertMessage<'tcx> = EvalErrorKind<'tcx, mir::Operand<'tcx>>; +pub type AssertMessage<'tcx> = InterpError<'tcx, mir::Operand<'tcx>>; #[derive(Clone, RustcEncodable, RustcDecodable, HashStable)] -pub enum EvalErrorKind<'tcx, O> { +pub enum InterpError<'tcx, O> { /// This variant is used by machines to signal their own errors that do not /// match an existing variant. MachineError(String), @@ -312,9 +312,9 @@ pub enum EvalErrorKind<'tcx, O> { pub type EvalResult<'tcx, T = ()> = Result<T, EvalError<'tcx>>; -impl<'tcx, O> EvalErrorKind<'tcx, O> { +impl<'tcx, O> InterpError<'tcx, O> { pub fn description(&self) -> &str { - use self::EvalErrorKind::*; + use self::InterpError::*; match *self { MachineError(ref inner) => inner, FunctionAbiMismatch(..) | FunctionArgMismatch(..) | FunctionRetMismatch(..) @@ -450,15 +450,15 @@ impl<'tcx> fmt::Display for EvalError<'tcx> { } } -impl<'tcx> fmt::Display for EvalErrorKind<'tcx, u64> { +impl<'tcx> fmt::Display for InterpError<'tcx, u64> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{:?}", self) } } -impl<'tcx, O: fmt::Debug> fmt::Debug for EvalErrorKind<'tcx, O> { +impl<'tcx, O: fmt::Debug> fmt::Debug for InterpError<'tcx, O> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - use self::EvalErrorKind::*; + use self::InterpError::*; match *self { PointerOutOfBounds { ptr, check, allocation_size } => { write!(f, "Pointer must be in-bounds{} at offset {}, but is outside bounds of \ diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs index 0dd83168527..2c619a7a250 100644 --- a/src/librustc/mir/interpret/mod.rs +++ b/src/librustc/mir/interpret/mod.rs @@ -2,7 +2,7 @@ #[macro_export] macro_rules! err { - ($($tt:tt)*) => { Err($crate::mir::interpret::EvalErrorKind::$($tt)*.into()) }; + ($($tt:tt)*) => { Err($crate::mir::interpret::InterpError::$($tt)*.into()) }; } mod error; @@ -11,7 +11,7 @@ mod allocation; mod pointer; pub use self::error::{ - EvalError, EvalResult, EvalErrorKind, AssertMessage, ConstEvalErr, struct_error, + EvalError, EvalResult, InterpError, AssertMessage, ConstEvalErr, struct_error, FrameInfo, ConstEvalRawResult, ConstEvalResult, ErrorHandled, }; diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 7b419e306db..3cab7a3812f 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -4,8 +4,8 @@ use crate::hir::def::{CtorKind, Namespace}; use crate::hir::def_id::DefId; -use crate::hir::{self, HirId, InlineAsm}; -use crate::mir::interpret::{ConstValue, EvalErrorKind, Scalar}; +use crate::hir::{self, HirId, InlineAsm as HirInlineAsm}; +use crate::mir::interpret::{ConstValue, InterpError, Scalar}; use crate::mir::visit::MirVisitable; use rustc_apfloat::ieee::{Double, Single}; use rustc_apfloat::Float; @@ -25,7 +25,7 @@ use std::slice; use std::vec::IntoIter; use std::{iter, mem, option, u32}; use syntax::ast::{self, Name}; -use syntax::symbol::InternedString; +use syntax::symbol::{InternedString, Symbol}; use syntax_pos::{Span, DUMMY_SP}; use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use crate::ty::subst::{Subst, SubstsRef}; @@ -772,7 +772,7 @@ pub struct LocalDecl<'tcx> { /// e.g., via `let x: T`, then we carry that type here. The MIR /// borrow checker needs this information since it can affect /// region inference. - pub user_ty: UserTypeProjections<'tcx>, + pub user_ty: UserTypeProjections, /// Name of the local, used in debuginfo and pretty-printing. /// @@ -1779,12 +1779,9 @@ pub enum StatementKind<'tcx> { /// End the current live range for the storage of the local. StorageDead(Local), - /// Executes a piece of inline Assembly. - InlineAsm { - asm: Box<InlineAsm>, - outputs: Box<[Place<'tcx>]>, - inputs: Box<[(Span, Operand<'tcx>)]>, - }, + /// Executes a piece of inline Assembly. Stored in a Box to keep the size + /// of `StatementKind` low. + InlineAsm(Box<InlineAsm<'tcx>>), /// Retag references in the given place, ensuring they got fresh tags. This is /// part of the Stacked Borrows model. These statements are currently only interpreted @@ -1805,7 +1802,7 @@ pub enum StatementKind<'tcx> { /// - `Contravariant` -- requires that `T_y :> T` /// - `Invariant` -- requires that `T_y == T` /// - `Bivariant` -- no effect - AscribeUserType(Place<'tcx>, ty::Variance, Box<UserTypeProjection<'tcx>>), + AscribeUserType(Place<'tcx>, ty::Variance, Box<UserTypeProjection>), /// No-op. Useful for deleting instructions without affecting statement indices. Nop, @@ -1858,6 +1855,13 @@ pub enum FakeReadCause { ForLet, } +#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] +pub struct InlineAsm<'tcx> { + pub asm: HirInlineAsm, + pub outputs: Box<[Place<'tcx>]>, + pub inputs: Box<[(Span, Operand<'tcx>)]>, +} + impl<'tcx> Debug for Statement<'tcx> { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { use self::StatementKind::*; @@ -1880,11 +1884,8 @@ impl<'tcx> Debug for Statement<'tcx> { ref place, variant_index, } => write!(fmt, "discriminant({:?}) = {:?}", place, variant_index), - InlineAsm { - ref asm, - ref outputs, - ref inputs, - } => write!(fmt, "asm!({:?} : {:?} : {:?})", asm, outputs, inputs), + InlineAsm(ref asm) => + write!(fmt, "asm!({:?} : {:?} : {:?})", asm.asm, asm.outputs, asm.inputs), AscribeUserType(ref place, ref variance, ref c_ty) => { write!(fmt, "AscribeUserType({:?}, {:?}, {:?})", place, variance, c_ty) } @@ -1939,14 +1940,14 @@ impl_stable_hash_for!(struct Static<'tcx> { /// `PlaceProjection` etc below. #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, HashStable)] -pub struct Projection<'tcx, B, V, T> { +pub struct Projection<B, V, T> { pub base: B, - pub elem: ProjectionElem<'tcx, V, T>, + pub elem: ProjectionElem<V, T>, } #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, HashStable)] -pub enum ProjectionElem<'tcx, V, T> { +pub enum ProjectionElem<V, T> { Deref, Field(Field, T), Index(V), @@ -1980,16 +1981,18 @@ pub enum ProjectionElem<'tcx, V, T> { /// "Downcast" to a variant of an ADT. Currently, we only introduce /// this for ADTs with more than one variant. It may be better to /// just introduce it always, or always for enums. - Downcast(&'tcx AdtDef, VariantIdx), + /// + /// The included Symbol is the name of the variant, used for printing MIR. + Downcast(Option<Symbol>, VariantIdx), } /// Alias for projections as they appear in places, where the base is a place /// and the index is a local. -pub type PlaceProjection<'tcx> = Projection<'tcx, Place<'tcx>, Local, Ty<'tcx>>; +pub type PlaceProjection<'tcx> = Projection<Place<'tcx>, Local, Ty<'tcx>>; /// Alias for projections as they appear in places, where the base is a place /// and the index is a local. -pub type PlaceElem<'tcx> = ProjectionElem<'tcx, Local, Ty<'tcx>>; +pub type PlaceElem<'tcx> = ProjectionElem<Local, Ty<'tcx>>; // at least on 64 bit systems, `PlaceElem` should not be larger than two pointers static_assert!(PROJECTION_ELEM_IS_2_PTRS_LARGE: @@ -1998,7 +2001,7 @@ static_assert!(PROJECTION_ELEM_IS_2_PTRS_LARGE: /// Alias for projections as they appear in `UserTypeProjection`, where we /// need neither the `V` parameter for `Index` nor the `T` for `Field`. -pub type ProjectionKind<'tcx> = ProjectionElem<'tcx, (), ()>; +pub type ProjectionKind = ProjectionElem<(), ()>; newtype_index! { pub struct Field { @@ -2019,7 +2022,9 @@ impl<'tcx> Place<'tcx> { } pub fn downcast(self, adt_def: &'tcx AdtDef, variant_index: VariantIdx) -> Place<'tcx> { - self.elem(ProjectionElem::Downcast(adt_def, variant_index)) + self.elem(ProjectionElem::Downcast( + Some(adt_def.variants[variant_index].ident.name), + variant_index)) } pub fn index(self, index: Local) -> Place<'tcx> { @@ -2080,8 +2085,11 @@ impl<'tcx> Debug for Place<'tcx> { ) }, Projection(ref data) => match data.elem { - ProjectionElem::Downcast(ref adt_def, index) => { - write!(fmt, "({:?} as {})", data.base, adt_def.variants[index].ident) + ProjectionElem::Downcast(Some(name), _index) => { + write!(fmt, "({:?} as {})", data.base, name) + } + ProjectionElem::Downcast(None, index) => { + write!(fmt, "({:?} as variant#{:?})", data.base, index) } ProjectionElem::Deref => write!(fmt, "(*{:?})", data.base), ProjectionElem::Field(field, ty) => { @@ -2542,36 +2550,36 @@ pub struct Constant<'tcx> { /// inferred region `'1`). The second will lead to the constraint `w: /// &'static str`. #[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, HashStable)] -pub struct UserTypeProjections<'tcx> { - pub(crate) contents: Vec<(UserTypeProjection<'tcx>, Span)>, +pub struct UserTypeProjections { + pub(crate) contents: Vec<(UserTypeProjection, Span)>, } BraceStructTypeFoldableImpl! { - impl<'tcx> TypeFoldable<'tcx> for UserTypeProjections<'tcx> { + impl<'tcx> TypeFoldable<'tcx> for UserTypeProjections { contents } } -impl<'tcx> UserTypeProjections<'tcx> { +impl<'tcx> UserTypeProjections { pub fn none() -> Self { UserTypeProjections { contents: vec![] } } - pub fn from_projections(projs: impl Iterator<Item=(UserTypeProjection<'tcx>, Span)>) -> Self { + pub fn from_projections(projs: impl Iterator<Item=(UserTypeProjection, Span)>) -> Self { UserTypeProjections { contents: projs.collect() } } - pub fn projections_and_spans(&self) -> impl Iterator<Item=&(UserTypeProjection<'tcx>, Span)> { + pub fn projections_and_spans(&self) -> impl Iterator<Item=&(UserTypeProjection, Span)> { self.contents.iter() } - pub fn projections(&self) -> impl Iterator<Item=&UserTypeProjection<'tcx>> { + pub fn projections(&self) -> impl Iterator<Item=&UserTypeProjection> { self.contents.iter().map(|&(ref user_type, _span)| user_type) } pub fn push_projection( mut self, - user_ty: &UserTypeProjection<'tcx>, + user_ty: &UserTypeProjection, span: Span, ) -> Self { self.contents.push((user_ty.clone(), span)); @@ -2580,7 +2588,7 @@ impl<'tcx> UserTypeProjections<'tcx> { fn map_projections( mut self, - mut f: impl FnMut(UserTypeProjection<'tcx>) -> UserTypeProjection<'tcx> + mut f: impl FnMut(UserTypeProjection) -> UserTypeProjection ) -> Self { self.contents = self.contents.drain(..).map(|(proj, span)| (f(proj), span)).collect(); self @@ -2628,14 +2636,14 @@ impl<'tcx> UserTypeProjections<'tcx> { /// `field[0]` (aka `.0`), indicating that the type of `s` is /// determined by finding the type of the `.0` field from `T`. #[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, HashStable)] -pub struct UserTypeProjection<'tcx> { +pub struct UserTypeProjection { pub base: UserTypeAnnotationIndex, - pub projs: Vec<ProjectionElem<'tcx, (), ()>>, + pub projs: Vec<ProjectionElem<(), ()>>, } -impl<'tcx> Copy for ProjectionKind<'tcx> { } +impl Copy for ProjectionKind { } -impl<'tcx> UserTypeProjection<'tcx> { +impl UserTypeProjection { pub(crate) fn index(mut self) -> Self { self.projs.push(ProjectionElem::Index(())); self @@ -2662,15 +2670,17 @@ impl<'tcx> UserTypeProjection<'tcx> { variant_index: VariantIdx, field: Field, ) -> Self { - self.projs.push(ProjectionElem::Downcast(adt_def, variant_index)); + self.projs.push(ProjectionElem::Downcast( + Some(adt_def.variants[variant_index].ident.name), + variant_index)); self.projs.push(ProjectionElem::Field(field, ())); self } } -CloneTypeFoldableAndLiftImpls! { ProjectionKind<'tcx>, } +CloneTypeFoldableAndLiftImpls! { ProjectionKind, } -impl<'tcx> TypeFoldable<'tcx> for UserTypeProjection<'tcx> { +impl<'tcx> TypeFoldable<'tcx> for UserTypeProjection { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { use crate::mir::ProjectionElem::*; @@ -3140,13 +3150,21 @@ EnumTypeFoldableImpl! { (StatementKind::SetDiscriminant) { place, variant_index }, (StatementKind::StorageLive)(a), (StatementKind::StorageDead)(a), - (StatementKind::InlineAsm) { asm, outputs, inputs }, + (StatementKind::InlineAsm)(a), (StatementKind::Retag)(kind, place), (StatementKind::AscribeUserType)(a, v, b), (StatementKind::Nop), } } +BraceStructTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for InlineAsm<'tcx> { + asm, + outputs, + inputs, + } +} + EnumTypeFoldableImpl! { impl<'tcx, T> TypeFoldable<'tcx> for ClearCrossCrate<T> { (ClearCrossCrate::Clear), @@ -3226,8 +3244,8 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { target, cleanup, } => { - let msg = if let EvalErrorKind::BoundsCheck { ref len, ref index } = *msg { - EvalErrorKind::BoundsCheck { + let msg = if let InterpError::BoundsCheck { ref len, ref index } = *msg { + InterpError::BoundsCheck { len: len.fold_with(folder), index: index.fold_with(folder), } @@ -3301,7 +3319,7 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { ref cond, ref msg, .. } => { if cond.visit_with(visitor) { - if let EvalErrorKind::BoundsCheck { ref len, ref index } = *msg { + if let InterpError::BoundsCheck { ref len, ref index } = *msg { len.visit_with(visitor) || index.visit_with(visitor) } else { false @@ -3428,7 +3446,7 @@ impl<'tcx> TypeFoldable<'tcx> for Operand<'tcx> { } } -impl<'tcx, B, V, T> TypeFoldable<'tcx> for Projection<'tcx, B, V, T> +impl<'tcx, B, V, T> TypeFoldable<'tcx> for Projection<B, V, T> where B: TypeFoldable<'tcx>, V: TypeFoldable<'tcx>, diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index ac42eacacd7..23be1bbf6c6 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -4,21 +4,17 @@ */ use crate::mir::*; -use crate::ty::subst::{Subst, SubstsRef}; -use crate::ty::{self, AdtDef, Ty, TyCtxt}; +use crate::ty::subst::Subst; +use crate::ty::{self, Ty, TyCtxt}; use crate::ty::layout::VariantIdx; use crate::hir; use crate::ty::util::IntTypeExt; #[derive(Copy, Clone, Debug)] -pub enum PlaceTy<'tcx> { - /// Normal type. - Ty { ty: Ty<'tcx> }, - - /// Downcast to a particular variant of an enum. - Downcast { adt_def: &'tcx AdtDef, - substs: SubstsRef<'tcx>, - variant_index: VariantIdx }, +pub struct PlaceTy<'tcx> { + pub ty: Ty<'tcx>, + /// Downcast to a particular variant of an enum, if included. + pub variant_index: Option<VariantIdx>, } static_assert!(PLACE_TY_IS_3_PTRS_LARGE: @@ -27,16 +23,7 @@ static_assert!(PLACE_TY_IS_3_PTRS_LARGE: impl<'a, 'gcx, 'tcx> PlaceTy<'tcx> { pub fn from_ty(ty: Ty<'tcx>) -> PlaceTy<'tcx> { - PlaceTy::Ty { ty } - } - - pub fn to_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> { - match *self { - PlaceTy::Ty { ty } => - ty, - PlaceTy::Downcast { adt_def, substs, variant_index: _ } => - tcx.mk_adt(adt_def, substs), - } + PlaceTy { ty, variant_index: None } } /// `place_ty.field_ty(tcx, f)` computes the type at a given field @@ -48,21 +35,20 @@ impl<'a, 'gcx, 'tcx> PlaceTy<'tcx> { /// Note that the resulting type has not been normalized. pub fn field_ty(self, tcx: TyCtxt<'a, 'gcx, 'tcx>, f: &Field) -> Ty<'tcx> { - // Pass `0` here so it can be used as a "default" variant_index in first arm below - let answer = match (self, VariantIdx::new(0)) { - (PlaceTy::Ty { - ty: &ty::TyS { sty: ty::TyKind::Adt(adt_def, substs), .. } }, variant_index) | - (PlaceTy::Downcast { adt_def, substs, variant_index }, _) => { - let variant_def = &adt_def.variants[variant_index]; + let answer = match self.ty.sty { + ty::Adt(adt_def, substs) => { + let variant_def = match self.variant_index { + None => adt_def.non_enum_variant(), + Some(variant_index) => { + assert!(adt_def.is_enum()); + &adt_def.variants[variant_index] + } + }; let field_def = &variant_def.fields[f.index()]; field_def.ty(tcx, substs) } - (PlaceTy::Ty { ty }, _) => { - match ty.sty { - ty::Tuple(ref tys) => tys[f.index()], - _ => bug!("extracting field of non-tuple non-adt: {:?}", self), - } - } + ty::Tuple(ref tys) => tys[f.index()], + _ => bug!("extracting field of non-tuple non-adt: {:?}", self), }; debug!("field_ty self: {:?} f: {:?} yields: {:?}", self, f, answer); answer @@ -86,7 +72,7 @@ impl<'a, 'gcx, 'tcx> PlaceTy<'tcx> { pub fn projection_ty_core<V, T>( self, tcx: TyCtxt<'a, 'gcx, 'tcx>, - elem: &ProjectionElem<'tcx, V, T>, + elem: &ProjectionElem<V, T>, mut handle_field: impl FnMut(&Self, &Field, &T) -> Ty<'tcx>) -> PlaceTy<'tcx> where @@ -94,62 +80,43 @@ impl<'a, 'gcx, 'tcx> PlaceTy<'tcx> { { let answer = match *elem { ProjectionElem::Deref => { - let ty = self.to_ty(tcx) + let ty = self.ty .builtin_deref(true) .unwrap_or_else(|| { bug!("deref projection of non-dereferencable ty {:?}", self) }) .ty; - PlaceTy::Ty { - ty, - } + PlaceTy::from_ty(ty) } ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => - PlaceTy::Ty { - ty: self.to_ty(tcx).builtin_index().unwrap() - }, + PlaceTy::from_ty(self.ty.builtin_index().unwrap()), ProjectionElem::Subslice { from, to } => { - let ty = self.to_ty(tcx); - PlaceTy::Ty { - ty: match ty.sty { - ty::Array(inner, size) => { - let size = size.unwrap_usize(tcx); - let len = size - (from as u64) - (to as u64); - tcx.mk_array(inner, len) - } - ty::Slice(..) => ty, - _ => { - bug!("cannot subslice non-array type: `{:?}`", self) - } - } - } - } - ProjectionElem::Downcast(adt_def1, index) => - match self.to_ty(tcx).sty { - ty::Adt(adt_def, substs) => { - assert!(adt_def.is_enum()); - assert!(index.as_usize() < adt_def.variants.len()); - assert_eq!(adt_def, adt_def1); - PlaceTy::Downcast { adt_def, - substs, - variant_index: index } + PlaceTy::from_ty(match self.ty.sty { + ty::Array(inner, size) => { + let size = size.unwrap_usize(tcx); + let len = size - (from as u64) - (to as u64); + tcx.mk_array(inner, len) } + ty::Slice(..) => self.ty, _ => { - bug!("cannot downcast non-ADT type: `{:?}`", self) + bug!("cannot subslice non-array type: `{:?}`", self) } - }, + }) + } + ProjectionElem::Downcast(_name, index) => + PlaceTy { ty: self.ty, variant_index: Some(index) }, ProjectionElem::Field(ref f, ref fty) => - PlaceTy::Ty { ty: handle_field(&self, f, fty) }, + PlaceTy::from_ty(handle_field(&self, f, fty)), }; debug!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem, answer); answer } } -EnumTypeFoldableImpl! { +BraceStructTypeFoldableImpl! { impl<'tcx> TypeFoldable<'tcx> for PlaceTy<'tcx> { - (PlaceTy::Ty) { ty }, - (PlaceTy::Downcast) { adt_def, substs, variant_index }, + ty, + variant_index, } } @@ -159,9 +126,9 @@ impl<'tcx> Place<'tcx> { { match *self { Place::Base(PlaceBase::Local(index)) => - PlaceTy::Ty { ty: local_decls.local_decls()[index].ty }, + PlaceTy::from_ty(local_decls.local_decls()[index].ty), Place::Base(PlaceBase::Static(ref data)) => - PlaceTy::Ty { ty: data.ty }, + PlaceTy::from_ty(data.ty), Place::Projection(ref proj) => proj.base.ty(local_decls, tcx).projection_ty(tcx, &proj.elem), } @@ -186,7 +153,7 @@ impl<'tcx> Place<'tcx> { match place { Place::Projection(ref proj) => match proj.elem { ProjectionElem::Field(field, _ty) => { - let base_ty = proj.base.ty(mir, *tcx).to_ty(*tcx); + let base_ty = proj.base.ty(mir, *tcx).ty; if (base_ty.is_closure() || base_ty.is_generator()) && (!by_ref || mir.upvar_decls[field.index()].by_ref) @@ -218,7 +185,7 @@ impl<'tcx> Rvalue<'tcx> { tcx.mk_array(operand.ty(local_decls, tcx), count) } Rvalue::Ref(reg, bk, ref place) => { - let place_ty = place.ty(local_decls, tcx).to_ty(tcx); + let place_ty = place.ty(local_decls, tcx).ty; tcx.mk_ref(reg, ty::TypeAndMut { ty: place_ty, @@ -244,7 +211,7 @@ impl<'tcx> Rvalue<'tcx> { operand.ty(local_decls, tcx) } Rvalue::Discriminant(ref place) => { - let ty = place.ty(local_decls, tcx).to_ty(tcx); + let ty = place.ty(local_decls, tcx).ty; if let ty::Adt(adt_def, _) = ty.sty { adt_def.repr.discr_type().to_ty(tcx) } else { @@ -293,7 +260,7 @@ impl<'tcx> Operand<'tcx> { { match self { &Operand::Copy(ref l) | - &Operand::Move(ref l) => l.ty(local_decls, tcx).to_ty(tcx), + &Operand::Move(ref l) => l.ty(local_decls, tcx).ty, &Operand::Constant(ref c) => c.ty, } } diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 54e5bfc4397..b04c28cde57 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -137,7 +137,7 @@ macro_rules! make_mir_visitor { fn visit_ascribe_user_ty(&mut self, place: & $($mutability)? Place<'tcx>, variance: & $($mutability)? ty::Variance, - user_ty: & $($mutability)? UserTypeProjection<'tcx>, + user_ty: & $($mutability)? UserTypeProjection, location: Location) { self.super_ascribe_user_ty(place, variance, user_ty, location); } @@ -205,7 +205,7 @@ macro_rules! make_mir_visitor { fn visit_user_type_projection( &mut self, - ty: & $($mutability)? UserTypeProjection<'tcx>, + ty: & $($mutability)? UserTypeProjection, ) { self.super_user_type_projection(ty); } @@ -391,15 +391,15 @@ macro_rules! make_mir_visitor { location ); } - StatementKind::InlineAsm { outputs, inputs, asm: _ } => { - for output in & $($mutability)? outputs[..] { + StatementKind::InlineAsm(asm) => { + for output in & $($mutability)? asm.outputs[..] { self.visit_place( output, PlaceContext::MutatingUse(MutatingUseContext::AsmOutput), location ); } - for (span, input) in & $($mutability)? inputs[..] { + for (span, input) in & $($mutability)? asm.inputs[..] { self.visit_span(span); self.visit_operand(input, location); } @@ -560,7 +560,7 @@ macro_rules! make_mir_visitor { fn super_assert_message(&mut self, msg: & $($mutability)? AssertMessage<'tcx>, location: Location) { - use crate::mir::interpret::EvalErrorKind::*; + use crate::mir::interpret::InterpError::*; if let BoundsCheck { len, index } = msg { self.visit_operand(len, location); self.visit_operand(index, location); @@ -700,7 +700,7 @@ macro_rules! make_mir_visitor { fn super_ascribe_user_ty(&mut self, place: & $($mutability)? Place<'tcx>, _variance: & $($mutability)? ty::Variance, - user_ty: & $($mutability)? UserTypeProjection<'tcx>, + user_ty: & $($mutability)? UserTypeProjection, location: Location) { self.visit_place( place, @@ -777,7 +777,7 @@ macro_rules! make_mir_visitor { min_length: _, from_end: _ } => { } - ProjectionElem::Downcast(_adt_def, _variant_index) => { + ProjectionElem::Downcast(_name, _variant_index) => { } } } @@ -851,7 +851,7 @@ macro_rules! make_mir_visitor { fn super_user_type_projection( &mut self, - _ty: & $($mutability)? UserTypeProjection<'tcx>, + _ty: & $($mutability)? UserTypeProjection, ) { } diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs index 8d64818f49b..d0ad2c90668 100644 --- a/src/librustc/query/mod.rs +++ b/src/librustc/query/mod.rs @@ -1,10 +1,21 @@ use crate::ty::query::QueryDescription; use crate::ty::query::queries; -use crate::ty::{self, Ty, TyCtxt}; -use crate::hir::def_id::{DefId, CrateNum}; +use crate::ty::{self, ParamEnvAnd, Ty, TyCtxt}; +use crate::ty::subst::SubstsRef; use crate::dep_graph::SerializedDepNodeIndex; +use crate::hir::def_id::{CrateNum, DefId, DefIndex}; +use crate::mir::interpret::GlobalId; use crate::traits; +use crate::traits::query::{ + CanonicalPredicateGoal, CanonicalProjectionGoal, + CanonicalTyGoal, CanonicalTypeOpAscribeUserTypeGoal, + CanonicalTypeOpEqGoal, CanonicalTypeOpSubtypeGoal, CanonicalTypeOpProvePredicateGoal, + CanonicalTypeOpNormalizeGoal, +}; + use std::borrow::Cow; +use syntax_pos::symbol::InternedString; + // Each of these queries corresponds to a function pointer field in the // `Providers` struct for requesting a value of that type, and a method @@ -73,7 +84,7 @@ rustc_queries! { /// Set of all the `DefId`s in this crate that have MIR associated with /// them. This includes all the body owners, but also things like struct /// constructors. - query mir_keys(_: CrateNum) -> Lrc<DefIdSet> { + query mir_keys(_: CrateNum) -> &'tcx DefIdSet { desc { "getting a list of all mir_keys" } } @@ -148,4 +159,909 @@ rustc_queries! { desc { "wasm import module map" } } } + + Other { + /// Maps from the `DefId` of an item (trait/struct/enum/fn) to the + /// predicates (where-clauses) directly defined on it. This is + /// equal to the `explicit_predicates_of` predicates plus the + /// `inferred_outlives_of` predicates. + query predicates_defined_on(_: DefId) + -> Lrc<ty::GenericPredicates<'tcx>> {} + + /// Returns the predicates written explicit by the user. + query explicit_predicates_of(_: DefId) + -> Lrc<ty::GenericPredicates<'tcx>> {} + + /// Returns the inferred outlives predicates (e.g., for `struct + /// Foo<'a, T> { x: &'a T }`, this would return `T: 'a`). + query inferred_outlives_of(_: DefId) -> Lrc<Vec<ty::Predicate<'tcx>>> {} + + /// Maps from the `DefId` of a trait to the list of + /// super-predicates. This is a subset of the full list of + /// predicates. We store these in a separate map because we must + /// evaluate them even during type conversion, often before the + /// full predicates are available (note that supertraits have + /// additional acyclicity requirements). + query super_predicates_of(key: DefId) -> Lrc<ty::GenericPredicates<'tcx>> { + desc { |tcx| "computing the supertraits of `{}`", tcx.def_path_str(key) } + } + + /// To avoid cycles within the predicates of a single item we compute + /// per-type-parameter predicates for resolving `T::AssocTy`. + query type_param_predicates(key: (DefId, DefId)) + -> Lrc<ty::GenericPredicates<'tcx>> { + no_force + desc { |tcx| "computing the bounds for type parameter `{}`", { + let id = tcx.hir().as_local_hir_id(key.1).unwrap(); + tcx.hir().ty_param_name(id) + }} + } + + query trait_def(_: DefId) -> &'tcx ty::TraitDef {} + query adt_def(_: DefId) -> &'tcx ty::AdtDef {} + query adt_destructor(_: DefId) -> Option<ty::Destructor> {} + + // The cycle error here should be reported as an error by `check_representable`. + // We consider the type as Sized in the meanwhile to avoid + // further errors (done in impl Value for AdtSizedConstraint). + // Use `cycle_delay_bug` to delay the cycle error here to be emitted later + // in case we accidentally otherwise don't emit an error. + query adt_sized_constraint( + _: DefId + ) -> AdtSizedConstraint<'tcx> { + cycle_delay_bug + } + + query adt_dtorck_constraint( + _: DefId + ) -> Result<DtorckConstraint<'tcx>, NoSolution> {} + + /// True if this is a const fn, use the `is_const_fn` to know whether your crate actually + /// sees it as const fn (e.g., the const-fn-ness might be unstable and you might not have + /// the feature gate active) + /// + /// **Do not call this function manually.** It is only meant to cache the base data for the + /// `is_const_fn` function. + query is_const_fn_raw(key: DefId) -> bool { + desc { |tcx| "checking if item is const fn: `{}`", tcx.def_path_str(key) } + } + + /// Returns true if calls to the function may be promoted + /// + /// This is either because the function is e.g., a tuple-struct or tuple-variant + /// constructor, or because it has the `#[rustc_promotable]` attribute. The attribute should + /// be removed in the future in favour of some form of check which figures out whether the + /// function does not inspect the bits of any of its arguments (so is essentially just a + /// constructor function). + query is_promotable_const_fn(_: DefId) -> bool {} + + /// True if this is a foreign item (i.e., linked via `extern { ... }`). + query is_foreign_item(_: DefId) -> bool {} + + /// Get a map with the variance of every item; use `item_variance` + /// instead. + query crate_variances(_: CrateNum) -> Lrc<ty::CrateVariancesMap> { + desc { "computing the variances for items in this crate" } + } + + /// Maps from def-id of a type or region parameter to its + /// (inferred) variance. + query variances_of(_: DefId) -> Lrc<Vec<ty::Variance>> {} + } + + TypeChecking { + /// Maps from def-id of a type to its (inferred) outlives. + query inferred_outlives_crate(_: CrateNum) + -> Lrc<ty::CratePredicatesMap<'tcx>> { + desc { "computing the inferred outlives predicates for items in this crate" } + } + } + + Other { + /// Maps from an impl/trait def-id to a list of the def-ids of its items + query associated_item_def_ids(_: DefId) -> Lrc<Vec<DefId>> {} + + /// Maps from a trait item to the trait item "descriptor" + query associated_item(_: DefId) -> ty::AssociatedItem {} + + query impl_trait_ref(_: DefId) -> Option<ty::TraitRef<'tcx>> {} + query impl_polarity(_: DefId) -> hir::ImplPolarity {} + + query issue33140_self_ty(_: DefId) -> Option<ty::Ty<'tcx>> {} + } + + TypeChecking { + /// Maps a DefId of a type to a list of its inherent impls. + /// Contains implementations of methods that are inherent to a type. + /// Methods in these implementations don't need to be exported. + query inherent_impls(_: DefId) -> Lrc<Vec<DefId>> { + eval_always + } + } + + TypeChecking { + /// The result of unsafety-checking this `DefId`. + query unsafety_check_result(_: DefId) -> mir::UnsafetyCheckResult {} + + /// HACK: when evaluated, this reports a "unsafe derive on repr(packed)" error + query unsafe_derive_on_repr_packed(_: DefId) -> () {} + + /// The signature of functions and closures. + query fn_sig(_: DefId) -> ty::PolyFnSig<'tcx> {} + } + + Other { + query lint_mod(key: DefId) -> () { + desc { |tcx| "linting {}", key.describe_as_module(tcx) } + } + + /// Checks the attributes in the module + query check_mod_attrs(key: DefId) -> () { + desc { |tcx| "checking attributes in {}", key.describe_as_module(tcx) } + } + + query check_mod_unstable_api_usage(key: DefId) -> () { + desc { |tcx| "checking for unstable API usage in {}", key.describe_as_module(tcx) } + } + + /// Checks the loops in the module + query check_mod_loops(key: DefId) -> () { + desc { |tcx| "checking loops in {}", key.describe_as_module(tcx) } + } + + query check_mod_item_types(key: DefId) -> () { + desc { |tcx| "checking item types in {}", key.describe_as_module(tcx) } + } + + query check_mod_privacy(key: DefId) -> () { + desc { |tcx| "checking privacy in {}", key.describe_as_module(tcx) } + } + + query check_mod_intrinsics(key: DefId) -> () { + desc { |tcx| "checking intrinsics in {}", key.describe_as_module(tcx) } + } + + query check_mod_liveness(key: DefId) -> () { + desc { |tcx| "checking liveness of variables in {}", key.describe_as_module(tcx) } + } + + query check_mod_impl_wf(key: DefId) -> () { + desc { |tcx| "checking that impls are well-formed in {}", key.describe_as_module(tcx) } + } + + query collect_mod_item_types(key: DefId) -> () { + desc { |tcx| "collecting item types in {}", key.describe_as_module(tcx) } + } + + /// Caches CoerceUnsized kinds for impls on custom types. + query coerce_unsized_info(_: DefId) + -> ty::adjustment::CoerceUnsizedInfo {} + } + + TypeChecking { + query typeck_item_bodies(_: CrateNum) -> () { + desc { "type-checking all item bodies" } + } + + query typeck_tables_of(key: DefId) -> &'tcx ty::TypeckTables<'tcx> { + cache { key.is_local() } + load_cached(tcx, id) { + let typeck_tables: Option<ty::TypeckTables<'tcx>> = tcx + .queries.on_disk_cache + .try_load_query_result(tcx, id); + + typeck_tables.map(|tables| tcx.alloc_tables(tables)) + } + } + } + + Other { + query used_trait_imports(_: DefId) -> Lrc<DefIdSet> {} + } + + TypeChecking { + query has_typeck_tables(_: DefId) -> bool {} + + query coherent_trait(def_id: DefId) -> () { + desc { |tcx| "coherence checking all impls of trait `{}`", tcx.def_path_str(def_id) } + } + } + + BorrowChecking { + query borrowck(_: DefId) -> Lrc<BorrowCheckResult> {} + + /// Borrow checks the function body. If this is a closure, returns + /// additional requirements that the closure's creator must verify. + query mir_borrowck(_: DefId) -> mir::BorrowCheckResult<'tcx> {} + } + + TypeChecking { + /// Gets a complete map from all types to their inherent impls. + /// Not meant to be used directly outside of coherence. + /// (Defined only for `LOCAL_CRATE`.) + query crate_inherent_impls(k: CrateNum) + -> Lrc<CrateInherentImpls> { + eval_always + desc { "all inherent impls defined in crate `{:?}`", k } + } + + /// Checks all types in the crate for overlap in their inherent impls. Reports errors. + /// Not meant to be used directly outside of coherence. + /// (Defined only for `LOCAL_CRATE`.) + query crate_inherent_impls_overlap_check(_: CrateNum) + -> () { + eval_always + desc { "check for overlap between inherent impls defined in this crate" } + } + } + + Other { + /// Evaluate a constant without running sanity checks + /// + /// **Do not use this** outside const eval. Const eval uses this to break query cycles + /// during validation. Please add a comment to every use site explaining why using + /// `const_eval` isn't sufficient + query const_eval_raw(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) + -> ConstEvalRawResult<'tcx> { + no_force + desc { |tcx| + "const-evaluating `{}`", + tcx.def_path_str(key.value.instance.def.def_id()) + } + cache { true } + load_cached(tcx, id) { + tcx.queries.on_disk_cache.try_load_query_result(tcx, id).map(Ok) + } + } + + /// Results of evaluating const items or constants embedded in + /// other items (such as enum variant explicit discriminants). + query const_eval(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) + -> ConstEvalResult<'tcx> { + no_force + desc { |tcx| + "const-evaluating + checking `{}`", + tcx.def_path_str(key.value.instance.def.def_id()) + } + cache { true } + load_cached(tcx, id) { + tcx.queries.on_disk_cache.try_load_query_result(tcx, id).map(Ok) + } + } + } + + TypeChecking { + query check_match(_: DefId) -> () {} + + /// Performs part of the privacy check and computes "access levels". + query privacy_access_levels(_: CrateNum) -> Lrc<AccessLevels> { + eval_always + desc { "privacy access levels" } + } + query check_private_in_public(_: CrateNum) -> () { + eval_always + desc { "checking for private elements in public interfaces" } + } + } + + Other { + query reachable_set(_: CrateNum) -> ReachableSet { + desc { "reachability" } + } + + /// Per-body `region::ScopeTree`. The `DefId` should be the owner `DefId` for the body; + /// in the case of closures, this will be redirected to the enclosing function. + query region_scope_tree(_: DefId) -> Lrc<region::ScopeTree> {} + + query mir_shims(key: ty::InstanceDef<'tcx>) -> &'tcx mir::Mir<'tcx> { + no_force + desc { |tcx| "generating MIR shim for `{}`", tcx.def_path_str(key.def_id()) } + } + + query symbol_name(key: ty::Instance<'tcx>) -> ty::SymbolName { + no_force + desc { "computing the symbol for `{}`", key } + cache { true } + } + + query describe_def(_: DefId) -> Option<Def> {} + query def_span(_: DefId) -> Span { + // FIXME(mw): DefSpans are not really inputs since they are derived from + // HIR. But at the moment HIR hashing still contains some hacks that allow + // to make type debuginfo to be source location independent. Declaring + // DefSpan an input makes sure that changes to these are always detected + // regardless of HIR hashing. + eval_always + } + query lookup_stability(_: DefId) -> Option<&'tcx attr::Stability> {} + query lookup_deprecation_entry(_: DefId) -> Option<DeprecationEntry> {} + query item_attrs(_: DefId) -> Lrc<[ast::Attribute]> {} + } + + Codegen { + query codegen_fn_attrs(_: DefId) -> CodegenFnAttrs {} + } + + Other { + query fn_arg_names(_: DefId) -> Vec<ast::Name> {} + /// Gets the rendered value of the specified constant or associated constant. + /// Used by rustdoc. + query rendered_const(_: DefId) -> String {} + query impl_parent(_: DefId) -> Option<DefId> {} + } + + TypeChecking { + query trait_of_item(_: DefId) -> Option<DefId> {} + query const_is_rvalue_promotable_to_static(key: DefId) -> bool { + desc { |tcx| + "const checking if rvalue is promotable to static `{}`", + tcx.def_path_str(key) + } + cache { true } + } + query rvalue_promotable_map(key: DefId) -> Lrc<ItemLocalSet> { + desc { |tcx| + "checking which parts of `{}` are promotable to static", + tcx.def_path_str(key) + } + } + } + + Codegen { + query is_mir_available(key: DefId) -> bool { + desc { |tcx| "checking if item has mir available: `{}`", tcx.def_path_str(key) } + } + } + + Other { + query vtable_methods(key: ty::PolyTraitRef<'tcx>) + -> &'tcx [Option<(DefId, SubstsRef<'tcx>)>] { + no_force + desc { |tcx| "finding all methods for trait {}", tcx.def_path_str(key.def_id()) } + } + } + + Codegen { + query codegen_fulfill_obligation( + key: (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>) + ) -> Vtable<'tcx, ()> { + no_force + cache { true } + desc { |tcx| + "checking if `{}` fulfills its obligations", + tcx.def_path_str(key.1.def_id()) + } + } + } + + TypeChecking { + query trait_impls_of(key: DefId) -> Lrc<ty::trait_def::TraitImpls> { + desc { |tcx| "trait impls of `{}`", tcx.def_path_str(key) } + } + query specialization_graph_of(_: DefId) -> &'tcx specialization_graph::Graph {} + query is_object_safe(key: DefId) -> bool { + desc { |tcx| "determine object safety of trait `{}`", tcx.def_path_str(key) } + } + + /// Gets the ParameterEnvironment for a given item; this environment + /// will be in "user-facing" mode, meaning that it is suitabe for + /// type-checking etc, and it does not normalize specializable + /// associated types. This is almost always what you want, + /// unless you are doing MIR optimizations, in which case you + /// might want to use `reveal_all()` method to change modes. + query param_env(_: DefId) -> ty::ParamEnv<'tcx> {} + + /// Trait selection queries. These are best used by invoking `ty.is_copy_modulo_regions()`, + /// `ty.is_copy()`, etc, since that will prune the environment where possible. + query is_copy_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { + no_force + desc { "computing whether `{}` is `Copy`", env.value } + } + query is_sized_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { + no_force + desc { "computing whether `{}` is `Sized`", env.value } + } + query is_freeze_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { + no_force + desc { "computing whether `{}` is freeze", env.value } + } + + // The cycle error here should be reported as an error by `check_representable`. + // We consider the type as not needing drop in the meanwhile to avoid + // further errors (done in impl Value for NeedsDrop). + // Use `cycle_delay_bug` to delay the cycle error here to be emitted later + // in case we accidentally otherwise don't emit an error. + query needs_drop_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> NeedsDrop { + cycle_delay_bug + no_force + desc { "computing whether `{}` needs drop", env.value } + } + + query layout_raw( + env: ty::ParamEnvAnd<'tcx, Ty<'tcx>> + ) -> Result<&'tcx ty::layout::LayoutDetails, ty::layout::LayoutError<'tcx>> { + no_force + desc { "computing layout of `{}`", env.value } + } + } + + Other { + query dylib_dependency_formats(_: CrateNum) + -> Lrc<Vec<(CrateNum, LinkagePreference)>> { + desc { "dylib dependency formats of crate" } + } + } + + Codegen { + query is_compiler_builtins(_: CrateNum) -> bool { + fatal_cycle + desc { "checking if the crate is_compiler_builtins" } + } + query has_global_allocator(_: CrateNum) -> bool { + fatal_cycle + desc { "checking if the crate has_global_allocator" } + } + query has_panic_handler(_: CrateNum) -> bool { + fatal_cycle + desc { "checking if the crate has_panic_handler" } + } + query is_sanitizer_runtime(_: CrateNum) -> bool { + fatal_cycle + desc { "query a crate is #![sanitizer_runtime]" } + } + query is_profiler_runtime(_: CrateNum) -> bool { + fatal_cycle + desc { "query a crate is #![profiler_runtime]" } + } + query panic_strategy(_: CrateNum) -> PanicStrategy { + fatal_cycle + desc { "query a crate's configured panic strategy" } + } + query is_no_builtins(_: CrateNum) -> bool { + fatal_cycle + desc { "test whether a crate has #![no_builtins]" } + } + + query extern_crate(_: DefId) -> Lrc<Option<ExternCrate>> { + eval_always + desc { "getting crate's ExternCrateData" } + } + } + + TypeChecking { + query specializes(_: (DefId, DefId)) -> bool { + no_force + desc { "computing whether impls specialize one another" } + } + query in_scope_traits_map(_: DefIndex) + -> Option<Lrc<FxHashMap<ItemLocalId, Lrc<StableVec<TraitCandidate>>>>> { + eval_always + desc { "traits in scope at a block" } + } + } + + Other { + query module_exports(_: DefId) -> Option<Lrc<Vec<Export>>> { + eval_always + } + } + + TypeChecking { + query impl_defaultness(_: DefId) -> hir::Defaultness {} + + query check_item_well_formed(_: DefId) -> () {} + query check_trait_item_well_formed(_: DefId) -> () {} + query check_impl_item_well_formed(_: DefId) -> () {} + } + + Linking { + // The DefIds of all non-generic functions and statics in the given crate + // that can be reached from outside the crate. + // + // We expect this items to be available for being linked to. + // + // This query can also be called for LOCAL_CRATE. In this case it will + // compute which items will be reachable to other crates, taking into account + // the kind of crate that is currently compiled. Crates with only a + // C interface have fewer reachable things. + // + // Does not include external symbols that don't have a corresponding DefId, + // like the compiler-generated `main` function and so on. + query reachable_non_generics(_: CrateNum) + -> Lrc<DefIdMap<SymbolExportLevel>> { + desc { "looking up the exported symbols of a crate" } + } + query is_reachable_non_generic(_: DefId) -> bool {} + query is_unreachable_local_definition(_: DefId) -> bool {} + } + + Codegen { + query upstream_monomorphizations( + k: CrateNum + ) -> Lrc<DefIdMap<Lrc<FxHashMap<SubstsRef<'tcx>, CrateNum>>>> { + desc { "collecting available upstream monomorphizations `{:?}`", k } + } + query upstream_monomorphizations_for(_: DefId) + -> Option<Lrc<FxHashMap<SubstsRef<'tcx>, CrateNum>>> {} + } + + Other { + query foreign_modules(_: CrateNum) -> Lrc<Vec<ForeignModule>> { + desc { "looking up the foreign modules of a linked crate" } + } + + /// Identifies the entry-point (e.g., the `main` function) for a given + /// crate, returning `None` if there is no entry point (such as for library crates). + query entry_fn(_: CrateNum) -> Option<(DefId, EntryFnType)> { + desc { "looking up the entry function of a crate" } + } + query plugin_registrar_fn(_: CrateNum) -> Option<DefId> { + desc { "looking up the plugin registrar for a crate" } + } + query proc_macro_decls_static(_: CrateNum) -> Option<DefId> { + desc { "looking up the derive registrar for a crate" } + } + query crate_disambiguator(_: CrateNum) -> CrateDisambiguator { + eval_always + desc { "looking up the disambiguator a crate" } + } + query crate_hash(_: CrateNum) -> Svh { + eval_always + desc { "looking up the hash a crate" } + } + query original_crate_name(_: CrateNum) -> Symbol { + eval_always + desc { "looking up the original name a crate" } + } + query extra_filename(_: CrateNum) -> String { + eval_always + desc { "looking up the extra filename for a crate" } + } + } + + TypeChecking { + query implementations_of_trait(_: (CrateNum, DefId)) + -> Lrc<Vec<DefId>> { + no_force + desc { "looking up implementations of a trait in a crate" } + } + query all_trait_implementations(_: CrateNum) + -> Lrc<Vec<DefId>> { + desc { "looking up all (?) trait implementations" } + } + } + + Other { + query dllimport_foreign_items(_: CrateNum) + -> Lrc<FxHashSet<DefId>> { + desc { "dllimport_foreign_items" } + } + query is_dllimport_foreign_item(_: DefId) -> bool {} + query is_statically_included_foreign_item(_: DefId) -> bool {} + query native_library_kind(_: DefId) + -> Option<NativeLibraryKind> {} + } + + Linking { + query link_args(_: CrateNum) -> Lrc<Vec<String>> { + eval_always + desc { "looking up link arguments for a crate" } + } + } + + BorrowChecking { + // Lifetime resolution. See `middle::resolve_lifetimes`. + query resolve_lifetimes(_: CrateNum) -> Lrc<ResolveLifetimes> { + desc { "resolving lifetimes" } + } + query named_region_map(_: DefIndex) -> + Option<Lrc<FxHashMap<ItemLocalId, Region>>> { + desc { "looking up a named region" } + } + query is_late_bound_map(_: DefIndex) -> + Option<Lrc<FxHashSet<ItemLocalId>>> { + desc { "testing if a region is late bound" } + } + query object_lifetime_defaults_map(_: DefIndex) + -> Option<Lrc<FxHashMap<ItemLocalId, Lrc<Vec<ObjectLifetimeDefault>>>>> { + desc { "looking up lifetime defaults for a region" } + } + } + + TypeChecking { + query visibility(_: DefId) -> ty::Visibility {} + } + + Other { + query dep_kind(_: CrateNum) -> DepKind { + eval_always + desc { "fetching what a dependency looks like" } + } + query crate_name(_: CrateNum) -> Symbol { + eval_always + desc { "fetching what a crate is named" } + } + query item_children(_: DefId) -> Lrc<Vec<Export>> {} + query extern_mod_stmt_cnum(_: DefId) -> Option<CrateNum> {} + + query get_lib_features(_: CrateNum) -> Lrc<LibFeatures> { + eval_always + desc { "calculating the lib features map" } + } + query defined_lib_features(_: CrateNum) + -> Lrc<Vec<(Symbol, Option<Symbol>)>> { + desc { "calculating the lib features defined in a crate" } + } + query get_lang_items(_: CrateNum) -> Lrc<LanguageItems> { + eval_always + desc { "calculating the lang items map" } + } + query defined_lang_items(_: CrateNum) -> Lrc<Vec<(DefId, usize)>> { + desc { "calculating the lang items defined in a crate" } + } + query missing_lang_items(_: CrateNum) -> Lrc<Vec<LangItem>> { + desc { "calculating the missing lang items in a crate" } + } + query visible_parent_map(_: CrateNum) + -> Lrc<DefIdMap<DefId>> { + desc { "calculating the visible parent map" } + } + query missing_extern_crate_item(_: CrateNum) -> bool { + eval_always + desc { "seeing if we're missing an `extern crate` item for this crate" } + } + query used_crate_source(_: CrateNum) -> Lrc<CrateSource> { + eval_always + desc { "looking at the source for a crate" } + } + query postorder_cnums(_: CrateNum) -> Lrc<Vec<CrateNum>> { + eval_always + desc { "generating a postorder list of CrateNums" } + } + + query freevars(_: DefId) -> Option<Lrc<Vec<hir::Freevar>>> { + eval_always + } + query maybe_unused_trait_import(_: DefId) -> bool { + eval_always + } + query maybe_unused_extern_crates(_: CrateNum) + -> Lrc<Vec<(DefId, Span)>> { + eval_always + desc { "looking up all possibly unused extern crates" } + } + query names_imported_by_glob_use(_: DefId) + -> Lrc<FxHashSet<ast::Name>> { + eval_always + } + + query stability_index(_: CrateNum) -> Lrc<stability::Index<'tcx>> { + eval_always + desc { "calculating the stability index for the local crate" } + } + query all_crate_nums(_: CrateNum) -> Lrc<Vec<CrateNum>> { + eval_always + desc { "fetching all foreign CrateNum instances" } + } + + /// A vector of every trait accessible in the whole crate + /// (i.e., including those from subcrates). This is used only for + /// error reporting. + query all_traits(_: CrateNum) -> Lrc<Vec<DefId>> { + desc { "fetching all foreign and local traits" } + } + } + + Linking { + query exported_symbols(_: CrateNum) + -> Arc<Vec<(ExportedSymbol<'tcx>, SymbolExportLevel)>> { + desc { "exported_symbols" } + } + } + + Codegen { + query collect_and_partition_mono_items(_: CrateNum) + -> (Arc<DefIdSet>, Arc<Vec<Arc<CodegenUnit<'tcx>>>>) { + eval_always + desc { "collect_and_partition_mono_items" } + } + query is_codegened_item(_: DefId) -> bool {} + query codegen_unit(_: InternedString) -> Arc<CodegenUnit<'tcx>> { + no_force + desc { "codegen_unit" } + } + query backend_optimization_level(_: CrateNum) -> OptLevel { + desc { "optimization level used by backend" } + } + } + + Other { + query output_filenames(_: CrateNum) -> Arc<OutputFilenames> { + eval_always + desc { "output_filenames" } + } + } + + TypeChecking { + /// Do not call this query directly: invoke `normalize` instead. + query normalize_projection_ty( + goal: CanonicalProjectionGoal<'tcx> + ) -> Result< + Lrc<Canonical<'tcx, canonical::QueryResponse<'tcx, NormalizationResult<'tcx>>>>, + NoSolution, + > { + no_force + desc { "normalizing `{:?}`", goal } + } + + /// Do not call this query directly: invoke `normalize_erasing_regions` instead. + query normalize_ty_after_erasing_regions( + goal: ParamEnvAnd<'tcx, Ty<'tcx>> + ) -> Ty<'tcx> { + no_force + desc { "normalizing `{:?}`", goal } + } + + query implied_outlives_bounds( + goal: CanonicalTyGoal<'tcx> + ) -> Result< + Lrc<Canonical<'tcx, canonical::QueryResponse<'tcx, Vec<OutlivesBound<'tcx>>>>>, + NoSolution, + > { + no_force + desc { "computing implied outlives bounds for `{:?}`", goal } + } + + /// Do not call this query directly: invoke `infcx.at().dropck_outlives()` instead. + query dropck_outlives( + goal: CanonicalTyGoal<'tcx> + ) -> Result< + Lrc<Canonical<'tcx, canonical::QueryResponse<'tcx, DropckOutlivesResult<'tcx>>>>, + NoSolution, + > { + no_force + desc { "computing dropck types for `{:?}`", goal } + } + + /// Do not call this query directly: invoke `infcx.predicate_may_hold()` or + /// `infcx.predicate_must_hold()` instead. + query evaluate_obligation( + goal: CanonicalPredicateGoal<'tcx> + ) -> Result<traits::EvaluationResult, traits::OverflowError> { + no_force + desc { "evaluating trait selection obligation `{}`", goal.value.value } + } + + query evaluate_goal( + goal: traits::ChalkCanonicalGoal<'tcx> + ) -> Result< + Lrc<Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>>, + NoSolution + > { + no_force + desc { "evaluating trait selection obligation `{}`", goal.value.goal } + } + + /// Do not call this query directly: part of the `Eq` type-op + query type_op_ascribe_user_type( + goal: CanonicalTypeOpAscribeUserTypeGoal<'tcx> + ) -> Result< + Lrc<Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>>, + NoSolution, + > { + no_force + desc { "evaluating `type_op_ascribe_user_type` `{:?}`", goal } + } + + /// Do not call this query directly: part of the `Eq` type-op + query type_op_eq( + goal: CanonicalTypeOpEqGoal<'tcx> + ) -> Result< + Lrc<Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>>, + NoSolution, + > { + no_force + desc { "evaluating `type_op_eq` `{:?}`", goal } + } + + /// Do not call this query directly: part of the `Subtype` type-op + query type_op_subtype( + goal: CanonicalTypeOpSubtypeGoal<'tcx> + ) -> Result< + Lrc<Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>>, + NoSolution, + > { + no_force + desc { "evaluating `type_op_subtype` `{:?}`", goal } + } + + /// Do not call this query directly: part of the `ProvePredicate` type-op + query type_op_prove_predicate( + goal: CanonicalTypeOpProvePredicateGoal<'tcx> + ) -> Result< + Lrc<Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>>, + NoSolution, + > { + no_force + desc { "evaluating `type_op_prove_predicate` `{:?}`", goal } + } + + /// Do not call this query directly: part of the `Normalize` type-op + query type_op_normalize_ty( + goal: CanonicalTypeOpNormalizeGoal<'tcx, Ty<'tcx>> + ) -> Result< + Lrc<Canonical<'tcx, canonical::QueryResponse<'tcx, Ty<'tcx>>>>, + NoSolution, + > { + no_force + desc { "normalizing `{:?}`", goal } + } + + /// Do not call this query directly: part of the `Normalize` type-op + query type_op_normalize_predicate( + goal: CanonicalTypeOpNormalizeGoal<'tcx, ty::Predicate<'tcx>> + ) -> Result< + Lrc<Canonical<'tcx, canonical::QueryResponse<'tcx, ty::Predicate<'tcx>>>>, + NoSolution, + > { + no_force + desc { "normalizing `{:?}`", goal } + } + + /// Do not call this query directly: part of the `Normalize` type-op + query type_op_normalize_poly_fn_sig( + goal: CanonicalTypeOpNormalizeGoal<'tcx, ty::PolyFnSig<'tcx>> + ) -> Result< + Lrc<Canonical<'tcx, canonical::QueryResponse<'tcx, ty::PolyFnSig<'tcx>>>>, + NoSolution, + > { + no_force + desc { "normalizing `{:?}`", goal } + } + + /// Do not call this query directly: part of the `Normalize` type-op + query type_op_normalize_fn_sig( + goal: CanonicalTypeOpNormalizeGoal<'tcx, ty::FnSig<'tcx>> + ) -> Result< + Lrc<Canonical<'tcx, canonical::QueryResponse<'tcx, ty::FnSig<'tcx>>>>, + NoSolution, + > { + no_force + desc { "normalizing `{:?}`", goal } + } + + query substitute_normalize_and_test_predicates(key: (DefId, SubstsRef<'tcx>)) -> bool { + no_force + desc { |tcx| + "testing substituted normalized predicates:`{}`", + tcx.def_path_str(key.0) + } + } + + query method_autoderef_steps( + goal: CanonicalTyGoal<'tcx> + ) -> MethodAutoderefStepsResult<'tcx> { + no_force + desc { "computing autoderef types for `{:?}`", goal } + } + } + + Other { + query target_features_whitelist(_: CrateNum) -> Lrc<FxHashMap<String, Option<String>>> { + eval_always + desc { "looking up the whitelist of target features" } + } + + // Get an estimate of the size of an InstanceDef based on its MIR for CGU partitioning. + query instance_def_size_estimate(def: ty::InstanceDef<'tcx>) + -> usize { + no_force + desc { |tcx| "estimating size for `{}`", tcx.def_path_str(def.def_id()) } + } + + query features_query(_: CrateNum) -> Lrc<feature_gate::Features> { + eval_always + desc { "looking up enabled feature gates" } + } + } } diff --git a/src/librustc/session/code_stats.rs b/src/librustc/session/code_stats.rs index 730abacf6f6..0f535249b5e 100644 --- a/src/librustc/session/code_stats.rs +++ b/src/librustc/session/code_stats.rs @@ -57,7 +57,13 @@ impl CodeStats { overall_size: Size, packed: bool, opt_discr_size: Option<Size>, - variants: Vec<VariantInfo>) { + mut variants: Vec<VariantInfo>) { + // Sort variants so the largest ones are shown first. A stable sort is + // used here so that source code order is preserved for all variants + // that have the same size. + variants.sort_by(|info1, info2| { + info2.size.cmp(&info1.size) + }); let info = TypeSizeInfo { kind, type_description: type_desc.to_string(), diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 988e4a9ff23..7c0eab26b09 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -113,6 +113,21 @@ impl LinkerPluginLto { } } +#[derive(Clone, PartialEq, Hash)] +pub enum PgoGenerate { + Enabled(Option<PathBuf>), + Disabled, +} + +impl PgoGenerate { + pub fn enabled(&self) -> bool { + match *self { + PgoGenerate::Enabled(_) => true, + PgoGenerate::Disabled => false, + } + } +} + #[derive(Clone, Copy, PartialEq, Hash)] pub enum DebugInfo { None, @@ -826,13 +841,15 @@ macro_rules! options { pub const parse_linker_plugin_lto: Option<&str> = Some("either a boolean (`yes`, `no`, `on`, `off`, etc), \ or the path to the linker plugin"); + pub const parse_pgo_generate: Option<&str> = + Some("an optional path to the profiling data output directory"); pub const parse_merge_functions: Option<&str> = Some("one of: `disabled`, `trampolines`, or `aliases`"); } #[allow(dead_code)] mod $mod_set { - use super::{$struct_name, Passes, Sanitizer, LtoCli, LinkerPluginLto}; + use super::{$struct_name, Passes, Sanitizer, LtoCli, LinkerPluginLto, PgoGenerate}; use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, RelroLevel}; use std::path::PathBuf; use std::str::FromStr; @@ -1087,6 +1104,14 @@ macro_rules! options { true } + fn parse_pgo_generate(slot: &mut PgoGenerate, v: Option<&str>) -> bool { + *slot = match v { + None => PgoGenerate::Enabled(None), + Some(path) => PgoGenerate::Enabled(Some(PathBuf::from(path))), + }; + true + } + fn parse_merge_functions(slot: &mut Option<MergeFunctions>, v: Option<&str>) -> bool { match v.and_then(|s| MergeFunctions::from_str(s).ok()) { Some(mergefunc) => *slot = Some(mergefunc), @@ -1363,7 +1388,7 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "extra arguments to prepend to the linker invocation (space separated)"), profile: bool = (false, parse_bool, [TRACKED], "insert profiling code"), - pgo_gen: Option<String> = (None, parse_opt_string, [TRACKED], + pgo_gen: PgoGenerate = (PgoGenerate::Disabled, parse_pgo_generate, [TRACKED], "Generate PGO profile data, to a given file, or to the default location if it's empty."), pgo_use: String = (String::new(), parse_string, [TRACKED], "Use PGO profile data from the given profile file."), @@ -1980,7 +2005,7 @@ pub fn build_session_options_and_crate_config( ); } - if debugging_opts.pgo_gen.is_some() && !debugging_opts.pgo_use.is_empty() { + if debugging_opts.pgo_gen.enabled() && !debugging_opts.pgo_use.is_empty() { early_error( error_format, "options `-Z pgo-gen` and `-Z pgo-use` are exclusive", @@ -2490,7 +2515,7 @@ mod dep_tracking { use std::path::PathBuf; use std::collections::hash_map::DefaultHasher; use super::{CrateType, DebugInfo, ErrorOutputType, OptLevel, OutputTypes, - Passes, Sanitizer, LtoCli, LinkerPluginLto}; + Passes, Sanitizer, LtoCli, LinkerPluginLto, PgoGenerate}; use syntax::feature_gate::UnstableFeatures; use rustc_target::spec::{MergeFunctions, PanicStrategy, RelroLevel, TargetTriple}; use syntax::edition::Edition; @@ -2558,6 +2583,7 @@ mod dep_tracking { impl_dep_tracking_hash_via_hash!(TargetTriple); impl_dep_tracking_hash_via_hash!(Edition); impl_dep_tracking_hash_via_hash!(LinkerPluginLto); + impl_dep_tracking_hash_via_hash!(PgoGenerate); impl_dep_tracking_hash_for_sortable_vec_of!(String); impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf); @@ -2625,7 +2651,7 @@ mod tests { build_session_options_and_crate_config, to_crate_config }; - use crate::session::config::{LtoCli, LinkerPluginLto}; + use crate::session::config::{LtoCli, LinkerPluginLto, PgoGenerate}; use crate::session::build_session; use crate::session::search_paths::SearchPath; use std::collections::{BTreeMap, BTreeSet}; @@ -3124,7 +3150,7 @@ mod tests { assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash()); opts = reference.clone(); - opts.debugging_opts.pgo_gen = Some(String::from("abc")); + opts.debugging_opts.pgo_gen = PgoGenerate::Enabled(None); assert_ne!(reference.dep_tracking_hash(), opts.dep_tracking_hash()); opts = reference.clone(); diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 2f3df32945c..a1966c02683 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -46,8 +46,6 @@ use std::path::PathBuf; use std::time::Duration; use std::sync::{Arc, mpsc}; -use parking_lot::Mutex as PlMutex; - mod code_stats; pub mod config; pub mod filesearch; @@ -130,7 +128,7 @@ pub struct Session { pub profile_channel: Lock<Option<mpsc::Sender<ProfileQueriesMsg>>>, /// Used by -Z self-profile - pub self_profiling: Option<Arc<PlMutex<SelfProfiler>>>, + pub self_profiling: Option<Arc<SelfProfiler>>, /// Some measurements that are being gathered during compilation. pub perf_stats: PerfStats, @@ -166,7 +164,7 @@ pub struct Session { pub driver_lint_caps: FxHashMap<lint::LintId, lint::Level>, /// `Span`s of trait methods that weren't found to avoid emitting object safety errors - pub trait_methods_not_found: OneThread<RefCell<FxHashSet<Span>>>, + pub trait_methods_not_found: Lock<FxHashSet<Span>>, } pub struct PerfStats { @@ -838,19 +836,17 @@ impl Session { #[inline(never)] #[cold] - fn profiler_active<F: FnOnce(&mut SelfProfiler) -> ()>(&self, f: F) { + fn profiler_active<F: FnOnce(&SelfProfiler) -> ()>(&self, f: F) { match &self.self_profiling { None => bug!("profiler_active() called but there was no profiler active"), Some(profiler) => { - let mut p = profiler.lock(); - - f(&mut p); + f(&profiler); } } } #[inline(always)] - pub fn profiler<F: FnOnce(&mut SelfProfiler) -> ()>(&self, f: F) { + pub fn profiler<F: FnOnce(&SelfProfiler) -> ()>(&self, f: F) { if unlikely!(self.self_profiling.is_some()) { self.profiler_active(f) } @@ -1138,7 +1134,19 @@ fn build_session_( driver_lint_caps: FxHashMap<lint::LintId, lint::Level>, ) -> Session { let self_profiler = - if sopts.debugging_opts.self_profile { Some(Arc::new(PlMutex::new(SelfProfiler::new()))) } + if sopts.debugging_opts.self_profile { + let profiler = SelfProfiler::new(); + match profiler { + Ok(profiler) => { + crate::ty::query::QueryName::register_with_profiler(&profiler); + Some(Arc::new(profiler)) + }, + Err(e) => { + early_warn(sopts.error_format, &format!("failed to create profiler: {}", e)); + None + } + } + } else { None }; let host_triple = TargetTriple::from_triple(config::host_triple()); @@ -1236,7 +1244,7 @@ fn build_session_( has_global_allocator: Once::new(), has_panic_handler: Once::new(), driver_lint_caps, - trait_methods_not_found: OneThread::new(RefCell::new(Default::default())), + trait_methods_not_found: Lock::new(Default::default()), }; validate_commandline_args_with_session_available(&sess); diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 78c80b48ee8..b875bfdfa9f 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -26,7 +26,6 @@ use crate::infer::{InferCtxt, SuppressRegionErrors}; use crate::infer::outlives::env::OutlivesEnvironment; use crate::middle::region; use crate::mir::interpret::ErrorHandled; -use rustc_data_structures::sync::Lrc; use rustc_macros::HashStable; use syntax::ast; use syntax_pos::{Span, DUMMY_SP}; @@ -227,6 +226,7 @@ pub enum ObligationCauseCode<'tcx> { source: hir::MatchSource, prior_arms: Vec<Span>, last_ty: Ty<'tcx>, + discrim_hir_id: hir::HirId, }, /// Computing common supertype in the pattern guard for the arms of a match expression @@ -984,11 +984,11 @@ fn substitute_normalize_and_test_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx fn vtable_methods<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_ref: ty::PolyTraitRef<'tcx>) - -> Lrc<Vec<Option<(DefId, SubstsRef<'tcx>)>>> + -> &'tcx [Option<(DefId, SubstsRef<'tcx>)>] { debug!("vtable_methods({:?})", trait_ref); - Lrc::new( + tcx.arena.alloc_from_iter( supertraits(tcx, trait_ref).flat_map(move |trait_ref| { let trait_methods = tcx.associated_items(trait_ref.def_id()) .filter(|item| item.kind == ty::AssociatedKind::Method); @@ -1039,7 +1039,7 @@ fn vtable_methods<'a, 'tcx>( Some((def_id, substs)) }) - }).collect() + }) ) } diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index c576586fcad..384a5862cde 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -16,7 +16,6 @@ use crate::infer::{InferCtxt, InferOk}; use crate::lint; use crate::traits::{self, coherence, FutureCompatOverlapErrorKind, ObligationCause, TraitEngine}; use rustc_data_structures::fx::FxHashSet; -use rustc_data_structures::sync::Lrc; use syntax_pos::DUMMY_SP; use crate::traits::select::IntercrateAmbiguityCause; use crate::ty::{self, TyCtxt, TypeFoldable}; @@ -289,7 +288,7 @@ fn fulfill_implication<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, pub(super) fn specialization_graph_provider<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_id: DefId, -) -> Lrc<specialization_graph::Graph> { +) -> &'tcx specialization_graph::Graph { let mut sg = specialization_graph::Graph::new(); let mut trait_impls = tcx.all_impls(trait_id); @@ -383,7 +382,7 @@ pub(super) fn specialization_graph_provider<'a, 'tcx>( } } - Lrc::new(sg) + tcx.arena.alloc(sg) } /// Recovers the "impl X for Y" signature from `impl_def_id` and returns it as a diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc/traits/specialize/specialization_graph.rs index 561859c7c31..dae1518d722 100644 --- a/src/librustc/traits/specialize/specialization_graph.rs +++ b/src/librustc/traits/specialize/specialization_graph.rs @@ -7,7 +7,6 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher, use crate::traits; use crate::ty::{self, TyCtxt, TypeFoldable}; use crate::ty::fast_reject::{self, SimplifiedType}; -use rustc_data_structures::sync::Lrc; use syntax::ast::Ident; use crate::util::captures::Captures; use crate::util::nodemap::{DefIdMap, FxHashMap}; @@ -439,13 +438,13 @@ impl<'a, 'gcx, 'tcx> Node { } } -pub struct Ancestors { +pub struct Ancestors<'tcx> { trait_def_id: DefId, - specialization_graph: Lrc<Graph>, + specialization_graph: &'tcx Graph, current_source: Option<Node>, } -impl Iterator for Ancestors { +impl Iterator for Ancestors<'_> { type Item = Node; fn next(&mut self) -> Option<Node> { let cur = self.current_source.take(); @@ -476,7 +475,7 @@ impl<T> NodeItem<T> { } } -impl<'a, 'gcx, 'tcx> Ancestors { +impl<'a, 'gcx, 'tcx> Ancestors<'gcx> { /// Search the items from the given ancestors, returning each definition /// with the given name and the given kind. // FIXME(#35870): avoid closures being unexported due to `impl Trait`. @@ -509,10 +508,10 @@ impl<'a, 'gcx, 'tcx> Ancestors { /// Walk up the specialization ancestors of a given impl, starting with that /// impl itself. -pub fn ancestors(tcx: TyCtxt<'_, '_, '_>, +pub fn ancestors(tcx: TyCtxt<'_, 'tcx, '_>, trait_def_id: DefId, start_from_impl: DefId) - -> Ancestors { + -> Ancestors<'tcx> { let specialization_graph = tcx.specialization_graph_of(trait_def_id); Ancestors { trait_def_id, diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index f3a800bf46d..0711f3539e5 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -519,6 +519,7 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> { source, ref prior_arms, last_ty, + discrim_hir_id, } => { tcx.lift(&last_ty).map(|last_ty| { super::MatchExpressionArm { @@ -526,6 +527,7 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> { source, prior_arms: prior_arms.clone(), last_ty, + discrim_hir_id, } }) } diff --git a/src/librustc/ty/codec.rs b/src/librustc/ty/codec.rs index e7474345c00..a76cc3dfdec 100644 --- a/src/librustc/ty/codec.rs +++ b/src/librustc/ty/codec.rs @@ -6,6 +6,7 @@ // The functionality in here is shared between persisting to crate metadata and // persisting to incr. comp. caches. +use crate::arena::ArenaAllocatable; use crate::hir::def_id::{DefId, CrateNum}; use crate::infer::canonical::{CanonicalVarInfo, CanonicalVarInfos}; use rustc_data_structures::fx::FxHashMap; @@ -131,6 +132,26 @@ pub trait TyDecoder<'a, 'tcx: 'a>: Decoder { } #[inline] +pub fn decode_arena_allocable<'a, 'tcx, D, T: ArenaAllocatable + Decodable>( + decoder: &mut D +) -> Result<&'tcx T, D::Error> + where D: TyDecoder<'a, 'tcx>, + 'tcx: 'a, +{ + Ok(decoder.tcx().arena.alloc(Decodable::decode(decoder)?)) +} + +#[inline] +pub fn decode_arena_allocable_slice<'a, 'tcx, D, T: ArenaAllocatable + Decodable>( + decoder: &mut D +) -> Result<&'tcx [T], D::Error> + where D: TyDecoder<'a, 'tcx>, + 'tcx: 'a, +{ + Ok(decoder.tcx().arena.alloc_from_iter(<Vec<T> as Decodable>::decode(decoder)?)) +} + +#[inline] pub fn decode_cnum<'a, 'tcx, D>(decoder: &mut D) -> Result<CrateNum, D::Error> where D: TyDecoder<'a, 'tcx>, 'tcx: 'a, @@ -274,6 +295,39 @@ macro_rules! __impl_decoder_methods { } #[macro_export] +macro_rules! impl_arena_allocatable_decoder { + ([]$args:tt) => {}; + ([decode $(, $attrs:ident)*] + [[$DecoderName:ident [$($typaram:tt),*]], [$name:ident: $ty:ty], $tcx:lifetime]) => { + impl<$($typaram),*> SpecializedDecoder<&$tcx $ty> for $DecoderName<$($typaram),*> { + #[inline] + fn specialized_decode(&mut self) -> Result<&$tcx $ty, Self::Error> { + decode_arena_allocable(self) + } + } + + impl<$($typaram),*> SpecializedDecoder<&$tcx [$ty]> for $DecoderName<$($typaram),*> { + #[inline] + fn specialized_decode(&mut self) -> Result<&$tcx [$ty], Self::Error> { + decode_arena_allocable_slice(self) + } + } + }; + ([$ignore:ident $(, $attrs:ident)*]$args:tt) => { + impl_arena_allocatable_decoder!([$($attrs),*]$args); + }; +} + +#[macro_export] +macro_rules! impl_arena_allocatable_decoders { + ($args:tt, [$($a:tt $name:ident: $ty:ty,)*], $tcx:lifetime) => { + $( + impl_arena_allocatable_decoder!($a [$args, [$name: $ty], $tcx]); + )* + } +} + +#[macro_export] macro_rules! implement_ty_decoder { ($DecoderName:ident <$($typaram:tt),*>) => { mod __ty_decoder_impl { @@ -322,6 +376,8 @@ macro_rules! implement_ty_decoder { // the caller to pick any lifetime for 'tcx, including 'static, // by using the unspecialized proxies to them. + arena_types!(impl_arena_allocatable_decoders, [$DecoderName [$($typaram),*]], 'tcx); + impl<$($typaram),*> SpecializedDecoder<CrateNum> for $DecoderName<$($typaram),*> { fn specialized_decode(&mut self) -> Result<CrateNum, Self::Error> { diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 77330c7a9d1..7dc4dee3fbf 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -1,5 +1,6 @@ //! Type context book-keeping. +use crate::arena::Arena; use crate::dep_graph::DepGraph; use crate::dep_graph::{self, DepNode, DepConstructor}; use crate::session::Session; @@ -125,7 +126,7 @@ pub struct CtxtInterners<'tcx> { clauses: InternedSet<'tcx, List<Clause<'tcx>>>, goal: InternedSet<'tcx, GoalKind<'tcx>>, goal_list: InternedSet<'tcx, List<Goal<'tcx>>>, - projs: InternedSet<'tcx, List<ProjectionKind<'tcx>>>, + projs: InternedSet<'tcx, List<ProjectionKind>>, const_: InternedSet<'tcx, Const<'tcx>>, } @@ -219,6 +220,11 @@ pub struct CommonTypes<'tcx> { pub never: Ty<'tcx>, pub err: Ty<'tcx>, + /// Dummy type used for the `Self` of a `TraitRef` created for converting + /// a trait object, and which gets removed in `ExistentialTraitRef`. + /// This type must not appear anywhere in other converted types. + pub trait_object_dummy_self: Ty<'tcx>, + pub re_empty: Region<'tcx>, pub re_static: Region<'tcx>, pub re_erased: Region<'tcx>, @@ -955,6 +961,8 @@ impl<'tcx> CommonTypes<'tcx> { f32: mk(Float(ast::FloatTy::F32)), f64: mk(Float(ast::FloatTy::F64)), + trait_object_dummy_self: mk(Infer(ty::FreshTy(0))), + re_empty: mk_region(RegionKind::ReEmpty), re_static: mk_region(RegionKind::ReStatic), re_erased: mk_region(RegionKind::ReErased), @@ -996,6 +1004,7 @@ impl<'gcx> Deref for TyCtxt<'_, 'gcx, '_> { } pub struct GlobalCtxt<'tcx> { + pub arena: WorkerLocal<Arena<'tcx>>, global_arenas: &'tcx WorkerLocal<GlobalArenas<'tcx>>, global_interners: CtxtInterners<'tcx>, @@ -1255,6 +1264,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { GlobalCtxt { sess: s, cstore, + arena: WorkerLocal::new(|_| Arena::default()), global_arenas: &arenas.global, global_interners: interners, dep_graph, @@ -1802,7 +1812,7 @@ nop_list_lift!{Ty<'a> => Ty<'tcx>} nop_list_lift!{ExistentialPredicate<'a> => ExistentialPredicate<'tcx>} nop_list_lift!{Predicate<'a> => Predicate<'tcx>} nop_list_lift!{CanonicalVarInfo => CanonicalVarInfo} -nop_list_lift!{ProjectionKind<'a> => ProjectionKind<'tcx>} +nop_list_lift!{ProjectionKind => ProjectionKind} // this is the impl for `&'a InternalSubsts<'a>` nop_list_lift!{Kind<'a> => Kind<'tcx>} @@ -2261,9 +2271,9 @@ impl<'tcx: 'lcx, 'lcx> Borrow<[Kind<'lcx>]> for Interned<'tcx, InternalSubsts<'t } } -impl<'tcx: 'lcx, 'lcx> Borrow<[ProjectionKind<'lcx>]> - for Interned<'tcx, List<ProjectionKind<'tcx>>> { - fn borrow<'a>(&'a self) -> &'a [ProjectionKind<'lcx>] { +impl<'tcx> Borrow<[ProjectionKind]> + for Interned<'tcx, List<ProjectionKind>> { + fn borrow<'a>(&'a self) -> &'a [ProjectionKind] { &self.0[..] } } @@ -2391,22 +2401,22 @@ direct_interners!('tcx, ); macro_rules! slice_interners { - ($($field:ident: $method:ident($ty:ident)),+) => ( + ($($field:ident: $method:ident($ty:ty)),+) => ( $(intern_method!( 'tcx, $field: $method( - &[$ty<'tcx>], + &[$ty], |a, v| List::from_arena(a, v), Deref::deref, - |xs: &[$ty<'_>]| xs.iter().any(keep_local)) -> List<$ty<'tcx>>);)+ - ) + |xs: &[$ty]| xs.iter().any(keep_local)) -> List<$ty>);)+ + ); } slice_interners!( - existential_predicates: _intern_existential_predicates(ExistentialPredicate), - predicates: _intern_predicates(Predicate), - type_list: _intern_type_list(Ty), - substs: _intern_substs(Kind), - clauses: _intern_clauses(Clause), - goal_list: _intern_goals(Goal), + existential_predicates: _intern_existential_predicates(ExistentialPredicate<'tcx>), + predicates: _intern_predicates(Predicate<'tcx>), + type_list: _intern_type_list(Ty<'tcx>), + substs: _intern_substs(Kind<'tcx>), + clauses: _intern_clauses(Clause<'tcx>), + goal_list: _intern_goals(Goal<'tcx>), projs: _intern_projs(ProjectionKind) ); @@ -2774,7 +2784,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } - pub fn intern_projs(self, ps: &[ProjectionKind<'tcx>]) -> &'tcx List<ProjectionKind<'tcx>> { + pub fn intern_projs(self, ps: &[ProjectionKind]) -> &'tcx List<ProjectionKind> { if ps.len() == 0 { List::empty() } else { diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index e01b50113b9..fd1d3a91ede 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -920,6 +920,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { niche_variants, niche_start, }, + discr_index: 0, variants: st, }, fields: FieldPlacement::Arbitrary { @@ -1142,6 +1143,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { variants: Variants::Multiple { discr: tag, discr_kind: DiscriminantKind::Tag, + discr_index: 0, variants: layout_variants, }, fields: FieldPlacement::Arbitrary { @@ -1884,10 +1886,12 @@ impl<'a> HashStable<StableHashingContext<'a>> for Variants { Multiple { ref discr, ref discr_kind, + discr_index, ref variants, } => { discr.hash_stable(hcx, hasher); discr_kind.hash_stable(hcx, hasher); + discr_index.hash_stable(hcx, hasher); variants.hash_stable(hcx, hasher); } } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 102057c1380..7d47867cea1 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1,3 +1,5 @@ +#![cfg_attr(not(stage0), allow(usage_of_ty_tykind))] + pub use self::Variance::*; pub use self::AssociatedItemContainer::*; pub use self::BorrowKind::*; diff --git a/src/librustc/ty/query/config.rs b/src/librustc/ty/query/config.rs index bc5caffb934..0eda92ea8b8 100644 --- a/src/librustc/ty/query/config.rs +++ b/src/librustc/ty/query/config.rs @@ -1,17 +1,9 @@ use crate::dep_graph::SerializedDepNodeIndex; use crate::dep_graph::DepNode; -use crate::hir::def_id::{CrateNum, DefId, DefIndex}; -use crate::mir::interpret::GlobalId; -use crate::traits; -use crate::traits::query::{ - CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal, - CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal, - CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal, -}; -use crate::ty::{self, ParamEnvAnd, Ty, TyCtxt}; -use crate::ty::subst::SubstsRef; +use crate::hir::def_id::{CrateNum, DefId}; +use crate::ty::TyCtxt; use crate::ty::query::queries; -use crate::ty::query::Query; +use crate::ty::query::{Query, QueryName}; use crate::ty::query::QueryCache; use crate::ty::query::plumbing::CycleError; use crate::util::profiling::ProfileCategory; @@ -19,7 +11,6 @@ use crate::util::profiling::ProfileCategory; use std::borrow::Cow; use std::hash::Hash; use std::fmt::Debug; -use syntax_pos::symbol::InternedString; use rustc_data_structures::sync::Lock; use rustc_data_structures::fingerprint::Fingerprint; use crate::ich::StableHashingContext; @@ -27,7 +18,7 @@ use crate::ich::StableHashingContext; // Query configuration and description traits. pub trait QueryConfig<'tcx> { - const NAME: &'static str; + const NAME: QueryName; const CATEGORY: ProfileCategory; type Key: Eq + Hash + Clone + Debug; @@ -79,843 +70,12 @@ impl<'tcx, M: QueryAccessors<'tcx, Key=DefId>> QueryDescription<'tcx> for M { } } -impl<'tcx> QueryDescription<'tcx> for queries::check_mod_attrs<'tcx> { - fn describe( - tcx: TyCtxt<'_, '_, '_>, - key: DefId, - ) -> Cow<'static, str> { - format!("checking attributes in {}", key.describe_as_module(tcx)).into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::check_mod_unstable_api_usage<'tcx> { - fn describe( - tcx: TyCtxt<'_, '_, '_>, - key: DefId, - ) -> Cow<'static, str> { - format!("checking for unstable API usage in {}", key.describe_as_module(tcx)).into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::check_mod_loops<'tcx> { - fn describe( - tcx: TyCtxt<'_, '_, '_>, - key: DefId, - ) -> Cow<'static, str> { - format!("checking loops in {}", key.describe_as_module(tcx)).into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::check_mod_item_types<'tcx> { - fn describe( - tcx: TyCtxt<'_, '_, '_>, - key: DefId, - ) -> Cow<'static, str> { - format!("checking item types in {}", key.describe_as_module(tcx)).into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::check_mod_privacy<'tcx> { - fn describe( - tcx: TyCtxt<'_, '_, '_>, - key: DefId, - ) -> Cow<'static, str> { - format!("checking privacy in {}", key.describe_as_module(tcx)).into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::check_mod_intrinsics<'tcx> { - fn describe( - tcx: TyCtxt<'_, '_, '_>, - key: DefId, - ) -> Cow<'static, str> { - format!("checking intrinsics in {}", key.describe_as_module(tcx)).into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::check_mod_liveness<'tcx> { - fn describe( - tcx: TyCtxt<'_, '_, '_>, - key: DefId, - ) -> Cow<'static, str> { - format!("checking liveness of variables in {}", key.describe_as_module(tcx)).into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::check_mod_impl_wf<'tcx> { - fn describe( - tcx: TyCtxt<'_, '_, '_>, - key: DefId, - ) -> Cow<'static, str> { - format!("checking that impls are well-formed in {}", key.describe_as_module(tcx)).into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::collect_mod_item_types<'tcx> { - fn describe( - tcx: TyCtxt<'_, '_, '_>, - key: DefId, - ) -> Cow<'static, str> { - format!("collecting item types in {}", key.describe_as_module(tcx)).into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::normalize_projection_ty<'tcx> { - fn describe( - _tcx: TyCtxt<'_, '_, '_>, - goal: CanonicalProjectionGoal<'tcx>, - ) -> Cow<'static, str> { - format!("normalizing `{:?}`", goal).into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::implied_outlives_bounds<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, goal: CanonicalTyGoal<'tcx>) -> Cow<'static, str> { - format!("computing implied outlives bounds for `{:?}`", goal).into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::dropck_outlives<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, goal: CanonicalTyGoal<'tcx>) -> Cow<'static, str> { - format!("computing dropck types for `{:?}`", goal).into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::normalize_ty_after_erasing_regions<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, goal: ParamEnvAnd<'tcx, Ty<'tcx>>) -> Cow<'static, str> { - format!("normalizing `{:?}`", goal).into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::evaluate_obligation<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, goal: CanonicalPredicateGoal<'tcx>) -> Cow<'static, str> { - format!("evaluating trait selection obligation `{}`", goal.value.value).into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::evaluate_goal<'tcx> { - fn describe( - _tcx: TyCtxt<'_, '_, '_>, - goal: traits::ChalkCanonicalGoal<'tcx> - ) -> Cow<'static, str> { - format!("evaluating trait selection obligation `{}`", goal.value.goal).into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::type_op_ascribe_user_type<'tcx> { - fn describe( - _tcx: TyCtxt<'_, '_, '_>, - goal: CanonicalTypeOpAscribeUserTypeGoal<'tcx>, - ) -> Cow<'static, str> { - format!("evaluating `type_op_ascribe_user_type` `{:?}`", goal).into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::type_op_eq<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, goal: CanonicalTypeOpEqGoal<'tcx>) -> Cow<'static, str> { - format!("evaluating `type_op_eq` `{:?}`", goal).into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::type_op_subtype<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, goal: CanonicalTypeOpSubtypeGoal<'tcx>) - -> Cow<'static, str> { - format!("evaluating `type_op_subtype` `{:?}`", goal).into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::type_op_prove_predicate<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, goal: CanonicalTypeOpProvePredicateGoal<'tcx>) - -> Cow<'static, str> { - format!("evaluating `type_op_prove_predicate` `{:?}`", goal).into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::type_op_normalize_ty<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, - goal: CanonicalTypeOpNormalizeGoal<'tcx, Ty<'tcx>>) -> Cow<'static, str> { - format!("normalizing `{:?}`", goal).into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::type_op_normalize_predicate<'tcx> { - fn describe( - _tcx: TyCtxt<'_, '_, '_>, - goal: CanonicalTypeOpNormalizeGoal<'tcx, ty::Predicate<'tcx>>, - ) -> Cow<'static, str> { - format!("normalizing `{:?}`", goal).into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::type_op_normalize_poly_fn_sig<'tcx> { - fn describe( - _tcx: TyCtxt<'_, '_, '_>, - goal: CanonicalTypeOpNormalizeGoal<'tcx, ty::PolyFnSig<'tcx>>, - ) -> Cow<'static, str> { - format!("normalizing `{:?}`", goal).into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::type_op_normalize_fn_sig<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, - goal: CanonicalTypeOpNormalizeGoal<'tcx, ty::FnSig<'tcx>>) -> Cow<'static, str> { - format!("normalizing `{:?}`", goal).into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::is_copy_raw<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) - -> Cow<'static, str> { - format!("computing whether `{}` is `Copy`", env.value).into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::is_sized_raw<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) - -> Cow<'static, str> { - format!("computing whether `{}` is `Sized`", env.value).into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::is_freeze_raw<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) - -> Cow<'static, str> { - format!("computing whether `{}` is freeze", env.value).into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::needs_drop_raw<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) - -> Cow<'static, str> { - format!("computing whether `{}` needs drop", env.value).into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::layout_raw<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) - -> Cow<'static, str> { - format!("computing layout of `{}`", env.value).into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::super_predicates_of<'tcx> { - fn describe(tcx: TyCtxt<'_, '_, '_>, def_id: DefId) -> Cow<'static, str> { - format!("computing the supertraits of `{}`", - tcx.def_path_str(def_id)).into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::type_param_predicates<'tcx> { - fn describe(tcx: TyCtxt<'_, '_, '_>, (_, def_id): (DefId, DefId)) -> Cow<'static, str> { - let id = tcx.hir().as_local_hir_id(def_id).unwrap(); - format!("computing the bounds for type parameter `{}`", - tcx.hir().ty_param_name(id)).into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::coherent_trait<'tcx> { - fn describe(tcx: TyCtxt<'_, '_, '_>, def_id: DefId) -> Cow<'static, str> { - format!("coherence checking all impls of trait `{}`", - tcx.def_path_str(def_id)).into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::upstream_monomorphizations<'tcx> { - fn describe(_: TyCtxt<'_, '_, '_>, k: CrateNum) -> Cow<'static, str> { - format!("collecting available upstream monomorphizations `{:?}`", k).into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::crate_inherent_impls<'tcx> { - fn describe(_: TyCtxt<'_, '_, '_>, k: CrateNum) -> Cow<'static, str> { - format!("all inherent impls defined in crate `{:?}`", k).into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::crate_inherent_impls_overlap_check<'tcx> { - fn describe(_: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> { - "check for overlap between inherent impls defined in this crate".into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::crate_variances<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> { - "computing the variances for items in this crate".into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::inferred_outlives_crate<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> { - "computing the inferred outlives predicates for items in this crate".into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::mir_shims<'tcx> { - fn describe(tcx: TyCtxt<'_, '_, '_>, def: ty::InstanceDef<'tcx>) -> Cow<'static, str> { - format!("generating MIR shim for `{}`", - tcx.def_path_str(def.def_id())).into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::privacy_access_levels<'tcx> { - fn describe(_: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> { - "privacy access levels".into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::check_private_in_public<'tcx> { - fn describe(_: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> { - "checking for private elements in public interfaces".into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::typeck_item_bodies<'tcx> { - fn describe(_: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> { - "type-checking all item bodies".into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::reachable_set<'tcx> { - fn describe(_: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> { - "reachability".into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::const_eval<'tcx> { - fn describe( - tcx: TyCtxt<'_, '_, '_>, - key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, - ) -> Cow<'static, str> { - format!( - "const-evaluating + checking `{}`", - tcx.def_path_str(key.value.instance.def.def_id()), - ).into() - } - - #[inline] - fn cache_on_disk(_: TyCtxt<'_, 'tcx, 'tcx>, _key: Self::Key) -> bool { - true - } - - #[inline] - fn try_load_from_disk<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - id: SerializedDepNodeIndex) - -> Option<Self::Value> { - tcx.queries.on_disk_cache.try_load_query_result(tcx, id).map(Ok) - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::const_eval_raw<'tcx> { - fn describe(tcx: TyCtxt<'_, '_, '_>, key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) - -> Cow<'static, str> - { - format!("const-evaluating `{}`", tcx.def_path_str(key.value.instance.def.def_id())).into() - } - - #[inline] - fn cache_on_disk(_: TyCtxt<'_, 'tcx, 'tcx>, _key: Self::Key) -> bool { - true - } - - #[inline] - fn try_load_from_disk<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - id: SerializedDepNodeIndex) - -> Option<Self::Value> { - tcx.queries.on_disk_cache.try_load_query_result(tcx, id).map(Ok) - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::symbol_name<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, instance: ty::Instance<'tcx>) -> Cow<'static, str> { - format!("computing the symbol for `{}`", instance).into() - } - - #[inline] - fn cache_on_disk(_: TyCtxt<'_, 'tcx, 'tcx>, _: Self::Key) -> bool { - true - } - - #[inline] - fn try_load_from_disk<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - id: SerializedDepNodeIndex) - -> Option<Self::Value> { - tcx.queries.on_disk_cache.try_load_query_result(tcx, id) - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::describe_def<'tcx> { - fn describe(_: TyCtxt<'_, '_, '_>, _: DefId) -> Cow<'static, str> { - bug!("describe_def") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::def_span<'tcx> { - fn describe(_: TyCtxt<'_, '_, '_>, _: DefId) -> Cow<'static, str> { - bug!("def_span") - } -} - - -impl<'tcx> QueryDescription<'tcx> for queries::lookup_stability<'tcx> { - fn describe(_: TyCtxt<'_, '_, '_>, _: DefId) -> Cow<'static, str> { - bug!("stability") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::lookup_deprecation_entry<'tcx> { - fn describe(_: TyCtxt<'_, '_, '_>, _: DefId) -> Cow<'static, str> { - bug!("deprecation") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::item_attrs<'tcx> { - fn describe(_: TyCtxt<'_, '_, '_>, _: DefId) -> Cow<'static, str> { - bug!("item_attrs") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::is_reachable_non_generic<'tcx> { - fn describe(_: TyCtxt<'_, '_, '_>, _: DefId) -> Cow<'static, str> { - bug!("is_reachable_non_generic") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::fn_arg_names<'tcx> { - fn describe(_: TyCtxt<'_, '_, '_>, _: DefId) -> Cow<'static, str> { - bug!("fn_arg_names") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::impl_parent<'tcx> { - fn describe(_: TyCtxt<'_, '_, '_>, _: DefId) -> Cow<'static, str> { - bug!("impl_parent") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::trait_of_item<'tcx> { - fn describe(_: TyCtxt<'_, '_, '_>, _: DefId) -> Cow<'static, str> { - bug!("trait_of_item") - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::const_is_rvalue_promotable_to_static<'tcx> { - fn describe(tcx: TyCtxt<'_, '_, '_>, def_id: DefId) -> Cow<'static, str> { - format!("const checking if rvalue is promotable to static `{}`", - tcx.def_path_str(def_id)).into() - } - - #[inline] - fn cache_on_disk(_: TyCtxt<'_, 'tcx, 'tcx>, _: Self::Key) -> bool { - true - } - - #[inline] - fn try_load_from_disk<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - id: SerializedDepNodeIndex) - -> Option<Self::Value> { - tcx.queries.on_disk_cache.try_load_query_result(tcx, id) - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::rvalue_promotable_map<'tcx> { - fn describe(tcx: TyCtxt<'_, '_, '_>, def_id: DefId) -> Cow<'static, str> { - format!("checking which parts of `{}` are promotable to static", - tcx.def_path_str(def_id)).into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::is_mir_available<'tcx> { - fn describe(tcx: TyCtxt<'_, '_, '_>, def_id: DefId) -> Cow<'static, str> { - format!("checking if item is mir available: `{}`", - tcx.def_path_str(def_id)).into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::codegen_fulfill_obligation<'tcx> { - fn describe(tcx: TyCtxt<'_, '_, '_>, - key: (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>)) -> Cow<'static, str> { - format!("checking if `{}` fulfills its obligations", tcx.def_path_str(key.1.def_id())) - .into() - } - - #[inline] - fn cache_on_disk(_: TyCtxt<'_, 'tcx, 'tcx>, _: Self::Key) -> bool { - true - } - - #[inline] - fn try_load_from_disk<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - id: SerializedDepNodeIndex) - -> Option<Self::Value> { - tcx.queries.on_disk_cache.try_load_query_result(tcx, id) - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::trait_impls_of<'tcx> { - fn describe(tcx: TyCtxt<'_, '_, '_>, def_id: DefId) -> Cow<'static, str> { - format!("trait impls of `{}`", tcx.def_path_str(def_id)).into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::is_object_safe<'tcx> { - fn describe(tcx: TyCtxt<'_, '_, '_>, def_id: DefId) -> Cow<'static, str> { - format!("determine object safety of trait `{}`", tcx.def_path_str(def_id)).into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::is_const_fn_raw<'tcx> { - fn describe(tcx: TyCtxt<'_, '_, '_>, def_id: DefId) -> Cow<'static, str> { - format!("checking if item is const fn: `{}`", tcx.def_path_str(def_id)).into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::dylib_dependency_formats<'tcx> { - fn describe(_: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> { - "dylib dependency formats of crate".into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::is_compiler_builtins<'tcx> { - fn describe(_: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> { - "checking if the crate is_compiler_builtins".into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::has_global_allocator<'tcx> { - fn describe(_: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> { - "checking if the crate has_global_allocator".into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::has_panic_handler<'tcx> { - fn describe(_: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> { - "checking if the crate has_panic_handler".into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::extern_crate<'tcx> { - fn describe(_: TyCtxt<'_, '_, '_>, _: DefId) -> Cow<'static, str> { - "getting crate's ExternCrateData".into() - } -} - impl<'tcx> QueryDescription<'tcx> for queries::analysis<'tcx> { fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> { "running analysis passes on this crate".into() } } -impl<'tcx> QueryDescription<'tcx> for queries::specializes<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, _: (DefId, DefId)) -> Cow<'static, str> { - "computing whether impls specialize one another".into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::in_scope_traits_map<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, _: DefIndex) -> Cow<'static, str> { - "traits in scope at a block".into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::is_no_builtins<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> { - "test whether a crate has #![no_builtins]".into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::panic_strategy<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> { - "query a crate's configured panic strategy".into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::is_profiler_runtime<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> { - "query a crate is #![profiler_runtime]".into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::is_sanitizer_runtime<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> { - "query a crate is #![sanitizer_runtime]".into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::reachable_non_generics<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> { - "looking up the exported symbols of a crate".into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::foreign_modules<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> { - "looking up the foreign modules of a linked crate".into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::entry_fn<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> { - "looking up the entry function of a crate".into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::plugin_registrar_fn<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> { - "looking up the plugin registrar for a crate".into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::proc_macro_decls_static<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> { - "looking up the derive registrar for a crate".into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::crate_disambiguator<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> { - "looking up the disambiguator a crate".into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::crate_hash<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> { - "looking up the hash a crate".into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::original_crate_name<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> { - "looking up the original name a crate".into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::extra_filename<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> { - "looking up the extra filename for a crate".into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::implementations_of_trait<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, _: (CrateNum, DefId)) -> Cow<'static, str> { - "looking up implementations of a trait in a crate".into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::all_trait_implementations<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> { - "looking up all (?) trait implementations".into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::link_args<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> { - "looking up link arguments for a crate".into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::resolve_lifetimes<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> { - "resolving lifetimes".into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::named_region_map<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, _: DefIndex) -> Cow<'static, str> { - "looking up a named region".into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::is_late_bound_map<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, _: DefIndex) -> Cow<'static, str> { - "testing if a region is late bound".into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::object_lifetime_defaults_map<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, _: DefIndex) -> Cow<'static, str> { - "looking up lifetime defaults for a region".into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::dep_kind<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> { - "fetching what a dependency looks like".into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::crate_name<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> { - "fetching what a crate is named".into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::get_lib_features<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> { - "calculating the lib features map".into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::defined_lib_features<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> { - "calculating the lib features defined in a crate".into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::get_lang_items<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> { - "calculating the lang items map".into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::defined_lang_items<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> { - "calculating the lang items defined in a crate".into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::missing_lang_items<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> { - "calculating the missing lang items in a crate".into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::visible_parent_map<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> { - "calculating the visible parent map".into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::missing_extern_crate_item<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> { - "seeing if we're missing an `extern crate` item for this crate".into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::used_crate_source<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> { - "looking at the source for a crate".into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::postorder_cnums<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> { - "generating a postorder list of CrateNums".into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::maybe_unused_extern_crates<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> { - "looking up all possibly unused extern crates".into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::stability_index<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> { - "calculating the stability index for the local crate".into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::all_traits<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> { - "fetching all foreign and local traits".into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::all_crate_nums<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> { - "fetching all foreign CrateNum instances".into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::exported_symbols<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> { - "exported_symbols".into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::collect_and_partition_mono_items<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> { - "collect_and_partition_mono_items".into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::codegen_unit<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, _: InternedString) -> Cow<'static, str> { - "codegen_unit".into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::output_filenames<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> { - "output_filenames".into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::vtable_methods<'tcx> { - fn describe(tcx: TyCtxt<'_, '_, '_>, key: ty::PolyTraitRef<'tcx> ) -> Cow<'static, str> { - format!("finding all methods for trait {}", tcx.def_path_str(key.def_id())).into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::features_query<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> { - "looking up enabled feature gates".into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::typeck_tables_of<'tcx> { - #[inline] - fn cache_on_disk(_: TyCtxt<'_, 'tcx, 'tcx>, def_id: Self::Key) -> bool { - def_id.is_local() - } - - fn try_load_from_disk(tcx: TyCtxt<'_, 'tcx, 'tcx>, - id: SerializedDepNodeIndex) - -> Option<Self::Value> { - let typeck_tables: Option<ty::TypeckTables<'tcx>> = tcx - .queries.on_disk_cache - .try_load_query_result(tcx, id); - - typeck_tables.map(|tables| tcx.alloc_tables(tables)) - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::substitute_normalize_and_test_predicates<'tcx> { - fn describe(tcx: TyCtxt<'_, '_, '_>, key: (DefId, SubstsRef<'tcx>)) -> Cow<'static, str> { - format!("testing substituted normalized predicates:`{}`", tcx.def_path_str(key.0)).into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::method_autoderef_steps<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, goal: CanonicalTyGoal<'tcx>) -> Cow<'static, str> { - format!("computing autoderef types for `{:?}`", goal).into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::target_features_whitelist<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> { - "looking up the whitelist of target features".into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::instance_def_size_estimate<'tcx> { - fn describe(tcx: TyCtxt<'_, '_, '_>, def: ty::InstanceDef<'tcx>) -> Cow<'static, str> { - format!("estimating size for `{}`", tcx.def_path_str(def.def_id())).into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::dllimport_foreign_items<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> { - "dllimport_foreign_items".into() - } -} - -impl<'tcx> QueryDescription<'tcx> for queries::backend_optimization_level<'tcx> { - fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> { - "optimization level used by backend".into() - } -} - macro_rules! impl_disk_cacheable_query( ($query_name:ident, |$tcx:tt, $key:tt| $cond:expr) => { impl<'tcx> QueryDescription<'tcx> for queries::$query_name<'tcx> { diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs index f64156beeaa..cd29ca81890 100644 --- a/src/librustc/ty/query/mod.rs +++ b/src/librustc/ty/query/mod.rs @@ -1,4 +1,4 @@ -use crate::dep_graph::{self, DepConstructor, DepNode}; +use crate::dep_graph::{self, DepNode}; use crate::hir::def_id::{CrateNum, DefId, DefIndex}; use crate::hir::def::{Def, Export}; use crate::hir::{self, TraitCandidate, ItemLocalId, CodegenFnAttrs}; @@ -41,7 +41,6 @@ use crate::ty::subst::SubstsRef; use crate::util::nodemap::{DefIdSet, DefIdMap, ItemLocalSet}; use crate::util::common::{ErrorReported}; use crate::util::profiling::ProfileCategory::*; -use crate::session::Session; use rustc_data_structures::svh::Svh; use rustc_data_structures::bit_set::BitSet; @@ -104,738 +103,5 @@ rustc_query_append! { [define_queries!][ <'tcx> /// Run analysis passes on the crate [] fn analysis: Analysis(CrateNum) -> Result<(), ErrorReported>, - /// Maps from the `DefId` of an item (trait/struct/enum/fn) to the - /// predicates (where-clauses) directly defined on it. This is - /// equal to the `explicit_predicates_of` predicates plus the - /// `inferred_outlives_of` predicates. - [] fn predicates_defined_on: PredicatesDefinedOnItem(DefId) - -> Lrc<ty::GenericPredicates<'tcx>>, - - /// Returns the predicates written explicit by the user. - [] fn explicit_predicates_of: ExplicitPredicatesOfItem(DefId) - -> Lrc<ty::GenericPredicates<'tcx>>, - - /// Returns the inferred outlives predicates (e.g., for `struct - /// Foo<'a, T> { x: &'a T }`, this would return `T: 'a`). - [] fn inferred_outlives_of: InferredOutlivesOf(DefId) -> Lrc<Vec<ty::Predicate<'tcx>>>, - - /// Maps from the `DefId` of a trait to the list of - /// super-predicates. This is a subset of the full list of - /// predicates. We store these in a separate map because we must - /// evaluate them even during type conversion, often before the - /// full predicates are available (note that supertraits have - /// additional acyclicity requirements). - [] fn super_predicates_of: SuperPredicatesOfItem(DefId) -> Lrc<ty::GenericPredicates<'tcx>>, - - /// To avoid cycles within the predicates of a single item we compute - /// per-type-parameter predicates for resolving `T::AssocTy`. - [] fn type_param_predicates: type_param_predicates((DefId, DefId)) - -> Lrc<ty::GenericPredicates<'tcx>>, - - [] fn trait_def: TraitDefOfItem(DefId) -> &'tcx ty::TraitDef, - [] fn adt_def: AdtDefOfItem(DefId) -> &'tcx ty::AdtDef, - [] fn adt_destructor: AdtDestructor(DefId) -> Option<ty::Destructor>, - - // The cycle error here should be reported as an error by `check_representable`. - // We consider the type as Sized in the meanwhile to avoid - // further errors (done in impl Value for AdtSizedConstraint). - // Use `cycle_delay_bug` to delay the cycle error here to be emitted later - // in case we accidentally otherwise don't emit an error. - [cycle_delay_bug] fn adt_sized_constraint: SizedConstraint( - DefId - ) -> AdtSizedConstraint<'tcx>, - - [] fn adt_dtorck_constraint: DtorckConstraint( - DefId - ) -> Result<DtorckConstraint<'tcx>, NoSolution>, - - /// True if this is a const fn, use the `is_const_fn` to know whether your crate actually - /// sees it as const fn (e.g., the const-fn-ness might be unstable and you might not have - /// the feature gate active) - /// - /// **Do not call this function manually.** It is only meant to cache the base data for the - /// `is_const_fn` function. - [] fn is_const_fn_raw: IsConstFn(DefId) -> bool, - - - /// Returns true if calls to the function may be promoted - /// - /// This is either because the function is e.g., a tuple-struct or tuple-variant - /// constructor, or because it has the `#[rustc_promotable]` attribute. The attribute should - /// be removed in the future in favour of some form of check which figures out whether the - /// function does not inspect the bits of any of its arguments (so is essentially just a - /// constructor function). - [] fn is_promotable_const_fn: IsPromotableConstFn(DefId) -> bool, - - /// True if this is a foreign item (i.e., linked via `extern { ... }`). - [] fn is_foreign_item: IsForeignItem(DefId) -> bool, - - /// Get a map with the variance of every item; use `item_variance` - /// instead. - [] fn crate_variances: crate_variances(CrateNum) -> Lrc<ty::CrateVariancesMap>, - - /// Maps from def-id of a type or region parameter to its - /// (inferred) variance. - [] fn variances_of: ItemVariances(DefId) -> Lrc<Vec<ty::Variance>>, - }, - - TypeChecking { - /// Maps from def-id of a type to its (inferred) outlives. - [] fn inferred_outlives_crate: InferredOutlivesCrate(CrateNum) - -> Lrc<ty::CratePredicatesMap<'tcx>>, - }, - - Other { - /// Maps from an impl/trait def-id to a list of the def-ids of its items - [] fn associated_item_def_ids: AssociatedItemDefIds(DefId) -> Lrc<Vec<DefId>>, - - /// Maps from a trait item to the trait item "descriptor" - [] fn associated_item: AssociatedItems(DefId) -> ty::AssociatedItem, - - [] fn impl_trait_ref: ImplTraitRef(DefId) -> Option<ty::TraitRef<'tcx>>, - [] fn impl_polarity: ImplPolarity(DefId) -> hir::ImplPolarity, - - [] fn issue33140_self_ty: Issue33140SelfTy(DefId) -> Option<ty::Ty<'tcx>>, - }, - - TypeChecking { - /// Maps a DefId of a type to a list of its inherent impls. - /// Contains implementations of methods that are inherent to a type. - /// Methods in these implementations don't need to be exported. - [] fn inherent_impls: InherentImpls(DefId) -> Lrc<Vec<DefId>>, - }, - - TypeChecking { - /// The result of unsafety-checking this `DefId`. - [] fn unsafety_check_result: UnsafetyCheckResult(DefId) -> mir::UnsafetyCheckResult, - - /// HACK: when evaluated, this reports a "unsafe derive on repr(packed)" error - [] fn unsafe_derive_on_repr_packed: UnsafeDeriveOnReprPacked(DefId) -> (), - - /// The signature of functions and closures. - [] fn fn_sig: FnSignature(DefId) -> ty::PolyFnSig<'tcx>, - }, - - Other { - [] fn lint_mod: LintMod(DefId) -> (), - - /// Checks the attributes in the module - [] fn check_mod_attrs: CheckModAttrs(DefId) -> (), - - [] fn check_mod_unstable_api_usage: CheckModUnstableApiUsage(DefId) -> (), - - /// Checks the loops in the module - [] fn check_mod_loops: CheckModLoops(DefId) -> (), - - [] fn check_mod_item_types: CheckModItemTypes(DefId) -> (), - - [] fn check_mod_privacy: CheckModPrivacy(DefId) -> (), - - [] fn check_mod_intrinsics: CheckModIntrinsics(DefId) -> (), - - [] fn check_mod_liveness: CheckModLiveness(DefId) -> (), - - [] fn check_mod_impl_wf: CheckModImplWf(DefId) -> (), - - [] fn collect_mod_item_types: CollectModItemTypes(DefId) -> (), - - /// Caches CoerceUnsized kinds for impls on custom types. - [] fn coerce_unsized_info: CoerceUnsizedInfo(DefId) - -> ty::adjustment::CoerceUnsizedInfo, - }, - - TypeChecking { - [] fn typeck_item_bodies: - typeck_item_bodies_dep_node(CrateNum) -> (), - - [] fn typeck_tables_of: TypeckTables(DefId) -> &'tcx ty::TypeckTables<'tcx>, - }, - - Other { - [] fn used_trait_imports: UsedTraitImports(DefId) -> Lrc<DefIdSet>, - }, - - TypeChecking { - [] fn has_typeck_tables: HasTypeckTables(DefId) -> bool, - - [] fn coherent_trait: CoherenceCheckTrait(DefId) -> (), - }, - - BorrowChecking { - [] fn borrowck: BorrowCheck(DefId) -> Lrc<BorrowCheckResult>, - - /// Borrow checks the function body. If this is a closure, returns - /// additional requirements that the closure's creator must verify. - [] fn mir_borrowck: MirBorrowCheck(DefId) -> mir::BorrowCheckResult<'tcx>, - }, - - TypeChecking { - /// Gets a complete map from all types to their inherent impls. - /// Not meant to be used directly outside of coherence. - /// (Defined only for `LOCAL_CRATE`.) - [] fn crate_inherent_impls: crate_inherent_impls_dep_node(CrateNum) - -> Lrc<CrateInherentImpls>, - - /// Checks all types in the crate for overlap in their inherent impls. Reports errors. - /// Not meant to be used directly outside of coherence. - /// (Defined only for `LOCAL_CRATE`.) - [] fn crate_inherent_impls_overlap_check: inherent_impls_overlap_check_dep_node(CrateNum) - -> (), - }, - - Other { - /// Evaluate a constant without running sanity checks - /// - /// **Do not use this** outside const eval. Const eval uses this to break query cycles - /// during validation. Please add a comment to every use site explaining why using - /// `const_eval` isn't sufficient - [] fn const_eval_raw: const_eval_raw_dep_node(ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) - -> ConstEvalRawResult<'tcx>, - - /// Results of evaluating const items or constants embedded in - /// other items (such as enum variant explicit discriminants). - [] fn const_eval: const_eval_dep_node(ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) - -> ConstEvalResult<'tcx>, - }, - - TypeChecking { - [] fn check_match: CheckMatch(DefId) -> (), - - /// Performs part of the privacy check and computes "access levels". - [] fn privacy_access_levels: PrivacyAccessLevels(CrateNum) -> Lrc<AccessLevels>, - [] fn check_private_in_public: CheckPrivateInPublic(CrateNum) -> (), - }, - - Other { - [] fn reachable_set: reachability_dep_node(CrateNum) -> ReachableSet, - - /// Per-body `region::ScopeTree`. The `DefId` should be the owner `DefId` for the body; - /// in the case of closures, this will be redirected to the enclosing function. - [] fn region_scope_tree: RegionScopeTree(DefId) -> Lrc<region::ScopeTree>, - - [] fn mir_shims: mir_shim_dep_node(ty::InstanceDef<'tcx>) -> &'tcx mir::Mir<'tcx>, - - [] fn symbol_name: symbol_name_dep_node(ty::Instance<'tcx>) -> ty::SymbolName, - - [] fn describe_def: DescribeDef(DefId) -> Option<Def>, - [] fn def_span: DefSpan(DefId) -> Span, - [] fn lookup_stability: LookupStability(DefId) -> Option<&'tcx attr::Stability>, - [] fn lookup_deprecation_entry: LookupDeprecationEntry(DefId) -> Option<DeprecationEntry>, - [] fn item_attrs: ItemAttrs(DefId) -> Lrc<[ast::Attribute]>, - }, - - Codegen { - [] fn codegen_fn_attrs: codegen_fn_attrs(DefId) -> CodegenFnAttrs, - }, - - Other { - [] fn fn_arg_names: FnArgNames(DefId) -> Vec<ast::Name>, - /// Gets the rendered value of the specified constant or associated constant. - /// Used by rustdoc. - [] fn rendered_const: RenderedConst(DefId) -> String, - [] fn impl_parent: ImplParent(DefId) -> Option<DefId>, - }, - - TypeChecking { - [] fn trait_of_item: TraitOfItem(DefId) -> Option<DefId>, - [] fn const_is_rvalue_promotable_to_static: ConstIsRvaluePromotableToStatic(DefId) -> bool, - [] fn rvalue_promotable_map: RvaluePromotableMap(DefId) -> Lrc<ItemLocalSet>, - }, - - Codegen { - [] fn is_mir_available: IsMirAvailable(DefId) -> bool, - }, - - Other { - [] fn vtable_methods: vtable_methods_node(ty::PolyTraitRef<'tcx>) - -> Lrc<Vec<Option<(DefId, SubstsRef<'tcx>)>>>, - }, - - Codegen { - [] fn codegen_fulfill_obligation: fulfill_obligation_dep_node( - (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>)) -> Vtable<'tcx, ()>, - }, - - TypeChecking { - [] fn trait_impls_of: TraitImpls(DefId) -> Lrc<ty::trait_def::TraitImpls>, - [] fn specialization_graph_of: SpecializationGraph(DefId) - -> Lrc<specialization_graph::Graph>, - [] fn is_object_safe: ObjectSafety(DefId) -> bool, - - /// Gets the ParameterEnvironment for a given item; this environment - /// will be in "user-facing" mode, meaning that it is suitabe for - /// type-checking etc, and it does not normalize specializable - /// associated types. This is almost always what you want, - /// unless you are doing MIR optimizations, in which case you - /// might want to use `reveal_all()` method to change modes. - [] fn param_env: ParamEnv(DefId) -> ty::ParamEnv<'tcx>, - - /// Trait selection queries. These are best used by invoking `ty.is_copy_modulo_regions()`, - /// `ty.is_copy()`, etc, since that will prune the environment where possible. - [] fn is_copy_raw: is_copy_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool, - [] fn is_sized_raw: is_sized_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool, - [] fn is_freeze_raw: is_freeze_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool, - - // The cycle error here should be reported as an error by `check_representable`. - // We consider the type as not needing drop in the meanwhile to avoid - // further errors (done in impl Value for NeedsDrop). - // Use `cycle_delay_bug` to delay the cycle error here to be emitted later - // in case we accidentally otherwise don't emit an error. - [cycle_delay_bug] fn needs_drop_raw: needs_drop_dep_node( - ty::ParamEnvAnd<'tcx, Ty<'tcx>> - ) -> NeedsDrop, - - [] fn layout_raw: layout_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) - -> Result<&'tcx ty::layout::LayoutDetails, - ty::layout::LayoutError<'tcx>>, - }, - - Other { - [] fn dylib_dependency_formats: DylibDepFormats(CrateNum) - -> Lrc<Vec<(CrateNum, LinkagePreference)>>, - }, - - Codegen { - [fatal_cycle] fn is_compiler_builtins: IsCompilerBuiltins(CrateNum) -> bool, - [fatal_cycle] fn has_global_allocator: HasGlobalAllocator(CrateNum) -> bool, - [fatal_cycle] fn has_panic_handler: HasPanicHandler(CrateNum) -> bool, - [fatal_cycle] fn is_sanitizer_runtime: IsSanitizerRuntime(CrateNum) -> bool, - [fatal_cycle] fn is_profiler_runtime: IsProfilerRuntime(CrateNum) -> bool, - [fatal_cycle] fn panic_strategy: GetPanicStrategy(CrateNum) -> PanicStrategy, - [fatal_cycle] fn is_no_builtins: IsNoBuiltins(CrateNum) -> bool, - - [] fn extern_crate: ExternCrate(DefId) -> Lrc<Option<ExternCrate>>, - }, - - TypeChecking { - [] fn specializes: specializes_node((DefId, DefId)) -> bool, - [] fn in_scope_traits_map: InScopeTraits(DefIndex) - -> Option<Lrc<FxHashMap<ItemLocalId, Lrc<StableVec<TraitCandidate>>>>>, - }, - - Other { - [] fn module_exports: ModuleExports(DefId) -> Option<Lrc<Vec<Export>>>, - }, - - TypeChecking { - [] fn impl_defaultness: ImplDefaultness(DefId) -> hir::Defaultness, - - [] fn check_item_well_formed: CheckItemWellFormed(DefId) -> (), - [] fn check_trait_item_well_formed: CheckTraitItemWellFormed(DefId) -> (), - [] fn check_impl_item_well_formed: CheckImplItemWellFormed(DefId) -> (), - }, - - Linking { - // The DefIds of all non-generic functions and statics in the given crate - // that can be reached from outside the crate. - // - // We expect this items to be available for being linked to. - // - // This query can also be called for LOCAL_CRATE. In this case it will - // compute which items will be reachable to other crates, taking into account - // the kind of crate that is currently compiled. Crates with only a - // C interface have fewer reachable things. - // - // Does not include external symbols that don't have a corresponding DefId, - // like the compiler-generated `main` function and so on. - [] fn reachable_non_generics: ReachableNonGenerics(CrateNum) - -> Lrc<DefIdMap<SymbolExportLevel>>, - [] fn is_reachable_non_generic: IsReachableNonGeneric(DefId) -> bool, - [] fn is_unreachable_local_definition: IsUnreachableLocalDefinition(DefId) -> bool, - }, - - Codegen { - [] fn upstream_monomorphizations: UpstreamMonomorphizations(CrateNum) - -> Lrc<DefIdMap<Lrc<FxHashMap<SubstsRef<'tcx>, CrateNum>>>>, - [] fn upstream_monomorphizations_for: UpstreamMonomorphizationsFor(DefId) - -> Option<Lrc<FxHashMap<SubstsRef<'tcx>, CrateNum>>>, - }, - - Other { - [] fn foreign_modules: ForeignModules(CrateNum) -> Lrc<Vec<ForeignModule>>, - - /// Identifies the entry-point (e.g., the `main` function) for a given - /// crate, returning `None` if there is no entry point (such as for library crates). - [] fn entry_fn: EntryFn(CrateNum) -> Option<(DefId, EntryFnType)>, - [] fn plugin_registrar_fn: PluginRegistrarFn(CrateNum) -> Option<DefId>, - [] fn proc_macro_decls_static: ProcMacroDeclsStatic(CrateNum) -> Option<DefId>, - [] fn crate_disambiguator: CrateDisambiguator(CrateNum) -> CrateDisambiguator, - [] fn crate_hash: CrateHash(CrateNum) -> Svh, - [] fn original_crate_name: OriginalCrateName(CrateNum) -> Symbol, - [] fn extra_filename: ExtraFileName(CrateNum) -> String, - }, - - TypeChecking { - [] fn implementations_of_trait: implementations_of_trait_node((CrateNum, DefId)) - -> Lrc<Vec<DefId>>, - [] fn all_trait_implementations: AllTraitImplementations(CrateNum) - -> Lrc<Vec<DefId>>, - }, - - Other { - [] fn dllimport_foreign_items: DllimportForeignItems(CrateNum) - -> Lrc<FxHashSet<DefId>>, - [] fn is_dllimport_foreign_item: IsDllimportForeignItem(DefId) -> bool, - [] fn is_statically_included_foreign_item: IsStaticallyIncludedForeignItem(DefId) -> bool, - [] fn native_library_kind: NativeLibraryKind(DefId) - -> Option<NativeLibraryKind>, - }, - - Linking { - [] fn link_args: link_args_node(CrateNum) -> Lrc<Vec<String>>, - }, - - BorrowChecking { - // Lifetime resolution. See `middle::resolve_lifetimes`. - [] fn resolve_lifetimes: ResolveLifetimes(CrateNum) -> Lrc<ResolveLifetimes>, - [] fn named_region_map: NamedRegion(DefIndex) -> - Option<Lrc<FxHashMap<ItemLocalId, Region>>>, - [] fn is_late_bound_map: IsLateBound(DefIndex) -> - Option<Lrc<FxHashSet<ItemLocalId>>>, - [] fn object_lifetime_defaults_map: ObjectLifetimeDefaults(DefIndex) - -> Option<Lrc<FxHashMap<ItemLocalId, Lrc<Vec<ObjectLifetimeDefault>>>>>, - }, - - TypeChecking { - [] fn visibility: Visibility(DefId) -> ty::Visibility, - }, - - Other { - [] fn dep_kind: DepKind(CrateNum) -> DepKind, - [] fn crate_name: CrateName(CrateNum) -> Symbol, - [] fn item_children: ItemChildren(DefId) -> Lrc<Vec<Export>>, - [] fn extern_mod_stmt_cnum: ExternModStmtCnum(DefId) -> Option<CrateNum>, - - [] fn get_lib_features: get_lib_features_node(CrateNum) -> Lrc<LibFeatures>, - [] fn defined_lib_features: DefinedLibFeatures(CrateNum) - -> Lrc<Vec<(Symbol, Option<Symbol>)>>, - [] fn get_lang_items: get_lang_items_node(CrateNum) -> Lrc<LanguageItems>, - [] fn defined_lang_items: DefinedLangItems(CrateNum) -> Lrc<Vec<(DefId, usize)>>, - [] fn missing_lang_items: MissingLangItems(CrateNum) -> Lrc<Vec<LangItem>>, - [] fn visible_parent_map: visible_parent_map_node(CrateNum) - -> Lrc<DefIdMap<DefId>>, - [] fn missing_extern_crate_item: MissingExternCrateItem(CrateNum) -> bool, - [] fn used_crate_source: UsedCrateSource(CrateNum) -> Lrc<CrateSource>, - [] fn postorder_cnums: postorder_cnums_node(CrateNum) -> Lrc<Vec<CrateNum>>, - - [] fn freevars: Freevars(DefId) -> Option<Lrc<Vec<hir::Freevar>>>, - [] fn maybe_unused_trait_import: MaybeUnusedTraitImport(DefId) -> bool, - [] fn maybe_unused_extern_crates: maybe_unused_extern_crates_node(CrateNum) - -> Lrc<Vec<(DefId, Span)>>, - [] fn names_imported_by_glob_use: NamesImportedByGlobUse(DefId) - -> Lrc<FxHashSet<ast::Name>>, - - [] fn stability_index: stability_index_node(CrateNum) -> Lrc<stability::Index<'tcx>>, - [] fn all_crate_nums: all_crate_nums_node(CrateNum) -> Lrc<Vec<CrateNum>>, - - /// A vector of every trait accessible in the whole crate - /// (i.e., including those from subcrates). This is used only for - /// error reporting. - [] fn all_traits: all_traits_node(CrateNum) -> Lrc<Vec<DefId>>, - }, - - Linking { - [] fn exported_symbols: ExportedSymbols(CrateNum) - -> Arc<Vec<(ExportedSymbol<'tcx>, SymbolExportLevel)>>, - }, - - Codegen { - [] fn collect_and_partition_mono_items: - collect_and_partition_mono_items_node(CrateNum) - -> (Arc<DefIdSet>, Arc<Vec<Arc<CodegenUnit<'tcx>>>>), - [] fn is_codegened_item: IsCodegenedItem(DefId) -> bool, - [] fn codegen_unit: CodegenUnit(InternedString) -> Arc<CodegenUnit<'tcx>>, - [] fn backend_optimization_level: BackendOptimizationLevel(CrateNum) -> OptLevel, - }, - - Other { - [] fn output_filenames: output_filenames_node(CrateNum) - -> Arc<OutputFilenames>, - }, - - TypeChecking { - /// Do not call this query directly: invoke `normalize` instead. - [] fn normalize_projection_ty: NormalizeProjectionTy( - CanonicalProjectionGoal<'tcx> - ) -> Result< - Lrc<Canonical<'tcx, canonical::QueryResponse<'tcx, NormalizationResult<'tcx>>>>, - NoSolution, - >, - - /// Do not call this query directly: invoke `normalize_erasing_regions` instead. - [] fn normalize_ty_after_erasing_regions: NormalizeTyAfterErasingRegions( - ParamEnvAnd<'tcx, Ty<'tcx>> - ) -> Ty<'tcx>, - - [] fn implied_outlives_bounds: ImpliedOutlivesBounds( - CanonicalTyGoal<'tcx> - ) -> Result< - Lrc<Canonical<'tcx, canonical::QueryResponse<'tcx, Vec<OutlivesBound<'tcx>>>>>, - NoSolution, - >, - - /// Do not call this query directly: invoke `infcx.at().dropck_outlives()` instead. - [] fn dropck_outlives: DropckOutlives( - CanonicalTyGoal<'tcx> - ) -> Result< - Lrc<Canonical<'tcx, canonical::QueryResponse<'tcx, DropckOutlivesResult<'tcx>>>>, - NoSolution, - >, - - /// Do not call this query directly: invoke `infcx.predicate_may_hold()` or - /// `infcx.predicate_must_hold()` instead. - [] fn evaluate_obligation: EvaluateObligation( - CanonicalPredicateGoal<'tcx> - ) -> Result<traits::EvaluationResult, traits::OverflowError>, - - [] fn evaluate_goal: EvaluateGoal( - traits::ChalkCanonicalGoal<'tcx> - ) -> Result< - Lrc<Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>>, - NoSolution - >, - - /// Do not call this query directly: part of the `Eq` type-op - [] fn type_op_ascribe_user_type: TypeOpAscribeUserType( - CanonicalTypeOpAscribeUserTypeGoal<'tcx> - ) -> Result< - Lrc<Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>>, - NoSolution, - >, - - /// Do not call this query directly: part of the `Eq` type-op - [] fn type_op_eq: TypeOpEq( - CanonicalTypeOpEqGoal<'tcx> - ) -> Result< - Lrc<Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>>, - NoSolution, - >, - - /// Do not call this query directly: part of the `Subtype` type-op - [] fn type_op_subtype: TypeOpSubtype( - CanonicalTypeOpSubtypeGoal<'tcx> - ) -> Result< - Lrc<Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>>, - NoSolution, - >, - - /// Do not call this query directly: part of the `ProvePredicate` type-op - [] fn type_op_prove_predicate: TypeOpProvePredicate( - CanonicalTypeOpProvePredicateGoal<'tcx> - ) -> Result< - Lrc<Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>>, - NoSolution, - >, - - /// Do not call this query directly: part of the `Normalize` type-op - [] fn type_op_normalize_ty: TypeOpNormalizeTy( - CanonicalTypeOpNormalizeGoal<'tcx, Ty<'tcx>> - ) -> Result< - Lrc<Canonical<'tcx, canonical::QueryResponse<'tcx, Ty<'tcx>>>>, - NoSolution, - >, - - /// Do not call this query directly: part of the `Normalize` type-op - [] fn type_op_normalize_predicate: TypeOpNormalizePredicate( - CanonicalTypeOpNormalizeGoal<'tcx, ty::Predicate<'tcx>> - ) -> Result< - Lrc<Canonical<'tcx, canonical::QueryResponse<'tcx, ty::Predicate<'tcx>>>>, - NoSolution, - >, - - /// Do not call this query directly: part of the `Normalize` type-op - [] fn type_op_normalize_poly_fn_sig: TypeOpNormalizePolyFnSig( - CanonicalTypeOpNormalizeGoal<'tcx, ty::PolyFnSig<'tcx>> - ) -> Result< - Lrc<Canonical<'tcx, canonical::QueryResponse<'tcx, ty::PolyFnSig<'tcx>>>>, - NoSolution, - >, - - /// Do not call this query directly: part of the `Normalize` type-op - [] fn type_op_normalize_fn_sig: TypeOpNormalizeFnSig( - CanonicalTypeOpNormalizeGoal<'tcx, ty::FnSig<'tcx>> - ) -> Result< - Lrc<Canonical<'tcx, canonical::QueryResponse<'tcx, ty::FnSig<'tcx>>>>, - NoSolution, - >, - - [] fn substitute_normalize_and_test_predicates: - substitute_normalize_and_test_predicates_node((DefId, SubstsRef<'tcx>)) -> bool, - - [] fn method_autoderef_steps: MethodAutoderefSteps( - CanonicalTyGoal<'tcx> - ) -> MethodAutoderefStepsResult<'tcx>, - }, - - Other { - [] fn target_features_whitelist: - target_features_whitelist_node(CrateNum) -> Lrc<FxHashMap<String, Option<String>>>, - - // Get an estimate of the size of an InstanceDef based on its MIR for CGU partitioning. - [] fn instance_def_size_estimate: instance_def_size_estimate_dep_node(ty::InstanceDef<'tcx>) - -> usize, - - [] fn features_query: features_node(CrateNum) -> Lrc<feature_gate::Features>, }, ]} - -////////////////////////////////////////////////////////////////////// -// These functions are little shims used to find the dep-node for a -// given query when there is not a *direct* mapping: - - -fn features_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { - DepConstructor::Features -} - -fn codegen_fn_attrs<'tcx>(id: DefId) -> DepConstructor<'tcx> { - DepConstructor::CodegenFnAttrs { 0: id } -} - -fn type_param_predicates<'tcx>((item_id, param_id): (DefId, DefId)) -> DepConstructor<'tcx> { - DepConstructor::TypeParamPredicates { - item_id, - param_id - } -} - -fn fulfill_obligation_dep_node<'tcx>((param_env, trait_ref): - (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>)) -> DepConstructor<'tcx> { - DepConstructor::FulfillObligation { - param_env, - trait_ref - } -} - -fn crate_inherent_impls_dep_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { - DepConstructor::Coherence -} - -fn inherent_impls_overlap_check_dep_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { - DepConstructor::CoherenceInherentImplOverlapCheck -} - -fn reachability_dep_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { - DepConstructor::Reachability -} - -fn mir_shim_dep_node<'tcx>(instance_def: ty::InstanceDef<'tcx>) -> DepConstructor<'tcx> { - DepConstructor::MirShim { - instance_def - } -} - -fn symbol_name_dep_node<'tcx>(instance: ty::Instance<'tcx>) -> DepConstructor<'tcx> { - DepConstructor::SymbolName { instance } -} - -fn typeck_item_bodies_dep_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { - DepConstructor::TypeckBodiesKrate -} - -fn const_eval_dep_node<'tcx>(param_env: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) - -> DepConstructor<'tcx> { - DepConstructor::ConstEval { param_env } -} -fn const_eval_raw_dep_node<'tcx>(param_env: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) - -> DepConstructor<'tcx> { - DepConstructor::ConstEvalRaw { param_env } -} - -fn crate_variances<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { - DepConstructor::CrateVariances -} - -fn is_copy_dep_node<'tcx>(param_env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor<'tcx> { - DepConstructor::IsCopy { param_env } -} - -fn is_sized_dep_node<'tcx>(param_env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor<'tcx> { - DepConstructor::IsSized { param_env } -} - -fn is_freeze_dep_node<'tcx>(param_env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor<'tcx> { - DepConstructor::IsFreeze { param_env } -} - -fn needs_drop_dep_node<'tcx>(param_env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor<'tcx> { - DepConstructor::NeedsDrop { param_env } -} - -fn layout_dep_node<'tcx>(param_env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor<'tcx> { - DepConstructor::Layout { param_env } -} - -fn specializes_node<'tcx>((a, b): (DefId, DefId)) -> DepConstructor<'tcx> { - DepConstructor::Specializes { impl1: a, impl2: b } -} - -fn implementations_of_trait_node<'tcx>((krate, trait_id): (CrateNum, DefId)) - -> DepConstructor<'tcx> -{ - DepConstructor::ImplementationsOfTrait { krate, trait_id } -} - -fn link_args_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { - DepConstructor::LinkArgs -} - -fn get_lib_features_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { - DepConstructor::GetLibFeatures -} - -fn get_lang_items_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { - DepConstructor::GetLangItems -} - -fn visible_parent_map_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { - DepConstructor::VisibleParentMap -} - -fn postorder_cnums_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { - DepConstructor::PostorderCnums -} - -fn maybe_unused_extern_crates_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { - DepConstructor::MaybeUnusedExternCrates -} - -fn stability_index_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { - DepConstructor::StabilityIndex -} - -fn all_crate_nums_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { - DepConstructor::AllCrateNums -} - -fn all_traits_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { - DepConstructor::AllTraits -} - -fn collect_and_partition_mono_items_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { - DepConstructor::CollectAndPartitionMonoItems -} - -fn output_filenames_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { - DepConstructor::OutputFilenames -} - -fn vtable_methods_node<'tcx>(trait_ref: ty::PolyTraitRef<'tcx>) -> DepConstructor<'tcx> { - DepConstructor::VtableMethods{ trait_ref } -} - -fn substitute_normalize_and_test_predicates_node<'tcx>(key: (DefId, SubstsRef<'tcx>)) - -> DepConstructor<'tcx> { - DepConstructor::SubstituteNormalizeAndTestPredicates { key } -} - -fn target_features_whitelist_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { - DepConstructor::TargetFeaturesWhitelist -} - -fn instance_def_size_estimate_dep_node<'tcx>(instance_def: ty::InstanceDef<'tcx>) - -> DepConstructor<'tcx> { - DepConstructor::InstanceDefSizeEstimate { - instance_def - } -} diff --git a/src/librustc/ty/query/plumbing.rs b/src/librustc/ty/query/plumbing.rs index 973291d94ac..d671b58470c 100644 --- a/src/librustc/ty/query/plumbing.rs +++ b/src/librustc/ty/query/plumbing.rs @@ -114,7 +114,7 @@ impl<'a, 'tcx, Q: QueryDescription<'tcx>> JobOwner<'a, 'tcx, Q> { let mut lock = cache.borrow_mut(); if let Some(value) = lock.results.get(key) { profq_msg!(tcx, ProfileQueriesMsg::CacheHit); - tcx.sess.profiler(|p| p.record_query_hit(Q::NAME, Q::CATEGORY)); + tcx.sess.profiler(|p| p.record_query_hit(Q::NAME)); let result = (value.value.clone(), value.index); #[cfg(debug_assertions)] { @@ -130,7 +130,7 @@ impl<'a, 'tcx, Q: QueryDescription<'tcx>> JobOwner<'a, 'tcx, Q> { //in another thread has completed. Record how long we wait in the //self-profiler #[cfg(parallel_compiler)] - tcx.sess.profiler(|p| p.query_blocked_start(Q::NAME, Q::CATEGORY)); + tcx.sess.profiler(|p| p.query_blocked_start(Q::NAME)); job.clone() }, @@ -172,7 +172,7 @@ impl<'a, 'tcx, Q: QueryDescription<'tcx>> JobOwner<'a, 'tcx, Q> { #[cfg(parallel_compiler)] { let result = job.r#await(tcx, span); - tcx.sess.profiler(|p| p.query_blocked_end(Q::NAME, Q::CATEGORY)); + tcx.sess.profiler(|p| p.query_blocked_end(Q::NAME)); if let Err(cycle) = result { return TryGetJob::Cycle(Q::handle_cycle_error(tcx, cycle)); @@ -358,14 +358,14 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { key: Q::Key) -> Q::Value { debug!("ty::query::get_query<{}>(key={:?}, span={:?})", - Q::NAME, + Q::NAME.as_str(), key, span); profq_msg!(self, ProfileQueriesMsg::QueryBegin( span.data(), - profq_query_msg!(Q::NAME, self, key), + profq_query_msg!(Q::NAME.as_str(), self, key), ) ); @@ -389,7 +389,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { if dep_node.kind.is_anon() { profq_msg!(self, ProfileQueriesMsg::ProviderBegin); - self.sess.profiler(|p| p.start_query(Q::NAME, Q::CATEGORY)); + self.sess.profiler(|p| p.start_query(Q::NAME)); let ((result, dep_node_index), diagnostics) = with_diagnostics(|diagnostics| { self.start_query(job.job.clone(), diagnostics, |tcx| { @@ -399,7 +399,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { }) }); - self.sess.profiler(|p| p.end_query(Q::NAME, Q::CATEGORY)); + self.sess.profiler(|p| p.end_query(Q::NAME)); profq_msg!(self, ProfileQueriesMsg::ProviderEnd); self.dep_graph.read_index(dep_node_index); @@ -474,14 +474,14 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { let result = if let Some(result) = result { profq_msg!(self, ProfileQueriesMsg::CacheHit); - self.sess.profiler(|p| p.record_query_hit(Q::NAME, Q::CATEGORY)); + self.sess.profiler(|p| p.record_query_hit(Q::NAME)); result } else { // We could not load a result from the on-disk cache, so // recompute. - self.sess.profiler(|p| p.start_query(Q::NAME, Q::CATEGORY)); + self.sess.profiler(|p| p.start_query(Q::NAME)); // The dep-graph for this computation is already in // place @@ -489,7 +489,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { Q::compute(self, key) }); - self.sess.profiler(|p| p.end_query(Q::NAME, Q::CATEGORY)); + self.sess.profiler(|p| p.end_query(Q::NAME)); result }; @@ -552,7 +552,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { key, dep_node); profq_msg!(self, ProfileQueriesMsg::ProviderBegin); - self.sess.profiler(|p| p.start_query(Q::NAME, Q::CATEGORY)); + self.sess.profiler(|p| p.start_query(Q::NAME)); let ((result, dep_node_index), diagnostics) = with_diagnostics(|diagnostics| { self.start_query(job.job.clone(), diagnostics, |tcx| { @@ -572,7 +572,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { }) }); - self.sess.profiler(|p| p.end_query(Q::NAME, Q::CATEGORY)); + self.sess.profiler(|p| p.end_query(Q::NAME)); profq_msg!(self, ProfileQueriesMsg::ProviderEnd); if unlikely!(self.sess.opts.debugging_opts.query_dep_graph) { @@ -619,7 +619,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { let _ = self.get_query::<Q>(DUMMY_SP, key); } else { profq_msg!(self, ProfileQueriesMsg::CacheHit); - self.sess.profiler(|p| p.record_query_hit(Q::NAME, Q::CATEGORY)); + self.sess.profiler(|p| p.record_query_hit(Q::NAME)); } } @@ -632,7 +632,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { ) { profq_msg!( self, - ProfileQueriesMsg::QueryBegin(span.data(), profq_query_msg!(Q::NAME, self, key)) + ProfileQueriesMsg::QueryBegin(span.data(), + profq_query_msg!(Q::NAME.as_str(), self, key)) ); // We may be concurrently trying both execute and force a query @@ -725,18 +726,6 @@ macro_rules! define_queries_inner { } } - pub fn record_computed_queries(&self, sess: &Session) { - sess.profiler(|p| { - $( - p.record_computed_queries( - <queries::$name<'_> as QueryConfig<'_>>::NAME, - <queries::$name<'_> as QueryConfig<'_>>::CATEGORY, - self.$name.lock().results.len() - ); - )* - }); - } - #[cfg(parallel_compiler)] pub fn collect_active_jobs(&self) -> Vec<Lrc<QueryJob<$tcx>>> { let mut jobs = Vec::new(); @@ -855,6 +844,24 @@ macro_rules! define_queries_inner { } #[allow(nonstandard_style)] + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] + pub enum QueryName { + $($name),* + } + + impl QueryName { + pub fn register_with_profiler(profiler: &crate::util::profiling::SelfProfiler) { + $(profiler.register_query_name(QueryName::$name);)* + } + + pub fn as_str(&self) -> &'static str { + match self { + $(QueryName::$name => stringify!($name),)* + } + } + } + + #[allow(nonstandard_style)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub enum Query<$tcx> { $($(#[$attr])* $name($K)),* @@ -894,6 +901,12 @@ macro_rules! define_queries_inner { $(Query::$name(key) => key.default_span(tcx),)* } } + + pub fn query_name(&self) -> QueryName { + match self { + $(Query::$name(_) => QueryName::$name,)* + } + } } impl<'a, $tcx> HashStable<StableHashingContext<'a>> for Query<$tcx> { @@ -930,7 +943,7 @@ macro_rules! define_queries_inner { type Key = $K; type Value = $V; - const NAME: &'static str = stringify!($name); + const NAME: QueryName = QueryName::$name; const CATEGORY: ProfileCategory = $category; } @@ -1139,12 +1152,11 @@ pub fn force_from_dep_node<'tcx>( tcx: TyCtxt<'_, 'tcx, 'tcx>, dep_node: &DepNode ) -> bool { - use crate::hir::def_id::LOCAL_CRATE; use crate::dep_graph::RecoverKey; // We must avoid ever having to call force_from_dep_node() for a - // DepNode::CodegenUnit: - // Since we cannot reconstruct the query key of a DepNode::CodegenUnit, we + // DepNode::codegen_unit: + // Since we cannot reconstruct the query key of a DepNode::codegen_unit, we // would always end up having to evaluate the first caller of the // `codegen_unit` query that *is* reconstructible. This might very well be // the `compile_codegen_unit` query, thus re-codegenning the whole CGU just @@ -1155,8 +1167,8 @@ pub fn force_from_dep_node<'tcx>( // each CGU, right after partitioning. This way `try_mark_green` will always // hit the cache instead of having to go through `force_from_dep_node`. // This assertion makes sure, we actually keep applying the solution above. - debug_assert!(dep_node.kind != DepKind::CodegenUnit, - "calling force_from_dep_node() on DepKind::CodegenUnit"); + debug_assert!(dep_node.kind != DepKind::codegen_unit, + "calling force_from_dep_node() on DepKind::codegen_unit"); if !dep_node.kind.can_reconstruct_query_key() { return false @@ -1193,9 +1205,6 @@ pub fn force_from_dep_node<'tcx>( ($query:ident, $key:expr) => { force_ex!(tcx, $query, $key) } }; - // FIXME(#45015): We should try move this boilerplate code into a macro - // somehow. - rustc_dep_node_force!([dep_node, tcx] // These are inputs that are expected to be pre-allocated and that // should therefore always be red or green already @@ -1210,223 +1219,11 @@ pub fn force_from_dep_node<'tcx>( // We don't have enough information to reconstruct the query key of // these - DepKind::IsCopy | - DepKind::IsSized | - DepKind::IsFreeze | - DepKind::NeedsDrop | - DepKind::Layout | - DepKind::ConstEval | - DepKind::ConstEvalRaw | - DepKind::SymbolName | - DepKind::MirShim | - DepKind::BorrowCheckKrate | - DepKind::Specializes | - DepKind::ImplementationsOfTrait | - DepKind::TypeParamPredicates | - DepKind::CodegenUnit | - DepKind::CompileCodegenUnit | - DepKind::FulfillObligation | - DepKind::VtableMethods | - DepKind::NormalizeProjectionTy | - DepKind::NormalizeTyAfterErasingRegions | - DepKind::ImpliedOutlivesBounds | - DepKind::DropckOutlives | - DepKind::EvaluateObligation | - DepKind::EvaluateGoal | - DepKind::TypeOpAscribeUserType | - DepKind::TypeOpEq | - DepKind::TypeOpSubtype | - DepKind::TypeOpProvePredicate | - DepKind::TypeOpNormalizeTy | - DepKind::TypeOpNormalizePredicate | - DepKind::TypeOpNormalizePolyFnSig | - DepKind::TypeOpNormalizeFnSig | - DepKind::SubstituteNormalizeAndTestPredicates | - DepKind::MethodAutoderefSteps | - DepKind::InstanceDefSizeEstimate => { + DepKind::CompileCodegenUnit => { bug!("force_from_dep_node() - Encountered {:?}", dep_node) } - // These are not queries - DepKind::CoherenceCheckTrait | - DepKind::ItemVarianceConstraints => { - return false - } - - DepKind::RegionScopeTree => { force!(region_scope_tree, def_id!()); } - - DepKind::Coherence => { force!(crate_inherent_impls, LOCAL_CRATE); } - DepKind::CoherenceInherentImplOverlapCheck => { - force!(crate_inherent_impls_overlap_check, LOCAL_CRATE) - }, - DepKind::PrivacyAccessLevels => { force!(privacy_access_levels, LOCAL_CRATE); } - DepKind::CheckPrivateInPublic => { force!(check_private_in_public, LOCAL_CRATE); } - - DepKind::BorrowCheck => { force!(borrowck, def_id!()); } - DepKind::MirBorrowCheck => { force!(mir_borrowck, def_id!()); } - DepKind::UnsafetyCheckResult => { force!(unsafety_check_result, def_id!()); } - DepKind::UnsafeDeriveOnReprPacked => { force!(unsafe_derive_on_repr_packed, def_id!()); } - DepKind::LintMod => { force!(lint_mod, def_id!()); } - DepKind::CheckModAttrs => { force!(check_mod_attrs, def_id!()); } - DepKind::CheckModLoops => { force!(check_mod_loops, def_id!()); } - DepKind::CheckModUnstableApiUsage => { force!(check_mod_unstable_api_usage, def_id!()); } - DepKind::CheckModItemTypes => { force!(check_mod_item_types, def_id!()); } - DepKind::CheckModPrivacy => { force!(check_mod_privacy, def_id!()); } - DepKind::CheckModIntrinsics => { force!(check_mod_intrinsics, def_id!()); } - DepKind::CheckModLiveness => { force!(check_mod_liveness, def_id!()); } - DepKind::CheckModImplWf => { force!(check_mod_impl_wf, def_id!()); } - DepKind::CollectModItemTypes => { force!(collect_mod_item_types, def_id!()); } - DepKind::Reachability => { force!(reachable_set, LOCAL_CRATE); } - DepKind::CrateVariances => { force!(crate_variances, LOCAL_CRATE); } - DepKind::AssociatedItems => { force!(associated_item, def_id!()); } - DepKind::PredicatesDefinedOnItem => { force!(predicates_defined_on, def_id!()); } - DepKind::ExplicitPredicatesOfItem => { force!(explicit_predicates_of, def_id!()); } - DepKind::InferredOutlivesOf => { force!(inferred_outlives_of, def_id!()); } - DepKind::InferredOutlivesCrate => { force!(inferred_outlives_crate, LOCAL_CRATE); } - DepKind::SuperPredicatesOfItem => { force!(super_predicates_of, def_id!()); } - DepKind::TraitDefOfItem => { force!(trait_def, def_id!()); } - DepKind::AdtDefOfItem => { force!(adt_def, def_id!()); } - DepKind::ImplTraitRef => { force!(impl_trait_ref, def_id!()); } - DepKind::ImplPolarity => { force!(impl_polarity, def_id!()); } - DepKind::Issue33140SelfTy => { force!(issue33140_self_ty, def_id!()); } - DepKind::FnSignature => { force!(fn_sig, def_id!()); } - DepKind::CoerceUnsizedInfo => { force!(coerce_unsized_info, def_id!()); } - DepKind::ItemVariances => { force!(variances_of, def_id!()); } - DepKind::IsConstFn => { force!(is_const_fn_raw, def_id!()); } - DepKind::IsPromotableConstFn => { force!(is_promotable_const_fn, def_id!()); } - DepKind::IsForeignItem => { force!(is_foreign_item, def_id!()); } - DepKind::SizedConstraint => { force!(adt_sized_constraint, def_id!()); } - DepKind::DtorckConstraint => { force!(adt_dtorck_constraint, def_id!()); } - DepKind::AdtDestructor => { force!(adt_destructor, def_id!()); } - DepKind::AssociatedItemDefIds => { force!(associated_item_def_ids, def_id!()); } - DepKind::InherentImpls => { force!(inherent_impls, def_id!()); } - DepKind::TypeckBodiesKrate => { force!(typeck_item_bodies, LOCAL_CRATE); } - DepKind::TypeckTables => { force!(typeck_tables_of, def_id!()); } - DepKind::UsedTraitImports => { force!(used_trait_imports, def_id!()); } - DepKind::HasTypeckTables => { force!(has_typeck_tables, def_id!()); } - DepKind::SpecializationGraph => { force!(specialization_graph_of, def_id!()); } - DepKind::ObjectSafety => { force!(is_object_safe, def_id!()); } - DepKind::TraitImpls => { force!(trait_impls_of, def_id!()); } - DepKind::CheckMatch => { force!(check_match, def_id!()); } - - DepKind::ParamEnv => { force!(param_env, def_id!()); } - DepKind::DescribeDef => { force!(describe_def, def_id!()); } - DepKind::DefSpan => { force!(def_span, def_id!()); } - DepKind::LookupStability => { force!(lookup_stability, def_id!()); } - DepKind::LookupDeprecationEntry => { - force!(lookup_deprecation_entry, def_id!()); - } - DepKind::ConstIsRvaluePromotableToStatic => { - force!(const_is_rvalue_promotable_to_static, def_id!()); - } - DepKind::RvaluePromotableMap => { force!(rvalue_promotable_map, def_id!()); } - DepKind::ImplParent => { force!(impl_parent, def_id!()); } - DepKind::TraitOfItem => { force!(trait_of_item, def_id!()); } - DepKind::IsReachableNonGeneric => { force!(is_reachable_non_generic, def_id!()); } - DepKind::IsUnreachableLocalDefinition => { - force!(is_unreachable_local_definition, def_id!()); - } - DepKind::IsMirAvailable => { force!(is_mir_available, def_id!()); } - DepKind::ItemAttrs => { force!(item_attrs, def_id!()); } - DepKind::CodegenFnAttrs => { force!(codegen_fn_attrs, def_id!()); } - DepKind::FnArgNames => { force!(fn_arg_names, def_id!()); } - DepKind::RenderedConst => { force!(rendered_const, def_id!()); } - DepKind::DylibDepFormats => { force!(dylib_dependency_formats, krate!()); } - DepKind::IsCompilerBuiltins => { force!(is_compiler_builtins, krate!()); } - DepKind::HasGlobalAllocator => { force!(has_global_allocator, krate!()); } - DepKind::HasPanicHandler => { force!(has_panic_handler, krate!()); } - DepKind::ExternCrate => { force!(extern_crate, def_id!()); } - DepKind::InScopeTraits => { force!(in_scope_traits_map, def_id!().index); } - DepKind::ModuleExports => { force!(module_exports, def_id!()); } - DepKind::IsSanitizerRuntime => { force!(is_sanitizer_runtime, krate!()); } - DepKind::IsProfilerRuntime => { force!(is_profiler_runtime, krate!()); } - DepKind::GetPanicStrategy => { force!(panic_strategy, krate!()); } - DepKind::IsNoBuiltins => { force!(is_no_builtins, krate!()); } - DepKind::ImplDefaultness => { force!(impl_defaultness, def_id!()); } - DepKind::CheckItemWellFormed => { force!(check_item_well_formed, def_id!()); } - DepKind::CheckTraitItemWellFormed => { force!(check_trait_item_well_formed, def_id!()); } - DepKind::CheckImplItemWellFormed => { force!(check_impl_item_well_formed, def_id!()); } - DepKind::ReachableNonGenerics => { force!(reachable_non_generics, krate!()); } - DepKind::EntryFn => { force!(entry_fn, krate!()); } - DepKind::PluginRegistrarFn => { force!(plugin_registrar_fn, krate!()); } - DepKind::ProcMacroDeclsStatic => { force!(proc_macro_decls_static, krate!()); } - DepKind::CrateDisambiguator => { force!(crate_disambiguator, krate!()); } - DepKind::CrateHash => { force!(crate_hash, krate!()); } - DepKind::OriginalCrateName => { force!(original_crate_name, krate!()); } - DepKind::ExtraFileName => { force!(extra_filename, krate!()); } DepKind::Analysis => { force!(analysis, krate!()); } - - DepKind::AllTraitImplementations => { - force!(all_trait_implementations, krate!()); - } - - DepKind::DllimportForeignItems => { - force!(dllimport_foreign_items, krate!()); - } - DepKind::IsDllimportForeignItem => { - force!(is_dllimport_foreign_item, def_id!()); - } - DepKind::IsStaticallyIncludedForeignItem => { - force!(is_statically_included_foreign_item, def_id!()); - } - DepKind::NativeLibraryKind => { force!(native_library_kind, def_id!()); } - DepKind::LinkArgs => { force!(link_args, LOCAL_CRATE); } - - DepKind::ResolveLifetimes => { force!(resolve_lifetimes, krate!()); } - DepKind::NamedRegion => { force!(named_region_map, def_id!().index); } - DepKind::IsLateBound => { force!(is_late_bound_map, def_id!().index); } - DepKind::ObjectLifetimeDefaults => { - force!(object_lifetime_defaults_map, def_id!().index); - } - - DepKind::Visibility => { force!(visibility, def_id!()); } - DepKind::DepKind => { force!(dep_kind, krate!()); } - DepKind::CrateName => { force!(crate_name, krate!()); } - DepKind::ItemChildren => { force!(item_children, def_id!()); } - DepKind::ExternModStmtCnum => { force!(extern_mod_stmt_cnum, def_id!()); } - DepKind::GetLibFeatures => { force!(get_lib_features, LOCAL_CRATE); } - DepKind::DefinedLibFeatures => { force!(defined_lib_features, krate!()); } - DepKind::GetLangItems => { force!(get_lang_items, LOCAL_CRATE); } - DepKind::DefinedLangItems => { force!(defined_lang_items, krate!()); } - DepKind::MissingLangItems => { force!(missing_lang_items, krate!()); } - DepKind::VisibleParentMap => { force!(visible_parent_map, LOCAL_CRATE); } - DepKind::MissingExternCrateItem => { - force!(missing_extern_crate_item, krate!()); - } - DepKind::UsedCrateSource => { force!(used_crate_source, krate!()); } - DepKind::PostorderCnums => { force!(postorder_cnums, LOCAL_CRATE); } - - DepKind::Freevars => { force!(freevars, def_id!()); } - DepKind::MaybeUnusedTraitImport => { - force!(maybe_unused_trait_import, def_id!()); - } - DepKind::NamesImportedByGlobUse => { force!(names_imported_by_glob_use, def_id!()); } - DepKind::MaybeUnusedExternCrates => { force!(maybe_unused_extern_crates, LOCAL_CRATE); } - DepKind::StabilityIndex => { force!(stability_index, LOCAL_CRATE); } - DepKind::AllTraits => { force!(all_traits, LOCAL_CRATE); } - DepKind::AllCrateNums => { force!(all_crate_nums, LOCAL_CRATE); } - DepKind::ExportedSymbols => { force!(exported_symbols, krate!()); } - DepKind::CollectAndPartitionMonoItems => { - force!(collect_and_partition_mono_items, LOCAL_CRATE); - } - DepKind::IsCodegenedItem => { force!(is_codegened_item, def_id!()); } - DepKind::OutputFilenames => { force!(output_filenames, LOCAL_CRATE); } - - DepKind::TargetFeaturesWhitelist => { force!(target_features_whitelist, LOCAL_CRATE); } - - DepKind::Features => { force!(features_query, LOCAL_CRATE); } - - DepKind::ForeignModules => { force!(foreign_modules, krate!()); } - - DepKind::UpstreamMonomorphizations => { - force!(upstream_monomorphizations, krate!()); - } - DepKind::UpstreamMonomorphizationsFor => { - force!(upstream_monomorphizations_for, def_id!()); - } - DepKind::BackendOptimizationLevel => { - force!(backend_optimization_level, krate!()); - } ); true @@ -1479,18 +1276,18 @@ macro_rules! impl_load_from_cache { } impl_load_from_cache!( - TypeckTables => typeck_tables_of, + typeck_tables_of => typeck_tables_of, optimized_mir => optimized_mir, - UnsafetyCheckResult => unsafety_check_result, - BorrowCheck => borrowck, - MirBorrowCheck => mir_borrowck, + unsafety_check_result => unsafety_check_result, + borrowck => borrowck, + mir_borrowck => mir_borrowck, mir_const_qualif => mir_const_qualif, - ConstIsRvaluePromotableToStatic => const_is_rvalue_promotable_to_static, - CheckMatch => check_match, + const_is_rvalue_promotable_to_static => const_is_rvalue_promotable_to_static, + check_match => check_match, type_of => type_of, generics_of => generics_of, predicates_of => predicates_of, - UsedTraitImports => used_trait_imports, - CodegenFnAttrs => codegen_fn_attrs, - SpecializationGraph => specialization_graph_of, + used_trait_imports => used_trait_imports, + codegen_fn_attrs => codegen_fn_attrs, + specialization_graph_of => specialization_graph_of, ); diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 4f1fda3f4e5..262dc300334 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -936,7 +936,7 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<Ty<'tcx>> { } } -impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ProjectionKind<'tcx>> { +impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ProjectionKind> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { let v = self.iter().map(|t| t.fold_with(folder)).collect::<SmallVec<[_; 8]>>(); folder.tcx().intern_projs(&v) diff --git a/src/librustc/ty/trait_def.rs b/src/librustc/ty/trait_def.rs index 143b5bf3762..58f21893de1 100644 --- a/src/librustc/ty/trait_def.rs +++ b/src/librustc/ty/trait_def.rs @@ -67,7 +67,7 @@ impl<'a, 'gcx, 'tcx> TraitDef { pub fn ancestors(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, of_impl: DefId) - -> specialization_graph::Ancestors { + -> specialization_graph::Ancestors<'gcx> { specialization_graph::ancestors(tcx, self.def_id, of_impl) } } diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs index 5622fe43436..26194176350 100644 --- a/src/librustc/util/common.rs +++ b/src/librustc/util/common.rs @@ -1,11 +1,10 @@ #![allow(non_camel_case_types)] -use rustc_data_structures::sync::Lock; +use rustc_data_structures::{fx::FxHashMap, sync::Lock}; use std::cell::{RefCell, Cell}; -use std::collections::HashMap; use std::fmt::Debug; -use std::hash::{Hash, BuildHasher}; +use std::hash::Hash; use std::panic; use std::env; use std::time::{Duration, Instant}; @@ -341,8 +340,8 @@ pub trait MemoizationMap { where OP: FnOnce() -> Self::Value; } -impl<K, V, S> MemoizationMap for RefCell<HashMap<K,V,S>> - where K: Hash+Eq+Clone, V: Clone, S: BuildHasher +impl<K, V> MemoizationMap for RefCell<FxHashMap<K,V>> + where K: Hash+Eq+Clone, V: Clone { type Key = K; type Value = V; diff --git a/src/librustc/util/profiling.rs b/src/librustc/util/profiling.rs index 2739a30a291..aabf9a401c6 100644 --- a/src/librustc/util/profiling.rs +++ b/src/librustc/util/profiling.rs @@ -1,14 +1,20 @@ use std::borrow::Cow; -use std::fs; -use std::io::{BufWriter, Write}; -use std::mem; +use std::error::Error; +use std::mem::{self, Discriminant}; use std::process; use std::thread::ThreadId; -use std::time::{Duration, Instant, SystemTime}; +use std::u32; -use crate::session::config::Options; +use crate::ty::query::QueryName; -use rustc_data_structures::fx::FxHashMap; +use measureme::{StringId, TimestampKind}; + +/// MmapSerializatioSink is faster on macOS and Linux +/// but FileSerializationSink is faster on Windows +#[cfg(not(windows))] +type Profiler = measureme::Profiler<measureme::MmapSerializationSink>; +#[cfg(windows)] +type Profiler = measureme::Profiler<measureme::FileSerializationSink>; #[derive(Clone, Copy, Debug, PartialEq, Eq, Ord, PartialOrd)] pub enum ProfileCategory { @@ -35,409 +41,129 @@ pub enum ProfilerEvent { QueryBlockedEnd { query_name: &'static str, category: ProfileCategory, time: u64 }, } -impl ProfilerEvent { - fn timestamp(&self) -> u64 { - use self::ProfilerEvent::*; - - match self { - QueryStart { time, .. } | - QueryEnd { time, .. } | - GenericActivityStart { time, .. } | - GenericActivityEnd { time, .. } | - QueryCacheHit { time, .. } | - QueryCount { time, .. } | - IncrementalLoadResultStart { time, .. } | - IncrementalLoadResultEnd { time, .. } | - QueryBlockedStart { time, .. } | - QueryBlockedEnd { time, .. } => *time - } - } -} - fn thread_id_to_u64(tid: ThreadId) -> u64 { unsafe { mem::transmute::<ThreadId, u64>(tid) } } pub struct SelfProfiler { - events: FxHashMap<ThreadId, Vec<ProfilerEvent>>, - start_time: SystemTime, - start_instant: Instant, + profiler: Profiler, + query_event_kind: StringId, + generic_activity_event_kind: StringId, + incremental_load_result_event_kind: StringId, + query_blocked_event_kind: StringId, + query_cache_hit_event_kind: StringId, } impl SelfProfiler { - pub fn new() -> SelfProfiler { - let profiler = SelfProfiler { - events: Default::default(), - start_time: SystemTime::now(), - start_instant: Instant::now(), + pub fn new() -> Result<SelfProfiler, Box<dyn Error>> { + let filename = format!("pid-{}.rustc_profile", process::id()); + let path = std::path::Path::new(&filename); + let profiler = Profiler::new(path)?; + + let query_event_kind = profiler.alloc_string("Query"); + let generic_activity_event_kind = profiler.alloc_string("GenericActivity"); + let incremental_load_result_event_kind = profiler.alloc_string("IncrementalLoadResult"); + let query_blocked_event_kind = profiler.alloc_string("QueryBlocked"); + let query_cache_hit_event_kind = profiler.alloc_string("QueryCacheHit"); + + Ok(SelfProfiler { + profiler, + query_event_kind, + generic_activity_event_kind, + incremental_load_result_event_kind, + query_blocked_event_kind, + query_cache_hit_event_kind, + }) + } + + fn get_query_name_string_id(query_name: QueryName) -> StringId { + let discriminant = unsafe { + mem::transmute::<Discriminant<QueryName>, u64>(mem::discriminant(&query_name)) }; - profiler + StringId::reserved(discriminant as u32) + } + + pub fn register_query_name(&self, query_name: QueryName) { + let id = SelfProfiler::get_query_name_string_id(query_name); + + self.profiler.alloc_string_with_reserved_id(id, query_name.as_str()); } #[inline] pub fn start_activity( - &mut self, - category: ProfileCategory, + &self, label: impl Into<Cow<'static, str>>, ) { - self.record(ProfilerEvent::GenericActivityStart { - category, - label: label.into(), - time: self.get_time_from_start(), - }) + self.record(&label.into(), self.generic_activity_event_kind, TimestampKind::Start); } #[inline] pub fn end_activity( - &mut self, - category: ProfileCategory, + &self, label: impl Into<Cow<'static, str>>, ) { - self.record(ProfilerEvent::GenericActivityEnd { - category, - label: label.into(), - time: self.get_time_from_start(), - }) + self.record(&label.into(), self.generic_activity_event_kind, TimestampKind::End); } #[inline] - pub fn record_computed_queries( - &mut self, - query_name: &'static str, - category: ProfileCategory, - count: usize) - { - self.record(ProfilerEvent::QueryCount { - query_name, - category, - count, - time: self.get_time_from_start(), - }) + pub fn record_query_hit(&self, query_name: QueryName) { + self.record_query(query_name, self.query_cache_hit_event_kind, TimestampKind::Instant); } #[inline] - pub fn record_query_hit(&mut self, query_name: &'static str, category: ProfileCategory) { - self.record(ProfilerEvent::QueryCacheHit { - query_name, - category, - time: self.get_time_from_start(), - }) + pub fn start_query(&self, query_name: QueryName) { + self.record_query(query_name, self.query_event_kind, TimestampKind::Start); } #[inline] - pub fn start_query(&mut self, query_name: &'static str, category: ProfileCategory) { - self.record(ProfilerEvent::QueryStart { - query_name, - category, - time: self.get_time_from_start(), - }); + pub fn end_query(&self, query_name: QueryName) { + self.record_query(query_name, self.query_event_kind, TimestampKind::End); } #[inline] - pub fn end_query(&mut self, query_name: &'static str, category: ProfileCategory) { - self.record(ProfilerEvent::QueryEnd { + pub fn incremental_load_result_start(&self, query_name: QueryName) { + self.record_query( query_name, - category, - time: self.get_time_from_start(), - }) + self.incremental_load_result_event_kind, + TimestampKind::Start + ); } #[inline] - pub fn incremental_load_result_start(&mut self, query_name: &'static str) { - self.record(ProfilerEvent::IncrementalLoadResultStart { - query_name, - time: self.get_time_from_start(), - }) + pub fn incremental_load_result_end(&self, query_name: QueryName) { + self.record_query(query_name, self.incremental_load_result_event_kind, TimestampKind::End); } #[inline] - pub fn incremental_load_result_end(&mut self, query_name: &'static str) { - self.record(ProfilerEvent::IncrementalLoadResultEnd { - query_name, - time: self.get_time_from_start(), - }) - } - - #[inline] - pub fn query_blocked_start(&mut self, query_name: &'static str, category: ProfileCategory) { - self.record(ProfilerEvent::QueryBlockedStart { - query_name, - category, - time: self.get_time_from_start(), - }) + pub fn query_blocked_start(&self, query_name: QueryName) { + self.record_query(query_name, self.query_blocked_event_kind, TimestampKind::Start); } #[inline] - pub fn query_blocked_end(&mut self, query_name: &'static str, category: ProfileCategory) { - self.record(ProfilerEvent::QueryBlockedEnd { - query_name, - category, - time: self.get_time_from_start(), - }) + pub fn query_blocked_end(&self, query_name: QueryName) { + self.record_query(query_name, self.query_blocked_event_kind, TimestampKind::End); } #[inline] - fn record(&mut self, event: ProfilerEvent) { - let thread_id = std::thread::current().id(); - let events = self.events.entry(thread_id).or_default(); + fn record(&self, event_id: &str, event_kind: StringId, timestamp_kind: TimestampKind) { + let thread_id = thread_id_to_u64(std::thread::current().id()); - events.push(event); + let event_id = self.profiler.alloc_string(event_id); + self.profiler.record_event(event_kind, event_id, thread_id, timestamp_kind); } #[inline] - fn get_time_from_start(&self) -> u64 { - let duration = Instant::now() - self.start_instant; - duration.as_nanos() as u64 - } - - pub fn dump_raw_events(&self, opts: &Options) { - use self::ProfilerEvent::*; - - let pid = process::id(); - - let filename = - format!("{}.profile_events.json", opts.crate_name.clone().unwrap_or_default()); - - let mut file = BufWriter::new(fs::File::create(filename).unwrap()); - - let threads: Vec<_> = - self.events - .keys() - .into_iter() - .map(|tid| format!("{}", thread_id_to_u64(*tid))) - .collect(); - - write!(file, - "{{\ - \"processes\": {{\ - \"{}\": {{\ - \"threads\": [{}],\ - \"crate_name\": \"{}\",\ - \"opt_level\": \"{:?}\",\ - \"incremental\": {}\ - }}\ - }},\ - \"events\": [\ - ", - pid, - threads.join(","), - opts.crate_name.clone().unwrap_or_default(), - opts.optimize, - if opts.incremental.is_some() { "true" } else { "false" }, - ).unwrap(); - - let mut is_first = true; - for (thread_id, events) in &self.events { - let thread_id = thread_id_to_u64(*thread_id); - - for event in events { - if is_first { - is_first = false; - } else { - writeln!(file, ",").unwrap(); - } - - let (secs, nanos) = { - let time = self.start_time + Duration::from_nanos(event.timestamp()); - let time_since_unix = - time.duration_since(SystemTime::UNIX_EPOCH).unwrap_or_default(); - (time_since_unix.as_secs(), time_since_unix.subsec_nanos()) - }; + fn record_query( + &self, + query_name: QueryName, + event_kind: StringId, + timestamp_kind: TimestampKind, + ) { + let dep_node_name = SelfProfiler::get_query_name_string_id(query_name); - match event { - QueryStart { query_name, category, time: _ } => - write!(file, - "{{ \ - \"QueryStart\": {{ \ - \"query_name\": \"{}\",\ - \"category\": \"{:?}\",\ - \"time\": {{\ - \"secs\": {},\ - \"nanos\": {}\ - }},\ - \"thread_id\": {}\ - }}\ - }}", - query_name, - category, - secs, - nanos, - thread_id, - ).unwrap(), - QueryEnd { query_name, category, time: _ } => - write!(file, - "{{\ - \"QueryEnd\": {{\ - \"query_name\": \"{}\",\ - \"category\": \"{:?}\",\ - \"time\": {{\ - \"secs\": {},\ - \"nanos\": {}\ - }},\ - \"thread_id\": {}\ - }}\ - }}", - query_name, - category, - secs, - nanos, - thread_id, - ).unwrap(), - GenericActivityStart { category, label, time: _ } => - write!(file, - "{{ - \"GenericActivityStart\": {{\ - \"category\": \"{:?}\",\ - \"label\": \"{}\",\ - \"time\": {{\ - \"secs\": {},\ - \"nanos\": {}\ - }},\ - \"thread_id\": {}\ - }}\ - }}", - category, - label, - secs, - nanos, - thread_id, - ).unwrap(), - GenericActivityEnd { category, label, time: _ } => - write!(file, - "{{\ - \"GenericActivityEnd\": {{\ - \"category\": \"{:?}\",\ - \"label\": \"{}\",\ - \"time\": {{\ - \"secs\": {},\ - \"nanos\": {}\ - }},\ - \"thread_id\": {}\ - }}\ - }}", - category, - label, - secs, - nanos, - thread_id, - ).unwrap(), - QueryCacheHit { query_name, category, time: _ } => - write!(file, - "{{\ - \"QueryCacheHit\": {{\ - \"query_name\": \"{}\",\ - \"category\": \"{:?}\",\ - \"time\": {{\ - \"secs\": {},\ - \"nanos\": {}\ - }},\ - \"thread_id\": {}\ - }}\ - }}", - query_name, - category, - secs, - nanos, - thread_id, - ).unwrap(), - QueryCount { query_name, category, count, time: _ } => - write!(file, - "{{\ - \"QueryCount\": {{\ - \"query_name\": \"{}\",\ - \"category\": \"{:?}\",\ - \"count\": {},\ - \"time\": {{\ - \"secs\": {},\ - \"nanos\": {}\ - }},\ - \"thread_id\": {}\ - }}\ - }}", - query_name, - category, - count, - secs, - nanos, - thread_id, - ).unwrap(), - IncrementalLoadResultStart { query_name, time: _ } => - write!(file, - "{{\ - \"IncrementalLoadResultStart\": {{\ - \"query_name\": \"{}\",\ - \"time\": {{\ - \"secs\": {},\ - \"nanos\": {}\ - }},\ - \"thread_id\": {}\ - }}\ - }}", - query_name, - secs, - nanos, - thread_id, - ).unwrap(), - IncrementalLoadResultEnd { query_name, time: _ } => - write!(file, - "{{\ - \"IncrementalLoadResultEnd\": {{\ - \"query_name\": \"{}\",\ - \"time\": {{\ - \"secs\": {},\ - \"nanos\": {}\ - }},\ - \"thread_id\": {}\ - }}\ - }}", - query_name, - secs, - nanos, - thread_id, - ).unwrap(), - QueryBlockedStart { query_name, category, time: _ } => - write!(file, - "{{\ - \"QueryBlockedStart\": {{\ - \"query_name\": \"{}\",\ - \"category\": \"{:?}\",\ - \"time\": {{\ - \"secs\": {},\ - \"nanos\": {}\ - }},\ - \"thread_id\": {}\ - }}\ - }}", - query_name, - category, - secs, - nanos, - thread_id, - ).unwrap(), - QueryBlockedEnd { query_name, category, time: _ } => - write!(file, - "{{\ - \"QueryBlockedEnd\": {{\ - \"query_name\": \"{}\",\ - \"category\": \"{:?}\",\ - \"time\": {{\ - \"secs\": {},\ - \"nanos\": {}\ - }},\ - \"thread_id\": {}\ - }}\ - }}", - query_name, - category, - secs, - nanos, - thread_id, - ).unwrap(), - } - } - } + let thread_id = thread_id_to_u64(std::thread::current().id()); - write!(file, "] }}").unwrap(); + self.profiler.record_event(event_kind, dep_node_name, thread_id, timestamp_kind); } } diff --git a/src/librustc_allocator/lib.rs b/src/librustc_allocator/lib.rs index 9d6e728e135..a9e422fb238 100644 --- a/src/librustc_allocator/lib.rs +++ b/src/librustc_allocator/lib.rs @@ -2,6 +2,7 @@ #![feature(rustc_private)] #![deny(rust_2018_idioms)] +#![cfg_attr(not(stage0), deny(internal))] pub mod expand; diff --git a/src/librustc_asan/Cargo.toml b/src/librustc_asan/Cargo.toml index 7d9641c83ee..df117de8720 100644 --- a/src/librustc_asan/Cargo.toml +++ b/src/librustc_asan/Cargo.toml @@ -12,7 +12,7 @@ test = false [build-dependencies] build_helper = { path = "../build_helper" } -cmake = "0.1.18" +cmake = "0.1.38" [dependencies] alloc = { path = "../liballoc" } diff --git a/src/librustc_borrowck/lib.rs b/src/librustc_borrowck/lib.rs index cf4669db87e..3761a52bccc 100644 --- a/src/librustc_borrowck/lib.rs +++ b/src/librustc_borrowck/lib.rs @@ -2,6 +2,7 @@ #![allow(non_camel_case_types)] #![deny(rust_2018_idioms)] +#![cfg_attr(not(stage0), deny(internal))] #![feature(nll)] diff --git a/src/librustc_codegen_llvm/abi.rs b/src/librustc_codegen_llvm/abi.rs index 3a0d9e1334c..348616790b0 100644 --- a/src/librustc_codegen_llvm/abi.rs +++ b/src/librustc_codegen_llvm/abi.rs @@ -266,7 +266,8 @@ impl ArgTypeExt<'ll, 'tcx> for ArgType<'tcx, Ty<'tcx>> { OperandValue::Ref(next(), Some(next()), self.layout.align.abi).store(bx, dst); } PassMode::Direct(_) | PassMode::Indirect(_, None) | PassMode::Cast(_) => { - self.store(bx, next(), dst); + let next_arg = next(); + self.store(bx, next_arg, dst); } } } diff --git a/src/librustc_codegen_llvm/attributes.rs b/src/librustc_codegen_llvm/attributes.rs index 77fa34e74dd..b15a64c966b 100644 --- a/src/librustc_codegen_llvm/attributes.rs +++ b/src/librustc_codegen_llvm/attributes.rs @@ -104,7 +104,7 @@ pub fn set_probestack(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) { } // probestack doesn't play nice either with pgo-gen. - if cx.sess().opts.debugging_opts.pgo_gen.is_some() { + if cx.sess().opts.debugging_opts.pgo_gen.enabled() { return; } diff --git a/src/librustc_codegen_llvm/back/link.rs b/src/librustc_codegen_llvm/back/link.rs index f10bc0516e5..6a3c2adc856 100644 --- a/src/librustc_codegen_llvm/back/link.rs +++ b/src/librustc_codegen_llvm/back/link.rs @@ -1014,7 +1014,7 @@ fn link_args(cmd: &mut dyn Linker, cmd.build_static_executable(); } - if sess.opts.debugging_opts.pgo_gen.is_some() { + if sess.opts.debugging_opts.pgo_gen.enabled() { cmd.pgo_gen(); } @@ -1396,10 +1396,6 @@ fn add_upstream_rust_crates(cmd: &mut dyn Linker, // Same thing as above, but for dynamic crates instead of static crates. fn add_dynamic_crate(cmd: &mut dyn Linker, sess: &Session, cratepath: &Path) { - // If we're performing LTO, then it should have been previously required - // that all upstream rust dependencies were available in an rlib format. - assert!(!are_upstream_rust_objects_already_included(sess)); - // Just need to tell the linker about where the library lives and // what its name is let parent = cratepath.parent(); diff --git a/src/librustc_codegen_llvm/back/lto.rs b/src/librustc_codegen_llvm/back/lto.rs index 84c652ff238..348f1a12126 100644 --- a/src/librustc_codegen_llvm/back/lto.rs +++ b/src/librustc_codegen_llvm/back/lto.rs @@ -15,7 +15,6 @@ use rustc::hir::def_id::LOCAL_CRATE; use rustc::middle::exported_symbols::SymbolExportLevel; use rustc::session::config::{self, Lto}; use rustc::util::common::time_ext; -use rustc::util::profiling::ProfileCategory; use rustc_data_structures::fx::FxHashMap; use rustc_codegen_ssa::{ModuleCodegen, ModuleKind}; @@ -67,8 +66,7 @@ fn prepare_lto(cgcx: &CodegenContext<LlvmCodegenBackend>, .iter() .filter_map(symbol_filter) .collect::<Vec<CString>>(); - let _timer = cgcx.profile_activity(ProfileCategory::Codegen, - "generate_symbol_white_list_for_thinlto"); + let _timer = cgcx.profile_activity("generate_symbol_white_list_for_thinlto"); info!("{} symbols to preserve in this crate", symbol_white_list.len()); // If we're performing LTO for the entire crate graph, then for each of our @@ -97,8 +95,7 @@ fn prepare_lto(cgcx: &CodegenContext<LlvmCodegenBackend>, } for &(cnum, ref path) in cgcx.each_linked_rlib_for_lto.iter() { - let _timer = cgcx.profile_activity(ProfileCategory::Codegen, - format!("load: {}", path.display())); + let _timer = cgcx.profile_activity(format!("load: {}", path.display())); let exported_symbols = cgcx.exported_symbols .as_ref().expect("needs exported symbols for LTO"); symbol_white_list.extend( @@ -727,8 +724,7 @@ pub unsafe fn optimize_thin_module( // Like with "fat" LTO, get some better optimizations if landing pads // are disabled by removing all landing pads. if cgcx.no_landing_pads { - let _timer = cgcx.profile_activity(ProfileCategory::Codegen, - "LLVM_remove_landing_pads"); + let _timer = cgcx.profile_activity("LLVM_remove_landing_pads"); llvm::LLVMRustMarkAllFunctionsNounwind(llmod); save_temp_bitcode(&cgcx, &module, "thin-lto-after-nounwind"); } diff --git a/src/librustc_codegen_llvm/back/write.rs b/src/librustc_codegen_llvm/back/write.rs index 7f259024cee..d803f10746e 100644 --- a/src/librustc_codegen_llvm/back/write.rs +++ b/src/librustc_codegen_llvm/back/write.rs @@ -13,12 +13,11 @@ use crate::LlvmCodegenBackend; use rustc::hir::def_id::LOCAL_CRATE; use rustc_codegen_ssa::back::write::{CodegenContext, ModuleConfig, run_assembler}; use rustc_codegen_ssa::traits::*; -use rustc::session::config::{self, OutputType, Passes, Lto}; +use rustc::session::config::{self, OutputType, Passes, Lto, PgoGenerate}; use rustc::session::Session; use rustc::ty::TyCtxt; use rustc_codegen_ssa::{ModuleCodegen, CompiledModule}; use rustc::util::common::time_ext; -use rustc::util::profiling::ProfileCategory; use rustc_fs_util::{path_to_c_string, link_or_copy}; use rustc_data_structures::small_c_str::SmallCStr; use errors::{Handler, FatalError}; @@ -26,7 +25,7 @@ use errors::{Handler, FatalError}; use std::ffi::{CString, CStr}; use std::fs; use std::io::{self, Write}; -use std::path::Path; +use std::path::{Path, PathBuf}; use std::str; use std::sync::Arc; use std::slice; @@ -73,12 +72,10 @@ pub fn write_output_file( unsafe { let output_c = path_to_c_string(output); let result = llvm::LLVMRustWriteOutputFile(target, pm, m, output_c.as_ptr(), file_type); - if result.into_result().is_err() { + result.into_result().map_err(|()| { let msg = format!("could not write output to {}", output.display()); - Err(llvm_err(handler, &msg)) - } else { - Ok(()) - } + llvm_err(handler, &msg) + }) } } @@ -416,7 +413,7 @@ pub(crate) unsafe fn optimize(cgcx: &CodegenContext<LlvmCodegenBackend>, // Finally, run the actual optimization passes { - let _timer = cgcx.profile_activity(ProfileCategory::Codegen, "LLVM_function_passes"); + let _timer = cgcx.profile_activity("LLVM_function_passes"); time_ext(config.time_passes, None, &format!("llvm function passes [{}]", module_name.unwrap()), @@ -425,7 +422,7 @@ pub(crate) unsafe fn optimize(cgcx: &CodegenContext<LlvmCodegenBackend>, }); } { - let _timer = cgcx.profile_activity(ProfileCategory::Codegen, "LLVM_module_passes"); + let _timer = cgcx.profile_activity("LLVM_module_passes"); time_ext(config.time_passes, None, &format!("llvm module passes [{}]", module_name.unwrap()), @@ -447,7 +444,7 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext<LlvmCodegenBackend>, config: &ModuleConfig) -> Result<CompiledModule, FatalError> { - let _timer = cgcx.profile_activity(ProfileCategory::Codegen, "codegen"); + let _timer = cgcx.profile_activity("codegen"); { let llmod = module.module_llvm.llmod(); let llcx = &*module.module_llvm.llcx; @@ -498,29 +495,30 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext<LlvmCodegenBackend>, if write_bc || config.emit_bc_compressed || config.embed_bitcode { - let _timer = cgcx.profile_activity(ProfileCategory::Codegen, "LLVM_make_bitcode"); + let _timer = cgcx.profile_activity("LLVM_make_bitcode"); let thin = ThinBuffer::new(llmod); let data = thin.data(); if write_bc { - let _timer = cgcx.profile_activity(ProfileCategory::Codegen, "LLVM_emit_bitcode"); + let _timer = cgcx.profile_activity("LLVM_emit_bitcode"); if let Err(e) = fs::write(&bc_out, data) { - diag_handler.err(&format!("failed to write bytecode: {}", e)); + let msg = format!("failed to write bytecode to {}: {}", bc_out.display(), e); + diag_handler.err(&msg); } } if config.embed_bitcode { - let _timer = cgcx.profile_activity(ProfileCategory::Codegen, "LLVM_embed_bitcode"); + let _timer = cgcx.profile_activity("LLVM_embed_bitcode"); embed_bitcode(cgcx, llcx, llmod, Some(data)); } if config.emit_bc_compressed { - let _timer = cgcx.profile_activity(ProfileCategory::Codegen, - "LLVM_compress_bitcode"); + let _timer = cgcx.profile_activity("LLVM_compress_bitcode"); let dst = bc_out.with_extension(RLIB_BYTECODE_EXTENSION); let data = bytecode::encode(&module.name, data); if let Err(e) = fs::write(&dst, data) { - diag_handler.err(&format!("failed to write bytecode: {}", e)); + let msg = format!("failed to write bytecode to {}: {}", dst.display(), e); + diag_handler.err(&msg); } } } else if config.embed_bitcode_marker { @@ -530,9 +528,9 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext<LlvmCodegenBackend>, time_ext(config.time_passes, None, &format!("codegen passes [{}]", module_name.unwrap()), || -> Result<(), FatalError> { if config.emit_ir { - let _timer = cgcx.profile_activity(ProfileCategory::Codegen, "LLVM_emit_ir"); + let _timer = cgcx.profile_activity("LLVM_emit_ir"); let out = cgcx.output_filenames.temp_path(OutputType::LlvmAssembly, module_name); - let out = path_to_c_string(&out); + let out_c = path_to_c_string(&out); extern "C" fn demangle_callback(input_ptr: *const c_char, input_len: size_t, @@ -566,13 +564,18 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext<LlvmCodegenBackend>, } with_codegen(tm, llmod, config.no_builtins, |cpm| { - llvm::LLVMRustPrintModule(cpm, llmod, out.as_ptr(), demangle_callback); + let result = + llvm::LLVMRustPrintModule(cpm, llmod, out_c.as_ptr(), demangle_callback); llvm::LLVMDisposePassManager(cpm); - }); + result.into_result().map_err(|()| { + let msg = format!("failed to write LLVM IR to {}", out.display()); + llvm_err(diag_handler, &msg) + }) + })?; } if config.emit_asm || asm_to_obj { - let _timer = cgcx.profile_activity(ProfileCategory::Codegen, "LLVM_emit_asm"); + let _timer = cgcx.profile_activity("LLVM_emit_asm"); let path = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name); // We can't use the same module for asm and binary output, because that triggers @@ -590,13 +593,13 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext<LlvmCodegenBackend>, } if write_obj { - let _timer = cgcx.profile_activity(ProfileCategory::Codegen, "LLVM_emit_obj"); + let _timer = cgcx.profile_activity("LLVM_emit_obj"); with_codegen(tm, llmod, config.no_builtins, |cpm| { write_output_file(diag_handler, tm, cpm, llmod, &obj_out, llvm::FileType::ObjectFile) })?; } else if asm_to_obj { - let _timer = cgcx.profile_activity(ProfileCategory::Codegen, "LLVM_asm_to_obj"); + let _timer = cgcx.profile_activity("LLVM_asm_to_obj"); let assembly = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name); run_assembler(cgcx, diag_handler, &assembly, &obj_out); @@ -703,10 +706,20 @@ pub unsafe fn with_llvm_pmb(llmod: &llvm::Module, .unwrap_or(llvm::CodeGenOptSizeNone); let inline_threshold = config.inline_threshold; - let pgo_gen_path = config.pgo_gen.as_ref().map(|s| { - let s = if s.is_empty() { "default_%m.profraw" } else { s }; - CString::new(s.as_bytes()).unwrap() - }); + let pgo_gen_path = match config.pgo_gen { + PgoGenerate::Enabled(ref opt_dir_path) => { + let path = if let Some(dir_path) = opt_dir_path { + dir_path.join("default_%m.profraw") + } else { + PathBuf::from("default_%m.profraw") + }; + + Some(CString::new(format!("{}", path.display())).unwrap()) + } + PgoGenerate::Disabled => { + None + } + }; let pgo_use_path = if config.pgo_use.is_empty() { None @@ -790,6 +803,7 @@ fn create_msvc_imps( } else { "\x01__imp_" }; + unsafe { let i8p_ty = Type::i8p_llcx(llcx); let globals = base::iter_globals(llmod) @@ -797,14 +811,23 @@ fn create_msvc_imps( llvm::LLVMRustGetLinkage(val) == llvm::Linkage::ExternalLinkage && llvm::LLVMIsDeclaration(val) == 0 }) - .map(move |val| { + .filter_map(|val| { + // Exclude some symbols that we know are not Rust symbols. let name = CStr::from_ptr(llvm::LLVMGetValueName(val)); + if ignored(name.to_bytes()) { + None + } else { + Some((val, name)) + } + }) + .map(move |(val, name)| { let mut imp_name = prefix.as_bytes().to_vec(); imp_name.extend(name.to_bytes()); let imp_name = CString::new(imp_name).unwrap(); (imp_name, val) }) .collect::<Vec<_>>(); + for (imp_name, val) in globals { let imp = llvm::LLVMAddGlobal(llmod, i8p_ty, @@ -813,4 +836,10 @@ fn create_msvc_imps( llvm::LLVMRustSetLinkage(imp, llvm::Linkage::ExternalLinkage); } } + + // Use this function to exclude certain symbols from `__imp` generation. + fn ignored(symbol_name: &[u8]) -> bool { + // These are symbols generated by LLVM's profiling instrumentation + symbol_name.starts_with(b"__llvm_profile_") + } } diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs index e549b120da9..6560ed0a8e6 100644 --- a/src/librustc_codegen_llvm/debuginfo/metadata.rs +++ b/src/librustc_codegen_llvm/debuginfo/metadata.rs @@ -22,6 +22,7 @@ use rustc::hir::CodegenFnAttrFlags; use rustc::hir::def::CtorKind; use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE}; use rustc::ich::NodeIdHashingMode; +use rustc::mir::Field; use rustc::mir::interpret::truncate; use rustc_data_structures::fingerprint::Fingerprint; use rustc::ty::Instance; @@ -117,6 +118,32 @@ impl TypeMap<'ll, 'tcx> { } } + // Removes a Ty to metadata mapping + // This is useful when computing the metadata for a potentially + // recursive type (e.g. a function ptr of the form: + // + // fn foo() -> impl Copy { foo } + // + // This kind of type cannot be properly represented + // via LLVM debuginfo. As a workaround, + // we register a temporary Ty to metadata mapping + // for the function before we compute its actual metadata. + // If the metadata computation ends up recursing back to the + // original function, it will use the temporary mapping + // for the inner self-reference, preventing us from + // recursing forever. + // + // This function is used to remove the temporary metadata + // mapping after we've computed the actual metadata + fn remove_type( + &mut self, + type_: Ty<'tcx>, + ) { + if self.type_to_metadata.remove(type_).is_none() { + bug!("Type metadata Ty '{}' is not in the TypeMap!", type_); + } + } + // Adds a UniqueTypeId to metadata mapping to the TypeMap. The method will // fail if the mapping already exists. fn register_unique_id_with_metadata( @@ -608,10 +635,7 @@ pub fn type_metadata( } } ty::FnDef(..) | ty::FnPtr(_) => { - let fn_metadata = subroutine_type_metadata(cx, - unique_type_id, - t.fn_sig(cx.tcx), - usage_site_span).metadata; + if let Some(metadata) = debug_context(cx).type_map .borrow() .find_metadata_for_unique_id(unique_type_id) @@ -619,6 +643,41 @@ pub fn type_metadata( return metadata; } + // It's possible to create a self-referential + // type in Rust by using 'impl trait': + // + // fn foo() -> impl Copy { foo } + // + // See TypeMap::remove_type for more detals + // about the workaround + + let temp_type = { + unsafe { + // The choice of type here is pretty arbitrary - + // anything reading the debuginfo for a recursive + // type is going to see *somthing* weird - the only + // question is what exactly it will see + let (size, align) = cx.size_and_align_of(t); + llvm::LLVMRustDIBuilderCreateBasicType( + DIB(cx), + SmallCStr::new("<recur_type>").as_ptr(), + size.bits(), + align.bits() as u32, + DW_ATE_unsigned) + } + }; + + let type_map = &debug_context(cx).type_map; + type_map.borrow_mut().register_type_with_metadata(t, temp_type); + + let fn_metadata = subroutine_type_metadata(cx, + unique_type_id, + t.fn_sig(cx.tcx), + usage_site_span).metadata; + + type_map.borrow_mut().remove_type(t); + + // This is actually a function pointer, so wrap it in pointer DI MetadataCreationResult::new(pointer_type_metadata(cx, t, fn_metadata), false) @@ -1248,12 +1307,15 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { } layout::Variants::Multiple { discr_kind: layout::DiscriminantKind::Tag, + discr_index, ref variants, .. } => { let discriminant_info = if fallback { - RegularDiscriminant(self.discriminant_type_metadata - .expect("")) + RegularDiscriminant { + discr_field: Field::from(discr_index), + discr_type_metadata: self.discriminant_type_metadata.unwrap() + } } else { // This doesn't matter in this case. NoDiscriminant @@ -1300,6 +1362,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { }, ref discr, ref variants, + discr_index, } => { if fallback { let variant = self.layout.for_variant(cx, dataful_variant); @@ -1345,8 +1408,8 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { } compute_field_path(cx, &mut name, self.layout, - self.layout.fields.offset(0), - self.layout.field(cx, 0).size); + self.layout.fields.offset(discr_index), + self.layout.field(cx, discr_index).size); name.push_str(&adt.variants[*niche_variants.start()].ident.as_str()); // Create the (singleton) list of descriptions of union members. @@ -1428,6 +1491,8 @@ impl VariantMemberDescriptionFactory<'ll, 'tcx> { name: name.to_string(), type_metadata: if use_enum_fallback(cx) { match self.discriminant_type_metadata { + // Discriminant is always the first field of our variant + // when using the enum fallback. Some(metadata) if i == 0 => metadata, _ => type_metadata(cx, ty, self.span) } @@ -1446,7 +1511,7 @@ impl VariantMemberDescriptionFactory<'ll, 'tcx> { #[derive(Copy, Clone)] enum EnumDiscriminantInfo<'ll> { - RegularDiscriminant(&'ll DIType), + RegularDiscriminant{ discr_field: Field, discr_type_metadata: &'ll DIType }, OptimizedDiscriminant, NoDiscriminant } @@ -1477,15 +1542,26 @@ fn describe_enum_variant( unique_type_id, Some(containing_scope)); + let arg_name = |i: usize| { + if variant.ctor_kind == CtorKind::Fn { + format!("__{}", i) + } else { + variant.fields[i].ident.to_string() + } + }; + // Build an array of (field name, field type) pairs to be captured in the factory closure. let (offsets, args) = if use_enum_fallback(cx) { // If this is not a univariant enum, there is also the discriminant field. let (discr_offset, discr_arg) = match discriminant_info { - RegularDiscriminant(_) => { + RegularDiscriminant { discr_field, .. } => { // We have the layout of an enum variant, we need the layout of the outer enum let enum_layout = cx.layout_of(layout.ty); - (Some(enum_layout.fields.offset(0)), - Some(("RUST$ENUM$DISR".to_owned(), enum_layout.field(cx, 0).ty))) + let offset = enum_layout.fields.offset(discr_field.as_usize()); + let args = ( + "RUST$ENUM$DISR".to_owned(), + enum_layout.field(cx, discr_field.as_usize()).ty); + (Some(offset), Some(args)) } _ => (None, None), }; @@ -1494,12 +1570,7 @@ fn describe_enum_variant( layout.fields.offset(i) })).collect(), discr_arg.into_iter().chain((0..layout.fields.count()).map(|i| { - let name = if variant.ctor_kind == CtorKind::Fn { - format!("__{}", i) - } else { - variant.fields[i].ident.to_string() - }; - (name, layout.field(cx, i).ty) + (arg_name(i), layout.field(cx, i).ty) })).collect() ) } else { @@ -1508,12 +1579,7 @@ fn describe_enum_variant( layout.fields.offset(i) }).collect(), (0..layout.fields.count()).map(|i| { - let name = if variant.ctor_kind == CtorKind::Fn { - format!("__{}", i) - } else { - variant.fields[i].ident.to_string() - }; - (name, layout.field(cx, i).ty) + (arg_name(i), layout.field(cx, i).ty) }).collect() ) }; @@ -1523,8 +1589,8 @@ fn describe_enum_variant( offsets, args, discriminant_type_metadata: match discriminant_info { - RegularDiscriminant(discriminant_type_metadata) => { - Some(discriminant_type_metadata) + RegularDiscriminant { discr_type_metadata, .. } => { + Some(discr_type_metadata) } _ => None }, @@ -1674,6 +1740,7 @@ fn prepare_enum_metadata( layout::Variants::Multiple { discr_kind: layout::DiscriminantKind::Niche { .. }, ref discr, + discr_index, .. } => { // Find the integer type of the correct size. @@ -1697,7 +1764,7 @@ fn prepare_enum_metadata( UNKNOWN_LINE_NUMBER, size.bits(), align.abi.bits() as u32, - layout.fields.offset(0).bits(), + layout.fields.offset(discr_index).bits(), DIFlags::FlagArtificial, discr_metadata)) } @@ -1706,6 +1773,7 @@ fn prepare_enum_metadata( layout::Variants::Multiple { discr_kind: layout::DiscriminantKind::Tag, ref discr, + discr_index, .. } => { let discr_type = discr.value.to_ty(cx.tcx); @@ -1721,7 +1789,7 @@ fn prepare_enum_metadata( UNKNOWN_LINE_NUMBER, size.bits(), align.bits() as u32, - layout.fields.offset(0).bits(), + layout.fields.offset(discr_index).bits(), DIFlags::FlagArtificial, discr_metadata)) } diff --git a/src/librustc_codegen_llvm/debuginfo/mod.rs b/src/librustc_codegen_llvm/debuginfo/mod.rs index 6abbcd9feba..57e4ac07d5e 100644 --- a/src/librustc_codegen_llvm/debuginfo/mod.rs +++ b/src/librustc_codegen_llvm/debuginfo/mod.rs @@ -296,12 +296,6 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { let mut flags = DIFlags::FlagPrototyped; - if let Some((id, _)) = self.tcx.entry_fn(LOCAL_CRATE) { - if id == def_id { - flags |= DIFlags::FlagMainSubprogram; - } - } - if self.layout_of(sig.output()).abi.is_uninhabited() { flags |= DIFlags::FlagNoReturn; } @@ -313,6 +307,11 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { if self.sess().opts.optimize != config::OptLevel::No { spflags |= DISPFlags::SPFlagOptimized; } + if let Some((id, _)) = self.tcx.entry_fn(LOCAL_CRATE) { + if id == def_id { + spflags |= DISPFlags::SPFlagMainSubprogram; + } + } let fn_metadata = unsafe { llvm::LLVMRustDIBuilderCreateFunction( diff --git a/src/librustc_codegen_llvm/debuginfo/type_names.rs b/src/librustc_codegen_llvm/debuginfo/type_names.rs index 8b218ab39d9..eff7cd1bc8a 100644 --- a/src/librustc_codegen_llvm/debuginfo/type_names.rs +++ b/src/librustc_codegen_llvm/debuginfo/type_names.rs @@ -5,6 +5,7 @@ use rustc::hir::def_id::DefId; use rustc::ty::subst::SubstsRef; use rustc::ty::{self, Ty}; use rustc_codegen_ssa::traits::*; +use rustc_data_structures::fx::FxHashSet; use rustc::hir; @@ -17,7 +18,8 @@ pub fn compute_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, qualified: bool) -> String { let mut result = String::with_capacity(64); - push_debuginfo_type_name(cx, t, qualified, &mut result); + let mut visited = FxHashSet::default(); + push_debuginfo_type_name(cx, t, qualified, &mut result, &mut visited); result } @@ -26,7 +28,9 @@ pub fn compute_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, t: Ty<'tcx>, qualified: bool, - output: &mut String) { + output: &mut String, + visited: &mut FxHashSet<Ty<'tcx>>) { + // When targeting MSVC, emit C++ style type names for compatibility with // .natvis visualizers (and perhaps other existing native debuggers?) let cpp_like_names = cx.sess().target.target.options.is_like_msvc; @@ -42,12 +46,12 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, ty::Foreign(def_id) => push_item_name(cx, def_id, qualified, output), ty::Adt(def, substs) => { push_item_name(cx, def.did, qualified, output); - push_type_params(cx, substs, output); + push_type_params(cx, substs, output, visited); }, ty::Tuple(component_types) => { output.push('('); for &component_type in component_types { - push_debuginfo_type_name(cx, component_type, true, output); + push_debuginfo_type_name(cx, component_type, true, output, visited); output.push_str(", "); } if !component_types.is_empty() { @@ -65,7 +69,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, hir::MutMutable => output.push_str("mut "), } - push_debuginfo_type_name(cx, inner_type, true, output); + push_debuginfo_type_name(cx, inner_type, true, output, visited); if cpp_like_names { output.push('*'); @@ -79,7 +83,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, output.push_str("mut "); } - push_debuginfo_type_name(cx, inner_type, true, output); + push_debuginfo_type_name(cx, inner_type, true, output, visited); if cpp_like_names { output.push('*'); @@ -87,7 +91,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, }, ty::Array(inner_type, len) => { output.push('['); - push_debuginfo_type_name(cx, inner_type, true, output); + push_debuginfo_type_name(cx, inner_type, true, output, visited); output.push_str(&format!("; {}", len.unwrap_usize(cx.tcx))); output.push(']'); }, @@ -98,7 +102,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, output.push('['); } - push_debuginfo_type_name(cx, inner_type, true, output); + push_debuginfo_type_name(cx, inner_type, true, output, visited); if cpp_like_names { output.push('>'); @@ -113,12 +117,31 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, &principal, ); push_item_name(cx, principal.def_id, false, output); - push_type_params(cx, principal.substs, output); + push_type_params(cx, principal.substs, output, visited); } else { output.push_str("dyn '_"); } }, ty::FnDef(..) | ty::FnPtr(_) => { + // We've encountered a weird 'recursive type' + // Currently, the only way to generate such a type + // is by using 'impl trait': + // + // fn foo() -> impl Copy { foo } + // + // There's not really a sensible name we can generate, + // since we don't include 'impl trait' types (e.g. ty::Opaque) + // in the output + // + // Since we need to generate *something*, we just + // use a dummy string that should make it clear + // that something unusual is going on + if !visited.insert(t) { + output.push_str("<recursive_type>"); + return; + } + + let sig = t.fn_sig(cx.tcx); if sig.unsafety() == hir::Unsafety::Unsafe { output.push_str("unsafe "); @@ -136,7 +159,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, let sig = cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); if !sig.inputs().is_empty() { for ¶meter_type in sig.inputs() { - push_debuginfo_type_name(cx, parameter_type, true, output); + push_debuginfo_type_name(cx, parameter_type, true, output, visited); output.push_str(", "); } output.pop(); @@ -155,8 +178,20 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, if !sig.output().is_unit() { output.push_str(" -> "); - push_debuginfo_type_name(cx, sig.output(), true, output); + push_debuginfo_type_name(cx, sig.output(), true, output, visited); } + + + // We only keep the type in 'visited' + // for the duration of the body of this method. + // It's fine for a particular function type + // to show up multiple times in one overall type + // (e.g. MyType<fn() -> u8, fn() -> u8> + // + // We only care about avoiding recursing + // directly back to the type we're currently + // processing + visited.remove(t); }, ty::Closure(..) => { output.push_str("closure"); @@ -200,7 +235,8 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, // common denominator - otherwise we would run into conflicts. fn push_type_params<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, substs: SubstsRef<'tcx>, - output: &mut String) { + output: &mut String, + visited: &mut FxHashSet<Ty<'tcx>>) { if substs.types().next().is_none() { return; } @@ -208,7 +244,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, output.push('<'); for type_parameter in substs.types() { - push_debuginfo_type_name(cx, type_parameter, true, output); + push_debuginfo_type_name(cx, type_parameter, true, output, visited); output.push_str(", "); } diff --git a/src/librustc_codegen_llvm/lib.rs b/src/librustc_codegen_llvm/lib.rs index 0aae6b46e3d..da91217e95e 100644 --- a/src/librustc_codegen_llvm/lib.rs +++ b/src/librustc_codegen_llvm/lib.rs @@ -65,7 +65,6 @@ use rustc::middle::cstore::{EncodedMetadata, MetadataLoader}; use rustc::session::Session; use rustc::session::config::{OutputFilenames, OutputType, PrintRequest, OptLevel}; use rustc::ty::{self, TyCtxt}; -use rustc::util::profiling::ProfileCategory; use rustc::util::common::ErrorReported; use rustc_mir::monomorphize; use rustc_codegen_ssa::ModuleCodegen; @@ -330,12 +329,12 @@ impl CodegenBackend for LlvmCodegenBackend { // Run the linker on any artifacts that resulted from the LLVM run. // This should produce either a finished executable or library. - sess.profiler(|p| p.start_activity(ProfileCategory::Linking, "link_crate")); + sess.profiler(|p| p.start_activity("link_crate")); time(sess, "linking", || { back::link::link_binary(sess, &codegen_results, outputs, &codegen_results.crate_name.as_str()); }); - sess.profiler(|p| p.end_activity(ProfileCategory::Linking, "link_crate")); + sess.profiler(|p| p.end_activity("link_crate")); // Now that we won't touch anything in the incremental compilation directory // any more, we can finalize it (which involves renaming it) diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/src/librustc_codegen_llvm/llvm/ffi.rs index 2ad6d9c053a..f6ee8bec16a 100644 --- a/src/librustc_codegen_llvm/llvm/ffi.rs +++ b/src/librustc_codegen_llvm/llvm/ffi.rs @@ -588,7 +588,6 @@ pub mod debuginfo { const FlagIntroducedVirtual = (1 << 18); const FlagBitField = (1 << 19); const FlagNoReturn = (1 << 20); - const FlagMainSubprogram = (1 << 21); } } @@ -603,6 +602,7 @@ pub mod debuginfo { const SPFlagLocalToUnit = (1 << 2); const SPFlagDefinition = (1 << 3); const SPFlagOptimized = (1 << 4); + const SPFlagMainSubprogram = (1 << 5); } } @@ -1687,7 +1687,8 @@ extern "C" { Demangle: extern fn(*const c_char, size_t, *mut c_char, - size_t) -> size_t); + size_t) -> size_t, + ) -> LLVMRustResult; pub fn LLVMRustSetLLVMOptions(Argc: c_int, Argv: *const *const c_char); pub fn LLVMRustPrintPasses(); pub fn LLVMRustSetNormalizedTarget(M: &Module, triple: *const c_char); diff --git a/src/librustc_codegen_llvm/type_of.rs b/src/librustc_codegen_llvm/type_of.rs index 020447608ee..d42fa829161 100644 --- a/src/librustc_codegen_llvm/type_of.rs +++ b/src/librustc_codegen_llvm/type_of.rs @@ -452,31 +452,27 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> { _ => { let mut data_variant = match self.variants { + // Within the discriminant field, only the niche itself is + // always initialized, so we only check for a pointer at its + // offset. + // + // If the niche is a pointer, it's either valid (according + // to its type), or null (which the niche field's scalar + // validity range encodes). This allows using + // `dereferenceable_or_null` for e.g., `Option<&T>`, and + // this will continue to work as long as we don't start + // using more niches than just null (e.g., the first page of + // the address space, or unaligned pointers). layout::Variants::Multiple { discr_kind: layout::DiscriminantKind::Niche { dataful_variant, .. }, + discr_index, .. - } => { - // Only the niche itself is always initialized, - // so only check for a pointer at its offset. - // - // If the niche is a pointer, it's either valid - // (according to its type), or null (which the - // niche field's scalar validity range encodes). - // This allows using `dereferenceable_or_null` - // for e.g., `Option<&T>`, and this will continue - // to work as long as we don't start using more - // niches than just null (e.g., the first page - // of the address space, or unaligned pointers). - if self.fields.offset(0) == offset { - Some(self.for_variant(cx, dataful_variant)) - } else { - None - } - } - _ => Some(*self) + } if self.fields.offset(discr_index) == offset => + Some(self.for_variant(cx, dataful_variant)), + _ => Some(*self), }; if let Some(variant) = data_variant { diff --git a/src/librustc_codegen_ssa/back/symbol_export.rs b/src/librustc_codegen_ssa/back/symbol_export.rs index 336f41b784a..a55f783df43 100644 --- a/src/librustc_codegen_ssa/back/symbol_export.rs +++ b/src/librustc_codegen_ssa/back/symbol_export.rs @@ -209,7 +209,7 @@ fn exported_symbols_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } - if tcx.sess.opts.debugging_opts.pgo_gen.is_some() { + if tcx.sess.opts.debugging_opts.pgo_gen.enabled() { // These are weak symbols that point to the profile version and the // profile name, which need to be treated as exported so LTO doesn't nix // them. diff --git a/src/librustc_codegen_ssa/back/write.rs b/src/librustc_codegen_ssa/back/write.rs index fa8c4177eaf..4b02425d40d 100644 --- a/src/librustc_codegen_ssa/back/write.rs +++ b/src/librustc_codegen_ssa/back/write.rs @@ -12,13 +12,14 @@ use rustc_incremental::{copy_cgu_workproducts_to_incr_comp_cache_dir, use rustc::dep_graph::{WorkProduct, WorkProductId, WorkProductFileKind}; use rustc::dep_graph::cgu_reuse_tracker::CguReuseTracker; use rustc::middle::cstore::EncodedMetadata; -use rustc::session::config::{self, OutputFilenames, OutputType, Passes, Sanitizer, Lto}; +use rustc::session::config::{self, OutputFilenames, OutputType, Passes, Lto, + Sanitizer, PgoGenerate}; use rustc::session::Session; use rustc::util::nodemap::FxHashMap; use rustc::hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc::ty::TyCtxt; use rustc::util::common::{time_depth, set_time_depth, print_time_passes_entry}; -use rustc::util::profiling::{ProfileCategory, SelfProfiler}; +use rustc::util::profiling::SelfProfiler; use rustc_fs_util::link_or_copy; use rustc_data_structures::svh::Svh; use rustc_errors::{Handler, Level, DiagnosticBuilder, FatalError, DiagnosticId}; @@ -29,7 +30,6 @@ use syntax::ext::hygiene::Mark; use syntax_pos::MultiSpan; use syntax_pos::symbol::Symbol; use jobserver::{Client, Acquired}; -use parking_lot::Mutex as PlMutex; use std::any::Any; use std::borrow::Cow; @@ -56,7 +56,7 @@ pub struct ModuleConfig { /// Some(level) to optimize binary size, or None to not affect program size. pub opt_size: Option<config::OptLevel>, - pub pgo_gen: Option<String>, + pub pgo_gen: PgoGenerate, pub pgo_use: String, // Flags indicating which outputs to produce. @@ -94,7 +94,7 @@ impl ModuleConfig { opt_level: None, opt_size: None, - pgo_gen: None, + pgo_gen: PgoGenerate::Disabled, pgo_use: String::new(), emit_no_opt_bc: false, @@ -198,25 +198,21 @@ impl<B: WriteBackendMethods> Clone for TargetMachineFactory<B> { } pub struct ProfileGenericActivityTimer { - profiler: Option<Arc<PlMutex<SelfProfiler>>>, - category: ProfileCategory, + profiler: Option<Arc<SelfProfiler>>, label: Cow<'static, str>, } impl ProfileGenericActivityTimer { pub fn start( - profiler: Option<Arc<PlMutex<SelfProfiler>>>, - category: ProfileCategory, + profiler: Option<Arc<SelfProfiler>>, label: Cow<'static, str>, ) -> ProfileGenericActivityTimer { if let Some(profiler) = &profiler { - let mut p = profiler.lock(); - p.start_activity(category, label.clone()); + profiler.start_activity(label.clone()); } ProfileGenericActivityTimer { profiler, - category, label, } } @@ -225,8 +221,7 @@ impl ProfileGenericActivityTimer { impl Drop for ProfileGenericActivityTimer { fn drop(&mut self) { if let Some(profiler) = &self.profiler { - let mut p = profiler.lock(); - p.end_activity(self.category, self.label.clone()); + profiler.end_activity(self.label.clone()); } } } @@ -237,7 +232,7 @@ pub struct CodegenContext<B: WriteBackendMethods> { // Resources needed when running LTO pub backend: B, pub time_passes: bool, - pub profiler: Option<Arc<PlMutex<SelfProfiler>>>, + pub profiler: Option<Arc<SelfProfiler>>, pub lto: Lto, pub no_landing_pads: bool, pub save_temps: bool, @@ -291,19 +286,17 @@ impl<B: WriteBackendMethods> CodegenContext<B> { #[inline(never)] #[cold] - fn profiler_active<F: FnOnce(&mut SelfProfiler) -> ()>(&self, f: F) { + fn profiler_active<F: FnOnce(&SelfProfiler) -> ()>(&self, f: F) { match &self.profiler { None => bug!("profiler_active() called but there was no profiler active"), Some(profiler) => { - let mut p = profiler.lock(); - - f(&mut p); + f(&*profiler); } } } #[inline(always)] - pub fn profile<F: FnOnce(&mut SelfProfiler) -> ()>(&self, f: F) { + pub fn profile<F: FnOnce(&SelfProfiler) -> ()>(&self, f: F) { if unlikely!(self.profiler.is_some()) { self.profiler_active(f) } @@ -311,10 +304,9 @@ impl<B: WriteBackendMethods> CodegenContext<B> { pub fn profile_activity( &self, - category: ProfileCategory, label: impl Into<Cow<'static, str>>, ) -> ProfileGenericActivityTimer { - ProfileGenericActivityTimer::start(self.profiler.clone(), category, label.into()) + ProfileGenericActivityTimer::start(self.profiler.clone(), label.into()) } } @@ -324,7 +316,7 @@ fn generate_lto_work<B: ExtraBackendMethods>( needs_thin_lto: Vec<(String, B::ThinBuffer)>, import_only_modules: Vec<(SerializedModule<B::ModuleBuffer>, WorkProduct)> ) -> Vec<(WorkItem<B>, u64)> { - cgcx.profile(|p| p.start_activity(ProfileCategory::Linking, "codegen_run_lto")); + cgcx.profile(|p| p.start_activity("codegen_run_lto")); let (lto_modules, copy_jobs) = if !needs_fat_lto.is_empty() { assert!(needs_thin_lto.is_empty()); @@ -351,7 +343,7 @@ fn generate_lto_work<B: ExtraBackendMethods>( }), 0) })).collect(); - cgcx.profile(|p| p.end_activity(ProfileCategory::Linking, "codegen_run_lto")); + cgcx.profile(|p| p.end_activity("codegen_run_lto")); result } @@ -1655,9 +1647,9 @@ fn spawn_work<B: ExtraBackendMethods>( // surface that there was an error in this worker. bomb.result = { let label = work.name(); - cgcx.profile(|p| p.start_activity(ProfileCategory::Codegen, label.clone())); + cgcx.profile(|p| p.start_activity(label.clone())); let result = execute_work_item(&cgcx, work).ok(); - cgcx.profile(|p| p.end_activity(ProfileCategory::Codegen, label)); + cgcx.profile(|p| p.end_activity(label)); result }; diff --git a/src/librustc_codegen_ssa/base.rs b/src/librustc_codegen_ssa/base.rs index 27e3e306699..6cb54831a07 100644 --- a/src/librustc_codegen_ssa/base.rs +++ b/src/librustc_codegen_ssa/base.rs @@ -25,7 +25,6 @@ use rustc::ty::layout::{self, Align, TyLayout, LayoutOf, VariantIdx, HasTyCtxt}; use rustc::ty::query::Providers; use rustc::middle::cstore::{self, LinkagePreference}; use rustc::util::common::{time, print_time_passes_entry}; -use rustc::util::profiling::ProfileCategory; use rustc::session::config::{self, EntryFnType, Lto}; use rustc::session::Session; use rustc_mir::monomorphize::item::DefPathBasedNames; @@ -539,7 +538,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>( let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx); // Codegen the metadata. - tcx.sess.profiler(|p| p.start_activity(ProfileCategory::Codegen, "codegen crate metadata")); + tcx.sess.profiler(|p| p.start_activity("codegen crate metadata")); let metadata_cgu_name = cgu_name_builder.build_cgu_name(LOCAL_CRATE, &["crate"], @@ -549,7 +548,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>( let metadata = time(tcx.sess, "write metadata", || { backend.write_metadata(tcx, &mut metadata_llvm_module) }); - tcx.sess.profiler(|p| p.end_activity(ProfileCategory::Codegen, "codegen crate metadata")); + tcx.sess.profiler(|p| p.end_activity("codegen crate metadata")); let metadata_module = ModuleCodegen { name: metadata_cgu_name, @@ -662,14 +661,12 @@ pub fn codegen_crate<B: ExtraBackendMethods>( match cgu_reuse { CguReuse::No => { - tcx.sess.profiler(|p| p.start_activity(ProfileCategory::Codegen, - format!("codegen {}", cgu.name()))); + tcx.sess.profiler(|p| p.start_activity(format!("codegen {}", cgu.name()))); let start_time = Instant::now(); let stats = backend.compile_codegen_unit(tcx, *cgu.name()); all_stats.extend(stats); total_codegen_time += start_time.elapsed(); - tcx.sess.profiler(|p| p.end_activity(ProfileCategory::Codegen, - format!("codegen {}", cgu.name()))); + tcx.sess.profiler(|p| p.end_activity(format!("codegen {}", cgu.name()))); false } CguReuse::PreLto => { diff --git a/src/librustc_codegen_ssa/lib.rs b/src/librustc_codegen_ssa/lib.rs index 1e898ced7a6..e2917578c0e 100644 --- a/src/librustc_codegen_ssa/lib.rs +++ b/src/librustc_codegen_ssa/lib.rs @@ -14,6 +14,7 @@ #![allow(unused_attributes)] #![allow(dead_code)] #![deny(rust_2018_idioms)] +#![cfg_attr(not(stage0), deny(internal))] #![allow(explicit_outlives_requirements)] #![recursion_limit="256"] diff --git a/src/librustc_codegen_ssa/mir/analyze.rs b/src/librustc_codegen_ssa/mir/analyze.rs index facae9a9797..8253a167245 100644 --- a/src/librustc_codegen_ssa/mir/analyze.rs +++ b/src/librustc_codegen_ssa/mir/analyze.rs @@ -172,14 +172,14 @@ impl<'mir, 'a: 'mir, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx> // ZSTs don't require any actual memory access. let elem_ty = base_ty .projection_ty(cx.tcx(), &proj.elem) - .to_ty(cx.tcx()); + .ty; let elem_ty = self.fx.monomorphize(&elem_ty); if cx.layout_of(elem_ty).is_zst() { return; } if let mir::ProjectionElem::Field(..) = proj.elem { - let layout = cx.layout_of(base_ty.to_ty(cx.tcx())); + let layout = cx.layout_of(base_ty.ty); if cx.is_backend_immediate(layout) || cx.is_backend_scalar_pair(layout) { // Recurse with the same context, instead of `Projection`, // potentially stopping at non-operand projections, @@ -247,7 +247,7 @@ impl<'mir, 'a: 'mir, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx> PlaceContext::MutatingUse(MutatingUseContext::Drop) => { let ty = mir::Place::Base(mir::PlaceBase::Local(local)).ty(self.fx.mir, self.fx.cx.tcx()); - let ty = self.fx.monomorphize(&ty.to_ty(self.fx.cx.tcx())); + let ty = self.fx.monomorphize(&ty.ty); // Only need the place if we're actually dropping it. if self.fx.cx.type_needs_drop(ty) { diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs index 26442faa321..e64c847db65 100644 --- a/src/librustc_codegen_ssa/mir/block.rs +++ b/src/librustc_codegen_ssa/mir/block.rs @@ -2,7 +2,7 @@ use rustc::middle::lang_items; use rustc::ty::{self, Ty, TypeFoldable}; use rustc::ty::layout::{self, LayoutOf, HasTyCtxt}; use rustc::mir::{self, Place, PlaceBase, Static, StaticKind}; -use rustc::mir::interpret::EvalErrorKind; +use rustc::mir::interpret::InterpError; use rustc_target::abi::call::{ArgType, FnType, PassMode, IgnoreMode}; use rustc_target::spec::abi::Abi; use rustc_mir::monomorphize; @@ -238,6 +238,13 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } } + if self.fn_ty.ret.layout.abi.is_uninhabited() { + // Functions with uninhabited return values are marked `noreturn`, + // so we should make sure that we never actually do. + bx.abort(); + bx.unreachable(); + return; + } let llval = match self.fn_ty.ret.mode { PassMode::Ignore(IgnoreMode::Zst) | PassMode::Indirect(..) => { bx.ret_void(); @@ -301,7 +308,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { target: mir::BasicBlock, unwind: Option<mir::BasicBlock>, ) { - let ty = location.ty(self.mir, bx.tcx()).to_ty(bx.tcx()); + let ty = location.ty(self.mir, bx.tcx()).ty; let ty = self.monomorphize(&ty); let drop_fn = monomorphize::resolve_drop_in_place(bx.tcx(), ty); @@ -365,7 +372,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // checked operation, just a comparison with the minimum // value, so we have to check for the assert message. if !bx.check_overflow() { - if let mir::interpret::EvalErrorKind::OverflowNeg = *msg { + if let mir::interpret::InterpError::OverflowNeg = *msg { const_cond = Some(expected); } } @@ -400,7 +407,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // Put together the arguments to the panic entry point. let (lang_item, args) = match *msg { - EvalErrorKind::BoundsCheck { ref len, ref index } => { + InterpError::BoundsCheck { ref len, ref index } => { let len = self.codegen_operand(&mut bx, len).immediate(); let index = self.codegen_operand(&mut bx, index).immediate(); diff --git a/src/librustc_codegen_ssa/mir/place.rs b/src/librustc_codegen_ssa/mir/place.rs index 9ed7e26729f..1134707f96c 100644 --- a/src/librustc_codegen_ssa/mir/place.rs +++ b/src/librustc_codegen_ssa/mir/place.rs @@ -216,19 +216,19 @@ impl<'a, 'tcx: 'a, V: CodegenObject> PlaceRef<'tcx, V> { if self.layout.abi.is_uninhabited() { return bx.cx().const_undef(cast_to); } - let (discr_scalar, discr_kind) = match self.layout.variants { + let (discr_scalar, discr_kind, discr_index) = match self.layout.variants { layout::Variants::Single { index } => { let discr_val = self.layout.ty.ty_adt_def().map_or( index.as_u32() as u128, |def| def.discriminant_for_variant(bx.cx().tcx(), index).val); return bx.cx().const_uint_big(cast_to, discr_val); } - layout::Variants::Multiple { ref discr, ref discr_kind, .. } => { - (discr, discr_kind) + layout::Variants::Multiple { ref discr, ref discr_kind, discr_index, .. } => { + (discr, discr_kind, discr_index) } }; - let discr = self.project_field(bx, 0); + let discr = self.project_field(bx, discr_index); let lldiscr = bx.load_operand(discr).immediate(); match *discr_kind { layout::DiscriminantKind::Tag => { @@ -292,9 +292,10 @@ impl<'a, 'tcx: 'a, V: CodegenObject> PlaceRef<'tcx, V> { } layout::Variants::Multiple { discr_kind: layout::DiscriminantKind::Tag, + discr_index, .. } => { - let ptr = self.project_field(bx, 0); + let ptr = self.project_field(bx, discr_index); let to = self.layout.ty.ty_adt_def().unwrap() .discriminant_for_variant(bx.tcx(), variant_index) .val; @@ -309,6 +310,7 @@ impl<'a, 'tcx: 'a, V: CodegenObject> PlaceRef<'tcx, V> { ref niche_variants, niche_start, }, + discr_index, .. } => { if variant_index != dataful_variant { @@ -321,7 +323,7 @@ impl<'a, 'tcx: 'a, V: CodegenObject> PlaceRef<'tcx, V> { bx.memset(self.llval, fill_byte, size, self.align, MemFlags::empty()); } - let niche = self.project_field(bx, 0); + let niche = self.project_field(bx, discr_index); let niche_llty = bx.cx().immediate_backend_type(niche.layout); let niche_value = variant_index.as_u32() - niche_variants.start().as_u32(); let niche_value = (niche_value as u128) @@ -494,8 +496,8 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::ProjectionElem::Subslice { from, to } => { let mut subslice = cg_base.project_index(bx, bx.cx().const_usize(from as u64)); - let projected_ty = PlaceTy::Ty { ty: cg_base.layout.ty } - .projection_ty(tcx, &projection.elem).to_ty(tcx); + let projected_ty = PlaceTy::from_ty(cg_base.layout.ty) + .projection_ty(tcx, &projection.elem).ty; subslice.layout = bx.cx().layout_of(self.monomorphize(&projected_ty)); if subslice.layout.is_unsized() { @@ -523,6 +525,6 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { pub fn monomorphized_place_ty(&self, place: &mir::Place<'tcx>) -> Ty<'tcx> { let tcx = self.cx.tcx(); let place_ty = place.ty(self.mir, tcx); - self.monomorphize(&place_ty.to_ty(tcx)) + self.monomorphize(&place_ty.ty) } } diff --git a/src/librustc_codegen_ssa/mir/statement.rs b/src/librustc_codegen_ssa/mir/statement.rs index 97729e8aeb3..618d05245d2 100644 --- a/src/librustc_codegen_ssa/mir/statement.rs +++ b/src/librustc_codegen_ssa/mir/statement.rs @@ -68,13 +68,13 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } bx } - mir::StatementKind::InlineAsm { ref asm, ref outputs, ref inputs } => { - let outputs = outputs.iter().map(|output| { + mir::StatementKind::InlineAsm(ref asm) => { + let outputs = asm.outputs.iter().map(|output| { self.codegen_place(&mut bx, output) }).collect(); - let input_vals = inputs.iter() - .fold(Vec::with_capacity(inputs.len()), |mut acc, (span, input)| { + let input_vals = asm.inputs.iter() + .fold(Vec::with_capacity(asm.inputs.len()), |mut acc, (span, input)| { let op = self.codegen_operand(&mut bx, input); if let OperandValue::Immediate(_) = op.val { acc.push(op.immediate()); @@ -85,8 +85,8 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { acc }); - if input_vals.len() == inputs.len() { - let res = bx.codegen_inline_asm(asm, outputs, input_vals); + if input_vals.len() == asm.inputs.len() { + let res = bx.codegen_inline_asm(&asm.asm, outputs, input_vals); if !res { span_err!(bx.sess(), statement.source_info.span, E0668, "malformed inline assembly"); diff --git a/src/librustc_codegen_utils/lib.rs b/src/librustc_codegen_utils/lib.rs index 1a3914e6ef4..330cfe154e3 100644 --- a/src/librustc_codegen_utils/lib.rs +++ b/src/librustc_codegen_utils/lib.rs @@ -16,6 +16,7 @@ #![recursion_limit="256"] #![deny(rust_2018_idioms)] +#![cfg_attr(not(stage0), deny(internal))] #[macro_use] extern crate rustc; diff --git a/src/librustc_data_structures/Cargo.toml b/src/librustc_data_structures/Cargo.toml index 63e44d82a28..d586b376d45 100644 --- a/src/librustc_data_structures/Cargo.toml +++ b/src/librustc_data_structures/Cargo.toml @@ -12,7 +12,7 @@ crate-type = ["dylib"] [dependencies] ena = "0.13" log = "0.4" -jobserver_crate = { version = "0.1", package = "jobserver" } +jobserver_crate = { version = "0.1.13", package = "jobserver" } lazy_static = "1" rustc_cratesio_shim = { path = "../librustc_cratesio_shim" } serialize = { path = "../libserialize" } diff --git a/src/librustc_data_structures/graph/dominators/mod.rs b/src/librustc_data_structures/graph/dominators/mod.rs index aaed41d9fa3..93a2a261c6f 100644 --- a/src/librustc_data_structures/graph/dominators/mod.rs +++ b/src/librustc_data_structures/graph/dominators/mod.rs @@ -8,8 +8,6 @@ use super::super::indexed_vec::{Idx, IndexVec}; use super::iterate::reverse_post_order; use super::ControlFlowGraph; -use std::fmt; - #[cfg(test)] mod test; @@ -158,48 +156,3 @@ impl<'dom, Node: Idx> Iterator for Iter<'dom, Node> { } } } - -pub struct DominatorTree<N: Idx> { - root: N, - children: IndexVec<N, Vec<N>>, -} - -impl<Node: Idx> DominatorTree<Node> { - pub fn children(&self, node: Node) -> &[Node] { - &self.children[node] - } -} - -impl<Node: Idx> fmt::Debug for DominatorTree<Node> { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt( - &DominatorTreeNode { - tree: self, - node: self.root, - }, - fmt, - ) - } -} - -struct DominatorTreeNode<'tree, Node: Idx> { - tree: &'tree DominatorTree<Node>, - node: Node, -} - -impl<'tree, Node: Idx> fmt::Debug for DominatorTreeNode<'tree, Node> { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - let subtrees: Vec<_> = self.tree - .children(self.node) - .iter() - .map(|&child| DominatorTreeNode { - tree: self.tree, - node: child, - }) - .collect(); - fmt.debug_tuple("") - .field(&self.node) - .field(&subtrees) - .finish() - } -} diff --git a/src/librustc_data_structures/jobserver.rs b/src/librustc_data_structures/jobserver.rs index 48ac8125a0d..b42ccb932b9 100644 --- a/src/librustc_data_structures/jobserver.rs +++ b/src/librustc_data_structures/jobserver.rs @@ -1,89 +1,5 @@ -use jobserver_crate::{Client, HelperThread, Acquired}; +use jobserver_crate::Client; use lazy_static::lazy_static; -use std::sync::{Condvar, Arc, Mutex}; -use std::mem; - -#[derive(Default)] -struct LockedProxyData { - /// The number of free thread tokens, this may include the implicit token given to the process - free: usize, - - /// The number of threads waiting for a token - waiters: usize, - - /// The number of tokens we requested from the server - requested: usize, - - /// Stored tokens which will be dropped when we no longer need them - tokens: Vec<Acquired>, -} - -impl LockedProxyData { - fn request_token(&mut self, thread: &Mutex<HelperThread>) { - self.requested += 1; - thread.lock().unwrap().request_token(); - } - - fn release_token(&mut self, cond_var: &Condvar) { - if self.waiters > 0 { - self.free += 1; - cond_var.notify_one(); - } else { - if self.tokens.is_empty() { - // We are returning the implicit token - self.free += 1; - } else { - // Return a real token to the server - self.tokens.pop().unwrap(); - } - } - } - - fn take_token(&mut self, thread: &Mutex<HelperThread>) -> bool { - if self.free > 0 { - self.free -= 1; - self.waiters -= 1; - - // We stole some token reqested by someone else - // Request another one - if self.requested + self.free < self.waiters { - self.request_token(thread); - } - - true - } else { - false - } - } - - fn new_requested_token(&mut self, token: Acquired, cond_var: &Condvar) { - self.requested -= 1; - - // Does anything need this token? - if self.waiters > 0 { - self.free += 1; - self.tokens.push(token); - cond_var.notify_one(); - } else { - // Otherwise we'll just drop it - mem::drop(token); - } - } -} - -#[derive(Default)] -struct ProxyData { - lock: Mutex<LockedProxyData>, - cond_var: Condvar, -} - -/// A helper type which makes managing jobserver tokens easier. -/// It also allows you to treat the implicit token given to the process -/// in the same manner as requested tokens. -struct Proxy { - thread: Mutex<HelperThread>, - data: Arc<ProxyData>, -} lazy_static! { // We can only call `from_env` once per process @@ -105,20 +21,12 @@ lazy_static! { // per-process. static ref GLOBAL_CLIENT: Client = unsafe { Client::from_env().unwrap_or_else(|| { - Client::new(32).expect("failed to create jobserver") + let client = Client::new(32).expect("failed to create jobserver"); + // Acquire a token for the main thread which we can release later + client.acquire_raw().ok(); + client }) }; - - static ref GLOBAL_PROXY: Proxy = { - let data = Arc::new(ProxyData::default()); - - Proxy { - data: data.clone(), - thread: Mutex::new(client().into_helper_thread(move |token| { - data.lock.lock().unwrap().new_requested_token(token.unwrap(), &data.cond_var); - }).unwrap()), - } - }; } pub fn client() -> Client { @@ -126,31 +34,9 @@ pub fn client() -> Client { } pub fn acquire_thread() { - GLOBAL_PROXY.acquire_token(); + GLOBAL_CLIENT.acquire_raw().ok(); } pub fn release_thread() { - GLOBAL_PROXY.release_token(); -} - -impl Proxy { - fn release_token(&self) { - self.data.lock.lock().unwrap().release_token(&self.data.cond_var); - } - - fn acquire_token(&self) { - let mut data = self.data.lock.lock().unwrap(); - data.waiters += 1; - if data.take_token(&self.thread) { - return; - } - // Request a token for us - data.request_token(&self.thread); - loop { - data = self.data.cond_var.wait(data).unwrap(); - if data.take_token(&self.thread) { - return; - } - } - } + GLOBAL_CLIENT.release_raw().ok(); } diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 4b7cffaad55..66c7c9d0eae 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -17,6 +17,7 @@ #![recursion_limit="256"] #![deny(rust_2018_idioms)] +#![cfg_attr(not(stage0), deny(internal))] pub extern crate getopts; #[cfg(unix)] @@ -743,7 +744,7 @@ fn usage(verbose: bool, include_unstable_options: bool) { } let message = "Usage: rustc [OPTIONS] INPUT"; let nightly_help = if nightly_options::is_nightly_build() { - "\n -Z help Print internal options for debugging rustc" + "\n -Z help Print unstable compiler options" } else { "" }; @@ -891,7 +892,7 @@ Available lint options: } fn describe_debug_flags() { - println!("\nAvailable debug options:\n"); + println!("\nAvailable options:\n"); print_flag_list("-Z", config::DB_OPTIONS); } diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index ebbc5a3d3a3..71bef54cd17 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -6,6 +6,7 @@ #![feature(nll)] #![feature(optin_builtin_traits)] #![deny(rust_2018_idioms)] +#![cfg_attr(not(stage0), deny(internal))] #[allow(unused_extern_crates)] extern crate serialize as rustc_serialize; // used by deriving diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs index fe75bbc36c3..d7db324f346 100644 --- a/src/librustc_incremental/lib.rs +++ b/src/librustc_incremental/lib.rs @@ -8,6 +8,7 @@ #![recursion_limit="256"] #![deny(rust_2018_idioms)] +#![cfg_attr(not(stage0), deny(internal))] #[macro_use] extern crate rustc; #[allow(unused_extern_crates)] diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index 46e2582ac3b..5c4fd9dba7a 100644 --- a/src/librustc_incremental/persist/dirty_clean.rs +++ b/src/librustc_incremental/persist/dirty_clean.rs @@ -3,9 +3,9 @@ //! we will compare the fingerprint from the current and from the previous //! compilation session as appropriate: //! -//! - `#[rustc_clean(cfg="rev2", except="TypeckTables")]` if we are +//! - `#[rustc_clean(cfg="rev2", except="typeck_tables_of")]` if we are //! in `#[cfg(rev2)]`, then the fingerprints associated with -//! `DepNode::TypeckTables(X)` must be DIFFERENT (`X` is the `DefId` of the +//! `DepNode::typeck_tables_of(X)` must be DIFFERENT (`X` is the `DefId` of the //! current node). //! - `#[rustc_clean(cfg="rev2")]` same as above, except that the //! fingerprints must be the SAME (along with all other fingerprints). @@ -42,14 +42,14 @@ const BASE_CONST: &[&str] = &[ /// DepNodes for functions + methods const BASE_FN: &[&str] = &[ // Callers will depend on the signature of these items, so we better test - label_strs::FnSignature, + label_strs::fn_sig, label_strs::generics_of, label_strs::predicates_of, label_strs::type_of, // And a big part of compilation (that we eventually want to cache) is type inference // information: - label_strs::TypeckTables, + label_strs::typeck_tables_of, ]; /// DepNodes for Hir, which is pretty much everything @@ -61,9 +61,9 @@ const BASE_HIR: &[&str] = &[ /// `impl` implementation of struct/trait const BASE_IMPL: &[&str] = &[ - label_strs::AssociatedItemDefIds, + label_strs::associated_item_def_ids, label_strs::generics_of, - label_strs::ImplTraitRef, + label_strs::impl_trait_ref, ]; /// DepNodes for mir_built/Optimized, which is relevant in "executable" @@ -85,22 +85,22 @@ const BASE_STRUCT: &[&str] = &[ /// Trait definition `DepNode`s. const BASE_TRAIT_DEF: &[&str] = &[ - label_strs::AssociatedItemDefIds, + label_strs::associated_item_def_ids, label_strs::generics_of, - label_strs::ObjectSafety, + label_strs::is_object_safe, label_strs::predicates_of, - label_strs::SpecializationGraph, - label_strs::TraitDefOfItem, - label_strs::TraitImpls, + label_strs::specialization_graph_of, + label_strs::trait_def, + label_strs::trait_impls_of, ]; /// Extra `DepNode`s for functions and methods. const EXTRA_ASSOCIATED: &[&str] = &[ - label_strs::AssociatedItems, + label_strs::associated_item, ]; const EXTRA_TRAIT: &[&str] = &[ - label_strs::TraitOfItem, + label_strs::trait_of_item, ]; // Fully Built Labels diff --git a/src/librustc_interface/interface.rs b/src/librustc_interface/interface.rs index 245a2bf92d5..23575e51dfc 100644 --- a/src/librustc_interface/interface.rs +++ b/src/librustc_interface/interface.rs @@ -12,7 +12,6 @@ use rustc_data_structures::OnDrop; use rustc_data_structures::sync::Lrc; use rustc_data_structures::fx::{FxHashSet, FxHashMap}; use rustc_metadata::cstore::CStore; -use std::collections::HashSet; use std::io::Write; use std::path::PathBuf; use std::result; @@ -124,10 +123,6 @@ where profile::dump(&compiler.sess, "profile_queries".to_string()) } - if compiler.sess.opts.debugging_opts.self_profile { - compiler.sess.profiler(|p| p.dump_raw_events(&compiler.sess.opts)); - } - r } diff --git a/src/librustc_interface/lib.rs b/src/librustc_interface/lib.rs index 3314681b698..353ff6a57a5 100644 --- a/src/librustc_interface/lib.rs +++ b/src/librustc_interface/lib.rs @@ -7,6 +7,7 @@ #![cfg_attr(unix, feature(libc))] #![deny(rust_2018_idioms)] +#![cfg_attr(not(stage0), deny(internal))] #![allow(unused_imports)] diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index 1547e15fd48..3fd684f5d97 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -69,7 +69,7 @@ pub fn parse<'a>(sess: &'a Session, input: &Input) -> PResult<'a, ast::Crate> { .set_continue_after_error(sess.opts.debugging_opts.continue_parse_after_error); hygiene::set_default_edition(sess.edition()); - sess.profiler(|p| p.start_activity(ProfileCategory::Parsing, "parsing")); + sess.profiler(|p| p.start_activity("parsing")); let krate = time(sess, "parsing", || match *input { Input::File(ref file) => parse::parse_crate_from_file(file, &sess.parse_sess), Input::Str { @@ -77,7 +77,7 @@ pub fn parse<'a>(sess: &'a Session, input: &Input) -> PResult<'a, ast::Crate> { ref name, } => parse::parse_crate_from_source_str(name.clone(), input.clone(), &sess.parse_sess), })?; - sess.profiler(|p| p.end_activity(ProfileCategory::Parsing, "parsing")); + sess.profiler(|p| p.end_activity("parsing")); sess.diagnostic().set_continue_after_error(true); @@ -375,7 +375,7 @@ fn configure_and_expand_inner<'a>( syntax_ext::register_builtins(&mut resolver, plugin_info.syntax_exts); // Expand all macros - sess.profiler(|p| p.start_activity(ProfileCategory::Expansion, "macro expansion")); + sess.profiler(|p| p.start_activity("macro expansion")); krate = time(sess, "expansion", || { // Windows dlls do not have rpaths, so they don't know how to find their // dependencies. It's up to us to tell the system where to find all the @@ -450,7 +450,7 @@ fn configure_and_expand_inner<'a>( } krate }); - sess.profiler(|p| p.end_activity(ProfileCategory::Expansion, "macro expansion")); + sess.profiler(|p| p.end_activity("macro expansion")); time(sess, "maybe building test harness", || { syntax::test::modify_for_testing( @@ -869,8 +869,6 @@ pub fn create_global_ctxt( yield BoxedGlobalCtxt::initial_yield(()); box_region_allow_access!(for('gcx), (&'gcx GlobalCtxt<'gcx>), (gcx)); - gcx.queries.record_computed_queries(sess); - if sess.opts.debugging_opts.query_stats { gcx.queries.print_stats(); } @@ -1022,9 +1020,9 @@ pub fn start_codegen<'tcx>( ::rustc::middle::dependency_format::calculate(tcx) }); - tcx.sess.profiler(|p| p.start_activity(ProfileCategory::Codegen, "codegen crate")); + tcx.sess.profiler(|p| p.start_activity("codegen crate")); let codegen = time(tcx.sess, "codegen", move || codegen_backend.codegen_crate(tcx, rx)); - tcx.sess.profiler(|p| p.end_activity(ProfileCategory::Codegen, "codegen crate")); + tcx.sess.profiler(|p| p.end_activity("codegen crate")); if log_enabled!(::log::Level::Info) { println!("Post-codegen"); diff --git a/src/librustc_interface/util.rs b/src/librustc_interface/util.rs index 6e4f2bf24e3..17523aedffb 100644 --- a/src/librustc_interface/util.rs +++ b/src/librustc_interface/util.rs @@ -21,7 +21,6 @@ use rustc_plugin; use rustc_privacy; use rustc_resolve; use rustc_typeck; -use std::collections::HashSet; use std::env; use std::env::consts::{DLL_PREFIX, DLL_SUFFIX}; use std::io::{self, Write}; @@ -109,6 +108,9 @@ pub fn create_session( let codegen_backend = get_codegen_backend(&sess); rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); + if sess.unstable_options() { + rustc_lint::register_internals(&mut sess.lint_store.borrow_mut(), Some(&sess)); + } let mut cfg = config::build_configuration(&sess, config::to_crate_config(cfg)); add_configuration(&mut cfg, &sess, &*codegen_backend); diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 1fae931e9f1..7fe047ec2c6 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -63,18 +63,7 @@ declare_lint! { "suggest using `loop { }` instead of `while true { }`" } -#[derive(Copy, Clone)] -pub struct WhileTrue; - -impl LintPass for WhileTrue { - fn name(&self) -> &'static str { - "WhileTrue" - } - - fn get_lints(&self) -> LintArray { - lint_array!(WHILE_TRUE) - } -} +declare_lint_pass!(WhileTrue => [WHILE_TRUE]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for WhileTrue { fn check_expr(&mut self, cx: &LateContext<'_, '_>, e: &hir::Expr) { @@ -105,8 +94,7 @@ declare_lint! { "use of owned (Box type) heap memory" } -#[derive(Copy, Clone)] -pub struct BoxPointers; +declare_lint_pass!(BoxPointers => [BOX_POINTERS]); impl BoxPointers { fn check_heap_type<'a, 'tcx>(&self, cx: &LateContext<'_, '_>, span: Span, ty: Ty<'_>) { @@ -119,16 +107,6 @@ impl BoxPointers { } } -impl LintPass for BoxPointers { - fn name(&self) -> &'static str { - "BoxPointers" - } - - fn get_lints(&self) -> LintArray { - lint_array!(BOX_POINTERS) - } -} - impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BoxPointers { fn check_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::Item) { match it.node { @@ -169,18 +147,7 @@ declare_lint! { "using `Struct { x: x }` instead of `Struct { x }` in a pattern" } -#[derive(Copy, Clone)] -pub struct NonShorthandFieldPatterns; - -impl LintPass for NonShorthandFieldPatterns { - fn name(&self) -> &'static str { - "NonShorthandFieldPatterns" - } - - fn get_lints(&self) -> LintArray { - lint_array!(NON_SHORTHAND_FIELD_PATTERNS) - } -} +declare_lint_pass!(NonShorthandFieldPatterns => [NON_SHORTHAND_FIELD_PATTERNS]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonShorthandFieldPatterns { fn check_pat(&mut self, cx: &LateContext<'_, '_>, pat: &hir::Pat) { @@ -226,18 +193,7 @@ declare_lint! { "usage of `unsafe` code" } -#[derive(Copy, Clone)] -pub struct UnsafeCode; - -impl LintPass for UnsafeCode { - fn name(&self) -> &'static str { - "UnsafeCode" - } - - fn get_lints(&self) -> LintArray { - lint_array!(UNSAFE_CODE) - } -} +declare_lint_pass!(UnsafeCode => [UNSAFE_CODE]); impl UnsafeCode { fn report_unsafe(&self, cx: &EarlyContext<'_>, span: Span, desc: &'static str) { @@ -327,6 +283,8 @@ pub struct MissingDoc { private_traits: FxHashSet<hir::HirId>, } +impl_lint_pass!(MissingDoc => [MISSING_DOCS]); + fn has_doc(attr: &ast::Attribute) -> bool { if !attr.check_name("doc") { return false; @@ -394,16 +352,6 @@ impl MissingDoc { } } -impl LintPass for MissingDoc { - fn name(&self) -> &'static str { - "MissingDoc" - } - - fn get_lints(&self) -> LintArray { - lint_array!(MISSING_DOCS) - } -} - impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc { fn enter_lint_attrs(&mut self, _: &LateContext<'_, '_>, attrs: &[ast::Attribute]) { let doc_hidden = self.doc_hidden() || @@ -541,18 +489,7 @@ declare_lint! { "detects potentially-forgotten implementations of `Copy`" } -#[derive(Copy, Clone)] -pub struct MissingCopyImplementations; - -impl LintPass for MissingCopyImplementations { - fn name(&self) -> &'static str { - "MissingCopyImplementations" - } - - fn get_lints(&self) -> LintArray { - lint_array!(MISSING_COPY_IMPLEMENTATIONS) - } -} +declare_lint_pass!(MissingCopyImplementations => [MISSING_COPY_IMPLEMENTATIONS]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingCopyImplementations { fn check_item(&mut self, cx: &LateContext<'_, '_>, item: &hir::Item) { @@ -609,22 +546,14 @@ pub struct MissingDebugImplementations { impling_types: Option<HirIdSet>, } +impl_lint_pass!(MissingDebugImplementations => [MISSING_DEBUG_IMPLEMENTATIONS]); + impl MissingDebugImplementations { pub fn new() -> MissingDebugImplementations { MissingDebugImplementations { impling_types: None } } } -impl LintPass for MissingDebugImplementations { - fn name(&self) -> &'static str { - "MissingDebugImplementations" - } - - fn get_lints(&self) -> LintArray { - lint_array!(MISSING_DEBUG_IMPLEMENTATIONS) - } -} - impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDebugImplementations { fn check_item(&mut self, cx: &LateContext<'_, '_>, item: &hir::Item) { if !cx.access_levels.is_reachable(item.hir_id) { @@ -672,19 +601,10 @@ declare_lint! { "detects anonymous parameters" } -/// Checks for use of anonymous parameters (RFC 1685). -#[derive(Copy, Clone)] -pub struct AnonymousParameters; - -impl LintPass for AnonymousParameters { - fn name(&self) -> &'static str { - "AnonymousParameters" - } - - fn get_lints(&self) -> LintArray { - lint_array!(ANONYMOUS_PARAMETERS) - } -} +declare_lint_pass!( + /// Checks for use of anonymous parameters (RFC 1685). + AnonymousParameters => [ANONYMOUS_PARAMETERS] +); impl EarlyLintPass for AnonymousParameters { fn check_trait_item(&mut self, cx: &EarlyContext<'_>, it: &ast::TraitItem) { @@ -736,6 +656,8 @@ pub struct DeprecatedAttr { depr_attrs: Vec<&'static (&'static str, AttributeType, AttributeTemplate, AttributeGate)>, } +impl_lint_pass!(DeprecatedAttr => []); + impl DeprecatedAttr { pub fn new() -> DeprecatedAttr { DeprecatedAttr { @@ -744,16 +666,6 @@ impl DeprecatedAttr { } } -impl LintPass for DeprecatedAttr { - fn name(&self) -> &'static str { - "DeprecatedAttr" - } - - fn get_lints(&self) -> LintArray { - lint_array!() - } -} - impl EarlyLintPass for DeprecatedAttr { fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) { let name = attr.name_or_empty(); @@ -786,18 +698,7 @@ declare_lint! { "detects doc comments that aren't used by rustdoc" } -#[derive(Copy, Clone)] -pub struct UnusedDocComment; - -impl LintPass for UnusedDocComment { - fn name(&self) -> &'static str { - "UnusedDocComment" - } - - fn get_lints(&self) -> LintArray { - lint_array![UNUSED_DOC_COMMENTS] - } -} +declare_lint_pass!(UnusedDocComment => [UNUSED_DOC_COMMENTS]); impl UnusedDocComment { fn warn_if_doc( @@ -884,18 +785,7 @@ declare_lint! { "compiler plugin used as ordinary library in non-plugin crate" } -#[derive(Copy, Clone)] -pub struct PluginAsLibrary; - -impl LintPass for PluginAsLibrary { - fn name(&self) -> &'static str { - "PluginAsLibrary" - } - - fn get_lints(&self) -> LintArray { - lint_array![PLUGIN_AS_LIBRARY] - } -} +declare_lint_pass!(PluginAsLibrary => [PLUGIN_AS_LIBRARY]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for PluginAsLibrary { fn check_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::Item) { @@ -940,19 +830,7 @@ declare_lint! { "generic items must be mangled" } -#[derive(Copy, Clone)] -pub struct InvalidNoMangleItems; - -impl LintPass for InvalidNoMangleItems { - fn name(&self) -> &'static str { - "InvalidNoMangleItems" - } - - fn get_lints(&self) -> LintArray { - lint_array!(NO_MANGLE_CONST_ITEMS, - NO_MANGLE_GENERIC_ITEMS) - } -} +declare_lint_pass!(InvalidNoMangleItems => [NO_MANGLE_CONST_ITEMS, NO_MANGLE_GENERIC_ITEMS]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidNoMangleItems { fn check_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::Item) { @@ -1011,24 +889,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidNoMangleItems { } } -#[derive(Clone, Copy)] -pub struct MutableTransmutes; - declare_lint! { MUTABLE_TRANSMUTES, Deny, "mutating transmuted &mut T from &T may cause undefined behavior" } -impl LintPass for MutableTransmutes { - fn name(&self) -> &'static str { - "MutableTransmutes" - } - - fn get_lints(&self) -> LintArray { - lint_array!(MUTABLE_TRANSMUTES) - } -} +declare_lint_pass!(MutableTransmutes => [MUTABLE_TRANSMUTES]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MutableTransmutes { fn check_expr(&mut self, cx: &LateContext<'_, '_>, expr: &hir::Expr) { @@ -1036,7 +903,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MutableTransmutes { let msg = "mutating transmuted &mut T from &T may cause undefined behavior, \ consider instead using an UnsafeCell"; - match get_transmute_from_to(cx, expr) { + match get_transmute_from_to(cx, expr).map(|(ty1, ty2)| (&ty1.sty, &ty2.sty)) { Some((&ty::Ref(_, _, from_mt), &ty::Ref(_, _, to_mt))) => { if to_mt == hir::Mutability::MutMutable && from_mt == hir::Mutability::MutImmutable { @@ -1049,7 +916,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MutableTransmutes { fn get_transmute_from_to<'a, 'tcx> (cx: &LateContext<'a, 'tcx>, expr: &hir::Expr) - -> Option<(&'tcx ty::TyKind<'tcx>, &'tcx ty::TyKind<'tcx>)> { + -> Option<(Ty<'tcx>, Ty<'tcx>)> { let def = if let hir::ExprKind::Path(ref qpath) = expr.node { cx.tables.qpath_def(qpath, expr.hir_id) } else { @@ -1062,7 +929,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MutableTransmutes { let sig = cx.tables.node_type(expr.hir_id).fn_sig(cx.tcx); let from = sig.inputs().skip_binder()[0]; let to = *sig.output().skip_binder(); - return Some((&from.sty, &to.sty)); + return Some((from, to)); } None } @@ -1074,25 +941,16 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MutableTransmutes { } } -/// Forbids using the `#[feature(...)]` attribute -#[derive(Copy, Clone)] -pub struct UnstableFeatures; - declare_lint! { UNSTABLE_FEATURES, Allow, "enabling unstable features (deprecated. do not use)" } -impl LintPass for UnstableFeatures { - fn name(&self) -> &'static str { - "UnstableFeatures" - } - - fn get_lints(&self) -> LintArray { - lint_array!(UNSTABLE_FEATURES) - } -} +declare_lint_pass!( + /// Forbids using the `#[feature(...)]` attribute + UnstableFeatures => [UNSTABLE_FEATURES] +); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnstableFeatures { fn check_attribute(&mut self, ctx: &LateContext<'_, '_>, attr: &ast::Attribute) { @@ -1106,24 +964,16 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnstableFeatures { } } -/// Lint for unions that contain fields with possibly non-trivial destructors. -pub struct UnionsWithDropFields; - declare_lint! { UNIONS_WITH_DROP_FIELDS, Warn, "use of unions that contain fields with possibly non-trivial drop code" } -impl LintPass for UnionsWithDropFields { - fn name(&self) -> &'static str { - "UnionsWithDropFields" - } - - fn get_lints(&self) -> LintArray { - lint_array!(UNIONS_WITH_DROP_FIELDS) - } -} +declare_lint_pass!( + /// Lint for unions that contain fields with possibly non-trivial destructors. + UnionsWithDropFields => [UNIONS_WITH_DROP_FIELDS] +); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnionsWithDropFields { fn check_item(&mut self, ctx: &LateContext<'_, '_>, item: &hir::Item) { @@ -1143,25 +993,16 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnionsWithDropFields { } } -/// Lint for items marked `pub` that aren't reachable from other crates. -#[derive(Copy, Clone)] -pub struct UnreachablePub; - declare_lint! { pub UNREACHABLE_PUB, Allow, "`pub` items not reachable from crate root" } -impl LintPass for UnreachablePub { - fn name(&self) -> &'static str { - "UnreachablePub" - } - - fn get_lints(&self) -> LintArray { - lint_array!(UNREACHABLE_PUB) - } -} +declare_lint_pass!( + /// Lint for items marked `pub` that aren't reachable from other crates. + UnreachablePub => [UNREACHABLE_PUB] +); impl UnreachablePub { fn perform_lint(&self, cx: &LateContext<'_, '_>, what: &str, id: hir::HirId, @@ -1197,7 +1038,6 @@ impl UnreachablePub { } } - impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnreachablePub { fn check_item(&mut self, cx: &LateContext<'_, '_>, item: &hir::Item) { self.perform_lint(cx, "item", item.hir_id, &item.vis, item.span, true); @@ -1217,27 +1057,18 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnreachablePub { } } -/// Lint for trait and lifetime bounds in type aliases being mostly ignored. -/// They are relevant when using associated types, but otherwise neither checked -/// at definition site nor enforced at use site. - -pub struct TypeAliasBounds; - declare_lint! { TYPE_ALIAS_BOUNDS, Warn, "bounds in type aliases are not enforced" } -impl LintPass for TypeAliasBounds { - fn name(&self) -> &'static str { - "TypeAliasBounds" - } - - fn get_lints(&self) -> LintArray { - lint_array!(TYPE_ALIAS_BOUNDS) - } -} +declare_lint_pass!( + /// Lint for trait and lifetime bounds in type aliases being mostly ignored. + /// They are relevant when using associated types, but otherwise neither checked + /// at definition site nor enforced at use site. + TypeAliasBounds => [TYPE_ALIAS_BOUNDS] +); impl TypeAliasBounds { fn is_type_variable_assoc(qpath: &hir::QPath) -> bool { @@ -1331,21 +1162,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeAliasBounds { } } -/// Lint constants that are erroneous. -/// Without this lint, we might not get any diagnostic if the constant is -/// unused within this crate, even though downstream crates can't use it -/// without producing an error. -pub struct UnusedBrokenConst; - -impl LintPass for UnusedBrokenConst { - fn name(&self) -> &'static str { - "UnusedBrokenConst" - } +declare_lint_pass!( + /// Lint constants that are erroneous. + /// Without this lint, we might not get any diagnostic if the constant is + /// unused within this crate, even though downstream crates can't use it + /// without producing an error. + UnusedBrokenConst => [] +); - fn get_lints(&self) -> LintArray { - lint_array!() - } -} fn check_const(cx: &LateContext<'_, '_>, body_id: hir::BodyId) { let def_id = cx.tcx.hir().body_owner_def_id(body_id); let is_static = cx.tcx.is_static(def_id).is_some(); @@ -1378,25 +1202,17 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedBrokenConst { } } -/// Lint for trait and lifetime bounds that don't depend on type parameters -/// which either do nothing, or stop the item from being used. -pub struct TrivialConstraints; - declare_lint! { TRIVIAL_BOUNDS, Warn, "these bounds don't depend on an type parameters" } -impl LintPass for TrivialConstraints { - fn name(&self) -> &'static str { - "TrivialConstraints" - } - - fn get_lints(&self) -> LintArray { - lint_array!(TRIVIAL_BOUNDS) - } -} +declare_lint_pass!( + /// Lint for trait and lifetime bounds that don't depend on type parameters + /// which either do nothing, or stop the item from being used. + TrivialConstraints => [TRIVIAL_BOUNDS] +); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TrivialConstraints { fn check_item( @@ -1440,40 +1256,30 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TrivialConstraints { } } - -/// Does nothing as a lint pass, but registers some `Lint`s -/// which are used by other parts of the compiler. -#[derive(Copy, Clone)] -pub struct SoftLints; - -impl LintPass for SoftLints { - fn name(&self) -> &'static str { - "SoftLints" - } - - fn get_lints(&self) -> LintArray { - lint_array!( - WHILE_TRUE, - BOX_POINTERS, - NON_SHORTHAND_FIELD_PATTERNS, - UNSAFE_CODE, - MISSING_DOCS, - MISSING_COPY_IMPLEMENTATIONS, - MISSING_DEBUG_IMPLEMENTATIONS, - ANONYMOUS_PARAMETERS, - UNUSED_DOC_COMMENTS, - PLUGIN_AS_LIBRARY, - NO_MANGLE_CONST_ITEMS, - NO_MANGLE_GENERIC_ITEMS, - MUTABLE_TRANSMUTES, - UNSTABLE_FEATURES, - UNIONS_WITH_DROP_FIELDS, - UNREACHABLE_PUB, - TYPE_ALIAS_BOUNDS, - TRIVIAL_BOUNDS - ) - } -} +declare_lint_pass!( + /// Does nothing as a lint pass, but registers some `Lint`s + /// which are used by other parts of the compiler. + SoftLints => [ + WHILE_TRUE, + BOX_POINTERS, + NON_SHORTHAND_FIELD_PATTERNS, + UNSAFE_CODE, + MISSING_DOCS, + MISSING_COPY_IMPLEMENTATIONS, + MISSING_DEBUG_IMPLEMENTATIONS, + ANONYMOUS_PARAMETERS, + UNUSED_DOC_COMMENTS, + PLUGIN_AS_LIBRARY, + NO_MANGLE_CONST_ITEMS, + NO_MANGLE_GENERIC_ITEMS, + MUTABLE_TRANSMUTES, + UNSTABLE_FEATURES, + UNIONS_WITH_DROP_FIELDS, + UNREACHABLE_PUB, + TYPE_ALIAS_BOUNDS, + TRIVIAL_BOUNDS + ] +); declare_lint! { pub ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, @@ -1481,18 +1287,7 @@ declare_lint! { "`...` range patterns are deprecated" } - -pub struct EllipsisInclusiveRangePatterns; - -impl LintPass for EllipsisInclusiveRangePatterns { - fn name(&self) -> &'static str { - "EllipsisInclusiveRangePatterns" - } - - fn get_lints(&self) -> LintArray { - lint_array!(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS) - } -} +declare_lint_pass!(EllipsisInclusiveRangePatterns => [ELLIPSIS_INCLUSIVE_RANGE_PATTERNS]); impl EarlyLintPass for EllipsisInclusiveRangePatterns { fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &ast::Pat, visit_subpats: &mut bool) { @@ -1553,6 +1348,8 @@ pub struct UnnameableTestItems { items_nameable: bool, } +impl_lint_pass!(UnnameableTestItems => [UNNAMEABLE_TEST_ITEMS]); + impl UnnameableTestItems { pub fn new() -> Self { Self { @@ -1562,16 +1359,6 @@ impl UnnameableTestItems { } } -impl LintPass for UnnameableTestItems { - fn name(&self) -> &'static str { - "UnnameableTestItems" - } - - fn get_lints(&self) -> LintArray { - lint_array!(UNNAMEABLE_TEST_ITEMS) - } -} - impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnnameableTestItems { fn check_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::Item) { if self.items_nameable { @@ -1605,19 +1392,10 @@ declare_lint! { "detects edition keywords being used as an identifier" } -/// Check for uses of edition keywords used as an identifier. -#[derive(Copy, Clone)] -pub struct KeywordIdents; - -impl LintPass for KeywordIdents { - fn name(&self) -> &'static str { - "KeywordIdents" - } - - fn get_lints(&self) -> LintArray { - lint_array!(KEYWORD_IDENTS) - } -} +declare_lint_pass!( + /// Check for uses of edition keywords used as an identifier. + KeywordIdents => [KEYWORD_IDENTS] +); struct UnderMacro(bool); @@ -1740,18 +1518,7 @@ impl EarlyLintPass for KeywordIdents { } } - -pub struct ExplicitOutlivesRequirements; - -impl LintPass for ExplicitOutlivesRequirements { - fn name(&self) -> &'static str { - "ExplicitOutlivesRequirements" - } - - fn get_lints(&self) -> LintArray { - lint_array![EXPLICIT_OUTLIVES_REQUIREMENTS] - } -} +declare_lint_pass!(ExplicitOutlivesRequirements => [EXPLICIT_OUTLIVES_REQUIREMENTS]); impl ExplicitOutlivesRequirements { fn collect_outlives_bound_spans( diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index c9301a32d83..4a2d6dc68ae 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -20,6 +20,7 @@ #![recursion_limit="256"] #![deny(rust_2018_idioms)] +#![cfg_attr(not(stage0), deny(internal))] #[macro_use] extern crate rustc; @@ -61,6 +62,7 @@ use nonstandard_style::*; use builtin::*; use types::*; use unused::*; +use rustc::lint::internal::*; /// Useful for other parts of the compiler. pub use builtin::SoftLints; @@ -427,15 +429,15 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { edition: None, }, FutureIncompatibleInfo { - id: LintId::of(DUPLICATE_MATCHER_BINDING_NAME), - reference: "issue #57593 <https://github.com/rust-lang/rust/issues/57593>", - edition: None, - }, - FutureIncompatibleInfo { id: LintId::of(NESTED_IMPL_TRAIT), reference: "issue #59014 <https://github.com/rust-lang/rust/issues/59014>", edition: None, }, + FutureIncompatibleInfo { + id: LintId::of(MUTABLE_BORROW_RESERVATION_CONFLICT), + reference: "issue #59159 <https://github.com/rust-lang/rust/issues/59159>", + edition: None, + } ]); // Register renamed and removed lints. @@ -487,4 +489,21 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { "no longer a warning, #[no_mangle] statics always exported"); store.register_removed("bad_repr", "replaced with a generic attribute input check"); + store.register_removed("duplicate_matcher_binding_name", + "converted into hard error, see https://github.com/rust-lang/rust/issues/57742"); +} + +pub fn register_internals(store: &mut lint::LintStore, sess: Option<&Session>) { + store.register_early_pass(sess, false, false, box DefaultHashTypes::new()); + store.register_late_pass(sess, false, false, false, box TyKindUsage); + store.register_group( + sess, + false, + "internal", + None, + vec![ + LintId::of(DEFAULT_HASH_TYPES), + LintId::of(USAGE_OF_TY_TYKIND), + ], + ); } diff --git a/src/librustc_lint/nonstandard_style.rs b/src/librustc_lint/nonstandard_style.rs index 7a164dbcdf1..1d8979f7d1c 100644 --- a/src/librustc_lint/nonstandard_style.rs +++ b/src/librustc_lint/nonstandard_style.rs @@ -38,6 +38,8 @@ declare_lint! { "types, variants, traits and type parameters should have camel case names" } +declare_lint_pass!(NonCamelCaseTypes => [NON_CAMEL_CASE_TYPES]); + fn char_has_case(c: char) -> bool { c.is_lowercase() || c.is_uppercase() } @@ -105,9 +107,6 @@ fn to_camel_case(s: &str) -> String { .0 } -#[derive(Copy, Clone)] -pub struct NonCamelCaseTypes; - impl NonCamelCaseTypes { fn check_case(&self, cx: &EarlyContext<'_>, sort: &str, ident: &Ident) { let name = &ident.name.as_str(); @@ -126,16 +125,6 @@ impl NonCamelCaseTypes { } } -impl LintPass for NonCamelCaseTypes { - fn name(&self) -> &'static str { - "NonCamelCaseTypes" - } - - fn get_lints(&self) -> LintArray { - lint_array!(NON_CAMEL_CASE_TYPES) - } -} - impl EarlyLintPass for NonCamelCaseTypes { fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) { let has_repr_c = it.attrs @@ -173,8 +162,7 @@ declare_lint! { "variables, methods, functions, lifetime parameters and modules should have snake case names" } -#[derive(Copy, Clone)] -pub struct NonSnakeCase; +declare_lint_pass!(NonSnakeCase => [NON_SNAKE_CASE]); impl NonSnakeCase { fn to_snake_case(mut str: &str) -> String { @@ -256,16 +244,6 @@ impl NonSnakeCase { } } -impl LintPass for NonSnakeCase { - fn name(&self) -> &'static str { - "NonSnakeCase" - } - - fn get_lints(&self) -> LintArray { - lint_array!(NON_SNAKE_CASE) - } -} - impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonSnakeCase { fn check_mod(&mut self, cx: &LateContext<'_, '_>, _: &'tcx hir::Mod, _: Span, id: hir::HirId) { if id != hir::CRATE_HIR_ID { @@ -387,8 +365,7 @@ declare_lint! { "static constants should have uppercase identifiers" } -#[derive(Copy, Clone)] -pub struct NonUpperCaseGlobals; +declare_lint_pass!(NonUpperCaseGlobals => [NON_UPPER_CASE_GLOBALS]); impl NonUpperCaseGlobals { fn check_upper_case(cx: &LateContext<'_, '_>, sort: &str, ident: &Ident) { @@ -410,16 +387,6 @@ impl NonUpperCaseGlobals { } } -impl LintPass for NonUpperCaseGlobals { - fn name(&self) -> &'static str { - "NonUpperCaseGlobals" - } - - fn get_lints(&self) -> LintArray { - lint_array!(NON_UPPER_CASE_GLOBALS) - } -} - impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonUpperCaseGlobals { fn check_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::Item) { match it.node { diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 494a9bb73ed..d3223c6edb8 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -49,23 +49,14 @@ pub struct TypeLimits { negated_expr_id: hir::HirId, } +impl_lint_pass!(TypeLimits => [UNUSED_COMPARISONS, OVERFLOWING_LITERALS]); + impl TypeLimits { pub fn new() -> TypeLimits { TypeLimits { negated_expr_id: hir::DUMMY_HIR_ID } } } -impl LintPass for TypeLimits { - fn name(&self) -> &'static str { - "TypeLimits" - } - - fn get_lints(&self) -> LintArray { - lint_array!(UNUSED_COMPARISONS, - OVERFLOWING_LITERALS) - } -} - impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits { fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx hir::Expr) { match e.node { @@ -104,7 +95,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits { report_bin_hex_error( cx, e, - ty::Int(t), + attr::IntType::SignedInt(t), repr_str, v, negative, @@ -159,7 +150,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits { report_bin_hex_error( cx, e, - ty::Uint(t), + attr::IntType::UnsignedInt(t), repr_str, lit_val, false, @@ -321,7 +312,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits { // // No suggestion for: `isize`, `usize`. fn get_type_suggestion<'a>( - t: &ty::TyKind<'_>, + t: Ty<'_>, val: u128, negative: bool, ) -> Option<String> { @@ -347,14 +338,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits { } } } - match t { - &ty::Int(i) => find_fit!(i, val, negative, + match t.sty { + ty::Int(i) => find_fit!(i, val, negative, I8 => [U8] => [I16, I32, I64, I128], I16 => [U16] => [I32, I64, I128], I32 => [U32] => [I64, I128], I64 => [U64] => [I128], I128 => [U128] => []), - &ty::Uint(u) => find_fit!(u, val, negative, + ty::Uint(u) => find_fit!(u, val, negative, U8 => [U8, U16, U32, U64, U128] => [], U16 => [U16, U32, U64, U128] => [], U32 => [U32, U64, U128] => [], @@ -367,25 +358,21 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits { fn report_bin_hex_error( cx: &LateContext<'_, '_>, expr: &hir::Expr, - ty: ty::TyKind<'_>, + ty: attr::IntType, repr_str: String, val: u128, negative: bool, ) { + let size = layout::Integer::from_attr(&cx.tcx, ty).size(); let (t, actually) = match ty { - ty::Int(t) => { - let ity = attr::IntType::SignedInt(t); - let size = layout::Integer::from_attr(&cx.tcx, ity).size(); + attr::IntType::SignedInt(t) => { let actually = sign_extend(val, size) as i128; (format!("{:?}", t), actually.to_string()) } - ty::Uint(t) => { - let ity = attr::IntType::UnsignedInt(t); - let size = layout::Integer::from_attr(&cx.tcx, ity).size(); + attr::IntType::UnsignedInt(t) => { let actually = truncate(val, size); (format!("{:?}", t), actually.to_string()) } - _ => bug!(), }; let mut err = cx.struct_span_lint( OVERFLOWING_LITERALS, @@ -398,7 +385,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits { repr_str, val, t, actually, t )); if let Some(sugg_ty) = - get_type_suggestion(&cx.tables.node_type(expr.hir_id).sty, val, negative) + get_type_suggestion(&cx.tables.node_type(expr.hir_id), val, negative) { if let Some(pos) = repr_str.chars().position(|c| c == 'i' || c == 'u') { let (sans_suffix, _) = repr_str.split_at(pos); @@ -424,6 +411,8 @@ declare_lint! { "proper use of libc types in foreign modules" } +declare_lint_pass!(ImproperCTypes => [IMPROPER_CTYPES]); + struct ImproperCTypesVisitor<'a, 'tcx: 'a> { cx: &'a LateContext<'a, 'tcx>, } @@ -793,19 +782,6 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } } -#[derive(Copy, Clone)] -pub struct ImproperCTypes; - -impl LintPass for ImproperCTypes { - fn name(&self) -> &'static str { - "ImproperCTypes" - } - - fn get_lints(&self) -> LintArray { - lint_array!(IMPROPER_CTYPES) - } -} - impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImproperCTypes { fn check_foreign_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::ForeignItem) { let mut vis = ImproperCTypesVisitor { cx }; @@ -824,17 +800,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImproperCTypes { } } -pub struct VariantSizeDifferences; - -impl LintPass for VariantSizeDifferences { - fn name(&self) -> &'static str { - "VariantSizeDifferences" - } - - fn get_lints(&self) -> LintArray { - lint_array!(VARIANT_SIZE_DIFFERENCES) - } -} +declare_lint_pass!(VariantSizeDifferences => [VARIANT_SIZE_DIFFERENCES]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences { fn check_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::Item) { @@ -854,6 +820,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences { discr_kind: layout::DiscriminantKind::Tag, ref discr, ref variants, + .. } => (variants, discr), _ => return, }; diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 37c147d93d8..d41d97f58bc 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -32,18 +32,7 @@ declare_lint! { "unused result of an expression in a statement" } -#[derive(Copy, Clone)] -pub struct UnusedResults; - -impl LintPass for UnusedResults { - fn name(&self) -> &'static str { - "UnusedResults" - } - - fn get_lints(&self) -> LintArray { - lint_array!(UNUSED_MUST_USE, UNUSED_RESULTS) - } -} +declare_lint_pass!(UnusedResults => [UNUSED_MUST_USE, UNUSED_RESULTS]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { fn check_stmt(&mut self, cx: &LateContext<'_, '_>, s: &hir::Stmt) { @@ -203,18 +192,7 @@ declare_lint! { "path statements with no effect" } -#[derive(Copy, Clone)] -pub struct PathStatements; - -impl LintPass for PathStatements { - fn name(&self) -> &'static str { - "PathStatements" - } - - fn get_lints(&self) -> LintArray { - lint_array!(PATH_STATEMENTS) - } -} +declare_lint_pass!(PathStatements => [PATH_STATEMENTS]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for PathStatements { fn check_stmt(&mut self, cx: &LateContext<'_, '_>, s: &hir::Stmt) { @@ -232,18 +210,7 @@ declare_lint! { "detects attributes that were not used by the compiler" } -#[derive(Copy, Clone)] -pub struct UnusedAttributes; - -impl LintPass for UnusedAttributes { - fn name(&self) -> &'static str { - "UnusedAttributes" - } - - fn get_lints(&self) -> LintArray { - lint_array!(UNUSED_ATTRIBUTES) - } -} +declare_lint_pass!(UnusedAttributes => [UNUSED_ATTRIBUTES]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAttributes { fn check_attribute(&mut self, cx: &LateContext<'_, '_>, attr: &ast::Attribute) { @@ -305,8 +272,7 @@ declare_lint! { "`if`, `match`, `while` and `return` do not need parentheses" } -#[derive(Copy, Clone)] -pub struct UnusedParens; +declare_lint_pass!(UnusedParens => [UNUSED_PARENS]); impl UnusedParens { fn check_unused_parens_expr(&self, @@ -383,16 +349,6 @@ impl UnusedParens { } } -impl LintPass for UnusedParens { - fn name(&self) -> &'static str { - "UnusedParens" - } - - fn get_lints(&self) -> LintArray { - lint_array!(UNUSED_PARENS) - } -} - impl EarlyLintPass for UnusedParens { fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) { use syntax::ast::ExprKind::*; @@ -465,8 +421,7 @@ declare_lint! { "unnecessary braces around an imported item" } -#[derive(Copy, Clone)] -pub struct UnusedImportBraces; +declare_lint_pass!(UnusedImportBraces => [UNUSED_IMPORT_BRACES]); impl UnusedImportBraces { fn check_use_tree(&self, cx: &EarlyContext<'_>, use_tree: &ast::UseTree, item: &ast::Item) { @@ -505,16 +460,6 @@ impl UnusedImportBraces { } } -impl LintPass for UnusedImportBraces { - fn name(&self) -> &'static str { - "UnusedImportBraces" - } - - fn get_lints(&self) -> LintArray { - lint_array!(UNUSED_IMPORT_BRACES) - } -} - impl EarlyLintPass for UnusedImportBraces { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) { if let ast::ItemKind::Use(ref use_tree) = item.node { @@ -529,18 +474,7 @@ declare_lint! { "detects unnecessary allocations that can be eliminated" } -#[derive(Copy, Clone)] -pub struct UnusedAllocation; - -impl LintPass for UnusedAllocation { - fn name(&self) -> &'static str { - "UnusedAllocation" - } - - fn get_lints(&self) -> LintArray { - lint_array!(UNUSED_ALLOCATION) - } -} +declare_lint_pass!(UnusedAllocation => [UNUSED_ALLOCATION]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAllocation { fn check_expr(&mut self, cx: &LateContext<'_, '_>, e: &hir::Expr) { diff --git a/src/librustc_lsan/Cargo.toml b/src/librustc_lsan/Cargo.toml index 9ad53ee6d09..9a24361f44e 100644 --- a/src/librustc_lsan/Cargo.toml +++ b/src/librustc_lsan/Cargo.toml @@ -12,7 +12,7 @@ test = false [build-dependencies] build_helper = { path = "../build_helper" } -cmake = "0.1.18" +cmake = "0.1.38" [dependencies] alloc = { path = "../liballoc" } diff --git a/src/librustc_macros/src/query.rs b/src/librustc_macros/src/query.rs index bd5be831ff6..e4a6dfcd4e8 100644 --- a/src/librustc_macros/src/query.rs +++ b/src/librustc_macros/src/query.rs @@ -43,6 +43,9 @@ enum QueryModifier { /// A cycle error for this query aborting the compilation with a fatal error. FatalCycle, + /// A cycle error results in a delay_bug call + CycleDelayBug, + /// Don't hash the result, instead just mark a query red if it runs NoHash, @@ -101,6 +104,8 @@ impl Parse for QueryModifier { Ok(QueryModifier::LoadCached(tcx, id, block)) } else if modifier == "fatal_cycle" { Ok(QueryModifier::FatalCycle) + } else if modifier == "cycle_delay_bug" { + Ok(QueryModifier::CycleDelayBug) } else if modifier == "no_hash" { Ok(QueryModifier::NoHash) } else if modifier == "no_force" { @@ -207,6 +212,9 @@ struct QueryModifiers { /// A cycle error for this query aborting the compilation with a fatal error. fatal_cycle: bool, + /// A cycle error results in a delay_bug call + cycle_delay_bug: bool, + /// Don't hash the result, instead just mark a query red if it runs no_hash: bool, @@ -226,6 +234,7 @@ fn process_modifiers(query: &mut Query) -> QueryModifiers { let mut cache = None; let mut desc = None; let mut fatal_cycle = false; + let mut cycle_delay_bug = false; let mut no_hash = false; let mut no_force = false; let mut anon = false; @@ -256,6 +265,12 @@ fn process_modifiers(query: &mut Query) -> QueryModifiers { } fatal_cycle = true; } + QueryModifier::CycleDelayBug => { + if cycle_delay_bug { + panic!("duplicate modifier `cycle_delay_bug` for query `{}`", query.name); + } + cycle_delay_bug = true; + } QueryModifier::NoHash => { if no_hash { panic!("duplicate modifier `no_hash` for query `{}`", query.name); @@ -287,6 +302,7 @@ fn process_modifiers(query: &mut Query) -> QueryModifiers { cache, desc, fatal_cycle, + cycle_delay_bug, no_hash, no_force, anon, @@ -333,6 +349,7 @@ fn add_query_description_impl( let tcx = tcx.as_ref().map(|t| quote! { #t }).unwrap_or(quote! { _ }); quote! { #[inline] + #[allow(unused_variables)] fn cache_on_disk(#tcx: TyCtxt<'_, 'tcx, 'tcx>, #key: Self::Key) -> bool { #expr } @@ -348,6 +365,7 @@ fn add_query_description_impl( let desc = modifiers.desc.as_ref().map(|(tcx, desc)| { let tcx = tcx.as_ref().map(|t| quote! { #t }).unwrap_or(quote! { _ }); quote! { + #[allow(unused_variables)] fn describe( #tcx: TyCtxt<'_, '_, '_>, #key: #arg, @@ -397,6 +415,10 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { if modifiers.fatal_cycle { attributes.push(quote! { fatal_cycle }); }; + // Pass on the cycle_delay_bug modifier + if modifiers.cycle_delay_bug { + attributes.push(quote! { cycle_delay_bug }); + }; // Pass on the no_hash modifier if modifiers.no_hash { attributes.push(quote! { no_hash }); diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 36d9bf9f50d..66daa4518be 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -862,7 +862,7 @@ impl<'a> CrateLoader<'a> { fn inject_profiler_runtime(&mut self) { if self.sess.opts.debugging_opts.profile || - self.sess.opts.debugging_opts.pgo_gen.is_some() + self.sess.opts.debugging_opts.pgo_gen.enabled() { info!("loading profiler"); diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index 14416b5ce07..4078171733f 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -14,6 +14,7 @@ #![recursion_limit="256"] #![deny(rust_2018_idioms)] +#![cfg_attr(not(stage0), deny(internal))] extern crate libc; #[allow(unused_extern_crates)] diff --git a/src/librustc_mir/borrow_check/borrow_set.rs b/src/librustc_mir/borrow_check/borrow_set.rs index cbef7a7f6c4..c81da66672f 100644 --- a/src/librustc_mir/borrow_check/borrow_set.rs +++ b/src/librustc_mir/borrow_check/borrow_set.rs @@ -52,7 +52,7 @@ crate enum TwoPhaseActivation { ActivatedAt(Location), } -#[derive(Debug)] +#[derive(Debug, Clone)] crate struct BorrowData<'tcx> { /// Location where the borrow reservation starts. /// In many cases, this will be equal to the activation location but not always. diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index 95701204cab..e6d818152f5 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -13,6 +13,7 @@ use rustc::mir::{ Static, StaticKind, TerminatorKind, VarBindingForm, }; use rustc::ty::{self, DefIdTree}; +use rustc::ty::layout::VariantIdx; use rustc::ty::print::Print; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::indexed_vec::Idx; @@ -25,8 +26,7 @@ use super::borrow_set::BorrowData; use super::{Context, MirBorrowckCtxt}; use super::{InitializationRequiringAction, PrefixSet}; use crate::dataflow::drop_flag_effects; -use crate::dataflow::move_paths::indexes::MoveOutIndex; -use crate::dataflow::move_paths::MovePathIndex; +use crate::dataflow::indexes::{MovePathIndex, MoveOutIndex}; use crate::util::borrowck_errors::{BorrowckErrors, Origin}; #[derive(Debug)] @@ -201,7 +201,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { ); } - let ty = used_place.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx); + let ty = used_place.ty(self.mir, self.infcx.tcx).ty; let needs_note = match ty.sty { ty::Closure(id, _) => { let tables = self.infcx.tcx.typeck_tables_of(id); @@ -216,13 +216,13 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { let mpi = self.move_data.moves[move_out_indices[0]].path; let place = &self.move_data.move_paths[mpi].place; - let ty = place.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx); + let ty = place.ty(self.mir, self.infcx.tcx).ty; let opt_name = self.describe_place_with_options(place, IncludingDowncast(true)); let note_msg = match opt_name { Some(ref name) => format!("`{}`", name), None => "value".to_owned(), }; - if let ty::TyKind::Param(param_ty) = ty.sty { + if let ty::Param(param_ty) = ty.sty { let tcx = self.infcx.tcx; let generics = tcx.generics_of(self.mir_def_id); let def_id = generics.type_param(¶m_ty, tcx).def_id; @@ -317,7 +317,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { context: Context, (place, _span): (&Place<'tcx>, Span), borrow: &BorrowData<'tcx>, - ) { + ) -> DiagnosticBuilder<'cx> { let tcx = self.infcx.tcx; let borrow_spans = self.retrieve_borrow_spans(borrow); @@ -346,7 +346,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { self.explain_why_borrow_contains_point(context, borrow, None) .add_explanation_to_diagnostic(self.infcx.tcx, self.mir, &mut err, "", None); - err.buffer(&mut self.errors_buffer); + err } pub(super) fn report_conflicting_borrow( @@ -355,7 +355,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { (place, span): (&Place<'tcx>, Span), gen_borrow_kind: BorrowKind, issued_borrow: &BorrowData<'tcx>, - ) { + ) -> DiagnosticBuilder<'cx> { let issued_spans = self.retrieve_borrow_spans(issued_borrow); let issued_span = issued_spans.args_or_use(); @@ -459,9 +459,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { "borrow occurs due to use of `{}`{}", desc_place, borrow_spans.describe() ), ); - err.buffer(&mut self.errors_buffer); - return; + return err; } (BorrowKind::Unique, _, _, _, _, _) => { @@ -511,14 +510,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { ) } - (BorrowKind::Shallow, _, _, BorrowKind::Unique, _, _) - | (BorrowKind::Shallow, _, _, BorrowKind::Mut { .. }, _, _) => { - // Shallow borrows are uses from the user's point of view. - self.report_use_while_mutably_borrowed(context, (place, span), issued_borrow); - return; - } (BorrowKind::Shared, _, _, BorrowKind::Shared, _, _) | (BorrowKind::Shared, _, _, BorrowKind::Shallow, _, _) + | (BorrowKind::Shallow, _, _, BorrowKind::Mut { .. }, _, _) + | (BorrowKind::Shallow, _, _, BorrowKind::Unique, _, _) | (BorrowKind::Shallow, _, _, BorrowKind::Shared, _, _) | (BorrowKind::Shallow, _, _, BorrowKind::Shallow, _, _) => unreachable!(), }; @@ -566,7 +561,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { None, ); - err.buffer(&mut self.errors_buffer); + err } /// Returns the description of the root place for a conflicting borrow and the full @@ -600,8 +595,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // Define a small closure that we can use to check if the type of a place // is a union. let is_union = |place: &Place<'tcx>| -> bool { - place.ty(self.mir, self.infcx.tcx) - .to_ty(self.infcx.tcx) + place.ty(self.mir, self.infcx.tcx).ty .ty_adt_def() .map(|adt| adt.is_union()) .unwrap_or(false) @@ -650,7 +644,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // Also compute the name of the union type, eg. `Foo` so we // can add a helpful note with it. - let ty = base.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx); + let ty = base.ty(self.mir, self.infcx.tcx).ty; return Some((desc_base, desc_first, desc_second, ty.to_string())); }, @@ -1533,7 +1527,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { if let TerminatorKind::Call { func: Operand::Constant(box Constant { literal: ty::Const { - ty: &ty::TyS { sty: ty::TyKind::FnDef(id, _), .. }, + ty: &ty::TyS { sty: ty::FnDef(id, _), .. }, .. }, .. @@ -1551,7 +1545,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { }; debug!("add_moved_or_invoked_closure_note: closure={:?}", closure); - if let ty::TyKind::Closure(did, _) = self.mir.local_decls[closure].ty.sty { + if let ty::Closure(did, _) = self.mir.local_decls[closure].ty.sty { let hir_id = self.infcx.tcx.hir().as_local_hir_id(did).unwrap(); if let Some((span, name)) = self.infcx.tcx.typeck_tables_of(did) @@ -1574,7 +1568,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // Check if we are just moving a closure after it has been invoked. if let Some(target) = target { - if let ty::TyKind::Closure(did, _) = self.mir.local_decls[target].ty.sty { + if let ty::Closure(did, _) = self.mir.local_decls[target].ty.sty { let hir_id = self.infcx.tcx.hir().as_local_hir_id(did).unwrap(); if let Some((span, name)) = self.infcx.tcx.typeck_tables_of(did) @@ -1765,20 +1759,22 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } /// End-user visible description of the `field`nth field of `base` - fn describe_field(&self, base: &Place<'_>, field: Field) -> String { + fn describe_field(&self, base: &Place<'tcx>, field: Field) -> String { match *base { Place::Base(PlaceBase::Local(local)) => { let local = &self.mir.local_decls[local]; - self.describe_field_from_ty(&local.ty, field) + self.describe_field_from_ty(&local.ty, field, None) } Place::Base(PlaceBase::Static(ref static_)) => - self.describe_field_from_ty(&static_.ty, field), + self.describe_field_from_ty(&static_.ty, field, None), Place::Projection(ref proj) => match proj.elem { ProjectionElem::Deref => self.describe_field(&proj.base, field), - ProjectionElem::Downcast(def, variant_index) => - def.variants[variant_index].fields[field.index()].ident.to_string(), + ProjectionElem::Downcast(_, variant_index) => { + let base_ty = base.ty(self.mir, self.infcx.tcx).ty; + self.describe_field_from_ty(&base_ty, field, Some(variant_index)) + } ProjectionElem::Field(_, field_type) => { - self.describe_field_from_ty(&field_type, field) + self.describe_field_from_ty(&field_type, field, None) } ProjectionElem::Index(..) | ProjectionElem::ConstantIndex { .. } @@ -1790,24 +1786,34 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } /// End-user visible description of the `field_index`nth field of `ty` - fn describe_field_from_ty(&self, ty: &ty::Ty<'_>, field: Field) -> String { + fn describe_field_from_ty( + &self, + ty: &ty::Ty<'_>, + field: Field, + variant_index: Option<VariantIdx> + ) -> String { if ty.is_box() { // If the type is a box, the field is described from the boxed type - self.describe_field_from_ty(&ty.boxed_ty(), field) + self.describe_field_from_ty(&ty.boxed_ty(), field, variant_index) } else { match ty.sty { - ty::Adt(def, _) => if def.is_enum() { - field.index().to_string() - } else { - def.non_enum_variant().fields[field.index()] + ty::Adt(def, _) => { + let variant = if let Some(idx) = variant_index { + assert!(def.is_enum()); + &def.variants[idx] + } else { + def.non_enum_variant() + }; + variant.fields[field.index()] .ident .to_string() }, ty::Tuple(_) => field.index().to_string(), ty::Ref(_, ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) => { - self.describe_field_from_ty(&ty, field) + self.describe_field_from_ty(&ty, field, variant_index) } - ty::Array(ty, _) | ty::Slice(ty) => self.describe_field_from_ty(&ty, field), + ty::Array(ty, _) | ty::Slice(ty) => + self.describe_field_from_ty(&ty, field, variant_index), ty::Closure(def_id, _) | ty::Generator(def_id, _, _) => { // Convert the def-id into a node-id. node-ids are only valid for // the local code in the current crate, so this returns an `Option` in case @@ -1865,7 +1871,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { StorageDeadOrDrop::LocalStorageDead | StorageDeadOrDrop::BoxedStorageDead => { assert!( - base.ty(self.mir, tcx).to_ty(tcx).is_box(), + base.ty(self.mir, tcx).ty.is_box(), "Drop of value behind a reference or raw pointer" ); StorageDeadOrDrop::BoxedStorageDead @@ -1873,7 +1879,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { StorageDeadOrDrop::Destructor(_) => base_access, }, ProjectionElem::Field(..) | ProjectionElem::Downcast(..) => { - let base_ty = base.ty(self.mir, tcx).to_ty(tcx); + let base_ty = base.ty(self.mir, tcx).ty; match base_ty.sty { ty::Adt(def, _) if def.has_dtor(tcx) => { // Report the outermost adt with a destructor @@ -1911,7 +1917,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } else { let ty = self.infcx.tcx.type_of(self.mir_def_id); match ty.sty { - ty::TyKind::FnDef(_, _) | ty::TyKind::FnPtr(_) => self.annotate_fn_sig( + ty::FnDef(_, _) | ty::FnPtr(_) => self.annotate_fn_sig( self.mir_def_id, self.infcx.tcx.fn_sig(self.mir_def_id), ), @@ -2156,12 +2162,12 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // anything. let return_ty = sig.output(); match return_ty.skip_binder().sty { - ty::TyKind::Ref(return_region, _, _) if return_region.has_name() && !is_closure => { + ty::Ref(return_region, _, _) if return_region.has_name() && !is_closure => { // This is case 1 from above, return type is a named reference so we need to // search for relevant arguments. let mut arguments = Vec::new(); for (index, argument) in sig.inputs().skip_binder().iter().enumerate() { - if let ty::TyKind::Ref(argument_region, _, _) = argument.sty { + if let ty::Ref(argument_region, _, _) = argument.sty { if argument_region == return_region { // Need to use the `rustc::ty` types to compare against the // `return_region`. Then use the `rustc::hir` type to get only @@ -2198,7 +2204,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { return_span, }) } - ty::TyKind::Ref(_, _, _) if is_closure => { + ty::Ref(_, _, _) if is_closure => { // This is case 2 from above but only for closures, return type is anonymous // reference so we select // the first argument. @@ -2207,9 +2213,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // Closure arguments are wrapped in a tuple, so we need to get the first // from that. - if let ty::TyKind::Tuple(elems) = argument_ty.sty { + if let ty::Tuple(elems) = argument_ty.sty { let argument_ty = elems.first()?; - if let ty::TyKind::Ref(_, _, _) = argument_ty.sty { + if let ty::Ref(_, _, _) = argument_ty.sty { return Some(AnnotatedBorrowFnSignature::Closure { argument_ty, argument_span, @@ -2219,7 +2225,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { None } - ty::TyKind::Ref(_, _, _) => { + ty::Ref(_, _, _) => { // This is also case 2 from above but for functions, return type is still an // anonymous reference so we select the first argument. let argument_span = fn_decl.inputs.first()?.span; @@ -2230,7 +2236,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // We expect the first argument to be a reference. match argument_ty.sty { - ty::TyKind::Ref(_, _, _) => {} + ty::Ref(_, _, _) => {} _ => return None, } @@ -2358,8 +2364,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // this by hooking into the pretty printer and telling it to label the // lifetimes without names with the value `'0`. match ty.sty { - ty::TyKind::Ref(ty::RegionKind::ReLateBound(_, br), _, _) - | ty::TyKind::Ref( + ty::Ref(ty::RegionKind::ReLateBound(_, br), _, _) + | ty::Ref( ty::RegionKind::RePlaceholder(ty::PlaceholderRegion { name: br, .. }), _, _, @@ -2378,7 +2384,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { let mut printer = ty::print::FmtPrinter::new(self.infcx.tcx, &mut s, Namespace::TypeNS); let region = match ty.sty { - ty::TyKind::Ref(region, _, _) => { + ty::Ref(region, _, _) => { match region { ty::RegionKind::ReLateBound(_, br) | ty::RegionKind::RePlaceholder(ty::PlaceholderRegion { name: br, .. }) => { diff --git a/src/librustc_mir/borrow_check/flows.rs b/src/librustc_mir/borrow_check/flows.rs index 8de39f0efc1..c0b199f1798 100644 --- a/src/librustc_mir/borrow_check/flows.rs +++ b/src/librustc_mir/borrow_check/flows.rs @@ -11,7 +11,7 @@ use crate::borrow_check::location::LocationIndex; use polonius_engine::Output; -use crate::dataflow::move_paths::indexes::BorrowIndex; +use crate::dataflow::indexes::BorrowIndex; use crate::dataflow::move_paths::HasMoveData; use crate::dataflow::Borrows; use crate::dataflow::EverInitializedPlaces; diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 5c159cda141..0b2c90b9160 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -6,6 +6,7 @@ use rustc::hir::Node; use rustc::hir::def_id::DefId; use rustc::infer::InferCtxt; use rustc::lint::builtin::UNUSED_MUT; +use rustc::lint::builtin::{MUTABLE_BORROW_RESERVATION_CONFLICT}; use rustc::middle::borrowck::SignalledError; use rustc::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind}; use rustc::mir::{ @@ -18,17 +19,18 @@ use rustc::ty::{self, TyCtxt}; use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, Level}; use rustc_data_structures::bit_set::BitSet; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::graph::dominators::Dominators; use smallvec::SmallVec; -use std::rc::Rc; use std::collections::BTreeMap; +use std::mem; +use std::rc::Rc; -use syntax_pos::Span; +use syntax_pos::{Span, DUMMY_SP}; use crate::dataflow::indexes::{BorrowIndex, InitIndex, MoveOutIndex, MovePathIndex}; -use crate::dataflow::move_paths::{HasMoveData, LookupResult, MoveData, MoveError}; +use crate::dataflow::move_paths::{HasMoveData, InitLocation, LookupResult, MoveData, MoveError}; use crate::dataflow::Borrows; use crate::dataflow::DataflowResultsConsumer; use crate::dataflow::FlowAtLocation; @@ -238,6 +240,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>( locals_are_invalidated_at_exit, access_place_error_reported: Default::default(), reservation_error_reported: Default::default(), + reservation_warnings: Default::default(), move_error_reported: BTreeMap::new(), uninitialized_error_reported: Default::default(), errors_buffer, @@ -260,6 +263,29 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>( } mbcx.analyze_results(&mut state); // entry point for DataflowResultsConsumer + // Convert any reservation warnings into lints. + let reservation_warnings = mem::replace(&mut mbcx.reservation_warnings, Default::default()); + for (_, (place, span, context, bk, borrow)) in reservation_warnings { + let mut initial_diag = mbcx.report_conflicting_borrow(context, (&place, span), bk, &borrow); + + let lint_root = if let ClearCrossCrate::Set(ref vsi) = mbcx.mir.source_scope_local_data { + let scope = mbcx.mir.source_info(context.loc).scope; + vsi[scope].lint_root + } else { + id + }; + + // Span and message don't matter; we overwrite them below anyway + let mut diag = mbcx.infcx.tcx.struct_span_lint_hir( + MUTABLE_BORROW_RESERVATION_CONFLICT, lint_root, DUMMY_SP, ""); + + diag.message = initial_diag.styled_message().clone(); + diag.span = initial_diag.span.clone(); + + initial_diag.cancel(); + diag.buffer(&mut mbcx.errors_buffer); + } + // For each non-user used mutable variable, check if it's been assigned from // a user-declared local. If so, then put that local into the used_mut set. // Note that this set is expected to be small - only upvars from closures @@ -341,18 +367,9 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>( // if AST-borrowck signalled no errors, then // downgrade all the buffered MIR-borrowck errors // to warnings. - for err in &mut mbcx.errors_buffer { - if err.is_error() { - err.level = Level::Warning; - err.warn( - "this error has been downgraded to a warning for backwards \ - compatibility with previous releases", - ); - err.warn( - "this represents potential undefined behavior in your code and \ - this warning will become a hard error in the future", - ); - } + + for err in mbcx.errors_buffer.iter_mut() { + downgrade_if_error(err); } } SignalledError::SawSomeError => { @@ -378,6 +395,20 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>( result } +fn downgrade_if_error(diag: &mut Diagnostic) { + if diag.is_error() { + diag.level = Level::Warning; + diag.warn( + "this error has been downgraded to a warning for backwards \ + compatibility with previous releases", + ); + diag.warn( + "this represents potential undefined behavior in your code and \ + this warning will become a hard error in the future", + ); + } +} + pub struct MirBorrowckCtxt<'cx, 'gcx: 'tcx, 'tcx: 'cx> { infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>, mir: &'cx Mir<'tcx>, @@ -410,6 +441,13 @@ pub struct MirBorrowckCtxt<'cx, 'gcx: 'tcx, 'tcx: 'cx> { // but it is currently inconvenient to track down the `BorrowIndex` // at the time we detect and report a reservation error. reservation_error_reported: FxHashSet<Place<'tcx>>, + /// Migration warnings to be reported for #56254. We delay reporting these + /// so that we can suppress the warning if there's a corresponding error + /// for the activation of the borrow. + reservation_warnings: FxHashMap< + BorrowIndex, + (Place<'tcx>, Span, Context, BorrowKind, BorrowData<'tcx>) + >, /// This field keeps track of move errors that are to be reported for given move indicies. /// /// There are situations where many errors can be reported for a single move out (see #53807) @@ -525,16 +563,12 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx flow_state, ); } - StatementKind::InlineAsm { - ref asm, - ref outputs, - ref inputs, - } => { + StatementKind::InlineAsm(ref asm) => { let context = ContextKind::InlineAsm.new(location); - for (o, output) in asm.outputs.iter().zip(outputs.iter()) { + for (o, output) in asm.asm.outputs.iter().zip(asm.outputs.iter()) { if o.is_indirect { // FIXME(eddyb) indirect inline asm outputs should - // be encoeded through MIR place derefs instead. + // be encoded through MIR place derefs instead. self.access_place( context, (output, o.span), @@ -558,7 +592,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx ); } } - for (_, input) in inputs.iter() { + for (_, input) in asm.inputs.iter() { self.consume_operand(context, (input, span), flow_state); } } @@ -616,8 +650,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx let drop_place_ty = drop_place.ty(self.mir, self.infcx.tcx); // Erase the regions. - let drop_place_ty = self.infcx.tcx.erase_regions(&drop_place_ty) - .to_ty(self.infcx.tcx); + let drop_place_ty = self.infcx.tcx.erase_regions(&drop_place_ty).ty; // "Lift" into the gcx -- once regions are erased, this type should be in the // global arenas; this "lift" operation basically just asserts that is true, but @@ -688,7 +721,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx cleanup: _, } => { self.consume_operand(ContextKind::Assert.new(loc), (cond, span), flow_state); - use rustc::mir::interpret::EvalErrorKind::BoundsCheck; + use rustc::mir::interpret::InterpError::BoundsCheck; if let BoundsCheck { ref len, ref index } = *msg { self.consume_operand(ContextKind::Assert.new(loc), (len, span), flow_state); self.consume_operand(ContextKind::Assert.new(loc), (index, span), flow_state); @@ -926,11 +959,18 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { let conflict_error = self.check_access_for_conflict(context, place_span, sd, rw, flow_state); + if let (Activation(_, borrow_idx), true) = (kind.1, conflict_error) { + // Suppress this warning when there's an error being emited for the + // same borrow: fixing the error is likely to fix the warning. + self.reservation_warnings.remove(&borrow_idx); + } + if conflict_error || mutability_error { debug!( "access_place: logging error place_span=`{:?}` kind=`{:?}`", place_span, kind ); + self.access_place_error_reported .insert((place_span.0.clone(), place_span.1)); } @@ -981,8 +1021,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { Control::Continue } - (Read(_), BorrowKind::Shared) | (Reservation(..), BorrowKind::Shared) - | (Read(_), BorrowKind::Shallow) | (Reservation(..), BorrowKind::Shallow) + (Read(_), BorrowKind::Shared) + | (Read(_), BorrowKind::Shallow) | (Read(ReadKind::Borrow(BorrowKind::Shallow)), BorrowKind::Unique) | (Read(ReadKind::Borrow(BorrowKind::Shallow)), BorrowKind::Mut { .. }) => { Control::Continue @@ -996,7 +1036,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { (Read(kind), BorrowKind::Unique) | (Read(kind), BorrowKind::Mut { .. }) => { // Reading from mere reservations of mutable-borrows is OK. if !is_active(&this.dominators, borrow, context.loc) { - assert!(allow_two_phase_borrow(&this.infcx.tcx, borrow.kind)); + assert!(allow_two_phase_borrow(&tcx, borrow.kind)); return Control::Continue; } @@ -1004,20 +1044,45 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { match kind { ReadKind::Copy => { this.report_use_while_mutably_borrowed(context, place_span, borrow) + .buffer(&mut this.errors_buffer); } ReadKind::Borrow(bk) => { - this.report_conflicting_borrow(context, place_span, bk, &borrow) + this.report_conflicting_borrow(context, place_span, bk, borrow) + .buffer(&mut this.errors_buffer); } } Control::Break } - (Reservation(kind), BorrowKind::Unique) - | (Reservation(kind), BorrowKind::Mut { .. }) + (Reservation(WriteKind::MutableBorrow(bk)), BorrowKind::Shallow) + | (Reservation(WriteKind::MutableBorrow(bk)), BorrowKind::Shared) if { + tcx.migrate_borrowck() + } => { + let bi = this.borrow_set.location_map[&context.loc]; + debug!( + "recording invalid reservation of place: {:?} with \ + borrow index {:?} as warning", + place_span.0, + bi, + ); + // rust-lang/rust#56254 - This was previously permitted on + // the 2018 edition so we emit it as a warning. We buffer + // these sepately so that we only emit a warning if borrow + // checking was otherwise successful. + this.reservation_warnings.insert( + bi, + (place_span.0.clone(), place_span.1, context, bk, borrow.clone()), + ); + + // Don't suppress actual errors. + Control::Continue + } + + (Reservation(kind), _) | (Activation(kind, _), _) | (Write(kind), _) => { match rw { - Reservation(_) => { + Reservation(..) => { debug!( "recording invalid reservation of \ place: {:?}", @@ -1038,7 +1103,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { error_reported = true; match kind { WriteKind::MutableBorrow(bk) => { - this.report_conflicting_borrow(context, place_span, bk, &borrow) + this.report_conflicting_borrow(context, place_span, bk, borrow) + .buffer(&mut this.errors_buffer); } WriteKind::StorageDeadOrDrop => { this.report_borrowed_value_does_not_live_long_enough( @@ -1051,7 +1117,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { this.report_illegal_mutation_of_borrowed(context, place_span, borrow) } WriteKind::Move => { - this.report_move_out_while_borrowed(context, place_span, &borrow) + this.report_move_out_while_borrowed(context, place_span, borrow) } } Control::Break @@ -1211,25 +1277,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } = self.infcx.tcx.mir_borrowck(def_id); debug!("{:?} used_mut_upvars={:?}", def_id, used_mut_upvars); for field in used_mut_upvars { - // This relies on the current way that by-value - // captures of a closure are copied/moved directly - // when generating MIR. - match operands[field.index()] { - Operand::Move(Place::Base(PlaceBase::Local(local))) - | Operand::Copy(Place::Base(PlaceBase::Local(local))) => { - self.used_mut.insert(local); - } - Operand::Move(ref place @ Place::Projection(_)) - | Operand::Copy(ref place @ Place::Projection(_)) => { - if let Some(field) = place.is_upvar_field_projection( - self.mir, &self.infcx.tcx) { - self.used_mut_upvars.push(field); - } - } - Operand::Move(Place::Base(PlaceBase::Static(..))) - | Operand::Copy(Place::Base(PlaceBase::Static(..))) - | Operand::Constant(..) => {} - } + self.propagate_closure_used_mut_upvar(&operands[field.index()]); } } AggregateKind::Adt(..) @@ -1244,6 +1292,80 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } } + fn propagate_closure_used_mut_upvar(&mut self, operand: &Operand<'tcx>) { + let propagate_closure_used_mut_place = |this: &mut Self, place: &Place<'tcx>| { + match *place { + Place::Projection { .. } => { + if let Some(field) = place.is_upvar_field_projection( + this.mir, &this.infcx.tcx) { + this.used_mut_upvars.push(field); + } + } + Place::Base(PlaceBase::Local(local)) => { + this.used_mut.insert(local); + } + Place::Base(PlaceBase::Static(_)) => {} + } + }; + + // This relies on the current way that by-value + // captures of a closure are copied/moved directly + // when generating MIR. + match *operand { + Operand::Move(Place::Base(PlaceBase::Local(local))) + | Operand::Copy(Place::Base(PlaceBase::Local(local))) + if self.mir.local_decls[local].is_user_variable.is_none() => + { + if self.mir.local_decls[local].ty.is_mutable_pointer() { + // The variable will be marked as mutable by the borrow. + return; + } + // This is an edge case where we have a `move` closure + // inside a non-move closure, and the inner closure + // contains a mutation: + // + // let mut i = 0; + // || { move || { i += 1; }; }; + // + // In this case our usual strategy of assuming that the + // variable will be captured by mutable reference is + // wrong, since `i` can be copied into the inner + // closure from a shared reference. + // + // As such we have to search for the local that this + // capture comes from and mark it as being used as mut. + + let temp_mpi = self.move_data.rev_lookup.find_local(local); + let init = if let [init_index] = *self.move_data.init_path_map[temp_mpi] { + &self.move_data.inits[init_index] + } else { + bug!("temporary should be initialized exactly once") + }; + + let loc = match init.location { + InitLocation::Statement(stmt) => stmt, + _ => bug!("temporary initialized in arguments"), + }; + + let bbd = &self.mir[loc.block]; + let stmt = &bbd.statements[loc.statement_index]; + debug!("temporary assigned in: stmt={:?}", stmt); + + if let StatementKind::Assign(_, box Rvalue::Ref(_, _, ref source)) = stmt.kind { + propagate_closure_used_mut_place(self, source); + } else { + bug!("closures should only capture user variables \ + or references to user variables"); + } + } + Operand::Move(ref place) + | Operand::Copy(ref place) => { + propagate_closure_used_mut_place(self, place); + } + Operand::Constant(..) => {} + } + } + fn consume_operand( &mut self, context: Context, @@ -1641,7 +1763,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // assigning to `P.f` requires `P` itself // be already initialized let tcx = self.infcx.tcx; - match base.ty(self.mir, tcx).to_ty(tcx).sty { + match base.ty(self.mir, tcx).ty.sty { ty::Adt(def, _) if def.has_dtor(tcx) => { self.check_if_path_or_subpath_is_moved( context, InitializationRequiringAction::Assignment, @@ -1746,7 +1868,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // no move out from an earlier location) then this is an attempt at initialization // of the union - we should error in that case. let tcx = this.infcx.tcx; - if let ty::TyKind::Adt(def, _) = base.ty(this.mir, tcx).to_ty(tcx).sty { + if let ty::Adt(def, _) = base.ty(this.mir, tcx).ty.sty { if def.is_union() { if this.move_data.path_map[mpi].iter().any(|moi| { this.move_data.moves[*moi].source.is_predecessor_of( @@ -2007,7 +2129,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { Place::Projection(ref proj) => { match proj.elem { ProjectionElem::Deref => { - let base_ty = proj.base.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx); + let base_ty = proj.base.ty(self.mir, self.infcx.tcx).ty; // Check the kind of deref to decide match base_ty.sty { diff --git a/src/librustc_mir/borrow_check/move_errors.rs b/src/librustc_mir/borrow_check/move_errors.rs index bd4bf67d0b1..7efe1d83c2e 100644 --- a/src/librustc_mir/borrow_check/move_errors.rs +++ b/src/librustc_mir/borrow_check/move_errors.rs @@ -266,7 +266,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { // Inspect the type of the content behind the // borrow to provide feedback about why this // was a move rather than a copy. - let ty = place.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx); + let ty = place.ty(self.mir, self.infcx.tcx).ty; let is_upvar_field_projection = self.prefixes(&original_path, PrefixSet::All) .any(|p| p.is_upvar_field_projection(self.mir, &self.infcx.tcx) @@ -530,9 +530,9 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { // We're only interested in assignments (in particular, where the // assignment came from - was it an `Rc` or `Arc`?). if let StatementKind::Assign(_, box Rvalue::Ref(_, _, source)) = &stmt.kind { - let ty = source.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx); + let ty = source.ty(self.mir, self.infcx.tcx).ty; let ty = match ty.sty { - ty::TyKind::Ref(_, ty, _) => ty, + ty::Ref(_, ty, _) => ty, _ => ty, }; debug!("borrowed_content_source: ty={:?}", ty); @@ -555,9 +555,9 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { _ => continue, }; - let ty = source.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx); + let ty = source.ty(self.mir, self.infcx.tcx).ty; let ty = match ty.sty { - ty::TyKind::Ref(_, ty, _) => ty, + ty::Ref(_, ty, _) => ty, _ => ty, }; debug!("borrowed_content_source: ty={:?}", ty); @@ -581,7 +581,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { base, elem: ProjectionElem::Deref, }) = place { - if base.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx).is_unsafe_ptr() { + if base.ty(self.mir, self.infcx.tcx).ty.is_unsafe_ptr() { return BorrowedContentSource::DerefRawPointer; } } diff --git a/src/librustc_mir/borrow_check/mutability_errors.rs b/src/librustc_mir/borrow_check/mutability_errors.rs index f351212e9d5..b780511315d 100644 --- a/src/librustc_mir/borrow_check/mutability_errors.rs +++ b/src/librustc_mir/borrow_check/mutability_errors.rs @@ -5,7 +5,7 @@ use rustc::mir::{ Mutability, Operand, Place, PlaceBase, Projection, ProjectionElem, Static, StaticKind, }; use rustc::mir::{Terminator, TerminatorKind}; -use rustc::ty::{self, Const, DefIdTree, TyS, TyKind, TyCtxt}; +use rustc::ty::{self, Const, DefIdTree, TyS, TyCtxt}; use rustc_data_structures::indexed_vec::Idx; use syntax_pos::Span; use syntax_pos::symbol::keywords; @@ -64,7 +64,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { elem: ProjectionElem::Field(upvar_index, _), }) => { debug_assert!(is_closure_or_generator( - base.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx) + base.ty(self.mir, self.infcx.tcx).ty )); item_msg = format!("`{}`", access_place_desc.unwrap()); @@ -85,7 +85,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { item_msg = format!("`{}`", access_place_desc.unwrap()); debug_assert!(self.mir.local_decls[Local::new(1)].ty.is_region_ptr()); debug_assert!(is_closure_or_generator( - the_place_err.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx) + the_place_err.ty(self.mir, self.infcx.tcx).ty )); reason = if access_place.is_upvar_field_projection(self.mir, @@ -110,7 +110,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { reason = ", as it is immutable for the pattern guard".to_string(); } else { let pointer_type = - if base.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx).is_region_ptr() { + if base.ty(self.mir, self.infcx.tcx).ty.is_region_ptr() { "`&` reference" } else { "`*const` pointer" @@ -232,7 +232,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { if let Some((span, message)) = annotate_struct_field( self.infcx.tcx, - base.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx), + base.ty(self.mir, self.infcx.tcx).ty, field, ) { err.span_suggestion( @@ -261,7 +261,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { // Otherwise, check if the name is the self kewyord - in which case // we have an explicit self. Do the same thing in this case and check // for a `self: &mut Self` to suggest removing the `&mut`. - if let ty::TyKind::Ref( + if let ty::Ref( _, _, hir::Mutability::MutMutable ) = local_decl.ty.sty { true @@ -304,7 +304,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { elem: ProjectionElem::Field(upvar_index, _), }) => { debug_assert!(is_closure_or_generator( - base.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx) + base.ty(self.mir, self.infcx.tcx).ty )); err.span_label(span, format!("cannot {ACT}", ACT = act)); @@ -476,7 +476,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { func: Operand::Constant(box Constant { literal: Const { ty: &TyS { - sty: TyKind::FnDef(id, substs), + sty: ty::FnDef(id, substs), .. }, .. @@ -633,8 +633,8 @@ fn annotate_struct_field( field: &mir::Field, ) -> Option<(Span, String)> { // Expect our local to be a reference to a struct of some kind. - if let ty::TyKind::Ref(_, ty, _) = ty.sty { - if let ty::TyKind::Adt(def, _) = ty.sty { + if let ty::Ref(_, ty, _) = ty.sty { + if let ty::Adt(def, _) = ty.sty { let field = def.all_fields().nth(field.index())?; // Use the HIR types to construct the diagnostic message. let hir_id = tcx.hir().as_local_hir_id(field.did)?; diff --git a/src/librustc_mir/borrow_check/nll/constraint_generation.rs b/src/librustc_mir/borrow_check/nll/constraint_generation.rs index 375dd6e97f1..bf9cff1e4ae 100644 --- a/src/librustc_mir/borrow_check/nll/constraint_generation.rs +++ b/src/librustc_mir/borrow_check/nll/constraint_generation.rs @@ -174,7 +174,7 @@ impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx &mut self, _place: &Place<'tcx>, _variance: &ty::Variance, - _user_ty: &UserTypeProjection<'tcx>, + _user_ty: &UserTypeProjection, _location: Location, ) { } diff --git a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs index 67b77605f3c..e30938bc326 100644 --- a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs +++ b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs @@ -589,7 +589,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // Check the type for a trait object. return match ty.sty { // `&dyn Trait` - ty::TyKind::Ref(_, ty, _) if ty.is_trait() => true, + ty::Ref(_, ty, _) if ty.is_trait() => true, // `Box<dyn Trait>` _ if ty.is_box() && ty.boxed_ty().is_trait() => true, // `dyn Trait` diff --git a/src/librustc_mir/borrow_check/nll/facts.rs b/src/librustc_mir/borrow_check/nll/facts.rs index 9714398d9d6..926f52b7cfc 100644 --- a/src/librustc_mir/borrow_check/nll/facts.rs +++ b/src/librustc_mir/borrow_check/nll/facts.rs @@ -72,18 +72,6 @@ impl Atom for BorrowIndex { } } -impl From<usize> for BorrowIndex { - fn from(i: usize) -> BorrowIndex { - BorrowIndex::new(i) - } -} - -impl From<BorrowIndex> for usize { - fn from(vid: BorrowIndex) -> usize { - Idx::index(vid) - } -} - impl Atom for LocationIndex { fn index(self) -> usize { Idx::index(self) diff --git a/src/librustc_mir/borrow_check/nll/invalidation.rs b/src/librustc_mir/borrow_check/nll/invalidation.rs index aafbff35776..36d3a03cdfd 100644 --- a/src/librustc_mir/borrow_check/nll/invalidation.rs +++ b/src/librustc_mir/borrow_check/nll/invalidation.rs @@ -9,7 +9,7 @@ use crate::borrow_check::ArtificialField; use crate::borrow_check::{ReadKind, WriteKind}; use crate::borrow_check::nll::facts::AllFacts; use crate::borrow_check::path_utils::*; -use crate::dataflow::move_paths::indexes::BorrowIndex; +use crate::dataflow::indexes::BorrowIndex; use rustc::ty::TyCtxt; use rustc::mir::visit::Visitor; use rustc::mir::{BasicBlock, Location, Mir, Place, PlaceBase, Rvalue}; @@ -92,16 +92,12 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> { JustWrite, ); } - StatementKind::InlineAsm { - ref asm, - ref outputs, - ref inputs, - } => { + StatementKind::InlineAsm(ref asm) => { let context = ContextKind::InlineAsm.new(location); - for (o, output) in asm.outputs.iter().zip(outputs.iter()) { + for (o, output) in asm.asm.outputs.iter().zip(asm.outputs.iter()) { if o.is_indirect { // FIXME(eddyb) indirect inline asm outputs should - // be encoeded through MIR place derefs instead. + // be encoded through MIR place derefs instead. self.access_place( context, output, @@ -117,7 +113,7 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> { ); } } - for (_, input) in inputs.iter() { + for (_, input) in asm.inputs.iter() { self.consume_operand(context, input); } } @@ -215,7 +211,7 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> { cleanup: _, } => { self.consume_operand(ContextKind::Assert.new(location), cond); - use rustc::mir::interpret::EvalErrorKind::BoundsCheck; + use rustc::mir::interpret::InterpError::BoundsCheck; if let BoundsCheck { ref len, ref index } = *msg { self.consume_operand(ContextKind::Assert.new(location), len); self.consume_operand(ContextKind::Assert.new(location), index); @@ -432,11 +428,11 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> { // have already taken the reservation } - (Read(_), BorrowKind::Shallow) | (Reservation(..), BorrowKind::Shallow) - | (Read(_), BorrowKind::Shared) | (Reservation(..), BorrowKind::Shared) + (Read(_), BorrowKind::Shallow) + | (Read(_), BorrowKind::Shared) | (Read(ReadKind::Borrow(BorrowKind::Shallow)), BorrowKind::Unique) | (Read(ReadKind::Borrow(BorrowKind::Shallow)), BorrowKind::Mut { .. }) => { - // Reads/reservations don't invalidate shared or shallow borrows + // Reads don't invalidate shared or shallow borrows } (Read(_), BorrowKind::Unique) | (Read(_), BorrowKind::Mut { .. }) => { @@ -452,16 +448,15 @@ impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cx, 'tcx, 'gcx> { this.generate_invalidates(borrow_index, context.loc); } - (Reservation(_), BorrowKind::Unique) - | (Reservation(_), BorrowKind::Mut { .. }) - | (Activation(_, _), _) - | (Write(_), _) => { - // unique or mutable borrows are invalidated by writes. - // Reservations count as writes since we need to check - // that activating the borrow will be OK - // FIXME(bob_twinkles) is this actually the right thing to do? - this.generate_invalidates(borrow_index, context.loc); - } + (Reservation(_), _) + | (Activation(_, _), _) + | (Write(_), _) => { + // unique or mutable borrows are invalidated by writes. + // Reservations count as writes since we need to check + // that activating the borrow will be OK + // FIXME(bob_twinkles) is this actually the right thing to do? + this.generate_invalidates(borrow_index, context.loc); + } } Control::Continue }, diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs index 3773f1a40c7..917e383cae8 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/mod.rs @@ -583,7 +583,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { (self.to_error_region(fr), self.to_error_region(outlived_fr)) { if let Some(ty::TyS { - sty: ty::TyKind::Opaque(did, substs), + sty: ty::Opaque(did, substs), .. }) = infcx .tcx diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs b/src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs index f0df7070e6b..4c4b4c04319 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs @@ -3,7 +3,7 @@ use crate::borrow_check::nll::region_infer::values::{self, PointIndex, RegionVal use crate::borrow_check::nll::type_check::liveness::local_use_map::LocalUseMap; use crate::borrow_check::nll::type_check::NormalizeLocation; use crate::borrow_check::nll::type_check::TypeChecker; -use crate::dataflow::move_paths::indexes::MovePathIndex; +use crate::dataflow::indexes::MovePathIndex; use crate::dataflow::move_paths::MoveData; use crate::dataflow::{FlowAtLocation, FlowsAtLocation, MaybeInitializedPlaces}; use rustc::infer::canonical::QueryRegionConstraint; diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index 3b559b28f12..ec5637d1707 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -28,7 +28,7 @@ use rustc::infer::canonical::QueryRegionConstraint; use rustc::infer::outlives::env::RegionBoundPairs; use rustc::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime, NLLRegionVariableOrigin}; use rustc::infer::type_variable::TypeVariableOrigin; -use rustc::mir::interpret::{EvalErrorKind::BoundsCheck, ConstValue}; +use rustc::mir::interpret::{InterpError::BoundsCheck, ConstValue}; use rustc::mir::tcx::PlaceTy; use rustc::mir::visit::{PlaceContext, Visitor, MutatingUseContext, NonMutatingUseContext}; use rustc::mir::*; @@ -39,7 +39,7 @@ use rustc::traits::{ObligationCause, PredicateObligations}; use rustc::ty::fold::TypeFoldable; use rustc::ty::subst::{Subst, SubstsRef, UnpackedKind, UserSubsts}; use rustc::ty::{ - self, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TyKind, UserType, + self, RegionVid, ToPolyTraitRef, Ty, TyCtxt, UserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, UserTypeAnnotationIndex, }; @@ -450,9 +450,8 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { ) -> PlaceTy<'tcx> { debug!("sanitize_place: {:?}", place); let place_ty = match place { - Place::Base(PlaceBase::Local(index)) => PlaceTy::Ty { - ty: self.mir.local_decls[*index].ty, - }, + Place::Base(PlaceBase::Local(index)) => + PlaceTy::from_ty(self.mir.local_decls[*index].ty), Place::Base(PlaceBase::Static(box Static { kind, ty: sty })) => { let sty = self.sanitize_type(place, sty); let check_err = @@ -493,7 +492,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { check_err(self, place, ty, sty); } } - PlaceTy::Ty { ty: sty } + PlaceTy::from_ty(sty) } Place::Projection(ref proj) => { let base_context = if context.is_mutating_use() { @@ -502,12 +501,10 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) }; let base_ty = self.sanitize_place(&proj.base, location, base_context); - if let PlaceTy::Ty { ty } = base_ty { - if ty.references_error() { + if base_ty.variant_index.is_none() { + if base_ty.ty.references_error() { assert!(self.errors_reported); - return PlaceTy::Ty { - ty: self.tcx().types.err, - }; + return PlaceTy::from_ty(self.tcx().types.err); } } self.sanitize_projection(base_ty, &proj.elem, place, location) @@ -517,7 +514,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { let tcx = self.tcx(); let trait_ref = ty::TraitRef { def_id: tcx.lang_items().copy_trait().unwrap(), - substs: tcx.mk_substs_trait(place_ty.to_ty(tcx), &[]), + substs: tcx.mk_substs_trait(place_ty.ty, &[]), }; // In order to have a Copy operand, the type T of the @@ -615,40 +612,40 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { ) -> PlaceTy<'tcx> { debug!("sanitize_projection: {:?} {:?} {:?}", base, pi, place); let tcx = self.tcx(); - let base_ty = base.to_ty(tcx); + let base_ty = base.ty; match *pi { ProjectionElem::Deref => { let deref_ty = base_ty.builtin_deref(true); - PlaceTy::Ty { - ty: deref_ty.map(|t| t.ty).unwrap_or_else(|| { + PlaceTy::from_ty( + deref_ty.map(|t| t.ty).unwrap_or_else(|| { span_mirbug_and_err!(self, place, "deref of non-pointer {:?}", base_ty) - }), - } + }) + ) } ProjectionElem::Index(i) => { - let index_ty = Place::Base(PlaceBase::Local(i)).ty(self.mir, tcx).to_ty(tcx); + let index_ty = Place::Base(PlaceBase::Local(i)).ty(self.mir, tcx).ty; if index_ty != tcx.types.usize { - PlaceTy::Ty { - ty: span_mirbug_and_err!(self, i, "index by non-usize {:?}", i), - } + PlaceTy::from_ty( + span_mirbug_and_err!(self, i, "index by non-usize {:?}", i), + ) } else { - PlaceTy::Ty { - ty: base_ty.builtin_index().unwrap_or_else(|| { + PlaceTy::from_ty( + base_ty.builtin_index().unwrap_or_else(|| { span_mirbug_and_err!(self, place, "index of non-array {:?}", base_ty) }), - } + ) } } ProjectionElem::ConstantIndex { .. } => { // consider verifying in-bounds - PlaceTy::Ty { - ty: base_ty.builtin_index().unwrap_or_else(|| { + PlaceTy::from_ty( + base_ty.builtin_index().unwrap_or_else(|| { span_mirbug_and_err!(self, place, "index of non-array {:?}", base_ty) }), - } + ) } - ProjectionElem::Subslice { from, to } => PlaceTy::Ty { - ty: match base_ty.sty { + ProjectionElem::Subslice { from, to } => PlaceTy::from_ty( + match base_ty.sty { ty::Array(inner, size) => { let size = size.unwrap_usize(tcx); let min_size = (from as u64) + (to as u64); @@ -666,35 +663,39 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { ty::Slice(..) => base_ty, _ => span_mirbug_and_err!(self, place, "slice of non-array {:?}", base_ty), }, - }, - ProjectionElem::Downcast(adt_def1, index) => match base_ty.sty { - ty::Adt(adt_def, substs) if adt_def.is_enum() && adt_def == adt_def1 => { + ), + ProjectionElem::Downcast(maybe_name, index) => match base_ty.sty { + ty::Adt(adt_def, _substs) if adt_def.is_enum() => { if index.as_usize() >= adt_def.variants.len() { - PlaceTy::Ty { - ty: span_mirbug_and_err!( + PlaceTy::from_ty( + span_mirbug_and_err!( self, place, "cast to variant #{:?} but enum only has {:?}", index, adt_def.variants.len() ), - } + ) } else { - PlaceTy::Downcast { - adt_def, - substs, - variant_index: index, + PlaceTy { + ty: base_ty, + variant_index: Some(index), } } } - _ => PlaceTy::Ty { - ty: span_mirbug_and_err!( - self, - place, - "can't downcast {:?} as {:?}", - base_ty, - adt_def1 - ), + _ => { + let ty = if let Some(name) = maybe_name { + span_mirbug_and_err!( + self, + place, + "can't downcast {:?} as {:?}", + base_ty, + name + ) + } else { + span_mirbug_and_err!(self, place, "can't downcast {:?}", base_ty) + }; + PlaceTy::from_ty(ty) }, }, ProjectionElem::Field(field, fty) => { @@ -723,7 +724,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { field_count ), } - PlaceTy::Ty { ty: fty } + PlaceTy::from_ty(fty) } } } @@ -743,12 +744,13 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { let tcx = self.tcx(); let (variant, substs) = match base_ty { - PlaceTy::Downcast { - adt_def, - substs, - variant_index, - } => (&adt_def.variants[variant_index], substs), - PlaceTy::Ty { ty } => match ty.sty { + PlaceTy { ty, variant_index: Some(variant_index) } => { + match ty.sty { + ty::Adt(adt_def, substs) => (&adt_def.variants[variant_index], substs), + _ => bug!("can't have downcast of non-adt type"), + } + } + PlaceTy { ty, variant_index: None } => match ty.sty { ty::Adt(adt_def, substs) if !adt_def.is_enum() => (&adt_def.variants[VariantIdx::new(0)], substs), ty::Closure(def_id, substs) => { @@ -1134,7 +1136,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { category: ConstraintCategory, ) -> Fallible<()> { if let Err(terr) = self.sub_types(sub, sup, locations, category) { - if let TyKind::Opaque(..) = sup.sty { + if let ty::Opaque(..) = sup.sty { // When you have `let x: impl Foo = ...` in a closure, // the resulting inferend values are stored with the // def-id of the base function. @@ -1161,7 +1163,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { &mut self, a: Ty<'tcx>, v: ty::Variance, - user_ty: &UserTypeProjection<'tcx>, + user_ty: &UserTypeProjection, locations: Locations, category: ConstraintCategory, ) -> Fallible<()> { @@ -1185,7 +1187,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { debug!("user_ty base: {:?} freshened: {:?} projs: {:?} yields: {:?}", user_ty.base, annotated_type, user_ty.projs, curr_projected_ty); - let ty = curr_projected_ty.to_ty(tcx); + let ty = curr_projected_ty.ty; self.relate_types(a, v, ty, locations, category)?; Ok(()) @@ -1333,7 +1335,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { _ => ConstraintCategory::Assignment, }; - let place_ty = place.ty(mir, tcx).to_ty(tcx); + let place_ty = place.ty(mir, tcx).ty; let rv_ty = rv.ty(mir, tcx); if let Err(terr) = self.sub_types_or_anon(rv_ty, place_ty, location.to_locations(), category) @@ -1385,9 +1387,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { ref place, variant_index, } => { - let place_type = place.ty(mir, tcx).to_ty(tcx); + let place_type = place.ty(mir, tcx).ty; let adt = match place_type.sty { - TyKind::Adt(adt, _) if adt.is_enum() => adt, + ty::Adt(adt, _) if adt.is_enum() => adt, _ => { span_bug!( stmt.source_info.span, @@ -1407,7 +1409,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { }; } StatementKind::AscribeUserType(ref place, variance, box ref projection) => { - let place_ty = place.ty(mir, tcx).to_ty(tcx); + let place_ty = place.ty(mir, tcx).ty; if let Err(terr) = self.relate_type_and_user_type( place_ty, variance, @@ -1463,7 +1465,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { target: _, unwind: _, } => { - let place_ty = location.ty(mir, tcx).to_ty(tcx); + let place_ty = location.ty(mir, tcx).ty; let rv_ty = value.ty(mir, tcx); let locations = term_location.to_locations(); @@ -1611,7 +1613,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { let tcx = self.tcx(); match *destination { Some((ref dest, _target_block)) => { - let dest_ty = dest.ty(mir, tcx).to_ty(tcx); + let dest_ty = dest.ty(mir, tcx).ty; let category = match *dest { Place::Base(PlaceBase::Local(RETURN_PLACE)) => { if let Some(BorrowCheckContext { @@ -2370,7 +2372,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { match *elem { ProjectionElem::Deref => { let tcx = self.infcx.tcx; - let base_ty = base.ty(mir, tcx).to_ty(tcx); + let base_ty = base.ty(mir, tcx).ty; debug!("add_reborrow_constraint - base_ty = {:?}", base_ty); match base_ty.sty { diff --git a/src/librustc_mir/borrow_check/place_ext.rs b/src/librustc_mir/borrow_check/place_ext.rs index 6bc56ab721f..8269b7b95f4 100644 --- a/src/librustc_mir/borrow_check/place_ext.rs +++ b/src/librustc_mir/borrow_check/place_ext.rs @@ -63,7 +63,7 @@ impl<'tcx> PlaceExt<'tcx> for Place<'tcx> { tcx, mir, locals_state_at_exit), ProjectionElem::Deref => { - let ty = proj.base.ty(mir, tcx).to_ty(tcx); + let ty = proj.base.ty(mir, tcx).ty; match ty.sty { // For both derefs of raw pointers and `&T` // references, the original path is `Copy` and diff --git a/src/librustc_mir/borrow_check/places_conflict.rs b/src/librustc_mir/borrow_check/places_conflict.rs index 52119d6b19b..fbe8b8485dd 100644 --- a/src/librustc_mir/borrow_check/places_conflict.rs +++ b/src/librustc_mir/borrow_check/places_conflict.rs @@ -191,7 +191,7 @@ fn place_components_conflict<'gcx, 'tcx>( Place::Projection(box Projection { base, elem }) => (base, elem), _ => bug!("place has no base?"), }; - let base_ty = base.ty(mir, tcx).to_ty(tcx); + let base_ty = base.ty(mir, tcx).ty; match (elem, &base_ty.sty, access) { (_, _, Shallow(Some(ArtificialField::ArrayLength))) @@ -427,7 +427,7 @@ fn place_element_conflict<'a, 'gcx: 'tcx, 'tcx>( debug!("place_element_conflict: DISJOINT-OR-EQ-FIELD"); Overlap::EqualOrDisjoint } else { - let ty = pi1.base.ty(mir, tcx).to_ty(tcx); + let ty = pi1.base.ty(mir, tcx).ty; match ty.sty { ty::Adt(def, _) if def.is_union() => { // Different fields of a union, we are basically stuck. diff --git a/src/librustc_mir/borrow_check/prefixes.rs b/src/librustc_mir/borrow_check/prefixes.rs index e70c9e81ebd..866f1cf994e 100644 --- a/src/librustc_mir/borrow_check/prefixes.rs +++ b/src/librustc_mir/borrow_check/prefixes.rs @@ -139,7 +139,7 @@ impl<'cx, 'gcx, 'tcx> Iterator for Prefixes<'cx, 'gcx, 'tcx> { // derefs, except we stop at the deref of a shared // reference. - let ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx); + let ty = proj.base.ty(self.mir, self.tcx).ty; match ty.sty { ty::RawPtr(_) | ty::Ref( diff --git a/src/librustc_mir/build/block.rs b/src/librustc_mir/build/block.rs index cba5039122a..7469aceee3a 100644 --- a/src/librustc_mir/build/block.rs +++ b/src/librustc_mir/build/block.rs @@ -163,7 +163,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // Then, the block may have an optional trailing expression which is a “return” value // of the block, which is stored into `destination`. let tcx = this.hir.tcx(); - let destination_ty = destination.ty(&this.local_decls, tcx).to_ty(tcx); + let destination_ty = destination.ty(&this.local_decls, tcx).ty; if let Some(expr) = expr { let tail_result_is_ignored = destination_ty.is_unit() || this.block_context.currently_ignores_tail_results(); diff --git a/src/librustc_mir/build/expr/as_place.rs b/src/librustc_mir/build/expr/as_place.rs index 199d03ac445..f7cf0902013 100644 --- a/src/librustc_mir/build/expr/as_place.rs +++ b/src/librustc_mir/build/expr/as_place.rs @@ -4,7 +4,7 @@ use crate::build::expr::category::Category; use crate::build::ForGuard::{OutsideGuard, RefWithinGuard}; use crate::build::{BlockAnd, BlockAndExtension, Builder}; use crate::hair::*; -use rustc::mir::interpret::EvalErrorKind::BoundsCheck; +use rustc::mir::interpret::InterpError::BoundsCheck; use rustc::mir::*; use rustc::ty::{CanonicalUserTypeAnnotation, Variance}; diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index 84f74484e60..7289dd96edb 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -7,7 +7,7 @@ use crate::build::expr::category::{Category, RvalueFunc}; use crate::build::{BlockAnd, BlockAndExtension, Builder}; use crate::hair::*; use rustc::middle::region; -use rustc::mir::interpret::EvalErrorKind; +use rustc::mir::interpret::InterpError; use rustc::mir::*; use rustc::ty::{self, CanonicalUserTypeAnnotation, Ty, UpvarSubsts}; use syntax_pos::Span; @@ -101,7 +101,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { block, Operand::Move(is_min), false, - EvalErrorKind::OverflowNeg, + InterpError::OverflowNeg, expr_span, ); } @@ -433,7 +433,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let val = result_value.clone().field(val_fld, ty); let of = result_value.field(of_fld, bool_ty); - let err = EvalErrorKind::Overflow(op); + let err = InterpError::Overflow(op); block = self.assert(block, Operand::Move(of), false, err, span); @@ -444,9 +444,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // and 2. there are two possible failure cases, divide-by-zero and overflow. let (zero_err, overflow_err) = if op == BinOp::Div { - (EvalErrorKind::DivisionByZero, EvalErrorKind::Overflow(op)) + (InterpError::DivisionByZero, InterpError::Overflow(op)) } else { - (EvalErrorKind::RemainderByZero, EvalErrorKind::Overflow(op)) + (InterpError::RemainderByZero, InterpError::Overflow(op)) }; // Check for / 0 diff --git a/src/librustc_mir/build/expr/stmt.rs b/src/librustc_mir/build/expr/stmt.rs index 9527a232795..b58914b017f 100644 --- a/src/librustc_mir/build/expr/stmt.rs +++ b/src/librustc_mir/build/expr/stmt.rs @@ -188,11 +188,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { block, Statement { source_info, - kind: StatementKind::InlineAsm { - asm: box asm.clone(), + kind: StatementKind::InlineAsm(box InlineAsm { + asm: asm.clone(), outputs, inputs, - }, + }), }, ); this.block_context.pop(); diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index be3d730c61a..566f1790f8f 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -374,7 +374,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let ty_source_info = self.source_info(user_ty_span); let user_ty = box pat_ascription_ty.user_ty( &mut self.canonical_user_type_annotations, - place.ty(&self.local_decls, self.hir.tcx()).to_ty(self.hir.tcx()), + place.ty(&self.local_decls, self.hir.tcx()).ty, ty_source_info.span, ); self.cfg.push( @@ -575,7 +575,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { pub(super) fn visit_bindings( &mut self, pattern: &Pattern<'tcx>, - pattern_user_ty: UserTypeProjections<'tcx>, + pattern_user_ty: UserTypeProjections, f: &mut impl FnMut( &mut Self, Mutability, @@ -584,7 +584,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { HirId, Span, Ty<'tcx>, - UserTypeProjections<'tcx>, + UserTypeProjections, ), ) { debug!("visit_bindings: pattern={:?} pattern_user_ty={:?}", pattern, pattern_user_ty); @@ -1293,7 +1293,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { debug!("add_fake_borrows all_fake_borrows = {:?}", all_fake_borrows); all_fake_borrows.into_iter().map(|matched_place| { - let fake_borrow_deref_ty = matched_place.ty(&self.local_decls, tcx).to_ty(tcx); + let fake_borrow_deref_ty = matched_place.ty(&self.local_decls, tcx).ty; let fake_borrow_ty = tcx.mk_imm_ref(tcx.types.re_erased, fake_borrow_deref_ty); let fake_borrow_temp = self.local_decls.push( LocalDecl::new_temp(fake_borrow_ty, temp_span) @@ -1587,7 +1587,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let user_ty = box ascription.user_ty.clone().user_ty( &mut self.canonical_user_type_annotations, - ascription.source.ty(&self.local_decls, self.hir.tcx()).to_ty(self.hir.tcx()), + ascription.source.ty(&self.local_decls, self.hir.tcx()).ty, source_info.span ); self.cfg.push( @@ -1701,7 +1701,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { mode: BindingMode, var_id: HirId, var_ty: Ty<'tcx>, - user_ty: UserTypeProjections<'tcx>, + user_ty: UserTypeProjections, has_guard: ArmHasGuard, opt_match_place: Option<(Option<Place<'tcx>>, Span)>, pat_span: Span, diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index 0c93984fda8..b0602219610 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -693,7 +693,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // So, if we have a match-pattern like `x @ Enum::Variant(P1, P2)`, // we want to create a set of derived match-patterns like // `(x as Variant).0 @ P1` and `(x as Variant).1 @ P1`. - let elem = ProjectionElem::Downcast(adt_def, variant_index); + let elem = ProjectionElem::Downcast( + Some(adt_def.variants[variant_index].ident.name), variant_index); let downcast_place = match_pair.place.elem(elem); // `(x as Variant)` let consequent_match_pairs = subpatterns.iter() diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs index d76d3765ac7..d71a13dec5a 100644 --- a/src/librustc_mir/build/misc.rs +++ b/src/librustc_mir/build/misc.rs @@ -70,7 +70,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { pub fn consume_by_copy_or_move(&self, place: Place<'tcx>) -> Operand<'tcx> { let tcx = self.hir.tcx(); - let ty = place.ty(&self.local_decls, tcx).to_ty(tcx); + let ty = place.ty(&self.local_decls, tcx).ty; if !self.hir.type_is_copy_modulo_regions(ty, DUMMY_SP) { Operand::Move(place) } else { diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index 2268568c5f8..4c8ab361e04 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -23,7 +23,7 @@ use syntax::source_map::{Span, DUMMY_SP}; use crate::interpret::{self, PlaceTy, MPlaceTy, MemPlace, OpTy, ImmTy, Immediate, Scalar, Pointer, RawConst, ConstValue, - EvalResult, EvalError, EvalErrorKind, GlobalId, InterpretCx, StackPopCleanup, + EvalResult, EvalError, InterpError, GlobalId, InterpretCx, StackPopCleanup, Allocation, AllocId, MemoryKind, snapshot, RefTracking, }; @@ -173,7 +173,7 @@ fn eval_body_using_ecx<'mir, 'tcx>( impl<'tcx> Into<EvalError<'tcx>> for ConstEvalError { fn into(self) -> EvalError<'tcx> { - EvalErrorKind::MachineError(self.to_string()).into() + InterpError::MachineError(self.to_string()).into() } } @@ -351,7 +351,7 @@ impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx> Ok(Some(match ecx.load_mir(instance.def) { Ok(mir) => mir, Err(err) => { - if let EvalErrorKind::NoMirFor(ref path) = err.kind { + if let InterpError::NoMirFor(ref path) = err.kind { return Err( ConstEvalError::NeedsRfc(format!("calling extern function `{}`", path)) .into(), @@ -615,22 +615,9 @@ pub fn const_eval_raw_provider<'a, 'tcx>( let cid = key.value; let def_id = cid.instance.def.def_id(); - if let Some(id) = tcx.hir().as_local_hir_id(def_id) { - let tables = tcx.typeck_tables_of(def_id); - - // Do match-check before building MIR - // FIXME(#59378) check_match may have errored but we're not checking for that anymore - tcx.check_match(def_id); - - if let hir::BodyOwnerKind::Const = tcx.hir().body_owner_kind_by_hir_id(id) { - tcx.mir_const_qualif(def_id); - } - - // Do not continue into miri if typeck errors occurred; it will fail horribly - if tables.tainted_by_errors { - return Err(ErrorHandled::Reported) - } - }; + if def_id.is_local() && tcx.typeck_tables_of(def_id).tainted_by_errors { + return Err(ErrorHandled::Reported); + } let (res, ecx) = eval_body_and_ecx(tcx, cid, None, key.param_env); res.and_then(|place| { @@ -679,7 +666,7 @@ pub fn const_eval_raw_provider<'a, 'tcx>( // any other kind of error will be reported to the user as a deny-by-default lint _ => if let Some(p) = cid.promoted { let span = tcx.optimized_mir(def_id).promoted[p].span; - if let EvalErrorKind::ReferencedConstant = err.error { + if let InterpError::ReferencedConstant = err.error { err.report_as_error( tcx.at(span), "evaluation of constant expression failed", diff --git a/src/librustc_mir/dataflow/drop_flag_effects.rs b/src/librustc_mir/dataflow/drop_flag_effects.rs index f78c82a9302..aae4590a387 100644 --- a/src/librustc_mir/dataflow/drop_flag_effects.rs +++ b/src/librustc_mir/dataflow/drop_flag_effects.rs @@ -49,7 +49,7 @@ pub fn move_path_children_matching<'tcx, F>(move_data: &MoveData<'tcx>, fn place_contents_drop_state_cannot_differ<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, mir: &Mir<'tcx>, place: &mir::Place<'tcx>) -> bool { - let ty = place.ty(mir, tcx).to_ty(tcx); + let ty = place.ty(mir, tcx).ty; match ty.sty { ty::Array(..) => { debug!("place_contents_drop_state_cannot_differ place: {:?} ty: {:?} => false", @@ -141,7 +141,7 @@ pub(crate) fn on_all_drop_children_bits<'a, 'gcx, 'tcx, F>( { on_all_children_bits(tcx, mir, &ctxt.move_data, path, |child| { let place = &ctxt.move_data.move_paths[path].place; - let ty = place.ty(mir, tcx).to_ty(tcx); + let ty = place.ty(mir, tcx).ty; debug!("on_all_drop_children_bits({:?}, {:?} : {:?})", path, place, ty); let gcx = tcx.global_tcx(); diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs index b47aff3a4f8..43cb0ed4565 100644 --- a/src/librustc_mir/dataflow/impls/borrows.rs +++ b/src/librustc_mir/dataflow/impls/borrows.rs @@ -10,13 +10,18 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use crate::dataflow::{BitDenotation, BlockSets, InitialFlow}; -pub use crate::dataflow::indexes::BorrowIndex; use crate::borrow_check::nll::region_infer::RegionInferenceContext; use crate::borrow_check::nll::ToRegionVid; use crate::borrow_check::places_conflict; use std::rc::Rc; +newtype_index! { + pub struct BorrowIndex { + DEBUG_FORMAT = "bw{}" + } +} + /// `Borrows` stores the data used in the analyses that track the flow /// of borrows. /// @@ -288,8 +293,8 @@ impl<'a, 'gcx, 'tcx> BitDenotation<'tcx> for Borrows<'a, 'gcx, 'tcx> { self.kill_borrows_on_place(sets, &Place::Base(PlaceBase::Local(local))); } - mir::StatementKind::InlineAsm { ref outputs, ref asm, .. } => { - for (output, kind) in outputs.iter().zip(&asm.outputs) { + mir::StatementKind::InlineAsm(ref asm) => { + for (output, kind) in asm.outputs.iter().zip(&asm.asm.outputs) { if !kind.is_indirect && !kind.is_rw { self.kill_borrows_on_place(sets, output); } diff --git a/src/librustc_mir/dataflow/mod.rs b/src/librustc_mir/dataflow/mod.rs index af0e3f5a270..83221aca6c5 100644 --- a/src/librustc_mir/dataflow/mod.rs +++ b/src/librustc_mir/dataflow/mod.rs @@ -33,7 +33,12 @@ mod graphviz; mod impls; pub mod move_paths; -pub(crate) use self::move_paths::indexes; +pub(crate) mod indexes { + pub(crate) use super::{ + move_paths::{MovePathIndex, MoveOutIndex, InitIndex}, + impls::borrows::BorrowIndex, + }; +} pub(crate) struct DataflowBuilder<'a, 'tcx: 'a, BD> where diff --git a/src/librustc_mir/dataflow/move_paths/abs_domain.rs b/src/librustc_mir/dataflow/move_paths/abs_domain.rs index 6dcc0325ec1..b26547c4ff7 100644 --- a/src/librustc_mir/dataflow/move_paths/abs_domain.rs +++ b/src/librustc_mir/dataflow/move_paths/abs_domain.rs @@ -18,8 +18,7 @@ use rustc::ty::Ty; pub struct AbstractOperand; #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub struct AbstractType; -pub type AbstractElem<'tcx> = - ProjectionElem<'tcx, AbstractOperand, AbstractType>; +pub type AbstractElem = ProjectionElem<AbstractOperand, AbstractType>; pub trait Lift { type Abstract; @@ -38,7 +37,7 @@ impl<'tcx> Lift for Ty<'tcx> { fn lift(&self) -> Self::Abstract { AbstractType } } impl<'tcx> Lift for PlaceElem<'tcx> { - type Abstract = AbstractElem<'tcx>; + type Abstract = AbstractElem; fn lift(&self) -> Self::Abstract { match *self { ProjectionElem::Deref => @@ -56,7 +55,7 @@ impl<'tcx> Lift for PlaceElem<'tcx> { from_end, }, ProjectionElem::Downcast(a, u) => - ProjectionElem::Downcast(a.clone(), u.clone()), + ProjectionElem::Downcast(a, u.clone()), } } } diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs index 71805fd02b8..2471c01e3f3 100644 --- a/src/librustc_mir/dataflow/move_paths/builder.rs +++ b/src/librustc_mir/dataflow/move_paths/builder.rs @@ -120,7 +120,7 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> { let base = self.move_path_for(&proj.base)?; let mir = self.builder.mir; let tcx = self.builder.tcx; - let place_ty = proj.base.ty(mir, tcx).to_ty(tcx); + let place_ty = proj.base.ty(mir, tcx).ty; match place_ty.sty { ty::Ref(..) | ty::RawPtr(..) => return Err(MoveError::cannot_move_out_of( @@ -272,13 +272,13 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> { StatementKind::FakeRead(_, ref place) => { self.create_move_path(place); } - StatementKind::InlineAsm { ref outputs, ref inputs, ref asm } => { - for (output, kind) in outputs.iter().zip(&asm.outputs) { + StatementKind::InlineAsm(ref asm) => { + for (output, kind) in asm.outputs.iter().zip(&asm.asm.outputs) { if !kind.is_indirect { self.gather_init(output, InitKind::Deep); } } - for (_, input) in inputs.iter() { + for (_, input) in asm.inputs.iter() { self.gather_operand(input); } } @@ -424,8 +424,8 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> { Place::Projection(box Projection { base, elem: ProjectionElem::Field(_, _), - }) if match base.ty(self.builder.mir, self.builder.tcx).to_ty(self.builder.tcx).sty { - ty::TyKind::Adt(def, _) if def.is_union() => true, + }) if match base.ty(self.builder.mir, self.builder.tcx).ty.sty { + ty::Adt(def, _) if def.is_union() => true, _ => false, } => base, // Otherwise, lookup the place. diff --git a/src/librustc_mir/dataflow/move_paths/mod.rs b/src/librustc_mir/dataflow/move_paths/mod.rs index 7eef68e5f80..8810be9326b 100644 --- a/src/librustc_mir/dataflow/move_paths/mod.rs +++ b/src/librustc_mir/dataflow/move_paths/mod.rs @@ -1,7 +1,7 @@ use rustc::ty::{self, TyCtxt}; use rustc::mir::*; use rustc::util::nodemap::FxHashMap; -use rustc_data_structures::indexed_vec::{IndexVec}; +use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use smallvec::SmallVec; use syntax_pos::{Span}; @@ -12,66 +12,23 @@ use self::abs_domain::{AbstractElem, Lift}; mod abs_domain; -// This submodule holds some newtype'd Index wrappers that are using -// NonZero to ensure that Option<Index> occupies only a single word. -// They are in a submodule to impose privacy restrictions; namely, to -// ensure that other code does not accidentally access `index.0` -// (which is likely to yield a subtle off-by-one error). -pub(crate) mod indexes { - use std::fmt; - use std::num::NonZeroUsize; - use rustc_data_structures::indexed_vec::Idx; - - macro_rules! new_index { - ($(#[$attrs:meta])* $Index:ident, $debug_name:expr) => { - #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] - pub struct $Index(NonZeroUsize); - - impl Idx for $Index { - fn new(idx: usize) -> Self { - $Index(NonZeroUsize::new(idx + 1).unwrap()) - } - fn index(self) -> usize { - self.0.get() - 1 - } - } - - impl fmt::Debug for $Index { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(fmt, "{}{}", $debug_name, self.index()) - } - } - } +newtype_index! { + pub struct MovePathIndex { + DEBUG_FORMAT = "mp{}" } +} - new_index!( - /// Index into MovePathData.move_paths - MovePathIndex, - "mp" - ); - - new_index!( - /// Index into MoveData.moves. - MoveOutIndex, - "mo" - ); - - new_index!( - /// Index into MoveData.inits. - InitIndex, - "in" - ); - - new_index!( - /// Index into Borrows.locations - BorrowIndex, - "bw" - ); +newtype_index! { + pub struct MoveOutIndex { + DEBUG_FORMAT = "mo{}" + } } -pub use self::indexes::MovePathIndex; -pub use self::indexes::MoveOutIndex; -pub use self::indexes::InitIndex; +newtype_index! { + pub struct InitIndex { + DEBUG_FORMAT = "in{}" + } +} impl MoveOutIndex { pub fn move_path_index(&self, move_data: &MoveData<'_>) -> MovePathIndex { @@ -148,7 +105,7 @@ pub struct MoveData<'tcx> { /// particular path being moved.) pub loc_map: LocationMap<SmallVec<[MoveOutIndex; 4]>>, pub path_map: IndexVec<MovePathIndex, SmallVec<[MoveOutIndex; 4]>>, - pub rev_lookup: MovePathLookup<'tcx>, + pub rev_lookup: MovePathLookup, pub inits: IndexVec<InitIndex, Init>, /// Each Location `l` is mapped to the Inits that are effects /// of executing the code at `l`. @@ -258,7 +215,7 @@ impl Init { /// Tables mapping from a place to its MovePathIndex. #[derive(Debug)] -pub struct MovePathLookup<'tcx> { +pub struct MovePathLookup { locals: IndexVec<Local, MovePathIndex>, /// projections are made from a base-place and a projection @@ -267,7 +224,7 @@ pub struct MovePathLookup<'tcx> { /// subsequent search so that it is solely relative to that /// base-place). For the remaining lookup, we map the projection /// elem to the associated MovePathIndex. - projections: FxHashMap<(MovePathIndex, AbstractElem<'tcx>), MovePathIndex> + projections: FxHashMap<(MovePathIndex, AbstractElem), MovePathIndex> } mod builder; @@ -278,7 +235,7 @@ pub enum LookupResult { Parent(Option<MovePathIndex>) } -impl<'tcx> MovePathLookup<'tcx> { +impl MovePathLookup { // Unlike the builder `fn move_path_for` below, this lookup // alternative will *not* create a MovePath on the fly for an // unknown place, but will rather return the nearest available diff --git a/src/librustc_mir/diagnostics.rs b/src/librustc_mir/diagnostics.rs index e1b66312da2..c8836fe5193 100644 --- a/src/librustc_mir/diagnostics.rs +++ b/src/librustc_mir/diagnostics.rs @@ -2307,10 +2307,10 @@ let q = *p; ``` Here, the expression `&foo()` is borrowing the expression -`foo()`. As `foo()` is call to a function, and not the name of +`foo()`. As `foo()` is a call to a function, and not the name of a variable, this creates a **temporary** -- that temporary stores the return value from `foo()` so that it can be borrowed. -So you might imagine that `let p = bar(&foo())` is equivalent +You could imagine that `let p = bar(&foo());` is equivalent to this: ```compile_fail,E0597 diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index 303ffcb3bfb..a9c521f59a9 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -1754,7 +1754,7 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>( // they should be pointing to memory is when they are subslices of nonzero // slices let (opt_ptr, n, ty) = match value.ty.sty { - ty::TyKind::Array(t, n) => { + ty::Array(t, n) => { match value.val { ConstValue::ByRef(ptr, alloc) => ( Some((ptr, alloc)), @@ -1767,7 +1767,7 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>( ), } }, - ty::TyKind::Slice(t) => { + ty::Slice(t) => { match value.val { ConstValue::Slice(ptr, n) => ( ptr.to_ptr().ok().map(|ptr| ( diff --git a/src/librustc_mir/hair/pattern/check_match.rs b/src/librustc_mir/hair/pattern/check_match.rs index 50df676aea9..7ded973701e 100644 --- a/src/librustc_mir/hair/pattern/check_match.rs +++ b/src/librustc_mir/hair/pattern/check_match.rs @@ -10,7 +10,7 @@ use rustc::middle::expr_use_visitor as euv; use rustc::middle::mem_categorization::cmt_; use rustc::middle::region; use rustc::session::Session; -use rustc::ty::{self, Ty, TyCtxt, TyKind}; +use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::subst::{InternalSubsts, SubstsRef}; use rustc::lint; use rustc_errors::{Applicability, DiagnosticBuilder}; @@ -481,7 +481,7 @@ fn check_exhaustive<'p, 'a: 'p, 'tcx: 'a>( } let patterns = witnesses.iter().map(|p| (**p).clone()).collect::<Vec<Pattern<'_>>>(); if patterns.len() < 4 { - for sp in maybe_point_at_variant(cx, &scrut_ty.sty, patterns.as_slice()) { + for sp in maybe_point_at_variant(cx, scrut_ty, patterns.as_slice()) { err.span_label(sp, "not covered"); } } @@ -498,11 +498,11 @@ fn check_exhaustive<'p, 'a: 'p, 'tcx: 'a>( fn maybe_point_at_variant( cx: &mut MatchCheckCtxt<'a, 'tcx>, - sty: &TyKind<'tcx>, + ty: Ty<'tcx>, patterns: &[Pattern<'_>], ) -> Vec<Span> { let mut covered = vec![]; - if let ty::Adt(def, _) = sty { + if let ty::Adt(def, _) = ty.sty { // Don't point at variants that have already been covered due to other patterns to avoid // visual clutter for pattern in patterns { @@ -518,7 +518,7 @@ fn maybe_point_at_variant( .map(|field_pattern| field_pattern.pattern.clone()) .collect::<Vec<_>>(); covered.extend( - maybe_point_at_variant(cx, sty, subpatterns.as_slice()), + maybe_point_at_variant(cx, ty, subpatterns.as_slice()), ); } } @@ -526,7 +526,7 @@ fn maybe_point_at_variant( let subpatterns = subpatterns.iter() .map(|field_pattern| field_pattern.pattern.clone()) .collect::<Vec<_>>(); - covered.extend(maybe_point_at_variant(cx, sty, subpatterns.as_slice())); + covered.extend(maybe_point_at_variant(cx, ty, subpatterns.as_slice())); } } } diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index 622cf00ed86..fc12443c092 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -74,7 +74,7 @@ impl<'tcx> PatternTypeProjection<'tcx> { annotations: &mut CanonicalUserTypeAnnotations<'tcx>, inferred_ty: Ty<'tcx>, span: Span, - ) -> UserTypeProjection<'tcx> { + ) -> UserTypeProjection { UserTypeProjection { base: annotations.push(CanonicalUserTypeAnnotation { span, @@ -1094,7 +1094,7 @@ CloneImpls!{ <'tcx> Span, Field, Mutability, ast::Name, hir::HirId, usize, ty::Const<'tcx>, Region<'tcx>, Ty<'tcx>, BindingMode, &'tcx AdtDef, SubstsRef<'tcx>, &'tcx Kind<'tcx>, UserType<'tcx>, - UserTypeProjection<'tcx>, PatternTypeProjection<'tcx> + UserTypeProjection, PatternTypeProjection<'tcx> } impl<'tcx> PatternFoldable<'tcx> for FieldPattern<'tcx> { diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs index fe719bff250..5056d79bec4 100644 --- a/src/librustc_mir/interpret/cast.rs +++ b/src/librustc_mir/interpret/cast.rs @@ -4,7 +4,7 @@ use syntax::ast::{FloatTy, IntTy, UintTy}; use rustc_apfloat::ieee::{Single, Double}; use rustc::mir::interpret::{ - Scalar, EvalResult, Pointer, PointerArithmetic, EvalErrorKind, truncate + Scalar, EvalResult, Pointer, PointerArithmetic, InterpError, truncate }; use rustc::mir::CastKind; use rustc_apfloat::Float; @@ -85,7 +85,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> self.param_env, def_id, substs, - ).ok_or_else(|| EvalErrorKind::TooGeneric.into()); + ).ok_or_else(|| InterpError::TooGeneric.into()); let fn_ptr = self.memory.create_fn_alloc(instance?).with_default_tag(); self.write_scalar(Scalar::Ptr(fn_ptr.into()), dest)?; } diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 8b7e28c3de0..32f7ecd97b2 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -16,7 +16,7 @@ use rustc_data_structures::indexed_vec::IndexVec; use rustc::mir::interpret::{ ErrorHandled, GlobalId, Scalar, FrameInfo, AllocId, - EvalResult, EvalErrorKind, + EvalResult, InterpError, truncate, sign_extend, }; use rustc_data_structures::fx::FxHashMap; @@ -108,34 +108,51 @@ pub enum StackPopCleanup { /// State of a local variable including a memoized layout #[derive(Clone, PartialEq, Eq)] pub struct LocalState<'tcx, Tag=(), Id=AllocId> { - pub state: LocalValue<Tag, Id>, + pub value: LocalValue<Tag, Id>, /// Don't modify if `Some`, this is only used to prevent computing the layout twice pub layout: Cell<Option<TyLayout<'tcx>>>, } -/// State of a local variable -#[derive(Copy, Clone, PartialEq, Eq, Hash)] +/// Current value of a local variable +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub enum LocalValue<Tag=(), Id=AllocId> { + /// This local is not currently alive, and cannot be used at all. Dead, - // Mostly for convenience, we re-use the `Operand` type here. - // This is an optimization over just always having a pointer here; - // we can thus avoid doing an allocation when the local just stores - // immediate values *and* never has its address taken. + /// This local is alive but not yet initialized. It can be written to + /// but not read from or its address taken. Locals get initialized on + /// first write because for unsized locals, we do not know their size + /// before that. + Uninitialized, + /// A normal, live local. + /// Mostly for convenience, we re-use the `Operand` type here. + /// This is an optimization over just always having a pointer here; + /// we can thus avoid doing an allocation when the local just stores + /// immediate values *and* never has its address taken. Live(Operand<Tag, Id>), } -impl<'tcx, Tag> LocalState<'tcx, Tag> { - pub fn access(&self) -> EvalResult<'tcx, &Operand<Tag>> { - match self.state { +impl<'tcx, Tag: Copy + 'static> LocalState<'tcx, Tag> { + pub fn access(&self) -> EvalResult<'tcx, Operand<Tag>> { + match self.value { LocalValue::Dead => err!(DeadLocal), - LocalValue::Live(ref val) => Ok(val), + LocalValue::Uninitialized => + bug!("The type checker should prevent reading from a never-written local"), + LocalValue::Live(val) => Ok(val), } } - pub fn access_mut(&mut self) -> EvalResult<'tcx, &mut Operand<Tag>> { - match self.state { + /// Overwrite the local. If the local can be overwritten in place, return a reference + /// to do so; otherwise return the `MemPlace` to consult instead. + pub fn access_mut( + &mut self, + ) -> EvalResult<'tcx, Result<&mut LocalValue<Tag>, MemPlace<Tag>>> { + match self.value { LocalValue::Dead => err!(DeadLocal), - LocalValue::Live(ref mut val) => Ok(val), + LocalValue::Live(Operand::Indirect(mplace)) => Ok(Err(mplace)), + ref mut local @ LocalValue::Live(Operand::Immediate(_)) | + ref mut local @ LocalValue::Uninitialized => { + Ok(Ok(local)) + } } } } @@ -167,7 +184,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> LayoutOf #[inline] fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyLayout { self.tcx.layout_of(self.param_env.and(ty)) - .map_err(|layout| EvalErrorKind::Layout(layout).into()) + .map_err(|layout| InterpError::Layout(layout).into()) } } @@ -255,7 +272,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tc self.param_env, def_id, substs, - ).ok_or_else(|| EvalErrorKind::TooGeneric.into()) + ).ok_or_else(|| InterpError::TooGeneric.into()) } pub fn type_is_sized(&self, ty: Ty<'tcx>) -> bool { @@ -327,6 +344,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tc let local_ty = self.monomorphize_with_substs(local_ty, frame.instance.substs); self.layout_of(local_ty) })?; + // Layouts of locals are requested a lot, so we cache them. frame.locals[local].layout.set(Some(layout)); Ok(layout) } @@ -473,19 +491,15 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tc // don't allocate at all for trivial constants if mir.local_decls.len() > 1 { - // We put some marker immediate into the locals that we later want to initialize. - // This can be anything except for LocalValue::Dead -- because *that* is the - // value we use for things that we know are initially dead. + // Locals are initially uninitialized. let dummy = LocalState { - state: LocalValue::Live(Operand::Immediate(Immediate::Scalar( - ScalarMaybeUndef::Undef, - ))), + value: LocalValue::Uninitialized, layout: Cell::new(None), }; let mut locals = IndexVec::from_elem(dummy, &mir.local_decls); // Return place is handled specially by the `eval_place` functions, and the // entry in `locals` should never be used. Make it dead, to be sure. - locals[mir::RETURN_PLACE].state = LocalValue::Dead; + locals[mir::RETURN_PLACE].value = LocalValue::Dead; // Now mark those locals as dead that we do not want to initialize match self.tcx.describe_def(instance.def_id()) { // statics and constants don't have `Storage*` statements, no need to look for them @@ -498,7 +512,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tc match stmt.kind { StorageLive(local) | StorageDead(local) => { - locals[local].state = LocalValue::Dead; + locals[local].value = LocalValue::Dead; } _ => {} } @@ -506,21 +520,6 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tc } }, } - // Finally, properly initialize all those that still have the dummy value - for (idx, local) in locals.iter_enumerated_mut() { - match local.state { - LocalValue::Live(_) => { - // This needs to be properly initialized. - let ty = self.monomorphize(mir.local_decls[idx].ty)?; - let layout = self.layout_of(ty)?; - local.state = LocalValue::Live(self.uninit_operand(layout)?); - local.layout = Cell::new(Some(layout)); - } - LocalValue::Dead => { - // Nothing to do - } - } - } // done self.frame_mut().locals = locals; } @@ -555,7 +554,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tc } // Deallocate all locals that are backed by an allocation. for local in frame.locals { - self.deallocate_local(local.state)?; + self.deallocate_local(local.value)?; } // Validate the return value. Do this after deallocating so that we catch dangling // references. @@ -603,10 +602,9 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tc assert!(local != mir::RETURN_PLACE, "Cannot make return place live"); trace!("{:?} is now live", local); - let layout = self.layout_of_local(self.frame(), local, None)?; - let init = LocalValue::Live(self.uninit_operand(layout)?); + let local_val = LocalValue::Uninitialized; // StorageLive *always* kills the value that's currently stored - Ok(mem::replace(&mut self.frame_mut().locals[local].state, init)) + Ok(mem::replace(&mut self.frame_mut().locals[local].value, local_val)) } /// Returns the old value of the local. @@ -615,7 +613,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tc assert!(local != mir::RETURN_PLACE, "Cannot make return place dead"); trace!("{:?} is now dead", local); - mem::replace(&mut self.frame_mut().locals[local].state, LocalValue::Dead) + mem::replace(&mut self.frame_mut().locals[local].value, LocalValue::Dead) } pub(super) fn deallocate_local( @@ -647,8 +645,8 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tc // `Memory::get_static_alloc` which has to use `const_eval_raw` to avoid cycles. let val = self.tcx.const_eval_raw(param_env.and(gid)).map_err(|err| { match err { - ErrorHandled::Reported => EvalErrorKind::ReferencedConstant, - ErrorHandled::TooGeneric => EvalErrorKind::TooGeneric, + ErrorHandled::Reported => InterpError::ReferencedConstant, + ErrorHandled::TooGeneric => InterpError::TooGeneric, } })?; self.raw_const_to_mplace(val) @@ -668,31 +666,31 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tc } write!(msg, ":").unwrap(); - match self.stack[frame].locals[local].access() { - Err(err) => { - if let EvalErrorKind::DeadLocal = err.kind { - write!(msg, " is dead").unwrap(); - } else { - panic!("Failed to access local: {:?}", err); - } - } - Ok(Operand::Indirect(mplace)) => { - let (ptr, align) = mplace.to_scalar_ptr_align(); - match ptr { + match self.stack[frame].locals[local].value { + LocalValue::Dead => write!(msg, " is dead").unwrap(), + LocalValue::Uninitialized => write!(msg, " is uninitialized").unwrap(), + LocalValue::Live(Operand::Indirect(mplace)) => { + match mplace.ptr { Scalar::Ptr(ptr) => { - write!(msg, " by align({}) ref:", align.bytes()).unwrap(); + write!(msg, " by align({}){} ref:", + mplace.align.bytes(), + match mplace.meta { + Some(meta) => format!(" meta({:?})", meta), + None => String::new() + } + ).unwrap(); allocs.push(ptr.alloc_id); } ptr => write!(msg, " by integral ref: {:?}", ptr).unwrap(), } } - Ok(Operand::Immediate(Immediate::Scalar(val))) => { + LocalValue::Live(Operand::Immediate(Immediate::Scalar(val))) => { write!(msg, " {:?}", val).unwrap(); if let ScalarMaybeUndef::Scalar(Scalar::Ptr(ptr)) = val { allocs.push(ptr.alloc_id); } } - Ok(Operand::Immediate(Immediate::ScalarPair(val1, val2))) => { + LocalValue::Live(Operand::Immediate(Immediate::ScalarPair(val1, val2))) => { write!(msg, " ({:?}, {:?})", val1, val2).unwrap(); if let ScalarMaybeUndef::Scalar(Scalar::Ptr(ptr)) = val1 { allocs.push(ptr.alloc_id); diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index 99dd654df21..d9721a8cadf 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -7,7 +7,7 @@ use rustc::ty; use rustc::ty::layout::{LayoutOf, Primitive, Size}; use rustc::mir::BinOp; use rustc::mir::interpret::{ - EvalResult, EvalErrorKind, Scalar, + EvalResult, InterpError, Scalar, }; use super::{ @@ -87,7 +87,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> let bits = self.read_scalar(args[0])?.to_bits(layout_of.size)?; let kind = match layout_of.abi { ty::layout::Abi::Scalar(ref scalar) => scalar.value, - _ => Err(::rustc::mir::interpret::EvalErrorKind::TypeNotPrimitive(ty))?, + _ => Err(::rustc::mir::interpret::InterpError::TypeNotPrimitive(ty))?, }; let out_val = if intrinsic_name.ends_with("_nonzero") { if bits == 0 { @@ -248,7 +248,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> let file = Symbol::intern(self.read_str(file_place)?); let line = self.read_scalar(line.into())?.to_u32()?; let col = self.read_scalar(col.into())?.to_u32()?; - return Err(EvalErrorKind::Panic { msg, file, line, col }.into()); + return Err(InterpError::Panic { msg, file, line, col }.into()); } else if Some(def_id) == self.tcx.lang_items().begin_panic_fn() { assert!(args.len() == 2); // &'static str, &(&'static str, u32, u32) @@ -266,7 +266,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> let file = Symbol::intern(self.read_str(file_place)?); let line = self.read_scalar(line.into())?.to_u32()?; let col = self.read_scalar(col.into())?.to_u32()?; - return Err(EvalErrorKind::Panic { msg, file, line, col }.into()); + return Err(InterpError::Panic { msg, file, line, col }.into()); } else { return Ok(false); } diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index 6ea200d4e4f..e5d8341dfcf 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -19,7 +19,7 @@ use syntax::ast::Mutability; use super::{ Pointer, AllocId, Allocation, GlobalId, AllocationExtra, - EvalResult, Scalar, EvalErrorKind, AllocKind, PointerArithmetic, + EvalResult, Scalar, InterpError, AllocKind, PointerArithmetic, Machine, AllocMap, MayLeak, ErrorHandled, InboundsCheck, }; @@ -344,8 +344,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { // no need to report anything, the const_eval call takes care of that for statics assert!(tcx.is_static(def_id).is_some()); match err { - ErrorHandled::Reported => EvalErrorKind::ReferencedConstant.into(), - ErrorHandled::TooGeneric => EvalErrorKind::TooGeneric.into(), + ErrorHandled::Reported => InterpError::ReferencedConstant.into(), + ErrorHandled::TooGeneric => InterpError::TooGeneric.into(), } }).map(|raw_const| { let allocation = tcx.alloc_map.lock().unwrap_memory(raw_const.alloc_id); @@ -458,7 +458,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { trace!("reading fn ptr: {}", ptr.alloc_id); match self.tcx.alloc_map.lock().get(ptr.alloc_id) { Some(AllocKind::Function(instance)) => Ok(instance), - _ => Err(EvalErrorKind::ExecuteMemory.into()), + _ => Err(InterpError::ExecuteMemory.into()), } } diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 38a9371b927..1ce6d09d7a4 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -9,12 +9,12 @@ use rustc::ty::layout::{self, Size, LayoutOf, TyLayout, HasDataLayout, IntegerEx use rustc::mir::interpret::{ GlobalId, AllocId, InboundsCheck, ConstValue, Pointer, Scalar, - EvalResult, EvalErrorKind, + EvalResult, InterpError, sign_extend, truncate, }; use super::{ InterpretCx, Machine, - MemPlace, MPlaceTy, PlaceTy, Place, MemoryKind, + MemPlace, MPlaceTy, PlaceTy, Place, }; pub use rustc::mir::interpret::ScalarMaybeUndef; @@ -369,37 +369,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> let len = mplace.len(self)?; let bytes = self.memory.read_bytes(mplace.ptr, Size::from_bytes(len as u64))?; let str = ::std::str::from_utf8(bytes) - .map_err(|err| EvalErrorKind::ValidationFailure(err.to_string()))?; + .map_err(|err| InterpError::ValidationFailure(err.to_string()))?; Ok(str) } - pub fn uninit_operand( - &mut self, - layout: TyLayout<'tcx> - ) -> EvalResult<'tcx, Operand<M::PointerTag>> { - // This decides which types we will use the Immediate optimization for, and hence should - // match what `try_read_immediate` and `eval_place_to_op` support. - if layout.is_zst() { - return Ok(Operand::Immediate(Immediate::Scalar(Scalar::zst().into()))); - } - - Ok(match layout.abi { - layout::Abi::Scalar(..) => - Operand::Immediate(Immediate::Scalar(ScalarMaybeUndef::Undef)), - layout::Abi::ScalarPair(..) => - Operand::Immediate(Immediate::ScalarPair( - ScalarMaybeUndef::Undef, - ScalarMaybeUndef::Undef, - )), - _ => { - trace!("Forcing allocation for local of type {:?}", layout.ty); - Operand::Indirect( - *self.allocate(layout, MemoryKind::Stack) - ) - } - }) - } - /// Projection functions pub fn operand_field( &self, @@ -486,8 +459,13 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> layout: Option<TyLayout<'tcx>>, ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> { assert_ne!(local, mir::RETURN_PLACE); - let op = *frame.locals[local].access()?; let layout = self.layout_of_local(frame, local, layout)?; + let op = if layout.is_zst() { + // Do not read from ZST, they might not be initialized + Operand::Immediate(Immediate::Scalar(Scalar::zst().into())) + } else { + frame.locals[local].access()? + }; Ok(OpTy { op, layout }) } @@ -502,7 +480,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> Operand::Indirect(mplace) } Place::Local { frame, local } => - *self.stack[frame].locals[local].access()? + *self.access_local(&self.stack[frame], local, None)? }; Ok(OpTy { op, layout: place.layout }) } @@ -610,18 +588,19 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> ) -> EvalResult<'tcx, (u128, VariantIdx)> { trace!("read_discriminant_value {:#?}", rval.layout); - let discr_kind = match rval.layout.variants { + let (discr_kind, discr_index) = match rval.layout.variants { layout::Variants::Single { index } => { let discr_val = rval.layout.ty.ty_adt_def().map_or( index.as_u32() as u128, |def| def.discriminant_for_variant(*self.tcx, index).val); return Ok((discr_val, index)); } - layout::Variants::Multiple { ref discr_kind, .. } => discr_kind, + layout::Variants::Multiple { ref discr_kind, discr_index, .. } => + (discr_kind, discr_index), }; // read raw discriminant value - let discr_op = self.operand_field(rval, 0)?; + let discr_op = self.operand_field(rval, discr_index as u64)?; let discr_val = self.read_immediate(discr_op)?; let raw_discr = discr_val.to_scalar_or_undef(); trace!("discr value: {:?}", raw_discr); @@ -653,7 +632,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> .expect("tagged layout for non adt") .discriminants(self.tcx.tcx) .find(|(_, var)| var.val == real_discr) - .ok_or_else(|| EvalErrorKind::InvalidDiscriminant(raw_discr.erase_tag()))?; + .ok_or_else(|| InterpError::InvalidDiscriminant(raw_discr.erase_tag()))?; (real_discr, index.0) }, layout::DiscriminantKind::Niche { diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 4d51772d5ea..32ad5274689 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -15,7 +15,7 @@ use rustc::ty::TypeFoldable; use super::{ GlobalId, AllocId, Allocation, Scalar, EvalResult, Pointer, PointerArithmetic, InterpretCx, Machine, AllocMap, AllocationExtra, - RawConst, Immediate, ImmTy, ScalarMaybeUndef, Operand, OpTy, MemoryKind + RawConst, Immediate, ImmTy, ScalarMaybeUndef, Operand, OpTy, MemoryKind, LocalValue }; #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] @@ -558,7 +558,7 @@ where pub fn place_projection( &mut self, base: PlaceTy<'tcx, M::PointerTag>, - proj_elem: &mir::ProjectionElem<'tcx, mir::Local, Ty<'tcx>>, + proj_elem: &mir::ProjectionElem<mir::Local, Ty<'tcx>>, ) -> EvalResult<'tcx, PlaceTy<'tcx, M::PointerTag>> { use rustc::mir::ProjectionElem::*; Ok(match *proj_elem { @@ -639,6 +639,7 @@ where None => return err!(InvalidNullPointerUsage), }, Base(PlaceBase::Local(local)) => PlaceTy { + // This works even for dead/uninitialized locals; we check further when writing place: Place::Local { frame: self.cur_frame(), local, @@ -714,16 +715,19 @@ where // but not factored as a separate function. let mplace = match dest.place { Place::Local { frame, local } => { - match *self.stack[frame].locals[local].access_mut()? { - Operand::Immediate(ref mut dest_val) => { - // Yay, we can just change the local directly. - *dest_val = src; + match self.stack[frame].locals[local].access_mut()? { + Ok(local) => { + // Local can be updated in-place. + *local = LocalValue::Live(Operand::Immediate(src)); return Ok(()); - }, - Operand::Indirect(mplace) => mplace, // already in memory + } + Err(mplace) => { + // The local is in memory, go on below. + mplace + } } }, - Place::Ptr(mplace) => mplace, // already in memory + Place::Ptr(mplace) => mplace, // already referring to memory }; let dest = MPlaceTy { mplace, layout: dest.layout }; @@ -822,8 +826,6 @@ where src: OpTy<'tcx, M::PointerTag>, dest: PlaceTy<'tcx, M::PointerTag>, ) -> EvalResult<'tcx> { - debug_assert!(!src.layout.is_unsized() && !dest.layout.is_unsized(), - "Cannot copy unsized data"); // We do NOT compare the types for equality, because well-typed code can // actually "transmute" `&mut T` to `&T` in an assignment without a cast. assert!(src.layout.details == dest.layout.details, @@ -832,6 +834,7 @@ where // Let us see if the layout is simple so we take a shortcut, avoid force_allocation. let src = match self.try_read_immediate(src)? { Ok(src_val) => { + assert!(!src.layout.is_unsized(), "cannot have unsized immediates"); // Yay, we got a value that we can write directly. // FIXME: Add a check to make sure that if `src` is indirect, // it does not overlap with `dest`. @@ -842,13 +845,19 @@ where // Slow path, this does not fit into an immediate. Just memcpy. trace!("copy_op: {:?} <- {:?}: {}", *dest, src, dest.layout.ty); - let dest = self.force_allocation(dest)?; - let (src_ptr, src_align) = src.to_scalar_ptr_align(); - let (dest_ptr, dest_align) = dest.to_scalar_ptr_align(); + // This interprets `src.meta` with the `dest` local's layout, if an unsized local + // is being initialized! + let (dest, size) = self.force_allocation_maybe_sized(dest, src.meta)?; + let size = size.unwrap_or_else(|| { + assert!(!dest.layout.is_unsized(), + "Cannot copy into already initialized unsized place"); + dest.layout.size + }); + assert_eq!(src.meta, dest.meta, "Can only copy between equally-sized instances"); self.memory.copy( - src_ptr, src_align, - dest_ptr, dest_align, - dest.layout.size, + src.ptr, src.align, + dest.ptr, dest.align, + size, /*nonoverlapping*/ true, )?; @@ -866,11 +875,13 @@ where // Fast path: Just use normal `copy_op` return self.copy_op(src, dest); } - // We still require the sizes to match - debug_assert!(!src.layout.is_unsized() && !dest.layout.is_unsized(), - "Cannot copy unsized data"); + // We still require the sizes to match. assert!(src.layout.size == dest.layout.size, "Size mismatch when transmuting!\nsrc: {:#?}\ndest: {:#?}", src, dest); + // Unsized copies rely on interpreting `src.meta` with `dest.layout`, we want + // to avoid that here. + assert!(!src.layout.is_unsized() && !dest.layout.is_unsized(), + "Cannot transmute unsized data"); // The hard case is `ScalarPair`. `src` is already read from memory in this case, // using `src.layout` to figure out which bytes to use for the 1st and 2nd field. @@ -898,39 +909,70 @@ where /// If the place currently refers to a local that doesn't yet have a matching allocation, /// create such an allocation. /// This is essentially `force_to_memplace`. - pub fn force_allocation( + /// + /// This supports unsized types and returns the computed size to avoid some + /// redundant computation when copying; use `force_allocation` for a simpler, sized-only + /// version. + pub fn force_allocation_maybe_sized( &mut self, place: PlaceTy<'tcx, M::PointerTag>, - ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { - let mplace = match place.place { + meta: Option<Scalar<M::PointerTag>>, + ) -> EvalResult<'tcx, (MPlaceTy<'tcx, M::PointerTag>, Option<Size>)> { + let (mplace, size) = match place.place { Place::Local { frame, local } => { - match *self.stack[frame].locals[local].access()? { - Operand::Indirect(mplace) => mplace, - Operand::Immediate(value) => { + match self.stack[frame].locals[local].access_mut()? { + Ok(local_val) => { // We need to make an allocation. // FIXME: Consider not doing anything for a ZST, and just returning // a fake pointer? Are we even called for ZST? + // We cannot hold on to the reference `local_val` while allocating, + // but we can hold on to the value in there. + let old_val = + if let LocalValue::Live(Operand::Immediate(value)) = *local_val { + Some(value) + } else { + None + }; + // We need the layout of the local. We can NOT use the layout we got, // that might e.g., be an inner field of a struct with `Scalar` layout, // that has different alignment than the outer field. + // We also need to support unsized types, and hence cannot use `allocate`. let local_layout = self.layout_of_local(&self.stack[frame], local, None)?; - let ptr = self.allocate(local_layout, MemoryKind::Stack); - // We don't have to validate as we can assume the local - // was already valid for its type. - self.write_immediate_to_mplace_no_validate(value, ptr)?; - let mplace = ptr.mplace; - // Update the local - *self.stack[frame].locals[local].access_mut()? = - Operand::Indirect(mplace); - mplace + let (size, align) = self.size_and_align_of(meta, local_layout)? + .expect("Cannot allocate for non-dyn-sized type"); + let ptr = self.memory.allocate(size, align, MemoryKind::Stack); + let ptr = M::tag_new_allocation(self, ptr, MemoryKind::Stack); + let mplace = MemPlace { ptr: ptr.into(), align, meta }; + if let Some(value) = old_val { + // Preserve old value. + // We don't have to validate as we can assume the local + // was already valid for its type. + let mplace = MPlaceTy { mplace, layout: local_layout }; + self.write_immediate_to_mplace_no_validate(value, mplace)?; + } + // Now we can call `access_mut` again, asserting it goes well, + // and actually overwrite things. + *self.stack[frame].locals[local].access_mut().unwrap().unwrap() = + LocalValue::Live(Operand::Indirect(mplace)); + (mplace, Some(size)) } + Err(mplace) => (mplace, None), // this already was an indirect local } } - Place::Ptr(mplace) => mplace + Place::Ptr(mplace) => (mplace, None) }; // Return with the original layout, so that the caller can go on - Ok(MPlaceTy { mplace, layout: place.layout }) + Ok((MPlaceTy { mplace, layout: place.layout }, size)) + } + + #[inline(always)] + pub fn force_allocation( + &mut self, + place: PlaceTy<'tcx, M::PointerTag>, + ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { + Ok(self.force_allocation_maybe_sized(place, None)?.0) } pub fn allocate( @@ -938,15 +980,9 @@ where layout: TyLayout<'tcx>, kind: MemoryKind<M::MemoryKinds>, ) -> MPlaceTy<'tcx, M::PointerTag> { - if layout.is_unsized() { - assert!(self.tcx.features().unsized_locals, "cannot alloc memory for unsized type"); - // FIXME: What should we do here? We should definitely also tag! - MPlaceTy::dangling(layout, self) - } else { - let ptr = self.memory.allocate(layout.size, layout.align.abi, kind); - let ptr = M::tag_new_allocation(self, ptr, kind); - MPlaceTy::from_aligned_ptr(ptr, layout) - } + let ptr = self.memory.allocate(layout.size, layout.align.abi, kind); + let ptr = M::tag_new_allocation(self, ptr, kind); + MPlaceTy::from_aligned_ptr(ptr, layout) } pub fn write_discriminant_index( @@ -961,6 +997,7 @@ where layout::Variants::Multiple { discr_kind: layout::DiscriminantKind::Tag, ref discr, + discr_index, .. } => { let adt_def = dest.layout.ty.ty_adt_def().unwrap(); @@ -975,7 +1012,7 @@ where let size = discr.value.size(self); let discr_val = truncate(discr_val, size); - let discr_dest = self.place_field(dest, 0)?; + let discr_dest = self.place_field(dest, discr_index as u64)?; self.write_scalar(Scalar::from_uint(discr_val, size), discr_dest)?; } layout::Variants::Multiple { @@ -984,6 +1021,7 @@ where ref niche_variants, niche_start, }, + discr_index, .. } => { assert!( @@ -991,7 +1029,7 @@ where ); if variant_index != dataful_variant { let niche_dest = - self.place_field(dest, 0)?; + self.place_field(dest, discr_index as u64)?; let niche_value = variant_index.as_u32() - niche_variants.start().as_u32(); let niche_value = (niche_value as u128) .wrapping_add(niche_start); diff --git a/src/librustc_mir/interpret/snapshot.rs b/src/librustc_mir/interpret/snapshot.rs index 8bb663f846b..0bb8b1d9d02 100644 --- a/src/librustc_mir/interpret/snapshot.rs +++ b/src/librustc_mir/interpret/snapshot.rs @@ -12,7 +12,7 @@ use rustc::mir; use rustc::mir::interpret::{ AllocId, Pointer, Scalar, Relocations, Allocation, UndefMask, - EvalResult, EvalErrorKind, + EvalResult, InterpError, }; use rustc::ty::{self, TyCtxt}; @@ -78,7 +78,7 @@ impl<'a, 'mir, 'tcx> InfiniteLoopDetector<'a, 'mir, 'tcx> } // Second cycle - Err(EvalErrorKind::InfiniteLoop.into()) + Err(InterpError::InfiniteLoop.into()) } } @@ -114,10 +114,11 @@ macro_rules! impl_snapshot_for { fn snapshot(&self, __ctx: &'a Ctx) -> Self::Item { match *self { $( - $enum_name::$variant $( ( $(ref $field),* ) )? => + $enum_name::$variant $( ( $(ref $field),* ) )? => { $enum_name::$variant $( - ( $( __impl_snapshot_field!($field, __ctx $(, $delegate)?) ),* ), + ( $( __impl_snapshot_field!($field, __ctx $(, $delegate)?) ),* ) )? + } )* } } @@ -250,11 +251,13 @@ impl_snapshot_for!(enum Operand { impl_stable_hash_for!(enum crate::interpret::LocalValue { Dead, + Uninitialized, Live(x), }); impl_snapshot_for!(enum LocalValue { - Live(v), Dead, + Uninitialized, + Live(v), }); impl<'a, Ctx> Snapshot<'a, Ctx> for Relocations @@ -360,13 +363,13 @@ impl<'a, 'tcx, Ctx> Snapshot<'a, Ctx> for &'a LocalState<'tcx> type Item = LocalValue<(), AllocIdSnapshot<'a>>; fn snapshot(&self, ctx: &'a Ctx) -> Self::Item { - let LocalState { state, layout: _ } = self; - state.snapshot(ctx) + let LocalState { value, layout: _ } = self; + value.snapshot(ctx) } } impl_stable_hash_for!(struct LocalState<'tcx> { - state, + value, layout -> _, }); diff --git a/src/librustc_mir/interpret/terminator.rs b/src/librustc_mir/interpret/terminator.rs index 01965f53c15..ba48a28fc83 100644 --- a/src/librustc_mir/interpret/terminator.rs +++ b/src/librustc_mir/interpret/terminator.rs @@ -5,7 +5,7 @@ use rustc::ty::layout::{self, TyLayout, LayoutOf}; use syntax::source_map::Span; use rustc_target::spec::abi::Abi; -use rustc::mir::interpret::{EvalResult, PointerArithmetic, EvalErrorKind, Scalar}; +use rustc::mir::interpret::{EvalResult, PointerArithmetic, InterpError, Scalar}; use super::{ InterpretCx, Machine, Immediate, OpTy, ImmTy, PlaceTy, MPlaceTy, StackPopCleanup }; @@ -134,7 +134,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> self.goto_block(Some(target))?; } else { // Compute error message - use rustc::mir::interpret::EvalErrorKind::*; + use rustc::mir::interpret::InterpError::*; return match *msg { BoundsCheck { ref len, ref index } => { let len = self.read_immediate(self.eval_operand(len, None)?) @@ -212,7 +212,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> return Ok(()); } let caller_arg = caller_arg.next() - .ok_or_else(|| EvalErrorKind::FunctionArgCountMismatch)?; + .ok_or_else(|| InterpError::FunctionArgCountMismatch)?; if rust_abi { debug_assert!(!caller_arg.layout.is_zst(), "ZSTs must have been already filtered out"); } @@ -315,12 +315,13 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> ); // Figure out how to pass which arguments. - // We have two iterators: Where the arguments come from, - // and where they go to. + // The Rust ABI is special: ZST get skipped. let rust_abi = match caller_abi { Abi::Rust | Abi::RustCall => true, _ => false }; + // We have two iterators: Where the arguments come from, + // and where they go to. // For where they come from: If the ABI is RustCall, we untuple the // last incoming argument. These two iterators do not have the same type, @@ -368,7 +369,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> } // Now we should have no more caller args if caller_iter.next().is_some() { - trace!("Caller has too many args over"); + trace!("Caller has passed too many args"); return err!(FunctionArgCountMismatch); } // Don't forget to check the return type! @@ -406,9 +407,24 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> } // cannot use the shim here, because that will only result in infinite recursion ty::InstanceDef::Virtual(_, idx) => { + let mut args = args.to_vec(); let ptr_size = self.pointer_size(); - let ptr = self.deref_operand(args[0])?; - let vtable = ptr.vtable()?; + // We have to implement all "object safe receivers". Currently we + // support built-in pointers (&, &mut, Box) as well as unsized-self. We do + // not yet support custom self types. + // Also see librustc_codegen_llvm/abi.rs and librustc_codegen_llvm/mir/block.rs. + let receiver_place = match args[0].layout.ty.builtin_deref(true) { + Some(_) => { + // Built-in pointer. + self.deref_operand(args[0])? + } + None => { + // Unsized self. + args[0].to_mem_place() + } + }; + // Find and consult vtable + let vtable = receiver_place.vtable()?; self.memory.check_align(vtable.into(), self.tcx.data_layout.pointer_align.abi)?; let fn_ptr = self.memory.get(vtable.alloc_id)?.read_ptr_sized( self, @@ -416,15 +432,16 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> )?.to_ptr()?; let instance = self.memory.get_fn(fn_ptr)?; - // We have to patch the self argument, in particular get the layout - // expected by the actual function. Cannot just use "field 0" due to - // Box<self>. - let mut args = args.to_vec(); - let pointee = args[0].layout.ty.builtin_deref(true).unwrap().ty; - let fake_fat_ptr_ty = self.tcx.mk_mut_ptr(pointee); - args[0] = OpTy::from(ImmTy { // strip vtable - layout: self.layout_of(fake_fat_ptr_ty)?.field(self, 0)?, - imm: Immediate::Scalar(ptr.ptr.into()) + // `*mut receiver_place.layout.ty` is almost the layout that we + // want for args[0]: We have to project to field 0 because we want + // a thin pointer. + assert!(receiver_place.layout.is_unsized()); + let receiver_ptr_ty = self.tcx.mk_mut_ptr(receiver_place.layout.ty); + let this_receiver_ptr = self.layout_of(receiver_ptr_ty)?.field(self, 0)?; + // Adjust receiver argument. + args[0] = OpTy::from(ImmTy { + layout: this_receiver_ptr, + imm: Immediate::Scalar(receiver_place.ptr.into()) }); trace!("Patched self operand to {:#?}", args[0]); // recurse with concrete function diff --git a/src/librustc_mir/interpret/traits.rs b/src/librustc_mir/interpret/traits.rs index cce6c95a312..a451f2afb46 100644 --- a/src/librustc_mir/interpret/traits.rs +++ b/src/librustc_mir/interpret/traits.rs @@ -1,9 +1,8 @@ -use rustc_data_structures::sync::Lrc; use rustc::ty::{self, Ty}; use rustc::ty::layout::{Size, Align, LayoutOf}; use rustc::mir::interpret::{Scalar, Pointer, EvalResult, PointerArithmetic}; -use super::{InterpretCx, Machine, MemoryKind}; +use super::{InterpretCx, InterpError, Machine, MemoryKind}; impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> { /// Creates a dynamic vtable for the given type and vtable origin. This is used only for @@ -35,7 +34,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> self.tcx.vtable_methods(trait_ref) } else { - Lrc::new(Vec::new()) + &[] }; let layout = self.layout_of(ty)?; @@ -76,7 +75,14 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> for (i, method) in methods.iter().enumerate() { if let Some((def_id, substs)) = *method { - let instance = self.resolve(def_id, substs)?; + // resolve for vtable: insert shims where needed + let substs = self.subst_and_normalize_erasing_regions(substs)?; + let instance = ty::Instance::resolve_for_vtable( + *self.tcx, + self.param_env, + def_id, + substs, + ).ok_or_else(|| InterpError::TooGeneric)?; let fn_ptr = self.memory.create_fn_alloc(instance).with_default_tag(); let method_ptr = vtable.offset(ptr_size * (3 + i as u64), self)?; self.memory diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index 3323ec387bf..d4cf906619d 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -7,7 +7,7 @@ use rustc::ty::layout::{self, Size, Align, TyLayout, LayoutOf, VariantIdx}; use rustc::ty; use rustc_data_structures::fx::FxHashSet; use rustc::mir::interpret::{ - Scalar, AllocKind, EvalResult, EvalErrorKind, + Scalar, AllocKind, EvalResult, InterpError, }; use super::{ @@ -258,11 +258,11 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> match self.walk_value(op) { Ok(()) => Ok(()), Err(err) => match err.kind { - EvalErrorKind::InvalidDiscriminant(val) => + InterpError::InvalidDiscriminant(val) => validation_failure!( val, self.path, "a valid enum discriminant" ), - EvalErrorKind::ReadPointerAsBytes => + InterpError::ReadPointerAsBytes => validation_failure!( "a pointer", self.path, "plain (non-pointer) bytes" ), @@ -355,9 +355,9 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Err(err) => { error!("{:?} is not aligned to {:?}", ptr, align); match err.kind { - EvalErrorKind::InvalidNullPointerUsage => + InterpError::InvalidNullPointerUsage => return validation_failure!("NULL reference", self.path), - EvalErrorKind::AlignmentCheckFailed { required, has } => + InterpError::AlignmentCheckFailed { required, has } => return validation_failure!(format!("unaligned reference \ (required {} byte alignment but found {})", required.bytes(), has.bytes()), self.path), @@ -562,7 +562,7 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Err(err) => { // For some errors we might be able to provide extra information match err.kind { - EvalErrorKind::ReadUndefBytes(offset) => { + InterpError::ReadUndefBytes(offset) => { // Some byte was undefined, determine which // element that byte belongs to so we can // provide an index. diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index c45e694ebf8..deeed9a0b98 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -28,6 +28,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![recursion_limit="256"] #![deny(rust_2018_idioms)] +#![cfg_attr(not(stage0), deny(internal))] #![allow(explicit_outlives_requirements)] #[macro_use] extern crate log; diff --git a/src/librustc_mir/lints.rs b/src/librustc_mir/lints.rs index 6d6a3f91472..572f7133cad 100644 --- a/src/librustc_mir/lints.rs +++ b/src/librustc_mir/lints.rs @@ -4,7 +4,7 @@ use rustc::hir::intravisit::FnKind; use rustc::hir::map::blocks::FnLikeNode; use rustc::lint::builtin::UNCONDITIONAL_RECURSION; use rustc::mir::{self, Mir, TerminatorKind}; -use rustc::ty::{AssociatedItem, AssociatedItemContainer, Instance, TyCtxt, TyKind}; +use rustc::ty::{self, AssociatedItem, AssociatedItemContainer, Instance, TyCtxt}; use rustc::ty::subst::InternalSubsts; pub fn check(tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -86,7 +86,7 @@ fn check_fn_for_unconditional_recursion(tcx: TyCtxt<'a, 'tcx, 'tcx>, TerminatorKind::Call { ref func, .. } => { let func_ty = func.ty(mir, tcx); - if let TyKind::FnDef(fn_def_id, substs) = func_ty.sty { + if let ty::FnDef(fn_def_id, substs) = func_ty.sty { let (call_fn_id, call_substs) = if let Some(instance) = Instance::resolve(tcx, param_env, diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index 45b346b6413..af875c2f9e8 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -625,8 +625,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { } mir::TerminatorKind::Drop { ref location, .. } | mir::TerminatorKind::DropAndReplace { ref location, .. } => { - let ty = location.ty(self.mir, self.tcx) - .to_ty(self.tcx); + let ty = location.ty(self.mir, self.tcx).ty; let ty = tcx.subst_and_normalize_erasing_regions( self.param_substs, ty::ParamEnv::reveal_all(), diff --git a/src/librustc_mir/transform/add_moves_for_packed_drops.rs b/src/librustc_mir/transform/add_moves_for_packed_drops.rs index e8528eee0bc..b6436ec70ee 100644 --- a/src/librustc_mir/transform/add_moves_for_packed_drops.rs +++ b/src/librustc_mir/transform/add_moves_for_packed_drops.rs @@ -106,7 +106,7 @@ fn add_move_for_packed_drop<'a, 'tcx>( }; let source_info = terminator.source_info; - let ty = location.ty(mir, tcx).to_ty(tcx); + let ty = location.ty(mir, tcx).ty; let temp = patch.new_temp(ty, terminator.source_info.span); let storage_dead_block = patch.new_block(BasicBlockData { diff --git a/src/librustc_mir/transform/add_retag.rs b/src/librustc_mir/transform/add_retag.rs index b13a5fd2fd1..a393847fd49 100644 --- a/src/librustc_mir/transform/add_retag.rs +++ b/src/librustc_mir/transform/add_retag.rs @@ -87,7 +87,7 @@ impl MirPass for AddRetag { let needs_retag = |place: &Place<'tcx>| { // FIXME: Instead of giving up for unstable places, we should introduce // a temporary and retag on that. - is_stable(place) && may_have_reference(place.ty(&*local_decls, tcx).to_ty(tcx), tcx) + is_stable(place) && may_have_reference(place.ty(&*local_decls, tcx).ty, tcx) }; // PART 1 @@ -164,7 +164,7 @@ impl MirPass for AddRetag { if src_ty.is_region_ptr() { // The only `Misc` casts on references are those creating raw pointers. assert!(dest_ty.is_unsafe_ptr()); - (RetagKind::Raw, place) + (RetagKind::Raw, place.clone()) } else { // Some other cast, no retag continue @@ -182,7 +182,7 @@ impl MirPass for AddRetag { _ => RetagKind::Default, }; - (kind, place) + (kind, place.clone()) } // Do nothing for the rest _ => continue, @@ -191,7 +191,7 @@ impl MirPass for AddRetag { let source_info = block_data.statements[i].source_info; block_data.statements.insert(i+1, Statement { source_info, - kind: StatementKind::Retag(retag_kind, place.clone()), + kind: StatementKind::Retag(retag_kind, place), }); } } diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index 0e31515e4af..93f3afe1aea 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -227,7 +227,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { } let is_borrow_of_interior_mut = context.is_borrow() && !base .ty(self.mir, self.tcx) - .to_ty(self.tcx) + .ty .is_freeze(self.tcx, self.param_env, self.source_info.span); // prevent // * `&mut x.field` @@ -249,7 +249,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { self.source_info = self.mir.local_decls[local].source_info; } } - let base_ty = base.ty(self.mir, self.tcx).to_ty(self.tcx); + let base_ty = base.ty(self.mir, self.tcx).ty; match base_ty.sty { ty::RawPtr(..) => { self.require_unsafe("dereference of raw pointer", @@ -420,7 +420,7 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { }) = place { match *elem { ProjectionElem::Field(..) => { - let ty = base.ty(&self.mir.local_decls, self.tcx).to_ty(self.tcx); + let ty = base.ty(&self.mir.local_decls, self.tcx).ty; match ty.sty { ty::Adt(def, _) => match self.tcx.layout_scalar_valid_range(def.did) { (Bound::Unbounded, Bound::Unbounded) => {}, diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index b3ef7407a7c..e0ff71cbe52 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -7,7 +7,7 @@ use rustc::mir::{Constant, Location, Place, PlaceBase, Mir, Operand, Rvalue, Loc use rustc::mir::{NullOp, UnOp, StatementKind, Statement, BasicBlock, LocalKind, Static, StaticKind}; use rustc::mir::{TerminatorKind, ClearCrossCrate, SourceInfo, BinOp, ProjectionElem}; use rustc::mir::visit::{Visitor, PlaceContext, MutatingUseContext, NonMutatingUseContext}; -use rustc::mir::interpret::{EvalErrorKind, Scalar, GlobalId, EvalResult}; +use rustc::mir::interpret::{InterpError, Scalar, GlobalId, EvalResult}; use rustc::ty::{TyCtxt, self, Instance}; use syntax::source_map::{Span, DUMMY_SP}; use rustc::ty::subst::InternalSubsts; @@ -144,7 +144,7 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> { Ok(val) => Some(val), Err(error) => { let diagnostic = error_to_const_error(&self.ecx, error); - use rustc::mir::interpret::EvalErrorKind::*; + use rustc::mir::interpret::InterpError::*; match diagnostic.error { // don't report these, they make no sense in a const prop context | MachineError(_) @@ -457,7 +457,7 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> { ) } else { if overflow { - let err = EvalErrorKind::Overflow(op).into(); + let err = InterpError::Overflow(op).into(); let _: Option<()> = self.use_ecx(source_info, |_| Err(err)); return None; } @@ -556,7 +556,7 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> { if let StatementKind::Assign(ref place, ref rval) = statement.kind { let place_ty: ty::Ty<'tcx> = place .ty(&self.mir.local_decls, self.tcx) - .to_ty(self.tcx); + .ty; if let Ok(place_layout) = self.tcx.layout_of(self.param_env.and(place_ty)) { if let Some(value) = self.const_prop(rval, place_layout, statement.source_info) { if let Place::Base(PlaceBase::Local(local)) = *place { @@ -611,7 +611,7 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> { .hir() .as_local_hir_id(self.source.def_id()) .expect("some part of a failing const eval must be local"); - use rustc::mir::interpret::EvalErrorKind::*; + use rustc::mir::interpret::InterpError::*; let msg = match msg { Overflow(_) | OverflowNeg | diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index c4e303eb9aa..e63c1899fe5 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -773,7 +773,7 @@ fn create_generator_resume_function<'a, 'tcx>( let mut cases = create_cases(mir, &transform, |point| Some(point.resume)); - use rustc::mir::interpret::EvalErrorKind::{ + use rustc::mir::interpret::InterpError::{ GeneratorResumedAfterPanic, GeneratorResumedAfterReturn, }; diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 1063381d6aa..027ae70b06a 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -319,8 +319,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { work_list.push(target); // If the location doesn't actually need dropping, treat it like // a regular goto. - let ty = location.ty(callee_mir, tcx).subst(tcx, callsite.substs); - let ty = ty.to_ty(tcx); + let ty = location.ty(callee_mir, tcx).subst(tcx, callsite.substs).ty; if ty.needs_drop(tcx, param_env) { cost += CALL_PENALTY; if let Some(unwind) = unwind { @@ -563,7 +562,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { assert!(args.next().is_none()); let tuple = Place::Base(PlaceBase::Local(tuple)); - let tuple_tys = if let ty::Tuple(s) = tuple.ty(caller_mir, tcx).to_ty(tcx).sty { + let tuple_tys = if let ty::Tuple(s) = tuple.ty(caller_mir, tcx).ty.sty { s } else { bug!("Closure arguments are not passed as a tuple"); diff --git a/src/librustc_mir/transform/instcombine.rs b/src/librustc_mir/transform/instcombine.rs index e0e64fd1f9b..8187a81f0ed 100644 --- a/src/librustc_mir/transform/instcombine.rs +++ b/src/librustc_mir/transform/instcombine.rs @@ -2,7 +2,7 @@ use rustc::mir::{Constant, Location, Place, PlaceBase, Mir, Operand, ProjectionElem, Rvalue, Local}; use rustc::mir::visit::{MutVisitor, Visitor}; -use rustc::ty::{TyCtxt, TyKind}; +use rustc::ty::{self, TyCtxt}; use rustc::util::nodemap::{FxHashMap, FxHashSet}; use rustc_data_structures::indexed_vec::Idx; use std::mem; @@ -82,15 +82,15 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for OptimizationFinder<'b, 'a, 'tcx> { fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { if let Rvalue::Ref(_, _, Place::Projection(ref projection)) = *rvalue { if let ProjectionElem::Deref = projection.elem { - if projection.base.ty(self.mir, self.tcx).to_ty(self.tcx).is_region_ptr() { + if projection.base.ty(self.mir, self.tcx).ty.is_region_ptr() { self.optimizations.and_stars.insert(location); } } } if let Rvalue::Len(ref place) = *rvalue { - let place_ty = place.ty(&self.mir.local_decls, self.tcx).to_ty(self.tcx); - if let TyKind::Array(_, len) = place_ty.sty { + let place_ty = place.ty(&self.mir.local_decls, self.tcx).ty; + if let ty::Array(_, len) = place_ty.sty { let span = self.mir.source_info(location).span; let ty = self.tcx.types.usize; let constant = Constant { span, ty, literal: len, user_ty: None }; diff --git a/src/librustc_mir/transform/lower_128bit.rs b/src/librustc_mir/transform/lower_128bit.rs index 54fc63f3057..fd9d6bb5760 100644 --- a/src/librustc_mir/transform/lower_128bit.rs +++ b/src/librustc_mir/transform/lower_128bit.rs @@ -3,7 +3,7 @@ use rustc::hir::def_id::DefId; use rustc::middle::lang_items::LangItem; use rustc::mir::*; -use rustc::ty::{List, Ty, TyCtxt, TyKind}; +use rustc::ty::{self, List, Ty, TyCtxt}; use rustc_data_structures::indexed_vec::{Idx}; use crate::transform::{MirPass, MirSource}; @@ -135,7 +135,7 @@ fn check_lang_item_type<'a, 'tcx, D>( let sig = poly_sig.no_bound_vars().unwrap(); let lhs_ty = lhs.ty(local_decls, tcx); let rhs_ty = rhs.ty(local_decls, tcx); - let place_ty = place.ty(local_decls, tcx).to_ty(tcx); + let place_ty = place.ty(local_decls, tcx).ty; let expected = [lhs_ty, rhs_ty, place_ty]; assert_eq!(sig.inputs_and_output[..], expected, "lang item `{}`", tcx.def_path_str(did)); @@ -183,8 +183,8 @@ impl RhsKind { fn sign_of_128bit(ty: Ty<'_>) -> Option<bool> { match ty.sty { - TyKind::Int(syntax::ast::IntTy::I128) => Some(true), - TyKind::Uint(syntax::ast::UintTy::U128) => Some(false), + ty::Int(syntax::ast::IntTy::I128) => Some(true), + ty::Uint(syntax::ast::UintTy::U128) => Some(false), _ => None, } } diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index 8df0d72407b..27cb87f5dca 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -8,7 +8,6 @@ use rustc::ty::steal::Steal; use rustc::hir; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; use rustc::util::nodemap::DefIdSet; -use rustc_data_structures::sync::Lrc; use std::borrow::Cow; use syntax::ast; use syntax_pos::Span; @@ -59,7 +58,7 @@ fn is_mir_available<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> boo /// Finds the full set of `DefId`s within the current crate that have /// MIR associated with them. fn mir_keys<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, krate: CrateNum) - -> Lrc<DefIdSet> { + -> &'tcx DefIdSet { assert_eq!(krate, LOCAL_CRATE); let mut set = DefIdSet::default(); @@ -94,7 +93,7 @@ fn mir_keys<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, krate: CrateNum) set: &mut set, }.as_deep_visitor()); - Lrc::new(set) + tcx.arena.alloc(set) } fn mir_built<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx Steal<Mir<'tcx>> { diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs index 73b88e9904b..ddf963c7fa9 100644 --- a/src/librustc_mir/transform/promote_consts.rs +++ b/src/librustc_mir/transform/promote_consts.rs @@ -44,8 +44,8 @@ pub enum TempState { impl TempState { pub fn is_promotable(&self) -> bool { debug!("is_promotable: self={:?}", self); - if let TempState::Defined { uses, .. } = *self { - uses > 0 + if let TempState::Defined { .. } = *self { + true } else { false } @@ -80,9 +80,14 @@ impl<'tcx> Visitor<'tcx> for TempCollector<'tcx> { context: PlaceContext<'tcx>, location: Location) { debug!("visit_local: index={:?} context={:?} location={:?}", index, context, location); - // We're only interested in temporaries - if self.mir.local_kind(index) != LocalKind::Temp { - return; + // We're only interested in temporaries and the return place + match self.mir.local_kind(index) { + | LocalKind::Temp + | LocalKind::ReturnPointer + => {}, + | LocalKind::Arg + | LocalKind::Var + => return, } // Ignore drops, if the temp gets promoted, @@ -101,7 +106,6 @@ impl<'tcx> Visitor<'tcx> for TempCollector<'tcx> { if *temp == TempState::Undefined { match context { PlaceContext::MutatingUse(MutatingUseContext::Store) | - PlaceContext::MutatingUse(MutatingUseContext::AsmOutput) | PlaceContext::MutatingUse(MutatingUseContext::Call) => { *temp = TempState::Defined { location, @@ -310,7 +314,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { place = &mut proj.base; }; - let ty = place.ty(local_decls, self.tcx).to_ty(self.tcx); + let ty = place.ty(local_decls, self.tcx).ty; let span = statement.source_info.span; Operand::Move(mem::replace(place, promoted_place(ty, span))) diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 9bd5fce31f1..3154f8e89e3 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -168,7 +168,7 @@ trait Qualif { cx, proj.base.ty(cx.mir, cx.tcx) .projection_ty(cx.tcx, &proj.elem) - .to_ty(cx.tcx), + .ty, ); match proj.elem { ProjectionElem::Deref | @@ -245,7 +245,7 @@ trait Qualif { // Special-case reborrows to be more like a copy of the reference. if let Place::Projection(ref proj) = *place { if let ProjectionElem::Deref = proj.elem { - let base_ty = proj.base.ty(cx.mir, cx.tcx).to_ty(cx.tcx); + let base_ty = proj.base.ty(cx.mir, cx.tcx).ty; if let ty::Ref(..) = base_ty.sty { return Self::in_place(cx, &proj.base); } @@ -301,7 +301,7 @@ impl Qualif for HasMutInterior { // allowed in constants (and the `Checker` will error), and/or it // won't be promoted, due to `&mut ...` or interior mutability. Rvalue::Ref(_, kind, ref place) => { - let ty = place.ty(cx.mir, cx.tcx).to_ty(cx.tcx); + let ty = place.ty(cx.mir, cx.tcx).ty; if let BorrowKind::Mut { .. } = kind { // In theory, any zero-sized value could be borrowed @@ -365,11 +365,11 @@ impl Qualif for NeedsDrop { } } -// Not constant at all - non-`const fn` calls, asm!, +// Not promotable at all - non-`const fn` calls, asm!, // pointer comparisons, ptr-to-int casts, etc. -struct IsNotConst; +struct IsNotPromotable; -impl Qualif for IsNotConst { +impl Qualif for IsNotPromotable { const IDX: usize = 2; fn in_static(cx: &ConstCx<'_, 'tcx>, static_: &Static<'tcx>) -> bool { @@ -398,7 +398,7 @@ impl Qualif for IsNotConst { ProjectionElem::Field(..) => { if cx.mode == Mode::Fn { - let base_ty = proj.base.ty(cx.mir, cx.tcx).to_ty(cx.tcx); + let base_ty = proj.base.ty(cx.mir, cx.tcx).ty; if let Some(def) = base_ty.ty_adt_def() { if def.is_union() { return true; @@ -508,13 +508,17 @@ impl Qualif for IsNotConst { } } -// Refers to temporaries which cannot be promoted as -// promote_consts decided they weren't simple enough. -// FIXME(oli-obk,eddyb): Remove this flag entirely and -// solely process this information via `IsNotConst`. -struct IsNotPromotable; - -impl Qualif for IsNotPromotable { +/// Refers to temporaries which cannot be promoted *implicitly*. +/// Explicit promotion happens e.g. for constant arguments declared via `rustc_args_required_const`. +/// Inside a const context all constness rules +/// apply, so implicit promotion simply has to follow the regular constant rules (modulo interior +/// mutability or `Drop` rules which are handled `HasMutInterior` and `NeedsDrop` respectively). +/// Implicit promotion inside regular functions does not happen if `const fn` calls are involved, +/// as the call may be perfectly alright at runtime, but fail at compile time e.g. due to addresses +/// being compared inside the function. +struct IsNotImplicitlyPromotable; + +impl Qualif for IsNotImplicitlyPromotable { const IDX: usize = 3; fn in_call( @@ -550,15 +554,18 @@ macro_rules! static_assert_seq_qualifs { static_assert!(SEQ_QUALIFS: QUALIF_COUNT == $i); }; } -static_assert_seq_qualifs!(0 => HasMutInterior, NeedsDrop, IsNotConst, IsNotPromotable); +static_assert_seq_qualifs!( + 0 => HasMutInterior, NeedsDrop, IsNotPromotable, IsNotImplicitlyPromotable +); impl ConstCx<'_, 'tcx> { fn qualifs_in_any_value_of_ty(&self, ty: Ty<'tcx>) -> PerQualif<bool> { let mut qualifs = PerQualif::default(); qualifs[HasMutInterior] = HasMutInterior::in_any_value_of_ty(self, ty).unwrap_or(false); qualifs[NeedsDrop] = NeedsDrop::in_any_value_of_ty(self, ty).unwrap_or(false); - qualifs[IsNotConst] = IsNotConst::in_any_value_of_ty(self, ty).unwrap_or(false); qualifs[IsNotPromotable] = IsNotPromotable::in_any_value_of_ty(self, ty).unwrap_or(false); + qualifs[IsNotImplicitlyPromotable] = + IsNotImplicitlyPromotable::in_any_value_of_ty(self, ty).unwrap_or(false); qualifs } @@ -566,8 +573,8 @@ impl ConstCx<'_, 'tcx> { let mut qualifs = PerQualif::default(); qualifs[HasMutInterior] = HasMutInterior::in_local(self, local); qualifs[NeedsDrop] = NeedsDrop::in_local(self, local); - qualifs[IsNotConst] = IsNotConst::in_local(self, local); qualifs[IsNotPromotable] = IsNotPromotable::in_local(self, local); + qualifs[IsNotImplicitlyPromotable] = IsNotImplicitlyPromotable::in_local(self, local); qualifs } @@ -575,8 +582,8 @@ impl ConstCx<'_, 'tcx> { let mut qualifs = PerQualif::default(); qualifs[HasMutInterior] = HasMutInterior::in_value(self, source); qualifs[NeedsDrop] = NeedsDrop::in_value(self, source); - qualifs[IsNotConst] = IsNotConst::in_value(self, source); qualifs[IsNotPromotable] = IsNotPromotable::in_value(self, source); + qualifs[IsNotImplicitlyPromotable] = IsNotImplicitlyPromotable::in_value(self, source); qualifs } } @@ -631,26 +638,21 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { }; for (local, decl) in mir.local_decls.iter_enumerated() { - match mir.local_kind(local) { - LocalKind::Arg => { - let qualifs = cx.qualifs_in_any_value_of_ty(decl.ty); - for (per_local, qualif) in &mut cx.per_local.as_mut().zip(qualifs).0 { - if *qualif { - per_local.insert(local); - } + if let LocalKind::Arg = mir.local_kind(local) { + let qualifs = cx.qualifs_in_any_value_of_ty(decl.ty); + for (per_local, qualif) in &mut cx.per_local.as_mut().zip(qualifs).0 { + if *qualif { + per_local.insert(local); } - cx.per_local[IsNotPromotable].insert(local); - } - - LocalKind::Var if mode == Mode::Fn => { - cx.per_local[IsNotConst].insert(local); } - - LocalKind::Temp if !temps[local].is_promotable() => { - cx.per_local[IsNotPromotable].insert(local); - } - - _ => {} + } + if !temps[local].is_promotable() { + cx.per_local[IsNotPromotable].insert(local); + } + if let LocalKind::Var = mir.local_kind(local) { + // Sanity check to prevent implicit and explicit promotion of + // named locals + assert!(cx.per_local[IsNotPromotable].contains(local)); } } @@ -698,11 +700,11 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { // the borrowed place is disallowed from being borrowed, // due to either a mutable borrow (with some exceptions), // or an shared borrow of a value with interior mutability. - // Then `HasMutInterior` is replaced with `IsNotConst`, + // Then `HasMutInterior` is replaced with `IsNotPromotable`, // to avoid duplicate errors (e.g. from reborrowing). if qualifs[HasMutInterior] { qualifs[HasMutInterior] = false; - qualifs[IsNotConst] = true; + qualifs[IsNotPromotable] = true; if self.mode != Mode::Fn { if let BorrowKind::Mut { .. } = kind { @@ -728,7 +730,10 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { interior mutability, create a static instead"); } } - } else { + } else if let BorrowKind::Mut { .. } | BorrowKind::Shared = kind { + // Don't promote BorrowKind::Shallow borrows, as they don't + // reach codegen. + // We might have a candidate for promotion. let candidate = Candidate::Ref(location); // We can only promote interior borrows of promotable temps. @@ -908,7 +913,7 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { // Account for errors in consts by using the // conservative type qualification instead. - if qualifs[IsNotConst] { + if qualifs[IsNotPromotable] { qualifs = self.qualifs_in_any_value_of_ty(mir.return_ty()); } @@ -985,7 +990,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { // `not_const` errors out in const contexts self.not_const() } - let base_ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx); + let base_ty = proj.base.ty(self.mir, self.tcx).ty; match self.mode { Mode::Fn => {}, _ => { @@ -1009,7 +1014,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { ProjectionElem::Subslice {..} | ProjectionElem::Field(..) | ProjectionElem::Index(_) => { - let base_ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx); + let base_ty = proj.base.ty(self.mir, self.tcx).ty; if let Some(def) = base_ty.ty_adt_def() { if def.is_union() { match self.mode { @@ -1066,7 +1071,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { let mut is_reborrow = false; if let Place::Projection(ref proj) = *place { if let ProjectionElem::Deref = proj.elem { - let base_ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx); + let base_ty = proj.base.ty(self.mir, self.tcx).ty; if let ty::Ref(..) = base_ty.sty { is_reborrow = true; } @@ -1190,7 +1195,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { self.assign(dest, ValueSource::Call { callee: func, args, - return_ty: dest.ty(self.mir, self.tcx).to_ty(self.tcx), + return_ty: dest.ty(self.mir, self.tcx).ty, }, location); } @@ -1323,7 +1328,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { // which happens even without the user requesting it. // We can error out with a hard error if the argument is not // constant here. - if !IsNotConst::in_operand(self, arg) { + if !IsNotPromotable::in_operand(self, arg) { debug!("visit_terminator_kind: candidate={:?}", candidate); self.promotion_candidates.push(candidate); } else { @@ -1364,7 +1369,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { if let Some(span) = needs_drop { // Double-check the type being dropped, to minimize false positives. - let ty = place.ty(self.mir, self.tcx).to_ty(self.tcx); + let ty = place.ty(self.mir, self.tcx).ty; if ty.needs_drop(self.tcx, self.param_env) { struct_span_err!(self.tcx.sess, span, E0493, "destructors cannot be evaluated at compile-time") @@ -1441,7 +1446,7 @@ fn mir_const_qualif<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if mir.return_ty().references_error() { tcx.sess.delay_span_bug(mir.span, "mir_const_qualif: Mir had errors"); - return (1 << IsNotConst::IDX, Lrc::new(BitSet::new_empty(0))); + return (1 << IsNotPromotable::IDX, Lrc::new(BitSet::new_empty(0))); } Checker::new(tcx, def_id, mir, Mode::Const).check_const() diff --git a/src/librustc_mir/transform/uniform_array_move_out.rs b/src/librustc_mir/transform/uniform_array_move_out.rs index b1d898bb5b0..616944dd7ef 100644 --- a/src/librustc_mir/transform/uniform_array_move_out.rs +++ b/src/librustc_mir/transform/uniform_array_move_out.rs @@ -69,7 +69,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UniformArrayMoveOutVisitor<'a, 'tcx> { from_end: false} = proj.elem { // no need to transformation } else { - let place_ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx); + let place_ty = proj.base.ty(self.mir, self.tcx).ty; if let ty::Array(item_ty, const_size) = place_ty.sty { if let Some(size) = const_size.assert_usize(self.tcx) { assert!(size <= u32::max_value() as u64, @@ -195,7 +195,7 @@ impl MirPass for RestoreSubsliceArrayMoveOut { let opt_src_place = items.first().and_then(|x| *x).map(|x| x.2); let opt_size = opt_src_place.and_then(|src_place| { - let src_ty = src_place.ty(mir, tcx).to_ty(tcx); + let src_ty = src_place.ty(mir, tcx).ty; if let ty::Array(_, ref size_o) = src_ty.sty { size_o.assert_usize(tcx) } else { diff --git a/src/librustc_mir/util/alignment.rs b/src/librustc_mir/util/alignment.rs index 7be34d001df..788b7fdaaf9 100644 --- a/src/librustc_mir/util/alignment.rs +++ b/src/librustc_mir/util/alignment.rs @@ -17,7 +17,7 @@ pub fn is_disaligned<'a, 'tcx, L>(tcx: TyCtxt<'a, 'tcx, 'tcx>, return false } - let ty = place.ty(local_decls, tcx).to_ty(tcx); + let ty = place.ty(local_decls, tcx).ty; match tcx.layout_raw(param_env.and(ty)) { Ok(layout) if layout.align.abi.bytes() == 1 => { // if the alignment is 1, the type can't be further @@ -46,7 +46,7 @@ fn is_within_packed<'a, 'tcx, L>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // encountered a Deref, which is ABI-aligned ProjectionElem::Deref => break, ProjectionElem::Field(..) => { - let ty = base.ty(local_decls, tcx).to_ty(tcx); + let ty = base.ty(local_decls, tcx).ty; match ty.sty { ty::Adt(def, _) if def.repr.packed() => { return true diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs index 37b38338ab9..2d275c9a137 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -122,7 +122,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> where D: DropElaborator<'b, 'tcx> { fn place_ty(&self, place: &Place<'tcx>) -> Ty<'tcx> { - place.ty(self.elaborator.mir(), self.tcx()).to_ty(self.tcx()) + place.ty(self.elaborator.mir(), self.tcx()).ty } fn tcx(&self) -> TyCtxt<'b, 'tcx, 'tcx> { @@ -412,8 +412,8 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> self.path, variant_index); if let Some(variant_path) = subpath { let base_place = self.place.clone().elem( - ProjectionElem::Downcast(adt, variant_index) - ); + ProjectionElem::Downcast(Some(adt.variants[variant_index].ident.name), + variant_index)); let fields = self.move_paths_for_fields( &base_place, variant_path, diff --git a/src/librustc_msan/Cargo.toml b/src/librustc_msan/Cargo.toml index 7d88aa59b3a..bda40785725 100644 --- a/src/librustc_msan/Cargo.toml +++ b/src/librustc_msan/Cargo.toml @@ -12,7 +12,7 @@ test = false [build-dependencies] build_helper = { path = "../build_helper" } -cmake = "0.1.18" +cmake = "0.1.38" [dependencies] alloc = { path = "../liballoc" } diff --git a/src/librustc_passes/lib.rs b/src/librustc_passes/lib.rs index ff2e345d084..20442a4a566 100644 --- a/src/librustc_passes/lib.rs +++ b/src/librustc_passes/lib.rs @@ -12,6 +12,7 @@ #![recursion_limit="256"] #![deny(rust_2018_idioms)] +#![cfg_attr(not(stage0), deny(internal))] #[macro_use] extern crate rustc; diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 030883c0159..9a8970b2935 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -1,6 +1,7 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] #![deny(rust_2018_idioms)] +#![cfg_attr(not(stage0), deny(internal))] #![feature(nll)] #![feature(rustc_diagnostic_macros)] diff --git a/src/librustc_resolve/error_reporting.rs b/src/librustc_resolve/error_reporting.rs index 461d02e515d..931bce91d7d 100644 --- a/src/librustc_resolve/error_reporting.rs +++ b/src/librustc_resolve/error_reporting.rs @@ -4,16 +4,17 @@ use errors::{Applicability, DiagnosticBuilder, DiagnosticId}; use log::debug; use rustc::hir::def::{Def, CtorKind, Namespace::*}; use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; -use rustc::session::config::nightly_options; -use syntax::ast::{Expr, ExprKind}; -use syntax::symbol::keywords; -use syntax_pos::Span; +use rustc::session::{Session, config::nightly_options}; +use syntax::ast::{Expr, ExprKind, Ident}; +use syntax::ext::base::MacroKind; +use syntax::symbol::{Symbol, keywords}; +use syntax_pos::{BytePos, Span}; use crate::macros::ParentScope; -use crate::resolve_imports::ImportResolver; +use crate::resolve_imports::{ImportDirective, ImportDirectiveSubclass, ImportResolver}; use crate::{import_candidate_to_enum_paths, is_self_type, is_self_value, path_names_to_string}; use crate::{AssocSuggestion, CrateLint, ImportSuggestion, ModuleOrUniformRoot, PathResult, - PathSource, Resolver, Segment}; + PathSource, Resolver, Segment, Suggestion}; impl<'a> Resolver<'a> { /// Handles error reporting for `smart_resolve_path_fragment` function. @@ -428,7 +429,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { span: Span, mut path: Vec<Segment>, parent_scope: &ParentScope<'b>, - ) -> Option<(Vec<Segment>, Option<String>)> { + ) -> Option<(Vec<Segment>, Vec<String>)> { debug!("make_path_suggestion: span={:?} path={:?}", span, path); match (path.get(0), path.get(1)) { @@ -463,13 +464,13 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { span: Span, mut path: Vec<Segment>, parent_scope: &ParentScope<'b>, - ) -> Option<(Vec<Segment>, Option<String>)> { + ) -> Option<(Vec<Segment>, Vec<String>)> { // Replace first ident with `self` and check if that is valid. path[0].ident.name = keywords::SelfLower.name(); let result = self.resolve_path(&path, None, parent_scope, false, span, CrateLint::No); debug!("make_missing_self_suggestion: path={:?} result={:?}", path, result); if let PathResult::Module(..) = result { - Some((path, None)) + Some((path, Vec::new())) } else { None } @@ -487,7 +488,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { span: Span, mut path: Vec<Segment>, parent_scope: &ParentScope<'b>, - ) -> Option<(Vec<Segment>, Option<String>)> { + ) -> Option<(Vec<Segment>, Vec<String>)> { // Replace first ident with `crate` and check if that is valid. path[0].ident.name = keywords::Crate.name(); let result = self.resolve_path(&path, None, parent_scope, false, span, CrateLint::No); @@ -495,11 +496,11 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { if let PathResult::Module(..) = result { Some(( path, - Some( + vec![ "`use` statements changed in Rust 2018; read more at \ <https://doc.rust-lang.org/edition-guide/rust-2018/module-system/path-\ clarity.html>".to_string() - ), + ], )) } else { None @@ -518,13 +519,13 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { span: Span, mut path: Vec<Segment>, parent_scope: &ParentScope<'b>, - ) -> Option<(Vec<Segment>, Option<String>)> { + ) -> Option<(Vec<Segment>, Vec<String>)> { // Replace first ident with `crate` and check if that is valid. path[0].ident.name = keywords::Super.name(); let result = self.resolve_path(&path, None, parent_scope, false, span, CrateLint::No); debug!("make_missing_super_suggestion: path={:?} result={:?}", path, result); if let PathResult::Module(..) = result { - Some((path, None)) + Some((path, Vec::new())) } else { None } @@ -545,7 +546,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { span: Span, mut path: Vec<Segment>, parent_scope: &ParentScope<'b>, - ) -> Option<(Vec<Segment>, Option<String>)> { + ) -> Option<(Vec<Segment>, Vec<String>)> { if path[1].ident.span.rust_2015() { return None; } @@ -564,10 +565,290 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { debug!("make_external_crate_suggestion: name={:?} path={:?} result={:?}", name, path, result); if let PathResult::Module(..) = result { - return Some((path, None)); + return Some((path, Vec::new())); } } None } + + /// Suggests importing a macro from the root of the crate rather than a module within + /// the crate. + /// + /// ``` + /// help: a macro with this name exists at the root of the crate + /// | + /// LL | use issue_59764::makro; + /// | ^^^^^^^^^^^^^^^^^^ + /// | + /// = note: this could be because a macro annotated with `#[macro_export]` will be exported + /// at the root of the crate instead of the module where it is defined + /// ``` + pub(crate) fn check_for_module_export_macro( + &self, + directive: &'b ImportDirective<'b>, + module: ModuleOrUniformRoot<'b>, + ident: Ident, + ) -> Option<(Option<Suggestion>, Vec<String>)> { + let mut crate_module = if let ModuleOrUniformRoot::Module(module) = module { + module + } else { + return None; + }; + + while let Some(parent) = crate_module.parent { + crate_module = parent; + } + + if ModuleOrUniformRoot::same_def(ModuleOrUniformRoot::Module(crate_module), module) { + // Don't make a suggestion if the import was already from the root of the + // crate. + return None; + } + + let resolutions = crate_module.resolutions.borrow(); + let resolution = resolutions.get(&(ident, MacroNS))?; + let binding = resolution.borrow().binding()?; + if let Def::Macro(_, MacroKind::Bang) = binding.def() { + let module_name = crate_module.kind.name().unwrap(); + let import = match directive.subclass { + ImportDirectiveSubclass::SingleImport { source, target, .. } if source != target => + format!("{} as {}", source, target), + _ => format!("{}", ident), + }; + + let mut corrections: Vec<(Span, String)> = Vec::new(); + if !directive.is_nested() { + // Assume this is the easy case of `use issue_59764::foo::makro;` and just remove + // intermediate segments. + corrections.push((directive.span, format!("{}::{}", module_name, import))); + } else { + // Find the binding span (and any trailing commas and spaces). + // ie. `use a::b::{c, d, e};` + // ^^^ + let (found_closing_brace, binding_span) = find_span_of_binding_until_next_binding( + self.resolver.session, directive.span, directive.use_span, + ); + debug!("check_for_module_export_macro: found_closing_brace={:?} binding_span={:?}", + found_closing_brace, binding_span); + + let mut removal_span = binding_span; + if found_closing_brace { + // If the binding span ended with a closing brace, as in the below example: + // ie. `use a::b::{c, d};` + // ^ + // Then expand the span of characters to remove to include the previous + // binding's trailing comma. + // ie. `use a::b::{c, d};` + // ^^^ + if let Some(previous_span) = extend_span_to_previous_binding( + self.resolver.session, binding_span, + ) { + debug!("check_for_module_export_macro: previous_span={:?}", previous_span); + removal_span = removal_span.with_lo(previous_span.lo()); + } + } + debug!("check_for_module_export_macro: removal_span={:?}", removal_span); + + // Remove the `removal_span`. + corrections.push((removal_span, "".to_string())); + + // Find the span after the crate name and if it has nested imports immediatately + // after the crate name already. + // ie. `use a::b::{c, d};` + // ^^^^^^^^^ + // or `use a::{b, c, d}};` + // ^^^^^^^^^^^ + let (has_nested, after_crate_name) = find_span_immediately_after_crate_name( + self.resolver.session, module_name, directive.use_span, + ); + debug!("check_for_module_export_macro: has_nested={:?} after_crate_name={:?}", + has_nested, after_crate_name); + + let source_map = self.resolver.session.source_map(); + + // Add the import to the start, with a `{` if required. + let start_point = source_map.start_point(after_crate_name); + if let Ok(start_snippet) = source_map.span_to_snippet(start_point) { + corrections.push(( + start_point, + if has_nested { + // In this case, `start_snippet` must equal '{'. + format!("{}{}, ", start_snippet, import) + } else { + // In this case, add a `{`, then the moved import, then whatever + // was there before. + format!("{{{}, {}", import, start_snippet) + } + )); + } + + // Add a `};` to the end if nested, matching the `{` added at the start. + if !has_nested { + corrections.push((source_map.end_point(after_crate_name), + "};".to_string())); + } + } + + let suggestion = Some(( + corrections, + String::from("a macro with this name exists at the root of the crate"), + Applicability::MaybeIncorrect, + )); + let note = vec![ + "this could be because a macro annotated with `#[macro_export]` will be exported \ + at the root of the crate instead of the module where it is defined".to_string(), + ]; + Some((suggestion, note)) + } else { + None + } + } +} + +/// Given a `binding_span` of a binding within a use statement: +/// +/// ``` +/// use foo::{a, b, c}; +/// ^ +/// ``` +/// +/// then return the span until the next binding or the end of the statement: +/// +/// ``` +/// use foo::{a, b, c}; +/// ^^^ +/// ``` +pub(crate) fn find_span_of_binding_until_next_binding( + sess: &Session, + binding_span: Span, + use_span: Span, +) -> (bool, Span) { + let source_map = sess.source_map(); + + // Find the span of everything after the binding. + // ie. `a, e};` or `a};` + let binding_until_end = binding_span.with_hi(use_span.hi()); + + // Find everything after the binding but not including the binding. + // ie. `, e};` or `};` + let after_binding_until_end = binding_until_end.with_lo(binding_span.hi()); + + // Keep characters in the span until we encounter something that isn't a comma or + // whitespace. + // ie. `, ` or ``. + // + // Also note whether a closing brace character was encountered. If there + // was, then later go backwards to remove any trailing commas that are left. + let mut found_closing_brace = false; + let after_binding_until_next_binding = source_map.span_take_while( + after_binding_until_end, + |&ch| { + if ch == '}' { found_closing_brace = true; } + ch == ' ' || ch == ',' + } + ); + + // Combine the two spans. + // ie. `a, ` or `a`. + // + // Removing these would leave `issue_52891::{d, e};` or `issue_52891::{d, e, };` + let span = binding_span.with_hi(after_binding_until_next_binding.hi()); + + (found_closing_brace, span) +} + +/// Given a `binding_span`, return the span through to the comma or opening brace of the previous +/// binding. +/// +/// ``` +/// use foo::a::{a, b, c}; +/// ^^--- binding span +/// | +/// returned span +/// +/// use foo::{a, b, c}; +/// --- binding span +/// ``` +pub(crate) fn extend_span_to_previous_binding( + sess: &Session, + binding_span: Span, +) -> Option<Span> { + let source_map = sess.source_map(); + + // `prev_source` will contain all of the source that came before the span. + // Then split based on a command and take the first (ie. closest to our span) + // snippet. In the example, this is a space. + let prev_source = source_map.span_to_prev_source(binding_span).ok()?; + + let prev_comma = prev_source.rsplit(',').collect::<Vec<_>>(); + let prev_starting_brace = prev_source.rsplit('{').collect::<Vec<_>>(); + if prev_comma.len() <= 1 || prev_starting_brace.len() <= 1 { + return None; + } + + let prev_comma = prev_comma.first().unwrap(); + let prev_starting_brace = prev_starting_brace.first().unwrap(); + + // If the amount of source code before the comma is greater than + // the amount of source code before the starting brace then we've only + // got one item in the nested item (eg. `issue_52891::{self}`). + if prev_comma.len() > prev_starting_brace.len() { + return None; + } + + Some(binding_span.with_lo(BytePos( + // Take away the number of bytes for the characters we've found and an + // extra for the comma. + binding_span.lo().0 - (prev_comma.as_bytes().len() as u32) - 1 + ))) +} + +/// Given a `use_span` of a binding within a use statement, returns the highlighted span and if +/// it is a nested use tree. +/// +/// ``` +/// use foo::a::{b, c}; +/// ^^^^^^^^^^ // false +/// +/// use foo::{a, b, c}; +/// ^^^^^^^^^^ // true +/// +/// use foo::{a, b::{c, d}}; +/// ^^^^^^^^^^^^^^^ // true +/// ``` +fn find_span_immediately_after_crate_name( + sess: &Session, + module_name: Symbol, + use_span: Span, +) -> (bool, Span) { + debug!("find_span_immediately_after_crate_name: module_name={:?} use_span={:?}", + module_name, use_span); + let source_map = sess.source_map(); + + // Using `use issue_59764::foo::{baz, makro};` as an example throughout.. + let mut num_colons = 0; + // Find second colon.. `use issue_59764:` + let until_second_colon = source_map.span_take_while(use_span, |c| { + if *c == ':' { num_colons += 1; } + match c { + ':' if num_colons == 2 => false, + _ => true, + } + }); + // Find everything after the second colon.. `foo::{baz, makro};` + let from_second_colon = use_span.with_lo(until_second_colon.hi() + BytePos(1)); + + let mut found_a_non_whitespace_character = false; + // Find the first non-whitespace character in `from_second_colon`.. `f` + let after_second_colon = source_map.span_take_while(from_second_colon, |c| { + if found_a_non_whitespace_character { return false; } + if !c.is_whitespace() { found_a_non_whitespace_character = true; } + true + }); + + // Find the first `{` in from_second_colon.. `foo::{` + let next_left_bracket = source_map.span_through_char(from_second_colon, '{'); + + (next_left_bracket == after_second_colon, from_second_colon) } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 3703ea08b62..b34786d8f12 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -8,6 +8,7 @@ #![recursion_limit="256"] #![deny(rust_2018_idioms)] +#![cfg_attr(not(stage0), deny(internal))] pub use rustc::hir::def::{Namespace, PerNS}; @@ -49,7 +50,7 @@ use syntax::ast::{QSelf, TraitItemKind, TraitRef, Ty, TyKind}; use syntax::ptr::P; use syntax::{span_err, struct_span_err, unwrap_or, walk_list}; -use syntax_pos::{BytePos, Span, DUMMY_SP, MultiSpan}; +use syntax_pos::{Span, DUMMY_SP, MultiSpan}; use errors::{Applicability, DiagnosticBuilder, DiagnosticId}; use log::debug; @@ -61,6 +62,7 @@ use std::mem::replace; use rustc_data_structures::ptr_key::PtrKey; use rustc_data_structures::sync::Lrc; +use error_reporting::{find_span_of_binding_until_next_binding, extend_span_to_previous_binding}; use resolve_imports::{ImportDirective, ImportDirectiveSubclass, NameResolution, ImportResolver}; use macros::{InvocationData, LegacyBinding, ParentScope}; @@ -137,8 +139,8 @@ impl Ord for BindingError { } } -/// A span, message, replacement text, and applicability. -type Suggestion = (Span, String, String, Applicability); +/// A vector of spans and replacements, a message and applicability. +type Suggestion = (Vec<(Span, String)>, String, Applicability); enum ResolutionError<'a> { /// Error E0401: can't use type or const parameters from outer function. @@ -388,8 +390,8 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver<'_>, "failed to resolve: {}", &label); err.span_label(span, label); - if let Some((span, msg, suggestion, applicability)) = suggestion { - err.span_suggestion(span, &msg, suggestion, applicability); + if let Some((suggestions, msg, applicability)) = suggestion { + err.multipart_suggestion(&msg, suggestions, applicability); } err @@ -1090,6 +1092,16 @@ enum ModuleKind { Def(Def, Name), } +impl ModuleKind { + /// Get name of the module. + pub fn name(&self) -> Option<Name> { + match self { + ModuleKind::Block(..) => None, + ModuleKind::Def(_, name) => Some(*name), + } + } +} + /// One node in the tree of modules. pub struct ModuleData<'a> { parent: Option<Module<'a>>, @@ -1352,7 +1364,7 @@ impl<'a> NameBinding<'a> { } } - // We sometimes need to treat variants as `pub` for backwards compatibility + // We sometimes need to treat variants as `pub` for backwards compatibility. fn pseudo_vis(&self) -> ty::Visibility { if self.is_variant() && self.def().def_id().is_local() { ty::Visibility::Public @@ -2714,7 +2726,7 @@ impl<'a> Resolver<'a> { { let mut self_type_rib = Rib::new(NormalRibKind); - // plain insert (no renaming, types are not currently hygienic....) + // Plain insert (no renaming, since types are not currently hygienic) self_type_rib.bindings.insert(keywords::SelfUpper.ident(), self_def); self.ribs[TypeNS].push(self_type_rib); f(self); @@ -3730,9 +3742,16 @@ impl<'a> Resolver<'a> { def, path.len() - i - 1 )); } else { + let label = format!( + "`{}` is {} {}, not a module", + ident, + def.article(), + def.kind_name(), + ); + return PathResult::Failed { span: ident.span, - label: format!("not a module `{}`", ident), + label, suggestion: None, is_error_from_last_segment: is_last, }; @@ -3762,9 +3781,8 @@ impl<'a> Resolver<'a> { ( String::from("unresolved import"), Some(( - ident.span, + vec![(ident.span, candidate.path.to_string())], String::from("a similar path exists"), - candidate.path.to_string(), Applicability::MaybeIncorrect, )), ) @@ -4438,26 +4456,47 @@ impl<'a> Resolver<'a> { let mut collected_traits = Vec::new(); module.for_each_child(|name, ns, binding| { if ns != TypeNS { return } - if let Def::Trait(_) = binding.def() { - collected_traits.push((name, binding)); + match binding.def() { + Def::Trait(_) | + Def::TraitAlias(_) => collected_traits.push((name, binding)), + _ => (), } }); *traits = Some(collected_traits.into_boxed_slice()); } for &(trait_name, binding) in traits.as_ref().unwrap().iter() { - let module = binding.module().unwrap(); - let mut ident = ident; - if ident.span.glob_adjust(module.expansion, binding.span.ctxt().modern()).is_none() { - continue - } - if self.resolve_ident_in_module_unadjusted( - ModuleOrUniformRoot::Module(module), - ident, - ns, - false, - module.span, - ).is_ok() { + // Traits have pseudo-modules that can be used to search for the given ident. + if let Some(module) = binding.module() { + let mut ident = ident; + if ident.span.glob_adjust( + module.expansion, + binding.span.ctxt().modern(), + ).is_none() { + continue + } + if self.resolve_ident_in_module_unadjusted( + ModuleOrUniformRoot::Module(module), + ident, + ns, + false, + module.span, + ).is_ok() { + let import_id = match binding.kind { + NameBindingKind::Import { directive, .. } => { + self.maybe_unused_trait_imports.insert(directive.id); + self.add_to_glob_map(&directive, trait_name); + Some(directive.id) + } + _ => None, + }; + let trait_def_id = module.def_id().unwrap(); + found_traits.push(TraitCandidate { def_id: trait_def_id, import_id }); + } + } else if let Def::TraitAlias(_) = binding.def() { + // For now, just treat all trait aliases as possible candidates, since we don't + // know if the ident is somewhere in the transitive bounds. + let import_id = match binding.kind { NameBindingKind::Import { directive, .. } => { self.maybe_unused_trait_imports.insert(directive.id); @@ -4466,8 +4505,10 @@ impl<'a> Resolver<'a> { } _ => None, }; - let trait_def_id = module.def_id().unwrap(); - found_traits.push(TraitCandidate { def_id: trait_def_id, import_id: import_id }); + let trait_def_id = binding.def().def_id(); + found_traits.push(TraitCandidate { def_id: trait_def_id, import_id }); + } else { + bug!("candidate is not trait or trait alias?") } } } @@ -5110,7 +5151,6 @@ impl<'a> Resolver<'a> { ) { assert!(directive.is_nested()); let message = "remove unnecessary import"; - let source_map = self.session.source_map(); // Two examples will be used to illustrate the span manipulations we're doing: // @@ -5119,73 +5159,24 @@ impl<'a> Resolver<'a> { // - Given `use issue_52891::{d, e, a};` where `a` is a duplicate then `binding_span` is // `a` and `directive.use_span` is `issue_52891::{d, e, a};`. - // Find the span of everything after the binding. - // ie. `a, e};` or `a};` - let binding_until_end = binding_span.with_hi(directive.use_span.hi()); - - // Find everything after the binding but not including the binding. - // ie. `, e};` or `};` - let after_binding_until_end = binding_until_end.with_lo(binding_span.hi()); - - // Keep characters in the span until we encounter something that isn't a comma or - // whitespace. - // ie. `, ` or ``. - // - // Also note whether a closing brace character was encountered. If there - // was, then later go backwards to remove any trailing commas that are left. - let mut found_closing_brace = false; - let after_binding_until_next_binding = source_map.span_take_while( - after_binding_until_end, - |&ch| { - if ch == '}' { found_closing_brace = true; } - ch == ' ' || ch == ',' - } + let (found_closing_brace, span) = find_span_of_binding_until_next_binding( + self.session, binding_span, directive.use_span, ); - // Combine the two spans. - // ie. `a, ` or `a`. - // - // Removing these would leave `issue_52891::{d, e};` or `issue_52891::{d, e, };` - let span = binding_span.with_hi(after_binding_until_next_binding.hi()); - // If there was a closing brace then identify the span to remove any trailing commas from // previous imports. if found_closing_brace { - if let Ok(prev_source) = source_map.span_to_prev_source(span) { - // `prev_source` will contain all of the source that came before the span. - // Then split based on a command and take the first (ie. closest to our span) - // snippet. In the example, this is a space. - let prev_comma = prev_source.rsplit(',').collect::<Vec<_>>(); - let prev_starting_brace = prev_source.rsplit('{').collect::<Vec<_>>(); - if prev_comma.len() > 1 && prev_starting_brace.len() > 1 { - let prev_comma = prev_comma.first().unwrap(); - let prev_starting_brace = prev_starting_brace.first().unwrap(); - - // If the amount of source code before the comma is greater than - // the amount of source code before the starting brace then we've only - // got one item in the nested item (eg. `issue_52891::{self}`). - if prev_comma.len() > prev_starting_brace.len() { - // So just remove the entire line... - err.span_suggestion( - directive.use_span_with_attributes, - message, - String::new(), - Applicability::MaybeIncorrect, - ); - return; - } - - let span = span.with_lo(BytePos( - // Take away the number of bytes for the characters we've found and an - // extra for the comma. - span.lo().0 - (prev_comma.as_bytes().len() as u32) - 1 - )); - err.tool_only_span_suggestion( - span, message, String::new(), Applicability::MaybeIncorrect, - ); - return; - } + if let Some(span) = extend_span_to_previous_binding(self.session, span) { + err.tool_only_span_suggestion(span, message, String::new(), + Applicability::MaybeIncorrect); + } else { + // Remove the entire line if we cannot extend the span back, this indicates a + // `issue_52891::{self}` case. + err.span_suggestion(directive.use_span_with_attributes, message, String::new(), + Applicability::MaybeIncorrect); } + + return; } err.span_suggestion(span, message, String::new(), Applicability::MachineApplicable); diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 7ea07f5e0cb..62af6e19603 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -145,7 +145,7 @@ pub struct NameResolution<'a> { impl<'a> NameResolution<'a> { // Returns the binding for the name if it is known or None if it not known. - fn binding(&self) -> Option<&'a NameBinding<'a>> { + pub(crate) fn binding(&self) -> Option<&'a NameBinding<'a>> { self.binding.and_then(|binding| { if !binding.is_glob_import() || self.single_imports.is_empty() { Some(binding) } else { None } @@ -636,7 +636,7 @@ impl<'a> Resolver<'a> { struct UnresolvedImportError { span: Span, label: Option<String>, - note: Option<String>, + note: Vec<String>, suggestion: Option<Suggestion>, } @@ -756,8 +756,8 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { /// Upper limit on the number of `span_label` messages. const MAX_LABEL_COUNT: usize = 10; - let (span, msg, note) = if errors.is_empty() { - (span.unwrap(), "unresolved import".to_string(), None) + let (span, msg) = if errors.is_empty() { + (span.unwrap(), "unresolved import".to_string()) } else { let span = MultiSpan::from_spans( errors @@ -766,11 +766,6 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { .collect(), ); - let note = errors - .iter() - .filter_map(|(_, err)| err.note.as_ref()) - .last(); - let paths = errors .iter() .map(|(path, _)| format!("`{}`", path)) @@ -782,13 +777,15 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { paths.join(", "), ); - (span, msg, note) + (span, msg) }; let mut diag = struct_span_err!(self.resolver.session, span, E0432, "{}", &msg); - if let Some(note) = ¬e { - diag.note(note); + if let Some((_, UnresolvedImportError { note, .. })) = errors.iter().last() { + for message in note { + diag.note(&message); + } } for (_, err) in errors.into_iter().take(MAX_LABEL_COUNT) { @@ -796,8 +793,8 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { diag.span_label(err.span, label); } - if let Some((span, msg, suggestion, applicability)) = err.suggestion { - diag.span_suggestion(span, &msg, suggestion, applicability); + if let Some((suggestions, msg, applicability)) = err.suggestion { + diag.multipart_suggestion(&msg, suggestions, applicability); } } @@ -950,9 +947,8 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { label: None, note, suggestion: Some(( - span, + vec![(span, Segment::names_to_string(&suggestion))], String::from("a similar path exists"), - Segment::names_to_string(&suggestion), Applicability::MaybeIncorrect, )), } @@ -961,7 +957,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { UnresolvedImportError { span, label: Some(label), - note: None, + note: Vec::new(), suggestion, } } @@ -1006,7 +1002,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { return Some(UnresolvedImportError { span: directive.span, label: Some(String::from("cannot glob-import a module into itself")), - note: None, + note: Vec::new(), suggestion: None, }); } @@ -1114,15 +1110,19 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { } }); - let lev_suggestion = - find_best_match_for_name(names, &ident.as_str(), None).map(|suggestion| { - ( - ident.span, - String::from("a similar name exists in the module"), - suggestion.to_string(), - Applicability::MaybeIncorrect, - ) - }); + let lev_suggestion = find_best_match_for_name(names, &ident.as_str(), None) + .map(|suggestion| + (vec![(ident.span, suggestion.to_string())], + String::from("a similar name exists in the module"), + Applicability::MaybeIncorrect) + ); + + let (suggestion, note) = match self.check_for_module_export_macro( + directive, module, ident, + ) { + Some((suggestion, note)) => (suggestion.or(lev_suggestion), note), + _ => (lev_suggestion, Vec::new()), + }; let label = match module { ModuleOrUniformRoot::Module(module) => { @@ -1143,11 +1143,12 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { } } }; + Some(UnresolvedImportError { span: directive.span, label: Some(label), - note: None, - suggestion: lev_suggestion, + note, + suggestion, }) } else { // `resolve_ident_in_module` reported a privacy error. @@ -1334,7 +1335,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { self.populate_module_if_necessary(module); - if let Some(Def::Trait(_)) = module.def() { + if module.is_trait() { self.session.span_err(directive.span, "items in traits are not importable."); return; } else if module.def_id() == directive.parent_scope.module.def_id() { diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 898ea62046d..d6923b4490d 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -2,6 +2,7 @@ #![feature(custom_attribute)] #![feature(nll)] #![deny(rust_2018_idioms)] +#![cfg_attr(not(stage0), deny(internal))] #![allow(unused_attributes)] #![recursion_limit="256"] @@ -22,7 +23,6 @@ use rustc::middle::cstore::ExternCrate; use rustc::session::config::{CrateType, Input, OutputType}; use rustc::ty::{self, DefIdTree, TyCtxt}; use rustc::{bug, span_bug}; -use rustc_typeck::hir_ty_to_ty; use rustc_codegen_utils::link::{filename_for_metadata, out_filename}; use rustc_data_structures::sync::Lrc; @@ -647,6 +647,10 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { Node::Pat(&hir::Pat { node: hir::PatKind::TupleStruct(ref qpath, ..), .. + }) | + Node::Ty(&hir::Ty { + node: hir::TyKind::Path(ref qpath), + .. }) => { let hir_id = self.tcx.hir().node_to_hir_id(id); self.tables.qpath_def(qpath, hir_id) @@ -657,25 +661,6 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { .. }) => HirDef::Local(self.tcx.hir().hir_to_node_id(canonical_id)), - Node::Ty(ty) => if let hir::Ty { - node: hir::TyKind::Path(ref qpath), - .. - } = *ty - { - match *qpath { - hir::QPath::Resolved(_, ref path) => path.def, - hir::QPath::TypeRelative(..) => { - let ty = hir_ty_to_ty(self.tcx, ty); - if let ty::Projection(proj) = ty.sty { - return HirDef::AssociatedTy(proj.item_def_id); - } - HirDef::Err - } - } - } else { - HirDef::Err - }, - _ => HirDef::Err, } } diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs index 235b530a7ef..59eda97a2f9 100644 --- a/src/librustc_target/abi/mod.rs +++ b/src/librustc_target/abi/mod.rs @@ -828,12 +828,13 @@ pub enum Variants { index: VariantIdx, }, - /// Enums with more than one inhabited variant: for each case there is - /// a struct, and they all have space reserved for the discriminant, - /// which is the sole field of the enum layout. + /// Enum-likes with more than one inhabited variant: for each case there is + /// a struct, and they all have space reserved for the discriminant. + /// For enums this is the sole field of the layout. Multiple { discr: Scalar, discr_kind: DiscriminantKind, + discr_index: usize, variants: IndexVec<VariantIdx, LayoutDetails>, }, } @@ -845,8 +846,9 @@ pub enum DiscriminantKind { /// Niche (values invalid for a type) encoding the discriminant: /// the variant `dataful_variant` contains a niche at an arbitrary - /// offset (field 0 of the enum), which for a variant with discriminant - /// `d` is set to `(d - niche_variants.start).wrapping_add(niche_start)`. + /// offset (field `discr_index` of the enum), which for a variant with + /// discriminant `d` is set to + /// `(d - niche_variants.start).wrapping_add(niche_start)`. /// /// For example, `Option<(usize, &T)>` is represented such that /// `None` has a null pointer for the second tuple field, and diff --git a/src/librustc_target/lib.rs b/src/librustc_target/lib.rs index efffb198572..f1812c20dcc 100644 --- a/src/librustc_target/lib.rs +++ b/src/librustc_target/lib.rs @@ -16,6 +16,7 @@ #![feature(step_trait)] #![deny(rust_2018_idioms)] +#![cfg_attr(not(stage0), deny(internal))] #[macro_use] extern crate log; diff --git a/src/librustc_target/spec/wasm32_base.rs b/src/librustc_target/spec/wasm32_base.rs index c7e75b4fa09..edaf902c130 100644 --- a/src/librustc_target/spec/wasm32_base.rs +++ b/src/librustc_target/spec/wasm32_base.rs @@ -118,6 +118,15 @@ pub fn options() -> TargetOptions { pre_link_args, + // This has no effect in LLVM 8 or prior, but in LLVM 9 and later when + // PIC code is implemented this has quite a drastric effect if it stays + // at the default, `pic`. In an effort to keep wasm binaries as minimal + // as possible we're defaulting to `static` for now, but the hope is + // that eventually we can ship a `pic`-compatible standard library which + // works with `static` as well (or works with some method of generating + // non-relative calls and such later on). + relocation_model: "static".to_string(), + .. Default::default() } } diff --git a/src/librustc_target/spec/x86_64_fortanix_unknown_sgx.rs b/src/librustc_target/spec/x86_64_fortanix_unknown_sgx.rs index 7c369daa2a8..46cf4cd8ae3 100644 --- a/src/librustc_target/spec/x86_64_fortanix_unknown_sgx.rs +++ b/src/librustc_target/spec/x86_64_fortanix_unknown_sgx.rs @@ -21,6 +21,15 @@ pub fn target() -> Result<Target, String> { "-Wl,--no-undefined-version", "-Wl,-Bsymbolic", "-Wl,--export-dynamic", + // The following symbols are needed by libunwind, which is linked after + // libstd. Make sure they're included in the link. + "-Wl,-u,__rust_abort", + "-Wl,-u,__rust_c_alloc", + "-Wl,-u,__rust_c_dealloc", + "-Wl,-u,__rust_print_err", + "-Wl,-u,__rust_rwlock_rdlock", + "-Wl,-u,__rust_rwlock_unlock", + "-Wl,-u,__rust_rwlock_wrlock", ]; const EXPORT_SYMBOLS: &[&str] = &[ diff --git a/src/librustc_target/spec/x86_64_unknown_linux_gnux32.rs b/src/librustc_target/spec/x86_64_unknown_linux_gnux32.rs index 0b2d7aacc4d..73151b194de 100644 --- a/src/librustc_target/spec/x86_64_unknown_linux_gnux32.rs +++ b/src/librustc_target/spec/x86_64_unknown_linux_gnux32.rs @@ -5,7 +5,8 @@ pub fn target() -> TargetResult { base.cpu = "x86-64".to_string(); base.max_atomic_width = Some(64); base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-mx32".to_string()); - base.stack_probes = true; + // BUG: temporarily workaround #59674 + base.stack_probes = false; base.has_elf_tls = false; // BUG(GabrielMajeri): disabling the PLT on x86_64 Linux with x32 ABI // breaks code gen. See LLVM bug 36743 diff --git a/src/librustc_traits/lib.rs b/src/librustc_traits/lib.rs index d52a976981d..bc034e1fb16 100644 --- a/src/librustc_traits/lib.rs +++ b/src/librustc_traits/lib.rs @@ -2,6 +2,7 @@ //! the guts are broken up into modules; see the comments in those modules. #![deny(rust_2018_idioms)] +#![cfg_attr(not(stage0), deny(internal))] #![feature(crate_visibility_modifier)] #![feature(in_band_lifetimes)] diff --git a/src/librustc_tsan/Cargo.toml b/src/librustc_tsan/Cargo.toml index d805833a7ef..82045dd0cdd 100644 --- a/src/librustc_tsan/Cargo.toml +++ b/src/librustc_tsan/Cargo.toml @@ -12,7 +12,7 @@ test = false [build-dependencies] build_helper = { path = "../build_helper" } -cmake = "0.1.18" +cmake = "0.1.38" [dependencies] alloc = { path = "../liballoc" } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index fba4414c127..0c206b27f80 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -99,11 +99,6 @@ enum GenericArgPosition { MethodCall, } -/// Dummy type used for the `Self` of a `TraitRef` created for converting -/// a trait object, and which gets removed in `ExistentialTraitRef`. -/// This type must not appear anywhere in other converted types. -const TRAIT_OBJECT_DUMMY_SELF: ty::TyKind<'static> = ty::Infer(ty::FreshTy(0)); - impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { pub fn ast_region_to_region(&self, lifetime: &hir::Lifetime, @@ -595,7 +590,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { infer_types, ); - let is_object = self_ty.map_or(false, |ty| ty.sty == TRAIT_OBJECT_DUMMY_SELF); + let is_object = self_ty.map_or(false, |ty| { + ty == self.tcx().types.trait_object_dummy_self + }); let default_needs_object_self = |param: &ty::GenericParamDef| { if let GenericParamDefKind::Type { has_default, .. } = param.kind { if is_object && has_default { @@ -956,10 +953,10 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { } /// Transform a `PolyTraitRef` into a `PolyExistentialTraitRef` by - /// removing the dummy `Self` type (`TRAIT_OBJECT_DUMMY_SELF`). + /// removing the dummy `Self` type (`trait_object_dummy_self`). fn trait_ref_to_existential(&self, trait_ref: ty::TraitRef<'tcx>) -> ty::ExistentialTraitRef<'tcx> { - if trait_ref.self_ty().sty != TRAIT_OBJECT_DUMMY_SELF { + if trait_ref.self_ty() != self.tcx().types.trait_object_dummy_self { bug!("trait_ref_to_existential called on {:?} with non-dummy Self", trait_ref); } ty::ExistentialTraitRef::erase_self_ty(self.tcx(), trait_ref) @@ -980,7 +977,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { } let mut projection_bounds = Vec::new(); - let dummy_self = tcx.mk_ty(TRAIT_OBJECT_DUMMY_SELF); + let dummy_self = self.tcx().types.trait_object_dummy_self; let (principal, potential_assoc_types) = self.instantiate_poly_trait_ref( &trait_bounds[0], dummy_self, @@ -1030,7 +1027,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { } ty::Predicate::Projection(pred) => { // A `Self` within the original bound will be substituted with a - // `TRAIT_OBJECT_DUMMY_SELF`, so check for that. + // `trait_object_dummy_self`, so check for that. let references_self = pred.skip_binder().ty.walk().any(|t| t == dummy_self); @@ -1130,7 +1127,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { err.emit(); } - // Erase the `dummy_self` (`TRAIT_OBJECT_DUMMY_SELF`) used above. + // Erase the `dummy_self` (`trait_object_dummy_self`) used above. let existential_principal = principal.map_bound(|trait_ref| { self.trait_ref_to_existential(trait_ref) }); @@ -1365,12 +1362,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { let msg = format!("expected type, found variant `{}`", assoc_ident); tcx.sess.span_err(span, &msg); } else if qself_ty.is_enum() { - // Report as incorrect enum variant rather than ambiguous type. let mut err = tcx.sess.struct_span_err( - span, - &format!("no variant `{}` on enum `{}`", &assoc_ident.as_str(), qself_ty), + assoc_ident.span, + &format!("no variant `{}` in enum `{}`", assoc_ident, qself_ty), ); - // Check if it was a typo. + let adt_def = qself_ty.ty_adt_def().expect("enum is not an ADT"); if let Some(suggested_name) = find_best_match_for_name( adt_def.variants.iter().map(|variant| &variant.ident.name), @@ -1378,14 +1374,20 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { None, ) { err.span_suggestion( - span, - "did you mean", - format!("{}::{}", qself_ty, suggested_name), + assoc_ident.span, + "there is a variant with a similar name", + suggested_name.to_string(), Applicability::MaybeIncorrect, ); } else { - err.span_label(span, "unknown variant"); + err.span_label(span, format!("variant not found in `{}`", qself_ty)); } + + if let Some(sp) = tcx.hir().span_if_local(adt_def.did) { + let sp = tcx.sess.source_map().def_span(sp); + err.span_label(sp, format!("variant `{}` not found here", assoc_ident)); + } + err.emit(); } else if !qself_ty.references_error() { // Don't print `TyErr` to the user. diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index affd3a2d16a..032821e6d42 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -732,6 +732,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); source: match_src, prior_arms: other_arms.clone(), last_ty: prior_arm_ty.unwrap(), + discrim_hir_id: discrim.hir_id, }) }; coercion.coerce(self, &cause, &arm.body, arm_ty); diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 40dd6217335..42156213f21 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -896,20 +896,36 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { let trait_substs = self.fresh_item_substs(trait_def_id); let trait_ref = ty::TraitRef::new(trait_def_id, trait_substs); - for item in self.impl_or_trait_item(trait_def_id) { - // Check whether `trait_def_id` defines a method with suitable name: - if !self.has_applicable_self(&item) { - debug!("method has inapplicable self"); - self.record_static_candidate(TraitSource(trait_def_id)); - continue; - } + if self.tcx.is_trait_alias(trait_def_id) { + // For trait aliases, assume all super-traits are relevant. + let bounds = iter::once(trait_ref.to_poly_trait_ref()); + self.elaborate_bounds(bounds, |this, new_trait_ref, item| { + let new_trait_ref = this.erase_late_bound_regions(&new_trait_ref); + + let (xform_self_ty, xform_ret_ty) = + this.xform_self_ty(&item, new_trait_ref.self_ty(), new_trait_ref.substs); + this.push_candidate(Candidate { + xform_self_ty, xform_ret_ty, item, import_id, + kind: TraitCandidate(new_trait_ref), + }, true); + }); + } else { + debug_assert!(self.tcx.is_trait(trait_def_id)); + for item in self.impl_or_trait_item(trait_def_id) { + // Check whether `trait_def_id` defines a method with suitable name. + if !self.has_applicable_self(&item) { + debug!("method has inapplicable self"); + self.record_static_candidate(TraitSource(trait_def_id)); + continue; + } - let (xform_self_ty, xform_ret_ty) = - self.xform_self_ty(&item, trait_ref.self_ty(), trait_substs); - self.push_candidate(Candidate { - xform_self_ty, xform_ret_ty, item, import_id, - kind: TraitCandidate(trait_ref), - }, false); + let (xform_self_ty, xform_ret_ty) = + self.xform_self_ty(&item, trait_ref.self_ty(), trait_substs); + self.push_candidate(Candidate { + xform_self_ty, xform_ret_ty, item, import_id, + kind: TraitCandidate(trait_ref), + }, false); + } } Ok(()) } @@ -930,7 +946,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { .filter(|&name| set.insert(name)) .collect(); - // sort them by the name so we have a stable result + // Sort them by the name so we have a stable result. names.sort_by_cached_key(|n| n.as_str()); names } @@ -945,6 +961,8 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { return r; } + debug!("pick: actual search failed, assemble diagnotics"); + let static_candidates = mem::replace(&mut self.static_candidates, vec![]); let private_candidate = self.private_candidate.take(); let unsatisfied_predicates = mem::replace(&mut self.unsatisfied_predicates, vec![]); diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index fde0e47650d..31b7724d638 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -14,11 +14,11 @@ use rustc::hir::map as hir_map; use rustc::hir::print; use rustc::infer::type_variable::TypeVariableOrigin; use rustc::traits::Obligation; -use rustc::ty::{self, Adt, Ty, TyCtxt, ToPolyTraitRef, ToPredicate, TypeFoldable}; +use rustc::ty::{self, Ty, TyCtxt, ToPolyTraitRef, ToPredicate, TypeFoldable}; use rustc::ty::print::with_crate_prefix; use syntax_pos::{Span, FileName}; use syntax::ast; -use syntax::util::lev_distance::find_best_match_for_name; +use syntax::util::lev_distance; use std::cmp::Ordering; @@ -188,17 +188,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let actual = self.resolve_type_vars_if_possible(&rcvr_ty); let ty_str = self.ty_to_string(actual); let is_method = mode == Mode::MethodCall; - let mut suggestion = None; let item_kind = if is_method { "method" } else if actual.is_enum() { - if let Adt(ref adt_def, _) = actual.sty { - let names = adt_def.variants.iter().map(|s| &s.ident.name); - suggestion = find_best_match_for_name(names, - &item_name.as_str(), - None); - } - "variant" + "variant or associated item" } else { match (item_name.as_str().chars().next(), actual.is_fresh_ty()) { (Some(name), false) if name.is_lowercase() => { @@ -299,7 +292,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { return; } else { span = item_name.span; - let mut err = struct_span_err!( + struct_span_err!( tcx.sess, span, E0599, @@ -307,17 +300,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { item_kind, item_name, ty_str - ); - if let Some(suggestion) = suggestion { - // enum variant - err.span_suggestion( - span, - "did you mean", - suggestion.to_string(), - Applicability::MaybeIncorrect, - ); - } - err + ) } } else { tcx.sess.diagnostic().struct_dummy() @@ -469,14 +452,36 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { out_of_scope_traits); } + if actual.is_enum() { + let adt_def = actual.ty_adt_def().expect("enum is not an ADT"); + if let Some(suggestion) = lev_distance::find_best_match_for_name( + adt_def.variants.iter().map(|s| &s.ident.name), + &item_name.as_str(), + None, + ) { + err.span_suggestion( + span, + "there is a variant with a similar name", + suggestion.to_string(), + Applicability::MaybeIncorrect, + ); + } + } + if let Some(lev_candidate) = lev_candidate { + let def = lev_candidate.def(); err.span_suggestion( span, - "did you mean", + &format!( + "there is {} {} with a similar name", + def.article(), + def.kind_name(), + ), lev_candidate.ident.to_string(), Applicability::MaybeIncorrect, ); } + err.emit(); } @@ -757,9 +762,13 @@ fn compute_all_traits<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Vec<DefId> impl<'v, 'a, 'tcx> itemlikevisit::ItemLikeVisitor<'v> for Visitor<'a, 'tcx> { fn visit_item(&mut self, i: &'v hir::Item) { - if let hir::ItemKind::Trait(..) = i.node { - let def_id = self.map.local_def_id_from_hir_id(i.hir_id); - self.traits.push(def_id); + match i.node { + hir::ItemKind::Trait(..) | + hir::ItemKind::TraitAlias(..) => { + let def_id = self.map.local_def_id_from_hir_id(i.hir_id); + self.traits.push(def_id); + } + _ => () } } @@ -781,7 +790,8 @@ fn compute_all_traits<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Vec<DefId> external_mods: &mut FxHashSet<DefId>, def: Def) { match def { - Def::Trait(def_id) => { + Def::Trait(def_id) | + Def::TraitAlias(def_id) => { traits.push(def_id); } Def::Mod(def_id) => { diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index d6932094ddd..d2fe099e433 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -3,7 +3,7 @@ use super::{FnCtxt, Needs}; use super::method::MethodCallee; use rustc::ty::{self, Ty, TypeFoldable}; -use rustc::ty::TyKind::{Ref, Adt, Str, Uint, Never, Tuple, Char, Array}; +use rustc::ty::TyKind::{Ref, Adt, FnDef, Str, Uint, Never, Tuple, Char, Array}; use rustc::ty::adjustment::{Adjustment, Adjust, AllowTwoPhase, AutoBorrow, AutoBorrowMutability}; use rustc::infer::type_variable::TypeVariableOrigin; use errors::{self,Applicability}; @@ -333,8 +333,22 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { lhs_ty); if !lhs_expr.span.eq(&rhs_expr.span) { - err.span_label(lhs_expr.span, lhs_ty.to_string()); - err.span_label(rhs_expr.span, rhs_ty.to_string()); + self.add_type_neq_err_label( + &mut err, + lhs_expr.span, + lhs_ty, + rhs_ty, + op, + is_assign + ); + self.add_type_neq_err_label( + &mut err, + rhs_expr.span, + rhs_ty, + lhs_ty, + op, + is_assign + ); } let mut suggested_deref = false; @@ -415,6 +429,62 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { (lhs_ty, rhs_ty, return_ty) } + fn add_type_neq_err_label( + &self, + err: &mut errors::DiagnosticBuilder<'_>, + span: Span, + ty: Ty<'tcx>, + other_ty: Ty<'tcx>, + op: hir::BinOp, + is_assign: IsAssign, + ) { + err.span_label(span, ty.to_string()); + if let FnDef(def_id, _) = ty.sty { + let source_map = self.tcx.sess.source_map(); + let hir_id = &self.tcx.hir().as_local_hir_id(def_id).unwrap(); + let fn_sig = { + match self.tcx.typeck_tables_of(def_id).liberated_fn_sigs().get(*hir_id) { + Some(f) => f.clone(), + None => { + bug!("No fn-sig entry for def_id={:?}", def_id); + } + } + }; + + let other_ty = if let FnDef(def_id, _) = other_ty.sty { + let hir_id = &self.tcx.hir().as_local_hir_id(def_id).unwrap(); + match self.tcx.typeck_tables_of(def_id).liberated_fn_sigs().get(*hir_id) { + Some(f) => f.clone().output(), + None => { + bug!("No fn-sig entry for def_id={:?}", def_id); + } + } + } else { + other_ty + }; + + if self.lookup_op_method(fn_sig.output(), + &[other_ty], + Op::Binary(op, is_assign)) + .is_ok() { + let (variable_snippet, applicability) = if fn_sig.inputs().len() > 0 { + (format!("{}( /* arguments */ )", source_map.span_to_snippet(span).unwrap()), + Applicability::HasPlaceholders) + } else { + (format!("{}()", source_map.span_to_snippet(span).unwrap()), + Applicability::MaybeIncorrect) + }; + + err.span_suggestion( + span, + "you might have forgotten to call this function", + variable_snippet, + applicability, + ); + } + } + } + fn check_str_addition( &self, expr: &'gcx hir::Expr, diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 3579810b8d7..d108e7c3107 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -3,7 +3,7 @@ use crate::constrained_generic_params::{identify_constrained_generic_params, Par use crate::hir::def_id::DefId; use rustc::traits::{self, ObligationCauseCode}; -use rustc::ty::{self, Lift, Ty, TyCtxt, TyKind, GenericParamDefKind, TypeFoldable, ToPredicate}; +use rustc::ty::{self, Lift, Ty, TyCtxt, GenericParamDefKind, TypeFoldable, ToPredicate}; use rustc::ty::subst::{Subst, InternalSubsts}; use rustc::util::nodemap::{FxHashSet, FxHashMap}; use rustc::mir::interpret::ConstValue; @@ -354,7 +354,7 @@ fn check_item_type<'a, 'tcx>( let mut forbid_unsized = true; if allow_foreign_ty { - if let TyKind::Foreign(_) = fcx.tcx.struct_tail(item_ty).sty { + if let ty::Foreign(_) = fcx.tcx.struct_tail(item_ty).sty { forbid_unsized = false; } } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 5edb8c92a3b..0cd7fe91594 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1918,7 +1918,10 @@ fn explicit_predicates_of<'a, 'tcx>( } } - let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); + let hir_id = match tcx.hir().as_local_hir_id(def_id) { + Some(hir_id) => hir_id, + None => return tcx.predicates_of(def_id), + }; let node = tcx.hir().get_by_hir_id(hir_id); let mut is_trait = None; @@ -1979,6 +1982,7 @@ fn explicit_predicates_of<'a, 'tcx>( ref bounds, impl_trait_fn, ref generics, + origin: _, }) => { let substs = InternalSubsts::identity_for_item(tcx, def_id); let opaque_ty = tcx.mk_opaque(def_id, substs); diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 1fa16352b86..21d1af229dd 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -71,6 +71,7 @@ This API is completely unstable and subject to change. #![recursion_limit="256"] #![deny(rust_2018_idioms)] +#![cfg_attr(not(stage0), deny(internal))] #![allow(explicit_outlives_requirements)] #[macro_use] extern crate log; @@ -108,7 +109,6 @@ use rustc::ty::subst::SubstsRef; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::query::Providers; use rustc::util; -use rustc::util::profiling::ProfileCategory; use syntax_pos::Span; use util::common::time; @@ -318,7 +318,7 @@ pub fn provide(providers: &mut Providers<'_>) { pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Result<(), ErrorReported> { - tcx.sess.profiler(|p| p.start_activity(ProfileCategory::TypeChecking, "type-check crate")); + tcx.sess.profiler(|p| p.start_activity("type-check crate")); // this ensures that later parts of type checking can assume that items // have valid types and not error @@ -369,7 +369,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) check_unused::check_crate(tcx); check_for_entry_fn(tcx); - tcx.sess.profiler(|p| p.end_activity(ProfileCategory::TypeChecking, "type-check crate")); + tcx.sess.profiler(|p| p.end_activity("type-check crate")); if tcx.sess.err_count() == 0 { Ok(()) @@ -378,7 +378,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) } } -/// A quasi-deprecated helper used in rustdoc and save-analysis to get +/// A quasi-deprecated helper used in rustdoc and clippy to get /// the type from a HIR node. pub fn hir_ty_to_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, hir_ty: &hir::Ty) -> Ty<'tcx> { // In case there are any projections etc, find the "environment" diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index a8c9166591d..4d2c03a4f2f 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -10,6 +10,6 @@ path = "lib.rs" [dependencies] pulldown-cmark = { version = "0.1.2", default-features = false } -minifier = "0.0.28" +minifier = "0.0.29" tempfile = "3" parking_lot = "0.7" diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index adbe73b165e..555cb1bd64f 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -568,7 +568,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { (replaced.clone(), replaced.clean(self.cx)) }); - let full_generics = (&type_generics, &tcx.predicates_of(did)); + let full_generics = (&type_generics, &tcx.explicit_predicates_of(did)); let Generics { params: mut generic_params, .. diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index aaae0bafd9e..570c61f1ffc 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -132,7 +132,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { .collect(); let ty = self.cx.get_real_ty(def_id, def_ctor, &real_name, generics); - let predicates = infcx.tcx.predicates_of(impl_def_id); + let predicates = infcx.tcx.explicit_predicates_of(impl_def_id); impls.push(Item { source: infcx.tcx.def_span(impl_def_id).clean(self.cx), diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index d9a63969fec..8da71cf708a 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -228,7 +228,7 @@ fn build_external_function(cx: &DocContext<'_>, did: DefId) -> clean::Function { } fn build_enum(cx: &DocContext<'_>, did: DefId) -> clean::Enum { - let predicates = cx.tcx.predicates_of(did); + let predicates = cx.tcx.explicit_predicates_of(did); clean::Enum { generics: (cx.tcx.generics_of(did), &predicates).clean(cx), @@ -238,7 +238,7 @@ fn build_enum(cx: &DocContext<'_>, did: DefId) -> clean::Enum { } fn build_struct(cx: &DocContext<'_>, did: DefId) -> clean::Struct { - let predicates = cx.tcx.predicates_of(did); + let predicates = cx.tcx.explicit_predicates_of(did); let variant = cx.tcx.adt_def(did).non_enum_variant(); clean::Struct { @@ -254,7 +254,7 @@ fn build_struct(cx: &DocContext<'_>, did: DefId) -> clean::Struct { } fn build_union(cx: &DocContext<'_>, did: DefId) -> clean::Union { - let predicates = cx.tcx.predicates_of(did); + let predicates = cx.tcx.explicit_predicates_of(did); let variant = cx.tcx.adt_def(did).non_enum_variant(); clean::Union { @@ -266,7 +266,7 @@ fn build_union(cx: &DocContext<'_>, did: DefId) -> clean::Union { } fn build_type_alias(cx: &DocContext<'_>, did: DefId) -> clean::Typedef { - let predicates = cx.tcx.predicates_of(did); + let predicates = cx.tcx.explicit_predicates_of(did); clean::Typedef { type_: cx.tcx.type_of(did).clean(cx), @@ -325,7 +325,7 @@ pub fn build_impl(cx: &DocContext<'_>, did: DefId, ret: &mut Vec<clean::Item>) { } } - let predicates = tcx.predicates_of(did); + let predicates = tcx.explicit_predicates_of(did); let (trait_items, generics) = if let Some(hir_id) = tcx.hir().as_local_hir_id(did) { match tcx.hir().expect_item_by_hir_id(hir_id).node { hir::ItemKind::Impl(.., ref gen, _, _, ref item_ids) => { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 27ffe4583df..e994c661fdc 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2288,7 +2288,7 @@ impl<'tcx> Clean<Item> for ty::AssociatedItem { } ty::AssociatedKind::Method => { let generics = (cx.tcx.generics_of(self.def_id), - &cx.tcx.predicates_of(self.def_id)).clean(cx); + &cx.tcx.explicit_predicates_of(self.def_id)).clean(cx); let sig = cx.tcx.fn_sig(self.def_id); let mut decl = (self.def_id, sig).clean(cx); @@ -2361,7 +2361,7 @@ impl<'tcx> Clean<Item> for ty::AssociatedItem { // are actually located on the trait/impl itself, so we need to load // all of the generics from there and then look for bounds that are // applied to this associated type in question. - let predicates = cx.tcx.predicates_of(did); + let predicates = cx.tcx.explicit_predicates_of(did); let generics = (cx.tcx.generics_of(did), &predicates).clean(cx); let mut bounds = generics.where_predicates.iter().filter_map(|pred| { let (name, self_type, trait_, bounds) = match *pred { @@ -3069,7 +3069,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> { ty::Opaque(def_id, substs) => { // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`, // by looking up the projections associated with the def_id. - let predicates_of = cx.tcx.predicates_of(def_id); + let predicates_of = cx.tcx.explicit_predicates_of(def_id); let substs = cx.tcx.lift(&substs).expect("Opaque lift failed"); let bounds = predicates_of.instantiate(cx.tcx, substs); let mut regions = vec![]; diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index 6ff3917a265..acf019fd225 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -157,11 +157,11 @@ pub fn render<T: fmt::Display, S: fmt::Display>( window.rootPath = \"{root_path}\";\ window.currentCrate = \"{krate}\";\ </script>\ - <script src=\"{root_path}aliases.js\"></script>\ + <script src=\"{root_path}aliases{suffix}.js\"></script>\ <script src=\"{static_root_path}main{suffix}.js\"></script>\ {static_extra_scripts}\ {extra_scripts}\ - <script defer src=\"{root_path}search-index.js\"></script>\ + <script defer src=\"{root_path}search-index{suffix}.js\"></script>\ </body>\ </html>", css_extension = if css_file_extension { diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index f7e8cdeaeca..3ee131d8f5c 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -965,7 +965,11 @@ themePicker.onblur = handleThemeButtonsBlur; if for_search_index && line.starts_with("var R") { variables.push(line.clone()); // We need to check if the crate name has been put into a variable as well. - let tokens = js::simple_minify(&line).apply(js::clean_tokens); + let tokens: js::Tokens<'_> = js::simple_minify(&line) + .into_iter() + .filter(js::clean_token) + .collect::<Vec<_>>() + .into(); let mut pos = 0; while pos < tokens.len() { if let Some((var_pos, Some(value_pos))) = @@ -1009,7 +1013,7 @@ themePicker.onblur = handleThemeButtonsBlur; }) } - let dst = cx.dst.join("aliases.js"); + let dst = cx.dst.join(&format!("aliases{}.js", cx.shared.resource_suffix)); { let (mut all_aliases, _, _) = try_err!(collect(&dst, &krate.name, "ALIASES", false), &dst); let mut w = try_err!(File::create(&dst), &dst); @@ -1060,11 +1064,22 @@ themePicker.onblur = handleThemeButtonsBlur; .expect("invalid osstring conversion"))) .collect::<Vec<_>>(); files.sort_unstable_by(|a, b| a.cmp(b)); - // FIXME(imperio): we could avoid to generate "dirs" and "files" if they're empty. - format!("{{\"name\":\"{name}\",\"dirs\":[{subs}],\"files\":[{files}]}}", + let subs = subs.iter().map(|s| s.to_json_string()).collect::<Vec<_>>().join(","); + let dirs = if subs.is_empty() { + String::new() + } else { + format!(",\"dirs\":[{}]", subs) + }; + let files = files.join(","); + let files = if files.is_empty() { + String::new() + } else { + format!(",\"files\":[{}]", files) + }; + format!("{{\"name\":\"{name}\"{dirs}{files}}}", name=self.elem.to_str().expect("invalid osstring conversion"), - subs=subs.iter().map(|s| s.to_json_string()).collect::<Vec<_>>().join(","), - files=files.join(",")) + dirs=dirs, + files=files) } } @@ -1095,7 +1110,7 @@ themePicker.onblur = handleThemeButtonsBlur; } } - let dst = cx.dst.join("source-files.js"); + let dst = cx.dst.join(&format!("source-files{}.js", cx.shared.resource_suffix)); let (mut all_sources, _krates, _) = try_err!(collect(&dst, &krate.name, "sourcesIndex", false), &dst); @@ -1111,7 +1126,7 @@ themePicker.onblur = handleThemeButtonsBlur; } // Update the search index - let dst = cx.dst.join("search-index.js"); + let dst = cx.dst.join(&format!("search-index{}.js", cx.shared.resource_suffix)); let (mut all_indexes, mut krates, variables) = try_err!(collect(&dst, &krate.name, "searchIndex", @@ -1288,46 +1303,51 @@ fn write_minify_replacer<W: Write>( contents: &str, enable_minification: bool, ) -> io::Result<()> { - use minifier::js::{Keyword, ReservedChar, Token}; + use minifier::js::{simple_minify, Keyword, ReservedChar, Token, Tokens}; if enable_minification { writeln!(dst, "{}", - minifier::js::simple_minify(contents) - .apply(|f| { - // We keep backlines. - minifier::js::clean_tokens_except(f, |c| { - c.get_char() != Some(ReservedChar::Backline) - }) - }) - .apply(|f| { - minifier::js::replace_token_with(f, |t| { - match *t { - Token::Keyword(Keyword::Null) => Some(Token::Other("N")), - Token::String(s) => { - let s = &s[1..s.len() -1]; // The quotes are included - if s.is_empty() { - Some(Token::Other("E")) - } else if s == "t" { - Some(Token::Other("T")) - } else if s == "u" { - Some(Token::Other("U")) - } else { - None - } - } - _ => None, - } - }) - }) - .apply(|f| { - // We add a backline after the newly created variables. - minifier::js::aggregate_strings_into_array_with_separation( - f, - "R", - Token::Char(ReservedChar::Backline), - ) - }) - .to_string()) + { + let tokens: Tokens<'_> = simple_minify(contents) + .into_iter() + .filter(|f| { + // We keep backlines. + minifier::js::clean_token_except(f, &|c: &Token<'_>| { + c.get_char() != Some(ReservedChar::Backline) + }) + }) + .map(|f| { + minifier::js::replace_token_with(f, &|t: &Token<'_>| { + match *t { + Token::Keyword(Keyword::Null) => Some(Token::Other("N")), + Token::String(s) => { + let s = &s[1..s.len() -1]; // The quotes are included + if s.is_empty() { + Some(Token::Other("E")) + } else if s == "t" { + Some(Token::Other("T")) + } else if s == "u" { + Some(Token::Other("U")) + } else { + None + } + } + _ => None, + } + }) + }) + .collect::<Vec<_>>() + .into(); + tokens.apply(|f| { + // We add a backline after the newly created variables. + minifier::js::aggregate_strings_into_array_with_separation( + f, + "R", + Token::Char(ReservedChar::Backline), + ) + }) + .to_string() + }) } else { writeln!(dst, "{}", contents) } @@ -1474,7 +1494,7 @@ impl<'a> SourceCollector<'a> { description: &desc, keywords: BASIC_KEYWORDS, resource_suffix: &self.scx.resource_suffix, - extra_scripts: &["source-files"], + extra_scripts: &[&format!("source-files{}", self.scx.resource_suffix)], static_extra_scripts: &[&format!("source-script{}", self.scx.resource_suffix)], }; layout::render(&mut w, &self.scx.layout, @@ -3127,7 +3147,6 @@ fn item_trait( // FIXME: we should be using a derived_id for the Anchors here write!(w, "{{\n")?; for t in &types { - write!(w, " ")?; render_assoc_item(w, t, AssocItemLink::Anchor(None), ItemType::Trait)?; write!(w, ";\n")?; } @@ -3135,7 +3154,6 @@ fn item_trait( w.write_str("\n")?; } for t in &consts { - write!(w, " ")?; render_assoc_item(w, t, AssocItemLink::Anchor(None), ItemType::Trait)?; write!(w, ";\n")?; } @@ -3143,7 +3161,6 @@ fn item_trait( w.write_str("\n")?; } for (pos, m) in required.iter().enumerate() { - write!(w, " ")?; render_assoc_item(w, m, AssocItemLink::Anchor(None), ItemType::Trait)?; write!(w, ";\n")?; @@ -3155,7 +3172,6 @@ fn item_trait( w.write_str("\n")?; } for (pos, m) in provided.iter().enumerate() { - write!(w, " ")?; render_assoc_item(w, m, AssocItemLink::Anchor(None), ItemType::Trait)?; match m.inner { clean::MethodItem(ref inner) if !inner.generics.where_predicates.is_empty() => { @@ -3464,8 +3480,9 @@ fn render_assoc_item(w: &mut fmt::Formatter<'_>, (0, true) }; render_attributes(w, meth)?; - write!(w, "{}{}{}{}{}{}fn <a href='{href}' class='fnname'>{name}</a>\ + write!(w, "{}{}{}{}{}{}{}fn <a href='{href}' class='fnname'>{name}</a>\ {generics}{decl}{where_clause}", + if parent == ItemType::Trait { " " } else { "" }, VisSpace(&meth.visibility), ConstnessSpace(header.constness), UnsafetySpace(header.unsafety), @@ -3766,7 +3783,7 @@ const ATTRIBUTE_WHITELIST: &'static [&'static str] = &[ "non_exhaustive" ]; -fn render_attributes(w: &mut fmt::Formatter<'_>, it: &clean::Item) -> fmt::Result { +fn render_attributes(w: &mut dyn fmt::Write, it: &clean::Item) -> fmt::Result { let mut attrs = String::new(); for attr in &it.attrs.other_attrs { diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 412029cf376..00ca78b749e 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -930,10 +930,10 @@ if (!DOMTokenList.prototype.remove) { returned = checkReturned(ty, output, true); if (output.name === "*" || returned === true) { in_args = false; - var module = false; + var is_module = false; if (input === "*") { - module = true; + is_module = true; } else { var allFound = true; for (var it = 0; allFound === true && it < inputs.length; it++) { @@ -955,7 +955,7 @@ if (!DOMTokenList.prototype.remove) { dontValidate: true, }; } - if (module === true) { + if (is_module === true) { results[fullId] = { id: i, index: -1, @@ -1073,6 +1073,10 @@ if (!DOMTokenList.prototype.remove) { if (index !== -1 || lev <= MAX_LEV_DISTANCE) { if (index !== -1 && paths.length < 2) { lev = 0; + } else if (searchWords[j] === val) { + // Small trick to fix when you're looking for a one letter type + // and there are other short named types. + lev = -1; } if (results[fullId] === undefined) { results[fullId] = { diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 5314255ac32..2228e58b0d2 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -1577,3 +1577,17 @@ div.name.expand::before { left: -15px; top: 2px; } + +/* This part is to fix the "Expand attributes" part in the type declaration. */ +.type-decl > pre > :first-child { + margin-left: 0 !important; +} +.type-decl > pre > :nth-child(2) { + margin-left: 1.8em !important; +} +.type-decl > pre > .toggle-attributes { + margin-left: 2.2em; +} +.type-decl > pre > .docblock.attributes { + margin-left: 4em; +} diff --git a/src/librustdoc/html/static/source-script.js b/src/librustdoc/html/static/source-script.js index 509c628ce5a..567022b4139 100644 --- a/src/librustdoc/html/static/source-script.js +++ b/src/librustdoc/html/static/source-script.js @@ -39,28 +39,32 @@ function createDirEntry(elem, parent, fullPath, currentFile, hasFoundFile) { children.className = "children"; var folders = document.createElement("div"); folders.className = "folders"; - for (var i = 0; i < elem.dirs.length; ++i) { - if (createDirEntry(elem.dirs[i], folders, fullPath, currentFile, - hasFoundFile) === true) { - addClass(name, "expand"); - hasFoundFile = true; + if (elem.dirs) { + for (var i = 0; i < elem.dirs.length; ++i) { + if (createDirEntry(elem.dirs[i], folders, fullPath, currentFile, + hasFoundFile) === true) { + addClass(name, "expand"); + hasFoundFile = true; + } } } children.appendChild(folders); var files = document.createElement("div"); files.className = "files"; - for (i = 0; i < elem.files.length; ++i) { - var file = document.createElement("a"); - file.innerText = elem.files[i]; - file.href = window.rootPath + "src/" + fullPath + elem.files[i] + ".html"; - if (hasFoundFile === false && - currentFile === fullPath + elem.files[i]) { - file.className = "selected"; - addClass(name, "expand"); - hasFoundFile = true; + if (elem.files) { + for (i = 0; i < elem.files.length; ++i) { + var file = document.createElement("a"); + file.innerText = elem.files[i]; + file.href = window.rootPath + "src/" + fullPath + elem.files[i] + ".html"; + if (hasFoundFile === false && + currentFile === fullPath + elem.files[i]) { + file.className = "selected"; + addClass(name, "expand"); + hasFoundFile = true; + } + files.appendChild(file); } - files.appendChild(file); } search.fullPath = fullPath; children.appendChild(files); diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 2ebb465d53d..6cb937d9216 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -1,4 +1,5 @@ #![deny(rust_2018_idioms)] +#![cfg_attr(not(stage0), deny(internal))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/", html_playground_url = "https://play.rust-lang.org/")] diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index ee182237b49..dbc55b62ef8 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -196,6 +196,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { _ => Err(()) } } else { + debug!("attempting to resolve item without parent module: {}", path_str); Err(()) } } @@ -404,6 +405,15 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { self.fold_item_recur(item) } } + + // FIXME: if we can resolve intra-doc links from other crates, we can use the stock + // `fold_crate`, but until then we should avoid scanning `krate.external_traits` since those + // will never resolve properly + fn fold_crate(&mut self, mut c: Crate) -> Crate { + c.module = c.module.take().and_then(|module| self.fold_item(module)); + + c + } } /// Resolves a string as a macro. diff --git a/src/libserialize/serialize.rs b/src/libserialize/serialize.rs index cf948078b08..8ef8c2b4c0a 100644 --- a/src/libserialize/serialize.rs +++ b/src/libserialize/serialize.rs @@ -911,4 +911,5 @@ impl<T: UseSpecializedDecodable> Decodable for T { impl<'a, T: ?Sized + Encodable> UseSpecializedEncodable for &'a T {} impl<T: ?Sized + Encodable> UseSpecializedEncodable for Box<T> {} impl<T: Decodable> UseSpecializedDecodable for Box<T> {} - +impl<'a, T: Decodable> UseSpecializedDecodable for &'a T {} +impl<'a, T: Decodable> UseSpecializedDecodable for &'a [T] {} diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml index 9ac03adfc27..86ad334d886 100644 --- a/src/libstd/Cargo.toml +++ b/src/libstd/Cargo.toml @@ -19,7 +19,7 @@ panic_unwind = { path = "../libpanic_unwind", optional = true } panic_abort = { path = "../libpanic_abort" } core = { path = "../libcore" } libc = { version = "0.2.51", default-features = false, features = ['rustc-dep-of-std'] } -compiler_builtins = { version = "0.1.8" } +compiler_builtins = { version = "0.1.9" } profiler_builtins = { path = "../libprofiler_builtins", optional = true } unwind = { path = "../libunwind" } rustc-demangle = { version = "0.1.10", features = ['rustc-dep-of-std'] } @@ -54,6 +54,7 @@ backtrace = ["backtrace-sys"] panic-unwind = ["panic_unwind"] profiler = ["profiler_builtins"] compiler_builtins_c = ["compiler_builtins/c"] +llvm-libunwind = ["unwind/llvm-libunwind"] # Make panics and failed asserts immediately abort without formatting any message panic_immediate_abort = ["core/panic_immediate_abort"] diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index 89d5b2ff30f..b9fcc2365fa 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -627,7 +627,11 @@ impl<T, S> HashSet<T, S> /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn is_subset(&self, other: &HashSet<T, S>) -> bool { - self.iter().all(|v| other.contains(v)) + if self.len() <= other.len() { + self.iter().all(|v| other.contains(v)) + } else { + false + } } /// Returns `true` if the set is a superset of another, diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index 2952c6aea00..133540ed6b9 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -193,11 +193,11 @@ impl f32 { } /// Returns a number composed of the magnitude of `self` and the sign of - /// `y`. + /// `sign`. /// - /// Equal to `self` if the sign of `self` and `y` are the same, otherwise + /// Equal to `self` if the sign of `self` and `sign` are the same, otherwise /// equal to `-self`. If `self` is a `NAN`, then a `NAN` with the sign of - /// `y` is returned. + /// `sign` is returned. /// /// # Examples /// @@ -216,8 +216,8 @@ impl f32 { #[inline] #[must_use] #[stable(feature = "copysign", since = "1.35.0")] - pub fn copysign(self, y: f32) -> f32 { - unsafe { intrinsics::copysignf32(self, y) } + pub fn copysign(self, sign: f32) -> f32 { + unsafe { intrinsics::copysignf32(self, sign) } } /// Fused multiply-add. Computes `(self * a) + b` with only one rounding diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index 3c3a35573ad..87467aeed8b 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -171,11 +171,11 @@ impl f64 { } /// Returns a number composed of the magnitude of `self` and the sign of - /// `y`. + /// `sign`. /// - /// Equal to `self` if the sign of `self` and `y` are the same, otherwise + /// Equal to `self` if the sign of `self` and `sign` are the same, otherwise /// equal to `-self`. If `self` is a `NAN`, then a `NAN` with the sign of - /// `y` is returned. + /// `sign` is returned. /// /// # Examples /// @@ -194,8 +194,8 @@ impl f64 { #[inline] #[must_use] #[stable(feature = "copysign", since = "1.35.0")] - pub fn copysign(self, y: f64) -> f64 { - unsafe { intrinsics::copysignf64(self, y) } + pub fn copysign(self, sign: f64) -> f64 { + unsafe { intrinsics::copysignf64(self, sign) } } /// Fused multiply-add. Computes `(self * a) + b` with only one rounding diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index 01e7a57cd00..13aee783750 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -960,6 +960,7 @@ impl IntoInner<Buf> for OsString { } impl AsInner<Slice> for OsStr { + #[inline] fn as_inner(&self) -> &Slice { &self.inner } diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 705dc8f40b5..dea198d8c91 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -9,7 +9,7 @@ use crate::fmt; use crate::ffi::OsString; -use crate::io::{self, SeekFrom, Seek, Read, Initializer, Write}; +use crate::io::{self, SeekFrom, Seek, Read, Initializer, Write, IoVec, IoVecMut}; use crate::path::{Path, PathBuf}; use crate::sys::fs as fs_imp; use crate::sys_common::{AsInnerMut, FromInner, AsInner, IntoInner}; @@ -21,7 +21,9 @@ use crate::time::SystemTime; /// it was opened with. Files also implement [`Seek`] to alter the logical cursor /// that the file contains internally. /// -/// Files are automatically closed when they go out of scope. +/// Files are automatically closed when they go out of scope. Errors detected +/// on closing are ignored by the implementation of `Drop`. Use the method +/// [`sync_all`] if these errors must be manually handled. /// /// # Examples /// @@ -84,6 +86,7 @@ use crate::time::SystemTime; /// [`Read`]: ../io/trait.Read.html /// [`Write`]: ../io/trait.Write.html /// [`BufReader<R>`]: ../io/struct.BufReader.html +/// [`sync_all`]: struct.File.html#method.sync_all #[stable(feature = "rust1", since = "1.0.0")] pub struct File { inner: fs_imp::File, @@ -391,9 +394,13 @@ impl File { /// Attempts to sync all OS-internal metadata to disk. /// - /// This function will attempt to ensure that all in-core data reaches the + /// This function will attempt to ensure that all in-memory data reaches the /// filesystem before returning. /// + /// This can be used to handle errors that would otherwise only be caught + /// when the `File` is closed. Dropping a file will ignore errors in + /// synchronizing this in-memory data. + /// /// # Examples /// /// ```no_run @@ -608,6 +615,10 @@ impl Read for File { self.inner.read(buf) } + fn read_vectored(&mut self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> { + self.inner.read_vectored(bufs) + } + #[inline] unsafe fn initializer(&self) -> Initializer { Initializer::nop() @@ -618,6 +629,11 @@ impl Write for File { fn write(&mut self, buf: &[u8]) -> io::Result<usize> { self.inner.write(buf) } + + fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result<usize> { + self.inner.write_vectored(bufs) + } + fn flush(&mut self) -> io::Result<()> { self.inner.flush() } } #[stable(feature = "rust1", since = "1.0.0")] @@ -632,6 +648,10 @@ impl Read for &File { self.inner.read(buf) } + fn read_vectored(&mut self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> { + self.inner.read_vectored(bufs) + } + #[inline] unsafe fn initializer(&self) -> Initializer { Initializer::nop() @@ -642,6 +662,11 @@ impl Write for &File { fn write(&mut self, buf: &[u8]) -> io::Result<usize> { self.inner.write(buf) } + + fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result<usize> { + self.inner.write_vectored(bufs) + } + fn flush(&mut self) -> io::Result<()> { self.inner.flush() } } #[stable(feature = "rust1", since = "1.0.0")] @@ -881,6 +906,10 @@ impl OpenOptions { } } +impl AsInner<fs_imp::OpenOptions> for OpenOptions { + fn as_inner(&self) -> &fs_imp::OpenOptions { &self.0 } +} + impl AsInnerMut<fs_imp::OpenOptions> for OpenOptions { fn as_inner_mut(&mut self) -> &mut fs_imp::OpenOptions { &mut self.0 } } @@ -1104,6 +1133,10 @@ impl AsInner<fs_imp::FileAttr> for Metadata { fn as_inner(&self) -> &fs_imp::FileAttr { &self.0 } } +impl FromInner<fs_imp::FileAttr> for Metadata { + fn from_inner(attr: fs_imp::FileAttr) -> Metadata { Metadata(attr) } +} + impl Permissions { /// Returns `true` if these permissions describe a readonly (unwritable) file. /// diff --git a/src/libstd/future.rs b/src/libstd/future.rs index aa784746122..898387cb9f5 100644 --- a/src/libstd/future.rs +++ b/src/libstd/future.rs @@ -5,7 +5,7 @@ use core::marker::Unpin; use core::pin::Pin; use core::option::Option; use core::ptr::NonNull; -use core::task::{Waker, Poll}; +use core::task::{Context, Poll}; use core::ops::{Drop, Generator, GeneratorState}; #[doc(inline)] @@ -32,10 +32,10 @@ impl<T: Generator<Yield = ()>> !Unpin for GenFuture<T> {} #[unstable(feature = "gen_future", issue = "50547")] impl<T: Generator<Yield = ()>> Future for GenFuture<T> { type Output = T::Return; - fn poll(self: Pin<&mut Self>, waker: &Waker) -> Poll<Self::Output> { + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { // Safe because we're !Unpin + !Drop mapping to a ?Unpin value let gen = unsafe { Pin::map_unchecked_mut(self, |s| &mut s.0) }; - set_task_waker(waker, || match gen.resume() { + set_task_context(cx, || match gen.resume() { GeneratorState::Yielded(()) => Poll::Pending, GeneratorState::Complete(x) => Poll::Ready(x), }) @@ -43,61 +43,72 @@ impl<T: Generator<Yield = ()>> Future for GenFuture<T> { } thread_local! { - static TLS_WAKER: Cell<Option<NonNull<Waker>>> = Cell::new(None); + static TLS_CX: Cell<Option<NonNull<Context<'static>>>> = Cell::new(None); } -struct SetOnDrop(Option<NonNull<Waker>>); +struct SetOnDrop(Option<NonNull<Context<'static>>>); impl Drop for SetOnDrop { fn drop(&mut self) { - TLS_WAKER.with(|tls_waker| { - tls_waker.set(self.0.take()); + TLS_CX.with(|tls_cx| { + tls_cx.set(self.0.take()); }); } } #[unstable(feature = "gen_future", issue = "50547")] /// Sets the thread-local task context used by async/await futures. -pub fn set_task_waker<F, R>(waker: &Waker, f: F) -> R +pub fn set_task_context<F, R>(cx: &mut Context<'_>, f: F) -> R where F: FnOnce() -> R { - let old_waker = TLS_WAKER.with(|tls_waker| { - tls_waker.replace(Some(NonNull::from(waker))) + // transmute the context's lifetime to 'static so we can store it. + let cx = unsafe { + core::mem::transmute::<&mut Context<'_>, &mut Context<'static>>(cx) + }; + let old_cx = TLS_CX.with(|tls_cx| { + tls_cx.replace(Some(NonNull::from(cx))) }); - let _reset_waker = SetOnDrop(old_waker); + let _reset = SetOnDrop(old_cx); f() } #[unstable(feature = "gen_future", issue = "50547")] -/// Retrieves the thread-local task waker used by async/await futures. +/// Retrieves the thread-local task context used by async/await futures. /// -/// This function acquires exclusive access to the task waker. +/// This function acquires exclusive access to the task context. /// -/// Panics if no waker has been set or if the waker has already been -/// retrieved by a surrounding call to get_task_waker. -pub fn get_task_waker<F, R>(f: F) -> R +/// Panics if no context has been set or if the context has already been +/// retrieved by a surrounding call to get_task_context. +pub fn get_task_context<F, R>(f: F) -> R where - F: FnOnce(&Waker) -> R + F: FnOnce(&mut Context<'_>) -> R { - let waker_ptr = TLS_WAKER.with(|tls_waker| { + let cx_ptr = TLS_CX.with(|tls_cx| { // Clear the entry so that nested `get_task_waker` calls // will fail or set their own value. - tls_waker.replace(None) + tls_cx.replace(None) }); - let _reset_waker = SetOnDrop(waker_ptr); + let _reset = SetOnDrop(cx_ptr); - let waker_ptr = waker_ptr.expect( - "TLS Waker not set. This is a rustc bug. \ + let mut cx_ptr = cx_ptr.expect( + "TLS Context not set. This is a rustc bug. \ Please file an issue on https://github.com/rust-lang/rust."); - unsafe { f(waker_ptr.as_ref()) } + + // Safety: we've ensured exclusive access to the context by + // removing the pointer from TLS, only to be replaced once + // we're done with it. + // + // The pointer that was inserted came from an `&mut Context<'_>`, + // so it is safe to treat as mutable. + unsafe { f(cx_ptr.as_mut()) } } #[unstable(feature = "gen_future", issue = "50547")] /// Polls a future in the current thread-local task waker. -pub fn poll_with_tls_waker<F>(f: Pin<&mut F>) -> Poll<F::Output> +pub fn poll_with_tls_context<F>(f: Pin<&mut F>) -> Poll<F::Output> where F: Future { - get_task_waker(|waker| F::poll(f, waker)) + get_task_context(|cx| F::poll(f, cx)) } diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index 0bbff5769ab..1848ddeab65 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -5,7 +5,7 @@ use crate::io::prelude::*; use crate::cell::RefCell; use crate::fmt; use crate::io::lazy::Lazy; -use crate::io::{self, Initializer, BufReader, LineWriter}; +use crate::io::{self, Initializer, BufReader, LineWriter, IoVec, IoVecMut}; use crate::sync::{Arc, Mutex, MutexGuard}; use crate::sys::stdio; use crate::sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard}; @@ -75,6 +75,10 @@ fn stderr_raw() -> io::Result<StderrRaw> { stdio::Stderr::new().map(StderrRaw) } impl Read for StdinRaw { fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.0.read(buf) } + fn read_vectored(&mut self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> { + self.0.read_vectored(bufs) + } + #[inline] unsafe fn initializer(&self) -> Initializer { Initializer::nop() @@ -82,10 +86,20 @@ impl Read for StdinRaw { } impl Write for StdoutRaw { fn write(&mut self, buf: &[u8]) -> io::Result<usize> { self.0.write(buf) } + + fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result<usize> { + self.0.write_vectored(bufs) + } + fn flush(&mut self) -> io::Result<()> { self.0.flush() } } impl Write for StderrRaw { fn write(&mut self, buf: &[u8]) -> io::Result<usize> { self.0.write(buf) } + + fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result<usize> { + self.0.write_vectored(bufs) + } + fn flush(&mut self) -> io::Result<()> { self.0.flush() } } @@ -102,6 +116,14 @@ impl<W: io::Write> io::Write for Maybe<W> { } } + fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result<usize> { + let total = bufs.iter().map(|b| b.len()).sum(); + match self { + Maybe::Real(w) => handle_ebadf(w.write_vectored(bufs), total), + Maybe::Fake => Ok(total), + } + } + fn flush(&mut self) -> io::Result<()> { match *self { Maybe::Real(ref mut w) => handle_ebadf(w.flush(), ()), @@ -117,6 +139,13 @@ impl<R: io::Read> io::Read for Maybe<R> { Maybe::Fake => Ok(0) } } + + fn read_vectored(&mut self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> { + match self { + Maybe::Real(r) => handle_ebadf(r.read_vectored(bufs), 0), + Maybe::Fake => Ok(0) + } + } } fn handle_ebadf<T>(r: io::Result<T>, default: T) -> io::Result<T> { @@ -305,6 +334,9 @@ impl Read for Stdin { fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.lock().read(buf) } + fn read_vectored(&mut self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> { + self.lock().read_vectored(bufs) + } #[inline] unsafe fn initializer(&self) -> Initializer { Initializer::nop() @@ -325,6 +357,11 @@ impl Read for StdinLock<'_> { fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.inner.read(buf) } + + fn read_vectored(&mut self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> { + self.inner.read_vectored(bufs) + } + #[inline] unsafe fn initializer(&self) -> Initializer { Initializer::nop() @@ -483,6 +520,9 @@ impl Write for Stdout { fn write(&mut self, buf: &[u8]) -> io::Result<usize> { self.lock().write(buf) } + fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result<usize> { + self.lock().write_vectored(bufs) + } fn flush(&mut self) -> io::Result<()> { self.lock().flush() } @@ -498,6 +538,9 @@ impl Write for StdoutLock<'_> { fn write(&mut self, buf: &[u8]) -> io::Result<usize> { self.inner.borrow_mut().write(buf) } + fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result<usize> { + self.inner.borrow_mut().write_vectored(bufs) + } fn flush(&mut self) -> io::Result<()> { self.inner.borrow_mut().flush() } @@ -636,6 +679,9 @@ impl Write for Stderr { fn write(&mut self, buf: &[u8]) -> io::Result<usize> { self.lock().write(buf) } + fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result<usize> { + self.lock().write_vectored(bufs) + } fn flush(&mut self) -> io::Result<()> { self.lock().flush() } @@ -651,6 +697,9 @@ impl Write for StderrLock<'_> { fn write(&mut self, buf: &[u8]) -> io::Result<usize> { self.inner.borrow_mut().write(buf) } + fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result<usize> { + self.inner.borrow_mut().write_vectored(bufs) + } fn flush(&mut self) -> io::Result<()> { self.inner.borrow_mut().flush() } diff --git a/src/libstd/keyword_docs.rs b/src/libstd/keyword_docs.rs index 7b0d1549e06..ffe50f11e8a 100644 --- a/src/libstd/keyword_docs.rs +++ b/src/libstd/keyword_docs.rs @@ -25,8 +25,7 @@ /// /// For more information on what `as` is capable of, see the [Reference] /// -/// [Reference]: -/// https://doc.rust-lang.org/reference/expressions/operator-expr.html#type-cast-expressions +/// [Reference]: ../reference/expressions/operator-expr.html#type-cast-expressions /// [`crate`]: keyword.crate.html mod as_keyword { } @@ -80,8 +79,8 @@ mod as_keyword { } /// /// [pointer]: primitive.pointer.html /// [Rust Book]: -/// https://doc.rust-lang.org/stable/book/2018-edition/ch03-01-variables-and-mutability.html#differences-between-variables-and-constants -/// [Reference]: https://doc.rust-lang.org/reference/items/constant-items.html +/// ../book/ch03-01-variables-and-mutability.html#differences-between-variables-and-constants +/// [Reference]: ../reference/items/constant-items.html mod const_keyword { } #[doc(keyword = "crate")] @@ -114,7 +113,7 @@ mod const_keyword { } /// } /// ``` /// -/// [Reference]: https://doc.rust-lang.org/reference/items/extern-crates.html +/// [Reference]: ../reference/items/extern-crates.html mod crate_keyword { } #[doc(keyword = "enum")] @@ -169,8 +168,8 @@ mod crate_keyword { } /// /// [Algebraic Data Types]: https://en.wikipedia.org/wiki/Algebraic_data_type /// [`Option`]: option/enum.Option.html -/// [Rust Book]: https://doc.rust-lang.org/book/ch06-01-defining-an-enum.html -/// [Reference]: https://doc.rust-lang.org/reference/items/enumerations.html +/// [Rust Book]: ../book/ch06-01-defining-an-enum.html +/// [Reference]: ../reference/items/enumerations.html mod enum_keyword { } #[doc(keyword = "extern")] @@ -211,8 +210,8 @@ mod enum_keyword { } /// For more information on FFI, check the [Rust book] or the [Reference]. /// /// [Rust book]: -/// https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html#using-extern-functions-to-call-external-code -/// [Reference]: https://doc.rust-lang.org/reference/items/external-blocks.html +/// ../book/ch19-01-unsafe-rust.html#using-extern-functions-to-call-external-code +/// [Reference]: ../reference/items/external-blocks.html mod extern_keyword { } #[doc(keyword = "fn")] @@ -278,8 +277,8 @@ mod extern_keyword { } /// /// [`impl`]: keyword.impl.html /// [`extern`]: keyword.extern.html -/// [Rust book]: https://doc.rust-lang.org/book/ch03-03-how-functions-work.html -/// [Reference]: https://doc.rust-lang.org/reference/items/functions.html +/// [Rust book]: ../book/ch03-03-how-functions-work.html +/// [Reference]: ../reference/items/functions.html mod fn_keyword { } #[doc(keyword = "for")] @@ -352,12 +351,11 @@ mod fn_keyword { } /// For more information on for-loops, see the [Rust book] or the [Reference]. /// /// [`impl`]: keyword.impl.html -/// [higher-ranked trait bounds]: -/// https://doc.rust-lang.org/nightly/reference/trait-bounds.html#higher-ranked-trait-bounds +/// [higher-ranked trait bounds]: ../reference/trait-bounds.html#higher-ranked-trait-bounds /// [`IntoIterator`]: iter/trait.IntoIterator.html /// [Rust book]: -/// https://doc.rust-lang.org/book/2018-edition/ch03-05-control-flow.html#looping-through-a-collection-with-for -/// [Reference]: https://doc.rust-lang.org/reference/expressions/loop-expr.html#iterator-loops +/// ../book/ch03-05-control-flow.html#looping-through-a-collection-with-for +/// [Reference]: ../reference/expressions/loop-expr.html#iterator-loops mod for_keyword { } #[doc(keyword = "if")] @@ -430,9 +428,8 @@ mod for_keyword { } /// /// For more information on `if` expressions, see the [Rust book] or the [Reference]. /// -/// [Rust book]: -/// https://doc.rust-lang.org/stable/book/2018-edition/ch03-05-control-flow.html#if-expressions -/// [Reference]: https://doc.rust-lang.org/reference/expressions/if-expr.html +/// [Rust book]: ../book/ch03-05-control-flow.html#if-expressions +/// [Reference]: ../reference/expressions/if-expr.html mod if_keyword { } #[doc(keyword = "impl")] @@ -493,10 +490,9 @@ mod if_keyword { } /// /// For more information on `impl Trait` syntax, see the [Rust book][book2]. /// -/// [book1]: https://doc.rust-lang.org/stable/book/2018-edition/ch05-03-method-syntax.html -/// [Reference]: https://doc.rust-lang.org/reference/items/implementations.html -/// [book2]: -/// https://doc.rust-lang.org/stable/book/2018-edition/ch10-02-traits.html#returning-traits +/// [book1]: ../book/ch05-03-method-syntax.html +/// [Reference]: ../reference/items/implementations.html +/// [book2]: ../book/ch10-02-traits.html#returning-types-that-implement-traits mod impl_keyword { } #[doc(keyword = "let")] @@ -554,13 +550,12 @@ mod impl_keyword { } /// enumerations. `while let` also exists, which runs a loop with a pattern matched value until /// that pattern can't be matched. /// -/// For more information on the `let` keyword, see the [Rust book] or the [Reference] +/// For more information on the `let` keyword, see the [Rust book][book2] or the [Reference] /// -/// [book1]: https://doc.rust-lang.org/stable/book/2018-edition/ch06-02-match.html +/// [book1]: ../book/ch06-02-match.html /// [`if`]: keyword.if.html -/// [book2]: -/// https://doc.rust-lang.org/stable/book/2018-edition/ch18-01-all-the-places-for-patterns.html#let-statements -/// [Reference]: https://doc.rust-lang.org/reference/statements.html#let-statements +/// [book2]: ../book/ch18-01-all-the-places-for-patterns.html#let-statements +/// [Reference]: ../reference/statements.html#let-statements mod let_keyword { } #[doc(keyword = "loop")] @@ -605,7 +600,7 @@ mod let_keyword { } /// /// For more information on `loop` and loops in general, see the [Reference]. /// -/// [Reference]: https://doc.rust-lang.org/reference/expressions/loop-expr.html +/// [Reference]: ../reference/expressions/loop-expr.html mod loop_keyword { } #[doc(keyword = "struct")] @@ -712,6 +707,6 @@ mod loop_keyword { } /// [Reference][reference]. /// /// [`PhantomData`]: marker/struct.PhantomData.html -/// [book]: https://doc.rust-lang.org/book/ch05-01-defining-structs.html -/// [reference]: https://doc.rust-lang.org/reference/items/structs.html +/// [book]: ../book/ch05-01-defining-structs.html +/// [reference]: ../reference/items/structs.html mod struct_keyword { } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index d11dee8fc97..ee6ba3f438f 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -229,7 +229,6 @@ #![feature(align_offset)] #![feature(alloc_error_handler)] #![feature(alloc_layout_extra)] -#![feature(alloc)] #![feature(allocator_api)] #![feature(allocator_internals)] #![feature(allow_internal_unsafe)] diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index be4db1f737d..14b266a4344 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -346,7 +346,7 @@ macro_rules! r#await { let mut pinned = $e; loop { if let $crate::task::Poll::Ready(x) = - $crate::future::poll_with_tls_waker(unsafe { + $crate::future::poll_with_tls_context(unsafe { $crate::pin::Pin::new_unchecked(&mut pinned) }) { @@ -836,9 +836,11 @@ mod builtin { /// boolean expression evaluation of configuration flags. This frequently /// leads to less duplicated code. /// - /// The syntax given to this macro is the same syntax as the `cfg` + /// The syntax given to this macro is the same syntax as the [`cfg`] /// attribute. /// + /// [`cfg`]: ../reference/conditional-compilation.html#the-cfg-attribute + /// /// # Examples /// /// ``` diff --git a/src/libstd/num.rs b/src/libstd/num.rs index 828d5720eec..d67d0b55a79 100644 --- a/src/libstd/num.rs +++ b/src/libstd/num.rs @@ -13,6 +13,8 @@ pub use core::num::Wrapping; #[stable(feature = "nonzero", since = "1.28.0")] pub use core::num::{NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, NonZeroUsize}; +#[stable(feature = "signed_nonzero", since = "1.34.0")] +pub use core::num::{NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128, NonZeroIsize}; #[cfg(test)] use crate::fmt; #[cfg(test)] use crate::ops::{Add, Sub, Mul, Div, Rem}; diff --git a/src/libstd/panic.rs b/src/libstd/panic.rs index cc147d851de..5a8101e2301 100644 --- a/src/libstd/panic.rs +++ b/src/libstd/panic.rs @@ -12,7 +12,7 @@ use crate::panicking; use crate::ptr::{Unique, NonNull}; use crate::rc::Rc; use crate::sync::{Arc, Mutex, RwLock, atomic}; -use crate::task::{Waker, Poll}; +use crate::task::{Context, Poll}; use crate::thread::Result; #[stable(feature = "panic_hooks", since = "1.10.0")] @@ -323,9 +323,9 @@ impl<T: fmt::Debug> fmt::Debug for AssertUnwindSafe<T> { impl<F: Future> Future for AssertUnwindSafe<F> { type Output = F::Output; - fn poll(self: Pin<&mut Self>, waker: &Waker) -> Poll<Self::Output> { + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { let pinned_field = unsafe { Pin::map_unchecked_mut(self, |x| &mut x.0) }; - F::poll(pinned_field, waker) + F::poll(pinned_field, cx) } } diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 71e82f0a9b0..1bbda9b5bcb 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -1551,9 +1551,7 @@ impl<P: AsRef<Path>> iter::FromIterator<P> for PathBuf { #[stable(feature = "rust1", since = "1.0.0")] impl<P: AsRef<Path>> iter::Extend<P> for PathBuf { fn extend<I: IntoIterator<Item = P>>(&mut self, iter: I) { - for p in iter { - self.push(p.as_ref()) - } + iter.into_iter().for_each(move |p| self.push(p.as_ref())); } } diff --git a/src/libstd/process.rs b/src/libstd/process.rs index e0c9b7cad86..ef5626700e8 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -111,7 +111,7 @@ use crate::io::prelude::*; use crate::ffi::OsStr; use crate::fmt; use crate::fs; -use crate::io::{self, Initializer}; +use crate::io::{self, Initializer, IoVec, IoVecMut}; use crate::path::Path; use crate::str; use crate::sys::pipe::{read2, AnonPipe}; @@ -225,6 +225,10 @@ impl Write for ChildStdin { self.inner.write(buf) } + fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result<usize> { + self.inner.write_vectored(bufs) + } + fn flush(&mut self) -> io::Result<()> { Ok(()) } @@ -271,6 +275,11 @@ impl Read for ChildStdout { fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.inner.read(buf) } + + fn read_vectored(&mut self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> { + self.inner.read_vectored(bufs) + } + #[inline] unsafe fn initializer(&self) -> Initializer { Initializer::nop() @@ -318,6 +327,11 @@ impl Read for ChildStderr { fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.inner.read(buf) } + + fn read_vectored(&mut self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> { + self.inner.read_vectored(bufs) + } + #[inline] unsafe fn initializer(&self) -> Initializer { Initializer::nop() diff --git a/src/libstd/sys/cloudabi/shims/fs.rs b/src/libstd/sys/cloudabi/shims/fs.rs index ee045b8e515..abd7f0fd3ee 100644 --- a/src/libstd/sys/cloudabi/shims/fs.rs +++ b/src/libstd/sys/cloudabi/shims/fs.rs @@ -1,7 +1,7 @@ use crate::ffi::OsString; use crate::fmt; use crate::hash::{Hash, Hasher}; -use crate::io::{self, SeekFrom}; +use crate::io::{self, SeekFrom, IoVec, IoVecMut}; use crate::path::{Path, PathBuf}; use crate::sys::time::SystemTime; use crate::sys::{unsupported, Void}; @@ -198,10 +198,18 @@ impl File { match self.0 {} } + pub fn read_vectored(&self, _bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> { + match self.0 {} + } + pub fn write(&self, _buf: &[u8]) -> io::Result<usize> { match self.0 {} } + pub fn write_vectored(&self, _bufs: &[IoVec<'_>]) -> io::Result<usize> { + match self.0 {} + } + pub fn flush(&self) -> io::Result<()> { match self.0 {} } diff --git a/src/libstd/sys/cloudabi/shims/pipe.rs b/src/libstd/sys/cloudabi/shims/pipe.rs index f3debb95047..804d3e001ac 100644 --- a/src/libstd/sys/cloudabi/shims/pipe.rs +++ b/src/libstd/sys/cloudabi/shims/pipe.rs @@ -1,4 +1,4 @@ -use crate::io; +use crate::io::{self, IoVec, IoVecMut}; use crate::sys::Void; pub struct AnonPipe(Void); @@ -8,10 +8,18 @@ impl AnonPipe { match self.0 {} } + pub fn read_vectored(&self, _bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> { + match self.0 {} + } + pub fn write(&self, _buf: &[u8]) -> io::Result<usize> { match self.0 {} } + pub fn write_vectored(&self, _bufs: &[IoVec<'_>]) -> io::Result<usize> { + match self.0 {} + } + pub fn diverge(&self) -> ! { match self.0 {} } diff --git a/src/libstd/sys/cloudabi/thread.rs b/src/libstd/sys/cloudabi/thread.rs index f853346e0e6..7da16c4d247 100644 --- a/src/libstd/sys/cloudabi/thread.rs +++ b/src/libstd/sys/cloudabi/thread.rs @@ -1,4 +1,3 @@ -use crate::boxed::FnBox; use crate::cmp; use crate::ffi::CStr; use crate::io; @@ -22,7 +21,7 @@ unsafe impl Sync for Thread {} impl Thread { // unsafe: see thread::Builder::spawn_unchecked for safety requirements - pub unsafe fn new(stack: usize, p: Box<dyn FnBox()>) -> io::Result<Thread> { + pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> { let p = box p; let mut native: libc::pthread_t = mem::zeroed(); let mut attr: libc::pthread_attr_t = mem::zeroed(); diff --git a/src/libstd/sys/redox/fs.rs b/src/libstd/sys/redox/fs.rs index 3ef9925705f..c86c6000eae 100644 --- a/src/libstd/sys/redox/fs.rs +++ b/src/libstd/sys/redox/fs.rs @@ -2,7 +2,7 @@ use crate::os::unix::prelude::*; use crate::ffi::{OsString, OsStr}; use crate::fmt; -use crate::io::{self, Error, ErrorKind, SeekFrom}; +use crate::io::{self, Error, SeekFrom, IoVec, IoVecMut}; use crate::path::{Path, PathBuf}; use crate::sync::Arc; use crate::sys::fd::FileDesc; @@ -10,6 +10,9 @@ use crate::sys::time::SystemTime; use crate::sys::{cvt, syscall}; use crate::sys_common::{AsInner, FromInner}; +pub use crate::sys_common::fs::copy; +pub use crate::sys_common::fs::remove_dir_all; + pub struct File(FileDesc); #[derive(Clone)] @@ -275,10 +278,18 @@ impl File { self.0.read(buf) } + pub fn read_vectored(&self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> { + crate::io::default_read_vectored(|buf| self.read(buf), bufs) + } + pub fn write(&self, buf: &[u8]) -> io::Result<usize> { self.0.write(buf) } + pub fn write_vectored(&self, bufs: &[IoVec<'_>]) -> io::Result<usize> { + crate::io::default_write_vectored(|buf| self.write(buf), bufs) + } + pub fn flush(&self) -> io::Result<()> { Ok(()) } pub fn seek(&self, pos: SeekFrom) -> io::Result<u64> { @@ -392,27 +403,6 @@ pub fn rmdir(p: &Path) -> io::Result<()> { Ok(()) } -pub fn remove_dir_all(path: &Path) -> io::Result<()> { - let filetype = lstat(path)?.file_type(); - if filetype.is_symlink() { - unlink(path) - } else { - remove_dir_all_recursive(path) - } -} - -fn remove_dir_all_recursive(path: &Path) -> io::Result<()> { - for child in readdir(path)? { - let child = child?; - if child.file_type()?.is_dir() { - remove_dir_all_recursive(&child.path())?; - } else { - unlink(&child.path())?; - } - } - rmdir(path) -} - pub fn readlink(p: &Path) -> io::Result<PathBuf> { let fd = cvt(syscall::open(p.to_str().unwrap(), syscall::O_CLOEXEC | syscall::O_SYMLINK | syscall::O_RDONLY))?; @@ -455,19 +445,3 @@ pub fn canonicalize(p: &Path) -> io::Result<PathBuf> { let file = File(FileDesc::new(fd)); file.path() } - -pub fn copy(from: &Path, to: &Path) -> io::Result<u64> { - use crate::fs::{File, set_permissions}; - if !from.is_file() { - return Err(Error::new(ErrorKind::InvalidInput, - "the source path is not an existing regular file")) - } - - let mut reader = File::open(from)?; - let mut writer = File::create(to)?; - let perm = reader.metadata()?.permissions(); - - let ret = io::copy(&mut reader, &mut writer)?; - set_permissions(to, perm)?; - Ok(ret) -} diff --git a/src/libstd/sys/redox/pipe.rs b/src/libstd/sys/redox/pipe.rs index 911ba9c3f65..b926968f7b3 100644 --- a/src/libstd/sys/redox/pipe.rs +++ b/src/libstd/sys/redox/pipe.rs @@ -1,4 +1,4 @@ -use crate::io; +use crate::io::{self, IoVec, IoVecMut}; use crate::sys::{cvt, syscall}; use crate::sys::fd::FileDesc; @@ -24,10 +24,18 @@ impl AnonPipe { self.0.read(buf) } + pub fn read_vectored(&self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> { + crate::io::default_read_vectored(|buf| self.read(buf), bufs) + } + pub fn write(&self, buf: &[u8]) -> io::Result<usize> { self.0.write(buf) } + pub fn write_vectored(&self, bufs: &[IoVec<'_>]) -> io::Result<usize> { + crate::io::default_write_vectored(|buf| self.write(buf), bufs) + } + pub fn fd(&self) -> &FileDesc { &self.0 } pub fn into_fd(self) -> FileDesc { self.0 } } diff --git a/src/libstd/sys/redox/thread.rs b/src/libstd/sys/redox/thread.rs index ae0b91b4d6c..9d40a7e8bb8 100644 --- a/src/libstd/sys/redox/thread.rs +++ b/src/libstd/sys/redox/thread.rs @@ -1,4 +1,3 @@ -use crate::boxed::FnBox; use crate::ffi::CStr; use crate::io; use crate::mem; @@ -19,7 +18,7 @@ unsafe impl Sync for Thread {} impl Thread { // unsafe: see thread::Builder::spawn_unchecked for safety requirements - pub unsafe fn new(_stack: usize, p: Box<dyn FnBox()>) -> io::Result<Thread> { + pub unsafe fn new(_stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> { let p = box p; let id = cvt(syscall::clone(syscall::CLONE_VM | syscall::CLONE_FS | syscall::CLONE_FILES))?; diff --git a/src/libstd/sys/sgx/abi/mod.rs b/src/libstd/sys/sgx/abi/mod.rs index 85ec8be4aae..1f433e25ee1 100644 --- a/src/libstd/sys/sgx/abi/mod.rs +++ b/src/libstd/sys/sgx/abi/mod.rs @@ -69,9 +69,9 @@ extern "C" fn entry(p1: u64, p2: u64, p3: u64, secondary: bool, p4: u64, p5: u64 } // check entry is being called according to ABI - assert_eq!(p3, 0); - assert_eq!(p4, 0); - assert_eq!(p5, 0); + rtassert!(p3 == 0); + rtassert!(p4 == 0); + rtassert!(p5 == 0); unsafe { // The actual types of these arguments are `p1: *const Arg, p2: diff --git a/src/libstd/sys/sgx/abi/reloc.rs b/src/libstd/sys/sgx/abi/reloc.rs index a39841bc36f..6dd24c524fc 100644 --- a/src/libstd/sys/sgx/abi/reloc.rs +++ b/src/libstd/sys/sgx/abi/reloc.rs @@ -23,7 +23,7 @@ pub fn relocate_elf_rela() { }; for rela in relas { if rela.info != (/*0 << 32 |*/ R_X86_64_RELATIVE as u64) { - panic!("Invalid relocation"); + rtabort!("Invalid relocation"); } unsafe { *mem::rel_ptr_mut::<*const ()>(rela.offset) = mem::rel_ptr(rela.addend) }; } diff --git a/src/libstd/sys/sgx/abi/tls.rs b/src/libstd/sys/sgx/abi/tls.rs index fa82e8ccf05..03e08ad547d 100644 --- a/src/libstd/sys/sgx/abi/tls.rs +++ b/src/libstd/sys/sgx/abi/tls.rs @@ -100,20 +100,24 @@ impl Tls { } pub fn create(dtor: Option<unsafe extern fn(*mut u8)>) -> Key { - let index = TLS_KEY_IN_USE.set().expect("TLS limit exceeded"); + let index = if let Some(index) = TLS_KEY_IN_USE.set() { + index + } else { + rtabort!("TLS limit exceeded") + }; TLS_DESTRUCTOR[index].store(dtor.map_or(0, |f| f as usize), Ordering::Relaxed); Key::from_index(index) } pub fn set(key: Key, value: *mut u8) { let index = key.to_index(); - assert!(TLS_KEY_IN_USE.get(index)); + rtassert!(TLS_KEY_IN_USE.get(index)); unsafe { Self::current() }.data[index].set(value); } pub fn get(key: Key) -> *mut u8 { let index = key.to_index(); - assert!(TLS_KEY_IN_USE.get(index)); + rtassert!(TLS_KEY_IN_USE.get(index)); unsafe { Self::current() }.data[index].get() } diff --git a/src/libstd/sys/sgx/abi/usercalls/alloc.rs b/src/libstd/sys/sgx/abi/usercalls/alloc.rs index ec9c30a3e4f..22ae2a8e07d 100644 --- a/src/libstd/sys/sgx/abi/usercalls/alloc.rs +++ b/src/libstd/sys/sgx/abi/usercalls/alloc.rs @@ -190,11 +190,15 @@ impl<T: ?Sized> User<T> where T: UserSafe { unsafe { // Mustn't call alloc with size 0. let ptr = if size > 0 { - super::alloc(size, T::align_of()).expect("User memory allocation failed") as _ + rtunwrap!(Ok, super::alloc(size, T::align_of())) as _ } else { T::align_of() as _ // dangling pointer ok for size 0 }; - User(NonNull::new_userref(T::from_raw_sized(ptr, size))) + if let Ok(v) = crate::panic::catch_unwind(|| T::from_raw_sized(ptr, size)) { + User(NonNull::new_userref(v)) + } else { + rtabort!("Got invalid pointer from alloc() usercall") + } } } diff --git a/src/libstd/sys/sgx/abi/usercalls/mod.rs b/src/libstd/sys/sgx/abi/usercalls/mod.rs index d84b6154cbe..0abfc26bced 100644 --- a/src/libstd/sys/sgx/abi/usercalls/mod.rs +++ b/src/libstd/sys/sgx/abi/usercalls/mod.rs @@ -52,7 +52,7 @@ pub fn close(fd: Fd) { fn string_from_bytebuffer(buf: &alloc::UserRef<ByteBuffer>, usercall: &str, arg: &str) -> String { String::from_utf8(buf.copy_user_buffer()) - .unwrap_or_else(|_| panic!("Usercall {}: expected {} to be valid UTF-8", usercall, arg)) + .unwrap_or_else(|_| rtabort!("Usercall {}: expected {} to be valid UTF-8", usercall, arg)) } /// Usercall `bind_stream`. See the ABI documentation for more information. @@ -176,7 +176,7 @@ fn check_os_error(err: Result) -> i32 { { err } else { - panic!("Usercall: returned invalid error value {}", err) + rtabort!("Usercall: returned invalid error value {}", err) } } diff --git a/src/libstd/sys/sgx/abi/usercalls/raw.rs b/src/libstd/sys/sgx/abi/usercalls/raw.rs index ad0b6d7b3d8..e4694a8827a 100644 --- a/src/libstd/sys/sgx/abi/usercalls/raw.rs +++ b/src/libstd/sys/sgx/abi/usercalls/raw.rs @@ -131,22 +131,22 @@ impl<T: RegisterArgument> RegisterArgument for Option<NonNull<T>> { impl ReturnValue for ! { fn from_registers(call: &'static str, _regs: (Register, Register)) -> Self { - panic!("Usercall {}: did not expect to be re-entered", call); + rtabort!("Usercall {}: did not expect to be re-entered", call); } } impl ReturnValue for () { - fn from_registers(call: &'static str, regs: (Register, Register)) -> Self { - assert_eq!(regs.0, 0, "Usercall {}: expected {} return value to be 0", call, "1st"); - assert_eq!(regs.1, 0, "Usercall {}: expected {} return value to be 0", call, "2nd"); + fn from_registers(call: &'static str, usercall_retval: (Register, Register)) -> Self { + rtassert!(usercall_retval.0 == 0); + rtassert!(usercall_retval.1 == 0); () } } impl<T: RegisterArgument> ReturnValue for T { - fn from_registers(call: &'static str, regs: (Register, Register)) -> Self { - assert_eq!(regs.1, 0, "Usercall {}: expected {} return value to be 0", call, "2nd"); - T::from_register(regs.0) + fn from_registers(call: &'static str, usercall_retval: (Register, Register)) -> Self { + rtassert!(usercall_retval.1 == 0); + T::from_register(usercall_retval.0) } } @@ -174,8 +174,7 @@ macro_rules! enclave_usercalls_internal_define_usercalls { #[inline(always)] pub unsafe fn $f($n1: $t1, $n2: $t2, $n3: $t3, $n4: $t4) -> $r { ReturnValue::from_registers(stringify!($f), do_usercall( - NonZeroU64::new(Usercalls::$f as Register) - .expect("Usercall number must be non-zero"), + rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)), RegisterArgument::into_register($n1), RegisterArgument::into_register($n2), RegisterArgument::into_register($n3), @@ -191,8 +190,7 @@ macro_rules! enclave_usercalls_internal_define_usercalls { #[inline(always)] pub unsafe fn $f($n1: $t1, $n2: $t2, $n3: $t3) -> $r { ReturnValue::from_registers(stringify!($f), do_usercall( - NonZeroU64::new(Usercalls::$f as Register) - .expect("Usercall number must be non-zero"), + rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)), RegisterArgument::into_register($n1), RegisterArgument::into_register($n2), RegisterArgument::into_register($n3), @@ -208,8 +206,7 @@ macro_rules! enclave_usercalls_internal_define_usercalls { #[inline(always)] pub unsafe fn $f($n1: $t1, $n2: $t2) -> $r { ReturnValue::from_registers(stringify!($f), do_usercall( - NonZeroU64::new(Usercalls::$f as Register) - .expect("Usercall number must be non-zero"), + rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)), RegisterArgument::into_register($n1), RegisterArgument::into_register($n2), 0,0, @@ -224,8 +221,7 @@ macro_rules! enclave_usercalls_internal_define_usercalls { #[inline(always)] pub unsafe fn $f($n1: $t1) -> $r { ReturnValue::from_registers(stringify!($f), do_usercall( - NonZeroU64::new(Usercalls::$f as Register) - .expect("Usercall number must be non-zero"), + rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)), RegisterArgument::into_register($n1), 0,0,0, return_type_is_abort!($r) @@ -239,8 +235,7 @@ macro_rules! enclave_usercalls_internal_define_usercalls { #[inline(always)] pub unsafe fn $f() -> $r { ReturnValue::from_registers(stringify!($f), do_usercall( - NonZeroU64::new(Usercalls::$f as Register) - .expect("Usercall number must be non-zero"), + rtunwrap!(Some, NonZeroU64::new(Usercalls::$f as Register)), 0,0,0,0, return_type_is_abort!($r) )) diff --git a/src/libstd/sys/sgx/alloc.rs b/src/libstd/sys/sgx/alloc.rs index 98eb8397436..40daec758a9 100644 --- a/src/libstd/sys/sgx/alloc.rs +++ b/src/libstd/sys/sgx/alloc.rs @@ -30,3 +30,17 @@ unsafe impl GlobalAlloc for System { DLMALLOC.lock().realloc(ptr, layout.size(), layout.align(), new_size) } } + +// The following functions are needed by libunwind. These symbols are named +// in pre-link args for the target specification, so keep that in sync. +#[cfg(not(test))] +#[no_mangle] +pub unsafe extern "C" fn __rust_c_alloc(size: usize, align: usize) -> *mut u8 { + crate::alloc::alloc(Layout::from_size_align_unchecked(size, align)) +} + +#[cfg(not(test))] +#[no_mangle] +pub unsafe extern "C" fn __rust_c_dealloc(ptr: *mut u8, size: usize, align: usize) { + crate::alloc::dealloc(ptr, Layout::from_size_align_unchecked(size, align)) +} diff --git a/src/libstd/sys/sgx/condvar.rs b/src/libstd/sys/sgx/condvar.rs index f9a76f0baf5..000bb19f269 100644 --- a/src/libstd/sys/sgx/condvar.rs +++ b/src/libstd/sys/sgx/condvar.rs @@ -32,9 +32,8 @@ impl Condvar { mutex.lock() } - pub unsafe fn wait_timeout(&self, mutex: &Mutex, _dur: Duration) -> bool { - mutex.unlock(); // don't hold the lock while panicking - panic!("timeout not supported in SGX"); + pub unsafe fn wait_timeout(&self, _mutex: &Mutex, _dur: Duration) -> bool { + rtabort!("timeout not supported in SGX"); } #[inline] diff --git a/src/libstd/sys/sgx/fs.rs b/src/libstd/sys/sgx/fs.rs index 68c8e9356a8..c3c898eb23e 100644 --- a/src/libstd/sys/sgx/fs.rs +++ b/src/libstd/sys/sgx/fs.rs @@ -1,7 +1,7 @@ use crate::ffi::OsString; use crate::fmt; use crate::hash::{Hash, Hasher}; -use crate::io::{self, SeekFrom}; +use crate::io::{self, SeekFrom, IoVec, IoVecMut}; use crate::path::{Path, PathBuf}; use crate::sys::time::SystemTime; use crate::sys::{unsupported, Void}; @@ -200,10 +200,18 @@ impl File { match self.0 {} } + pub fn read_vectored(&self, _bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> { + match self.0 {} + } + pub fn write(&self, _buf: &[u8]) -> io::Result<usize> { match self.0 {} } + pub fn write_vectored(&self, _bufs: &[IoVec<'_>]) -> io::Result<usize> { + match self.0 {} + } + pub fn flush(&self) -> io::Result<()> { match self.0 {} } diff --git a/src/libstd/sys/sgx/mod.rs b/src/libstd/sys/sgx/mod.rs index dc51a932c61..a99a534f41e 100644 --- a/src/libstd/sys/sgx/mod.rs +++ b/src/libstd/sys/sgx/mod.rs @@ -130,6 +130,15 @@ pub unsafe fn abort_internal() -> ! { abi::usercalls::exit(true) } +// This function is needed by the panic runtime. The symbol is named in +// pre-link args for the target specification, so keep that in sync. +#[cfg(not(test))] +#[no_mangle] +// NB. used by both libunwind and libpanic_abort +pub unsafe extern "C" fn __rust_abort() { + abort_internal(); +} + pub fn hashmap_random_keys() -> (u64, u64) { fn rdrand64() -> u64 { unsafe { @@ -139,7 +148,7 @@ pub fn hashmap_random_keys() -> (u64, u64) { return ret; } } - panic!("Failed to obtain random data"); + rtabort!("Failed to obtain random data"); } } (rdrand64(), rdrand64()) diff --git a/src/libstd/sys/sgx/pipe.rs b/src/libstd/sys/sgx/pipe.rs index 2582b993b60..804d3e001ac 100644 --- a/src/libstd/sys/sgx/pipe.rs +++ b/src/libstd/sys/sgx/pipe.rs @@ -1,4 +1,4 @@ -use crate::io; +use crate::io::{self, IoVec, IoVecMut}; use crate::sys::Void; pub struct AnonPipe(Void); @@ -8,18 +8,23 @@ impl AnonPipe { match self.0 {} } + pub fn read_vectored(&self, _bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> { + match self.0 {} + } + pub fn write(&self, _buf: &[u8]) -> io::Result<usize> { match self.0 {} } + pub fn write_vectored(&self, _bufs: &[IoVec<'_>]) -> io::Result<usize> { + match self.0 {} + } + pub fn diverge(&self) -> ! { match self.0 {} } } -pub fn read2(p1: AnonPipe, - _v1: &mut Vec<u8>, - _p2: AnonPipe, - _v2: &mut Vec<u8>) -> io::Result<()> { +pub fn read2(p1: AnonPipe, _v1: &mut Vec<u8>, _p2: AnonPipe, _v2: &mut Vec<u8>) -> io::Result<()> { match p1.0 {} } diff --git a/src/libstd/sys/sgx/rwlock.rs b/src/libstd/sys/sgx/rwlock.rs index 4cba36aa64d..30c47e44eef 100644 --- a/src/libstd/sys/sgx/rwlock.rs +++ b/src/libstd/sys/sgx/rwlock.rs @@ -1,10 +1,4 @@ -#[cfg(not(test))] -use crate::alloc::{self, Layout}; use crate::num::NonZeroUsize; -#[cfg(not(test))] -use crate::slice; -#[cfg(not(test))] -use crate::str; use super::waitqueue::{ try_lock_or_false, NotifiedTcs, SpinMutex, SpinMutexGuard, WaitQueue, WaitVariable, @@ -105,7 +99,7 @@ impl RWLock { *wguard.lock_var_mut() = true; } else { // No writers were waiting, the lock is released - assert!(rguard.queue_empty()); + rtassert!(rguard.queue_empty()); } } } @@ -165,10 +159,11 @@ impl RWLock { pub unsafe fn destroy(&self) {} } +// The following functions are needed by libunwind. These symbols are named +// in pre-link args for the target specification, so keep that in sync. #[cfg(not(test))] const EINVAL: i32 = 22; -// used by libunwind port #[cfg(not(test))] #[no_mangle] pub unsafe extern "C" fn __rust_rwlock_rdlock(p: *mut RWLock) -> i32 { @@ -198,39 +193,6 @@ pub unsafe extern "C" fn __rust_rwlock_unlock(p: *mut RWLock) -> i32 { return 0; } -// the following functions are also used by the libunwind port. They're -// included here to make sure parallel codegen and LTO don't mess things up. -#[cfg(not(test))] -#[no_mangle] -pub unsafe extern "C" fn __rust_print_err(m: *mut u8, s: i32) { - if s < 0 { - return; - } - let buf = slice::from_raw_parts(m as *const u8, s as _); - if let Ok(s) = str::from_utf8(&buf[..buf.iter().position(|&b| b == 0).unwrap_or(buf.len())]) { - eprint!("{}", s); - } -} - -#[cfg(not(test))] -#[no_mangle] -// NB. used by both libunwind and libpanic_abort -pub unsafe extern "C" fn __rust_abort() { - crate::sys::abort_internal(); -} - -#[cfg(not(test))] -#[no_mangle] -pub unsafe extern "C" fn __rust_c_alloc(size: usize, align: usize) -> *mut u8 { - alloc::alloc(Layout::from_size_align_unchecked(size, align)) -} - -#[cfg(not(test))] -#[no_mangle] -pub unsafe extern "C" fn __rust_c_dealloc(ptr: *mut u8, size: usize, align: usize) { - alloc::dealloc(ptr, Layout::from_size_align_unchecked(size, align)) -} - #[cfg(test)] mod tests { use super::*; diff --git a/src/libstd/sys/sgx/stdio.rs b/src/libstd/sys/sgx/stdio.rs index f2c6892bfb7..a575401f5f6 100644 --- a/src/libstd/sys/sgx/stdio.rs +++ b/src/libstd/sys/sgx/stdio.rs @@ -2,6 +2,10 @@ use fortanix_sgx_abi as abi; use crate::io; use crate::sys::fd::FileDesc; +#[cfg(not(test))] +use crate::slice; +#[cfg(not(test))] +use crate::str; pub struct Stdin(()); pub struct Stdout(()); @@ -62,3 +66,17 @@ pub fn is_ebadf(err: &io::Error) -> bool { pub fn panic_output() -> Option<impl io::Write> { super::abi::panic::SgxPanicOutput::new() } + +// This function is needed by libunwind. The symbol is named in pre-link args +// for the target specification, so keep that in sync. +#[cfg(not(test))] +#[no_mangle] +pub unsafe extern "C" fn __rust_print_err(m: *mut u8, s: i32) { + if s < 0 { + return; + } + let buf = slice::from_raw_parts(m as *const u8, s as _); + if let Ok(s) = str::from_utf8(&buf[..buf.iter().position(|&b| b == 0).unwrap_or(buf.len())]) { + eprint!("{}", s); + } +} diff --git a/src/libstd/sys/sgx/thread.rs b/src/libstd/sys/sgx/thread.rs index a3637723ba1..b9f42d4ad1c 100644 --- a/src/libstd/sys/sgx/thread.rs +++ b/src/libstd/sys/sgx/thread.rs @@ -1,5 +1,4 @@ #![cfg_attr(test, allow(dead_code))] // why is this necessary? -use crate::boxed::FnBox; use crate::ffi::CStr; use crate::io; use crate::time::Duration; @@ -13,17 +12,16 @@ pub const DEFAULT_MIN_STACK_SIZE: usize = 4096; mod task_queue { use crate::sync::{Mutex, MutexGuard, Once}; use crate::sync::mpsc; - use crate::boxed::FnBox; pub type JoinHandle = mpsc::Receiver<()>; pub(super) struct Task { - p: Box<dyn FnBox()>, + p: Box<dyn FnOnce()>, done: mpsc::Sender<()>, } impl Task { - pub(super) fn new(p: Box<dyn FnBox()>) -> (Task, JoinHandle) { + pub(super) fn new(p: Box<dyn FnOnce()>) -> (Task, JoinHandle) { let (done, recv) = mpsc::channel(); (Task { p, done }, recv) } @@ -51,7 +49,7 @@ mod task_queue { impl Thread { // unsafe: see thread::Builder::spawn_unchecked for safety requirements - pub unsafe fn new(_stack: usize, p: Box<dyn FnBox()>) + pub unsafe fn new(_stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> { let mut queue_lock = task_queue::lock(); @@ -62,17 +60,15 @@ impl Thread { } pub(super) fn entry() { - let mut guard = task_queue::lock(); - let task = guard.pop().expect("Thread started but no tasks pending"); - drop(guard); // make sure to not hold the task queue lock longer than necessary + let mut pending_tasks = task_queue::lock(); + let task = rtunwrap!(Some, pending_tasks.pop()); + drop(pending_tasks); // make sure to not hold the task queue lock longer than necessary task.run() } pub fn yield_now() { - assert_eq!( - usercalls::wait(0, usercalls::raw::WAIT_NO).unwrap_err().kind(), - io::ErrorKind::WouldBlock - ); + let wait_error = rtunwrap!(Err, usercalls::wait(0, usercalls::raw::WAIT_NO)); + rtassert!(wait_error.kind() == io::ErrorKind::WouldBlock); } pub fn set_name(_name: &CStr) { @@ -80,7 +76,7 @@ impl Thread { } pub fn sleep(_dur: Duration) { - panic!("can't sleep"); // FIXME + rtabort!("can't sleep"); // FIXME } pub fn join(self) { diff --git a/src/libstd/sys/sgx/waitqueue.rs b/src/libstd/sys/sgx/waitqueue.rs index f4adb7d1e16..d542f9b4101 100644 --- a/src/libstd/sys/sgx/waitqueue.rs +++ b/src/libstd/sys/sgx/waitqueue.rs @@ -121,7 +121,7 @@ impl<'a, T> Drop for WaitGuard<'a, T> { NotifiedTcs::Single(tcs) => Some(tcs), NotifiedTcs::All { .. } => None }; - usercalls::send(EV_UNPARK, target_tcs).unwrap(); + rtunwrap!(Ok, usercalls::send(EV_UNPARK, target_tcs)); } } @@ -141,6 +141,7 @@ impl WaitQueue { /// /// This function does not return until this thread has been awoken. pub fn wait<T>(mut guard: SpinMutexGuard<'_, WaitVariable<T>>) { + // very unsafe: check requirements of UnsafeList::push unsafe { let mut entry = UnsafeListEntry::new(SpinMutex::new(WaitEntry { tcs: thread::current(), @@ -149,10 +150,9 @@ impl WaitQueue { let entry = guard.queue.inner.push(&mut entry); drop(guard); while !entry.lock().wake { - assert_eq!( - usercalls::wait(EV_UNPARK, WAIT_INDEFINITE).unwrap() & EV_UNPARK, - EV_UNPARK - ); + // don't panic, this would invalidate `entry` during unwinding + let eventset = rtunwrap!(Ok, usercalls::wait(EV_UNPARK, WAIT_INDEFINITE)); + rtassert!(eventset & EV_UNPARK == EV_UNPARK); } } } @@ -269,7 +269,7 @@ mod unsafe_list { // ,-------> /---------\ next ---, // | |head_tail| | // `--- prev \---------/ <-------` - assert_eq!(self.head_tail.as_ref().prev, first); + rtassert!(self.head_tail.as_ref().prev == first); true } else { false @@ -285,7 +285,9 @@ mod unsafe_list { /// # Safety /// /// The entry must remain allocated until the entry is removed from the - /// list AND the caller who popped is done using the entry. + /// list AND the caller who popped is done using the entry. Special + /// care must be taken in the caller of `push` to ensure unwinding does + /// not destroy the stack frame containing the entry. pub unsafe fn push<'a>(&mut self, entry: &'a mut UnsafeListEntry<T>) -> &'a T { self.init(); @@ -303,6 +305,7 @@ mod unsafe_list { entry.as_mut().prev = prev_tail; entry.as_mut().next = self.head_tail; prev_tail.as_mut().next = entry; + // unwrap ok: always `Some` on non-dummy entries (*entry.as_ptr()).value.as_ref().unwrap() } @@ -333,6 +336,7 @@ mod unsafe_list { second.as_mut().prev = self.head_tail; first.as_mut().next = NonNull::dangling(); first.as_mut().prev = NonNull::dangling(); + // unwrap ok: always `Some` on non-dummy entries Some((*first.as_ptr()).value.as_ref().unwrap()) } } diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index a36dae2f5a1..a14db108c34 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -2,7 +2,7 @@ use crate::os::unix::prelude::*; use crate::ffi::{CString, CStr, OsString, OsStr}; use crate::fmt; -use crate::io::{self, Error, ErrorKind, SeekFrom}; +use crate::io::{self, Error, ErrorKind, SeekFrom, IoVec, IoVecMut}; use crate::mem; use crate::path::{Path, PathBuf}; use crate::ptr; @@ -36,6 +36,8 @@ use libc::{stat as stat64, fstat as fstat64, lstat as lstat64, off_t as off64_t, target_os = "fuchsia")))] use libc::{readdir_r as readdir64_r}; +pub use crate::sys_common::fs::remove_dir_all; + pub struct File(FileDesc); #[derive(Clone)] @@ -558,6 +560,10 @@ impl File { self.0.read(buf) } + pub fn read_vectored(&self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> { + self.0.read_vectored(bufs) + } + pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> { self.0.read_at(buf, offset) } @@ -566,6 +572,10 @@ impl File { self.0.write(buf) } + pub fn write_vectored(&self, bufs: &[IoVec<'_>]) -> io::Result<usize> { + self.0.write_vectored(bufs) + } + pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> { self.0.write_at(buf, offset) } @@ -734,27 +744,6 @@ pub fn rmdir(p: &Path) -> io::Result<()> { Ok(()) } -pub fn remove_dir_all(path: &Path) -> io::Result<()> { - let filetype = lstat(path)?.file_type(); - if filetype.is_symlink() { - unlink(path) - } else { - remove_dir_all_recursive(path) - } -} - -fn remove_dir_all_recursive(path: &Path) -> io::Result<()> { - for child in readdir(path)? { - let child = child?; - if child.file_type()?.is_dir() { - remove_dir_all_recursive(&child.path())?; - } else { - unlink(&child.path())?; - } - } - rmdir(path) -} - pub fn readlink(p: &Path) -> io::Result<PathBuf> { let c_path = cstr(p)?; let p = c_path.as_ptr(); diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs index bc3c026adab..a7792d42af9 100644 --- a/src/libstd/sys/unix/pipe.rs +++ b/src/libstd/sys/unix/pipe.rs @@ -1,4 +1,4 @@ -use crate::io; +use crate::io::{self, IoVec, IoVecMut}; use crate::mem; use crate::sync::atomic::{AtomicBool, Ordering}; use crate::sys::fd::FileDesc; @@ -60,10 +60,18 @@ impl AnonPipe { self.0.read(buf) } + pub fn read_vectored(&self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> { + self.0.read_vectored(bufs) + } + pub fn write(&self, buf: &[u8]) -> io::Result<usize> { self.0.write(buf) } + pub fn write_vectored(&self, bufs: &[IoVec<'_>]) -> io::Result<usize> { + self.0.write_vectored(bufs) + } + pub fn fd(&self) -> &FileDesc { &self.0 } pub fn into_fd(self) -> FileDesc { self.0 } } diff --git a/src/libstd/sys/unix/stdio.rs b/src/libstd/sys/unix/stdio.rs index 35f163bbdb1..bc2986f624e 100644 --- a/src/libstd/sys/unix/stdio.rs +++ b/src/libstd/sys/unix/stdio.rs @@ -1,5 +1,6 @@ -use crate::io; +use crate::io::{self, IoVec, IoVecMut}; use crate::sys::fd::FileDesc; +use crate::mem::ManuallyDrop; pub struct Stdin(()); pub struct Stdout(()); @@ -11,10 +12,11 @@ impl Stdin { impl io::Read for Stdin { fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { - let fd = FileDesc::new(libc::STDIN_FILENO); - let ret = fd.read(buf); - fd.into_raw(); // do not close this FD - ret + ManuallyDrop::new(FileDesc::new(libc::STDIN_FILENO)).read(buf) + } + + fn read_vectored(&mut self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> { + ManuallyDrop::new(FileDesc::new(libc::STDIN_FILENO)).read_vectored(bufs) } } @@ -24,10 +26,11 @@ impl Stdout { impl io::Write for Stdout { fn write(&mut self, buf: &[u8]) -> io::Result<usize> { - let fd = FileDesc::new(libc::STDOUT_FILENO); - let ret = fd.write(buf); - fd.into_raw(); // do not close this FD - ret + ManuallyDrop::new(FileDesc::new(libc::STDOUT_FILENO)).write(buf) + } + + fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result<usize> { + ManuallyDrop::new(FileDesc::new(libc::STDOUT_FILENO)).write_vectored(bufs) } fn flush(&mut self) -> io::Result<()> { @@ -41,10 +44,11 @@ impl Stderr { impl io::Write for Stderr { fn write(&mut self, buf: &[u8]) -> io::Result<usize> { - let fd = FileDesc::new(libc::STDERR_FILENO); - let ret = fd.write(buf); - fd.into_raw(); // do not close this FD - ret + ManuallyDrop::new(FileDesc::new(libc::STDERR_FILENO)).write(buf) + } + + fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result<usize> { + ManuallyDrop::new(FileDesc::new(libc::STDERR_FILENO)).write_vectored(bufs) } fn flush(&mut self) -> io::Result<()> { diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs index feb15e8f585..f7d604ac4c8 100644 --- a/src/libstd/sys/unix/thread.rs +++ b/src/libstd/sys/unix/thread.rs @@ -1,4 +1,3 @@ -use crate::boxed::FnBox; use crate::cmp; use crate::ffi::CStr; use crate::io; @@ -39,7 +38,7 @@ unsafe fn pthread_attr_setstacksize(_attr: *mut libc::pthread_attr_t, impl Thread { // unsafe: see thread::Builder::spawn_unchecked for safety requirements - pub unsafe fn new(stack: usize, p: Box<dyn FnBox()>) + pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> { let p = box p; let mut native: libc::pthread_t = mem::zeroed(); diff --git a/src/libstd/sys/unix/time.rs b/src/libstd/sys/unix/time.rs index 127ae6aa104..e21c32cd91b 100644 --- a/src/libstd/sys/unix/time.rs +++ b/src/libstd/sys/unix/time.rs @@ -114,7 +114,8 @@ impl Hash for Timespec { #[cfg(any(target_os = "macos", target_os = "ios"))] mod inner { use crate::fmt; - use crate::sync::Once; + use crate::mem; + use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst}; use crate::sys::cvt; use crate::sys_common::mul_div_u64; use crate::time::Duration; @@ -229,18 +230,30 @@ mod inner { Some(mul_div_u64(nanos, info.denom as u64, info.numer as u64)) } - fn info() -> &'static libc::mach_timebase_info { + fn info() -> libc::mach_timebase_info { static mut INFO: libc::mach_timebase_info = libc::mach_timebase_info { numer: 0, denom: 0, }; - static ONCE: Once = Once::new(); + static STATE: AtomicUsize = AtomicUsize::new(0); unsafe { - ONCE.call_once(|| { - libc::mach_timebase_info(&mut INFO); - }); - &INFO + // If a previous thread has filled in this global state, use that. + if STATE.load(SeqCst) == 2 { + return INFO; + } + + // ... otherwise learn for ourselves ... + let mut info = mem::zeroed(); + libc::mach_timebase_info(&mut info); + + // ... and attempt to be the one thread that stores it globally for + // all other threads + if STATE.compare_exchange(0, 1, SeqCst, SeqCst).is_ok() { + INFO = info; + STATE.store(2, SeqCst); + } + return info; } } } diff --git a/src/libstd/sys/wasi/args.rs b/src/libstd/sys/wasi/args.rs index 20558a8042d..9c8e59e4fb5 100644 --- a/src/libstd/sys/wasi/args.rs +++ b/src/libstd/sys/wasi/args.rs @@ -1,30 +1,15 @@ -use crate::any::Any; use crate::ffi::CStr; +use crate::io; +use crate::sys::cvt_wasi; use crate::ffi::OsString; use crate::marker::PhantomData; use crate::os::wasi::ffi::OsStringExt; -use crate::ptr; use crate::vec; -static mut ARGC: isize = 0; -static mut ARGV: *const *const u8 = ptr::null(); - -#[cfg(not(target_feature = "atomics"))] -pub unsafe fn args_lock() -> impl Any { - // No need for a lock if we're single-threaded, but this function will need - // to get implemented for multi-threaded scenarios -} - -pub unsafe fn init(argc: isize, argv: *const *const u8) { - let _guard = args_lock(); - ARGC = argc; - ARGV = argv; +pub unsafe fn init(_argc: isize, _argv: *const *const u8) { } pub unsafe fn cleanup() { - let _guard = args_lock(); - ARGC = 0; - ARGV = ptr::null(); } pub struct Args { @@ -34,18 +19,31 @@ pub struct Args { /// Returns the command line arguments pub fn args() -> Args { + maybe_args().unwrap_or_else(|_| { + Args { + iter: Vec::new().into_iter(), + _dont_send_or_sync_me: PhantomData + } + }) +} + +fn maybe_args() -> io::Result<Args> { unsafe { - let _guard = args_lock(); - let args = (0..ARGC) - .map(|i| { - let cstr = CStr::from_ptr(*ARGV.offset(i) as *const libc::c_char); - OsStringExt::from_vec(cstr.to_bytes().to_vec()) - }) + let (mut argc, mut argv_buf_size) = (0, 0); + cvt_wasi(libc::__wasi_args_sizes_get(&mut argc, &mut argv_buf_size))?; + + let mut argc = vec![0 as *mut libc::c_char; argc]; + let mut argv_buf = vec![0; argv_buf_size]; + cvt_wasi(libc::__wasi_args_get(argc.as_mut_ptr(), argv_buf.as_mut_ptr()))?; + + let args = argc.into_iter() + .map(|ptr| CStr::from_ptr(ptr).to_bytes().to_vec()) + .map(|bytes| OsString::from_vec(bytes)) .collect::<Vec<_>>(); - Args { + Ok(Args { iter: args.into_iter(), _dont_send_or_sync_me: PhantomData, - } + }) } } diff --git a/src/libstd/sys/wasi/ext/ffi.rs b/src/libstd/sys/wasi/ext/ffi.rs index 07b93dd143f..f71f316d1ba 100644 --- a/src/libstd/sys/wasi/ext/ffi.rs +++ b/src/libstd/sys/wasi/ext/ffi.rs @@ -2,60 +2,5 @@ #![stable(feature = "rust1", since = "1.0.0")] -use crate::ffi::{OsStr, OsString}; -use crate::mem; -use crate::sys::os_str::Buf; -use crate::sys_common::{FromInner, IntoInner, AsInner}; - -/// WASI-specific extensions to [`OsString`]. -/// -/// [`OsString`]: ../../../../std/ffi/struct.OsString.html -#[stable(feature = "rust1", since = "1.0.0")] -pub trait OsStringExt { - /// Creates an `OsString` from a byte vector. - #[stable(feature = "rust1", since = "1.0.0")] - fn from_vec(vec: Vec<u8>) -> Self; - - /// Yields the underlying byte vector of this `OsString`. - #[stable(feature = "rust1", since = "1.0.0")] - fn into_vec(self) -> Vec<u8>; -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl OsStringExt for OsString { - fn from_vec(vec: Vec<u8>) -> OsString { - FromInner::from_inner(Buf { inner: vec }) - } - fn into_vec(self) -> Vec<u8> { - self.into_inner().inner - } -} - -/// WASI-specific extensions to [`OsStr`]. -/// -/// [`OsStr`]: ../../../../std/ffi/struct.OsStr.html #[stable(feature = "rust1", since = "1.0.0")] -pub trait OsStrExt { - #[stable(feature = "rust1", since = "1.0.0")] - /// Creates an [`OsStr`] from a byte slice. - /// - /// [`OsStr`]: ../../../ffi/struct.OsStr.html - fn from_bytes(slice: &[u8]) -> &Self; - - /// Gets the underlying byte view of the [`OsStr`] slice. - /// - /// [`OsStr`]: ../../../ffi/struct.OsStr.html - #[stable(feature = "rust1", since = "1.0.0")] - fn as_bytes(&self) -> &[u8]; -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl OsStrExt for OsStr { - fn from_bytes(slice: &[u8]) -> &OsStr { - unsafe { mem::transmute(slice) } - } - fn as_bytes(&self) -> &[u8] { - &self.as_inner().inner - } -} - +pub use crate::sys_common::os_str_bytes::*; diff --git a/src/libstd/sys/wasi/ext/fs.rs b/src/libstd/sys/wasi/ext/fs.rs new file mode 100644 index 00000000000..53f415c7821 --- /dev/null +++ b/src/libstd/sys/wasi/ext/fs.rs @@ -0,0 +1,412 @@ +//! WASI-specific extensions to primitives in the `std::fs` module. + +#![unstable(feature = "wasi_ext", issue = "0")] + +use crate::fs::{self, File, Metadata, OpenOptions}; +use crate::io::{self, IoVec, IoVecMut}; +use crate::os::wasi::ffi::OsStrExt; +use crate::path::{Path, PathBuf}; +use crate::sys_common::{AsInner, AsInnerMut, FromInner}; + +/// WASI-specific extensions to [`File`]. +/// +/// [`File`]: ../../../../std/fs/struct.File.html +pub trait FileExt { + /// Reads a number of bytes starting from a given offset. + /// + /// Returns the number of bytes read. + /// + /// The offset is relative to the start of the file and thus independent + /// from the current cursor. + /// + /// The current file cursor is not affected by this function. + /// + /// Note that similar to [`File::read_vectored`], it is not an error to + /// return with a short read. + /// + /// [`File::read`]: ../../../../std/fs/struct.File.html#method.read_vectored + fn read_at(&self, bufs: &mut [IoVecMut<'_>], offset: u64) -> io::Result<usize>; + + /// Writes a number of bytes starting from a given offset. + /// + /// Returns the number of bytes written. + /// + /// The offset is relative to the start of the file and thus independent + /// from the current cursor. + /// + /// The current file cursor is not affected by this function. + /// + /// When writing beyond the end of the file, the file is appropriately + /// extended and the intermediate bytes are initialized with the value 0. + /// + /// Note that similar to [`File::write_vectored`], it is not an error to return a + /// short write. + /// + /// [`File::write`]: ../../../../std/fs/struct.File.html#method.write_vectored + fn write_at(&self, bufs: &[IoVec<'_>], offset: u64) -> io::Result<usize>; + + /// Returns the current position within the file. + /// + /// This corresponds to the `__wasi_fd_tell` syscall and is similar to + /// `seek` where you offset 0 bytes from the current position. + fn tell(&self) -> io::Result<u64>; + + /// Adjust the flags associated with this file. + /// + /// This corresponds to the `__wasi_fd_fdstat_set_flags` syscall. + fn fdstat_set_flags(&self, flags: u16) -> io::Result<()>; + + /// Adjust the rights associated with this file. + /// + /// This corresponds to the `__wasi_fd_fdstat_set_rights` syscall. + fn fdstat_set_rights(&self, rights: u64, inheriting: u64) -> io::Result<()>; + + /// Provide file advisory information on a file descriptor. + /// + /// This corresponds to the `__wasi_fd_advise` syscall. + fn advise(&self, offset: u64, len: u64, advice: u8) -> io::Result<()>; + + /// Force the allocation of space in a file. + /// + /// This corresponds to the `__wasi_fd_allocate` syscall. + fn allocate(&self, offset: u64, len: u64) -> io::Result<()>; + + /// Create a directory. + /// + /// This corresponds to the `__wasi_path_create_directory` syscall. + fn create_directory<P: AsRef<Path>>(&self, dir: P) -> io::Result<()>; + + /// Read the contents of a symbolic link. + /// + /// This corresponds to the `__wasi_path_readlink` syscall. + fn read_link<P: AsRef<Path>>(&self, path: P) -> io::Result<PathBuf>; + + /// Return the attributes of a file or directory. + /// + /// This corresponds to the `__wasi_path_filestat_get` syscall. + fn metadata_at<P: AsRef<Path>>(&self, lookup_flags: u32, path: P) -> io::Result<Metadata>; + + /// Unlink a file. + /// + /// This corresponds to the `__wasi_path_unlink_file` syscall. + fn remove_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()>; + + /// Remove a directory. + /// + /// This corresponds to the `__wasi_path_remove_directory` syscall. + fn remove_directory<P: AsRef<Path>>(&self, path: P) -> io::Result<()>; +} + +// FIXME: bind __wasi_fd_fdstat_get - need to define a custom return type +// FIXME: bind __wasi_fd_readdir - can't return `ReadDir` since we only have entry name +// FIXME: bind __wasi_fd_filestat_set_times maybe? - on crates.io for unix +// FIXME: bind __wasi_path_filestat_set_times maybe? - on crates.io for unix +// FIXME: bind __wasi_poll_oneoff maybe? - probably should wait for I/O to settle +// FIXME: bind __wasi_random_get maybe? - on crates.io for unix + +impl FileExt for fs::File { + fn read_at(&self, bufs: &mut [IoVecMut<'_>], offset: u64) -> io::Result<usize> { + self.as_inner().fd().pread(bufs, offset) + } + + fn write_at(&self, bufs: &[IoVec<'_>], offset: u64) -> io::Result<usize> { + self.as_inner().fd().pwrite(bufs, offset) + } + + fn tell(&self) -> io::Result<u64> { + self.as_inner().fd().tell() + } + + fn fdstat_set_flags(&self, flags: u16) -> io::Result<()> { + self.as_inner().fd().set_flags(flags) + } + + fn fdstat_set_rights(&self, rights: u64, inheriting: u64) -> io::Result<()> { + self.as_inner().fd().set_rights(rights, inheriting) + } + + fn advise(&self, offset: u64, len: u64, advice: u8) -> io::Result<()> { + self.as_inner().fd().advise(offset, len, advice) + } + + fn allocate(&self, offset: u64, len: u64) -> io::Result<()> { + self.as_inner().fd().allocate(offset, len) + } + + fn create_directory<P: AsRef<Path>>(&self, dir: P) -> io::Result<()> { + self.as_inner() + .fd() + .create_directory(dir.as_ref().as_os_str().as_bytes()) + } + + fn read_link<P: AsRef<Path>>(&self, path: P) -> io::Result<PathBuf> { + self.as_inner().read_link(path.as_ref()) + } + + fn metadata_at<P: AsRef<Path>>(&self, lookup_flags: u32, path: P) -> io::Result<Metadata> { + let m = self.as_inner().metadata_at(lookup_flags, path.as_ref())?; + Ok(FromInner::from_inner(m)) + } + + fn remove_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()> { + self.as_inner() + .fd() + .unlink_file(path.as_ref().as_os_str().as_bytes()) + } + + fn remove_directory<P: AsRef<Path>>(&self, path: P) -> io::Result<()> { + self.as_inner() + .fd() + .remove_directory(path.as_ref().as_os_str().as_bytes()) + } +} + +/// WASI-specific extensions to [`fs::OpenOptions`]. +/// +/// [`fs::OpenOptions`]: ../../../../std/fs/struct.OpenOptions.html +pub trait OpenOptionsExt { + /// Pass custom `dirflags` argument to `__wasi_path_open`. + /// + /// This option configures the `dirflags` argument to the + /// `__wasi_path_open` syscall which `OpenOptions` will eventually call. The + /// `dirflags` argument configures how the file is looked up, currently + /// primarily affecting whether symlinks are followed or not. + /// + /// By default this value is `__WASI_LOOKUP_SYMLINK_FOLLOW`, or symlinks are + /// followed. You can call this method with 0 to disable following symlinks + fn lookup_flags(&mut self, flags: u32) -> &mut Self; + + /// Indicates whether `OpenOptions` must open a directory or not. + /// + /// This method will configure whether the `__WASI_O_DIRECTORY` flag is + /// passed when opening a file. When passed it will require that the opened + /// path is a directory. + /// + /// This option is by default `false` + fn directory(&mut self, dir: bool) -> &mut Self; + + /// Indicates whether `__WASI_FDFLAG_DSYNC` is passed in the `fs_flags` + /// field of `__wasi_path_open`. + /// + /// This option is by default `false` + fn dsync(&mut self, dsync: bool) -> &mut Self; + + /// Indicates whether `__WASI_FDFLAG_NONBLOCK` is passed in the `fs_flags` + /// field of `__wasi_path_open`. + /// + /// This option is by default `false` + fn nonblock(&mut self, nonblock: bool) -> &mut Self; + + /// Indicates whether `__WASI_FDFLAG_RSYNC` is passed in the `fs_flags` + /// field of `__wasi_path_open`. + /// + /// This option is by default `false` + fn rsync(&mut self, rsync: bool) -> &mut Self; + + /// Indicates whether `__WASI_FDFLAG_SYNC` is passed in the `fs_flags` + /// field of `__wasi_path_open`. + /// + /// This option is by default `false` + fn sync(&mut self, sync: bool) -> &mut Self; + + /// Indicates the value that should be passed in for the `fs_rights_base` + /// parameter of `__wasi_path_open`. + /// + /// This option defaults based on the `read` and `write` configuration of + /// this `OpenOptions` builder. If this method is called, however, the + /// exact mask passed in will be used instead. + fn fs_rights_base(&mut self, rights: u64) -> &mut Self; + + /// Indicates the value that should be passed in for the + /// `fs_rights_inheriting` parameter of `__wasi_path_open`. + /// + /// The default for this option is the same value as what will be passed + /// for the `fs_rights_base` parameter but if this method is called then + /// the specified value will be used instead. + fn fs_rights_inheriting(&mut self, rights: u64) -> &mut Self; + + /// Open a file or directory. + /// + /// This corresponds to the `__wasi_path_open` syscall. + fn open_at<P: AsRef<Path>>(&self, file: &File, path: P) -> io::Result<File>; +} + +impl OpenOptionsExt for OpenOptions { + fn lookup_flags(&mut self, flags: u32) -> &mut OpenOptions { + self.as_inner_mut().lookup_flags(flags); + self + } + + fn directory(&mut self, dir: bool) -> &mut OpenOptions { + self.as_inner_mut().directory(dir); + self + } + + fn dsync(&mut self, enabled: bool) -> &mut OpenOptions { + self.as_inner_mut().dsync(enabled); + self + } + + fn nonblock(&mut self, enabled: bool) -> &mut OpenOptions { + self.as_inner_mut().nonblock(enabled); + self + } + + fn rsync(&mut self, enabled: bool) -> &mut OpenOptions { + self.as_inner_mut().rsync(enabled); + self + } + + fn sync(&mut self, enabled: bool) -> &mut OpenOptions { + self.as_inner_mut().sync(enabled); + self + } + + fn fs_rights_base(&mut self, rights: u64) -> &mut OpenOptions { + self.as_inner_mut().fs_rights_base(rights); + self + } + + fn fs_rights_inheriting(&mut self, rights: u64) -> &mut OpenOptions { + self.as_inner_mut().fs_rights_inheriting(rights); + self + } + + fn open_at<P: AsRef<Path>>(&self, file: &File, path: P) -> io::Result<File> { + let inner = file.as_inner().open_at(path.as_ref(), self.as_inner())?; + Ok(File::from_inner(inner)) + } +} + +/// WASI-specific extensions to [`fs::Metadata`]. +/// +/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html +pub trait MetadataExt { + /// Returns the `st_dev` field of the internal `__wasi_filestat_t` + fn dev(&self) -> u64; + /// Returns the `st_ino` field of the internal `__wasi_filestat_t` + fn ino(&self) -> u64; + /// Returns the `st_nlink` field of the internal `__wasi_filestat_t` + fn nlink(&self) -> u32; + /// Returns the `st_atim` field of the internal `__wasi_filestat_t` + fn atim(&self) -> u64; + /// Returns the `st_mtim` field of the internal `__wasi_filestat_t` + fn mtim(&self) -> u64; + /// Returns the `st_ctim` field of the internal `__wasi_filestat_t` + fn ctim(&self) -> u64; +} + +impl MetadataExt for fs::Metadata { + fn dev(&self) -> u64 { + self.as_inner().as_wasi().st_dev + } + fn ino(&self) -> u64 { + self.as_inner().as_wasi().st_ino + } + fn nlink(&self) -> u32 { + self.as_inner().as_wasi().st_nlink + } + fn atim(&self) -> u64 { + self.as_inner().as_wasi().st_atim + } + fn mtim(&self) -> u64 { + self.as_inner().as_wasi().st_mtim + } + fn ctim(&self) -> u64 { + self.as_inner().as_wasi().st_ctim + } +} + +/// WASI-specific extensions for [`FileType`]. +/// +/// Adds support for special WASI file types such as block/character devices, +/// pipes, and sockets. +/// +/// [`FileType`]: ../../../../std/fs/struct.FileType.html +pub trait FileTypeExt { + /// Returns `true` if this file type is a block device. + fn is_block_device(&self) -> bool; + /// Returns `true` if this file type is a character device. + fn is_character_device(&self) -> bool; + /// Returns `true` if this file type is a socket datagram. + fn is_socket_dgram(&self) -> bool; + /// Returns `true` if this file type is a socket stream. + fn is_socket_stream(&self) -> bool; +} + +impl FileTypeExt for fs::FileType { + fn is_block_device(&self) -> bool { + self.as_inner().bits() == libc::__WASI_FILETYPE_BLOCK_DEVICE + } + fn is_character_device(&self) -> bool { + self.as_inner().bits() == libc::__WASI_FILETYPE_CHARACTER_DEVICE + } + fn is_socket_dgram(&self) -> bool { + self.as_inner().bits() == libc::__WASI_FILETYPE_SOCKET_DGRAM + } + fn is_socket_stream(&self) -> bool { + self.as_inner().bits() == libc::__WASI_FILETYPE_SOCKET_STREAM + } +} + +/// WASI-specific extension methods for [`fs::DirEntry`]. +/// +/// [`fs::DirEntry`]: ../../../../std/fs/struct.DirEntry.html +pub trait DirEntryExt { + /// Returns the underlying `d_ino` field of the `__wasi_dirent_t` + fn ino(&self) -> u64; +} + +impl DirEntryExt for fs::DirEntry { + fn ino(&self) -> u64 { + self.as_inner().ino() + } +} + +/// Create a hard link. +/// +/// This corresponds to the `__wasi_path_link` syscall. +pub fn link<P: AsRef<Path>, U: AsRef<Path>>( + old_fd: &File, + old_flags: u32, + old_path: P, + new_fd: &File, + new_path: U, +) -> io::Result<()> { + old_fd.as_inner().fd().link( + old_flags, + old_path.as_ref().as_os_str().as_bytes(), + new_fd.as_inner().fd(), + new_path.as_ref().as_os_str().as_bytes(), + ) +} + +/// Rename a file or directory. +/// +/// This corresponds to the `__wasi_path_rename` syscall. +pub fn rename<P: AsRef<Path>, U: AsRef<Path>>( + old_fd: &File, + old_path: P, + new_fd: &File, + new_path: U, +) -> io::Result<()> { + old_fd.as_inner().fd().rename( + old_path.as_ref().as_os_str().as_bytes(), + new_fd.as_inner().fd(), + new_path.as_ref().as_os_str().as_bytes(), + ) +} + +/// Create a symbolic link. +/// +/// This corresponds to the `__wasi_path_symlink` syscall. +pub fn symlink<P: AsRef<Path>, U: AsRef<Path>>( + old_path: P, + fd: &File, + new_path: U, +) -> io::Result<()> { + fd.as_inner().fd().symlink( + old_path.as_ref().as_os_str().as_bytes(), + new_path.as_ref().as_os_str().as_bytes(), + ) +} diff --git a/src/libstd/sys/wasi/ext/io.rs b/src/libstd/sys/wasi/ext/io.rs new file mode 100644 index 00000000000..12afd1d42dc --- /dev/null +++ b/src/libstd/sys/wasi/ext/io.rs @@ -0,0 +1,142 @@ +//! WASI-specific extensions to general I/O primitives + +#![unstable(feature = "wasi_ext", issue = "0")] + +use crate::fs; +use crate::io; +use crate::sys; +use crate::net; +use crate::sys_common::{AsInner, FromInner, IntoInner}; + +/// Raw file descriptors. +pub type RawFd = u32; + +/// A trait to extract the raw WASI file descriptor from an underlying +/// object. +pub trait AsRawFd { + /// Extracts the raw file descriptor. + /// + /// This method does **not** pass ownership of the raw file descriptor + /// to the caller. The descriptor is only guaranteed to be valid while + /// the original object has not yet been destroyed. + fn as_raw_fd(&self) -> RawFd; +} + +/// A trait to express the ability to construct an object from a raw file +/// descriptor. +pub trait FromRawFd { + /// Constructs a new instance of `Self` from the given raw file + /// descriptor. + /// + /// This function **consumes ownership** of the specified file + /// descriptor. The returned object will take responsibility for closing + /// it when the object goes out of scope. + /// + /// This function is also unsafe as the primitives currently returned + /// have the contract that they are the sole owner of the file + /// descriptor they are wrapping. Usage of this function could + /// accidentally allow violating this contract which can cause memory + /// unsafety in code that relies on it being true. + unsafe fn from_raw_fd(fd: RawFd) -> Self; +} + +/// A trait to express the ability to consume an object and acquire ownership of +/// its raw file descriptor. +pub trait IntoRawFd { + /// Consumes this object, returning the raw underlying file descriptor. + /// + /// This function **transfers ownership** of the underlying file descriptor + /// to the caller. Callers are then the unique owners of the file descriptor + /// and must close the descriptor once it's no longer needed. + fn into_raw_fd(self) -> RawFd; +} + +impl AsRawFd for net::TcpStream { + fn as_raw_fd(&self) -> RawFd { + self.as_inner().fd().as_raw() + } +} + +impl FromRawFd for net::TcpStream { + unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream { + net::TcpStream::from_inner(sys::net::TcpStream::from_inner(fd)) + } +} + +impl IntoRawFd for net::TcpStream { + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_fd().into_raw() + } +} + +impl AsRawFd for net::TcpListener { + fn as_raw_fd(&self) -> RawFd { + self.as_inner().fd().as_raw() + } +} + +impl FromRawFd for net::TcpListener { + unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener { + net::TcpListener::from_inner(sys::net::TcpListener::from_inner(fd)) + } +} + +impl IntoRawFd for net::TcpListener { + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_fd().into_raw() + } +} + +impl AsRawFd for net::UdpSocket { + fn as_raw_fd(&self) -> RawFd { + self.as_inner().fd().as_raw() + } +} + +impl FromRawFd for net::UdpSocket { + unsafe fn from_raw_fd(fd: RawFd) -> net::UdpSocket { + net::UdpSocket::from_inner(sys::net::UdpSocket::from_inner(fd)) + } +} + +impl IntoRawFd for net::UdpSocket { + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_fd().into_raw() + } +} + +impl AsRawFd for fs::File { + fn as_raw_fd(&self) -> RawFd { + self.as_inner().fd().as_raw() + } +} + +impl FromRawFd for fs::File { + unsafe fn from_raw_fd(fd: RawFd) -> fs::File { + fs::File::from_inner(sys::fs::File::from_inner(fd)) + } +} + +impl IntoRawFd for fs::File { + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_fd().into_raw() + } +} + +impl AsRawFd for io::Stdin { + fn as_raw_fd(&self) -> RawFd { + libc::STDIN_FILENO as u32 + } +} + +impl AsRawFd for io::Stdout { + fn as_raw_fd(&self) -> RawFd { + libc::STDOUT_FILENO as u32 + } +} + +impl AsRawFd for io::Stderr { + fn as_raw_fd(&self) -> RawFd { + libc::STDERR_FILENO as u32 + } +} diff --git a/src/libstd/sys/wasi/ext/mod.rs b/src/libstd/sys/wasi/ext/mod.rs index 877b9ed89d8..1c24b244b8c 100644 --- a/src/libstd/sys/wasi/ext/mod.rs +++ b/src/libstd/sys/wasi/ext/mod.rs @@ -1,4 +1,6 @@ pub mod ffi; +pub mod fs; +pub mod io; /// A prelude for conveniently writing platform-specific code. /// @@ -7,4 +9,10 @@ pub mod ffi; pub mod prelude { #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] pub use crate::sys::ext::ffi::{OsStringExt, OsStrExt}; + #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] + pub use crate::sys::ext::fs::{FileExt, DirEntryExt, MetadataExt, OpenOptionsExt}; + #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] + pub use crate::sys::ext::fs::FileTypeExt; + #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] + pub use crate::sys::ext::io::{AsRawFd, IntoRawFd, FromRawFd}; } diff --git a/src/libstd/sys/wasi/fd.rs b/src/libstd/sys/wasi/fd.rs index 29e1880b8f1..0b68b6f4d9c 100644 --- a/src/libstd/sys/wasi/fd.rs +++ b/src/libstd/sys/wasi/fd.rs @@ -6,6 +6,7 @@ use crate::net::Shutdown; use crate::sys::cvt_wasi; use libc::{self, c_char, c_void}; +#[derive(Debug)] pub struct WasiFd { fd: libc::__wasi_fd_t, } @@ -52,6 +53,16 @@ impl WasiFd { WasiFd { fd } } + pub fn into_raw(self) -> libc::__wasi_fd_t { + let ret = self.fd; + mem::forget(self); + ret + } + + pub fn as_raw(&self) -> libc::__wasi_fd_t { + self.fd + } + pub fn datasync(&self) -> io::Result<()> { cvt_wasi(unsafe { libc::__wasi_fd_datasync(self.fd) }) } @@ -123,7 +134,7 @@ impl WasiFd { cvt_wasi(unsafe { libc::__wasi_fd_allocate(self.fd, offset, len) }) } - pub fn crate_directory(&self, path: &[u8]) -> io::Result<()> { + pub fn create_directory(&self, path: &[u8]) -> io::Result<()> { cvt_wasi(unsafe { libc::__wasi_path_create_directory(self.fd, path.as_ptr() as *const c_char, path.len()) }) @@ -217,7 +228,9 @@ impl WasiFd { }) } - // FIXME: __wasi_fd_filestat_get + pub fn filestat_get(&self, buf: *mut libc::__wasi_filestat_t) -> io::Result<()> { + cvt_wasi(unsafe { libc::__wasi_fd_filestat_get(self.fd, buf) }) + } pub fn filestat_set_times( &self, @@ -232,7 +245,22 @@ impl WasiFd { cvt_wasi(unsafe { libc::__wasi_fd_filestat_set_size(self.fd, size) }) } - // FIXME: __wasi_path_filestat_get + pub fn path_filestat_get( + &self, + flags: LookupFlags, + path: &[u8], + buf: *mut libc::__wasi_filestat_t, + ) -> io::Result<()> { + cvt_wasi(unsafe { + libc::__wasi_path_filestat_get( + self.fd, + flags, + path.as_ptr() as *const c_char, + path.len(), + buf, + ) + }) + } pub fn path_filestat_set_times( &self, diff --git a/src/libstd/sys/wasi/fs.rs b/src/libstd/sys/wasi/fs.rs index 68c8e9356a8..589593299d6 100644 --- a/src/libstd/sys/wasi/fs.rs +++ b/src/libstd/sys/wasi/fs.rs @@ -1,138 +1,142 @@ -use crate::ffi::OsString; +use crate::ffi::{CStr, CString, OsStr, OsString}; use crate::fmt; -use crate::hash::{Hash, Hasher}; -use crate::io::{self, SeekFrom}; +use crate::io::{self, IoVec, IoVecMut, SeekFrom}; +use crate::iter; +use crate::mem::{self, ManuallyDrop}; +use crate::os::wasi::ffi::{OsStrExt, OsStringExt}; use crate::path::{Path, PathBuf}; +use crate::ptr; +use crate::sync::Arc; +use crate::sys::fd::{DirCookie, WasiFd}; use crate::sys::time::SystemTime; -use crate::sys::{unsupported, Void}; +use crate::sys::unsupported; +use crate::sys_common::FromInner; -pub struct File(Void); +pub use crate::sys_common::fs::copy; +pub use crate::sys_common::fs::remove_dir_all; -pub struct FileAttr(Void); +pub struct File { + fd: WasiFd, +} + +#[derive(Clone)] +pub struct FileAttr { + meta: libc::__wasi_filestat_t, +} -pub struct ReadDir(Void); +pub struct ReadDir { + inner: Arc<ReadDirInner>, + cookie: Option<DirCookie>, + buf: Vec<u8>, + offset: usize, + cap: usize, +} -pub struct DirEntry(Void); +struct ReadDirInner { + root: PathBuf, + dir: File, +} + +pub struct DirEntry { + meta: libc::__wasi_dirent_t, + name: Vec<u8>, + inner: Arc<ReadDirInner>, +} -#[derive(Clone, Debug)] -pub struct OpenOptions { } +#[derive(Clone, Debug, Default)] +pub struct OpenOptions { + read: bool, + write: bool, + dirflags: libc::__wasi_lookupflags_t, + fdflags: libc::__wasi_fdflags_t, + oflags: libc::__wasi_oflags_t, + rights_base: Option<libc::__wasi_rights_t>, + rights_inheriting: Option<libc::__wasi_rights_t>, +} -pub struct FilePermissions(Void); +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct FilePermissions { + readonly: bool, +} -pub struct FileType(Void); +#[derive(PartialEq, Eq, Hash, Debug, Copy, Clone)] +pub struct FileType { + bits: libc::__wasi_filetype_t, +} #[derive(Debug)] -pub struct DirBuilder { } +pub struct DirBuilder {} impl FileAttr { + fn zero() -> FileAttr { + FileAttr { + meta: unsafe { mem::zeroed() }, + } + } + pub fn size(&self) -> u64 { - match self.0 {} + self.meta.st_size } pub fn perm(&self) -> FilePermissions { - match self.0 {} + // not currently implemented in wasi yet + FilePermissions { readonly: false } } pub fn file_type(&self) -> FileType { - match self.0 {} + FileType { + bits: self.meta.st_filetype, + } } pub fn modified(&self) -> io::Result<SystemTime> { - match self.0 {} + Ok(SystemTime::from_wasi_timestamp(self.meta.st_mtim)) } pub fn accessed(&self) -> io::Result<SystemTime> { - match self.0 {} + Ok(SystemTime::from_wasi_timestamp(self.meta.st_atim)) } pub fn created(&self) -> io::Result<SystemTime> { - match self.0 {} + Ok(SystemTime::from_wasi_timestamp(self.meta.st_ctim)) } -} -impl Clone for FileAttr { - fn clone(&self) -> FileAttr { - match self.0 {} + pub fn as_wasi(&self) -> &libc::__wasi_filestat_t { + &self.meta } } impl FilePermissions { pub fn readonly(&self) -> bool { - match self.0 {} - } - - pub fn set_readonly(&mut self, _readonly: bool) { - match self.0 {} - } -} - -impl Clone for FilePermissions { - fn clone(&self) -> FilePermissions { - match self.0 {} - } -} - -impl PartialEq for FilePermissions { - fn eq(&self, _other: &FilePermissions) -> bool { - match self.0 {} + self.readonly } -} - -impl Eq for FilePermissions { -} -impl fmt::Debug for FilePermissions { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 {} + pub fn set_readonly(&mut self, readonly: bool) { + self.readonly = readonly; } } impl FileType { pub fn is_dir(&self) -> bool { - match self.0 {} + self.bits == libc::__WASI_FILETYPE_DIRECTORY } pub fn is_file(&self) -> bool { - match self.0 {} + self.bits == libc::__WASI_FILETYPE_REGULAR_FILE } pub fn is_symlink(&self) -> bool { - match self.0 {} - } -} - -impl Clone for FileType { - fn clone(&self) -> FileType { - match self.0 {} - } -} - -impl Copy for FileType {} - -impl PartialEq for FileType { - fn eq(&self, _other: &FileType) -> bool { - match self.0 {} - } -} - -impl Eq for FileType { -} - -impl Hash for FileType { - fn hash<H: Hasher>(&self, _h: &mut H) { - match self.0 {} + self.bits == libc::__WASI_FILETYPE_SYMBOLIC_LINK } -} -impl fmt::Debug for FileType { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 {} + pub fn bits(&self) -> libc::__wasi_filetype_t { + self.bits } } impl fmt::Debug for ReadDir { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 {} + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ReadDir").finish() } } @@ -140,155 +144,548 @@ impl Iterator for ReadDir { type Item = io::Result<DirEntry>; fn next(&mut self) -> Option<io::Result<DirEntry>> { - match self.0 {} + loop { + // If we've reached the capacity of our buffer then we need to read + // some more from the OS, otherwise we pick up at our old offset. + let offset = if self.offset == self.cap { + let cookie = self.cookie.take()?; + match self.inner.dir.fd.readdir(&mut self.buf, cookie) { + Ok(bytes) => self.cap = bytes, + Err(e) => return Some(Err(e)), + } + self.offset = 0; + self.cookie = Some(cookie); + + // If we didn't actually read anything, this is in theory the + // end of the directory. + if self.cap == 0 { + self.cookie = None; + return None; + } + + 0 + } else { + self.offset + }; + let data = &self.buf[offset..self.cap]; + + // If we're not able to read a directory entry then that means it + // must have been truncated at the end of the buffer, so reset our + // offset so we can go back and reread into the buffer, picking up + // where we last left off. + let dirent_size = mem::size_of::<libc::__wasi_dirent_t>(); + if data.len() < dirent_size { + assert!(self.cookie.is_some()); + assert!(self.buf.len() >= dirent_size); + self.offset = self.cap; + continue; + } + let (dirent, data) = data.split_at(dirent_size); + let dirent = + unsafe { ptr::read_unaligned(dirent.as_ptr() as *const libc::__wasi_dirent_t) }; + + // If the file name was truncated, then we need to reinvoke + // `readdir` so we truncate our buffer to start over and reread this + // descriptor. Note that if our offset is 0 that means the file name + // is massive and we need a bigger buffer. + if data.len() < dirent.d_namlen as usize { + if offset == 0 { + let amt_to_add = self.buf.capacity(); + self.buf.extend(iter::repeat(0).take(amt_to_add)); + } + assert!(self.cookie.is_some()); + self.offset = self.cap; + continue; + } + self.cookie = Some(dirent.d_next); + self.offset = offset + dirent_size + dirent.d_namlen as usize; + + let name = &data[..(dirent.d_namlen as usize)]; + + // These names are skipped on all other platforms, so let's skip + // them here too + if name == b"." || name == b".." { + continue; + } + + return Some(Ok(DirEntry { + meta: dirent, + name: name.to_vec(), + inner: self.inner.clone(), + })); + } } } impl DirEntry { pub fn path(&self) -> PathBuf { - match self.0 {} + let name = OsStr::from_bytes(&self.name); + self.inner.root.join(name) } pub fn file_name(&self) -> OsString { - match self.0 {} + OsString::from_vec(self.name.clone()) } pub fn metadata(&self) -> io::Result<FileAttr> { - match self.0 {} + metadata_at( + &self.inner.dir.fd, + 0, + OsStr::from_bytes(&self.name).as_ref(), + ) } pub fn file_type(&self) -> io::Result<FileType> { - match self.0 {} + Ok(FileType { + bits: self.meta.d_type, + }) + } + + pub fn ino(&self) -> libc::__wasi_inode_t { + self.meta.d_ino } } impl OpenOptions { pub fn new() -> OpenOptions { - OpenOptions { } + let mut base = OpenOptions::default(); + base.dirflags = libc::__WASI_LOOKUP_SYMLINK_FOLLOW; + return base; + } + + pub fn read(&mut self, read: bool) { + self.read = read; + } + + pub fn write(&mut self, write: bool) { + self.write = write; + } + + pub fn truncate(&mut self, truncate: bool) { + self.oflag(libc::__WASI_O_TRUNC, truncate); + } + + pub fn create(&mut self, create: bool) { + self.oflag(libc::__WASI_O_CREAT, create); + } + + pub fn create_new(&mut self, create_new: bool) { + self.oflag(libc::__WASI_O_EXCL, create_new); + self.oflag(libc::__WASI_O_CREAT, create_new); + } + + pub fn directory(&mut self, directory: bool) { + self.oflag(libc::__WASI_O_DIRECTORY, directory); + } + + fn oflag(&mut self, bit: libc::__wasi_oflags_t, set: bool) { + if set { + self.oflags |= bit; + } else { + self.oflags &= !bit; + } + } + + pub fn append(&mut self, set: bool) { + self.fdflag(libc::__WASI_FDFLAG_APPEND, set); + } + + pub fn dsync(&mut self, set: bool) { + self.fdflag(libc::__WASI_FDFLAG_DSYNC, set); + } + + pub fn nonblock(&mut self, set: bool) { + self.fdflag(libc::__WASI_FDFLAG_NONBLOCK, set); + } + + pub fn rsync(&mut self, set: bool) { + self.fdflag(libc::__WASI_FDFLAG_RSYNC, set); + } + + pub fn sync(&mut self, set: bool) { + self.fdflag(libc::__WASI_FDFLAG_SYNC, set); + } + + fn fdflag(&mut self, bit: libc::__wasi_fdflags_t, set: bool) { + if set { + self.fdflags |= bit; + } else { + self.fdflags &= !bit; + } + } + + pub fn fs_rights_base(&mut self, rights: libc::__wasi_rights_t) { + self.rights_base = Some(rights); + } + + pub fn fs_rights_inheriting(&mut self, rights: libc::__wasi_rights_t) { + self.rights_inheriting = Some(rights); + } + + fn rights_base(&self) -> libc::__wasi_rights_t { + if let Some(rights) = self.rights_base { + return rights; + } + + // If rights haven't otherwise been specified try to pick a reasonable + // set. This can always be overridden by users via extension traits, and + // implementations may give us fewer rights silently than we ask for. So + // given that, just look at `read` and `write` and bucket permissions + // based on that. + let mut base = 0; + if self.read { + base |= libc::__WASI_RIGHT_FD_READ; + base |= libc::__WASI_RIGHT_FD_READDIR; + } + if self.write { + base |= libc::__WASI_RIGHT_FD_WRITE; + base |= libc::__WASI_RIGHT_FD_DATASYNC; + base |= libc::__WASI_RIGHT_FD_ALLOCATE; + base |= libc::__WASI_RIGHT_FD_FILESTAT_SET_SIZE; + } + + // FIXME: some of these should probably be read-only or write-only... + base |= libc::__WASI_RIGHT_FD_ADVISE; + base |= libc::__WASI_RIGHT_FD_FDSTAT_SET_FLAGS; + base |= libc::__WASI_RIGHT_FD_FILESTAT_SET_TIMES; + base |= libc::__WASI_RIGHT_FD_SEEK; + base |= libc::__WASI_RIGHT_FD_SYNC; + base |= libc::__WASI_RIGHT_FD_TELL; + base |= libc::__WASI_RIGHT_PATH_CREATE_DIRECTORY; + base |= libc::__WASI_RIGHT_PATH_CREATE_FILE; + base |= libc::__WASI_RIGHT_PATH_FILESTAT_GET; + base |= libc::__WASI_RIGHT_PATH_LINK_SOURCE; + base |= libc::__WASI_RIGHT_PATH_LINK_TARGET; + base |= libc::__WASI_RIGHT_PATH_OPEN; + base |= libc::__WASI_RIGHT_PATH_READLINK; + base |= libc::__WASI_RIGHT_PATH_REMOVE_DIRECTORY; + base |= libc::__WASI_RIGHT_PATH_RENAME_SOURCE; + base |= libc::__WASI_RIGHT_PATH_RENAME_TARGET; + base |= libc::__WASI_RIGHT_PATH_SYMLINK; + base |= libc::__WASI_RIGHT_PATH_UNLINK_FILE; + base |= libc::__WASI_RIGHT_POLL_FD_READWRITE; + + return base; } - pub fn read(&mut self, _read: bool) { } - pub fn write(&mut self, _write: bool) { } - pub fn append(&mut self, _append: bool) { } - pub fn truncate(&mut self, _truncate: bool) { } - pub fn create(&mut self, _create: bool) { } - pub fn create_new(&mut self, _create_new: bool) { } + fn rights_inheriting(&self) -> libc::__wasi_rights_t { + self.rights_inheriting.unwrap_or_else(|| self.rights_base()) + } + + pub fn lookup_flags(&mut self, flags: libc::__wasi_lookupflags_t) { + self.dirflags = flags; + } } impl File { - pub fn open(_path: &Path, _opts: &OpenOptions) -> io::Result<File> { - unsupported() + pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> { + let (dir, file) = open_parent(path, libc::__WASI_RIGHT_PATH_OPEN)?; + open_at(&dir, &file, opts) + } + + pub fn open_at(&self, path: &Path, opts: &OpenOptions) -> io::Result<File> { + open_at(&self.fd, path, opts) } pub fn file_attr(&self) -> io::Result<FileAttr> { - match self.0 {} + let mut ret = FileAttr::zero(); + self.fd.filestat_get(&mut ret.meta)?; + Ok(ret) + } + + pub fn metadata_at( + &self, + flags: libc::__wasi_lookupflags_t, + path: &Path, + ) -> io::Result<FileAttr> { + metadata_at(&self.fd, flags, path) } pub fn fsync(&self) -> io::Result<()> { - match self.0 {} + self.fd.sync() } pub fn datasync(&self) -> io::Result<()> { - match self.0 {} + self.fd.datasync() + } + + pub fn truncate(&self, size: u64) -> io::Result<()> { + self.fd.filestat_set_size(size) } - pub fn truncate(&self, _size: u64) -> io::Result<()> { - match self.0 {} + pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> { + self.read_vectored(&mut [IoVecMut::new(buf)]) } - pub fn read(&self, _buf: &mut [u8]) -> io::Result<usize> { - match self.0 {} + pub fn read_vectored(&self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> { + self.fd.read(bufs) } - pub fn write(&self, _buf: &[u8]) -> io::Result<usize> { - match self.0 {} + pub fn write(&self, buf: &[u8]) -> io::Result<usize> { + self.write_vectored(&[IoVec::new(buf)]) + } + + pub fn write_vectored(&self, bufs: &[IoVec<'_>]) -> io::Result<usize> { + self.fd.write(bufs) } pub fn flush(&self) -> io::Result<()> { - match self.0 {} + Ok(()) } - pub fn seek(&self, _pos: SeekFrom) -> io::Result<u64> { - match self.0 {} + pub fn seek(&self, pos: SeekFrom) -> io::Result<u64> { + self.fd.seek(pos) } pub fn duplicate(&self) -> io::Result<File> { - match self.0 {} + // https://github.com/CraneStation/wasmtime/blob/master/docs/WASI-rationale.md#why-no-dup + unsupported() } pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> { - match self.0 {} + // Permissions haven't been fully figured out in wasi yet, so this is + // likely temporary + unsupported() } - pub fn diverge(&self) -> ! { - match self.0 {} + pub fn fd(&self) -> &WasiFd { + &self.fd } -} -impl DirBuilder { - pub fn new() -> DirBuilder { - DirBuilder { } + pub fn into_fd(self) -> WasiFd { + self.fd } - pub fn mkdir(&self, _p: &Path) -> io::Result<()> { - unsupported() + pub fn read_link(&self, file: &Path) -> io::Result<PathBuf> { + read_link(&self.fd, file) } } -impl fmt::Debug for File { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 {} +impl FromInner<u32> for File { + fn from_inner(fd: u32) -> File { + unsafe { + File { + fd: WasiFd::from_raw(fd), + } + } } } -pub fn readdir(_p: &Path) -> io::Result<ReadDir> { - unsupported() -} +impl DirBuilder { + pub fn new() -> DirBuilder { + DirBuilder {} + } -pub fn unlink(_p: &Path) -> io::Result<()> { - unsupported() + pub fn mkdir(&self, p: &Path) -> io::Result<()> { + let (dir, file) = open_parent(p, libc::__WASI_RIGHT_PATH_CREATE_DIRECTORY)?; + dir.create_directory(file.as_os_str().as_bytes()) + } } -pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> { +impl fmt::Debug for File { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("File") + .field("fd", &self.fd.as_raw()) + .finish() + } +} + +pub fn readdir(p: &Path) -> io::Result<ReadDir> { + let mut opts = OpenOptions::new(); + opts.directory(true); + opts.read(true); + let dir = File::open(p, &opts)?; + Ok(ReadDir { + cookie: Some(0), + buf: vec![0; 128], + offset: 0, + cap: 0, + inner: Arc::new(ReadDirInner { + dir, + root: p.to_path_buf(), + }), + }) +} + +pub fn unlink(p: &Path) -> io::Result<()> { + let (dir, file) = open_parent(p, libc::__WASI_RIGHT_PATH_UNLINK_FILE)?; + dir.unlink_file(file.as_os_str().as_bytes()) +} + +pub fn rename(old: &Path, new: &Path) -> io::Result<()> { + let (old, old_file) = open_parent(old, libc::__WASI_RIGHT_PATH_RENAME_SOURCE)?; + let (new, new_file) = open_parent(new, libc::__WASI_RIGHT_PATH_RENAME_TARGET)?; + old.rename( + old_file.as_os_str().as_bytes(), + &new, + new_file.as_os_str().as_bytes(), + ) +} + +pub fn set_perm(_p: &Path, _perm: FilePermissions) -> io::Result<()> { + // Permissions haven't been fully figured out in wasi yet, so this is + // likely temporary unsupported() } -pub fn set_perm(_p: &Path, perm: FilePermissions) -> io::Result<()> { - match perm.0 {} +pub fn rmdir(p: &Path) -> io::Result<()> { + let (dir, file) = open_parent(p, libc::__WASI_RIGHT_PATH_REMOVE_DIRECTORY)?; + dir.remove_directory(file.as_os_str().as_bytes()) } -pub fn rmdir(_p: &Path) -> io::Result<()> { - unsupported() +pub fn readlink(p: &Path) -> io::Result<PathBuf> { + let (dir, file) = open_parent(p, libc::__WASI_RIGHT_PATH_READLINK)?; + read_link(&dir, &file) } -pub fn remove_dir_all(_path: &Path) -> io::Result<()> { - unsupported() +fn read_link(fd: &WasiFd, file: &Path) -> io::Result<PathBuf> { + // Try to get a best effort initial capacity for the vector we're going to + // fill. Note that if it's not a symlink we don't use a file to avoid + // allocating gigabytes if you read_link a huge movie file by accident. + // Additionally we add 1 to the initial size so if it doesn't change until + // when we call `readlink` the returned length will be less than the + // capacity, guaranteeing that we got all the data. + let meta = metadata_at(fd, 0, file)?; + let initial_size = if meta.file_type().is_symlink() { + (meta.size() as usize).saturating_add(1) + } else { + 1 // this'll fail in just a moment + }; + + // Now that we have an initial guess of how big to make our buffer, call + // `readlink` in a loop until it fails or reports it filled fewer bytes than + // we asked for, indicating we got everything. + let file = file.as_os_str().as_bytes(); + let mut destination = vec![0u8; initial_size]; + loop { + let len = fd.readlink(file, &mut destination)?; + if len < destination.len() { + destination.truncate(len); + destination.shrink_to_fit(); + return Ok(PathBuf::from(OsString::from_vec(destination))); + } + let amt_to_add = destination.len(); + destination.extend(iter::repeat(0).take(amt_to_add)); + } } -pub fn readlink(_p: &Path) -> io::Result<PathBuf> { - unsupported() +pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> { + let (dst, dst_file) = open_parent(dst, libc::__WASI_RIGHT_PATH_SYMLINK)?; + dst.symlink(src.as_os_str().as_bytes(), dst_file.as_os_str().as_bytes()) } -pub fn symlink(_src: &Path, _dst: &Path) -> io::Result<()> { - unsupported() +pub fn link(src: &Path, dst: &Path) -> io::Result<()> { + let (src, src_file) = open_parent(src, libc::__WASI_RIGHT_PATH_LINK_SOURCE)?; + let (dst, dst_file) = open_parent(dst, libc::__WASI_RIGHT_PATH_LINK_TARGET)?; + src.link( + libc::__WASI_LOOKUP_SYMLINK_FOLLOW, + src_file.as_os_str().as_bytes(), + &dst, + dst_file.as_os_str().as_bytes(), + ) } -pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> { - unsupported() +pub fn stat(p: &Path) -> io::Result<FileAttr> { + let (dir, file) = open_parent(p, libc::__WASI_RIGHT_PATH_FILESTAT_GET)?; + metadata_at(&dir, libc::__WASI_LOOKUP_SYMLINK_FOLLOW, &file) } -pub fn stat(_p: &Path) -> io::Result<FileAttr> { - unsupported() +pub fn lstat(p: &Path) -> io::Result<FileAttr> { + let (dir, file) = open_parent(p, libc::__WASI_RIGHT_PATH_FILESTAT_GET)?; + metadata_at(&dir, 0, &file) } -pub fn lstat(_p: &Path) -> io::Result<FileAttr> { - unsupported() +fn metadata_at( + fd: &WasiFd, + flags: libc::__wasi_lookupflags_t, + path: &Path, +) -> io::Result<FileAttr> { + let mut ret = FileAttr::zero(); + fd.path_filestat_get(flags, path.as_os_str().as_bytes(), &mut ret.meta)?; + Ok(ret) } pub fn canonicalize(_p: &Path) -> io::Result<PathBuf> { + // This seems to not be in wasi's API yet, and we may need to end up + // emulating it ourselves. For now just return an error. unsupported() } -pub fn copy(_from: &Path, _to: &Path) -> io::Result<u64> { - unsupported() +fn open_at(fd: &WasiFd, path: &Path, opts: &OpenOptions) -> io::Result<File> { + let fd = fd.open( + opts.dirflags, + path.as_os_str().as_bytes(), + opts.oflags, + opts.rights_base(), + opts.rights_inheriting(), + opts.fdflags, + )?; + Ok(File { fd }) +} + +/// Attempts to open a bare path `p`. +/// +/// WASI has no fundamental capability to do this. All syscalls and operations +/// are relative to already-open file descriptors. The C library, however, +/// manages a map of preopened file descriptors to their path, and then the C +/// library provides an API to look at this. In other words, when you want to +/// open a path `p`, you have to find a previously opened file descriptor in a +/// global table and then see if `p` is relative to that file descriptor. +/// +/// This function, if successful, will return two items: +/// +/// * The first is a `ManuallyDrop<WasiFd>`. This represents a preopened file +/// descriptor which we don't have ownership of, but we can use. You shouldn't +/// actually drop the `fd`. +/// +/// * The second is a path that should be a part of `p` and represents a +/// relative traversal from the file descriptor specified to the desired +/// location `p`. +/// +/// If successful you can use the returned file descriptor to perform +/// file-descriptor-relative operations on the path returned as well. The +/// `rights` argument indicates what operations are desired on the returned file +/// descriptor, and if successful the returned file descriptor should have the +/// appropriate rights for performing `rights` actions. +/// +/// Note that this can fail if `p` doesn't look like it can be opened relative +/// to any preopened file descriptor. +fn open_parent( + p: &Path, + rights: libc::__wasi_rights_t, +) -> io::Result<(ManuallyDrop<WasiFd>, PathBuf)> { + let p = CString::new(p.as_os_str().as_bytes())?; + unsafe { + let mut ret = ptr::null(); + let fd = __wasilibc_find_relpath(p.as_ptr(), rights, 0, &mut ret); + if fd == -1 { + let msg = format!( + "failed to find a preopened file descriptor \ + through which {:?} could be opened", + p + ); + return Err(io::Error::new(io::ErrorKind::Other, msg)); + } + let path = Path::new(OsStr::from_bytes(CStr::from_ptr(ret).to_bytes())); + + // FIXME: right now `path` is a pointer into `p`, the `CString` above. + // When we return `p` is deallocated and we can't use it, so we need to + // currently separately allocate `path`. If this becomes an issue though + // we should probably turn this into a closure-taking interface or take + // `&CString` and then pass off `&Path` tied to the same lifetime. + let path = path.to_path_buf(); + + return Ok((ManuallyDrop::new(WasiFd::from_raw(fd as u32)), path)); + } + + // FIXME(rust-lang/libc#1314) use the `libc` crate for this when the API + // there is published + extern "C" { + pub fn __wasilibc_find_relpath( + path: *const libc::c_char, + rights_base: libc::__wasi_rights_t, + rights_inheriting: libc::__wasi_rights_t, + relative_path: *mut *const libc::c_char, + ) -> libc::c_int; + } } diff --git a/src/libstd/sys/wasi/net.rs b/src/libstd/sys/wasi/net.rs index 1579aa4b572..5486cdec4c0 100644 --- a/src/libstd/sys/wasi/net.rs +++ b/src/libstd/sys/wasi/net.rs @@ -4,8 +4,12 @@ use crate::net::{SocketAddr, Shutdown, Ipv4Addr, Ipv6Addr}; use crate::time::Duration; use crate::sys::{unsupported, Void}; use crate::convert::TryFrom; +use crate::sys::fd::{WasiFd}; +use crate::sys_common::FromInner; -pub struct TcpStream(Void); +pub struct TcpStream { + fd: WasiFd, +} impl TcpStream { pub fn connect(_: io::Result<&SocketAddr>) -> io::Result<TcpStream> { @@ -17,89 +21,111 @@ impl TcpStream { } pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> { - match self.0 {} + unsupported() } pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> { - match self.0 {} + unsupported() } pub fn read_timeout(&self) -> io::Result<Option<Duration>> { - match self.0 {} + unsupported() } pub fn write_timeout(&self) -> io::Result<Option<Duration>> { - match self.0 {} + unsupported() } pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> { - match self.0 {} + unsupported() } pub fn read(&self, _: &mut [u8]) -> io::Result<usize> { - match self.0 {} + unsupported() } pub fn read_vectored(&self, _: &mut [IoVecMut<'_>]) -> io::Result<usize> { - match self.0 {} + unsupported() } pub fn write(&self, _: &[u8]) -> io::Result<usize> { - match self.0 {} + unsupported() } pub fn write_vectored(&self, _: &[IoVec<'_>]) -> io::Result<usize> { - match self.0 {} + unsupported() } pub fn peer_addr(&self) -> io::Result<SocketAddr> { - match self.0 {} + unsupported() } pub fn socket_addr(&self) -> io::Result<SocketAddr> { - match self.0 {} + unsupported() } pub fn shutdown(&self, _: Shutdown) -> io::Result<()> { - match self.0 {} + unsupported() } pub fn duplicate(&self) -> io::Result<TcpStream> { - match self.0 {} + unsupported() } pub fn set_nodelay(&self, _: bool) -> io::Result<()> { - match self.0 {} + unsupported() } pub fn nodelay(&self) -> io::Result<bool> { - match self.0 {} + unsupported() } pub fn set_ttl(&self, _: u32) -> io::Result<()> { - match self.0 {} + unsupported() } pub fn ttl(&self) -> io::Result<u32> { - match self.0 {} + unsupported() } pub fn take_error(&self) -> io::Result<Option<io::Error>> { - match self.0 {} + unsupported() } pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { - match self.0 {} + unsupported() + } + + pub fn fd(&self) -> &WasiFd { + &self.fd + } + + pub fn into_fd(self) -> WasiFd { + self.fd + } +} + +impl FromInner<u32> for TcpStream { + fn from_inner(fd: u32) -> TcpStream { + unsafe { + TcpStream { + fd: WasiFd::from_raw(fd), + } + } } } impl fmt::Debug for TcpStream { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 {} + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("TcpStream") + .field("fd", &self.fd.as_raw()) + .finish() } } -pub struct TcpListener(Void); +pub struct TcpListener { + fd: WasiFd +} impl TcpListener { pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<TcpListener> { @@ -107,49 +133,71 @@ impl TcpListener { } pub fn socket_addr(&self) -> io::Result<SocketAddr> { - match self.0 {} + unsupported() } pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> { - match self.0 {} + unsupported() } pub fn duplicate(&self) -> io::Result<TcpListener> { - match self.0 {} + unsupported() } pub fn set_ttl(&self, _: u32) -> io::Result<()> { - match self.0 {} + unsupported() } pub fn ttl(&self) -> io::Result<u32> { - match self.0 {} + unsupported() } pub fn set_only_v6(&self, _: bool) -> io::Result<()> { - match self.0 {} + unsupported() } pub fn only_v6(&self) -> io::Result<bool> { - match self.0 {} + unsupported() } pub fn take_error(&self) -> io::Result<Option<io::Error>> { - match self.0 {} + unsupported() } pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { - match self.0 {} + unsupported() + } + + pub fn fd(&self) -> &WasiFd { + &self.fd + } + + pub fn into_fd(self) -> WasiFd { + self.fd + } +} + +impl FromInner<u32> for TcpListener { + fn from_inner(fd: u32) -> TcpListener { + unsafe { + TcpListener { + fd: WasiFd::from_raw(fd), + } + } } } impl fmt::Debug for TcpListener { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 {} + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("TcpListener") + .field("fd", &self.fd.as_raw()) + .finish() } } -pub struct UdpSocket(Void); +pub struct UdpSocket { + fd: WasiFd, +} impl UdpSocket { pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<UdpSocket> { @@ -157,133 +205,153 @@ impl UdpSocket { } pub fn peer_addr(&self) -> io::Result<SocketAddr> { - match self.0 {} + unsupported() } pub fn socket_addr(&self) -> io::Result<SocketAddr> { - match self.0 {} + unsupported() } pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - match self.0 {} + unsupported() } pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - match self.0 {} + unsupported() } pub fn send_to(&self, _: &[u8], _: &SocketAddr) -> io::Result<usize> { - match self.0 {} + unsupported() } pub fn duplicate(&self) -> io::Result<UdpSocket> { - match self.0 {} + unsupported() } pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> { - match self.0 {} + unsupported() } pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> { - match self.0 {} + unsupported() } pub fn read_timeout(&self) -> io::Result<Option<Duration>> { - match self.0 {} + unsupported() } pub fn write_timeout(&self) -> io::Result<Option<Duration>> { - match self.0 {} + unsupported() } pub fn set_broadcast(&self, _: bool) -> io::Result<()> { - match self.0 {} + unsupported() } pub fn broadcast(&self) -> io::Result<bool> { - match self.0 {} + unsupported() } pub fn set_multicast_loop_v4(&self, _: bool) -> io::Result<()> { - match self.0 {} + unsupported() } pub fn multicast_loop_v4(&self) -> io::Result<bool> { - match self.0 {} + unsupported() } pub fn set_multicast_ttl_v4(&self, _: u32) -> io::Result<()> { - match self.0 {} + unsupported() } pub fn multicast_ttl_v4(&self) -> io::Result<u32> { - match self.0 {} + unsupported() } pub fn set_multicast_loop_v6(&self, _: bool) -> io::Result<()> { - match self.0 {} + unsupported() } pub fn multicast_loop_v6(&self) -> io::Result<bool> { - match self.0 {} + unsupported() } pub fn join_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> { - match self.0 {} + unsupported() } pub fn join_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> { - match self.0 {} + unsupported() } pub fn leave_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> { - match self.0 {} + unsupported() } pub fn leave_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> { - match self.0 {} + unsupported() } pub fn set_ttl(&self, _: u32) -> io::Result<()> { - match self.0 {} + unsupported() } pub fn ttl(&self) -> io::Result<u32> { - match self.0 {} + unsupported() } pub fn take_error(&self) -> io::Result<Option<io::Error>> { - match self.0 {} + unsupported() } pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { - match self.0 {} + unsupported() } pub fn recv(&self, _: &mut [u8]) -> io::Result<usize> { - match self.0 {} + unsupported() } pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> { - match self.0 {} + unsupported() } pub fn send(&self, _: &[u8]) -> io::Result<usize> { - match self.0 {} + unsupported() } pub fn connect(&self, _: io::Result<&SocketAddr>) -> io::Result<()> { - match self.0 {} + unsupported() + } + + pub fn fd(&self) -> &WasiFd { + &self.fd + } + + pub fn into_fd(self) -> WasiFd { + self.fd + } +} + +impl FromInner<u32> for UdpSocket { + fn from_inner(fd: u32) -> UdpSocket { + unsafe { + UdpSocket { + fd: WasiFd::from_raw(fd), + } + } } } impl fmt::Debug for UdpSocket { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 {} + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("UdpSocket") + .field("fd", &self.fd.as_raw()) + .finish() } } diff --git a/src/libstd/sys/wasi/os.rs b/src/libstd/sys/wasi/os.rs index 6d4d6aae61b..822ea02a11b 100644 --- a/src/libstd/sys/wasi/os.rs +++ b/src/libstd/sys/wasi/os.rs @@ -27,8 +27,21 @@ pub fn errno() -> i32 { unsafe { errno as i32 } } -pub fn error_string(_errno: i32) -> String { - "operation failed".to_string() +pub fn error_string(errno: i32) -> String { + extern { + fn strerror_r(errnum: libc::c_int, buf: *mut libc::c_char, + buflen: libc::size_t) -> libc::c_int; + } + + let mut buf = [0 as libc::c_char; 1024]; + + let p = buf.as_mut_ptr(); + unsafe { + if strerror_r(errno as libc::c_int, p, buf.len()) < 0 { + panic!("strerror_r failure"); + } + str::from_utf8(CStr::from_ptr(p).to_bytes()).unwrap().to_owned() + } } pub fn getcwd() -> io::Result<PathBuf> { diff --git a/src/libstd/sys/wasi/pipe.rs b/src/libstd/sys/wasi/pipe.rs index 2582b993b60..aa6bf8076f6 100644 --- a/src/libstd/sys/wasi/pipe.rs +++ b/src/libstd/sys/wasi/pipe.rs @@ -1,4 +1,4 @@ -use crate::io; +use crate::io::{self, IoVec, IoVecMut}; use crate::sys::Void; pub struct AnonPipe(Void); @@ -8,10 +8,18 @@ impl AnonPipe { match self.0 {} } + pub fn read_vectored(&self, _bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> { + match self.0 {} + } + pub fn write(&self, _buf: &[u8]) -> io::Result<usize> { match self.0 {} } + pub fn write_vectored(&self, _bufs: &[IoVec<'_>]) -> io::Result<usize> { + match self.0 {} + } + pub fn diverge(&self) -> ! { match self.0 {} } diff --git a/src/libstd/sys/wasi/process.rs b/src/libstd/sys/wasi/process.rs index a02e009d953..788b829f4ba 100644 --- a/src/libstd/sys/wasi/process.rs +++ b/src/libstd/sys/wasi/process.rs @@ -67,8 +67,8 @@ impl From<AnonPipe> for Stdio { } impl From<File> for Stdio { - fn from(file: File) -> Stdio { - file.diverge() + fn from(_file: File) -> Stdio { + panic!("unsupported") } } diff --git a/src/libstd/sys/wasi/stdio.rs b/src/libstd/sys/wasi/stdio.rs index f6a4958897d..bdad4084891 100644 --- a/src/libstd/sys/wasi/stdio.rs +++ b/src/libstd/sys/wasi/stdio.rs @@ -1,6 +1,7 @@ -use crate::io; +use crate::io::{self, IoVec, IoVecMut}; use crate::libc; -use crate::sys::cvt; +use crate::mem::ManuallyDrop; +use crate::sys::fd::WasiFd; pub struct Stdin; pub struct Stdout; @@ -12,10 +13,12 @@ impl Stdin { } pub fn read(&self, data: &mut [u8]) -> io::Result<usize> { - let amt = cvt(unsafe { - libc::read(libc::STDIN_FILENO, data.as_mut_ptr() as *mut _, data.len()) - })?; - Ok(amt as usize) + self.read_vectored(&mut [IoVecMut::new(data)]) + } + + pub fn read_vectored(&self, data: &mut [IoVecMut<'_>]) -> io::Result<usize> { + ManuallyDrop::new(unsafe { WasiFd::from_raw(libc::STDIN_FILENO as u32) }) + .read(data) } } @@ -25,10 +28,12 @@ impl Stdout { } pub fn write(&self, data: &[u8]) -> io::Result<usize> { - let amt = cvt(unsafe { - libc::write(libc::STDOUT_FILENO, data.as_ptr() as *const _, data.len()) - })?; - Ok(amt as usize) + self.write_vectored(&[IoVec::new(data)]) + } + + pub fn write_vectored(&self, data: &[IoVec<'_>]) -> io::Result<usize> { + ManuallyDrop::new(unsafe { WasiFd::from_raw(libc::STDOUT_FILENO as u32) }) + .write(data) } pub fn flush(&self) -> io::Result<()> { @@ -42,10 +47,12 @@ impl Stderr { } pub fn write(&self, data: &[u8]) -> io::Result<usize> { - let amt = cvt(unsafe { - libc::write(libc::STDERR_FILENO, data.as_ptr() as *const _, data.len()) - })?; - Ok(amt as usize) + self.write_vectored(&[IoVec::new(data)]) + } + + pub fn write_vectored(&self, data: &[IoVec<'_>]) -> io::Result<usize> { + ManuallyDrop::new(unsafe { WasiFd::from_raw(libc::STDERR_FILENO as u32) }) + .write(data) } pub fn flush(&self) -> io::Result<()> { diff --git a/src/libstd/sys/wasi/thread.rs b/src/libstd/sys/wasi/thread.rs index 9d3c6ac59d1..5e69e4d948f 100644 --- a/src/libstd/sys/wasi/thread.rs +++ b/src/libstd/sys/wasi/thread.rs @@ -1,4 +1,3 @@ -use crate::boxed::FnBox; use crate::cmp; use crate::ffi::CStr; use crate::io; @@ -13,7 +12,7 @@ pub const DEFAULT_MIN_STACK_SIZE: usize = 4096; impl Thread { // unsafe: see thread::Builder::spawn_unchecked for safety requirements - pub unsafe fn new(_stack: usize, _p: Box<dyn FnBox()>) + pub unsafe fn new(_stack: usize, _p: Box<dyn FnOnce()>) -> io::Result<Thread> { unsupported() diff --git a/src/libstd/sys/wasi/time.rs b/src/libstd/sys/wasi/time.rs index e1b92e7c5a7..3f14c80928c 100644 --- a/src/libstd/sys/wasi/time.rs +++ b/src/libstd/sys/wasi/time.rs @@ -57,6 +57,10 @@ impl SystemTime { SystemTime(current_time(libc::__WASI_CLOCK_REALTIME)) } + pub fn from_wasi_timestamp(ts: libc::__wasi_timestamp_t) -> SystemTime { + SystemTime(Duration::from_nanos(ts)) + } + pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> { self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0) diff --git a/src/libstd/sys/wasm/fs.rs b/src/libstd/sys/wasm/fs.rs index 68c8e9356a8..c3c898eb23e 100644 --- a/src/libstd/sys/wasm/fs.rs +++ b/src/libstd/sys/wasm/fs.rs @@ -1,7 +1,7 @@ use crate::ffi::OsString; use crate::fmt; use crate::hash::{Hash, Hasher}; -use crate::io::{self, SeekFrom}; +use crate::io::{self, SeekFrom, IoVec, IoVecMut}; use crate::path::{Path, PathBuf}; use crate::sys::time::SystemTime; use crate::sys::{unsupported, Void}; @@ -200,10 +200,18 @@ impl File { match self.0 {} } + pub fn read_vectored(&self, _bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> { + match self.0 {} + } + pub fn write(&self, _buf: &[u8]) -> io::Result<usize> { match self.0 {} } + pub fn write_vectored(&self, _bufs: &[IoVec<'_>]) -> io::Result<usize> { + match self.0 {} + } + pub fn flush(&self) -> io::Result<()> { match self.0 {} } diff --git a/src/libstd/sys/wasm/pipe.rs b/src/libstd/sys/wasm/pipe.rs index 2582b993b60..aa6bf8076f6 100644 --- a/src/libstd/sys/wasm/pipe.rs +++ b/src/libstd/sys/wasm/pipe.rs @@ -1,4 +1,4 @@ -use crate::io; +use crate::io::{self, IoVec, IoVecMut}; use crate::sys::Void; pub struct AnonPipe(Void); @@ -8,10 +8,18 @@ impl AnonPipe { match self.0 {} } + pub fn read_vectored(&self, _bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> { + match self.0 {} + } + pub fn write(&self, _buf: &[u8]) -> io::Result<usize> { match self.0 {} } + pub fn write_vectored(&self, _bufs: &[IoVec<'_>]) -> io::Result<usize> { + match self.0 {} + } + pub fn diverge(&self) -> ! { match self.0 {} } diff --git a/src/libstd/sys/wasm/thread.rs b/src/libstd/sys/wasm/thread.rs index a65c413119f..1dc786cd5d7 100644 --- a/src/libstd/sys/wasm/thread.rs +++ b/src/libstd/sys/wasm/thread.rs @@ -1,4 +1,3 @@ -use crate::boxed::FnBox; use crate::ffi::CStr; use crate::io; use crate::sys::{unsupported, Void}; @@ -10,7 +9,7 @@ pub const DEFAULT_MIN_STACK_SIZE: usize = 4096; impl Thread { // unsafe: see thread::Builder::spawn_unchecked for safety requirements - pub unsafe fn new(_stack: usize, _p: Box<dyn FnBox()>) + pub unsafe fn new(_stack: usize, _p: Box<dyn FnOnce()>) -> io::Result<Thread> { unsupported() diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs index 4ebbb0707f7..1d8e47a4793 100644 --- a/src/libstd/sys/windows/fs.rs +++ b/src/libstd/sys/windows/fs.rs @@ -2,7 +2,7 @@ use crate::os::windows::prelude::*; use crate::ffi::OsString; use crate::fmt; -use crate::io::{self, Error, SeekFrom}; +use crate::io::{self, Error, SeekFrom, IoVec, IoVecMut}; use crate::mem; use crate::path::{Path, PathBuf}; use crate::ptr; @@ -314,6 +314,10 @@ impl File { self.handle.read(buf) } + pub fn read_vectored(&self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> { + self.handle.read_vectored(bufs) + } + pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> { self.handle.read_at(buf, offset) } @@ -322,6 +326,10 @@ impl File { self.handle.write(buf) } + pub fn write_vectored(&self, bufs: &[IoVec<'_>]) -> io::Result<usize> { + self.handle.write_vectored(bufs) + } + pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> { self.handle.write_at(buf, offset) } diff --git a/src/libstd/sys/windows/handle.rs b/src/libstd/sys/windows/handle.rs index 02549088c87..c3fa6c4e0bd 100644 --- a/src/libstd/sys/windows/handle.rs +++ b/src/libstd/sys/windows/handle.rs @@ -1,7 +1,7 @@ #![unstable(issue = "0", feature = "windows_handle")] use crate::cmp; -use crate::io::{self, ErrorKind, Read}; +use crate::io::{self, ErrorKind, Read, IoVec, IoVecMut}; use crate::mem; use crate::ops::Deref; use crate::ptr; @@ -89,6 +89,10 @@ impl RawHandle { } } + pub fn read_vectored(&self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> { + crate::io::default_read_vectored(|buf| self.read(buf), bufs) + } + pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> { let mut read = 0; let len = cmp::min(buf.len(), <c::DWORD>::max_value() as usize) as c::DWORD; @@ -169,6 +173,10 @@ impl RawHandle { Ok(amt as usize) } + pub fn write_vectored(&self, bufs: &[IoVec<'_>]) -> io::Result<usize> { + crate::io::default_write_vectored(|buf| self.write(buf), bufs) + } + pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> { let mut written = 0; let len = cmp::min(buf.len(), <c::DWORD>::max_value() as usize) as c::DWORD; @@ -199,4 +207,8 @@ impl<'a> Read for &'a RawHandle { fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { (**self).read(buf) } + + fn read_vectored(&mut self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> { + (**self).read_vectored(bufs) + } } diff --git a/src/libstd/sys/windows/pipe.rs b/src/libstd/sys/windows/pipe.rs index b38727830f3..6613d3a0567 100644 --- a/src/libstd/sys/windows/pipe.rs +++ b/src/libstd/sys/windows/pipe.rs @@ -1,7 +1,7 @@ use crate::os::windows::prelude::*; use crate::ffi::OsStr; -use crate::io; +use crate::io::{self, IoVec, IoVecMut}; use crate::mem; use crate::path::Path; use crate::ptr; @@ -166,9 +166,17 @@ impl AnonPipe { self.inner.read(buf) } + pub fn read_vectored(&self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> { + self.inner.read_vectored(bufs) + } + pub fn write(&self, buf: &[u8]) -> io::Result<usize> { self.inner.write(buf) } + + pub fn write_vectored(&self, bufs: &[IoVec<'_>]) -> io::Result<usize> { + self.inner.write_vectored(bufs) + } } pub fn read2(p1: AnonPipe, diff --git a/src/libstd/sys/windows/thread.rs b/src/libstd/sys/windows/thread.rs index 1b0a811f13b..ebdf3612e06 100644 --- a/src/libstd/sys/windows/thread.rs +++ b/src/libstd/sys/windows/thread.rs @@ -1,4 +1,3 @@ -use crate::boxed::FnBox; use crate::io; use crate::ffi::CStr; use crate::mem; @@ -20,7 +19,7 @@ pub struct Thread { impl Thread { // unsafe: see thread::Builder::spawn_unchecked for safety requirements - pub unsafe fn new(stack: usize, p: Box<dyn FnBox()>) + pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> { let p = box p; diff --git a/src/libstd/sys/windows/time.rs b/src/libstd/sys/windows/time.rs index 4c9d2aee157..e0f0e3a1a45 100644 --- a/src/libstd/sys/windows/time.rs +++ b/src/libstd/sys/windows/time.rs @@ -173,7 +173,7 @@ fn intervals2dur(intervals: u64) -> Duration { mod perf_counter { use super::{NANOS_PER_SEC}; - use crate::sync::Once; + use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst}; use crate::sys_common::mul_div_u64; use crate::sys::c; use crate::sys::cvt; @@ -210,13 +210,25 @@ mod perf_counter { fn frequency() -> c::LARGE_INTEGER { static mut FREQUENCY: c::LARGE_INTEGER = 0; - static ONCE: Once = Once::new(); + static STATE: AtomicUsize = AtomicUsize::new(0); unsafe { - ONCE.call_once(|| { - cvt(c::QueryPerformanceFrequency(&mut FREQUENCY)).unwrap(); - }); - FREQUENCY + // If a previous thread has filled in this global state, use that. + if STATE.load(SeqCst) == 2 { + return FREQUENCY; + } + + // ... otherwise learn for ourselves ... + let mut frequency = 0; + cvt(c::QueryPerformanceFrequency(&mut frequency)).unwrap(); + + // ... and attempt to be the one thread that stores it globally for + // all other threads + if STATE.compare_exchange(0, 1, SeqCst, SeqCst).is_ok() { + FREQUENCY = frequency; + STATE.store(2, SeqCst); + } + return frequency; } } diff --git a/src/libstd/sys_common/at_exit_imp.rs b/src/libstd/sys_common/at_exit_imp.rs index 1181b861611..cdb72ee872e 100644 --- a/src/libstd/sys_common/at_exit_imp.rs +++ b/src/libstd/sys_common/at_exit_imp.rs @@ -2,12 +2,11 @@ //! //! Documentation can be found on the `rt::at_exit` function. -use crate::boxed::FnBox; use crate::ptr; use crate::mem; use crate::sys_common::mutex::Mutex; -type Queue = Vec<Box<dyn FnBox()>>; +type Queue = Vec<Box<dyn FnOnce()>>; // NB these are specifically not types from `std::sync` as they currently rely // on poisoning and this module needs to operate at a lower level than requiring @@ -61,7 +60,7 @@ pub fn cleanup() { } } -pub fn push(f: Box<dyn FnBox()>) -> bool { +pub fn push(f: Box<dyn FnOnce()>) -> bool { unsafe { let _guard = LOCK.lock(); if init() { diff --git a/src/libstd/sys_common/fs.rs b/src/libstd/sys_common/fs.rs new file mode 100644 index 00000000000..7152fcd215c --- /dev/null +++ b/src/libstd/sys_common/fs.rs @@ -0,0 +1,41 @@ +#![allow(dead_code)] // not used on all platforms + +use crate::path::Path; +use crate::fs; +use crate::io::{self, Error, ErrorKind}; + +pub fn copy(from: &Path, to: &Path) -> io::Result<u64> { + if !from.is_file() { + return Err(Error::new(ErrorKind::InvalidInput, + "the source path is not an existing regular file")) + } + + let mut reader = fs::File::open(from)?; + let mut writer = fs::File::create(to)?; + let perm = reader.metadata()?.permissions(); + + let ret = io::copy(&mut reader, &mut writer)?; + fs::set_permissions(to, perm)?; + Ok(ret) +} + +pub fn remove_dir_all(path: &Path) -> io::Result<()> { + let filetype = fs::symlink_metadata(path)?.file_type(); + if filetype.is_symlink() { + fs::remove_file(path) + } else { + remove_dir_all_recursive(path) + } +} + +fn remove_dir_all_recursive(path: &Path) -> io::Result<()> { + for child in fs::read_dir(path)? { + let child = child?; + if child.file_type()?.is_dir() { + remove_dir_all_recursive(&child.path())?; + } else { + fs::remove_file(&child.path())?; + } + } + fs::remove_dir(path) +} diff --git a/src/libstd/sys_common/mod.rs b/src/libstd/sys_common/mod.rs index 883ab34f07c..6260c3b77ff 100644 --- a/src/libstd/sys_common/mod.rs +++ b/src/libstd/sys_common/mod.rs @@ -28,6 +28,15 @@ macro_rules! rtassert { }) } +#[allow(unused_macros)] // not used on all platforms +macro_rules! rtunwrap { + ($ok:ident, $e:expr) => (if let $ok(v) = $e { + v + } else { + rtabort!(concat!("unwrap failed: ", stringify!($e))); + }) +} + pub mod alloc; pub mod at_exit_imp; #[cfg(feature = "backtrace")] @@ -52,6 +61,7 @@ pub mod util; pub mod wtf8; pub mod bytestring; pub mod process; +pub mod fs; cfg_if! { if #[cfg(any(target_os = "cloudabi", diff --git a/src/libstd/sys_common/os_str_bytes.rs b/src/libstd/sys_common/os_str_bytes.rs index 7cc93477a73..a4961974d89 100644 --- a/src/libstd/sys_common/os_str_bytes.rs +++ b/src/libstd/sys_common/os_str_bytes.rs @@ -236,9 +236,11 @@ pub trait OsStrExt { #[stable(feature = "rust1", since = "1.0.0")] impl OsStrExt for OsStr { + #[inline] fn from_bytes(slice: &[u8]) -> &OsStr { unsafe { mem::transmute(slice) } } + #[inline] fn as_bytes(&self) -> &[u8] { &self.as_inner().inner } diff --git a/src/libstd/sys_common/thread.rs b/src/libstd/sys_common/thread.rs index b2142e75308..6ab0d5cbe9c 100644 --- a/src/libstd/sys_common/thread.rs +++ b/src/libstd/sys_common/thread.rs @@ -1,4 +1,3 @@ -use crate::boxed::FnBox; use crate::env; use crate::sync::atomic::{self, Ordering}; use crate::sys::stack_overflow; @@ -11,7 +10,7 @@ pub unsafe fn start_thread(main: *mut u8) { let _handler = stack_overflow::Handler::new(); // Finally, let's run some code. - Box::from_raw(main as *mut Box<dyn FnBox()>)() + Box::from_raw(main as *mut Box<dyn FnOnce()>)() } pub fn min_stack() -> usize { diff --git a/src/libstd/sys_common/wtf8.rs b/src/libstd/sys_common/wtf8.rs index 7fe1818291e..f17020de44e 100644 --- a/src/libstd/sys_common/wtf8.rs +++ b/src/libstd/sys_common/wtf8.rs @@ -388,9 +388,7 @@ impl Extend<CodePoint> for Wtf8Buf { let (low, _high) = iterator.size_hint(); // Lower bound of one byte per code point (ASCII only) self.bytes.reserve(low); - for code_point in iterator { - self.push(code_point); - } + iterator.for_each(move |code_point| self.push(code_point)); } } diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index cb507971091..c59226e0c0b 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -157,7 +157,6 @@ #![stable(feature = "rust1", since = "1.0.0")] use crate::any::Any; -use crate::boxed::FnBox; use crate::cell::UnsafeCell; use crate::ffi::{CStr, CString}; use crate::fmt; @@ -488,7 +487,9 @@ impl Builder { // returning. native: Some(imp::Thread::new( stack_size, - mem::transmute::<Box<dyn FnBox() + 'a>, Box<dyn FnBox() + 'static>>(Box::new(main)) + mem::transmute::<Box<dyn FnOnce() + 'a>, Box<dyn FnOnce() + 'static>>(Box::new( + main, + )), )?), thread: my_thread, packet: Packet(my_packet), diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index bcc8fdf8cd4..cf909e30e32 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -946,7 +946,7 @@ pub struct Expr { // `Expr` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(target_arch = "x86_64")] -static_assert!(MEM_SIZE_OF_EXPR: std::mem::size_of::<Expr>() == 88); +static_assert!(MEM_SIZE_OF_EXPR: std::mem::size_of::<Expr>() == 96); impl Expr { /// Whether this expression would be valid somewhere that expects a value; for example, an `if` diff --git a/src/libsyntax/diagnostics/metadata.rs b/src/libsyntax/diagnostics/metadata.rs index 704135fe1d5..53f37bb10bd 100644 --- a/src/libsyntax/diagnostics/metadata.rs +++ b/src/libsyntax/diagnostics/metadata.rs @@ -36,9 +36,9 @@ pub struct ErrorLocation { impl ErrorLocation { /// Creates an error location from a span. pub fn from_span(ecx: &ExtCtxt<'_>, sp: Span) -> ErrorLocation { - let loc = ecx.source_map().lookup_char_pos_adj(sp.lo()); + let loc = ecx.source_map().lookup_char_pos(sp.lo()); ErrorLocation { - filename: loc.filename, + filename: loc.file.name.clone(), line: loc.line } } diff --git a/src/libsyntax/early_buffered_lints.rs b/src/libsyntax/early_buffered_lints.rs index 29cb9cd7f30..977e6d45877 100644 --- a/src/libsyntax/early_buffered_lints.rs +++ b/src/libsyntax/early_buffered_lints.rs @@ -12,8 +12,6 @@ pub enum BufferedEarlyLintId { /// Usage of `?` as a macro separator is deprecated. QuestionMarkMacroSep, IllFormedAttributeInput, - /// Usage of a duplicate macro matcher binding name. - DuplicateMacroMatcherBindingName, } /// Stores buffered lint info which can later be passed to `librustc`. diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 12912044e4e..b1b9d25b3d5 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -497,22 +497,14 @@ fn check_lhs_duplicate_matcher_bindings( node_id: ast::NodeId, ) -> bool { use self::quoted::TokenTree; - use crate::early_buffered_lints::BufferedEarlyLintId; for tt in tts { match *tt { TokenTree::MetaVarDecl(span, name, _kind) => { if let Some(&prev_span) = metavar_names.get(&name) { - // FIXME(mark-i-m): in a few cycles, make this a hard error. - // sess.span_diagnostic - // .struct_span_err(span, "duplicate matcher binding") - // .span_note(prev_span, "previous declaration was here") - // .emit(); - sess.buffer_lint( - BufferedEarlyLintId::DuplicateMacroMatcherBindingName, - crate::source_map::MultiSpan::from(vec![prev_span, span]), - node_id, - "duplicate matcher binding" - ); + sess.span_diagnostic + .struct_span_err(span, "duplicate matcher binding") + .span_note(prev_span, "previous declaration was here") + .emit(); return false; } else { metavar_names.insert(name, span); diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index dcb55fb572f..f77593ed02a 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -903,7 +903,7 @@ pub const BUILTIN_ATTRIBUTES: &[(&str, AttributeType, AttributeTemplate, Attribu ("thread_local", Whitelisted, template!(Word), Gated(Stability::Unstable, "thread_local", "`#[thread_local]` is an experimental feature, and does \ - not currently handle destructors.", + not currently handle destructors", cfg_fn!(thread_local))), ("rustc_on_unimplemented", Whitelisted, template!(List: @@ -1438,18 +1438,34 @@ pub enum GateStrength { Soft, } -pub fn emit_feature_err(sess: &ParseSess, feature: &str, span: Span, issue: GateIssue, - explain: &str) { +pub fn emit_feature_err( + sess: &ParseSess, + feature: &str, + span: Span, + issue: GateIssue, + explain: &str, +) { feature_err(sess, feature, span, issue, explain).emit(); } -pub fn feature_err<'a>(sess: &'a ParseSess, feature: &str, span: Span, issue: GateIssue, - explain: &str) -> DiagnosticBuilder<'a> { +pub fn feature_err<'a>( + sess: &'a ParseSess, + feature: &str, + span: Span, + issue: GateIssue, + explain: &str, +) -> DiagnosticBuilder<'a> { leveled_feature_err(sess, feature, span, issue, explain, GateStrength::Hard) } -fn leveled_feature_err<'a>(sess: &'a ParseSess, feature: &str, span: Span, issue: GateIssue, - explain: &str, level: GateStrength) -> DiagnosticBuilder<'a> { +fn leveled_feature_err<'a>( + sess: &'a ParseSess, + feature: &str, + span: Span, + issue: GateIssue, + explain: &str, + level: GateStrength, +) -> DiagnosticBuilder<'a> { let diag = &sess.span_diagnostic; let issue = match issue { @@ -1457,23 +1473,26 @@ fn leveled_feature_err<'a>(sess: &'a ParseSess, feature: &str, span: Span, issue GateIssue::Library(lib) => lib, }; - let explanation = match issue { - None | Some(0) => explain.to_owned(), - Some(n) => format!("{} (see issue #{})", explain, n) - }; - let mut err = match level { GateStrength::Hard => { - diag.struct_span_err_with_code(span, &explanation, stringify_error_code!(E0658)) + diag.struct_span_err_with_code(span, explain, stringify_error_code!(E0658)) } - GateStrength::Soft => diag.struct_span_warn(span, &explanation), + GateStrength::Soft => diag.struct_span_warn(span, explain), }; + match issue { + None | Some(0) => {} // We still accept `0` as a stand-in for backwards compatibility + Some(n) => { + err.note(&format!( + "for more information, see https://github.com/rust-lang/rust/issues/{}", + n, + )); + } + } + // #23973: do not suggest `#![feature(...)]` if we are in beta/stable if sess.unstable_features.is_nightly_build() { - err.help(&format!("add #![feature({})] to the \ - crate attributes to enable", - feature)); + err.help(&format!("add #![feature({})] to the crate attributes to enable", feature)); } // If we're on stable and only emitting a "soft" warning, add a note to @@ -1488,10 +1507,10 @@ fn leveled_feature_err<'a>(sess: &'a ParseSess, feature: &str, span: Span, issue } const EXPLAIN_BOX_SYNTAX: &str = - "box expression syntax is experimental; you can call `Box::new` instead."; + "box expression syntax is experimental; you can call `Box::new` instead"; pub const EXPLAIN_STMT_ATTR_SYNTAX: &str = - "attributes on expressions are experimental."; + "attributes on expressions are experimental"; pub const EXPLAIN_ASM: &str = "inline assembly is not stable enough for use and is subject to change"; @@ -1685,10 +1704,12 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { fn visit_name(&mut self, sp: Span, name: ast::Name) { if !name.as_str().is_ascii() { - gate_feature_post!(&self, - non_ascii_idents, - self.context.parse_sess.source_map().def_span(sp), - "non-ascii idents are not fully supported."); + gate_feature_post!( + &self, + non_ascii_idents, + self.context.parse_sess.source_map().def_span(sp), + "non-ascii idents are not fully supported" + ); } } diff --git a/src/libsyntax/json.rs b/src/libsyntax/json.rs index 9acd0d099a0..838dfc62646 100644 --- a/src/libsyntax/json.rs +++ b/src/libsyntax/json.rs @@ -348,19 +348,17 @@ impl DiagnosticSpanLine { /// `span` within the line. fn from_span(span: Span, je: &JsonEmitter) -> Vec<DiagnosticSpanLine> { je.sm.span_to_lines(span) - .map(|lines| { - let fm = &*lines.file; - lines.lines - .iter() - .map(|line| { - DiagnosticSpanLine::line_from_source_file(fm, - line.line_index, - line.start_col.0 + 1, - line.end_col.0 + 1) - }) - .collect() - }) - .unwrap_or_else(|_| vec![]) + .map(|lines| { + let fm = &*lines.file; + lines.lines + .iter() + .map(|line| DiagnosticSpanLine::line_from_source_file( + fm, + line.line_index, + line.start_col.0 + 1, + line.end_col.0 + 1, + )).collect() + }).unwrap_or_else(|_| vec![]) } } diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index a6145d5dcb3..9905b981395 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -8,6 +8,7 @@ test(attr(deny(warnings))))] #![deny(rust_2018_idioms)] +#![cfg_attr(not(stage0), deny(internal))] #![feature(crate_visibility_modifier)] #![feature(label_break_value)] diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index cd4944deadb..5557e281a66 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -1,10 +1,9 @@ use crate::ast::{self, Ident}; -use crate::source_map::{SourceMap, FilePathMapping}; use crate::parse::{token, ParseSess}; use crate::symbol::Symbol; use errors::{Applicability, FatalError, Diagnostic, DiagnosticBuilder}; -use syntax_pos::{BytePos, CharPos, Pos, Span, NO_EXPANSION}; +use syntax_pos::{BytePos, Pos, Span, NO_EXPANSION}; use core::unicode::property::Pattern_White_Space; use std::borrow::Cow; @@ -43,16 +42,16 @@ pub struct UnmatchedBrace { } pub struct StringReader<'a> { - pub sess: &'a ParseSess, + crate sess: &'a ParseSess, /// The absolute offset within the source_map of the next character to read - pub next_pos: BytePos, + crate next_pos: BytePos, /// The absolute offset within the source_map of the current character - pub pos: BytePos, + crate pos: BytePos, /// The current character (which has been read from self.pos) - pub ch: Option<char>, - pub source_file: Lrc<syntax_pos::SourceFile>, + crate ch: Option<char>, + crate source_file: Lrc<syntax_pos::SourceFile>, /// Stop reading src at this index. - pub end_src_index: usize, + crate end_src_index: usize, // cached: peek_tok: token::Token, peek_span: Span, @@ -126,7 +125,7 @@ impl<'a> StringReader<'a> { } /// Immutably extract string if found at current position with given delimiters - pub fn peek_delimited(&self, from_ch: char, to_ch: char) -> Option<String> { + fn peek_delimited(&self, from_ch: char, to_ch: char) -> Option<String> { let mut pos = self.pos; let mut idx = self.src_index(pos); let mut ch = char_at(&self.src, idx); @@ -191,7 +190,7 @@ impl<'a> StringReader<'a> { self.fatal_span(self.peek_span, m) } - pub fn emit_fatal_errors(&mut self) { + crate fn emit_fatal_errors(&mut self) { for err in &mut self.fatal_errs { err.emit(); } @@ -667,14 +666,9 @@ impl<'a> StringReader<'a> { return None; } - // I guess this is the only way to figure out if - // we're at the beginning of the file... - let smap = SourceMap::new(FilePathMapping::empty()); - smap.files.borrow_mut().source_files.push(self.source_file.clone()); - let loc = smap.lookup_char_pos_adj(self.pos); - debug!("Skipping a shebang"); - if loc.line == 1 && loc.col == CharPos(0) { - // FIXME: Add shebang "token", return it + let is_beginning_of_file = self.pos == self.source_file.start_pos; + if is_beginning_of_file { + debug!("Skipping a shebang"); let start = self.pos; while !self.ch_is('\n') && !self.is_eof() { self.bump(); @@ -1911,7 +1905,7 @@ mod tests { use crate::ast::{Ident, CrateConfig}; use crate::symbol::Symbol; - use crate::source_map::SourceMap; + use crate::source_map::{SourceMap, FilePathMapping}; use crate::feature_gate::UnstableFeatures; use crate::parse::token; use crate::diagnostics::plugin::ErrorMap; diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 37360a56395..a5adb37f745 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -851,8 +851,34 @@ impl<'a> Parser<'a> { } } + let is_semi_suggestable = expected.iter().any(|t| match t { + TokenType::Token(token::Semi) => true, // we expect a `;` here + _ => false, + }) && ( // a `;` would be expected before the current keyword + self.token.is_keyword(keywords::Break) || + self.token.is_keyword(keywords::Continue) || + self.token.is_keyword(keywords::For) || + self.token.is_keyword(keywords::If) || + self.token.is_keyword(keywords::Let) || + self.token.is_keyword(keywords::Loop) || + self.token.is_keyword(keywords::Match) || + self.token.is_keyword(keywords::Return) || + self.token.is_keyword(keywords::While) + ); let cm = self.sess.source_map(); match (cm.lookup_line(self.span.lo()), cm.lookup_line(sp.lo())) { + (Ok(ref a), Ok(ref b)) if a.line != b.line && is_semi_suggestable => { + // The spans are in different lines, expected `;` and found `let` or `return`. + // High likelihood that it is only a missing `;`. + err.span_suggestion_short( + label_sp, + "a semicolon may be missing here", + ";".to_string(), + Applicability::MaybeIncorrect, + ); + err.emit(); + return Ok(true); + } (Ok(ref a), Ok(ref b)) if a.line == b.line => { // When the spans are in the same line, it means that the only content between // them is whitespace, point at the found token in that case: @@ -2165,9 +2191,11 @@ impl<'a> Parser<'a> { suffix, ) = self.token { let suffix = suffix.and_then(|s| { - let s = s.as_str().get(); - if ["f32", "f64"].contains(&s) { - Some(s) + let s = s.as_str(); + if s == "f32" { + Some("f32") + } else if s == "f64" { + Some("f64") } else { None } @@ -4089,7 +4117,15 @@ impl<'a> Parser<'a> { { let (iattrs, body) = self.parse_inner_attrs_and_block()?; attrs.extend(iattrs); - Ok(self.mk_expr(span_lo.to(body.span), ExprKind::TryBlock(body), attrs)) + if self.eat_keyword(keywords::Catch) { + let mut error = self.struct_span_err(self.prev_span, + "keyword `catch` cannot follow a `try` block"); + error.help("try using `match` on the result of the `try` block instead"); + error.emit(); + Err(error) + } else { + Ok(self.mk_expr(span_lo.to(body.span), ExprKind::TryBlock(body), attrs)) + } } // `match` token already eaten diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index f5a9aded845..ca05ff71c94 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -645,7 +645,7 @@ pub trait PrintState<'a> { ast::LitKind::Float(ref f, t) => { self.writer().word(format!("{}{}", &f, t.ty_to_string())) } - ast::LitKind::FloatUnsuffixed(ref f) => self.writer().word(f.as_str().get()), + ast::LitKind::FloatUnsuffixed(ref f) => self.writer().word(f.as_str().to_string()), ast::LitKind::Bool(val) => { if val { self.writer().word("true") } else { self.writer().word("false") } } @@ -731,7 +731,7 @@ pub trait PrintState<'a> { if segment.ident.name == keywords::DollarCrate.name() { self.print_dollar_crate(segment.ident)?; } else { - self.writer().word(segment.ident.as_str().get())?; + self.writer().word(segment.ident.as_str().to_string())?; } } } @@ -749,7 +749,7 @@ pub trait PrintState<'a> { } self.maybe_print_comment(attr.span.lo())?; if attr.is_sugared_doc { - self.writer().word(attr.value_str().unwrap().as_str().get())?; + self.writer().word(attr.value_str().unwrap().as_str().to_string())?; self.writer().hardbreak() } else { match attr.style { @@ -858,7 +858,7 @@ pub trait PrintState<'a> { if !ast::Ident::with_empty_ctxt(name).is_path_segment_keyword() { self.writer().word("::")?; } - self.writer().word(name.as_str().get()) + self.writer().word(name.as_str().to_string()) } } @@ -1300,7 +1300,7 @@ impl<'a> State<'a> { } ast::ItemKind::GlobalAsm(ref ga) => { self.head(visibility_qualified(&item.vis, "global_asm!"))?; - self.s.word(ga.asm.as_str().get())?; + self.s.word(ga.asm.as_str().to_string())?; self.end()?; } ast::ItemKind::Ty(ref ty, ref generics) => { @@ -2437,7 +2437,7 @@ impl<'a> State<'a> { if ident.is_raw_guess() { self.s.word(format!("r#{}", ident))?; } else { - self.s.word(ident.as_str().get())?; + self.s.word(ident.as_str().to_string())?; } self.ann.post(self, AnnNode::Ident(&ident)) } @@ -2447,7 +2447,7 @@ impl<'a> State<'a> { } pub fn print_name(&mut self, name: ast::Name) -> io::Result<()> { - self.s.word(name.as_str().get())?; + self.s.word(name.as_str().to_string())?; self.ann.post(self, AnnNode::Name(&name)) } diff --git a/src/libsyntax/source_map.rs b/src/libsyntax/source_map.rs index 62a6972122a..08abbf5e8a4 100644 --- a/src/libsyntax/source_map.rs +++ b/src/libsyntax/source_map.rs @@ -388,16 +388,6 @@ impl SourceMap { } } - pub fn lookup_char_pos_adj(&self, pos: BytePos) -> LocWithOpt { - let loc = self.lookup_char_pos(pos); - LocWithOpt { - filename: loc.file.name.clone(), - line: loc.line, - col: loc.col, - file: Some(loc.file) - } - } - /// Returns `Some(span)`, a union of the lhs and rhs span. The lhs must precede the rhs. If /// there are gaps between lhs and rhs, the resulting union will cross these gaps. /// For this to work, the spans have to be: @@ -438,10 +428,10 @@ impl SourceMap { return "no-location".to_string(); } - let lo = self.lookup_char_pos_adj(sp.lo()); - let hi = self.lookup_char_pos_adj(sp.hi()); + let lo = self.lookup_char_pos(sp.lo()); + let hi = self.lookup_char_pos(sp.hi()); format!("{}:{}:{}: {}:{}", - lo.filename, + lo.file.name, lo.line, lo.col.to_usize() + 1, hi.line, diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs index 5efa6b36f67..24fbc9b6caf 100644 --- a/src/libsyntax_ext/format.rs +++ b/src/libsyntax_ext/format.rs @@ -347,9 +347,9 @@ impl<'a, 'b> Context<'a, 'b> { Named(name) => { match self.names.get(&name) { - Some(idx) => { + Some(&idx) => { // Treat as positional arg. - self.verify_arg_type(Exact(*idx), ty) + self.verify_arg_type(Exact(idx), ty) } None => { let msg = format!("there is no argument named `{}`", name); diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs index aa472eee3ca..ee0b86963f3 100644 --- a/src/libsyntax_ext/lib.rs +++ b/src/libsyntax_ext/lib.rs @@ -3,6 +3,7 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] #![deny(rust_2018_idioms)] +#![cfg_attr(not(stage0), deny(internal))] #![feature(in_band_lifetimes)] #![feature(proc_macro_diagnostic)] diff --git a/src/libsyntax_ext/proc_macro_server.rs b/src/libsyntax_ext/proc_macro_server.rs index f902e8169b6..09dce775790 100644 --- a/src/libsyntax_ext/proc_macro_server.rs +++ b/src/libsyntax_ext/proc_macro_server.rs @@ -336,11 +336,11 @@ impl Ident { } } fn new(sym: Symbol, is_raw: bool, span: Span) -> Ident { - let string = sym.as_str().get(); - if !Self::is_valid(string) { + let string = sym.as_str(); + if !Self::is_valid(&string) { panic!("`{:?}` is not a valid identifier", string) } - if is_raw && !ast::Ident::from_str(string).can_be_raw() { + if is_raw && !ast::Ident::from_interned_str(sym.as_interned_str()).can_be_raw() { panic!("`{}` cannot be a raw identifier", string); } Ident { sym, is_raw, span } diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index 6331fe60886..1ffecea44ed 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -218,14 +218,17 @@ pub fn clear_markings() { } impl SyntaxContext { + #[inline] pub const fn empty() -> Self { SyntaxContext(0) } + #[inline] crate fn as_u32(self) -> u32 { self.0 } + #[inline] crate fn from_u32(raw: u32) -> SyntaxContext { SyntaxContext(raw) } diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 48d087ee43c..81cf804cf0b 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -7,6 +7,7 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] #![deny(rust_2018_idioms)] +#![cfg_attr(not(stage0), deny(internal))] #![feature(const_fn)] #![feature(crate_visibility_modifier)] @@ -1294,7 +1295,7 @@ impl Sub for CharPos { } // _____________________________________________________________________________ -// Loc, LocWithOpt, SourceFileAndLine, SourceFileAndBytePos +// Loc, SourceFileAndLine, SourceFileAndBytePos // /// A source code location used for error reporting. @@ -1310,17 +1311,6 @@ pub struct Loc { pub col_display: usize, } -/// A source code location used as the result of `lookup_char_pos_adj`. -// Actually, *none* of the clients use the filename *or* file field; -// perhaps they should just be removed. -#[derive(Debug)] -pub struct LocWithOpt { - pub filename: FileName, - pub line: usize, - pub col: CharPos, - pub file: Option<Lrc<SourceFile>>, -} - // Used to be structural records. #[derive(Debug)] pub struct SourceFileAndLine { pub sf: Lrc<SourceFile>, pub line: usize } diff --git a/src/libsyntax_pos/span_encoding.rs b/src/libsyntax_pos/span_encoding.rs index 03d7a9eb742..525ec136232 100644 --- a/src/libsyntax_pos/span_encoding.rs +++ b/src/libsyntax_pos/span_encoding.rs @@ -9,122 +9,106 @@ use crate::{BytePos, SpanData}; use crate::hygiene::SyntaxContext; use rustc_data_structures::fx::FxHashMap; -use std::hash::{Hash, Hasher}; /// A compressed span. -/// Contains either fields of `SpanData` inline if they are small, or index into span interner. -/// The primary goal of `Span` is to be as small as possible and fit into other structures -/// (that's why it uses `packed` as well). Decoding speed is the second priority. -/// See `SpanData` for the info on span fields in decoded representation. -#[repr(packed)] -pub struct Span(u32); - -impl Copy for Span {} -impl Clone for Span { - #[inline] - fn clone(&self) -> Span { - *self - } -} -impl PartialEq for Span { - #[inline] - fn eq(&self, other: &Span) -> bool { - let a = self.0; - let b = other.0; - a == b - } -} -impl Eq for Span {} -impl Hash for Span { - #[inline] - fn hash<H: Hasher>(&self, state: &mut H) { - let a = self.0; - a.hash(state) - } +/// +/// `SpanData` is 12 bytes, which is a bit too big to stick everywhere. `Span` +/// is a form that only takes up 8 bytes, with less space for the length and +/// context. The vast majority (99.9%+) of `SpanData` instances will fit within +/// those 8 bytes; any `SpanData` whose fields don't fit into a `Span` are +/// stored in a separate interner table, and the `Span` will index into that +/// table. Interning is rare enough that the cost is low, but common enough +/// that the code is exercised regularly. +/// +/// An earlier version of this code used only 4 bytes for `Span`, but that was +/// slower because only 80--90% of spans could be stored inline (even less in +/// very large crates) and so the interner was used a lot more. +/// +/// Inline (compressed) format: +/// - `span.base_or_index == span_data.lo` +/// - `span.len_or_tag == len == span_data.hi - span_data.lo` (must be `<= MAX_LEN`) +/// - `span.ctxt == span_data.ctxt` (must be `<= MAX_CTXT`) +/// +/// Interned format: +/// - `span.base_or_index == index` (indexes into the interner table) +/// - `span.len_or_tag == LEN_TAG` (high bit set, all other bits are zero) +/// - `span.ctxt == 0` +/// +/// The inline form uses 0 for the tag value (rather than 1) so that we don't +/// need to mask out the tag bit when getting the length, and so that the +/// dummy span can be all zeroes. +/// +/// Notes about the choice of field sizes: +/// - `base` is 32 bits in both `Span` and `SpanData`, which means that `base` +/// values never cause interning. The number of bits needed for `base` +/// depends on the crate size. 32 bits allows up to 4 GiB of code in a crate. +/// `script-servo` is the largest crate in `rustc-perf`, requiring 26 bits +/// for some spans. +/// - `len` is 15 bits in `Span` (a u16, minus 1 bit for the tag) and 32 bits +/// in `SpanData`, which means that large `len` values will cause interning. +/// The number of bits needed for `len` does not depend on the crate size. +/// The most common number of bits for `len` are 0--7, with a peak usually at +/// 3 or 4, and then it drops off quickly from 8 onwards. 15 bits is enough +/// for 99.99%+ of cases, but larger values (sometimes 20+ bits) might occur +/// dozens of times in a typical crate. +/// - `ctxt` is 16 bits in `Span` and 32 bits in `SpanData`, which means that +/// large `ctxt` values will cause interning. The number of bits needed for +/// `ctxt` values depend partly on the crate size and partly on the form of +/// the code. No crates in `rustc-perf` need more than 15 bits for `ctxt`, +/// but larger crates might need more than 16 bits. +/// +#[derive(Clone, Copy, Eq, PartialEq, Hash)] +pub struct Span { + base_or_index: u32, + len_or_tag: u16, + ctxt_or_zero: u16 } +const LEN_TAG: u16 = 0b1000_0000_0000_0000; +const MAX_LEN: u32 = 0b0111_1111_1111_1111; +const MAX_CTXT: u32 = 0b1111_1111_1111_1111; + /// Dummy span, both position and length are zero, syntax context is zero as well. -/// This span is kept inline and encoded with format 0. -pub const DUMMY_SP: Span = Span(0); +pub const DUMMY_SP: Span = Span { base_or_index: 0, len_or_tag: 0, ctxt_or_zero: 0 }; impl Span { #[inline] - pub fn new(lo: BytePos, hi: BytePos, ctxt: SyntaxContext) -> Self { - encode(&match lo <= hi { - true => SpanData { lo, hi, ctxt }, - false => SpanData { lo: hi, hi: lo, ctxt }, - }) + pub fn new(mut lo: BytePos, mut hi: BytePos, ctxt: SyntaxContext) -> Self { + if lo > hi { + std::mem::swap(&mut lo, &mut hi); + } + + let (base, len, ctxt2) = (lo.0, hi.0 - lo.0, ctxt.as_u32()); + + if len <= MAX_LEN && ctxt2 <= MAX_CTXT { + // Inline format. + Span { base_or_index: base, len_or_tag: len as u16, ctxt_or_zero: ctxt2 as u16 } + } else { + // Interned format. + let index = with_span_interner(|interner| interner.intern(&SpanData { lo, hi, ctxt })); + Span { base_or_index: index, len_or_tag: LEN_TAG, ctxt_or_zero: 0 } + } } #[inline] pub fn data(self) -> SpanData { - decode(self) + if self.len_or_tag != LEN_TAG { + // Inline format. + debug_assert!(self.len_or_tag as u32 <= MAX_LEN); + SpanData { + lo: BytePos(self.base_or_index), + hi: BytePos(self.base_or_index + self.len_or_tag as u32), + ctxt: SyntaxContext::from_u32(self.ctxt_or_zero as u32), + } + } else { + // Interned format. + debug_assert!(self.ctxt_or_zero == 0); + let index = self.base_or_index; + with_span_interner(|interner| *interner.get(index)) + } } } -// Tags -const TAG_INLINE: u32 = 0; -const TAG_INTERNED: u32 = 1; -const TAG_MASK: u32 = 1; - -// Fields indexes -const BASE_INDEX: usize = 0; -const LEN_INDEX: usize = 1; -const CTXT_INDEX: usize = 2; - -// Tag = 0, inline format. -// ------------------------------------------------------------- -// | base 31:8 | len 7:1 | ctxt (currently 0 bits) | tag 0:0 | -// ------------------------------------------------------------- -// Since there are zero bits for ctxt, only SpanData with a 0 SyntaxContext -// can be inline. -const INLINE_SIZES: [u32; 3] = [24, 7, 0]; -const INLINE_OFFSETS: [u32; 3] = [8, 1, 1]; - -// Tag = 1, interned format. -// ------------------------ -// | index 31:1 | tag 0:0 | -// ------------------------ -const INTERNED_INDEX_SIZE: u32 = 31; -const INTERNED_INDEX_OFFSET: u32 = 1; - -#[inline] -fn encode(sd: &SpanData) -> Span { - let (base, len, ctxt) = (sd.lo.0, sd.hi.0 - sd.lo.0, sd.ctxt.as_u32()); - - let val = if (base >> INLINE_SIZES[BASE_INDEX]) == 0 && - (len >> INLINE_SIZES[LEN_INDEX]) == 0 && - (ctxt >> INLINE_SIZES[CTXT_INDEX]) == 0 { - (base << INLINE_OFFSETS[BASE_INDEX]) | (len << INLINE_OFFSETS[LEN_INDEX]) | - (ctxt << INLINE_OFFSETS[CTXT_INDEX]) | TAG_INLINE - } else { - let index = with_span_interner(|interner| interner.intern(sd)); - (index << INTERNED_INDEX_OFFSET) | TAG_INTERNED - }; - Span(val) -} - -#[inline] -fn decode(span: Span) -> SpanData { - let val = span.0; - - // Extract a field at position `pos` having size `size`. - let extract = |pos: u32, size: u32| { - let mask = ((!0u32) as u64 >> (32 - size)) as u32; // Can't shift u32 by 32 - (val >> pos) & mask - }; - - let (base, len, ctxt) = if val & TAG_MASK == TAG_INLINE {( - extract(INLINE_OFFSETS[BASE_INDEX], INLINE_SIZES[BASE_INDEX]), - extract(INLINE_OFFSETS[LEN_INDEX], INLINE_SIZES[LEN_INDEX]), - extract(INLINE_OFFSETS[CTXT_INDEX], INLINE_SIZES[CTXT_INDEX]), - )} else { - let index = extract(INTERNED_INDEX_OFFSET, INTERNED_INDEX_SIZE); - return with_span_interner(|interner| *interner.get(index)); - }; - SpanData { lo: BytePos(base), hi: BytePos(base + len), ctxt: SyntaxContext::from_u32(ctxt) } -} - #[derive(Default)] pub struct SpanInterner { spans: FxHashMap<SpanData, u32>, diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs index f61aa4284d2..393f52e7de5 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -524,7 +524,11 @@ impl LocalInternedString { } } - pub fn get(&self) -> &'static str { + pub fn get(&self) -> &str { + // This returns a valid string since we ensure that `self` outlives the interner + // by creating the interner on a thread which outlives threads which can access it. + // This type cannot move to a thread which outlives the interner since it does + // not implement Send. self.string } } diff --git a/src/libterm/Cargo.toml b/src/libterm/Cargo.toml new file mode 100644 index 00000000000..4eba9a9d79c --- /dev/null +++ b/src/libterm/Cargo.toml @@ -0,0 +1,10 @@ +[package] +authors = ["The Rust Project Developers"] +name = "term" +version = "0.0.0" +edition = "2018" + +[lib] +name = "term" +path = "lib.rs" +crate-type = ["dylib", "rlib"] diff --git a/src/libterm/lib.rs b/src/libterm/lib.rs new file mode 100644 index 00000000000..711716d9b92 --- /dev/null +++ b/src/libterm/lib.rs @@ -0,0 +1,201 @@ +//! Terminal formatting library. +//! +//! This crate provides the `Terminal` trait, which abstracts over an [ANSI +//! Terminal][ansi] to provide color printing, among other things. There are two +//! implementations, the `TerminfoTerminal`, which uses control characters from +//! a [terminfo][ti] database, and `WinConsole`, which uses the [Win32 Console +//! API][win]. +//! +//! # Examples +//! +//! ```no_run +//! # #![feature(rustc_private)] +//! extern crate term; +//! use std::io::prelude::*; +//! +//! fn main() { +//! let mut t = term::stdout().unwrap(); +//! +//! t.fg(term::color::GREEN).unwrap(); +//! write!(t, "hello, ").unwrap(); +//! +//! t.fg(term::color::RED).unwrap(); +//! writeln!(t, "world!").unwrap(); +//! +//! assert!(t.reset().unwrap()); +//! } +//! ``` +//! +//! [ansi]: https://en.wikipedia.org/wiki/ANSI_escape_code +//! [win]: http://msdn.microsoft.com/en-us/library/windows/desktop/ms682010%28v=vs.85%29.aspx +//! [ti]: https://en.wikipedia.org/wiki/Terminfo + +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/", + html_playground_url = "https://play.rust-lang.org/", + test(attr(deny(warnings))))] +#![deny(missing_docs)] + +#![deny(rust_2018_idioms)] + +#![cfg_attr(windows, feature(libc))] +// Handle rustfmt skips +#![feature(custom_attribute)] +#![allow(unused_attributes)] + +use std::io::prelude::*; +use std::io::{self, Stdout, Stderr}; + +pub use terminfo::TerminfoTerminal; +#[cfg(windows)] +pub use win::WinConsole; + +pub mod terminfo; + +#[cfg(windows)] +mod win; + +/// Alias for stdout terminals. +pub type StdoutTerminal = dyn Terminal<Output = Stdout> + Send; +/// Alias for stderr terminals. +pub type StderrTerminal = dyn Terminal<Output = Stderr> + Send; + +#[cfg(not(windows))] +/// Returns a Terminal wrapping stdout, or None if a terminal couldn't be +/// opened. +pub fn stdout() -> Option<Box<StdoutTerminal>> { + TerminfoTerminal::new(io::stdout()).map(|t| Box::new(t) as Box<StdoutTerminal>) +} + +#[cfg(windows)] +/// Returns a Terminal wrapping stdout, or None if a terminal couldn't be +/// opened. +pub fn stdout() -> Option<Box<StdoutTerminal>> { + TerminfoTerminal::new(io::stdout()) + .map(|t| Box::new(t) as Box<StdoutTerminal>) + .or_else(|| WinConsole::new(io::stdout()).ok().map(|t| Box::new(t) as Box<StdoutTerminal>)) +} + +#[cfg(not(windows))] +/// Returns a Terminal wrapping stderr, or None if a terminal couldn't be +/// opened. +pub fn stderr() -> Option<Box<StderrTerminal>> { + TerminfoTerminal::new(io::stderr()).map(|t| Box::new(t) as Box<StderrTerminal>) +} + +#[cfg(windows)] +/// Returns a Terminal wrapping stderr, or None if a terminal couldn't be +/// opened. +pub fn stderr() -> Option<Box<StderrTerminal>> { + TerminfoTerminal::new(io::stderr()) + .map(|t| Box::new(t) as Box<StderrTerminal>) + .or_else(|| WinConsole::new(io::stderr()).ok().map(|t| Box::new(t) as Box<StderrTerminal>)) +} + + +/// Terminal color definitions +#[allow(missing_docs)] +pub mod color { + /// Number for a terminal color + pub type Color = u16; + + pub const BLACK: Color = 0; + pub const RED: Color = 1; + pub const GREEN: Color = 2; + pub const YELLOW: Color = 3; + pub const BLUE: Color = 4; + pub const MAGENTA: Color = 5; + pub const CYAN: Color = 6; + pub const WHITE: Color = 7; + + pub const BRIGHT_BLACK: Color = 8; + pub const BRIGHT_RED: Color = 9; + pub const BRIGHT_GREEN: Color = 10; + pub const BRIGHT_YELLOW: Color = 11; + pub const BRIGHT_BLUE: Color = 12; + pub const BRIGHT_MAGENTA: Color = 13; + pub const BRIGHT_CYAN: Color = 14; + pub const BRIGHT_WHITE: Color = 15; +} + +/// Terminal attributes for use with term.attr(). +/// +/// Most attributes can only be turned on and must be turned off with term.reset(). +/// The ones that can be turned off explicitly take a boolean value. +/// Color is also represented as an attribute for convenience. +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +pub enum Attr { + /// Bold (or possibly bright) mode + Bold, + /// Dim mode, also called faint or half-bright. Often not supported + Dim, + /// Italics mode. Often not supported + Italic(bool), + /// Underline mode + Underline(bool), + /// Blink mode + Blink, + /// Standout mode. Often implemented as Reverse, sometimes coupled with Bold + Standout(bool), + /// Reverse mode, inverts the foreground and background colors + Reverse, + /// Secure mode, also called invis mode. Hides the printed text + Secure, + /// Convenience attribute to set the foreground color + ForegroundColor(color::Color), + /// Convenience attribute to set the background color + BackgroundColor(color::Color), +} + +/// A terminal with similar capabilities to an ANSI Terminal +/// (foreground/background colors etc). +pub trait Terminal: Write { + /// The terminal's output writer type. + type Output: Write; + + /// Sets the foreground color to the given color. + /// + /// If the color is a bright color, but the terminal only supports 8 colors, + /// the corresponding normal color will be used instead. + /// + /// Returns `Ok(true)` if the color was set, `Ok(false)` otherwise, and `Err(e)` + /// if there was an I/O error. + fn fg(&mut self, color: color::Color) -> io::Result<bool>; + + /// Sets the background color to the given color. + /// + /// If the color is a bright color, but the terminal only supports 8 colors, + /// the corresponding normal color will be used instead. + /// + /// Returns `Ok(true)` if the color was set, `Ok(false)` otherwise, and `Err(e)` + /// if there was an I/O error. + fn bg(&mut self, color: color::Color) -> io::Result<bool>; + + /// Sets the given terminal attribute, if supported. Returns `Ok(true)` + /// if the attribute was supported, `Ok(false)` otherwise, and `Err(e)` if + /// there was an I/O error. + fn attr(&mut self, attr: Attr) -> io::Result<bool>; + + /// Returns `true` if the given terminal attribute is supported. + fn supports_attr(&self, attr: Attr) -> bool; + + /// Resets all terminal attributes and colors to their defaults. + /// + /// Returns `Ok(true)` if the terminal was reset, `Ok(false)` otherwise, and `Err(e)` if there + /// was an I/O error. + /// + /// *Note: This does not flush.* + /// + /// That means the reset command may get buffered so, if you aren't planning on doing anything + /// else that might flush stdout's buffer (e.g., writing a line of text), you should flush after + /// calling reset. + fn reset(&mut self) -> io::Result<bool>; + + /// Gets an immutable reference to the stream inside + fn get_ref(&self) -> &Self::Output; + + /// Gets a mutable reference to the stream inside + fn get_mut(&mut self) -> &mut Self::Output; + + /// Returns the contained stream, destroying the `Terminal` + fn into_inner(self) -> Self::Output where Self: Sized; +} diff --git a/src/libterm/terminfo/mod.rs b/src/libterm/terminfo/mod.rs new file mode 100644 index 00000000000..be90195065e --- /dev/null +++ b/src/libterm/terminfo/mod.rs @@ -0,0 +1,265 @@ +//! Terminfo database interface. + +use std::collections::HashMap; +use std::env; +use std::error; +use std::fmt; +use std::fs::File; +use std::io::{self, prelude::*, BufReader}; +use std::path::Path; + +use crate::Attr; +use crate::color; +use crate::Terminal; + +use searcher::get_dbpath_for_term; +use parser::compiled::{parse, msys_terminfo}; +use parm::{expand, Variables, Param}; + +/// A parsed terminfo database entry. +#[derive(Debug)] +pub struct TermInfo { + /// Names for the terminal + pub names: Vec<String>, + /// Map of capability name to boolean value + pub bools: HashMap<String, bool>, + /// Map of capability name to numeric value + pub numbers: HashMap<String, u16>, + /// Map of capability name to raw (unexpanded) string + pub strings: HashMap<String, Vec<u8>>, +} + +/// A terminfo creation error. +#[derive(Debug)] +pub enum Error { + /// TermUnset Indicates that the environment doesn't include enough information to find + /// the terminfo entry. + TermUnset, + /// MalformedTerminfo indicates that parsing the terminfo entry failed. + MalformedTerminfo(String), + /// io::Error forwards any io::Errors encountered when finding or reading the terminfo entry. + IoError(io::Error), +} + +impl error::Error for Error { + fn description(&self) -> &str { + "failed to create TermInfo" + } + + fn cause(&self) -> Option<&dyn error::Error> { + use Error::*; + match *self { + IoError(ref e) => Some(e), + _ => None, + } + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use Error::*; + match *self { + TermUnset => Ok(()), + MalformedTerminfo(ref e) => e.fmt(f), + IoError(ref e) => e.fmt(f), + } + } +} + +impl TermInfo { + /// Creates a TermInfo based on current environment. + pub fn from_env() -> Result<TermInfo, Error> { + let term = match env::var("TERM") { + Ok(name) => TermInfo::from_name(&name), + Err(..) => return Err(Error::TermUnset), + }; + + if term.is_err() && env::var("MSYSCON").ok().map_or(false, |s| "mintty.exe" == s) { + // msys terminal + Ok(msys_terminfo()) + } else { + term + } + } + + /// Creates a TermInfo for the named terminal. + pub fn from_name(name: &str) -> Result<TermInfo, Error> { + get_dbpath_for_term(name) + .ok_or_else(|| { + Error::IoError(io::Error::new(io::ErrorKind::NotFound, "terminfo file not found")) + }) + .and_then(|p| TermInfo::from_path(&(*p))) + } + + /// Parse the given TermInfo. + pub fn from_path<P: AsRef<Path>>(path: P) -> Result<TermInfo, Error> { + Self::_from_path(path.as_ref()) + } + // Keep the metadata small + fn _from_path(path: &Path) -> Result<TermInfo, Error> { + let file = File::open(path).map_err(Error::IoError)?; + let mut reader = BufReader::new(file); + parse(&mut reader, false).map_err(Error::MalformedTerminfo) + } +} + +pub mod searcher; + +/// TermInfo format parsing. +pub mod parser { + //! ncurses-compatible compiled terminfo format parsing (term(5)) + pub mod compiled; +} +pub mod parm; + + +fn cap_for_attr(attr: Attr) -> &'static str { + match attr { + Attr::Bold => "bold", + Attr::Dim => "dim", + Attr::Italic(true) => "sitm", + Attr::Italic(false) => "ritm", + Attr::Underline(true) => "smul", + Attr::Underline(false) => "rmul", + Attr::Blink => "blink", + Attr::Standout(true) => "smso", + Attr::Standout(false) => "rmso", + Attr::Reverse => "rev", + Attr::Secure => "invis", + Attr::ForegroundColor(_) => "setaf", + Attr::BackgroundColor(_) => "setab", + } +} + +/// A Terminal that knows how many colors it supports, with a reference to its +/// parsed Terminfo database record. +pub struct TerminfoTerminal<T> { + num_colors: u16, + out: T, + ti: TermInfo, +} + +impl<T: Write + Send> Terminal for TerminfoTerminal<T> { + type Output = T; + fn fg(&mut self, color: color::Color) -> io::Result<bool> { + let color = self.dim_if_necessary(color); + if self.num_colors > color { + return self.apply_cap("setaf", &[Param::Number(color as i32)]); + } + Ok(false) + } + + fn bg(&mut self, color: color::Color) -> io::Result<bool> { + let color = self.dim_if_necessary(color); + if self.num_colors > color { + return self.apply_cap("setab", &[Param::Number(color as i32)]); + } + Ok(false) + } + + fn attr(&mut self, attr: Attr) -> io::Result<bool> { + match attr { + Attr::ForegroundColor(c) => self.fg(c), + Attr::BackgroundColor(c) => self.bg(c), + _ => self.apply_cap(cap_for_attr(attr), &[]), + } + } + + fn supports_attr(&self, attr: Attr) -> bool { + match attr { + Attr::ForegroundColor(_) | Attr::BackgroundColor(_) => self.num_colors > 0, + _ => { + let cap = cap_for_attr(attr); + self.ti.strings.get(cap).is_some() + } + } + } + + fn reset(&mut self) -> io::Result<bool> { + // are there any terminals that have color/attrs and not sgr0? + // Try falling back to sgr, then op + let cmd = match ["sgr0", "sgr", "op"] + .iter() + .filter_map(|cap| self.ti.strings.get(*cap)) + .next() { + Some(op) => { + match expand(&op, &[], &mut Variables::new()) { + Ok(cmd) => cmd, + Err(e) => return Err(io::Error::new(io::ErrorKind::InvalidData, e)), + } + } + None => return Ok(false), + }; + self.out.write_all(&cmd).and(Ok(true)) + } + + fn get_ref(&self) -> &T { + &self.out + } + + fn get_mut(&mut self) -> &mut T { + &mut self.out + } + + fn into_inner(self) -> T + where Self: Sized + { + self.out + } +} + +impl<T: Write + Send> TerminfoTerminal<T> { + /// Creates a new TerminfoTerminal with the given TermInfo and Write. + pub fn new_with_terminfo(out: T, terminfo: TermInfo) -> TerminfoTerminal<T> { + let nc = if terminfo.strings.contains_key("setaf") && + terminfo.strings.contains_key("setab") { + terminfo.numbers.get("colors").map_or(0, |&n| n) + } else { + 0 + }; + + TerminfoTerminal { + out, + ti: terminfo, + num_colors: nc, + } + } + + /// Creates a new TerminfoTerminal for the current environment with the given Write. + /// + /// Returns `None` when the terminfo cannot be found or parsed. + pub fn new(out: T) -> Option<TerminfoTerminal<T>> { + TermInfo::from_env().map(move |ti| TerminfoTerminal::new_with_terminfo(out, ti)).ok() + } + + fn dim_if_necessary(&self, color: color::Color) -> color::Color { + if color >= self.num_colors && color >= 8 && color < 16 { + color - 8 + } else { + color + } + } + + fn apply_cap(&mut self, cmd: &str, params: &[Param]) -> io::Result<bool> { + match self.ti.strings.get(cmd) { + Some(cmd) => { + match expand(&cmd, params, &mut Variables::new()) { + Ok(s) => self.out.write_all(&s).and(Ok(true)), + Err(e) => Err(io::Error::new(io::ErrorKind::InvalidData, e)), + } + } + None => Ok(false), + } + } +} + + +impl<T: Write> Write for TerminfoTerminal<T> { + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + self.out.write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.out.flush() + } +} diff --git a/src/libterm/terminfo/parm.rs b/src/libterm/terminfo/parm.rs new file mode 100644 index 00000000000..28229bd87b0 --- /dev/null +++ b/src/libterm/terminfo/parm.rs @@ -0,0 +1,669 @@ +//! Parameterized string expansion + +use self::Param::*; +use self::States::*; + +use std::iter::repeat; + +#[derive(Clone, Copy, PartialEq)] +enum States { + Nothing, + Percent, + SetVar, + GetVar, + PushParam, + CharConstant, + CharClose, + IntConstant(i32), + FormatPattern(Flags, FormatState), + SeekIfElse(usize), + SeekIfElsePercent(usize), + SeekIfEnd(usize), + SeekIfEndPercent(usize), +} + +#[derive(Copy, PartialEq, Clone)] +enum FormatState { + Flags, + Width, + Precision, +} + +/// Types of parameters a capability can use +#[allow(missing_docs)] +#[derive(Clone)] +pub enum Param { + Words(String), + Number(i32), +} + +/// Container for static and dynamic variable arrays +pub struct Variables { + /// Static variables A-Z + sta_va: [Param; 26], + /// Dynamic variables a-z + dyn_va: [Param; 26], +} + +impl Variables { + /// Returns a new zero-initialized Variables + pub fn new() -> Variables { + Variables { + sta_va: [ + Number(0), Number(0), Number(0), Number(0), Number(0), Number(0), Number(0), + Number(0), Number(0), Number(0), Number(0), Number(0), Number(0), Number(0), + Number(0), Number(0), Number(0), Number(0), Number(0), Number(0), Number(0), + Number(0), Number(0), Number(0), Number(0), Number(0) + ], + dyn_va: [ + Number(0), Number(0), Number(0), Number(0), Number(0), Number(0), Number(0), + Number(0), Number(0), Number(0), Number(0), Number(0), Number(0), Number(0), + Number(0), Number(0), Number(0), Number(0), Number(0), Number(0), Number(0), + Number(0), Number(0), Number(0), Number(0), Number(0) + ], + } + } +} + +/// Expand a parameterized capability +/// +/// # Arguments +/// * `cap` - string to expand +/// * `params` - vector of params for %p1 etc +/// * `vars` - Variables struct for %Pa etc +/// +/// To be compatible with ncurses, `vars` should be the same between calls to `expand` for +/// multiple capabilities for the same terminal. +pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) -> Result<Vec<u8>, String> { + let mut state = Nothing; + + // expanded cap will only rarely be larger than the cap itself + let mut output = Vec::with_capacity(cap.len()); + + let mut stack: Vec<Param> = Vec::new(); + + // Copy parameters into a local vector for mutability + let mut mparams = [Number(0), Number(0), Number(0), Number(0), Number(0), Number(0), + Number(0), Number(0), Number(0)]; + for (dst, src) in mparams.iter_mut().zip(params.iter()) { + *dst = (*src).clone(); + } + + for &c in cap.iter() { + let cur = c as char; + let mut old_state = state; + match state { + Nothing => { + if cur == '%' { + state = Percent; + } else { + output.push(c); + } + } + Percent => { + match cur { + '%' => { + output.push(c); + state = Nothing + } + 'c' => { + match stack.pop() { + // if c is 0, use 0200 (128) for ncurses compatibility + Some(Number(0)) => output.push(128u8), + // Don't check bounds. ncurses just casts and truncates. + Some(Number(c)) => output.push(c as u8), + Some(_) => return Err("a non-char was used with %c".to_string()), + None => return Err("stack is empty".to_string()), + } + } + 'p' => state = PushParam, + 'P' => state = SetVar, + 'g' => state = GetVar, + '\'' => state = CharConstant, + '{' => state = IntConstant(0), + 'l' => { + match stack.pop() { + Some(Words(s)) => stack.push(Number(s.len() as i32)), + Some(_) => return Err("a non-str was used with %l".to_string()), + None => return Err("stack is empty".to_string()), + } + } + '+' | '-' | '/' | '*' | '^' | '&' | '|' | 'm' => { + match (stack.pop(), stack.pop()) { + (Some(Number(y)), Some(Number(x))) => { + stack.push(Number(match cur { + '+' => x + y, + '-' => x - y, + '*' => x * y, + '/' => x / y, + '|' => x | y, + '&' => x & y, + '^' => x ^ y, + 'm' => x % y, + _ => unreachable!("All cases handled"), + })) + } + (Some(_), Some(_)) => { + return Err(format!("non-numbers on stack with {}", cur)) + } + _ => return Err("stack is empty".to_string()), + } + } + '=' | '>' | '<' | 'A' | 'O' => { + match (stack.pop(), stack.pop()) { + (Some(Number(y)), Some(Number(x))) => { + stack.push(Number(if match cur { + '=' => x == y, + '<' => x < y, + '>' => x > y, + 'A' => x > 0 && y > 0, + 'O' => x > 0 || y > 0, + _ => unreachable!(), + } { + 1 + } else { + 0 + })) + } + (Some(_), Some(_)) => { + return Err(format!("non-numbers on stack with {}", cur)) + } + _ => return Err("stack is empty".to_string()), + } + } + '!' | '~' => { + match stack.pop() { + Some(Number(x)) => { + stack.push(Number(match cur { + '!' if x > 0 => 0, + '!' => 1, + '~' => !x, + _ => unreachable!(), + })) + } + Some(_) => return Err(format!("non-numbers on stack with {}", cur)), + None => return Err("stack is empty".to_string()), + } + } + 'i' => { + match (&mparams[0], &mparams[1]) { + (&Number(x), &Number(y)) => { + mparams[0] = Number(x + 1); + mparams[1] = Number(y + 1); + } + _ => { + return Err("first two params not numbers with %i".to_string()) + } + } + } + + // printf-style support for %doxXs + 'd' | 'o' | 'x' | 'X' | 's' => { + if let Some(arg) = stack.pop() { + let flags = Flags::new(); + let res = format(arg, FormatOp::from_char(cur), flags)?; + output.extend(res.iter().cloned()); + } else { + return Err("stack is empty".to_string()); + } + } + ':' | '#' | ' ' | '.' | '0'..='9' => { + let mut flags = Flags::new(); + let mut fstate = FormatState::Flags; + match cur { + ':' => (), + '#' => flags.alternate = true, + ' ' => flags.space = true, + '.' => fstate = FormatState::Precision, + '0'..='9' => { + flags.width = cur as usize - '0' as usize; + fstate = FormatState::Width; + } + _ => unreachable!(), + } + state = FormatPattern(flags, fstate); + } + + // conditionals + '?' => (), + 't' => { + match stack.pop() { + Some(Number(0)) => state = SeekIfElse(0), + Some(Number(_)) => (), + Some(_) => { + return Err("non-number on stack with conditional".to_string()) + } + None => return Err("stack is empty".to_string()), + } + } + 'e' => state = SeekIfEnd(0), + ';' => (), + _ => return Err(format!("unrecognized format option {}", cur)), + } + } + PushParam => { + // params are 1-indexed + stack.push(mparams[match cur.to_digit(10) { + Some(d) => d as usize - 1, + None => return Err("bad param number".to_string()), + }] + .clone()); + } + SetVar => { + if cur >= 'A' && cur <= 'Z' { + if let Some(arg) = stack.pop() { + let idx = (cur as u8) - b'A'; + vars.sta_va[idx as usize] = arg; + } else { + return Err("stack is empty".to_string()); + } + } else if cur >= 'a' && cur <= 'z' { + if let Some(arg) = stack.pop() { + let idx = (cur as u8) - b'a'; + vars.dyn_va[idx as usize] = arg; + } else { + return Err("stack is empty".to_string()); + } + } else { + return Err("bad variable name in %P".to_string()); + } + } + GetVar => { + if cur >= 'A' && cur <= 'Z' { + let idx = (cur as u8) - b'A'; + stack.push(vars.sta_va[idx as usize].clone()); + } else if cur >= 'a' && cur <= 'z' { + let idx = (cur as u8) - b'a'; + stack.push(vars.dyn_va[idx as usize].clone()); + } else { + return Err("bad variable name in %g".to_string()); + } + } + CharConstant => { + stack.push(Number(c as i32)); + state = CharClose; + } + CharClose => { + if cur != '\'' { + return Err("malformed character constant".to_string()); + } + } + IntConstant(i) => { + if cur == '}' { + stack.push(Number(i)); + state = Nothing; + } else if let Some(digit) = cur.to_digit(10) { + match i.checked_mul(10).and_then(|i_ten| i_ten.checked_add(digit as i32)) { + Some(i) => { + state = IntConstant(i); + old_state = Nothing; + } + None => return Err("int constant too large".to_string()), + } + } else { + return Err("bad int constant".to_string()); + } + } + FormatPattern(ref mut flags, ref mut fstate) => { + old_state = Nothing; + match (*fstate, cur) { + (_, 'd') | (_, 'o') | (_, 'x') | (_, 'X') | (_, 's') => { + if let Some(arg) = stack.pop() { + let res = format(arg, FormatOp::from_char(cur), *flags)?; + output.extend(res.iter().cloned()); + // will cause state to go to Nothing + old_state = FormatPattern(*flags, *fstate); + } else { + return Err("stack is empty".to_string()); + } + } + (FormatState::Flags, '#') => { + flags.alternate = true; + } + (FormatState::Flags, '-') => { + flags.left = true; + } + (FormatState::Flags, '+') => { + flags.sign = true; + } + (FormatState::Flags, ' ') => { + flags.space = true; + } + (FormatState::Flags, '0'..='9') => { + flags.width = cur as usize - '0' as usize; + *fstate = FormatState::Width; + } + (FormatState::Flags, '.') => { + *fstate = FormatState::Precision; + } + (FormatState::Width, '0'..='9') => { + let old = flags.width; + flags.width = flags.width * 10 + (cur as usize - '0' as usize); + if flags.width < old { + return Err("format width overflow".to_string()); + } + } + (FormatState::Width, '.') => { + *fstate = FormatState::Precision; + } + (FormatState::Precision, '0'..='9') => { + let old = flags.precision; + flags.precision = flags.precision * 10 + (cur as usize - '0' as usize); + if flags.precision < old { + return Err("format precision overflow".to_string()); + } + } + _ => return Err("invalid format specifier".to_string()), + } + } + SeekIfElse(level) => { + if cur == '%' { + state = SeekIfElsePercent(level); + } + old_state = Nothing; + } + SeekIfElsePercent(level) => { + if cur == ';' { + if level == 0 { + state = Nothing; + } else { + state = SeekIfElse(level - 1); + } + } else if cur == 'e' && level == 0 { + state = Nothing; + } else if cur == '?' { + state = SeekIfElse(level + 1); + } else { + state = SeekIfElse(level); + } + } + SeekIfEnd(level) => { + if cur == '%' { + state = SeekIfEndPercent(level); + } + old_state = Nothing; + } + SeekIfEndPercent(level) => { + if cur == ';' { + if level == 0 { + state = Nothing; + } else { + state = SeekIfEnd(level - 1); + } + } else if cur == '?' { + state = SeekIfEnd(level + 1); + } else { + state = SeekIfEnd(level); + } + } + } + if state == old_state { + state = Nothing; + } + } + Ok(output) +} + +#[derive(Copy, PartialEq, Clone)] +struct Flags { + width: usize, + precision: usize, + alternate: bool, + left: bool, + sign: bool, + space: bool, +} + +impl Flags { + fn new() -> Flags { + Flags { + width: 0, + precision: 0, + alternate: false, + left: false, + sign: false, + space: false, + } + } +} + +#[derive(Copy, Clone)] +enum FormatOp { + Digit, + Octal, + LowerHex, + UpperHex, + String, +} + +impl FormatOp { + fn from_char(c: char) -> FormatOp { + match c { + 'd' => FormatOp::Digit, + 'o' => FormatOp::Octal, + 'x' => FormatOp::LowerHex, + 'X' => FormatOp::UpperHex, + 's' => FormatOp::String, + _ => panic!("bad FormatOp char"), + } + } + fn to_char(self) -> char { + match self { + FormatOp::Digit => 'd', + FormatOp::Octal => 'o', + FormatOp::LowerHex => 'x', + FormatOp::UpperHex => 'X', + FormatOp::String => 's', + } + } +} + +fn format(val: Param, op: FormatOp, flags: Flags) -> Result<Vec<u8>, String> { + let mut s = match val { + Number(d) => { + match op { + FormatOp::Digit => { + if flags.sign { + format!("{:+01$}", d, flags.precision) + } else if d < 0 { + // C doesn't take sign into account in precision calculation. + format!("{:01$}", d, flags.precision + 1) + } else if flags.space { + format!(" {:01$}", d, flags.precision) + } else { + format!("{:01$}", d, flags.precision) + } + } + FormatOp::Octal => { + if flags.alternate { + // Leading octal zero counts against precision. + format!("0{:01$o}", d, flags.precision.saturating_sub(1)) + } else { + format!("{:01$o}", d, flags.precision) + } + } + FormatOp::LowerHex => { + if flags.alternate && d != 0 { + format!("0x{:01$x}", d, flags.precision) + } else { + format!("{:01$x}", d, flags.precision) + } + } + FormatOp::UpperHex => { + if flags.alternate && d != 0 { + format!("0X{:01$X}", d, flags.precision) + } else { + format!("{:01$X}", d, flags.precision) + } + } + FormatOp::String => return Err("non-number on stack with %s".to_string()), + } + .into_bytes() + } + Words(s) => { + match op { + FormatOp::String => { + let mut s = s.into_bytes(); + if flags.precision > 0 && flags.precision < s.len() { + s.truncate(flags.precision); + } + s + } + _ => return Err(format!("non-string on stack with %{}", op.to_char())), + } + } + }; + if flags.width > s.len() { + let n = flags.width - s.len(); + if flags.left { + s.extend(repeat(b' ').take(n)); + } else { + let mut s_ = Vec::with_capacity(flags.width); + s_.extend(repeat(b' ').take(n)); + s_.extend(s.into_iter()); + s = s_; + } + } + Ok(s) +} + +#[cfg(test)] +mod test { + use super::{expand, Variables}; + use super::Param::{self, Words, Number}; + use std::result::Result::Ok; + + #[test] + fn test_basic_setabf() { + let s = b"\\E[48;5;%p1%dm"; + assert_eq!(expand(s, &[Number(1)], &mut Variables::new()).unwrap(), + "\\E[48;5;1m".bytes().collect::<Vec<_>>()); + } + + #[test] + fn test_multiple_int_constants() { + assert_eq!(expand(b"%{1}%{2}%d%d", &[], &mut Variables::new()).unwrap(), + "21".bytes().collect::<Vec<_>>()); + } + + #[test] + fn test_op_i() { + let mut vars = Variables::new(); + assert_eq!(expand(b"%p1%d%p2%d%p3%d%i%p1%d%p2%d%p3%d", + &[Number(1), Number(2), Number(3)], + &mut vars), + Ok("123233".bytes().collect::<Vec<_>>())); + assert_eq!(expand(b"%p1%d%p2%d%i%p1%d%p2%d", &[], &mut vars), + Ok("0011".bytes().collect::<Vec<_>>())); + } + + #[test] + fn test_param_stack_failure_conditions() { + let mut varstruct = Variables::new(); + let vars = &mut varstruct; + fn get_res(fmt: &str, + cap: &str, + params: &[Param], + vars: &mut Variables) + -> Result<Vec<u8>, String> { + let mut u8v: Vec<_> = fmt.bytes().collect(); + u8v.extend(cap.as_bytes().iter().map(|&b| b)); + expand(&u8v, params, vars) + } + + let caps = ["%d", "%c", "%s", "%Pa", "%l", "%!", "%~"]; + for &cap in caps.iter() { + let res = get_res("", cap, &[], vars); + assert!(res.is_err(), + "Op {} succeeded incorrectly with 0 stack entries", + cap); + let p = if cap == "%s" || cap == "%l" { + Words("foo".to_string()) + } else { + Number(97) + }; + let res = get_res("%p1", cap, &[p], vars); + assert!(res.is_ok(), + "Op {} failed with 1 stack entry: {}", + cap, + res.unwrap_err()); + } + let caps = ["%+", "%-", "%*", "%/", "%m", "%&", "%|", "%A", "%O"]; + for &cap in caps.iter() { + let res = expand(cap.as_bytes(), &[], vars); + assert!(res.is_err(), + "Binop {} succeeded incorrectly with 0 stack entries", + cap); + let res = get_res("%{1}", cap, &[], vars); + assert!(res.is_err(), + "Binop {} succeeded incorrectly with 1 stack entry", + cap); + let res = get_res("%{1}%{2}", cap, &[], vars); + assert!(res.is_ok(), + "Binop {} failed with 2 stack entries: {}", + cap, + res.unwrap_err()); + } + } + + #[test] + fn test_push_bad_param() { + assert!(expand(b"%pa", &[], &mut Variables::new()).is_err()); + } + + #[test] + fn test_comparison_ops() { + let v = [('<', [1u8, 0u8, 0u8]), ('=', [0u8, 1u8, 0u8]), ('>', [0u8, 0u8, 1u8])]; + for &(op, bs) in v.iter() { + let s = format!("%{{1}}%{{2}}%{}%d", op); + let res = expand(s.as_bytes(), &[], &mut Variables::new()); + assert!(res.is_ok(), res.unwrap_err()); + assert_eq!(res.unwrap(), vec![b'0' + bs[0]]); + let s = format!("%{{1}}%{{1}}%{}%d", op); + let res = expand(s.as_bytes(), &[], &mut Variables::new()); + assert!(res.is_ok(), res.unwrap_err()); + assert_eq!(res.unwrap(), vec![b'0' + bs[1]]); + let s = format!("%{{2}}%{{1}}%{}%d", op); + let res = expand(s.as_bytes(), &[], &mut Variables::new()); + assert!(res.is_ok(), res.unwrap_err()); + assert_eq!(res.unwrap(), vec![b'0' + bs[2]]); + } + } + + #[test] + fn test_conditionals() { + let mut vars = Variables::new(); + let s = b"\\E[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m"; + let res = expand(s, &[Number(1)], &mut vars); + assert!(res.is_ok(), res.unwrap_err()); + assert_eq!(res.unwrap(), "\\E[31m".bytes().collect::<Vec<_>>()); + let res = expand(s, &[Number(8)], &mut vars); + assert!(res.is_ok(), res.unwrap_err()); + assert_eq!(res.unwrap(), "\\E[90m".bytes().collect::<Vec<_>>()); + let res = expand(s, &[Number(42)], &mut vars); + assert!(res.is_ok(), res.unwrap_err()); + assert_eq!(res.unwrap(), "\\E[38;5;42m".bytes().collect::<Vec<_>>()); + } + + #[test] + fn test_format() { + let mut varstruct = Variables::new(); + let vars = &mut varstruct; + assert_eq!(expand(b"%p1%s%p2%2s%p3%2s%p4%.2s", + &[Words("foo".to_string()), + Words("foo".to_string()), + Words("f".to_string()), + Words("foo".to_string())], + vars), + Ok("foofoo ffo".bytes().collect::<Vec<_>>())); + assert_eq!(expand(b"%p1%:-4.2s", &[Words("foo".to_string())], vars), + Ok("fo ".bytes().collect::<Vec<_>>())); + + assert_eq!(expand(b"%p1%d%p1%.3d%p1%5d%p1%:+d", &[Number(1)], vars), + Ok("1001 1+1".bytes().collect::<Vec<_>>())); + assert_eq!(expand(b"%p1%o%p1%#o%p2%6.4x%p2%#6.4X", + &[Number(15), Number(27)], + vars), + Ok("17017 001b0X001B".bytes().collect::<Vec<_>>())); + } +} diff --git a/src/libterm/terminfo/parser/compiled.rs b/src/libterm/terminfo/parser/compiled.rs new file mode 100644 index 00000000000..05a8c9420ed --- /dev/null +++ b/src/libterm/terminfo/parser/compiled.rs @@ -0,0 +1,346 @@ +#![allow(non_upper_case_globals, missing_docs)] + +//! ncurses-compatible compiled terminfo format parsing (term(5)) + +use std::collections::HashMap; +use std::io; +use std::io::prelude::*; +use super::super::TermInfo; + +// These are the orders ncurses uses in its compiled format (as of 5.9). Not sure if portable. + +#[rustfmt::skip] +pub static boolfnames: &[&str] = &["auto_left_margin", "auto_right_margin", + "no_esc_ctlc", "ceol_standout_glitch", "eat_newline_glitch", "erase_overstrike", "generic_type", + "hard_copy", "has_meta_key", "has_status_line", "insert_null_glitch", "memory_above", + "memory_below", "move_insert_mode", "move_standout_mode", "over_strike", "status_line_esc_ok", + "dest_tabs_magic_smso", "tilde_glitch", "transparent_underline", "xon_xoff", "needs_xon_xoff", + "prtr_silent", "hard_cursor", "non_rev_rmcup", "no_pad_char", "non_dest_scroll_region", + "can_change", "back_color_erase", "hue_lightness_saturation", "col_addr_glitch", + "cr_cancels_micro_mode", "has_print_wheel", "row_addr_glitch", "semi_auto_right_margin", + "cpi_changes_res", "lpi_changes_res", "backspaces_with_bs", "crt_no_scrolling", + "no_correctly_working_cr", "gnu_has_meta_key", "linefeed_is_newline", "has_hardware_tabs", + "return_does_clr_eol"]; + +#[rustfmt::skip] +pub static boolnames: &[&str] = &["bw", "am", "xsb", "xhp", "xenl", "eo", + "gn", "hc", "km", "hs", "in", "db", "da", "mir", "msgr", "os", "eslok", "xt", "hz", "ul", "xon", + "nxon", "mc5i", "chts", "nrrmc", "npc", "ndscr", "ccc", "bce", "hls", "xhpa", "crxm", "daisy", + "xvpa", "sam", "cpix", "lpix", "OTbs", "OTns", "OTnc", "OTMT", "OTNL", "OTpt", "OTxr"]; + +#[rustfmt::skip] +pub static numfnames: &[&str] = &[ "columns", "init_tabs", "lines", + "lines_of_memory", "magic_cookie_glitch", "padding_baud_rate", "virtual_terminal", + "width_status_line", "num_labels", "label_height", "label_width", "max_attributes", + "maximum_windows", "max_colors", "max_pairs", "no_color_video", "buffer_capacity", + "dot_vert_spacing", "dot_horz_spacing", "max_micro_address", "max_micro_jump", "micro_col_size", + "micro_line_size", "number_of_pins", "output_res_char", "output_res_line", + "output_res_horz_inch", "output_res_vert_inch", "print_rate", "wide_char_size", "buttons", + "bit_image_entwining", "bit_image_type", "magic_cookie_glitch_ul", "carriage_return_delay", + "new_line_delay", "backspace_delay", "horizontal_tab_delay", "number_of_function_keys"]; + +#[rustfmt::skip] +pub static numnames: &[&str] = &[ "cols", "it", "lines", "lm", "xmc", "pb", + "vt", "wsl", "nlab", "lh", "lw", "ma", "wnum", "colors", "pairs", "ncv", "bufsz", "spinv", + "spinh", "maddr", "mjump", "mcs", "mls", "npins", "orc", "orl", "orhi", "orvi", "cps", "widcs", + "btns", "bitwin", "bitype", "UTug", "OTdC", "OTdN", "OTdB", "OTdT", "OTkn"]; + +#[rustfmt::skip] +pub static stringfnames: &[&str] = &[ "back_tab", "bell", "carriage_return", + "change_scroll_region", "clear_all_tabs", "clear_screen", "clr_eol", "clr_eos", + "column_address", "command_character", "cursor_address", "cursor_down", "cursor_home", + "cursor_invisible", "cursor_left", "cursor_mem_address", "cursor_normal", "cursor_right", + "cursor_to_ll", "cursor_up", "cursor_visible", "delete_character", "delete_line", + "dis_status_line", "down_half_line", "enter_alt_charset_mode", "enter_blink_mode", + "enter_bold_mode", "enter_ca_mode", "enter_delete_mode", "enter_dim_mode", "enter_insert_mode", + "enter_secure_mode", "enter_protected_mode", "enter_reverse_mode", "enter_standout_mode", + "enter_underline_mode", "erase_chars", "exit_alt_charset_mode", "exit_attribute_mode", + "exit_ca_mode", "exit_delete_mode", "exit_insert_mode", "exit_standout_mode", + "exit_underline_mode", "flash_screen", "form_feed", "from_status_line", "init_1string", + "init_2string", "init_3string", "init_file", "insert_character", "insert_line", + "insert_padding", "key_backspace", "key_catab", "key_clear", "key_ctab", "key_dc", "key_dl", + "key_down", "key_eic", "key_eol", "key_eos", "key_f0", "key_f1", "key_f10", "key_f2", "key_f3", + "key_f4", "key_f5", "key_f6", "key_f7", "key_f8", "key_f9", "key_home", "key_ic", "key_il", + "key_left", "key_ll", "key_npage", "key_ppage", "key_right", "key_sf", "key_sr", "key_stab", + "key_up", "keypad_local", "keypad_xmit", "lab_f0", "lab_f1", "lab_f10", "lab_f2", "lab_f3", + "lab_f4", "lab_f5", "lab_f6", "lab_f7", "lab_f8", "lab_f9", "meta_off", "meta_on", "newline", + "pad_char", "parm_dch", "parm_delete_line", "parm_down_cursor", "parm_ich", "parm_index", + "parm_insert_line", "parm_left_cursor", "parm_right_cursor", "parm_rindex", "parm_up_cursor", + "pkey_key", "pkey_local", "pkey_xmit", "print_screen", "prtr_off", "prtr_on", "repeat_char", + "reset_1string", "reset_2string", "reset_3string", "reset_file", "restore_cursor", + "row_address", "save_cursor", "scroll_forward", "scroll_reverse", "set_attributes", "set_tab", + "set_window", "tab", "to_status_line", "underline_char", "up_half_line", "init_prog", "key_a1", + "key_a3", "key_b2", "key_c1", "key_c3", "prtr_non", "char_padding", "acs_chars", "plab_norm", + "key_btab", "enter_xon_mode", "exit_xon_mode", "enter_am_mode", "exit_am_mode", "xon_character", + "xoff_character", "ena_acs", "label_on", "label_off", "key_beg", "key_cancel", "key_close", + "key_command", "key_copy", "key_create", "key_end", "key_enter", "key_exit", "key_find", + "key_help", "key_mark", "key_message", "key_move", "key_next", "key_open", "key_options", + "key_previous", "key_print", "key_redo", "key_reference", "key_refresh", "key_replace", + "key_restart", "key_resume", "key_save", "key_suspend", "key_undo", "key_sbeg", "key_scancel", + "key_scommand", "key_scopy", "key_screate", "key_sdc", "key_sdl", "key_select", "key_send", + "key_seol", "key_sexit", "key_sfind", "key_shelp", "key_shome", "key_sic", "key_sleft", + "key_smessage", "key_smove", "key_snext", "key_soptions", "key_sprevious", "key_sprint", + "key_sredo", "key_sreplace", "key_sright", "key_srsume", "key_ssave", "key_ssuspend", + "key_sundo", "req_for_input", "key_f11", "key_f12", "key_f13", "key_f14", "key_f15", "key_f16", + "key_f17", "key_f18", "key_f19", "key_f20", "key_f21", "key_f22", "key_f23", "key_f24", + "key_f25", "key_f26", "key_f27", "key_f28", "key_f29", "key_f30", "key_f31", "key_f32", + "key_f33", "key_f34", "key_f35", "key_f36", "key_f37", "key_f38", "key_f39", "key_f40", + "key_f41", "key_f42", "key_f43", "key_f44", "key_f45", "key_f46", "key_f47", "key_f48", + "key_f49", "key_f50", "key_f51", "key_f52", "key_f53", "key_f54", "key_f55", "key_f56", + "key_f57", "key_f58", "key_f59", "key_f60", "key_f61", "key_f62", "key_f63", "clr_bol", + "clear_margins", "set_left_margin", "set_right_margin", "label_format", "set_clock", + "display_clock", "remove_clock", "create_window", "goto_window", "hangup", "dial_phone", + "quick_dial", "tone", "pulse", "flash_hook", "fixed_pause", "wait_tone", "user0", "user1", + "user2", "user3", "user4", "user5", "user6", "user7", "user8", "user9", "orig_pair", + "orig_colors", "initialize_color", "initialize_pair", "set_color_pair", "set_foreground", + "set_background", "change_char_pitch", "change_line_pitch", "change_res_horz", + "change_res_vert", "define_char", "enter_doublewide_mode", "enter_draft_quality", + "enter_italics_mode", "enter_leftward_mode", "enter_micro_mode", "enter_near_letter_quality", + "enter_normal_quality", "enter_shadow_mode", "enter_subscript_mode", "enter_superscript_mode", + "enter_upward_mode", "exit_doublewide_mode", "exit_italics_mode", "exit_leftward_mode", + "exit_micro_mode", "exit_shadow_mode", "exit_subscript_mode", "exit_superscript_mode", + "exit_upward_mode", "micro_column_address", "micro_down", "micro_left", "micro_right", + "micro_row_address", "micro_up", "order_of_pins", "parm_down_micro", "parm_left_micro", + "parm_right_micro", "parm_up_micro", "select_char_set", "set_bottom_margin", + "set_bottom_margin_parm", "set_left_margin_parm", "set_right_margin_parm", "set_top_margin", + "set_top_margin_parm", "start_bit_image", "start_char_set_def", "stop_bit_image", + "stop_char_set_def", "subscript_characters", "superscript_characters", "these_cause_cr", + "zero_motion", "char_set_names", "key_mouse", "mouse_info", "req_mouse_pos", "get_mouse", + "set_a_foreground", "set_a_background", "pkey_plab", "device_type", "code_set_init", + "set0_des_seq", "set1_des_seq", "set2_des_seq", "set3_des_seq", "set_lr_margin", + "set_tb_margin", "bit_image_repeat", "bit_image_newline", "bit_image_carriage_return", + "color_names", "define_bit_image_region", "end_bit_image_region", "set_color_band", + "set_page_length", "display_pc_char", "enter_pc_charset_mode", "exit_pc_charset_mode", + "enter_scancode_mode", "exit_scancode_mode", "pc_term_options", "scancode_escape", + "alt_scancode_esc", "enter_horizontal_hl_mode", "enter_left_hl_mode", "enter_low_hl_mode", + "enter_right_hl_mode", "enter_top_hl_mode", "enter_vertical_hl_mode", "set_a_attributes", + "set_pglen_inch", "termcap_init2", "termcap_reset", "linefeed_if_not_lf", "backspace_if_not_bs", + "other_non_function_keys", "arrow_key_map", "acs_ulcorner", "acs_llcorner", "acs_urcorner", + "acs_lrcorner", "acs_ltee", "acs_rtee", "acs_btee", "acs_ttee", "acs_hline", "acs_vline", + "acs_plus", "memory_lock", "memory_unlock", "box_chars_1"]; + +#[rustfmt::skip] +pub static stringnames: &[&str] = &[ "cbt", "_", "cr", "csr", "tbc", "clear", + "_", "_", "hpa", "cmdch", "cup", "cud1", "home", "civis", "cub1", "mrcup", "cnorm", "cuf1", + "ll", "cuu1", "cvvis", "dch1", "dl1", "dsl", "hd", "smacs", "blink", "bold", "smcup", "smdc", + "dim", "smir", "invis", "prot", "rev", "smso", "smul", "ech", "rmacs", "sgr0", "rmcup", "rmdc", + "rmir", "rmso", "rmul", "flash", "ff", "fsl", "is1", "is2", "is3", "if", "ich1", "il1", "ip", + "kbs", "ktbc", "kclr", "kctab", "_", "_", "kcud1", "_", "_", "_", "_", "_", "_", "_", "_", "_", + "_", "_", "_", "_", "_", "khome", "_", "_", "kcub1", "_", "knp", "kpp", "kcuf1", "_", "_", + "khts", "_", "rmkx", "smkx", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "rmm", "_", + "_", "pad", "dch", "dl", "cud", "ich", "indn", "il", "cub", "cuf", "rin", "cuu", "pfkey", + "pfloc", "pfx", "mc0", "mc4", "_", "rep", "rs1", "rs2", "rs3", "rf", "rc", "vpa", "sc", "ind", + "ri", "sgr", "_", "wind", "_", "tsl", "uc", "hu", "iprog", "_", "_", "_", "_", "_", "mc5p", + "rmp", "acsc", "pln", "kcbt", "smxon", "rmxon", "smam", "rmam", "xonc", "xoffc", "_", "smln", + "rmln", "_", "kcan", "kclo", "kcmd", "kcpy", "kcrt", "_", "kent", "kext", "kfnd", "khlp", + "kmrk", "kmsg", "kmov", "knxt", "kopn", "kopt", "kprv", "kprt", "krdo", "kref", "krfr", "krpl", + "krst", "kres", "ksav", "kspd", "kund", "kBEG", "kCAN", "kCMD", "kCPY", "kCRT", "_", "_", + "kslt", "kEND", "kEOL", "kEXT", "kFND", "kHLP", "kHOM", "_", "kLFT", "kMSG", "kMOV", "kNXT", + "kOPT", "kPRV", "kPRT", "kRDO", "kRPL", "kRIT", "kRES", "kSAV", "kSPD", "kUND", "rfi", "_", "_", + "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", + "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", + "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", + "dclk", "rmclk", "cwin", "wingo", "_", "dial", "qdial", "_", "_", "hook", "pause", "wait", "_", + "_", "_", "_", "_", "_", "_", "_", "_", "_", "op", "oc", "initc", "initp", "scp", "setf", + "setb", "cpi", "lpi", "chr", "cvr", "defc", "swidm", "sdrfq", "sitm", "slm", "smicm", "snlq", + "snrmq", "sshm", "ssubm", "ssupm", "sum", "rwidm", "ritm", "rlm", "rmicm", "rshm", "rsubm", + "rsupm", "rum", "mhpa", "mcud1", "mcub1", "mcuf1", "mvpa", "mcuu1", "porder", "mcud", "mcub", + "mcuf", "mcuu", "scs", "smgb", "smgbp", "smglp", "smgrp", "smgt", "smgtp", "sbim", "scsd", + "rbim", "rcsd", "subcs", "supcs", "docr", "zerom", "csnm", "kmous", "minfo", "reqmp", "getm", + "setaf", "setab", "pfxl", "devt", "csin", "s0ds", "s1ds", "s2ds", "s3ds", "smglr", "smgtb", + "birep", "binel", "bicr", "colornm", "defbi", "endbi", "setcolor", "slines", "dispc", "smpch", + "rmpch", "smsc", "rmsc", "pctrm", "scesc", "scesa", "ehhlm", "elhlm", "elohlm", "erhlm", + "ethlm", "evhlm", "sgr1", "slength", "OTi2", "OTrs", "OTnl", "OTbs", "OTko", "OTma", "OTG2", + "OTG3", "OTG1", "OTG4", "OTGR", "OTGL", "OTGU", "OTGD", "OTGH", "OTGV", "OTGC", "meml", "memu", + "box1"]; + +fn read_le_u16(r: &mut dyn io::Read) -> io::Result<u16> { + let mut b = [0; 2]; + let mut amt = 0; + while amt < b.len() { + match r.read(&mut b[amt..])? { + 0 => return Err(io::Error::new(io::ErrorKind::Other, "end of file")), + n => amt += n, + } + } + Ok((b[0] as u16) | ((b[1] as u16) << 8)) +} + +fn read_byte(r: &mut dyn io::Read) -> io::Result<u8> { + match r.bytes().next() { + Some(s) => s, + None => Err(io::Error::new(io::ErrorKind::Other, "end of file")), + } +} + +/// Parse a compiled terminfo entry, using long capability names if `longnames` +/// is true +pub fn parse(file: &mut dyn io::Read, longnames: bool) -> Result<TermInfo, String> { + macro_rules! t( ($e:expr) => ( + match $e { + Ok(e) => e, + Err(e) => return Err(e.to_string()) + } + ) ); + + let (bnames, snames, nnames) = if longnames { + (boolfnames, stringfnames, numfnames) + } else { + (boolnames, stringnames, numnames) + }; + + // Check magic number + let magic = t!(read_le_u16(file)); + if magic != 0x011A { + return Err(format!("invalid magic number: expected {:x}, found {:x}", + 0x011A, + magic)); + } + + // According to the spec, these fields must be >= -1 where -1 means that the feature is not + // supported. Using 0 instead of -1 works because we skip sections with length 0. + macro_rules! read_nonneg { + () => {{ + match t!(read_le_u16(file)) as i16 { + n if n >= 0 => n as usize, + -1 => 0, + _ => return Err("incompatible file: length fields must be >= -1".to_string()), + } + }} + } + + let names_bytes = read_nonneg!(); + let bools_bytes = read_nonneg!(); + let numbers_count = read_nonneg!(); + let string_offsets_count = read_nonneg!(); + let string_table_bytes = read_nonneg!(); + + if names_bytes == 0 { + return Err("incompatible file: names field must be at least 1 byte wide".to_string()); + } + + if bools_bytes > boolnames.len() { + return Err("incompatible file: more booleans than expected".to_string()); + } + + if numbers_count > numnames.len() { + return Err("incompatible file: more numbers than expected".to_string()); + } + + if string_offsets_count > stringnames.len() { + return Err("incompatible file: more string offsets than expected".to_string()); + } + + // don't read NUL + let mut bytes = Vec::new(); + t!(file.take((names_bytes - 1) as u64).read_to_end(&mut bytes)); + let names_str = match String::from_utf8(bytes) { + Ok(s) => s, + Err(_) => return Err("input not utf-8".to_string()), + }; + + let term_names: Vec<String> = names_str.split('|') + .map(|s| s.to_string()) + .collect(); + // consume NUL + if t!(read_byte(file)) != b'\0' { + return Err("incompatible file: missing null terminator for names section".to_string()); + } + + let bools_map: HashMap<String, bool> = t! { + (0..bools_bytes).filter_map(|i| match read_byte(file) { + Err(e) => Some(Err(e)), + Ok(1) => Some(Ok((bnames[i].to_string(), true))), + Ok(_) => None + }).collect() + }; + + if (bools_bytes + names_bytes) % 2 == 1 { + t!(read_byte(file)); // compensate for padding + } + + let numbers_map: HashMap<String, u16> = t! { + (0..numbers_count).filter_map(|i| match read_le_u16(file) { + Ok(0xFFFF) => None, + Ok(n) => Some(Ok((nnames[i].to_string(), n))), + Err(e) => Some(Err(e)) + }).collect() + }; + + let string_map: HashMap<String, Vec<u8>> = if string_offsets_count > 0 { + let string_offsets: Vec<u16> = t!((0..string_offsets_count) + .map(|_| read_le_u16(file)) + .collect()); + + let mut string_table = Vec::new(); + t!(file.take(string_table_bytes as u64).read_to_end(&mut string_table)); + + t!(string_offsets.into_iter().enumerate().filter(|&(_, offset)| { + // non-entry + offset != 0xFFFF + }).map(|(i, offset)| { + let offset = offset as usize; + + let name = if snames[i] == "_" { + stringfnames[i] + } else { + snames[i] + }; + + if offset == 0xFFFE { + // undocumented: FFFE indicates cap@, which means the capability is not present + // unsure if the handling for this is correct + return Ok((name.to_string(), Vec::new())); + } + + // Find the offset of the NUL we want to go to + let nulpos = string_table[offset..string_table_bytes].iter().position(|&b| b == 0); + match nulpos { + Some(len) => Ok((name.to_string(), string_table[offset..offset + len].to_vec())), + None => Err("invalid file: missing NUL in string_table".to_string()), + } + }).collect()) + } else { + HashMap::new() + }; + + // And that's all there is to it + Ok(TermInfo { + names: term_names, + bools: bools_map, + numbers: numbers_map, + strings: string_map, + }) +} + +/// Creates a dummy TermInfo struct for msys terminals +pub fn msys_terminfo() -> TermInfo { + let mut strings = HashMap::new(); + strings.insert("sgr0".to_string(), b"\x1B[0m".to_vec()); + strings.insert("bold".to_string(), b"\x1B[1m".to_vec()); + strings.insert("setaf".to_string(), b"\x1B[3%p1%dm".to_vec()); + strings.insert("setab".to_string(), b"\x1B[4%p1%dm".to_vec()); + + let mut numbers = HashMap::new(); + numbers.insert("colors".to_string(), 8u16); + + TermInfo { + names: vec!["cygwin".to_string()], // msys is a fork of an older cygwin version + bools: HashMap::new(), + numbers, + strings, + } +} + +#[cfg(test)] +mod test { + + use super::{boolnames, boolfnames, numnames, numfnames, stringnames, stringfnames}; + + #[test] + fn test_veclens() { + assert_eq!(boolfnames.len(), boolnames.len()); + assert_eq!(numfnames.len(), numnames.len()); + assert_eq!(stringfnames.len(), stringnames.len()); + } +} diff --git a/src/libterm/terminfo/searcher.rs b/src/libterm/terminfo/searcher.rs new file mode 100644 index 00000000000..0b17ed36fc8 --- /dev/null +++ b/src/libterm/terminfo/searcher.rs @@ -0,0 +1,84 @@ +//! ncurses-compatible database discovery. +//! +//! Does not support hashed database, only filesystem! + +use std::env; +use std::fs; +use std::path::PathBuf; + +/// Return path to database entry for `term` +#[allow(deprecated)] +pub fn get_dbpath_for_term(term: &str) -> Option<PathBuf> { + let mut dirs_to_search = Vec::new(); + let first_char = term.chars().next()?; + + // Find search directory + if let Some(dir) = env::var_os("TERMINFO") { + dirs_to_search.push(PathBuf::from(dir)); + } + + if let Ok(dirs) = env::var("TERMINFO_DIRS") { + for i in dirs.split(':') { + if i == "" { + dirs_to_search.push(PathBuf::from("/usr/share/terminfo")); + } else { + dirs_to_search.push(PathBuf::from(i)); + } + } + } else { + // Found nothing in TERMINFO_DIRS, use the default paths: + // According to /etc/terminfo/README, after looking at + // ~/.terminfo, ncurses will search /etc/terminfo, then + // /lib/terminfo, and eventually /usr/share/terminfo. + // On Haiku the database can be found at /boot/system/data/terminfo + if let Some(mut homedir) = env::home_dir() { + homedir.push(".terminfo"); + dirs_to_search.push(homedir) + } + + dirs_to_search.push(PathBuf::from("/etc/terminfo")); + dirs_to_search.push(PathBuf::from("/lib/terminfo")); + dirs_to_search.push(PathBuf::from("/usr/share/terminfo")); + dirs_to_search.push(PathBuf::from("/boot/system/data/terminfo")); + } + + // Look for the terminal in all of the search directories + for mut p in dirs_to_search { + if fs::metadata(&p).is_ok() { + p.push(&first_char.to_string()); + p.push(&term); + if fs::metadata(&p).is_ok() { + return Some(p); + } + p.pop(); + p.pop(); + + // on some installations the dir is named after the hex of the char + // (e.g., macOS) + p.push(&format!("{:x}", first_char as usize)); + p.push(term); + if fs::metadata(&p).is_ok() { + return Some(p); + } + } + } + None +} + +#[test] +#[ignore = "buildbots don't have ncurses installed and I can't mock everything I need"] +fn test_get_dbpath_for_term() { + // woefully inadequate test coverage + // note: current tests won't work with non-standard terminfo hierarchies (e.g., macOS's) + use std::env; + // FIXME (#9639): This needs to handle non-utf8 paths + fn x(t: &str) -> String { + let p = get_dbpath_for_term(t).expect("no terminfo entry found"); + p.to_str().unwrap().to_string() + } + assert!(x("screen") == "/usr/share/terminfo/s/screen"); + assert!(get_dbpath_for_term("") == None); + env::set_var("TERMINFO_DIRS", ":"); + assert!(x("screen") == "/usr/share/terminfo/s/screen"); + env::remove_var("TERMINFO_DIRS"); +} diff --git a/src/libterm/win.rs b/src/libterm/win.rs new file mode 100644 index 00000000000..6d42b01337e --- /dev/null +++ b/src/libterm/win.rs @@ -0,0 +1,203 @@ +//! Windows console handling + +// FIXME (#13400): this is only a tiny fraction of the Windows console api + +extern crate libc; + +use std::io; +use std::io::prelude::*; + +use crate::Attr; +use crate::color; +use crate::Terminal; + +/// A Terminal implementation that uses the Win32 Console API. +pub struct WinConsole<T> { + buf: T, + def_foreground: color::Color, + def_background: color::Color, + foreground: color::Color, + background: color::Color, +} + +type WORD = u16; +type DWORD = u32; +type BOOL = i32; +type HANDLE = *mut u8; + +#[allow(non_snake_case)] +#[repr(C)] +struct CONSOLE_SCREEN_BUFFER_INFO { + dwSize: [libc::c_short; 2], + dwCursorPosition: [libc::c_short; 2], + wAttributes: WORD, + srWindow: [libc::c_short; 4], + dwMaximumWindowSize: [libc::c_short; 2], +} + +#[allow(non_snake_case)] +#[link(name = "kernel32")] +extern "system" { + fn SetConsoleTextAttribute(handle: HANDLE, attr: WORD) -> BOOL; + fn GetStdHandle(which: DWORD) -> HANDLE; + fn GetConsoleScreenBufferInfo(handle: HANDLE, info: *mut CONSOLE_SCREEN_BUFFER_INFO) -> BOOL; +} + +fn color_to_bits(color: color::Color) -> u16 { + // magic numbers from mingw-w64's wincon.h + + let bits = match color % 8 { + color::BLACK => 0, + color::BLUE => 0x1, + color::GREEN => 0x2, + color::RED => 0x4, + color::YELLOW => 0x2 | 0x4, + color::MAGENTA => 0x1 | 0x4, + color::CYAN => 0x1 | 0x2, + color::WHITE => 0x1 | 0x2 | 0x4, + _ => unreachable!(), + }; + + if color >= 8 { + bits | 0x8 + } else { + bits + } +} + +fn bits_to_color(bits: u16) -> color::Color { + let color = match bits & 0x7 { + 0 => color::BLACK, + 0x1 => color::BLUE, + 0x2 => color::GREEN, + 0x4 => color::RED, + 0x6 => color::YELLOW, + 0x5 => color::MAGENTA, + 0x3 => color::CYAN, + 0x7 => color::WHITE, + _ => unreachable!(), + }; + + color | (bits & 0x8) // copy the hi-intensity bit +} + +impl<T: Write + Send + 'static> WinConsole<T> { + fn apply(&mut self) { + let _unused = self.buf.flush(); + let mut accum: WORD = 0; + accum |= color_to_bits(self.foreground); + accum |= color_to_bits(self.background) << 4; + + unsafe { + // Magic -11 means stdout, from + // http://msdn.microsoft.com/en-us/library/windows/desktop/ms683231%28v=vs.85%29.aspx + // + // You may be wondering, "but what about stderr?", and the answer + // to that is that setting terminal attributes on the stdout + // handle also sets them for stderr, since they go to the same + // terminal! Admittedly, this is fragile, since stderr could be + // redirected to a different console. This is good enough for + // rustc though. See #13400. + let out = GetStdHandle(-11i32 as DWORD); + SetConsoleTextAttribute(out, accum); + } + } + + /// Returns `None` whenever the terminal cannot be created for some reason. + pub fn new(out: T) -> io::Result<WinConsole<T>> { + let fg; + let bg; + unsafe { + let mut buffer_info = ::std::mem::uninitialized(); + if GetConsoleScreenBufferInfo(GetStdHandle(-11i32 as DWORD), &mut buffer_info) != 0 { + fg = bits_to_color(buffer_info.wAttributes); + bg = bits_to_color(buffer_info.wAttributes >> 4); + } else { + fg = color::WHITE; + bg = color::BLACK; + } + } + Ok(WinConsole { + buf: out, + def_foreground: fg, + def_background: bg, + foreground: fg, + background: bg, + }) + } +} + +impl<T: Write> Write for WinConsole<T> { + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + self.buf.write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.buf.flush() + } +} + +impl<T: Write + Send + 'static> Terminal for WinConsole<T> { + type Output = T; + + fn fg(&mut self, color: color::Color) -> io::Result<bool> { + self.foreground = color; + self.apply(); + + Ok(true) + } + + fn bg(&mut self, color: color::Color) -> io::Result<bool> { + self.background = color; + self.apply(); + + Ok(true) + } + + fn attr(&mut self, attr: Attr) -> io::Result<bool> { + match attr { + Attr::ForegroundColor(f) => { + self.foreground = f; + self.apply(); + Ok(true) + } + Attr::BackgroundColor(b) => { + self.background = b; + self.apply(); + Ok(true) + } + _ => Ok(false), + } + } + + fn supports_attr(&self, attr: Attr) -> bool { + // it claims support for underscore and reverse video, but I can't get + // it to do anything -cmr + match attr { + Attr::ForegroundColor(_) | Attr::BackgroundColor(_) => true, + _ => false, + } + } + + fn reset(&mut self) -> io::Result<bool> { + self.foreground = self.def_foreground; + self.background = self.def_background; + self.apply(); + + Ok(true) + } + + fn get_ref(&self) -> &T { + &self.buf + } + + fn get_mut(&mut self) -> &mut T { + &mut self.buf + } + + fn into_inner(self) -> T + where Self: Sized + { + self.buf + } +} diff --git a/src/libtest/Cargo.toml b/src/libtest/Cargo.toml index 26ac7888184..10bdd6e877c 100644 --- a/src/libtest/Cargo.toml +++ b/src/libtest/Cargo.toml @@ -10,7 +10,8 @@ path = "lib.rs" crate-type = ["dylib", "rlib"] [dependencies] -libtest = { version = "0.0.1" } +getopts = "0.2" +term = { path = "../libterm" } # not actually used but needed to always have proc_macro in the sysroot proc_macro = { path = "../libproc_macro" } diff --git a/src/libtest/README.md b/src/libtest/README.md deleted file mode 100644 index 6d9fe30dcad..00000000000 --- a/src/libtest/README.md +++ /dev/null @@ -1,13 +0,0 @@ -WIP - stable libtest -=== - -The migration of libtest to stable Rust is currently in progress. - -You can find libtest at: https://github.com/rust-lang/libtest . If you need to -make a change: - -* perform the change there, -* do a new crates.io release, and -* send a PR to rust-lang/rust bumping the libtest version. - -The roadmap of the migration is being tracked here: https://github.com/rust-lang/libtest/issues/2 diff --git a/src/libtest/formatters/json.rs b/src/libtest/formatters/json.rs new file mode 100644 index 00000000000..a06497f9862 --- /dev/null +++ b/src/libtest/formatters/json.rs @@ -0,0 +1,208 @@ +use super::*; + +pub(crate) struct JsonFormatter<T> { + out: OutputLocation<T>, +} + +impl<T: Write> JsonFormatter<T> { + pub fn new(out: OutputLocation<T>) -> Self { + Self { out } + } + + fn write_message(&mut self, s: &str) -> io::Result<()> { + assert!(!s.contains('\n')); + + self.out.write_all(s.as_ref())?; + self.out.write_all(b"\n") + } + + fn write_event( + &mut self, + ty: &str, + name: &str, + evt: &str, + extra: Option<String>, + ) -> io::Result<()> { + if let Some(extras) = extra { + self.write_message(&*format!( + r#"{{ "type": "{}", "name": "{}", "event": "{}", {} }}"#, + ty, name, evt, extras + )) + } else { + self.write_message(&*format!( + r#"{{ "type": "{}", "name": "{}", "event": "{}" }}"#, + ty, name, evt + )) + } + } +} + +impl<T: Write> OutputFormatter for JsonFormatter<T> { + fn write_run_start(&mut self, test_count: usize) -> io::Result<()> { + self.write_message(&*format!( + r#"{{ "type": "suite", "event": "started", "test_count": {} }}"#, + test_count + )) + } + + fn write_test_start(&mut self, desc: &TestDesc) -> io::Result<()> { + self.write_message(&*format!( + r#"{{ "type": "test", "event": "started", "name": "{}" }}"#, + desc.name + )) + } + + fn write_result( + &mut self, + desc: &TestDesc, + result: &TestResult, + stdout: &[u8], + ) -> io::Result<()> { + match *result { + TrOk => self.write_event("test", desc.name.as_slice(), "ok", None), + + TrFailed => { + let extra_data = if stdout.len() > 0 { + Some(format!( + r#""stdout": "{}""#, + EscapedString(String::from_utf8_lossy(stdout)) + )) + } else { + None + }; + + self.write_event("test", desc.name.as_slice(), "failed", extra_data) + } + + TrFailedMsg(ref m) => self.write_event( + "test", + desc.name.as_slice(), + "failed", + Some(format!(r#""message": "{}""#, EscapedString(m))), + ), + + TrIgnored => self.write_event("test", desc.name.as_slice(), "ignored", None), + + TrAllowedFail => { + self.write_event("test", desc.name.as_slice(), "allowed_failure", None) + } + + TrBench(ref bs) => { + let median = bs.ns_iter_summ.median as usize; + let deviation = (bs.ns_iter_summ.max - bs.ns_iter_summ.min) as usize; + + let mbps = if bs.mb_s == 0 { + String::new() + } else { + format!(r#", "mib_per_second": {}"#, bs.mb_s) + }; + + let line = format!( + "{{ \"type\": \"bench\", \ + \"name\": \"{}\", \ + \"median\": {}, \ + \"deviation\": {}{} }}", + desc.name, median, deviation, mbps + ); + + self.write_message(&*line) + } + } + } + + fn write_timeout(&mut self, desc: &TestDesc) -> io::Result<()> { + self.write_message(&*format!( + r#"{{ "type": "test", "event": "timeout", "name": "{}" }}"#, + desc.name + )) + } + + fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result<bool> { + self.write_message(&*format!( + "{{ \"type\": \"suite\", \ + \"event\": \"{}\", \ + \"passed\": {}, \ + \"failed\": {}, \ + \"allowed_fail\": {}, \ + \"ignored\": {}, \ + \"measured\": {}, \ + \"filtered_out\": {} }}", + if state.failed == 0 { "ok" } else { "failed" }, + state.passed, + state.failed + state.allowed_fail, + state.allowed_fail, + state.ignored, + state.measured, + state.filtered_out + ))?; + + Ok(state.failed == 0) + } +} + +/// A formatting utility used to print strings with characters in need of escaping. +/// Base code taken form `libserialize::json::escape_str` +struct EscapedString<S: AsRef<str>>(S); + +impl<S: AsRef<str>> ::std::fmt::Display for EscapedString<S> { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + let mut start = 0; + + for (i, byte) in self.0.as_ref().bytes().enumerate() { + let escaped = match byte { + b'"' => "\\\"", + b'\\' => "\\\\", + b'\x00' => "\\u0000", + b'\x01' => "\\u0001", + b'\x02' => "\\u0002", + b'\x03' => "\\u0003", + b'\x04' => "\\u0004", + b'\x05' => "\\u0005", + b'\x06' => "\\u0006", + b'\x07' => "\\u0007", + b'\x08' => "\\b", + b'\t' => "\\t", + b'\n' => "\\n", + b'\x0b' => "\\u000b", + b'\x0c' => "\\f", + b'\r' => "\\r", + b'\x0e' => "\\u000e", + b'\x0f' => "\\u000f", + b'\x10' => "\\u0010", + b'\x11' => "\\u0011", + b'\x12' => "\\u0012", + b'\x13' => "\\u0013", + b'\x14' => "\\u0014", + b'\x15' => "\\u0015", + b'\x16' => "\\u0016", + b'\x17' => "\\u0017", + b'\x18' => "\\u0018", + b'\x19' => "\\u0019", + b'\x1a' => "\\u001a", + b'\x1b' => "\\u001b", + b'\x1c' => "\\u001c", + b'\x1d' => "\\u001d", + b'\x1e' => "\\u001e", + b'\x1f' => "\\u001f", + b'\x7f' => "\\u007f", + _ => { + continue; + } + }; + + if start < i { + f.write_str(&self.0.as_ref()[start..i])?; + } + + f.write_str(escaped)?; + + start = i + 1; + } + + if start != self.0.as_ref().len() { + f.write_str(&self.0.as_ref()[start..])?; + } + + Ok(()) + } +} diff --git a/src/libtest/formatters/mod.rs b/src/libtest/formatters/mod.rs new file mode 100644 index 00000000000..be5f6a65039 --- /dev/null +++ b/src/libtest/formatters/mod.rs @@ -0,0 +1,22 @@ +use super::*; + +mod pretty; +mod json; +mod terse; + +pub(crate) use self::pretty::PrettyFormatter; +pub(crate) use self::json::JsonFormatter; +pub(crate) use self::terse::TerseFormatter; + +pub(crate) trait OutputFormatter { + fn write_run_start(&mut self, test_count: usize) -> io::Result<()>; + fn write_test_start(&mut self, desc: &TestDesc) -> io::Result<()>; + fn write_timeout(&mut self, desc: &TestDesc) -> io::Result<()>; + fn write_result( + &mut self, + desc: &TestDesc, + result: &TestResult, + stdout: &[u8], + ) -> io::Result<()>; + fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result<bool>; +} diff --git a/src/libtest/formatters/pretty.rs b/src/libtest/formatters/pretty.rs new file mode 100644 index 00000000000..4af00428ca8 --- /dev/null +++ b/src/libtest/formatters/pretty.rs @@ -0,0 +1,232 @@ +use super::*; + +pub(crate) struct PrettyFormatter<T> { + out: OutputLocation<T>, + use_color: bool, + + /// Number of columns to fill when aligning names + max_name_len: usize, + + is_multithreaded: bool, +} + +impl<T: Write> PrettyFormatter<T> { + pub fn new( + out: OutputLocation<T>, + use_color: bool, + max_name_len: usize, + is_multithreaded: bool, + ) -> Self { + PrettyFormatter { + out, + use_color, + max_name_len, + is_multithreaded, + } + } + + #[cfg(test)] + pub fn output_location(&self) -> &OutputLocation<T> { + &self.out + } + + pub fn write_ok(&mut self) -> io::Result<()> { + self.write_short_result("ok", term::color::GREEN) + } + + pub fn write_failed(&mut self) -> io::Result<()> { + self.write_short_result("FAILED", term::color::RED) + } + + pub fn write_ignored(&mut self) -> io::Result<()> { + self.write_short_result("ignored", term::color::YELLOW) + } + + pub fn write_allowed_fail(&mut self) -> io::Result<()> { + self.write_short_result("FAILED (allowed)", term::color::YELLOW) + } + + pub fn write_bench(&mut self) -> io::Result<()> { + self.write_pretty("bench", term::color::CYAN) + } + + pub fn write_short_result( + &mut self, + result: &str, + color: term::color::Color, + ) -> io::Result<()> { + self.write_pretty(result, color)?; + self.write_plain("\n") + } + + pub fn write_pretty(&mut self, word: &str, color: term::color::Color) -> io::Result<()> { + match self.out { + Pretty(ref mut term) => { + if self.use_color { + term.fg(color)?; + } + term.write_all(word.as_bytes())?; + if self.use_color { + term.reset()?; + } + term.flush() + } + Raw(ref mut stdout) => { + stdout.write_all(word.as_bytes())?; + stdout.flush() + } + } + } + + pub fn write_plain<S: AsRef<str>>(&mut self, s: S) -> io::Result<()> { + let s = s.as_ref(); + self.out.write_all(s.as_bytes())?; + self.out.flush() + } + + pub fn write_successes(&mut self, state: &ConsoleTestState) -> io::Result<()> { + self.write_plain("\nsuccesses:\n")?; + let mut successes = Vec::new(); + let mut stdouts = String::new(); + for &(ref f, ref stdout) in &state.not_failures { + successes.push(f.name.to_string()); + if !stdout.is_empty() { + stdouts.push_str(&format!("---- {} stdout ----\n", f.name)); + let output = String::from_utf8_lossy(stdout); + stdouts.push_str(&output); + stdouts.push_str("\n"); + } + } + if !stdouts.is_empty() { + self.write_plain("\n")?; + self.write_plain(&stdouts)?; + } + + self.write_plain("\nsuccesses:\n")?; + successes.sort(); + for name in &successes { + self.write_plain(&format!(" {}\n", name))?; + } + Ok(()) + } + + pub fn write_failures(&mut self, state: &ConsoleTestState) -> io::Result<()> { + self.write_plain("\nfailures:\n")?; + let mut failures = Vec::new(); + let mut fail_out = String::new(); + for &(ref f, ref stdout) in &state.failures { + failures.push(f.name.to_string()); + if !stdout.is_empty() { + fail_out.push_str(&format!("---- {} stdout ----\n", f.name)); + let output = String::from_utf8_lossy(stdout); + fail_out.push_str(&output); + fail_out.push_str("\n"); + } + } + if !fail_out.is_empty() { + self.write_plain("\n")?; + self.write_plain(&fail_out)?; + } + + self.write_plain("\nfailures:\n")?; + failures.sort(); + for name in &failures { + self.write_plain(&format!(" {}\n", name))?; + } + Ok(()) + } + + fn write_test_name(&mut self, desc: &TestDesc) -> io::Result<()> { + let name = desc.padded_name(self.max_name_len, desc.name.padding()); + self.write_plain(&format!("test {} ... ", name))?; + + Ok(()) + } +} + +impl<T: Write> OutputFormatter for PrettyFormatter<T> { + fn write_run_start(&mut self, test_count: usize) -> io::Result<()> { + let noun = if test_count != 1 { "tests" } else { "test" }; + self.write_plain(&format!("\nrunning {} {}\n", test_count, noun)) + } + + fn write_test_start(&mut self, desc: &TestDesc) -> io::Result<()> { + // When running tests concurrently, we should not print + // the test's name as the result will be mis-aligned. + // When running the tests serially, we print the name here so + // that the user can see which test hangs. + if !self.is_multithreaded { + self.write_test_name(desc)?; + } + + Ok(()) + } + + fn write_result(&mut self, desc: &TestDesc, result: &TestResult, _: &[u8]) -> io::Result<()> { + if self.is_multithreaded { + self.write_test_name(desc)?; + } + + match *result { + TrOk => self.write_ok(), + TrFailed | TrFailedMsg(_) => self.write_failed(), + TrIgnored => self.write_ignored(), + TrAllowedFail => self.write_allowed_fail(), + TrBench(ref bs) => { + self.write_bench()?; + self.write_plain(&format!(": {}\n", fmt_bench_samples(bs))) + } + } + } + + fn write_timeout(&mut self, desc: &TestDesc) -> io::Result<()> { + if self.is_multithreaded { + self.write_test_name(desc)?; + } + + self.write_plain(&format!( + "test {} has been running for over {} seconds\n", + desc.name, TEST_WARN_TIMEOUT_S + )) + } + + fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result<bool> { + if state.options.display_output { + self.write_successes(state)?; + } + let success = state.failed == 0; + if !success { + self.write_failures(state)?; + } + + self.write_plain("\ntest result: ")?; + + if success { + // There's no parallelism at this point so it's safe to use color + self.write_pretty("ok", term::color::GREEN)?; + } else { + self.write_pretty("FAILED", term::color::RED)?; + } + + let s = if state.allowed_fail > 0 { + format!( + ". {} passed; {} failed ({} allowed); {} ignored; {} measured; {} filtered out\n\n", + state.passed, + state.failed + state.allowed_fail, + state.allowed_fail, + state.ignored, + state.measured, + state.filtered_out + ) + } else { + format!( + ". {} passed; {} failed; {} ignored; {} measured; {} filtered out\n\n", + state.passed, state.failed, state.ignored, state.measured, state.filtered_out + ) + }; + + self.write_plain(&s)?; + + Ok(success) + } +} diff --git a/src/libtest/formatters/terse.rs b/src/libtest/formatters/terse.rs new file mode 100644 index 00000000000..1400fba5d60 --- /dev/null +++ b/src/libtest/formatters/terse.rs @@ -0,0 +1,235 @@ +use super::*; + +pub(crate) struct TerseFormatter<T> { + out: OutputLocation<T>, + use_color: bool, + is_multithreaded: bool, + /// Number of columns to fill when aligning names + max_name_len: usize, + + test_count: usize, + total_test_count: usize, +} + +impl<T: Write> TerseFormatter<T> { + pub fn new( + out: OutputLocation<T>, + use_color: bool, + max_name_len: usize, + is_multithreaded: bool, + ) -> Self { + TerseFormatter { + out, + use_color, + max_name_len, + is_multithreaded, + test_count: 0, + total_test_count: 0, // initialized later, when write_run_start is called + } + } + + pub fn write_ok(&mut self) -> io::Result<()> { + self.write_short_result(".", term::color::GREEN) + } + + pub fn write_failed(&mut self) -> io::Result<()> { + self.write_short_result("F", term::color::RED) + } + + pub fn write_ignored(&mut self) -> io::Result<()> { + self.write_short_result("i", term::color::YELLOW) + } + + pub fn write_allowed_fail(&mut self) -> io::Result<()> { + self.write_short_result("a", term::color::YELLOW) + } + + pub fn write_bench(&mut self) -> io::Result<()> { + self.write_pretty("bench", term::color::CYAN) + } + + pub fn write_short_result( + &mut self, + result: &str, + color: term::color::Color, + ) -> io::Result<()> { + self.write_pretty(result, color)?; + if self.test_count % QUIET_MODE_MAX_COLUMN == QUIET_MODE_MAX_COLUMN - 1 { + // we insert a new line every 100 dots in order to flush the + // screen when dealing with line-buffered output (e.g., piping to + // `stamp` in the rust CI). + let out = format!(" {}/{}\n", self.test_count+1, self.total_test_count); + self.write_plain(&out)?; + } + + self.test_count += 1; + Ok(()) + } + + pub fn write_pretty(&mut self, word: &str, color: term::color::Color) -> io::Result<()> { + match self.out { + Pretty(ref mut term) => { + if self.use_color { + term.fg(color)?; + } + term.write_all(word.as_bytes())?; + if self.use_color { + term.reset()?; + } + term.flush() + } + Raw(ref mut stdout) => { + stdout.write_all(word.as_bytes())?; + stdout.flush() + } + } + } + + pub fn write_plain<S: AsRef<str>>(&mut self, s: S) -> io::Result<()> { + let s = s.as_ref(); + self.out.write_all(s.as_bytes())?; + self.out.flush() + } + + pub fn write_outputs(&mut self, state: &ConsoleTestState) -> io::Result<()> { + self.write_plain("\nsuccesses:\n")?; + let mut successes = Vec::new(); + let mut stdouts = String::new(); + for &(ref f, ref stdout) in &state.not_failures { + successes.push(f.name.to_string()); + if !stdout.is_empty() { + stdouts.push_str(&format!("---- {} stdout ----\n", f.name)); + let output = String::from_utf8_lossy(stdout); + stdouts.push_str(&output); + stdouts.push_str("\n"); + } + } + if !stdouts.is_empty() { + self.write_plain("\n")?; + self.write_plain(&stdouts)?; + } + + self.write_plain("\nsuccesses:\n")?; + successes.sort(); + for name in &successes { + self.write_plain(&format!(" {}\n", name))?; + } + Ok(()) + } + + pub fn write_failures(&mut self, state: &ConsoleTestState) -> io::Result<()> { + self.write_plain("\nfailures:\n")?; + let mut failures = Vec::new(); + let mut fail_out = String::new(); + for &(ref f, ref stdout) in &state.failures { + failures.push(f.name.to_string()); + if !stdout.is_empty() { + fail_out.push_str(&format!("---- {} stdout ----\n", f.name)); + let output = String::from_utf8_lossy(stdout); + fail_out.push_str(&output); + fail_out.push_str("\n"); + } + } + if !fail_out.is_empty() { + self.write_plain("\n")?; + self.write_plain(&fail_out)?; + } + + self.write_plain("\nfailures:\n")?; + failures.sort(); + for name in &failures { + self.write_plain(&format!(" {}\n", name))?; + } + Ok(()) + } + + fn write_test_name(&mut self, desc: &TestDesc) -> io::Result<()> { + let name = desc.padded_name(self.max_name_len, desc.name.padding()); + self.write_plain(&format!("test {} ... ", name))?; + + Ok(()) + } +} + +impl<T: Write> OutputFormatter for TerseFormatter<T> { + fn write_run_start(&mut self, test_count: usize) -> io::Result<()> { + self.total_test_count = test_count; + let noun = if test_count != 1 { "tests" } else { "test" }; + self.write_plain(&format!("\nrunning {} {}\n", test_count, noun)) + } + + fn write_test_start(&mut self, desc: &TestDesc) -> io::Result<()> { + // Remnants from old libtest code that used the padding value + // in order to indicate benchmarks. + // When running benchmarks, terse-mode should still print their name as if + // it is the Pretty formatter. + if !self.is_multithreaded && desc.name.padding() == PadOnRight { + self.write_test_name(desc)?; + } + + Ok(()) + } + + fn write_result(&mut self, desc: &TestDesc, result: &TestResult, _: &[u8]) -> io::Result<()> { + match *result { + TrOk => self.write_ok(), + TrFailed | TrFailedMsg(_) => self.write_failed(), + TrIgnored => self.write_ignored(), + TrAllowedFail => self.write_allowed_fail(), + TrBench(ref bs) => { + if self.is_multithreaded { + self.write_test_name(desc)?; + } + self.write_bench()?; + self.write_plain(&format!(": {}\n", fmt_bench_samples(bs))) + } + } + } + + fn write_timeout(&mut self, desc: &TestDesc) -> io::Result<()> { + self.write_plain(&format!( + "test {} has been running for over {} seconds\n", + desc.name, TEST_WARN_TIMEOUT_S + )) + } + + fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result<bool> { + if state.options.display_output { + self.write_outputs(state)?; + } + let success = state.failed == 0; + if !success { + self.write_failures(state)?; + } + + self.write_plain("\ntest result: ")?; + + if success { + // There's no parallelism at this point so it's safe to use color + self.write_pretty("ok", term::color::GREEN)?; + } else { + self.write_pretty("FAILED", term::color::RED)?; + } + + let s = if state.allowed_fail > 0 { + format!( + ". {} passed; {} failed ({} allowed); {} ignored; {} measured; {} filtered out\n\n", + state.passed, + state.failed + state.allowed_fail, + state.allowed_fail, + state.ignored, + state.measured, + state.filtered_out + ) + } else { + format!( + ". {} passed; {} failed; {} ignored; {} measured; {} filtered out\n\n", + state.passed, state.failed, state.ignored, state.measured, state.filtered_out + ) + }; + + self.write_plain(&s)?; + + Ok(success) + } +} diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 5c91c0ec43b..26612964c30 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -8,48 +8,2224 @@ //! //! See the [Testing Chapter](../book/ch11-00-testing.html) of the book for more details. +// Currently, not much of this is meant for users. It is intended to +// support the simplest interface possible for representing and +// running tests while providing a base that other test frameworks may +// build off of. + +// N.B., this is also specified in this crate's Cargo.toml, but libsyntax contains logic specific to +// this crate, which relies on this attribute (rather than the value of `--crate-name` passed by +// cargo) to detect this crate. + +#![deny(rust_2018_idioms)] #![crate_name = "test"] #![unstable(feature = "test", issue = "27812")] -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/", - test(attr(deny(warnings))))] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/", test(attr(deny(warnings))))] #![feature(asm)] +#![feature(fnbox)] +#![cfg_attr(any(unix, target_os = "cloudabi"), feature(libc, rustc_private))] +#![feature(nll)] +#![feature(set_stdio)] +#![feature(panic_unwind)] #![feature(staged_api)] +#![feature(termination_trait_lib)] #![feature(test)] -extern crate libtest; +use getopts; +#[cfg(any(unix, target_os = "cloudabi"))] +extern crate libc; +use term; + +// FIXME(#54291): rustc and/or LLVM don't yet support building with panic-unwind +// on aarch64-pc-windows-msvc, so we don't link libtest against +// libunwind (for the time being), even though it means that +// libtest won't be fully functional on this platform. +// +// See also: https://github.com/rust-lang/rust/issues/54190#issuecomment-422904437 +#[cfg(not(all(windows, target_arch = "aarch64")))] +extern crate panic_unwind; + +pub use self::ColorConfig::*; +use self::NamePadding::*; +use self::OutputLocation::*; +use self::TestEvent::*; +pub use self::TestFn::*; +pub use self::TestName::*; +pub use self::TestResult::*; + +use std::any::Any; +use std::borrow::Cow; +use std::boxed::FnBox; +use std::cmp; +use std::collections::BTreeMap; +use std::env; +use std::fmt; +use std::fs::File; +use std::io; +use std::io::prelude::*; +use std::panic::{catch_unwind, AssertUnwindSafe}; +use std::path::PathBuf; +use std::process; +use std::process::Termination; +use std::sync::mpsc::{channel, Sender}; +use std::sync::{Arc, Mutex}; +use std::thread; +use std::time::{Duration, Instant}; + +const TEST_WARN_TIMEOUT_S: u64 = 60; +const QUIET_MODE_MAX_COLUMN: usize = 100; // insert a '\n' after 100 tests in quiet mode + +// to be used by rustc to compile tests in libtest +pub mod test { + pub use crate::{ + assert_test_result, filter_tests, parse_opts, run_test, test_main, test_main_static, + Bencher, DynTestFn, DynTestName, Metric, MetricMap, Options, RunIgnored, ShouldPanic, + StaticBenchFn, StaticTestFn, StaticTestName, TestDesc, TestDescAndFn, TestName, TestOpts, + TestResult, TrFailed, TrFailedMsg, TrIgnored, TrOk, + }; +} + +mod formatters; +pub mod stats; + +use crate::formatters::{JsonFormatter, OutputFormatter, PrettyFormatter, TerseFormatter}; + +/// Whether to execute tests concurrently or not +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum Concurrent { + Yes, + No, +} + +// The name of a test. By convention this follows the rules for rust +// paths; i.e., it should be a series of identifiers separated by double +// colons. This way if some test runner wants to arrange the tests +// hierarchically it may. + +#[derive(Clone, PartialEq, Eq, Hash, Debug)] +pub enum TestName { + StaticTestName(&'static str), + DynTestName(String), + AlignedTestName(Cow<'static, str>, NamePadding), +} +impl TestName { + fn as_slice(&self) -> &str { + match *self { + StaticTestName(s) => s, + DynTestName(ref s) => s, + AlignedTestName(ref s, _) => &*s, + } + } + + fn padding(&self) -> NamePadding { + match self { + &AlignedTestName(_, p) => p, + _ => PadNone, + } + } + + fn with_padding(&self, padding: NamePadding) -> TestName { + let name = match self { + &TestName::StaticTestName(name) => Cow::Borrowed(name), + &TestName::DynTestName(ref name) => Cow::Owned(name.clone()), + &TestName::AlignedTestName(ref name, _) => name.clone(), + }; + + TestName::AlignedTestName(name, padding) + } +} +impl fmt::Display for TestName { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self.as_slice(), f) + } +} + +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +pub enum NamePadding { + PadNone, + PadOnRight, +} + +impl TestDesc { + fn padded_name(&self, column_count: usize, align: NamePadding) -> String { + let mut name = String::from(self.name.as_slice()); + let fill = column_count.saturating_sub(name.len()); + let pad = " ".repeat(fill); + match align { + PadNone => name, + PadOnRight => { + name.push_str(&pad); + name + } + } + } +} + +/// Represents a benchmark function. +pub trait TDynBenchFn: Send { + fn run(&self, harness: &mut Bencher); +} + +// A function that runs a test. If the function returns successfully, +// the test succeeds; if the function panics then the test fails. We +// may need to come up with a more clever definition of test in order +// to support isolation of tests into threads. +pub enum TestFn { + StaticTestFn(fn()), + StaticBenchFn(fn(&mut Bencher)), + DynTestFn(Box<dyn FnBox() + Send>), + DynBenchFn(Box<dyn TDynBenchFn + 'static>), +} + +impl TestFn { + fn padding(&self) -> NamePadding { + match *self { + StaticTestFn(..) => PadNone, + StaticBenchFn(..) => PadOnRight, + DynTestFn(..) => PadNone, + DynBenchFn(..) => PadOnRight, + } + } +} + +impl fmt::Debug for TestFn { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(match *self { + StaticTestFn(..) => "StaticTestFn(..)", + StaticBenchFn(..) => "StaticBenchFn(..)", + DynTestFn(..) => "DynTestFn(..)", + DynBenchFn(..) => "DynBenchFn(..)", + }) + } +} + +/// Manager of the benchmarking runs. +/// +/// This is fed into functions marked with `#[bench]` to allow for +/// set-up & tear-down before running a piece of code repeatedly via a +/// call to `iter`. +#[derive(Clone)] +pub struct Bencher { + mode: BenchMode, + summary: Option<stats::Summary>, + pub bytes: u64, +} + +#[derive(Clone, PartialEq, Eq)] +pub enum BenchMode { + Auto, + Single, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub enum ShouldPanic { + No, + Yes, + YesWithMessage(&'static str), +} + +// The definition of a single test. A test runner will run a list of +// these. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct TestDesc { + pub name: TestName, + pub ignore: bool, + pub should_panic: ShouldPanic, + pub allow_fail: bool, +} + +#[derive(Debug)] +pub struct TestDescAndFn { + pub desc: TestDesc, + pub testfn: TestFn, +} + +#[derive(Clone, PartialEq, Debug, Copy)] +pub struct Metric { + value: f64, + noise: f64, +} + +impl Metric { + pub fn new(value: f64, noise: f64) -> Metric { + Metric { value, noise } + } +} + +/// In case we want to add other options as well, just add them in this struct. +#[derive(Copy, Clone, Debug)] +pub struct Options { + display_output: bool, +} + +impl Options { + pub fn new() -> Options { + Options { + display_output: false, + } + } + + pub fn display_output(mut self, display_output: bool) -> Options { + self.display_output = display_output; + self + } +} + +// The default console test runner. It accepts the command line +// arguments and a vector of test_descs. +pub fn test_main(args: &[String], tests: Vec<TestDescAndFn>, options: Options) { + let mut opts = match parse_opts(args) { + Some(Ok(o)) => o, + Some(Err(msg)) => { + eprintln!("error: {}", msg); + process::exit(101); + } + None => return, + }; + + opts.options = options; + if opts.list { + if let Err(e) = list_tests_console(&opts, tests) { + eprintln!("error: io error when listing tests: {:?}", e); + process::exit(101); + } + } else { + match run_tests_console(&opts, tests) { + Ok(true) => {} + Ok(false) => process::exit(101), + Err(e) => { + eprintln!("error: io error when listing tests: {:?}", e); + process::exit(101); + } + } + } +} + +// A variant optimized for invocation with a static test vector. +// This will panic (intentionally) when fed any dynamic tests, because +// it is copying the static values out into a dynamic vector and cannot +// copy dynamic values. It is doing this because from this point on +// a Vec<TestDescAndFn> is used in order to effect ownership-transfer +// semantics into parallel test runners, which in turn requires a Vec<> +// rather than a &[]. +pub fn test_main_static(tests: &[&TestDescAndFn]) { + let args = env::args().collect::<Vec<_>>(); + let owned_tests = tests + .iter() + .map(|t| match t.testfn { + StaticTestFn(f) => TestDescAndFn { + testfn: StaticTestFn(f), + desc: t.desc.clone(), + }, + StaticBenchFn(f) => TestDescAndFn { + testfn: StaticBenchFn(f), + desc: t.desc.clone(), + }, + _ => panic!("non-static tests passed to test::test_main_static"), + }) + .collect(); + test_main(&args, owned_tests, Options::new()) +} + +/// Invoked when unit tests terminate. Should panic if the unit +/// Tests is considered a failure. By default, invokes `report()` +/// and checks for a `0` result. +pub fn assert_test_result<T: Termination>(result: T) { + let code = result.report(); + assert_eq!( + code, 0, + "the test returned a termination value with a non-zero status code ({}) \ + which indicates a failure", + code + ); +} + +#[derive(Copy, Clone, Debug)] +pub enum ColorConfig { + AutoColor, + AlwaysColor, + NeverColor, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum OutputFormat { + Pretty, + Terse, + Json, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum RunIgnored { + Yes, + No, + Only, +} + +#[derive(Debug)] +pub struct TestOpts { + pub list: bool, + pub filter: Option<String>, + pub filter_exact: bool, + pub exclude_should_panic: bool, + pub run_ignored: RunIgnored, + pub run_tests: bool, + pub bench_benchmarks: bool, + pub logfile: Option<PathBuf>, + pub nocapture: bool, + pub color: ColorConfig, + pub format: OutputFormat, + pub test_threads: Option<usize>, + pub skip: Vec<String>, + pub options: Options, +} + +impl TestOpts { + #[cfg(test)] + fn new() -> TestOpts { + TestOpts { + list: false, + filter: None, + filter_exact: false, + exclude_should_panic: false, + run_ignored: RunIgnored::No, + run_tests: false, + bench_benchmarks: false, + logfile: None, + nocapture: false, + color: AutoColor, + format: OutputFormat::Pretty, + test_threads: None, + skip: vec![], + options: Options::new(), + } + } +} + +/// Result of parsing the options. +pub type OptRes = Result<TestOpts, String>; + +fn optgroups() -> getopts::Options { + let mut opts = getopts::Options::new(); + opts.optflag("", "include-ignored", "Run ignored and not ignored tests") + .optflag("", "ignored", "Run only ignored tests") + .optflag("", "exclude-should-panic", "Excludes tests marked as should_panic") + .optflag("", "test", "Run tests and not benchmarks") + .optflag("", "bench", "Run benchmarks instead of tests") + .optflag("", "list", "List all tests and benchmarks") + .optflag("h", "help", "Display this message (longer with --help)") + .optopt( + "", + "logfile", + "Write logs to the specified file instead \ + of stdout", + "PATH", + ) + .optflag( + "", + "nocapture", + "don't capture stdout/stderr of each \ + task, allow printing directly", + ) + .optopt( + "", + "test-threads", + "Number of threads used for running tests \ + in parallel", + "n_threads", + ) + .optmulti( + "", + "skip", + "Skip tests whose names contain FILTER (this flag can \ + be used multiple times)", + "FILTER", + ) + .optflag( + "q", + "quiet", + "Display one character per test instead of one line. \ + Alias to --format=terse", + ) + .optflag( + "", + "exact", + "Exactly match filters rather than by substring", + ) + .optopt( + "", + "color", + "Configure coloring of output: + auto = colorize if stdout is a tty and tests are run on serially (default); + always = always colorize output; + never = never colorize output;", + "auto|always|never", + ) + .optopt( + "", + "format", + "Configure formatting of output: + pretty = Print verbose output; + terse = Display one character per test; + json = Output a json document", + "pretty|terse|json", + ) + .optopt( + "Z", + "", + "Enable nightly-only flags: + unstable-options = Allow use of experimental features", + "unstable-options", + ); + return opts; +} + +fn usage(binary: &str, options: &getopts::Options) { + let message = format!("Usage: {} [OPTIONS] [FILTER]", binary); + println!( + r#"{usage} + +The FILTER string is tested against the name of all tests, and only those +tests whose names contain the filter are run. + +By default, all tests are run in parallel. This can be altered with the +--test-threads flag or the RUST_TEST_THREADS environment variable when running +tests (set it to 1). + +All tests have their standard output and standard error captured by default. +This can be overridden with the --nocapture flag or setting RUST_TEST_NOCAPTURE +environment variable to a value other than "0". Logging is not captured by default. + +Test Attributes: + + #[test] - Indicates a function is a test to be run. This function + takes no arguments. + #[bench] - Indicates a function is a benchmark to be run. This + function takes one argument (test::Bencher). + #[should_panic] - This function (also labeled with #[test]) will only pass if + the code causes a panic (an assertion failure or panic!) + A message may be provided, which the failure string must + contain: #[should_panic(expected = "foo")]. + #[ignore] - When applied to a function which is already attributed as a + test, then the test runner will ignore these tests during + normal test runs. Running with --ignored or --include-ignored will run + these tests."#, + usage = options.usage(&message) + ); +} + +// FIXME: Copied from libsyntax until linkage errors are resolved. Issue #47566 +fn is_nightly() -> bool { + // Whether this is a feature-staged build, i.e., on the beta or stable channel + let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some(); + // Whether we should enable unstable features for bootstrapping + let bootstrap = env::var("RUSTC_BOOTSTRAP").is_ok(); + + bootstrap || !disable_unstable_features +} + +// Parses command line arguments into test options +pub fn parse_opts(args: &[String]) -> Option<OptRes> { + let mut allow_unstable = false; + let opts = optgroups(); + let args = args.get(1..).unwrap_or(args); + let matches = match opts.parse(args) { + Ok(m) => m, + Err(f) => return Some(Err(f.to_string())), + }; + + if let Some(opt) = matches.opt_str("Z") { + if !is_nightly() { + return Some(Err( + "the option `Z` is only accepted on the nightly compiler".into(), + )); + } + + match &*opt { + "unstable-options" => { + allow_unstable = true; + } + _ => { + return Some(Err("Unrecognized option to `Z`".into())); + } + } + }; + + if matches.opt_present("h") { + usage(&args[0], &opts); + return None; + } + + let filter = if !matches.free.is_empty() { + Some(matches.free[0].clone()) + } else { + None + }; + + let exclude_should_panic = matches.opt_present("exclude-should-panic"); + if !allow_unstable && exclude_should_panic { + return Some(Err( + "The \"exclude-should-panic\" flag is only accepted on the nightly compiler".into(), + )); + } + + let include_ignored = matches.opt_present("include-ignored"); + if !allow_unstable && include_ignored { + return Some(Err( + "The \"include-ignored\" flag is only accepted on the nightly compiler".into(), + )); + } + + let run_ignored = match (include_ignored, matches.opt_present("ignored")) { + (true, true) => { + return Some(Err( + "the options --include-ignored and --ignored are mutually exclusive".into(), + )); + } + (true, false) => RunIgnored::Yes, + (false, true) => RunIgnored::Only, + (false, false) => RunIgnored::No, + }; + let quiet = matches.opt_present("quiet"); + let exact = matches.opt_present("exact"); + let list = matches.opt_present("list"); + + let logfile = matches.opt_str("logfile"); + let logfile = logfile.map(|s| PathBuf::from(&s)); + + let bench_benchmarks = matches.opt_present("bench"); + let run_tests = !bench_benchmarks || matches.opt_present("test"); + + let mut nocapture = matches.opt_present("nocapture"); + if !nocapture { + nocapture = match env::var("RUST_TEST_NOCAPTURE") { + Ok(val) => &val != "0", + Err(_) => false, + }; + } + + let test_threads = match matches.opt_str("test-threads") { + Some(n_str) => match n_str.parse::<usize>() { + Ok(0) => return Some(Err("argument for --test-threads must not be 0".to_string())), + Ok(n) => Some(n), + Err(e) => { + return Some(Err(format!( + "argument for --test-threads must be a number > 0 \ + (error: {})", + e + ))); + } + }, + None => None, + }; + + let color = match matches.opt_str("color").as_ref().map(|s| &**s) { + Some("auto") | None => AutoColor, + Some("always") => AlwaysColor, + Some("never") => NeverColor, + + Some(v) => { + return Some(Err(format!( + "argument for --color must be auto, always, or never (was \ + {})", + v + ))); + } + }; + + let format = match matches.opt_str("format").as_ref().map(|s| &**s) { + None if quiet => OutputFormat::Terse, + Some("pretty") | None => OutputFormat::Pretty, + Some("terse") => OutputFormat::Terse, + Some("json") => { + if !allow_unstable { + return Some(Err( + "The \"json\" format is only accepted on the nightly compiler".into(), + )); + } + OutputFormat::Json + } + + Some(v) => { + return Some(Err(format!( + "argument for --format must be pretty, terse, or json (was \ + {})", + v + ))); + } + }; + + let test_opts = TestOpts { + list, + filter, + filter_exact: exact, + exclude_should_panic, + run_ignored, + run_tests, + bench_benchmarks, + logfile, + nocapture, + color, + format, + test_threads, + skip: matches.opt_strs("skip"), + options: Options::new(), + }; + + Some(Ok(test_opts)) +} + +#[derive(Clone, PartialEq)] +pub struct BenchSamples { + ns_iter_summ: stats::Summary, + mb_s: usize, +} + +#[derive(Clone, PartialEq)] +pub enum TestResult { + TrOk, + TrFailed, + TrFailedMsg(String), + TrIgnored, + TrAllowedFail, + TrBench(BenchSamples), +} + +unsafe impl Send for TestResult {} + +enum OutputLocation<T> { + Pretty(Box<term::StdoutTerminal>), + Raw(T), +} + +impl<T: Write> Write for OutputLocation<T> { + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + match *self { + Pretty(ref mut term) => term.write(buf), + Raw(ref mut stdout) => stdout.write(buf), + } + } + + fn flush(&mut self) -> io::Result<()> { + match *self { + Pretty(ref mut term) => term.flush(), + Raw(ref mut stdout) => stdout.flush(), + } + } +} + +struct ConsoleTestState { + log_out: Option<File>, + total: usize, + passed: usize, + failed: usize, + ignored: usize, + allowed_fail: usize, + filtered_out: usize, + measured: usize, + metrics: MetricMap, + failures: Vec<(TestDesc, Vec<u8>)>, + not_failures: Vec<(TestDesc, Vec<u8>)>, + options: Options, +} + +impl ConsoleTestState { + pub fn new(opts: &TestOpts) -> io::Result<ConsoleTestState> { + let log_out = match opts.logfile { + Some(ref path) => Some(File::create(path)?), + None => None, + }; + + Ok(ConsoleTestState { + log_out, + total: 0, + passed: 0, + failed: 0, + ignored: 0, + allowed_fail: 0, + filtered_out: 0, + measured: 0, + metrics: MetricMap::new(), + failures: Vec::new(), + not_failures: Vec::new(), + options: opts.options, + }) + } + + pub fn write_log<S: AsRef<str>>(&mut self, msg: S) -> io::Result<()> { + let msg = msg.as_ref(); + match self.log_out { + None => Ok(()), + Some(ref mut o) => o.write_all(msg.as_bytes()), + } + } + + pub fn write_log_result(&mut self, test: &TestDesc, result: &TestResult) -> io::Result<()> { + self.write_log(format!( + "{} {}\n", + match *result { + TrOk => "ok".to_owned(), + TrFailed => "failed".to_owned(), + TrFailedMsg(ref msg) => format!("failed: {}", msg), + TrIgnored => "ignored".to_owned(), + TrAllowedFail => "failed (allowed)".to_owned(), + TrBench(ref bs) => fmt_bench_samples(bs), + }, + test.name + )) + } + + fn current_test_count(&self) -> usize { + self.passed + self.failed + self.ignored + self.measured + self.allowed_fail + } +} + +// Format a number with thousands separators +fn fmt_thousands_sep(mut n: usize, sep: char) -> String { + use std::fmt::Write; + let mut output = String::new(); + let mut trailing = false; + for &pow in &[9, 6, 3, 0] { + let base = 10_usize.pow(pow); + if pow == 0 || trailing || n / base != 0 { + if !trailing { + output.write_fmt(format_args!("{}", n / base)).unwrap(); + } else { + output.write_fmt(format_args!("{:03}", n / base)).unwrap(); + } + if pow != 0 { + output.push(sep); + } + trailing = true; + } + n %= base; + } + + output +} + +pub fn fmt_bench_samples(bs: &BenchSamples) -> String { + use std::fmt::Write; + let mut output = String::new(); + + let median = bs.ns_iter_summ.median as usize; + let deviation = (bs.ns_iter_summ.max - bs.ns_iter_summ.min) as usize; + + output + .write_fmt(format_args!( + "{:>11} ns/iter (+/- {})", + fmt_thousands_sep(median, ','), + fmt_thousands_sep(deviation, ',') + )) + .unwrap(); + if bs.mb_s != 0 { + output + .write_fmt(format_args!(" = {} MB/s", bs.mb_s)) + .unwrap(); + } + output +} + +// List the tests to console, and optionally to logfile. Filters are honored. +pub fn list_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Result<()> { + let mut output = match term::stdout() { + None => Raw(io::stdout()), + Some(t) => Pretty(t), + }; + + let quiet = opts.format == OutputFormat::Terse; + let mut st = ConsoleTestState::new(opts)?; + + let mut ntest = 0; + let mut nbench = 0; + + for test in filter_tests(&opts, tests) { + use crate::TestFn::*; + + let TestDescAndFn { + desc: TestDesc { name, .. }, + testfn, + } = test; + + let fntype = match testfn { + StaticTestFn(..) | DynTestFn(..) => { + ntest += 1; + "test" + } + StaticBenchFn(..) | DynBenchFn(..) => { + nbench += 1; + "benchmark" + } + }; + + writeln!(output, "{}: {}", name, fntype)?; + st.write_log(format!("{} {}\n", fntype, name))?; + } + + fn plural(count: u32, s: &str) -> String { + match count { + 1 => format!("{} {}", 1, s), + n => format!("{} {}s", n, s), + } + } + + if !quiet { + if ntest != 0 || nbench != 0 { + writeln!(output, "")?; + } + + writeln!( + output, + "{}, {}", + plural(ntest, "test"), + plural(nbench, "benchmark") + )?; + } + + Ok(()) +} + +// A simple console test runner +pub fn run_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Result<bool> { + fn callback( + event: &TestEvent, + st: &mut ConsoleTestState, + out: &mut dyn OutputFormatter, + ) -> io::Result<()> { + match (*event).clone() { + TeFiltered(ref filtered_tests) => { + st.total = filtered_tests.len(); + out.write_run_start(filtered_tests.len()) + } + TeFilteredOut(filtered_out) => Ok(st.filtered_out = filtered_out), + TeWait(ref test) => out.write_test_start(test), + TeTimeout(ref test) => out.write_timeout(test), + TeResult(test, result, stdout) => { + st.write_log_result(&test, &result)?; + out.write_result(&test, &result, &*stdout)?; + match result { + TrOk => { + st.passed += 1; + st.not_failures.push((test, stdout)); + } + TrIgnored => st.ignored += 1, + TrAllowedFail => st.allowed_fail += 1, + TrBench(bs) => { + st.metrics.insert_metric( + test.name.as_slice(), + bs.ns_iter_summ.median, + bs.ns_iter_summ.max - bs.ns_iter_summ.min, + ); + st.measured += 1 + } + TrFailed => { + st.failed += 1; + st.failures.push((test, stdout)); + } + TrFailedMsg(msg) => { + st.failed += 1; + let mut stdout = stdout; + stdout.extend_from_slice(format!("note: {}", msg).as_bytes()); + st.failures.push((test, stdout)); + } + } + Ok(()) + } + } + } + + let output = match term::stdout() { + None => Raw(io::stdout()), + Some(t) => Pretty(t), + }; + + let max_name_len = tests + .iter() + .max_by_key(|t| len_if_padded(*t)) + .map(|t| t.desc.name.as_slice().len()) + .unwrap_or(0); + + let is_multithreaded = opts.test_threads.unwrap_or_else(get_concurrency) > 1; + + let mut out: Box<dyn OutputFormatter> = match opts.format { + OutputFormat::Pretty => Box::new(PrettyFormatter::new( + output, + use_color(opts), + max_name_len, + is_multithreaded, + )), + OutputFormat::Terse => Box::new(TerseFormatter::new( + output, + use_color(opts), + max_name_len, + is_multithreaded, + )), + OutputFormat::Json => Box::new(JsonFormatter::new(output)), + }; + let mut st = ConsoleTestState::new(opts)?; + fn len_if_padded(t: &TestDescAndFn) -> usize { + match t.testfn.padding() { + PadNone => 0, + PadOnRight => t.desc.name.as_slice().len(), + } + } + + run_tests(opts, tests, |x| callback(&x, &mut st, &mut *out))?; + + assert!(st.current_test_count() == st.total); + + return out.write_run_finish(&st); +} + +#[test] +fn should_sort_failures_before_printing_them() { + let test_a = TestDesc { + name: StaticTestName("a"), + ignore: false, + should_panic: ShouldPanic::No, + allow_fail: false, + }; + + let test_b = TestDesc { + name: StaticTestName("b"), + ignore: false, + should_panic: ShouldPanic::No, + allow_fail: false, + }; + + let mut out = PrettyFormatter::new(Raw(Vec::new()), false, 10, false); + + let st = ConsoleTestState { + log_out: None, + total: 0, + passed: 0, + failed: 0, + ignored: 0, + allowed_fail: 0, + filtered_out: 0, + measured: 0, + metrics: MetricMap::new(), + failures: vec![(test_b, Vec::new()), (test_a, Vec::new())], + options: Options::new(), + not_failures: Vec::new(), + }; + + out.write_failures(&st).unwrap(); + let s = match out.output_location() { + &Raw(ref m) => String::from_utf8_lossy(&m[..]), + &Pretty(_) => unreachable!(), + }; + + let apos = s.find("a").unwrap(); + let bpos = s.find("b").unwrap(); + assert!(apos < bpos); +} + +fn use_color(opts: &TestOpts) -> bool { + match opts.color { + AutoColor => !opts.nocapture && stdout_isatty(), + AlwaysColor => true, + NeverColor => false, + } +} + +#[cfg(any( + target_os = "cloudabi", + target_os = "redox", + all(target_arch = "wasm32", not(target_os = "emscripten")), + all(target_vendor = "fortanix", target_env = "sgx") +))] +fn stdout_isatty() -> bool { + // FIXME: Implement isatty on Redox and SGX + false +} +#[cfg(unix)] +fn stdout_isatty() -> bool { + unsafe { libc::isatty(libc::STDOUT_FILENO) != 0 } +} +#[cfg(windows)] +fn stdout_isatty() -> bool { + type DWORD = u32; + type BOOL = i32; + type HANDLE = *mut u8; + type LPDWORD = *mut u32; + const STD_OUTPUT_HANDLE: DWORD = -11i32 as DWORD; + extern "system" { + fn GetStdHandle(which: DWORD) -> HANDLE; + fn GetConsoleMode(hConsoleHandle: HANDLE, lpMode: LPDWORD) -> BOOL; + } + unsafe { + let handle = GetStdHandle(STD_OUTPUT_HANDLE); + let mut out = 0; + GetConsoleMode(handle, &mut out) != 0 + } +} + +#[derive(Clone)] +pub enum TestEvent { + TeFiltered(Vec<TestDesc>), + TeWait(TestDesc), + TeResult(TestDesc, TestResult, Vec<u8>), + TeTimeout(TestDesc), + TeFilteredOut(usize), +} + +pub type MonitorMsg = (TestDesc, TestResult, Vec<u8>); -// FIXME: we should be more explicit about the exact APIs that we -// export to users. -pub use libtest::{ - assert_test_result, filter_tests, parse_opts, run_test, test_main, test_main_static, - Bencher, DynTestFn, DynTestName, Metric, MetricMap, Options, RunIgnored, ShouldPanic, - StaticBenchFn, StaticTestFn, StaticTestName, TestDesc, TestDescAndFn, TestName, TestOpts, - TestResult, TrFailed, TrFailedMsg, TrIgnored, TrOk, stats::Summary -}; +struct Sink(Arc<Mutex<Vec<u8>>>); +impl Write for Sink { + fn write(&mut self, data: &[u8]) -> io::Result<usize> { + Write::write(&mut *self.0.lock().unwrap(), data) + } + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +pub fn run_tests<F>(opts: &TestOpts, tests: Vec<TestDescAndFn>, mut callback: F) -> io::Result<()> +where + F: FnMut(TestEvent) -> io::Result<()>, +{ + use std::collections::{self, HashMap}; + use std::hash::BuildHasherDefault; + use std::sync::mpsc::RecvTimeoutError; + // Use a deterministic hasher + type TestMap = + HashMap<TestDesc, Instant, BuildHasherDefault<collections::hash_map::DefaultHasher>>; + + let tests_len = tests.len(); + + let mut filtered_tests = filter_tests(opts, tests); + if !opts.bench_benchmarks { + filtered_tests = convert_benchmarks_to_tests(filtered_tests); + } + + let filtered_tests = { + let mut filtered_tests = filtered_tests; + for test in filtered_tests.iter_mut() { + test.desc.name = test.desc.name.with_padding(test.testfn.padding()); + } + + filtered_tests + }; + + let filtered_out = tests_len - filtered_tests.len(); + callback(TeFilteredOut(filtered_out))?; + + let filtered_descs = filtered_tests.iter().map(|t| t.desc.clone()).collect(); + + callback(TeFiltered(filtered_descs))?; + + let (filtered_tests, filtered_benchs): (Vec<_>, _) = + filtered_tests.into_iter().partition(|e| match e.testfn { + StaticTestFn(_) | DynTestFn(_) => true, + _ => false, + }); + + let concurrency = opts.test_threads.unwrap_or_else(get_concurrency); + + let mut remaining = filtered_tests; + remaining.reverse(); + let mut pending = 0; + + let (tx, rx) = channel::<MonitorMsg>(); + + let mut running_tests: TestMap = HashMap::default(); + + fn get_timed_out_tests(running_tests: &mut TestMap) -> Vec<TestDesc> { + let now = Instant::now(); + let timed_out = running_tests + .iter() + .filter_map(|(desc, timeout)| { + if &now >= timeout { + Some(desc.clone()) + } else { + None + } + }) + .collect(); + for test in &timed_out { + running_tests.remove(test); + } + timed_out + }; + + fn calc_timeout(running_tests: &TestMap) -> Option<Duration> { + running_tests.values().min().map(|next_timeout| { + let now = Instant::now(); + if *next_timeout >= now { + *next_timeout - now + } else { + Duration::new(0, 0) + } + }) + }; + + if concurrency == 1 { + while !remaining.is_empty() { + let test = remaining.pop().unwrap(); + callback(TeWait(test.desc.clone()))?; + run_test(opts, !opts.run_tests, test, tx.clone(), Concurrent::No); + let (test, result, stdout) = rx.recv().unwrap(); + callback(TeResult(test, result, stdout))?; + } + } else { + while pending > 0 || !remaining.is_empty() { + while pending < concurrency && !remaining.is_empty() { + let test = remaining.pop().unwrap(); + let timeout = Instant::now() + Duration::from_secs(TEST_WARN_TIMEOUT_S); + running_tests.insert(test.desc.clone(), timeout); + callback(TeWait(test.desc.clone()))?; //here no pad + run_test(opts, !opts.run_tests, test, tx.clone(), Concurrent::Yes); + pending += 1; + } + + let mut res; + loop { + if let Some(timeout) = calc_timeout(&running_tests) { + res = rx.recv_timeout(timeout); + for test in get_timed_out_tests(&mut running_tests) { + callback(TeTimeout(test))?; + } + if res != Err(RecvTimeoutError::Timeout) { + break; + } + } else { + res = rx.recv().map_err(|_| RecvTimeoutError::Disconnected); + break; + } + } + + let (desc, result, stdout) = res.unwrap(); + running_tests.remove(&desc); + + callback(TeResult(desc, result, stdout))?; + pending -= 1; + } + } + + if opts.bench_benchmarks { + // All benchmarks run at the end, in serial. + for b in filtered_benchs { + callback(TeWait(b.desc.clone()))?; + run_test(opts, false, b, tx.clone(), Concurrent::No); + let (test, result, stdout) = rx.recv().unwrap(); + callback(TeResult(test, result, stdout))?; + } + } + Ok(()) +} + +#[allow(deprecated)] +fn get_concurrency() -> usize { + return match env::var("RUST_TEST_THREADS") { + Ok(s) => { + let opt_n: Option<usize> = s.parse().ok(); + match opt_n { + Some(n) if n > 0 => n, + _ => panic!( + "RUST_TEST_THREADS is `{}`, should be a positive integer.", + s + ), + } + } + Err(..) => num_cpus(), + }; + + #[cfg(windows)] + #[allow(nonstandard_style)] + fn num_cpus() -> usize { + #[repr(C)] + struct SYSTEM_INFO { + wProcessorArchitecture: u16, + wReserved: u16, + dwPageSize: u32, + lpMinimumApplicationAddress: *mut u8, + lpMaximumApplicationAddress: *mut u8, + dwActiveProcessorMask: *mut u8, + dwNumberOfProcessors: u32, + dwProcessorType: u32, + dwAllocationGranularity: u32, + wProcessorLevel: u16, + wProcessorRevision: u16, + } + extern "system" { + fn GetSystemInfo(info: *mut SYSTEM_INFO) -> i32; + } + unsafe { + let mut sysinfo = std::mem::zeroed(); + GetSystemInfo(&mut sysinfo); + sysinfo.dwNumberOfProcessors as usize + } + } + + #[cfg(target_os = "redox")] + fn num_cpus() -> usize { + // FIXME: Implement num_cpus on Redox + 1 + } + + #[cfg(any( + all(target_arch = "wasm32", not(target_os = "emscripten")), + all(target_vendor = "fortanix", target_env = "sgx") + ))] + fn num_cpus() -> usize { + 1 + } + + #[cfg(any( + target_os = "android", + target_os = "cloudabi", + target_os = "emscripten", + target_os = "fuchsia", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "solaris" + ))] + fn num_cpus() -> usize { + unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as usize } + } + + #[cfg(any( + target_os = "freebsd", + target_os = "dragonfly", + target_os = "bitrig", + target_os = "netbsd" + ))] + fn num_cpus() -> usize { + use std::ptr; + + let mut cpus: libc::c_uint = 0; + let mut cpus_size = std::mem::size_of_val(&cpus); + + unsafe { + cpus = libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as libc::c_uint; + } + if cpus < 1 { + let mut mib = [libc::CTL_HW, libc::HW_NCPU, 0, 0]; + unsafe { + libc::sysctl( + mib.as_mut_ptr(), + 2, + &mut cpus as *mut _ as *mut _, + &mut cpus_size as *mut _ as *mut _, + ptr::null_mut(), + 0, + ); + } + if cpus < 1 { + cpus = 1; + } + } + cpus as usize + } + + #[cfg(target_os = "openbsd")] + fn num_cpus() -> usize { + use std::ptr; + + let mut cpus: libc::c_uint = 0; + let mut cpus_size = std::mem::size_of_val(&cpus); + let mut mib = [libc::CTL_HW, libc::HW_NCPU, 0, 0]; + + unsafe { + libc::sysctl( + mib.as_mut_ptr(), + 2, + &mut cpus as *mut _ as *mut _, + &mut cpus_size as *mut _ as *mut _, + ptr::null_mut(), + 0, + ); + } + if cpus < 1 { + cpus = 1; + } + cpus as usize + } + + #[cfg(target_os = "haiku")] + fn num_cpus() -> usize { + // FIXME: implement + 1 + } + + #[cfg(target_os = "l4re")] + fn num_cpus() -> usize { + // FIXME: implement + 1 + } +} + +pub fn filter_tests(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> Vec<TestDescAndFn> { + let mut filtered = tests; + let matches_filter = |test: &TestDescAndFn, filter: &str| { + let test_name = test.desc.name.as_slice(); + + match opts.filter_exact { + true => test_name == filter, + false => test_name.contains(filter), + } + }; + + // Remove tests that don't match the test filter + if let Some(ref filter) = opts.filter { + filtered.retain(|test| matches_filter(test, filter)); + } + + // Skip tests that match any of the skip filters + filtered.retain(|test| !opts.skip.iter().any(|sf| matches_filter(test, sf))); + + // Excludes #[should_panic] tests + if opts.exclude_should_panic { + filtered.retain(|test| test.desc.should_panic == ShouldPanic::No); + } + + // maybe unignore tests + match opts.run_ignored { + RunIgnored::Yes => { + filtered + .iter_mut() + .for_each(|test| test.desc.ignore = false); + } + RunIgnored::Only => { + filtered.retain(|test| test.desc.ignore); + filtered + .iter_mut() + .for_each(|test| test.desc.ignore = false); + } + RunIgnored::No => {} + } + + // Sort the tests alphabetically + filtered.sort_by(|t1, t2| t1.desc.name.as_slice().cmp(t2.desc.name.as_slice())); + + filtered +} + +pub fn convert_benchmarks_to_tests(tests: Vec<TestDescAndFn>) -> Vec<TestDescAndFn> { + // convert benchmarks to tests, if we're not benchmarking them + tests + .into_iter() + .map(|x| { + let testfn = match x.testfn { + DynBenchFn(bench) => DynTestFn(Box::new(move || { + bench::run_once(|b| __rust_begin_short_backtrace(|| bench.run(b))) + })), + StaticBenchFn(benchfn) => DynTestFn(Box::new(move || { + bench::run_once(|b| __rust_begin_short_backtrace(|| benchfn(b))) + })), + f => f, + }; + TestDescAndFn { + desc: x.desc, + testfn, + } + }) + .collect() +} + +pub fn run_test( + opts: &TestOpts, + force_ignore: bool, + test: TestDescAndFn, + monitor_ch: Sender<MonitorMsg>, + concurrency: Concurrent, +) { + let TestDescAndFn { desc, testfn } = test; + + let ignore_because_panic_abort = cfg!(target_arch = "wasm32") + && !cfg!(target_os = "emscripten") + && desc.should_panic != ShouldPanic::No; + + if force_ignore || desc.ignore || ignore_because_panic_abort { + monitor_ch.send((desc, TrIgnored, Vec::new())).unwrap(); + return; + } + + fn run_test_inner( + desc: TestDesc, + monitor_ch: Sender<MonitorMsg>, + nocapture: bool, + testfn: Box<dyn FnBox() + Send>, + concurrency: Concurrent, + ) { + // Buffer for capturing standard I/O + let data = Arc::new(Mutex::new(Vec::new())); + let data2 = data.clone(); + + let name = desc.name.clone(); + let runtest = move || { + let oldio = if !nocapture { + Some(( + io::set_print(Some(Box::new(Sink(data2.clone())))), + io::set_panic(Some(Box::new(Sink(data2)))), + )) + } else { + None + }; + + let result = catch_unwind(AssertUnwindSafe(testfn)); + + if let Some((printio, panicio)) = oldio { + io::set_print(printio); + io::set_panic(panicio); + }; + + let test_result = calc_result(&desc, result); + let stdout = data.lock().unwrap().to_vec(); + monitor_ch + .send((desc.clone(), test_result, stdout)) + .unwrap(); + }; + + // If the platform is single-threaded we're just going to run + // the test synchronously, regardless of the concurrency + // level. + let supports_threads = !cfg!(target_os = "emscripten") && !cfg!(target_arch = "wasm32"); + if concurrency == Concurrent::Yes && supports_threads { + let cfg = thread::Builder::new().name(name.as_slice().to_owned()); + cfg.spawn(runtest).unwrap(); + } else { + runtest(); + } + } + + match testfn { + DynBenchFn(bencher) => { + crate::bench::benchmark(desc, monitor_ch, opts.nocapture, |harness| { + bencher.run(harness) + }); + } + StaticBenchFn(benchfn) => { + crate::bench::benchmark(desc, monitor_ch, opts.nocapture, |harness| { + (benchfn.clone())(harness) + }); + } + DynTestFn(f) => { + let cb = move || __rust_begin_short_backtrace(f); + run_test_inner(desc, monitor_ch, opts.nocapture, Box::new(cb), concurrency) + } + StaticTestFn(f) => run_test_inner( + desc, + monitor_ch, + opts.nocapture, + Box::new(move || __rust_begin_short_backtrace(f)), + concurrency, + ), + } +} + +/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`. +#[inline(never)] +fn __rust_begin_short_backtrace<F: FnOnce()>(f: F) { + f() +} + +fn calc_result(desc: &TestDesc, task_result: Result<(), Box<dyn Any + Send>>) -> TestResult { + match (&desc.should_panic, task_result) { + (&ShouldPanic::No, Ok(())) | (&ShouldPanic::Yes, Err(_)) => TrOk, + (&ShouldPanic::YesWithMessage(msg), Err(ref err)) => { + if err + .downcast_ref::<String>() + .map(|e| &**e) + .or_else(|| err.downcast_ref::<&'static str>().map(|e| *e)) + .map(|e| e.contains(msg)) + .unwrap_or(false) + { + TrOk + } else { + if desc.allow_fail { + TrAllowedFail + } else { + TrFailedMsg(format!("Panic did not include expected string '{}'", msg)) + } + } + } + _ if desc.allow_fail => TrAllowedFail, + _ => TrFailed, + } +} + +#[derive(Clone, PartialEq)] +pub struct MetricMap(BTreeMap<String, Metric>); + +impl MetricMap { + pub fn new() -> MetricMap { + MetricMap(BTreeMap::new()) + } + + /// Insert a named `value` (+/- `noise`) metric into the map. The value + /// must be non-negative. The `noise` indicates the uncertainty of the + /// metric, which doubles as the "noise range" of acceptable + /// pairwise-regressions on this named value, when comparing from one + /// metric to the next using `compare_to_old`. + /// + /// If `noise` is positive, then it means this metric is of a value + /// you want to see grow smaller, so a change larger than `noise` in the + /// positive direction represents a regression. + /// + /// If `noise` is negative, then it means this metric is of a value + /// you want to see grow larger, so a change larger than `noise` in the + /// negative direction represents a regression. + pub fn insert_metric(&mut self, name: &str, value: f64, noise: f64) { + let m = Metric { value, noise }; + self.0.insert(name.to_owned(), m); + } + + pub fn fmt_metrics(&self) -> String { + let v = self + .0 + .iter() + .map(|(k, v)| format!("{}: {} (+/- {})", *k, v.value, v.noise)) + .collect::<Vec<_>>(); + v.join(", ") + } +} + +// Benchmarking pub use std::hint::black_box; +impl Bencher { + /// Callback for benchmark functions to run in their body. + pub fn iter<T, F>(&mut self, mut inner: F) + where + F: FnMut() -> T, + { + if self.mode == BenchMode::Single { + ns_iter_inner(&mut inner, 1); + return; + } + + self.summary = Some(iter(&mut inner)); + } + + pub fn bench<F>(&mut self, mut f: F) -> Option<stats::Summary> + where + F: FnMut(&mut Bencher), + { + f(self); + return self.summary; + } +} + +fn ns_from_dur(dur: Duration) -> u64 { + dur.as_secs() * 1_000_000_000 + (dur.subsec_nanos() as u64) +} + +fn ns_iter_inner<T, F>(inner: &mut F, k: u64) -> u64 +where + F: FnMut() -> T, +{ + let start = Instant::now(); + for _ in 0..k { + black_box(inner()); + } + return ns_from_dur(start.elapsed()); +} + +pub fn iter<T, F>(inner: &mut F) -> stats::Summary +where + F: FnMut() -> T, +{ + // Initial bench run to get ballpark figure. + let ns_single = ns_iter_inner(inner, 1); + + // Try to estimate iter count for 1ms falling back to 1m + // iterations if first run took < 1ns. + let ns_target_total = 1_000_000; // 1ms + let mut n = ns_target_total / cmp::max(1, ns_single); + + // if the first run took more than 1ms we don't want to just + // be left doing 0 iterations on every loop. The unfortunate + // side effect of not being able to do as many runs is + // automatically handled by the statistical analysis below + // (i.e., larger error bars). + n = cmp::max(1, n); + + let mut total_run = Duration::new(0, 0); + let samples: &mut [f64] = &mut [0.0_f64; 50]; + loop { + let loop_start = Instant::now(); + + for p in &mut *samples { + *p = ns_iter_inner(inner, n) as f64 / n as f64; + } + + stats::winsorize(samples, 5.0); + let summ = stats::Summary::new(samples); + + for p in &mut *samples { + let ns = ns_iter_inner(inner, 5 * n); + *p = ns as f64 / (5 * n) as f64; + } + + stats::winsorize(samples, 5.0); + let summ5 = stats::Summary::new(samples); + + let loop_run = loop_start.elapsed(); + + // If we've run for 100ms and seem to have converged to a + // stable median. + if loop_run > Duration::from_millis(100) + && summ.median_abs_dev_pct < 1.0 + && summ.median - summ5.median < summ5.median_abs_dev + { + return summ5; + } + + total_run = total_run + loop_run; + // Longest we ever run for is 3s. + if total_run > Duration::from_secs(3) { + return summ5; + } + + // If we overflow here just return the results so far. We check a + // multiplier of 10 because we're about to multiply by 2 and the + // next iteration of the loop will also multiply by 5 (to calculate + // the summ5 result) + n = match n.checked_mul(10) { + Some(_) => n * 2, + None => { + return summ5; + } + }; + } +} + +pub mod bench { + use super::{BenchMode, BenchSamples, Bencher, MonitorMsg, Sender, Sink, TestDesc, TestResult}; + use crate::stats; + use std::cmp; + use std::io; + use std::panic::{catch_unwind, AssertUnwindSafe}; + use std::sync::{Arc, Mutex}; + + pub fn benchmark<F>(desc: TestDesc, monitor_ch: Sender<MonitorMsg>, nocapture: bool, f: F) + where + F: FnMut(&mut Bencher), + { + let mut bs = Bencher { + mode: BenchMode::Auto, + summary: None, + bytes: 0, + }; + + let data = Arc::new(Mutex::new(Vec::new())); + let data2 = data.clone(); + + let oldio = if !nocapture { + Some(( + io::set_print(Some(Box::new(Sink(data2.clone())))), + io::set_panic(Some(Box::new(Sink(data2)))), + )) + } else { + None + }; + + let result = catch_unwind(AssertUnwindSafe(|| bs.bench(f))); + + if let Some((printio, panicio)) = oldio { + io::set_print(printio); + io::set_panic(panicio); + }; + + let test_result = match result { + //bs.bench(f) { + Ok(Some(ns_iter_summ)) => { + let ns_iter = cmp::max(ns_iter_summ.median as u64, 1); + let mb_s = bs.bytes * 1000 / ns_iter; + + let bs = BenchSamples { + ns_iter_summ, + mb_s: mb_s as usize, + }; + TestResult::TrBench(bs) + } + Ok(None) => { + // iter not called, so no data. + // FIXME: error in this case? + let samples: &mut [f64] = &mut [0.0_f64; 1]; + let bs = BenchSamples { + ns_iter_summ: stats::Summary::new(samples), + mb_s: 0, + }; + TestResult::TrBench(bs) + } + Err(_) => TestResult::TrFailed, + }; + + let stdout = data.lock().unwrap().to_vec(); + monitor_ch.send((desc, test_result, stdout)).unwrap(); + } + + pub fn run_once<F>(f: F) + where + F: FnMut(&mut Bencher), + { + let mut bs = Bencher { + mode: BenchMode::Single, + summary: None, + bytes: 0, + }; + bs.bench(f); + } +} + #[cfg(test)] mod tests { + use crate::bench; + use crate::test::{ + filter_tests, parse_opts, run_test, DynTestFn, DynTestName, MetricMap, RunIgnored, + ShouldPanic, StaticTestName, TestDesc, TestDescAndFn, TestOpts, TrFailed, TrFailedMsg, + TrIgnored, TrOk, + }; use crate::Bencher; - use libtest::stats::Stats; + use crate::Concurrent; + use std::sync::mpsc::channel; - #[bench] - pub fn sum_three_items(b: &mut Bencher) { - b.iter(|| { - [1e20f64, 1.5f64, -1e20f64].sum(); - }) + fn one_ignored_one_unignored_test() -> Vec<TestDescAndFn> { + vec![ + TestDescAndFn { + desc: TestDesc { + name: StaticTestName("1"), + ignore: true, + should_panic: ShouldPanic::No, + allow_fail: false, + }, + testfn: DynTestFn(Box::new(move || {})), + }, + TestDescAndFn { + desc: TestDesc { + name: StaticTestName("2"), + ignore: false, + should_panic: ShouldPanic::No, + allow_fail: false, + }, + testfn: DynTestFn(Box::new(move || {})), + }, + ] } - #[bench] - pub fn sum_many_f64(b: &mut Bencher) { - let nums = [-1e30f64, 1e60, 1e30, 1.0, -1e60]; - let v = (0..500).map(|i| nums[i % 5]).collect::<Vec<_>>(); - b.iter(|| { - v.sum(); - }) + #[test] + pub fn do_not_run_ignored_tests() { + fn f() { + panic!(); + } + let desc = TestDescAndFn { + desc: TestDesc { + name: StaticTestName("whatever"), + ignore: true, + should_panic: ShouldPanic::No, + allow_fail: false, + }, + testfn: DynTestFn(Box::new(f)), + }; + let (tx, rx) = channel(); + run_test(&TestOpts::new(), false, desc, tx, Concurrent::No); + let (_, res, _) = rx.recv().unwrap(); + assert!(res != TrOk); + } + + #[test] + pub fn ignored_tests_result_in_ignored() { + fn f() {} + let desc = TestDescAndFn { + desc: TestDesc { + name: StaticTestName("whatever"), + ignore: true, + should_panic: ShouldPanic::No, + allow_fail: false, + }, + testfn: DynTestFn(Box::new(f)), + }; + let (tx, rx) = channel(); + run_test(&TestOpts::new(), false, desc, tx, Concurrent::No); + let (_, res, _) = rx.recv().unwrap(); + assert!(res == TrIgnored); + } + + #[test] + fn test_should_panic() { + fn f() { + panic!(); + } + let desc = TestDescAndFn { + desc: TestDesc { + name: StaticTestName("whatever"), + ignore: false, + should_panic: ShouldPanic::Yes, + allow_fail: false, + }, + testfn: DynTestFn(Box::new(f)), + }; + let (tx, rx) = channel(); + run_test(&TestOpts::new(), false, desc, tx, Concurrent::No); + let (_, res, _) = rx.recv().unwrap(); + assert!(res == TrOk); + } + + #[test] + fn test_should_panic_good_message() { + fn f() { + panic!("an error message"); + } + let desc = TestDescAndFn { + desc: TestDesc { + name: StaticTestName("whatever"), + ignore: false, + should_panic: ShouldPanic::YesWithMessage("error message"), + allow_fail: false, + }, + testfn: DynTestFn(Box::new(f)), + }; + let (tx, rx) = channel(); + run_test(&TestOpts::new(), false, desc, tx, Concurrent::No); + let (_, res, _) = rx.recv().unwrap(); + assert!(res == TrOk); + } + + #[test] + fn test_should_panic_bad_message() { + fn f() { + panic!("an error message"); + } + let expected = "foobar"; + let failed_msg = "Panic did not include expected string"; + let desc = TestDescAndFn { + desc: TestDesc { + name: StaticTestName("whatever"), + ignore: false, + should_panic: ShouldPanic::YesWithMessage(expected), + allow_fail: false, + }, + testfn: DynTestFn(Box::new(f)), + }; + let (tx, rx) = channel(); + run_test(&TestOpts::new(), false, desc, tx, Concurrent::No); + let (_, res, _) = rx.recv().unwrap(); + assert!(res == TrFailedMsg(format!("{} '{}'", failed_msg, expected))); + } + + #[test] + fn test_should_panic_but_succeeds() { + fn f() {} + let desc = TestDescAndFn { + desc: TestDesc { + name: StaticTestName("whatever"), + ignore: false, + should_panic: ShouldPanic::Yes, + allow_fail: false, + }, + testfn: DynTestFn(Box::new(f)), + }; + let (tx, rx) = channel(); + run_test(&TestOpts::new(), false, desc, tx, Concurrent::No); + let (_, res, _) = rx.recv().unwrap(); + assert!(res == TrFailed); + } + + #[test] + fn parse_ignored_flag() { + let args = vec![ + "progname".to_string(), + "filter".to_string(), + "--ignored".to_string(), + ]; + let opts = parse_opts(&args).unwrap().unwrap(); + assert_eq!(opts.run_ignored, RunIgnored::Only); + } + + #[test] + fn parse_include_ignored_flag() { + let args = vec![ + "progname".to_string(), + "filter".to_string(), + "-Zunstable-options".to_string(), + "--include-ignored".to_string(), + ]; + let opts = parse_opts(&args).unwrap().unwrap(); + assert_eq!(opts.run_ignored, RunIgnored::Yes); + } + + #[test] + pub fn filter_for_ignored_option() { + // When we run ignored tests the test filter should filter out all the + // unignored tests and flip the ignore flag on the rest to false + + let mut opts = TestOpts::new(); + opts.run_tests = true; + opts.run_ignored = RunIgnored::Only; + + let tests = one_ignored_one_unignored_test(); + let filtered = filter_tests(&opts, tests); + + assert_eq!(filtered.len(), 1); + assert_eq!(filtered[0].desc.name.to_string(), "1"); + assert!(!filtered[0].desc.ignore); } - #[bench] - pub fn no_iter(_: &mut Bencher) {} + #[test] + pub fn run_include_ignored_option() { + // When we "--include-ignored" tests, the ignore flag should be set to false on + // all tests and no test filtered out + + let mut opts = TestOpts::new(); + opts.run_tests = true; + opts.run_ignored = RunIgnored::Yes; + + let tests = one_ignored_one_unignored_test(); + let filtered = filter_tests(&opts, tests); + + assert_eq!(filtered.len(), 2); + assert!(!filtered[0].desc.ignore); + assert!(!filtered[1].desc.ignore); + } + + #[test] + pub fn exclude_should_panic_option() { + let mut opts = TestOpts::new(); + opts.run_tests = true; + opts.exclude_should_panic = true; + + let mut tests = one_ignored_one_unignored_test(); + tests.push(TestDescAndFn { + desc: TestDesc { + name: StaticTestName("3"), + ignore: false, + should_panic: ShouldPanic::Yes, + allow_fail: false, + }, + testfn: DynTestFn(Box::new(move || {})), + }); + + let filtered = filter_tests(&opts, tests); + + assert_eq!(filtered.len(), 2); + assert!(filtered.iter().all(|test| test.desc.should_panic == ShouldPanic::No)); + } + + #[test] + pub fn exact_filter_match() { + fn tests() -> Vec<TestDescAndFn> { + vec!["base", "base::test", "base::test1", "base::test2"] + .into_iter() + .map(|name| TestDescAndFn { + desc: TestDesc { + name: StaticTestName(name), + ignore: false, + should_panic: ShouldPanic::No, + allow_fail: false, + }, + testfn: DynTestFn(Box::new(move || {})), + }) + .collect() + } + + let substr = filter_tests( + &TestOpts { + filter: Some("base".into()), + ..TestOpts::new() + }, + tests(), + ); + assert_eq!(substr.len(), 4); + + let substr = filter_tests( + &TestOpts { + filter: Some("bas".into()), + ..TestOpts::new() + }, + tests(), + ); + assert_eq!(substr.len(), 4); + + let substr = filter_tests( + &TestOpts { + filter: Some("::test".into()), + ..TestOpts::new() + }, + tests(), + ); + assert_eq!(substr.len(), 3); + + let substr = filter_tests( + &TestOpts { + filter: Some("base::test".into()), + ..TestOpts::new() + }, + tests(), + ); + assert_eq!(substr.len(), 3); + + let exact = filter_tests( + &TestOpts { + filter: Some("base".into()), + filter_exact: true, + ..TestOpts::new() + }, + tests(), + ); + assert_eq!(exact.len(), 1); + + let exact = filter_tests( + &TestOpts { + filter: Some("bas".into()), + filter_exact: true, + ..TestOpts::new() + }, + tests(), + ); + assert_eq!(exact.len(), 0); + + let exact = filter_tests( + &TestOpts { + filter: Some("::test".into()), + filter_exact: true, + ..TestOpts::new() + }, + tests(), + ); + assert_eq!(exact.len(), 0); + + let exact = filter_tests( + &TestOpts { + filter: Some("base::test".into()), + filter_exact: true, + ..TestOpts::new() + }, + tests(), + ); + assert_eq!(exact.len(), 1); + } + + #[test] + pub fn sort_tests() { + let mut opts = TestOpts::new(); + opts.run_tests = true; + + let names = vec![ + "sha1::test".to_string(), + "isize::test_to_str".to_string(), + "isize::test_pow".to_string(), + "test::do_not_run_ignored_tests".to_string(), + "test::ignored_tests_result_in_ignored".to_string(), + "test::first_free_arg_should_be_a_filter".to_string(), + "test::parse_ignored_flag".to_string(), + "test::parse_include_ignored_flag".to_string(), + "test::filter_for_ignored_option".to_string(), + "test::run_include_ignored_option".to_string(), + "test::sort_tests".to_string(), + ]; + let tests = { + fn testfn() {} + let mut tests = Vec::new(); + for name in &names { + let test = TestDescAndFn { + desc: TestDesc { + name: DynTestName((*name).clone()), + ignore: false, + should_panic: ShouldPanic::No, + allow_fail: false, + }, + testfn: DynTestFn(Box::new(testfn)), + }; + tests.push(test); + } + tests + }; + let filtered = filter_tests(&opts, tests); + + let expected = vec![ + "isize::test_pow".to_string(), + "isize::test_to_str".to_string(), + "sha1::test".to_string(), + "test::do_not_run_ignored_tests".to_string(), + "test::filter_for_ignored_option".to_string(), + "test::first_free_arg_should_be_a_filter".to_string(), + "test::ignored_tests_result_in_ignored".to_string(), + "test::parse_ignored_flag".to_string(), + "test::parse_include_ignored_flag".to_string(), + "test::run_include_ignored_option".to_string(), + "test::sort_tests".to_string(), + ]; + + for (a, b) in expected.iter().zip(filtered) { + assert!(*a == b.desc.name.to_string()); + } + } + + #[test] + pub fn test_metricmap_compare() { + let mut m1 = MetricMap::new(); + let mut m2 = MetricMap::new(); + m1.insert_metric("in-both-noise", 1000.0, 200.0); + m2.insert_metric("in-both-noise", 1100.0, 200.0); + + m1.insert_metric("in-first-noise", 1000.0, 2.0); + m2.insert_metric("in-second-noise", 1000.0, 2.0); + + m1.insert_metric("in-both-want-downwards-but-regressed", 1000.0, 10.0); + m2.insert_metric("in-both-want-downwards-but-regressed", 2000.0, 10.0); + + m1.insert_metric("in-both-want-downwards-and-improved", 2000.0, 10.0); + m2.insert_metric("in-both-want-downwards-and-improved", 1000.0, 10.0); + + m1.insert_metric("in-both-want-upwards-but-regressed", 2000.0, -10.0); + m2.insert_metric("in-both-want-upwards-but-regressed", 1000.0, -10.0); + + m1.insert_metric("in-both-want-upwards-and-improved", 1000.0, -10.0); + m2.insert_metric("in-both-want-upwards-and-improved", 2000.0, -10.0); + } + + #[test] + pub fn test_bench_once_no_iter() { + fn f(_: &mut Bencher) {} + bench::run_once(f); + } + + #[test] + pub fn test_bench_once_iter() { + fn f(b: &mut Bencher) { + b.iter(|| {}) + } + bench::run_once(f); + } + + #[test] + pub fn test_bench_no_iter() { + fn f(_: &mut Bencher) {} + + let (tx, rx) = channel(); + + let desc = TestDesc { + name: StaticTestName("f"), + ignore: false, + should_panic: ShouldPanic::No, + allow_fail: false, + }; + + crate::bench::benchmark(desc, tx, true, f); + rx.recv().unwrap(); + } + + #[test] + pub fn test_bench_iter() { + fn f(b: &mut Bencher) { + b.iter(|| {}) + } + + let (tx, rx) = channel(); + + let desc = TestDesc { + name: StaticTestName("f"), + ignore: false, + should_panic: ShouldPanic::No, + allow_fail: false, + }; + + crate::bench::benchmark(desc, tx, true, f); + rx.recv().unwrap(); + } } diff --git a/src/libtest/stats.rs b/src/libtest/stats.rs new file mode 100644 index 00000000000..5c9421d5ea4 --- /dev/null +++ b/src/libtest/stats.rs @@ -0,0 +1,922 @@ +#![allow(missing_docs)] +#![allow(deprecated)] // Float + +use std::cmp::Ordering::{self, Equal, Greater, Less}; +use std::mem; + +fn local_cmp(x: f64, y: f64) -> Ordering { + // arbitrarily decide that NaNs are larger than everything. + if y.is_nan() { + Less + } else if x.is_nan() { + Greater + } else if x < y { + Less + } else if x == y { + Equal + } else { + Greater + } +} + +fn local_sort(v: &mut [f64]) { + v.sort_by(|x: &f64, y: &f64| local_cmp(*x, *y)); +} + +/// Trait that provides simple descriptive statistics on a univariate set of numeric samples. +pub trait Stats { + /// Sum of the samples. + /// + /// Note: this method sacrifices performance at the altar of accuracy + /// Depends on IEEE-754 arithmetic guarantees. See proof of correctness at: + /// ["Adaptive Precision Floating-Point Arithmetic and Fast Robust Geometric + /// Predicates"][paper] + /// + /// [paper]: http://www.cs.cmu.edu/~quake-papers/robust-arithmetic.ps + fn sum(&self) -> f64; + + /// Minimum value of the samples. + fn min(&self) -> f64; + + /// Maximum value of the samples. + fn max(&self) -> f64; + + /// Arithmetic mean (average) of the samples: sum divided by sample-count. + /// + /// See: <https://en.wikipedia.org/wiki/Arithmetic_mean> + fn mean(&self) -> f64; + + /// Median of the samples: value separating the lower half of the samples from the higher half. + /// Equal to `self.percentile(50.0)`. + /// + /// See: <https://en.wikipedia.org/wiki/Median> + fn median(&self) -> f64; + + /// Variance of the samples: bias-corrected mean of the squares of the differences of each + /// sample from the sample mean. Note that this calculates the _sample variance_ rather than the + /// population variance, which is assumed to be unknown. It therefore corrects the `(n-1)/n` + /// bias that would appear if we calculated a population variance, by dividing by `(n-1)` rather + /// than `n`. + /// + /// See: <https://en.wikipedia.org/wiki/Variance> + fn var(&self) -> f64; + + /// Standard deviation: the square root of the sample variance. + /// + /// Note: this is not a robust statistic for non-normal distributions. Prefer the + /// `median_abs_dev` for unknown distributions. + /// + /// See: <https://en.wikipedia.org/wiki/Standard_deviation> + fn std_dev(&self) -> f64; + + /// Standard deviation as a percent of the mean value. See `std_dev` and `mean`. + /// + /// Note: this is not a robust statistic for non-normal distributions. Prefer the + /// `median_abs_dev_pct` for unknown distributions. + fn std_dev_pct(&self) -> f64; + + /// Scaled median of the absolute deviations of each sample from the sample median. This is a + /// robust (distribution-agnostic) estimator of sample variability. Use this in preference to + /// `std_dev` if you cannot assume your sample is normally distributed. Note that this is scaled + /// by the constant `1.4826` to allow its use as a consistent estimator for the standard + /// deviation. + /// + /// See: <http://en.wikipedia.org/wiki/Median_absolute_deviation> + fn median_abs_dev(&self) -> f64; + + /// Median absolute deviation as a percent of the median. See `median_abs_dev` and `median`. + fn median_abs_dev_pct(&self) -> f64; + + /// Percentile: the value below which `pct` percent of the values in `self` fall. For example, + /// percentile(95.0) will return the value `v` such that 95% of the samples `s` in `self` + /// satisfy `s <= v`. + /// + /// Calculated by linear interpolation between closest ranks. + /// + /// See: <http://en.wikipedia.org/wiki/Percentile> + fn percentile(&self, pct: f64) -> f64; + + /// Quartiles of the sample: three values that divide the sample into four equal groups, each + /// with 1/4 of the data. The middle value is the median. See `median` and `percentile`. This + /// function may calculate the 3 quartiles more efficiently than 3 calls to `percentile`, but + /// is otherwise equivalent. + /// + /// See also: <https://en.wikipedia.org/wiki/Quartile> + fn quartiles(&self) -> (f64, f64, f64); + + /// Inter-quartile range: the difference between the 25th percentile (1st quartile) and the 75th + /// percentile (3rd quartile). See `quartiles`. + /// + /// See also: <https://en.wikipedia.org/wiki/Interquartile_range> + fn iqr(&self) -> f64; +} + +/// Extracted collection of all the summary statistics of a sample set. +#[derive(Clone, PartialEq, Copy)] +#[allow(missing_docs)] +pub struct Summary { + pub sum: f64, + pub min: f64, + pub max: f64, + pub mean: f64, + pub median: f64, + pub var: f64, + pub std_dev: f64, + pub std_dev_pct: f64, + pub median_abs_dev: f64, + pub median_abs_dev_pct: f64, + pub quartiles: (f64, f64, f64), + pub iqr: f64, +} + +impl Summary { + /// Construct a new summary of a sample set. + pub fn new(samples: &[f64]) -> Summary { + Summary { + sum: samples.sum(), + min: samples.min(), + max: samples.max(), + mean: samples.mean(), + median: samples.median(), + var: samples.var(), + std_dev: samples.std_dev(), + std_dev_pct: samples.std_dev_pct(), + median_abs_dev: samples.median_abs_dev(), + median_abs_dev_pct: samples.median_abs_dev_pct(), + quartiles: samples.quartiles(), + iqr: samples.iqr(), + } + } +} + +impl Stats for [f64] { + // FIXME #11059 handle NaN, inf and overflow + fn sum(&self) -> f64 { + let mut partials = vec![]; + + for &x in self { + let mut x = x; + let mut j = 0; + // This inner loop applies `hi`/`lo` summation to each + // partial so that the list of partial sums remains exact. + for i in 0..partials.len() { + let mut y: f64 = partials[i]; + if x.abs() < y.abs() { + mem::swap(&mut x, &mut y); + } + // Rounded `x+y` is stored in `hi` with round-off stored in + // `lo`. Together `hi+lo` are exactly equal to `x+y`. + let hi = x + y; + let lo = y - (hi - x); + if lo != 0.0 { + partials[j] = lo; + j += 1; + } + x = hi; + } + if j >= partials.len() { + partials.push(x); + } else { + partials[j] = x; + partials.truncate(j + 1); + } + } + let zero: f64 = 0.0; + partials.iter().fold(zero, |p, q| p + *q) + } + + fn min(&self) -> f64 { + assert!(!self.is_empty()); + self.iter().fold(self[0], |p, q| p.min(*q)) + } + + fn max(&self) -> f64 { + assert!(!self.is_empty()); + self.iter().fold(self[0], |p, q| p.max(*q)) + } + + fn mean(&self) -> f64 { + assert!(!self.is_empty()); + self.sum() / (self.len() as f64) + } + + fn median(&self) -> f64 { + self.percentile(50 as f64) + } + + fn var(&self) -> f64 { + if self.len() < 2 { + 0.0 + } else { + let mean = self.mean(); + let mut v: f64 = 0.0; + for s in self { + let x = *s - mean; + v = v + x * x; + } + // N.B., this is _supposed to be_ len-1, not len. If you + // change it back to len, you will be calculating a + // population variance, not a sample variance. + let denom = (self.len() - 1) as f64; + v / denom + } + } + + fn std_dev(&self) -> f64 { + self.var().sqrt() + } + + fn std_dev_pct(&self) -> f64 { + let hundred = 100 as f64; + (self.std_dev() / self.mean()) * hundred + } + + fn median_abs_dev(&self) -> f64 { + let med = self.median(); + let abs_devs: Vec<f64> = self.iter().map(|&v| (med - v).abs()).collect(); + // This constant is derived by smarter statistics brains than me, but it is + // consistent with how R and other packages treat the MAD. + let number = 1.4826; + abs_devs.median() * number + } + + fn median_abs_dev_pct(&self) -> f64 { + let hundred = 100 as f64; + (self.median_abs_dev() / self.median()) * hundred + } + + fn percentile(&self, pct: f64) -> f64 { + let mut tmp = self.to_vec(); + local_sort(&mut tmp); + percentile_of_sorted(&tmp, pct) + } + + fn quartiles(&self) -> (f64, f64, f64) { + let mut tmp = self.to_vec(); + local_sort(&mut tmp); + let first = 25f64; + let a = percentile_of_sorted(&tmp, first); + let second = 50f64; + let b = percentile_of_sorted(&tmp, second); + let third = 75f64; + let c = percentile_of_sorted(&tmp, third); + (a, b, c) + } + + fn iqr(&self) -> f64 { + let (a, _, c) = self.quartiles(); + c - a + } +} + +// Helper function: extract a value representing the `pct` percentile of a sorted sample-set, using +// linear interpolation. If samples are not sorted, return nonsensical value. +fn percentile_of_sorted(sorted_samples: &[f64], pct: f64) -> f64 { + assert!(!sorted_samples.is_empty()); + if sorted_samples.len() == 1 { + return sorted_samples[0]; + } + let zero: f64 = 0.0; + assert!(zero <= pct); + let hundred = 100f64; + assert!(pct <= hundred); + if pct == hundred { + return sorted_samples[sorted_samples.len() - 1]; + } + let length = (sorted_samples.len() - 1) as f64; + let rank = (pct / hundred) * length; + let lrank = rank.floor(); + let d = rank - lrank; + let n = lrank as usize; + let lo = sorted_samples[n]; + let hi = sorted_samples[n + 1]; + lo + (hi - lo) * d +} + +/// Winsorize a set of samples, replacing values above the `100-pct` percentile +/// and below the `pct` percentile with those percentiles themselves. This is a +/// way of minimizing the effect of outliers, at the cost of biasing the sample. +/// It differs from trimming in that it does not change the number of samples, +/// just changes the values of those that are outliers. +/// +/// See: <http://en.wikipedia.org/wiki/Winsorising> +pub fn winsorize(samples: &mut [f64], pct: f64) { + let mut tmp = samples.to_vec(); + local_sort(&mut tmp); + let lo = percentile_of_sorted(&tmp, pct); + let hundred = 100 as f64; + let hi = percentile_of_sorted(&tmp, hundred - pct); + for samp in samples { + if *samp > hi { + *samp = hi + } else if *samp < lo { + *samp = lo + } + } +} + +// Test vectors generated from R, using the script src/etc/stat-test-vectors.r. + +#[cfg(test)] +mod tests { + use crate::stats::Stats; + use crate::stats::Summary; + use std::f64; + use std::io::prelude::*; + use std::io; + + macro_rules! assert_approx_eq { + ($a: expr, $b: expr) => {{ + let (a, b) = (&$a, &$b); + assert!( + (*a - *b).abs() < 1.0e-6, + "{} is not approximately equal to {}", + *a, + *b + ); + }}; + } + + fn check(samples: &[f64], summ: &Summary) { + let summ2 = Summary::new(samples); + + let mut w = io::sink(); + let w = &mut w; + (write!(w, "\n")).unwrap(); + + assert_eq!(summ.sum, summ2.sum); + assert_eq!(summ.min, summ2.min); + assert_eq!(summ.max, summ2.max); + assert_eq!(summ.mean, summ2.mean); + assert_eq!(summ.median, summ2.median); + + // We needed a few more digits to get exact equality on these + // but they're within float epsilon, which is 1.0e-6. + assert_approx_eq!(summ.var, summ2.var); + assert_approx_eq!(summ.std_dev, summ2.std_dev); + assert_approx_eq!(summ.std_dev_pct, summ2.std_dev_pct); + assert_approx_eq!(summ.median_abs_dev, summ2.median_abs_dev); + assert_approx_eq!(summ.median_abs_dev_pct, summ2.median_abs_dev_pct); + + assert_eq!(summ.quartiles, summ2.quartiles); + assert_eq!(summ.iqr, summ2.iqr); + } + + #[test] + fn test_min_max_nan() { + let xs = &[1.0, 2.0, f64::NAN, 3.0, 4.0]; + let summary = Summary::new(xs); + assert_eq!(summary.min, 1.0); + assert_eq!(summary.max, 4.0); + } + + #[test] + fn test_norm2() { + let val = &[958.0000000000, 924.0000000000]; + let summ = &Summary { + sum: 1882.0000000000, + min: 924.0000000000, + max: 958.0000000000, + mean: 941.0000000000, + median: 941.0000000000, + var: 578.0000000000, + std_dev: 24.0416305603, + std_dev_pct: 2.5549022912, + median_abs_dev: 25.2042000000, + median_abs_dev_pct: 2.6784484591, + quartiles: (932.5000000000, 941.0000000000, 949.5000000000), + iqr: 17.0000000000, + }; + check(val, summ); + } + #[test] + fn test_norm10narrow() { + let val = &[ + 966.0000000000, + 985.0000000000, + 1110.0000000000, + 848.0000000000, + 821.0000000000, + 975.0000000000, + 962.0000000000, + 1157.0000000000, + 1217.0000000000, + 955.0000000000, + ]; + let summ = &Summary { + sum: 9996.0000000000, + min: 821.0000000000, + max: 1217.0000000000, + mean: 999.6000000000, + median: 970.5000000000, + var: 16050.7111111111, + std_dev: 126.6914010938, + std_dev_pct: 12.6742097933, + median_abs_dev: 102.2994000000, + median_abs_dev_pct: 10.5408964451, + quartiles: (956.7500000000, 970.5000000000, 1078.7500000000), + iqr: 122.0000000000, + }; + check(val, summ); + } + #[test] + fn test_norm10medium() { + let val = &[ + 954.0000000000, + 1064.0000000000, + 855.0000000000, + 1000.0000000000, + 743.0000000000, + 1084.0000000000, + 704.0000000000, + 1023.0000000000, + 357.0000000000, + 869.0000000000, + ]; + let summ = &Summary { + sum: 8653.0000000000, + min: 357.0000000000, + max: 1084.0000000000, + mean: 865.3000000000, + median: 911.5000000000, + var: 48628.4555555556, + std_dev: 220.5186059170, + std_dev_pct: 25.4846418487, + median_abs_dev: 195.7032000000, + median_abs_dev_pct: 21.4704552935, + quartiles: (771.0000000000, 911.5000000000, 1017.2500000000), + iqr: 246.2500000000, + }; + check(val, summ); + } + #[test] + fn test_norm10wide() { + let val = &[ + 505.0000000000, + 497.0000000000, + 1591.0000000000, + 887.0000000000, + 1026.0000000000, + 136.0000000000, + 1580.0000000000, + 940.0000000000, + 754.0000000000, + 1433.0000000000, + ]; + let summ = &Summary { + sum: 9349.0000000000, + min: 136.0000000000, + max: 1591.0000000000, + mean: 934.9000000000, + median: 913.5000000000, + var: 239208.9888888889, + std_dev: 489.0899599142, + std_dev_pct: 52.3146817750, + median_abs_dev: 611.5725000000, + median_abs_dev_pct: 66.9482758621, + quartiles: (567.2500000000, 913.5000000000, 1331.2500000000), + iqr: 764.0000000000, + }; + check(val, summ); + } + #[test] + fn test_norm25verynarrow() { + let val = &[ + 991.0000000000, + 1018.0000000000, + 998.0000000000, + 1013.0000000000, + 974.0000000000, + 1007.0000000000, + 1014.0000000000, + 999.0000000000, + 1011.0000000000, + 978.0000000000, + 985.0000000000, + 999.0000000000, + 983.0000000000, + 982.0000000000, + 1015.0000000000, + 1002.0000000000, + 977.0000000000, + 948.0000000000, + 1040.0000000000, + 974.0000000000, + 996.0000000000, + 989.0000000000, + 1015.0000000000, + 994.0000000000, + 1024.0000000000, + ]; + let summ = &Summary { + sum: 24926.0000000000, + min: 948.0000000000, + max: 1040.0000000000, + mean: 997.0400000000, + median: 998.0000000000, + var: 393.2066666667, + std_dev: 19.8294393937, + std_dev_pct: 1.9888308788, + median_abs_dev: 22.2390000000, + median_abs_dev_pct: 2.2283567134, + quartiles: (983.0000000000, 998.0000000000, 1013.0000000000), + iqr: 30.0000000000, + }; + check(val, summ); + } + #[test] + fn test_exp10a() { + let val = &[ + 23.0000000000, + 11.0000000000, + 2.0000000000, + 57.0000000000, + 4.0000000000, + 12.0000000000, + 5.0000000000, + 29.0000000000, + 3.0000000000, + 21.0000000000, + ]; + let summ = &Summary { + sum: 167.0000000000, + min: 2.0000000000, + max: 57.0000000000, + mean: 16.7000000000, + median: 11.5000000000, + var: 287.7888888889, + std_dev: 16.9643416875, + std_dev_pct: 101.5828843560, + median_abs_dev: 13.3434000000, + median_abs_dev_pct: 116.0295652174, + quartiles: (4.2500000000, 11.5000000000, 22.5000000000), + iqr: 18.2500000000, + }; + check(val, summ); + } + #[test] + fn test_exp10b() { + let val = &[ + 24.0000000000, + 17.0000000000, + 6.0000000000, + 38.0000000000, + 25.0000000000, + 7.0000000000, + 51.0000000000, + 2.0000000000, + 61.0000000000, + 32.0000000000, + ]; + let summ = &Summary { + sum: 263.0000000000, + min: 2.0000000000, + max: 61.0000000000, + mean: 26.3000000000, + median: 24.5000000000, + var: 383.5666666667, + std_dev: 19.5848580967, + std_dev_pct: 74.4671410520, + median_abs_dev: 22.9803000000, + median_abs_dev_pct: 93.7971428571, + quartiles: (9.5000000000, 24.5000000000, 36.5000000000), + iqr: 27.0000000000, + }; + check(val, summ); + } + #[test] + fn test_exp10c() { + let val = &[ + 71.0000000000, + 2.0000000000, + 32.0000000000, + 1.0000000000, + 6.0000000000, + 28.0000000000, + 13.0000000000, + 37.0000000000, + 16.0000000000, + 36.0000000000, + ]; + let summ = &Summary { + sum: 242.0000000000, + min: 1.0000000000, + max: 71.0000000000, + mean: 24.2000000000, + median: 22.0000000000, + var: 458.1777777778, + std_dev: 21.4050876611, + std_dev_pct: 88.4507754589, + median_abs_dev: 21.4977000000, + median_abs_dev_pct: 97.7168181818, + quartiles: (7.7500000000, 22.0000000000, 35.0000000000), + iqr: 27.2500000000, + }; + check(val, summ); + } + #[test] + fn test_exp25() { + let val = &[ + 3.0000000000, + 24.0000000000, + 1.0000000000, + 19.0000000000, + 7.0000000000, + 5.0000000000, + 30.0000000000, + 39.0000000000, + 31.0000000000, + 13.0000000000, + 25.0000000000, + 48.0000000000, + 1.0000000000, + 6.0000000000, + 42.0000000000, + 63.0000000000, + 2.0000000000, + 12.0000000000, + 108.0000000000, + 26.0000000000, + 1.0000000000, + 7.0000000000, + 44.0000000000, + 25.0000000000, + 11.0000000000, + ]; + let summ = &Summary { + sum: 593.0000000000, + min: 1.0000000000, + max: 108.0000000000, + mean: 23.7200000000, + median: 19.0000000000, + var: 601.0433333333, + std_dev: 24.5161851301, + std_dev_pct: 103.3565983562, + median_abs_dev: 19.2738000000, + median_abs_dev_pct: 101.4410526316, + quartiles: (6.0000000000, 19.0000000000, 31.0000000000), + iqr: 25.0000000000, + }; + check(val, summ); + } + #[test] + fn test_binom25() { + let val = &[ + 18.0000000000, + 17.0000000000, + 27.0000000000, + 15.0000000000, + 21.0000000000, + 25.0000000000, + 17.0000000000, + 24.0000000000, + 25.0000000000, + 24.0000000000, + 26.0000000000, + 26.0000000000, + 23.0000000000, + 15.0000000000, + 23.0000000000, + 17.0000000000, + 18.0000000000, + 18.0000000000, + 21.0000000000, + 16.0000000000, + 15.0000000000, + 31.0000000000, + 20.0000000000, + 17.0000000000, + 15.0000000000, + ]; + let summ = &Summary { + sum: 514.0000000000, + min: 15.0000000000, + max: 31.0000000000, + mean: 20.5600000000, + median: 20.0000000000, + var: 20.8400000000, + std_dev: 4.5650848842, + std_dev_pct: 22.2037202539, + median_abs_dev: 5.9304000000, + median_abs_dev_pct: 29.6520000000, + quartiles: (17.0000000000, 20.0000000000, 24.0000000000), + iqr: 7.0000000000, + }; + check(val, summ); + } + #[test] + fn test_pois25lambda30() { + let val = &[ + 27.0000000000, + 33.0000000000, + 34.0000000000, + 34.0000000000, + 24.0000000000, + 39.0000000000, + 28.0000000000, + 27.0000000000, + 31.0000000000, + 28.0000000000, + 38.0000000000, + 21.0000000000, + 33.0000000000, + 36.0000000000, + 29.0000000000, + 37.0000000000, + 32.0000000000, + 34.0000000000, + 31.0000000000, + 39.0000000000, + 25.0000000000, + 31.0000000000, + 32.0000000000, + 40.0000000000, + 24.0000000000, + ]; + let summ = &Summary { + sum: 787.0000000000, + min: 21.0000000000, + max: 40.0000000000, + mean: 31.4800000000, + median: 32.0000000000, + var: 26.5933333333, + std_dev: 5.1568724372, + std_dev_pct: 16.3814245145, + median_abs_dev: 5.9304000000, + median_abs_dev_pct: 18.5325000000, + quartiles: (28.0000000000, 32.0000000000, 34.0000000000), + iqr: 6.0000000000, + }; + check(val, summ); + } + #[test] + fn test_pois25lambda40() { + let val = &[ + 42.0000000000, + 50.0000000000, + 42.0000000000, + 46.0000000000, + 34.0000000000, + 45.0000000000, + 34.0000000000, + 49.0000000000, + 39.0000000000, + 28.0000000000, + 40.0000000000, + 35.0000000000, + 37.0000000000, + 39.0000000000, + 46.0000000000, + 44.0000000000, + 32.0000000000, + 45.0000000000, + 42.0000000000, + 37.0000000000, + 48.0000000000, + 42.0000000000, + 33.0000000000, + 42.0000000000, + 48.0000000000, + ]; + let summ = &Summary { + sum: 1019.0000000000, + min: 28.0000000000, + max: 50.0000000000, + mean: 40.7600000000, + median: 42.0000000000, + var: 34.4400000000, + std_dev: 5.8685603004, + std_dev_pct: 14.3978417577, + median_abs_dev: 5.9304000000, + median_abs_dev_pct: 14.1200000000, + quartiles: (37.0000000000, 42.0000000000, 45.0000000000), + iqr: 8.0000000000, + }; + check(val, summ); + } + #[test] + fn test_pois25lambda50() { + let val = &[ + 45.0000000000, + 43.0000000000, + 44.0000000000, + 61.0000000000, + 51.0000000000, + 53.0000000000, + 59.0000000000, + 52.0000000000, + 49.0000000000, + 51.0000000000, + 51.0000000000, + 50.0000000000, + 49.0000000000, + 56.0000000000, + 42.0000000000, + 52.0000000000, + 51.0000000000, + 43.0000000000, + 48.0000000000, + 48.0000000000, + 50.0000000000, + 42.0000000000, + 43.0000000000, + 42.0000000000, + 60.0000000000, + ]; + let summ = &Summary { + sum: 1235.0000000000, + min: 42.0000000000, + max: 61.0000000000, + mean: 49.4000000000, + median: 50.0000000000, + var: 31.6666666667, + std_dev: 5.6273143387, + std_dev_pct: 11.3913245723, + median_abs_dev: 4.4478000000, + median_abs_dev_pct: 8.8956000000, + quartiles: (44.0000000000, 50.0000000000, 52.0000000000), + iqr: 8.0000000000, + }; + check(val, summ); + } + #[test] + fn test_unif25() { + let val = &[ + 99.0000000000, + 55.0000000000, + 92.0000000000, + 79.0000000000, + 14.0000000000, + 2.0000000000, + 33.0000000000, + 49.0000000000, + 3.0000000000, + 32.0000000000, + 84.0000000000, + 59.0000000000, + 22.0000000000, + 86.0000000000, + 76.0000000000, + 31.0000000000, + 29.0000000000, + 11.0000000000, + 41.0000000000, + 53.0000000000, + 45.0000000000, + 44.0000000000, + 98.0000000000, + 98.0000000000, + 7.0000000000, + ]; + let summ = &Summary { + sum: 1242.0000000000, + min: 2.0000000000, + max: 99.0000000000, + mean: 49.6800000000, + median: 45.0000000000, + var: 1015.6433333333, + std_dev: 31.8691595957, + std_dev_pct: 64.1488719719, + median_abs_dev: 45.9606000000, + median_abs_dev_pct: 102.1346666667, + quartiles: (29.0000000000, 45.0000000000, 79.0000000000), + iqr: 50.0000000000, + }; + check(val, summ); + } + + #[test] + fn test_sum_f64s() { + assert_eq!([0.5f64, 3.2321f64, 1.5678f64].sum(), 5.2999); + } + #[test] + fn test_sum_f64_between_ints_that_sum_to_0() { + assert_eq!([1e30f64, 1.2f64, -1e30f64].sum(), 1.2); + } +} + +#[cfg(test)] +mod bench { + extern crate test; + use self::test::Bencher; + use crate::stats::Stats; + + #[bench] + pub fn sum_three_items(b: &mut Bencher) { + b.iter(|| { + [1e20f64, 1.5f64, -1e20f64].sum(); + }) + } + #[bench] + pub fn sum_many_f64(b: &mut Bencher) { + let nums = [-1e30f64, 1e60, 1e30, 1.0, -1e60]; + let v = (0..500).map(|i| nums[i % 5]).collect::<Vec<_>>(); + + b.iter(|| { + v.sum(); + }) + } + + #[bench] + pub fn no_iter(_: &mut Bencher) {} +} diff --git a/src/libunwind/Cargo.toml b/src/libunwind/Cargo.toml index 2378b0a315a..4ddc878997e 100644 --- a/src/libunwind/Cargo.toml +++ b/src/libunwind/Cargo.toml @@ -4,6 +4,9 @@ name = "unwind" version = "0.0.0" build = "build.rs" edition = "2018" +include = [ + '/libunwind/*', +] [lib] name = "unwind" @@ -16,3 +19,9 @@ doc = false core = { path = "../libcore" } libc = { version = "0.2.43", features = ['rustc-dep-of-std'], default-features = false } compiler_builtins = "0.1.0" + +[build-dependencies] +cc = { optional = true, version = "1.0.1" } + +[features] +llvm-libunwind = ["cc"] diff --git a/src/libunwind/build.rs b/src/libunwind/build.rs index b50a11fa03a..f3fda9eaa75 100644 --- a/src/libunwind/build.rs +++ b/src/libunwind/build.rs @@ -4,7 +4,13 @@ fn main() { println!("cargo:rerun-if-changed=build.rs"); let target = env::var("TARGET").expect("TARGET was not set"); - if target.contains("linux") { + if cfg!(feature = "llvm-libunwind") && + (target.contains("linux") || + target.contains("fuchsia")) { + // Build the unwinding from libunwind C/C++ source code. + #[cfg(feature = "llvm-libunwind")] + llvm_libunwind::compile(); + } else if target.contains("linux") { if target.contains("musl") { // musl is handled in lib.rs } else if !target.contains("android") { @@ -37,3 +43,62 @@ fn main() { println!("cargo:rustc-link-lib=unwind"); } } + +#[cfg(feature = "llvm-libunwind")] +mod llvm_libunwind { + use std::env; + use std::path::Path; + + /// Compile the libunwind C/C++ source code. + pub fn compile() { + let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap(); + let target_vendor = env::var("CARGO_CFG_TARGET_VENDOR").unwrap(); + let cfg = &mut cc::Build::new(); + + cfg.cpp(true); + cfg.cpp_set_stdlib(None); + cfg.warnings(false); + + if target_env == "msvc" { + // Don't pull in extra libraries on MSVC + cfg.flag("/Zl"); + cfg.flag("/EHsc"); + cfg.define("_CRT_SECURE_NO_WARNINGS", None); + cfg.define("_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS", None); + } else { + cfg.flag("-std=c99"); + cfg.flag("-std=c++11"); + cfg.flag("-nostdinc++"); + if cfg.is_flag_supported("-funwind-tables").unwrap_or_default() && + cfg.is_flag_supported("-fno-exceptions").unwrap_or_default() { + cfg.flag("-funwind-tables"); + cfg.flag("-fno-exceptions"); + } + cfg.flag("-fno-rtti"); + cfg.flag("-fstrict-aliasing"); + } + + let mut unwind_sources = vec![ + "Unwind-EHABI.cpp", + "Unwind-seh.cpp", + "Unwind-sjlj.c", + "UnwindLevel1-gcc-ext.c", + "UnwindLevel1.c", + "UnwindRegistersRestore.S", + "UnwindRegistersSave.S", + "libunwind.cpp", + ]; + + if target_vendor == "apple" { + unwind_sources.push("Unwind_AppleExtras.cpp"); + } + + let root = Path::new("../llvm-project/libunwind"); + cfg.include(root.join("include")); + for src in unwind_sources { + cfg.file(root.join("src").join(src)); + } + + cfg.compile("unwind"); + } +} diff --git a/src/llvm-project b/src/llvm-project -Subproject 1f484cbe0e863e9e215f1b3d7198063444d6087 +Subproject 84abffda0e03b03c62bdfc3cfeda1c2cf1f88c8 diff --git a/src/rustllvm/ArchiveWrapper.cpp b/src/rustllvm/ArchiveWrapper.cpp index 65975ec574c..dd0111d3f2c 100644 --- a/src/rustllvm/ArchiveWrapper.cpp +++ b/src/rustllvm/ArchiveWrapper.cpp @@ -24,9 +24,14 @@ struct RustArchiveIterator { bool First; Archive::child_iterator Cur; Archive::child_iterator End; - Error Err; - - RustArchiveIterator() : First(true), Err(Error::success()) {} + std::unique_ptr<Error> Err; + + RustArchiveIterator(Archive::child_iterator Cur, Archive::child_iterator End, + std::unique_ptr<Error> Err) + : First(true), + Cur(Cur), + End(End), + Err(std::move(Err)) {} }; enum class LLVMRustArchiveKind { @@ -84,15 +89,14 @@ extern "C" void LLVMRustDestroyArchive(LLVMRustArchiveRef RustArchive) { extern "C" LLVMRustArchiveIteratorRef LLVMRustArchiveIteratorNew(LLVMRustArchiveRef RustArchive) { Archive *Archive = RustArchive->getBinary(); - RustArchiveIterator *RAI = new RustArchiveIterator(); - RAI->Cur = Archive->child_begin(RAI->Err); - if (RAI->Err) { - LLVMRustSetLastError(toString(std::move(RAI->Err)).c_str()); - delete RAI; + std::unique_ptr<Error> Err = llvm::make_unique<Error>(Error::success()); + auto Cur = Archive->child_begin(*Err); + if (*Err) { + LLVMRustSetLastError(toString(std::move(*Err)).c_str()); return nullptr; } - RAI->End = Archive->child_end(); - return RAI; + auto End = Archive->child_end(); + return new RustArchiveIterator(Cur, End, std::move(Err)); } extern "C" LLVMRustArchiveChildConstRef @@ -108,8 +112,8 @@ LLVMRustArchiveIteratorNext(LLVMRustArchiveIteratorRef RAI) { // but instead advance it *before* fetching the child in all later calls. if (!RAI->First) { ++RAI->Cur; - if (RAI->Err) { - LLVMRustSetLastError(toString(std::move(RAI->Err)).c_str()); + if (*RAI->Err) { + LLVMRustSetLastError(toString(std::move(*RAI->Err)).c_str()); return nullptr; } } else { diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index 25595e14982..319c66a21f1 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -646,8 +646,9 @@ char RustPrintModulePass::ID = 0; INITIALIZE_PASS(RustPrintModulePass, "print-rust-module", "Print rust module to stderr", false, false) -extern "C" void LLVMRustPrintModule(LLVMPassManagerRef PMR, LLVMModuleRef M, - const char *Path, DemangleFn Demangle) { +extern "C" LLVMRustResult +LLVMRustPrintModule(LLVMPassManagerRef PMR, LLVMModuleRef M, + const char *Path, DemangleFn Demangle) { llvm::legacy::PassManager *PM = unwrap<llvm::legacy::PassManager>(PMR); std::string ErrorInfo; @@ -655,12 +656,18 @@ extern "C" void LLVMRustPrintModule(LLVMPassManagerRef PMR, LLVMModuleRef M, raw_fd_ostream OS(Path, EC, sys::fs::F_None); if (EC) ErrorInfo = EC.message(); + if (ErrorInfo != "") { + LLVMRustSetLastError(ErrorInfo.c_str()); + return LLVMRustResult::Failure; + } formatted_raw_ostream FOS(OS); PM->add(new RustPrintModulePass(FOS, Demangle)); PM->run(*unwrap(M)); + + return LLVMRustResult::Success; } extern "C" void LLVMRustPrintPasses() { diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index a00417a3629..437e2d482ef 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -117,7 +117,11 @@ extern "C" LLVMValueRef LLVMRustGetOrInsertFunction(LLVMModuleRef M, const char *Name, LLVMTypeRef FunctionTy) { return wrap( - unwrap(M)->getOrInsertFunction(Name, unwrap<FunctionType>(FunctionTy))); + unwrap(M)->getOrInsertFunction(Name, unwrap<FunctionType>(FunctionTy)) +#if LLVM_VERSION_GE(9, 0) + .getCallee() +#endif + ); } extern "C" LLVMValueRef @@ -417,7 +421,6 @@ enum class LLVMRustDIFlags : uint32_t { FlagIntroducedVirtual = (1 << 18), FlagBitField = (1 << 19), FlagNoReturn = (1 << 20), - FlagMainSubprogram = (1 << 21), // Do not add values that are not supported by the minimum LLVM // version we support! see llvm/include/llvm/IR/DebugInfoFlags.def }; @@ -508,9 +511,6 @@ static DINode::DIFlags fromRust(LLVMRustDIFlags Flags) { if (isSet(Flags & LLVMRustDIFlags::FlagNoReturn)) { Result |= DINode::DIFlags::FlagNoReturn; } - if (isSet(Flags & LLVMRustDIFlags::FlagMainSubprogram)) { - Result |= DINode::DIFlags::FlagMainSubprogram; - } return Result; } @@ -525,6 +525,7 @@ enum class LLVMRustDISPFlags : uint32_t { SPFlagLocalToUnit = (1 << 2), SPFlagDefinition = (1 << 3), SPFlagOptimized = (1 << 4), + SPFlagMainSubprogram = (1 << 5), // Do not add values that are not supported by the minimum LLVM // version we support! see llvm/include/llvm/IR/DebugInfoFlags.def // (In LLVM < 8, createFunction supported these as separate bool arguments.) @@ -575,6 +576,11 @@ static DISubprogram::DISPFlags fromRust(LLVMRustDISPFlags SPFlags) { if (isSet(SPFlags & LLVMRustDISPFlags::SPFlagOptimized)) { Result |= DISubprogram::DISPFlags::SPFlagOptimized; } +#if LLVM_VERSION_GE(9, 0) + if (isSet(SPFlags & LLVMRustDISPFlags::SPFlagMainSubprogram)) { + Result |= DISubprogram::DISPFlags::SPFlagMainSubprogram; + } +#endif return Result; } @@ -671,18 +677,27 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateFunction( DITemplateParameterArray TParams = DITemplateParameterArray(unwrap<MDTuple>(TParam)); #if LLVM_VERSION_GE(8, 0) + DISubprogram::DISPFlags llvmSPFlags = fromRust(SPFlags); + DINode::DIFlags llvmFlags = fromRust(Flags); +#if LLVM_VERSION_LT(9, 0) + if (isSet(SPFlags & LLVMRustDISPFlags::SPFlagMainSubprogram)) + llvmFlags |= DINode::DIFlags::FlagMainSubprogram; +#endif DISubprogram *Sub = Builder->createFunction( unwrapDI<DIScope>(Scope), Name, LinkageName, unwrapDI<DIFile>(File), - LineNo, unwrapDI<DISubroutineType>(Ty), ScopeLine, fromRust(Flags), - fromRust(SPFlags), TParams, unwrapDIPtr<DISubprogram>(Decl)); + LineNo, unwrapDI<DISubroutineType>(Ty), ScopeLine, llvmFlags, + llvmSPFlags, TParams, unwrapDIPtr<DISubprogram>(Decl)); #else bool IsLocalToUnit = isSet(SPFlags & LLVMRustDISPFlags::SPFlagLocalToUnit); bool IsDefinition = isSet(SPFlags & LLVMRustDISPFlags::SPFlagDefinition); bool IsOptimized = isSet(SPFlags & LLVMRustDISPFlags::SPFlagOptimized); + DINode::DIFlags llvmFlags = fromRust(Flags); + if (isSet(SPFlags & LLVMRustDISPFlags::SPFlagMainSubprogram)) + llvmFlags |= DINode::DIFlags::FlagMainSubprogram; DISubprogram *Sub = Builder->createFunction( unwrapDI<DIScope>(Scope), Name, LinkageName, unwrapDI<DIFile>(File), LineNo, unwrapDI<DISubroutineType>(Ty), IsLocalToUnit, IsDefinition, - ScopeLine, fromRust(Flags), IsOptimized, TParams, + ScopeLine, llvmFlags, IsOptimized, TParams, unwrapDIPtr<DISubprogram>(Decl)); #endif unwrap<Function>(Fn)->setSubprogram(Sub); diff --git a/src/stdsimd b/src/stdsimd -Subproject 12bdc2ed6b32653866d02b42f0885d9cd8bd295 +Subproject 2792b45c975880038240d477adb0d66f760ac04 diff --git a/src/test/codegen/fn-impl-trait-self.rs b/src/test/codegen/fn-impl-trait-self.rs new file mode 100644 index 00000000000..f9113d50197 --- /dev/null +++ b/src/test/codegen/fn-impl-trait-self.rs @@ -0,0 +1,15 @@ +// compile-flags: -g +// +// CHECK-LABEL: @main +// CHECK: {{.*}}DIDerivedType(tag: DW_TAG_pointer_type, name: "fn() -> <recursive_type>",{{.*}} +// +// CHECK: {{.*}}DISubroutineType{{.*}} +// CHECK: {{.*}}DIBasicType(name: "<recur_type>", encoding: DW_ATE_unsigned) + +pub fn foo() -> impl Copy { + foo +} + +fn main() { + let my_res = foo(); +} diff --git a/src/test/codegen/noreturn-uninhabited.rs b/src/test/codegen/noreturn-uninhabited.rs new file mode 100644 index 00000000000..1b65da9f287 --- /dev/null +++ b/src/test/codegen/noreturn-uninhabited.rs @@ -0,0 +1,32 @@ +// compile-flags: -g -C no-prepopulate-passes +// ignore-tidy-linelength + +#![crate_type = "lib"] + +#[derive(Clone, Copy)] +pub enum EmptyEnum {} + +#[no_mangle] +pub fn empty(x: &EmptyEnum) -> EmptyEnum { + // CHECK: @empty({{.*}}) unnamed_addr #0 + // CHECK-NOT: ret void + // CHECK: call void @llvm.trap() + // CHECK: unreachable + *x +} + +pub struct Foo(String, EmptyEnum); + +#[no_mangle] +pub fn foo(x: String, y: &EmptyEnum) -> Foo { + // CHECK: @foo({{.*}}) unnamed_addr #0 + // CHECK-NOT: ret %Foo + // CHECK: call void @llvm.trap() + // CHECK: unreachable + Foo(x, *y) +} + +// CHECK: attributes #0 = {{{.*}} noreturn {{.*}}} + +// CHECK: DISubprogram(name: "empty", {{.*}} DIFlagNoReturn +// CHECK: DISubprogram(name: "foo", {{.*}} DIFlagNoReturn diff --git a/src/test/compile-fail/must_use-in-stdlib-traits.rs b/src/test/compile-fail/must_use-in-stdlib-traits.rs index b4f07ab3321..503b39e181a 100644 --- a/src/test/compile-fail/must_use-in-stdlib-traits.rs +++ b/src/test/compile-fail/must_use-in-stdlib-traits.rs @@ -4,7 +4,7 @@ use std::iter::Iterator; use std::future::Future; -use std::task::{Poll, Waker}; +use std::task::{Context, Poll}; use std::pin::Pin; use std::unimplemented; @@ -13,7 +13,7 @@ struct MyFuture; impl Future for MyFuture { type Output = u32; - fn poll(self: Pin<&mut Self>, waker: &Waker) -> Poll<u32> { + fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<u32> { Poll::Pending } } diff --git a/src/test/incremental/add_private_fn_at_krate_root_cc/struct_point.rs b/src/test/incremental/add_private_fn_at_krate_root_cc/struct_point.rs index 0e17a29dea0..13daa72a4d1 100644 --- a/src/test/incremental/add_private_fn_at_krate_root_cc/struct_point.rs +++ b/src/test/incremental/add_private_fn_at_krate_root_cc/struct_point.rs @@ -24,7 +24,7 @@ extern crate point; pub mod fn_calls_methods_in_same_impl { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="cfail2")] + #[rustc_clean(label="typeck_tables_of", cfg="cfail2")] pub fn check() { let x = Point { x: 2.0, y: 2.0 }; x.distance_from_origin(); @@ -35,7 +35,7 @@ pub mod fn_calls_methods_in_same_impl { pub mod fn_calls_free_fn { use point::{self, Point}; - #[rustc_clean(label="TypeckTables", cfg="cfail2")] + #[rustc_clean(label="typeck_tables_of", cfg="cfail2")] pub fn check() { let x = Point { x: 2.0, y: 2.0 }; point::distance_squared(&x); @@ -46,7 +46,7 @@ pub mod fn_calls_free_fn { pub mod fn_make_struct { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="cfail2")] + #[rustc_clean(label="typeck_tables_of", cfg="cfail2")] pub fn make_origin() -> Point { Point { x: 2.0, y: 2.0 } } @@ -56,7 +56,7 @@ pub mod fn_make_struct { pub mod fn_read_field { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="cfail2")] + #[rustc_clean(label="typeck_tables_of", cfg="cfail2")] pub fn get_x(p: Point) -> f32 { p.x } @@ -66,7 +66,7 @@ pub mod fn_read_field { pub mod fn_write_field { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="cfail2")] + #[rustc_clean(label="typeck_tables_of", cfg="cfail2")] pub fn inc_x(p: &mut Point) { p.x += 1.0; } diff --git a/src/test/incremental/callee_caller_cross_crate/b.rs b/src/test/incremental/callee_caller_cross_crate/b.rs index 95285b7a03c..b49731b26e7 100644 --- a/src/test/incremental/callee_caller_cross_crate/b.rs +++ b/src/test/incremental/callee_caller_cross_crate/b.rs @@ -6,12 +6,12 @@ extern crate a; -#[rustc_dirty(label="TypeckTables", cfg="rpass2")] +#[rustc_dirty(label="typeck_tables_of", cfg="rpass2")] pub fn call_function0() { a::function0(77); } -#[rustc_clean(label="TypeckTables", cfg="rpass2")] +#[rustc_clean(label="typeck_tables_of", cfg="rpass2")] pub fn call_function1() { a::function1(77); } diff --git a/src/test/incremental/change_add_field/struct_point.rs b/src/test/incremental/change_add_field/struct_point.rs index 182e6cb45be..9e34aedbed3 100644 --- a/src/test/incremental/change_add_field/struct_point.rs +++ b/src/test/incremental/change_add_field/struct_point.rs @@ -70,7 +70,7 @@ pub mod point { pub mod fn_with_type_in_sig { use point::Point; - #[rustc_dirty(label="TypeckTables", cfg="cfail2")] + #[rustc_dirty(label="typeck_tables_of", cfg="cfail2")] pub fn boop(p: Option<&Point>) -> f32 { p.map(|p| p.total()).unwrap_or(0.0) } @@ -86,7 +86,7 @@ pub mod fn_with_type_in_sig { pub mod call_fn_with_type_in_sig { use fn_with_type_in_sig; - #[rustc_dirty(label="TypeckTables", cfg="cfail2")] + #[rustc_dirty(label="typeck_tables_of", cfg="cfail2")] pub fn bip() -> f32 { fn_with_type_in_sig::boop(None) } @@ -102,7 +102,7 @@ pub mod call_fn_with_type_in_sig { pub mod fn_with_type_in_body { use point::Point; - #[rustc_dirty(label="TypeckTables", cfg="cfail2")] + #[rustc_dirty(label="typeck_tables_of", cfg="cfail2")] pub fn boop() -> f32 { Point::origin().total() } @@ -115,7 +115,7 @@ pub mod fn_with_type_in_body { pub mod call_fn_with_type_in_body { use fn_with_type_in_body; - #[rustc_clean(label="TypeckTables", cfg="cfail2")] + #[rustc_clean(label="typeck_tables_of", cfg="cfail2")] pub fn bip() -> f32 { fn_with_type_in_body::boop() } @@ -125,7 +125,7 @@ pub mod call_fn_with_type_in_body { pub mod fn_make_struct { use point::Point; - #[rustc_dirty(label="TypeckTables", cfg="cfail2")] + #[rustc_dirty(label="typeck_tables_of", cfg="cfail2")] pub fn make_origin(p: Point) -> Point { Point { ..p } } @@ -135,7 +135,7 @@ pub mod fn_make_struct { pub mod fn_read_field { use point::Point; - #[rustc_dirty(label="TypeckTables", cfg="cfail2")] + #[rustc_dirty(label="typeck_tables_of", cfg="cfail2")] pub fn get_x(p: Point) -> f32 { p.x } @@ -145,7 +145,7 @@ pub mod fn_read_field { pub mod fn_write_field { use point::Point; - #[rustc_dirty(label="TypeckTables", cfg="cfail2")] + #[rustc_dirty(label="typeck_tables_of", cfg="cfail2")] pub fn inc_x(p: &mut Point) { p.x += 1.0; } diff --git a/src/test/incremental/change_crate_order/main.rs b/src/test/incremental/change_crate_order/main.rs index e514c8519f8..c167cf6e035 100644 --- a/src/test/incremental/change_crate_order/main.rs +++ b/src/test/incremental/change_crate_order/main.rs @@ -18,7 +18,7 @@ extern crate a; use a::A; use b::B; -//? #[rustc_clean(label="TypeckTables", cfg="rpass2")] +//? #[rustc_clean(label="typeck_tables_of", cfg="rpass2")] pub fn main() { A + B; } diff --git a/src/test/incremental/change_private_fn/struct_point.rs b/src/test/incremental/change_private_fn/struct_point.rs index f9f83169ef4..be287b86bbc 100644 --- a/src/test/incremental/change_private_fn/struct_point.rs +++ b/src/test/incremental/change_private_fn/struct_point.rs @@ -51,7 +51,7 @@ pub mod point { pub mod fn_calls_methods_in_same_impl { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="cfail2")] + #[rustc_clean(label="typeck_tables_of", cfg="cfail2")] pub fn check() { let x = Point { x: 2.0, y: 2.0 }; x.distance_from_origin(); @@ -62,7 +62,7 @@ pub mod fn_calls_methods_in_same_impl { pub mod fn_calls_methods_in_another_impl { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="cfail2")] + #[rustc_clean(label="typeck_tables_of", cfg="cfail2")] pub fn check() { let mut x = Point { x: 2.0, y: 2.0 }; x.translate(3.0, 3.0); @@ -73,7 +73,7 @@ pub mod fn_calls_methods_in_another_impl { pub mod fn_make_struct { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="cfail2")] + #[rustc_clean(label="typeck_tables_of", cfg="cfail2")] pub fn make_origin() -> Point { Point { x: 2.0, y: 2.0 } } @@ -83,7 +83,7 @@ pub mod fn_make_struct { pub mod fn_read_field { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="cfail2")] + #[rustc_clean(label="typeck_tables_of", cfg="cfail2")] pub fn get_x(p: Point) -> f32 { p.x } @@ -93,7 +93,7 @@ pub mod fn_read_field { pub mod fn_write_field { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="cfail2")] + #[rustc_clean(label="typeck_tables_of", cfg="cfail2")] pub fn inc_x(p: &mut Point) { p.x += 1.0; } diff --git a/src/test/incremental/change_private_fn_cc/struct_point.rs b/src/test/incremental/change_private_fn_cc/struct_point.rs index 827eb8105b2..521fe99ebc2 100644 --- a/src/test/incremental/change_private_fn_cc/struct_point.rs +++ b/src/test/incremental/change_private_fn_cc/struct_point.rs @@ -23,7 +23,7 @@ extern crate point; pub mod fn_calls_methods_in_same_impl { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="cfail2")] + #[rustc_clean(label="typeck_tables_of", cfg="cfail2")] pub fn check() { let x = Point { x: 2.0, y: 2.0 }; x.distance_from_origin(); @@ -34,7 +34,7 @@ pub mod fn_calls_methods_in_same_impl { pub mod fn_calls_methods_in_another_impl { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="cfail2")] + #[rustc_clean(label="typeck_tables_of", cfg="cfail2")] pub fn check() { let mut x = Point { x: 2.0, y: 2.0 }; x.translate(3.0, 3.0); @@ -45,7 +45,7 @@ pub mod fn_calls_methods_in_another_impl { pub mod fn_make_struct { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="cfail2")] + #[rustc_clean(label="typeck_tables_of", cfg="cfail2")] pub fn make_origin() -> Point { Point { x: 2.0, y: 2.0 } } @@ -55,7 +55,7 @@ pub mod fn_make_struct { pub mod fn_read_field { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="cfail2")] + #[rustc_clean(label="typeck_tables_of", cfg="cfail2")] pub fn get_x(p: Point) -> f32 { p.x } @@ -65,7 +65,7 @@ pub mod fn_read_field { pub mod fn_write_field { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="cfail2")] + #[rustc_clean(label="typeck_tables_of", cfg="cfail2")] pub fn inc_x(p: &mut Point) { p.x += 1.0; } diff --git a/src/test/incremental/change_private_impl_method/struct_point.rs b/src/test/incremental/change_private_impl_method/struct_point.rs index e3073b170df..c2796b5e3c9 100644 --- a/src/test/incremental/change_private_impl_method/struct_point.rs +++ b/src/test/incremental/change_private_impl_method/struct_point.rs @@ -51,7 +51,7 @@ pub mod point { pub mod fn_calls_methods_in_same_impl { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="cfail2")] + #[rustc_clean(label="typeck_tables_of", cfg="cfail2")] pub fn check() { let x = Point { x: 2.0, y: 2.0 }; x.distance_from_origin(); @@ -62,7 +62,7 @@ pub mod fn_calls_methods_in_same_impl { pub mod fn_calls_methods_in_another_impl { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="cfail2")] + #[rustc_clean(label="typeck_tables_of", cfg="cfail2")] pub fn check() { let mut x = Point { x: 2.0, y: 2.0 }; x.translate(3.0, 3.0); @@ -73,7 +73,7 @@ pub mod fn_calls_methods_in_another_impl { pub mod fn_make_struct { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="cfail2")] + #[rustc_clean(label="typeck_tables_of", cfg="cfail2")] pub fn make_origin() -> Point { Point { x: 2.0, y: 2.0 } } @@ -83,7 +83,7 @@ pub mod fn_make_struct { pub mod fn_read_field { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="cfail2")] + #[rustc_clean(label="typeck_tables_of", cfg="cfail2")] pub fn get_x(p: Point) -> f32 { p.x } @@ -93,7 +93,7 @@ pub mod fn_read_field { pub mod fn_write_field { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="cfail2")] + #[rustc_clean(label="typeck_tables_of", cfg="cfail2")] pub fn inc_x(p: &mut Point) { p.x += 1.0; } diff --git a/src/test/incremental/change_private_impl_method_cc/struct_point.rs b/src/test/incremental/change_private_impl_method_cc/struct_point.rs index bd5e9636d48..731dcdf78c9 100644 --- a/src/test/incremental/change_private_impl_method_cc/struct_point.rs +++ b/src/test/incremental/change_private_impl_method_cc/struct_point.rs @@ -24,7 +24,7 @@ extern crate point; pub mod fn_calls_methods_in_same_impl { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="cfail2")] + #[rustc_clean(label="typeck_tables_of", cfg="cfail2")] pub fn check() { let x = Point { x: 2.0, y: 2.0 }; x.distance_from_origin(); @@ -35,7 +35,7 @@ pub mod fn_calls_methods_in_same_impl { pub mod fn_calls_methods_in_another_impl { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="cfail2")] + #[rustc_clean(label="typeck_tables_of", cfg="cfail2")] pub fn dirty() { let mut x = Point { x: 2.0, y: 2.0 }; x.translate(3.0, 3.0); @@ -46,7 +46,7 @@ pub mod fn_calls_methods_in_another_impl { pub mod fn_make_struct { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="cfail2")] + #[rustc_clean(label="typeck_tables_of", cfg="cfail2")] pub fn make_origin() -> Point { Point { x: 2.0, y: 2.0 } } @@ -56,7 +56,7 @@ pub mod fn_make_struct { pub mod fn_read_field { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="cfail2")] + #[rustc_clean(label="typeck_tables_of", cfg="cfail2")] pub fn get_x(p: Point) -> f32 { p.x } @@ -66,7 +66,7 @@ pub mod fn_read_field { pub mod fn_write_field { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="cfail2")] + #[rustc_clean(label="typeck_tables_of", cfg="cfail2")] pub fn inc_x(p: &mut Point) { p.x += 1.0; } diff --git a/src/test/incremental/change_pub_inherent_method_body/struct_point.rs b/src/test/incremental/change_pub_inherent_method_body/struct_point.rs index 8e87fde54ef..76dcff848ca 100644 --- a/src/test/incremental/change_pub_inherent_method_body/struct_point.rs +++ b/src/test/incremental/change_pub_inherent_method_body/struct_point.rs @@ -42,7 +42,7 @@ pub mod point { pub mod fn_calls_changed_method { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="cfail2")] + #[rustc_clean(label="typeck_tables_of", cfg="cfail2")] pub fn check() { let p = Point { x: 2.0, y: 2.0 }; p.distance_from_origin(); @@ -53,7 +53,7 @@ pub mod fn_calls_changed_method { pub mod fn_calls_another_method { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="cfail2")] + #[rustc_clean(label="typeck_tables_of", cfg="cfail2")] pub fn check() { let p = Point { x: 2.0, y: 2.0 }; p.x(); @@ -64,7 +64,7 @@ pub mod fn_calls_another_method { pub mod fn_make_struct { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="cfail2")] + #[rustc_clean(label="typeck_tables_of", cfg="cfail2")] pub fn make_origin() -> Point { Point { x: 2.0, y: 2.0 } } @@ -74,7 +74,7 @@ pub mod fn_make_struct { pub mod fn_read_field { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="cfail2")] + #[rustc_clean(label="typeck_tables_of", cfg="cfail2")] pub fn get_x(p: Point) -> f32 { p.x } @@ -84,7 +84,7 @@ pub mod fn_read_field { pub mod fn_write_field { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="cfail2")] + #[rustc_clean(label="typeck_tables_of", cfg="cfail2")] pub fn inc_x(p: &mut Point) { p.x += 1.0; } diff --git a/src/test/incremental/change_pub_inherent_method_sig/struct_point.rs b/src/test/incremental/change_pub_inherent_method_sig/struct_point.rs index 7ea64a08472..9c95d4cc2a9 100644 --- a/src/test/incremental/change_pub_inherent_method_sig/struct_point.rs +++ b/src/test/incremental/change_pub_inherent_method_sig/struct_point.rs @@ -52,7 +52,7 @@ pub mod point { pub mod fn_calls_changed_method { use point::Point; - #[rustc_dirty(label="TypeckTables", cfg="cfail2")] + #[rustc_dirty(label="typeck_tables_of", cfg="cfail2")] pub fn check() { let p = Point { x: 2.0, y: 2.0 }; p.distance_from_point(None); @@ -63,7 +63,7 @@ pub mod fn_calls_changed_method { pub mod fn_calls_another_method { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="cfail2")] + #[rustc_clean(label="typeck_tables_of", cfg="cfail2")] pub fn check() { let p = Point { x: 2.0, y: 2.0 }; p.x(); @@ -74,7 +74,7 @@ pub mod fn_calls_another_method { pub mod fn_make_struct { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="cfail2")] + #[rustc_clean(label="typeck_tables_of", cfg="cfail2")] pub fn make_origin() -> Point { Point { x: 2.0, y: 2.0 } } @@ -84,7 +84,7 @@ pub mod fn_make_struct { pub mod fn_read_field { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="cfail2")] + #[rustc_clean(label="typeck_tables_of", cfg="cfail2")] pub fn get_x(p: Point) -> f32 { p.x } @@ -94,7 +94,7 @@ pub mod fn_read_field { pub mod fn_write_field { use point::Point; - #[rustc_clean(label="TypeckTables", cfg="cfail2")] + #[rustc_clean(label="typeck_tables_of", cfg="cfail2")] pub fn inc_x(p: &mut Point) { p.x += 1.0; } diff --git a/src/test/incremental/dirty_clean.rs b/src/test/incremental/dirty_clean.rs index f4248dbdd6d..b9a1846b37d 100644 --- a/src/test/incremental/dirty_clean.rs +++ b/src/test/incremental/dirty_clean.rs @@ -25,16 +25,16 @@ mod x { mod y { use x; - #[rustc_clean(label="TypeckTables", cfg="cfail2")] + #[rustc_clean(label="typeck_tables_of", cfg="cfail2")] pub fn y() { - //[cfail2]~^ ERROR `TypeckTables(y::y)` should be clean but is not + //[cfail2]~^ ERROR `typeck_tables_of(y::y)` should be clean but is not x::x(); } } mod z { - #[rustc_dirty(label="TypeckTables", cfg="cfail2")] + #[rustc_dirty(label="typeck_tables_of", cfg="cfail2")] pub fn z() { - //[cfail2]~^ ERROR `TypeckTables(z::z)` should be dirty but is not + //[cfail2]~^ ERROR `typeck_tables_of(z::z)` should be dirty but is not } } diff --git a/src/test/incremental/hashes/call_expressions.rs b/src/test/incremental/hashes/call_expressions.rs index 05cc945bbaf..55dd3745123 100644 --- a/src/test/incremental/hashes/call_expressions.rs +++ b/src/test/incremental/hashes/call_expressions.rs @@ -25,7 +25,7 @@ pub fn change_callee_function() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody,mir_built,optimized_mir,TypeckTables")] +#[rustc_clean(cfg="cfail2", except="HirBody,mir_built,optimized_mir,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn change_callee_function() { callee2(1, 2) @@ -81,7 +81,7 @@ pub fn change_callee_method() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody,mir_built,optimized_mir,TypeckTables")] +#[rustc_clean(cfg="cfail2", except="HirBody,mir_built,optimized_mir,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn change_callee_method() { let s = Struct; @@ -115,7 +115,7 @@ pub fn change_ufcs_callee_method() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody,mir_built,optimized_mir,TypeckTables")] +#[rustc_clean(cfg="cfail2", except="HirBody,mir_built,optimized_mir,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn change_ufcs_callee_method() { let s = Struct; @@ -149,7 +149,7 @@ pub fn change_to_ufcs() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody,mir_built,optimized_mir,TypeckTables")] +#[rustc_clean(cfg="cfail2", except="HirBody,mir_built,optimized_mir,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] // One might think this would be expanded in the HirBody/Mir, but it actually // results in slightly different Hir/Mir. @@ -171,7 +171,7 @@ pub mod change_ufcs_callee_indirectly { #[cfg(not(cfail1))] use super::Struct2 as Struct; - #[rustc_clean(cfg="cfail2", except="HirBody,mir_built,optimized_mir,TypeckTables")] + #[rustc_clean(cfg="cfail2", except="HirBody,mir_built,optimized_mir,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] diff --git a/src/test/incremental/hashes/closure_expressions.rs b/src/test/incremental/hashes/closure_expressions.rs index b8e84173ec0..5bfd540eca6 100644 --- a/src/test/incremental/hashes/closure_expressions.rs +++ b/src/test/incremental/hashes/closure_expressions.rs @@ -37,7 +37,7 @@ pub fn add_parameter() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir, TypeckTables")] +#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir, typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn add_parameter() { let x = 0u32; @@ -53,7 +53,7 @@ pub fn change_parameter_pattern() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, TypeckTables")] +#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn change_parameter_pattern() { let _ = |&x: &u32| x; @@ -84,7 +84,7 @@ pub fn add_type_ascription_to_parameter() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, TypeckTables")] +#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn add_type_ascription_to_parameter() { let closure = |x: u32| x + 1u32; @@ -101,7 +101,7 @@ pub fn change_parameter_type() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir, TypeckTables")] +#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir, typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn change_parameter_type() { let closure = |x: u16| (x as u64) + 1; diff --git a/src/test/incremental/hashes/enum_constructors.rs b/src/test/incremental/hashes/enum_constructors.rs index d3f96c9947b..f553b2d1b51 100644 --- a/src/test/incremental/hashes/enum_constructors.rs +++ b/src/test/incremental/hashes/enum_constructors.rs @@ -57,7 +57,7 @@ pub fn change_field_order_struct_like() -> Enum { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody,TypeckTables")] +#[rustc_clean(cfg="cfail2", except="HirBody,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] // FIXME(michaelwoerister):Interesting. I would have thought that that changes the MIR. And it // would if it were not all constants @@ -96,7 +96,7 @@ pub fn change_constructor_path_struct_like() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody,optimized_mir,mir_built,TypeckTables")] +#[rustc_clean(cfg="cfail2", except="HirBody,optimized_mir,mir_built,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn change_constructor_path_struct_like() { let _ = Enum2::Struct { @@ -139,8 +139,8 @@ pub mod change_constructor_path_indirectly_struct_like { #[rustc_clean( cfg="cfail2", - except="FnSignature,Hir,HirBody,optimized_mir,mir_built,\ - TypeckTables" + except="fn_sig,Hir,HirBody,optimized_mir,mir_built,\ + typeck_tables_of" )] #[rustc_clean(cfg="cfail3")] pub fn function() -> TheEnum { @@ -197,7 +197,7 @@ pub fn change_constructor_path_tuple_like() { #[cfg(not(cfail1))] #[rustc_clean( cfg="cfail2", - except="HirBody,optimized_mir,mir_built,TypeckTables" + except="HirBody,optimized_mir,mir_built,typeck_tables_of" )] #[rustc_clean(cfg="cfail3")] pub fn change_constructor_path_tuple_like() { @@ -215,7 +215,7 @@ pub fn change_constructor_variant_tuple_like() { #[cfg(not(cfail1))] #[rustc_clean( cfg="cfail2", - except="HirBody,optimized_mir,mir_built,TypeckTables" + except="HirBody,optimized_mir,mir_built,typeck_tables_of" )] #[rustc_clean(cfg="cfail3")] pub fn change_constructor_variant_tuple_like() { @@ -232,8 +232,8 @@ pub mod change_constructor_path_indirectly_tuple_like { #[rustc_clean( cfg="cfail2", - except="FnSignature,Hir,HirBody,optimized_mir,mir_built,\ - TypeckTables" + except="fn_sig,Hir,HirBody,optimized_mir,mir_built,\ + typeck_tables_of" )] #[rustc_clean(cfg="cfail3")] pub fn function() -> TheEnum { @@ -251,7 +251,7 @@ pub mod change_constructor_variant_indirectly_tuple_like { #[cfg(not(cfail1))] use super::Enum2::Tuple2 as Variant; - #[rustc_clean(cfg="cfail2", except="HirBody,optimized_mir,mir_built,TypeckTables")] + #[rustc_clean(cfg="cfail2", except="HirBody,optimized_mir,mir_built,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn function() -> Enum2 { Variant(0, 1, 2) @@ -278,7 +278,7 @@ pub fn change_constructor_path_c_like() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody,optimized_mir,mir_built,TypeckTables")] +#[rustc_clean(cfg="cfail2", except="HirBody,optimized_mir,mir_built,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn change_constructor_path_c_like() { let _ = Clike2::B; @@ -309,8 +309,8 @@ pub mod change_constructor_path_indirectly_c_like { #[rustc_clean( cfg="cfail2", - except="FnSignature,Hir,HirBody,optimized_mir,mir_built,\ - TypeckTables" + except="fn_sig,Hir,HirBody,optimized_mir,mir_built,\ + typeck_tables_of" )] #[rustc_clean(cfg="cfail3")] pub fn function() -> TheEnum { diff --git a/src/test/incremental/hashes/for_loops.rs b/src/test/incremental/hashes/for_loops.rs index 91abca3312b..503cb8732ef 100644 --- a/src/test/incremental/hashes/for_loops.rs +++ b/src/test/incremental/hashes/for_loops.rs @@ -71,7 +71,7 @@ pub fn change_iteration_variable_pattern() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir, TypeckTables")] +#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir, typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn change_iteration_variable_pattern() { let mut _x = 0; @@ -116,7 +116,7 @@ pub fn add_break() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir, TypeckTables")] +#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir, typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn add_break() { let mut _x = 0; diff --git a/src/test/incremental/hashes/function_interfaces.rs b/src/test/incremental/hashes/function_interfaces.rs index db8fa9ced11..7850291fc56 100644 --- a/src/test/incremental/hashes/function_interfaces.rs +++ b/src/test/incremental/hashes/function_interfaces.rs @@ -24,7 +24,7 @@ pub fn add_parameter() {} #[cfg(not(cfail1))] #[rustc_clean(cfg = "cfail2", - except = "Hir, HirBody, mir_built, optimized_mir, TypeckTables, FnSignature")] + except = "Hir, HirBody, mir_built, optimized_mir, typeck_tables_of, fn_sig")] #[rustc_clean(cfg = "cfail3")] pub fn add_parameter(p: i32) {} @@ -47,7 +47,7 @@ pub fn type_of_parameter(p: i32) {} #[cfg(not(cfail1))] #[rustc_clean(cfg = "cfail2", - except = "Hir, HirBody, mir_built, optimized_mir, TypeckTables, FnSignature")] + except = "Hir, HirBody, mir_built, optimized_mir, typeck_tables_of, fn_sig")] #[rustc_clean(cfg = "cfail3")] pub fn type_of_parameter(p: i64) {} @@ -59,7 +59,7 @@ pub fn type_of_parameter_ref(p: &i32) {} #[cfg(not(cfail1))] #[rustc_clean(cfg = "cfail2", - except = "Hir, HirBody, mir_built, optimized_mir, TypeckTables, FnSignature")] + except = "Hir, HirBody, mir_built, optimized_mir, typeck_tables_of, fn_sig")] #[rustc_clean(cfg = "cfail3")] pub fn type_of_parameter_ref(p: &mut i32) {} @@ -71,7 +71,7 @@ pub fn order_of_parameters(p1: i32, p2: i64) {} #[cfg(not(cfail1))] #[rustc_clean(cfg = "cfail2", - except = "Hir, HirBody, mir_built, optimized_mir, TypeckTables, FnSignature")] + except = "Hir, HirBody, mir_built, optimized_mir, typeck_tables_of, fn_sig")] #[rustc_clean(cfg = "cfail3")] pub fn order_of_parameters(p2: i64, p1: i32) {} @@ -83,7 +83,7 @@ pub fn make_unsafe() {} #[cfg(not(cfail1))] #[rustc_clean(cfg = "cfail2", - except = "Hir, HirBody, mir_built, optimized_mir, TypeckTables, FnSignature")] + except = "Hir, HirBody, mir_built, optimized_mir, typeck_tables_of, fn_sig")] #[rustc_clean(cfg = "cfail3")] pub unsafe fn make_unsafe() {} @@ -94,7 +94,7 @@ pub unsafe fn make_unsafe() {} pub fn make_extern() {} #[cfg(not(cfail1))] -#[rustc_clean(cfg = "cfail2", except = "Hir, HirBody, mir_built, TypeckTables, FnSignature")] +#[rustc_clean(cfg = "cfail2", except = "Hir, HirBody, mir_built, typeck_tables_of, fn_sig")] #[rustc_clean(cfg = "cfail3")] pub extern "C" fn make_extern() {} @@ -105,7 +105,7 @@ pub extern "C" fn make_extern() {} pub extern "C" fn make_intrinsic() {} #[cfg(not(cfail1))] -#[rustc_clean(cfg = "cfail2", except = "Hir, HirBody, TypeckTables, FnSignature")] +#[rustc_clean(cfg = "cfail2", except = "Hir, HirBody, typeck_tables_of, fn_sig")] #[rustc_clean(cfg = "cfail3")] pub extern "rust-intrinsic" fn make_intrinsic() {} @@ -258,7 +258,7 @@ pub fn return_impl_trait() -> i32 { } #[cfg(not(cfail1))] -#[rustc_clean(cfg = "cfail2", except = "Hir, HirBody, TypeckTables, FnSignature")] +#[rustc_clean(cfg = "cfail2", except = "Hir, HirBody, typeck_tables_of, fn_sig")] #[rustc_clean(cfg = "cfail3")] pub fn return_impl_trait() -> impl Clone { 0 @@ -292,7 +292,7 @@ pub mod change_return_type_indirectly { use super::ReferencedType2 as ReturnType; #[rustc_clean(cfg = "cfail2", - except = "Hir, HirBody, mir_built, optimized_mir, TypeckTables, FnSignature")] + except = "Hir, HirBody, mir_built, optimized_mir, typeck_tables_of, fn_sig")] #[rustc_clean(cfg = "cfail3")] pub fn indirect_return_type() -> ReturnType { ReturnType {} @@ -309,7 +309,7 @@ pub mod change_parameter_type_indirectly { use super::ReferencedType2 as ParameterType; #[rustc_clean(cfg = "cfail2", - except = "Hir, HirBody, mir_built, optimized_mir, TypeckTables, FnSignature")] + except = "Hir, HirBody, mir_built, optimized_mir, typeck_tables_of, fn_sig")] #[rustc_clean(cfg = "cfail3")] pub fn indirect_parameter_type(p: ParameterType) {} } diff --git a/src/test/incremental/hashes/if_expressions.rs b/src/test/incremental/hashes/if_expressions.rs index 32a0c8b6b7e..fba7869af42 100644 --- a/src/test/incremental/hashes/if_expressions.rs +++ b/src/test/incremental/hashes/if_expressions.rs @@ -25,7 +25,7 @@ pub fn change_condition(x: bool) -> u32 { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody,mir_built,optimized_mir,TypeckTables")] +#[rustc_clean(cfg="cfail2", except="HirBody,mir_built,optimized_mir,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn change_condition(x: bool) -> u32 { if !x { @@ -94,7 +94,7 @@ pub fn add_else_branch(x: bool) -> u32 { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody,TypeckTables")] +#[rustc_clean(cfg="cfail2", except="HirBody,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn add_else_branch(x: bool) -> u32 { let mut ret = 1; @@ -120,7 +120,7 @@ pub fn change_condition_if_let(x: Option<u32>) -> u32 { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody,mir_built,optimized_mir,TypeckTables")] +#[rustc_clean(cfg="cfail2", except="HirBody,mir_built,optimized_mir,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn change_condition_if_let(x: Option<u32>) -> u32 { if let Some(_) = x { @@ -143,7 +143,7 @@ pub fn change_then_branch_if_let(x: Option<u32>) -> u32 { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody,mir_built,optimized_mir,TypeckTables")] +#[rustc_clean(cfg="cfail2", except="HirBody,mir_built,optimized_mir,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn change_then_branch_if_let(x: Option<u32>) -> u32 { if let Some(x) = x { @@ -191,7 +191,7 @@ pub fn add_else_branch_if_let(x: Option<u32>) -> u32 { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody,TypeckTables")] +#[rustc_clean(cfg="cfail2", except="HirBody,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn add_else_branch_if_let(x: Option<u32>) -> u32 { let mut ret = 1; diff --git a/src/test/incremental/hashes/inherent_impls.rs b/src/test/incremental/hashes/inherent_impls.rs index 1b6b41ce05b..268c37508a7 100644 --- a/src/test/incremental/hashes/inherent_impls.rs +++ b/src/test/incremental/hashes/inherent_impls.rs @@ -23,7 +23,7 @@ impl Foo { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="Hir,HirBody,AssociatedItemDefIds")] +#[rustc_clean(cfg="cfail2", except="Hir,HirBody,associated_item_def_ids")] #[rustc_clean(cfg="cfail3")] impl Foo { #[rustc_clean(cfg="cfail3")] @@ -42,7 +42,7 @@ impl Foo { #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] impl Foo { - #[rustc_clean(cfg="cfail2", except="HirBody,optimized_mir,mir_built,TypeckTables")] + #[rustc_clean(cfg="cfail2", except="HirBody,optimized_mir,mir_built,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn method_body() { println!("Hello, world!"); @@ -63,7 +63,7 @@ impl Foo { #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] impl Foo { - #[rustc_clean(cfg="cfail2", except="HirBody,optimized_mir,mir_built,TypeckTables")] + #[rustc_clean(cfg="cfail2", except="HirBody,optimized_mir,mir_built,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] #[inline] pub fn method_body_inlined() { @@ -82,7 +82,7 @@ impl Foo { #[rustc_clean(cfg="cfail2", except="Hir,HirBody")] #[rustc_clean(cfg="cfail3")] impl Foo { - #[rustc_clean(cfg="cfail2", except="AssociatedItems,Hir,HirBody")] + #[rustc_clean(cfg="cfail2", except="associated_item,Hir,HirBody")] #[rustc_clean(cfg="cfail3")] fn method_privacy() { } } @@ -114,7 +114,7 @@ impl Foo { impl Foo { #[rustc_clean( cfg="cfail2", - except="Hir,HirBody,FnSignature,TypeckTables,optimized_mir,mir_built" + except="Hir,HirBody,fn_sig,typeck_tables_of,optimized_mir,mir_built" )] #[rustc_clean(cfg="cfail3")] pub fn method_selfmutness(&mut self) { } @@ -129,7 +129,7 @@ impl Foo { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="Hir,HirBody,AssociatedItemDefIds")] +#[rustc_clean(cfg="cfail2", except="Hir,HirBody,associated_item_def_ids")] #[rustc_clean(cfg="cfail3")] impl Foo { #[rustc_clean(cfg="cfail2")] @@ -154,7 +154,7 @@ impl Foo { impl Foo { #[rustc_clean( cfg="cfail2", - except="Hir,HirBody,FnSignature,TypeckTables,optimized_mir,mir_built" + except="Hir,HirBody,fn_sig,typeck_tables_of,optimized_mir,mir_built" )] #[rustc_clean(cfg="cfail3")] pub fn add_method_parameter(&self, _: i32) { } @@ -191,7 +191,7 @@ impl Foo { impl Foo { #[rustc_clean( cfg="cfail2", - except="Hir,HirBody,FnSignature,optimized_mir,mir_built,TypeckTables")] + except="Hir,HirBody,fn_sig,optimized_mir,mir_built,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn change_method_return_type(&self) -> u8 { 0 } } @@ -245,7 +245,7 @@ impl Foo { impl Foo { #[rustc_clean( cfg="cfail2", - except="Hir,HirBody,FnSignature,TypeckTables,optimized_mir,mir_built" + except="Hir,HirBody,fn_sig,typeck_tables_of,optimized_mir,mir_built" )] #[rustc_clean(cfg="cfail3")] pub unsafe fn make_method_unsafe(&self) { } @@ -263,7 +263,7 @@ impl Foo { #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] impl Foo { - #[rustc_clean(cfg="cfail2", except="Hir,HirBody,mir_built,FnSignature,TypeckTables")] + #[rustc_clean(cfg="cfail2", except="Hir,HirBody,mir_built,fn_sig,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub extern fn make_method_extern(&self) { } } @@ -280,7 +280,7 @@ impl Foo { #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] impl Foo { - #[rustc_clean(cfg="cfail2", except="Hir,HirBody,FnSignature,TypeckTables")] + #[rustc_clean(cfg="cfail2", except="Hir,HirBody,fn_sig,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub extern "system" fn change_method_calling_convention(&self) { } } @@ -297,15 +297,15 @@ impl Foo { #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] impl Foo { - // Warning: Note that `TypeckTables` are coming up clean here. + // Warning: Note that `typeck_tables_of` are coming up clean here. // The addition or removal of lifetime parameters that don't // appear in the arguments or fn body in any way does not, in - // fact, affect the `TypeckTables` in any semantic way (at least + // fact, affect the `typeck_tables_of` in any semantic way (at least // as of this writing). **However,** altering the order of - // lowering **can** cause it appear to affect the `TypeckTables`: + // lowering **can** cause it appear to affect the `typeck_tables_of`: // if we lower generics before the body, then the `HirId` for // things in the body will be affected. So if you start to see - // `TypeckTables` appear dirty, that might be the cause. -nmatsakis + // `typeck_tables_of` appear dirty, that might be the cause. -nmatsakis #[rustc_clean(cfg="cfail2", except="Hir,HirBody")] #[rustc_clean(cfg="cfail3")] pub fn add_lifetime_parameter_to_method<'a>(&self) { } @@ -323,14 +323,14 @@ impl Foo { #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] impl Foo { - // Warning: Note that `TypeckTables` are coming up clean here. + // Warning: Note that `typeck_tables_of` are coming up clean here. // The addition or removal of type parameters that don't appear in // the arguments or fn body in any way does not, in fact, affect - // the `TypeckTables` in any semantic way (at least as of this + // the `typeck_tables_of` in any semantic way (at least as of this // writing). **However,** altering the order of lowering **can** - // cause it appear to affect the `TypeckTables`: if we lower + // cause it appear to affect the `typeck_tables_of`: if we lower // generics before the body, then the `HirId` for things in the - // body will be affected. So if you start to see `TypeckTables` + // body will be affected. So if you start to see `typeck_tables_of` // appear dirty, that might be the cause. -nmatsakis #[rustc_clean( cfg="cfail2", @@ -354,7 +354,7 @@ impl Foo { impl Foo { #[rustc_clean( cfg="cfail2", - except="Hir,HirBody,generics_of,predicates_of,type_of,TypeckTables" + except="Hir,HirBody,generics_of,predicates_of,type_of,typeck_tables_of" )] #[rustc_clean(cfg="cfail3")] pub fn add_lifetime_bound_to_lifetime_param_of_method<'a, 'b: 'a>(&self) { } @@ -372,14 +372,14 @@ impl Foo { #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] impl Foo { - // Warning: Note that `TypeckTables` are coming up clean here. + // Warning: Note that `typeck_tables_of` are coming up clean here. // The addition or removal of bounds that don't appear in the // arguments or fn body in any way does not, in fact, affect the - // `TypeckTables` in any semantic way (at least as of this + // `typeck_tables_of` in any semantic way (at least as of this // writing). **However,** altering the order of lowering **can** - // cause it appear to affect the `TypeckTables`: if we lower + // cause it appear to affect the `typeck_tables_of`: if we lower // generics before the body, then the `HirId` for things in the - // body will be affected. So if you start to see `TypeckTables` + // body will be affected. So if you start to see `typeck_tables_of` // appear dirty, that might be the cause. -nmatsakis #[rustc_clean(cfg="cfail2", except="Hir,HirBody,generics_of,predicates_of,\ type_of")] @@ -399,14 +399,14 @@ impl Foo { #[rustc_clean(cfg="cfail2")] #[rustc_clean(cfg="cfail3")] impl Foo { - // Warning: Note that `TypeckTables` are coming up clean here. + // Warning: Note that `typeck_tables_of` are coming up clean here. // The addition or removal of bounds that don't appear in the // arguments or fn body in any way does not, in fact, affect the - // `TypeckTables` in any semantic way (at least as of this + // `typeck_tables_of` in any semantic way (at least as of this // writing). **However,** altering the order of lowering **can** - // cause it appear to affect the `TypeckTables`: if we lower + // cause it appear to affect the `typeck_tables_of`: if we lower // generics before the body, then the `HirId` for things in the - // body will be affected. So if you start to see `TypeckTables` + // body will be affected. So if you start to see `typeck_tables_of` // appear dirty, that might be the cause. -nmatsakis #[rustc_clean(cfg="cfail2", except="Hir,HirBody,predicates_of")] #[rustc_clean(cfg="cfail3")] @@ -447,7 +447,7 @@ impl Bar<u32> { impl<T> Bar<T> { #[rustc_clean( cfg="cfail2", - except="generics_of,FnSignature,TypeckTables,type_of,optimized_mir,mir_built" + except="generics_of,fn_sig,typeck_tables_of,type_of,optimized_mir,mir_built" )] #[rustc_clean(cfg="cfail3")] pub fn add_type_parameter_to_impl(&self) { } @@ -465,7 +465,7 @@ impl Bar<u32> { #[rustc_clean(cfg="cfail2", except="Hir,HirBody")] #[rustc_clean(cfg="cfail3")] impl Bar<u64> { - #[rustc_clean(cfg="cfail2", except="FnSignature,optimized_mir,mir_built,TypeckTables")] + #[rustc_clean(cfg="cfail2", except="fn_sig,optimized_mir,mir_built,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn change_impl_self_type(&self) { } } diff --git a/src/test/incremental/hashes/let_expressions.rs b/src/test/incremental/hashes/let_expressions.rs index 76be2ccbf60..e016b92a9eb 100644 --- a/src/test/incremental/hashes/let_expressions.rs +++ b/src/test/incremental/hashes/let_expressions.rs @@ -38,7 +38,7 @@ pub fn add_type() { #[cfg(not(cfail1))] #[rustc_clean(cfg="cfail2", - except="HirBody,TypeckTables,mir_built,optimized_mir")] + except="HirBody,typeck_tables_of,mir_built,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn add_type() { let _x: u32 = 2u32; @@ -54,7 +54,7 @@ pub fn change_type() { #[cfg(not(cfail1))] #[rustc_clean(cfg="cfail2", - except="HirBody,TypeckTables,mir_built,optimized_mir")] + except="HirBody,typeck_tables_of,mir_built,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn change_type() { let _x: u8 = 2; @@ -70,7 +70,7 @@ pub fn change_mutability_of_reference_type() { #[cfg(not(cfail1))] #[rustc_clean(cfg="cfail2", - except="HirBody,TypeckTables,mir_built,optimized_mir")] + except="HirBody,typeck_tables_of,mir_built,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn change_mutability_of_reference_type() { let _x: &mut u64; @@ -86,7 +86,7 @@ pub fn change_mutability_of_slot() { #[cfg(not(cfail1))] #[rustc_clean(cfg="cfail2", - except="HirBody,TypeckTables,mir_built,optimized_mir")] + except="HirBody,typeck_tables_of,mir_built,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn change_mutability_of_slot() { let _x: u64 = 0; @@ -102,7 +102,7 @@ pub fn change_simple_binding_to_pattern() { #[cfg(not(cfail1))] #[rustc_clean(cfg="cfail2", - except="HirBody,TypeckTables,mir_built,optimized_mir")] + except="HirBody,typeck_tables_of,mir_built,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn change_simple_binding_to_pattern() { let (_a, _b) = (0u8, 'x'); @@ -134,7 +134,7 @@ pub fn add_ref_in_pattern() { #[cfg(not(cfail1))] #[rustc_clean(cfg="cfail2", - except="HirBody,TypeckTables,mir_built,optimized_mir")] + except="HirBody,typeck_tables_of,mir_built,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn add_ref_in_pattern() { let (ref _a, _b) = (1u8, 'y'); @@ -150,7 +150,7 @@ pub fn add_amp_in_pattern() { #[cfg(not(cfail1))] #[rustc_clean(cfg="cfail2", - except="HirBody,TypeckTables,mir_built,optimized_mir")] + except="HirBody,typeck_tables_of,mir_built,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn add_amp_in_pattern() { let (&_a, _b) = (&1u8, 'y'); @@ -166,7 +166,7 @@ pub fn change_mutability_of_binding_in_pattern() { #[cfg(not(cfail1))] #[rustc_clean(cfg="cfail2", - except="HirBody,TypeckTables,mir_built,optimized_mir")] + except="HirBody,typeck_tables_of,mir_built,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn change_mutability_of_binding_in_pattern() { let (mut _a, _b) = (99u8, 'q'); @@ -182,7 +182,7 @@ pub fn add_initializer() { #[cfg(not(cfail1))] #[rustc_clean(cfg="cfail2", - except="HirBody,TypeckTables,mir_built,optimized_mir")] + except="HirBody,typeck_tables_of,mir_built,optimized_mir")] #[rustc_clean(cfg="cfail3")] pub fn add_initializer() { let _x: i16 = 3i16; diff --git a/src/test/incremental/hashes/loop_expressions.rs b/src/test/incremental/hashes/loop_expressions.rs index 63cf1e9d5e8..c04bdd43a95 100644 --- a/src/test/incremental/hashes/loop_expressions.rs +++ b/src/test/incremental/hashes/loop_expressions.rs @@ -47,7 +47,7 @@ pub fn add_break() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir, TypeckTables")] +#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir, typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn add_break() { let mut _x = 0; @@ -118,7 +118,7 @@ pub fn change_break_label() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir, TypeckTables")] +#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir, typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn change_break_label() { let mut _x = 0; @@ -168,7 +168,7 @@ pub fn change_continue_label() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, TypeckTables")] +#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn change_continue_label() { let mut _x = 0; @@ -193,7 +193,7 @@ pub fn change_continue_to_break() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir, TypeckTables")] +#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir, typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn change_continue_to_break() { let mut _x = 0; diff --git a/src/test/incremental/hashes/match_expressions.rs b/src/test/incremental/hashes/match_expressions.rs index 37f6aa9ee9b..02f2cd6634d 100644 --- a/src/test/incremental/hashes/match_expressions.rs +++ b/src/test/incremental/hashes/match_expressions.rs @@ -26,7 +26,7 @@ pub fn add_arm(x: u32) -> u32 { #[cfg(not(cfail1))] #[rustc_clean(cfg="cfail2", - except="HirBody,mir_built,optimized_mir,TypeckTables")] + except="HirBody,mir_built,optimized_mir,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn add_arm(x: u32) -> u32 { match x { @@ -75,7 +75,7 @@ pub fn add_guard_clause(x: u32, y: bool) -> u32 { #[cfg(not(cfail1))] #[rustc_clean(cfg="cfail2", - except="HirBody,mir_built,optimized_mir,TypeckTables")] + except="HirBody,mir_built,optimized_mir,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn add_guard_clause(x: u32, y: bool) -> u32 { match x { @@ -99,7 +99,7 @@ pub fn change_guard_clause(x: u32, y: bool) -> u32 { #[cfg(not(cfail1))] #[rustc_clean(cfg="cfail2", - except="HirBody,mir_built,optimized_mir,TypeckTables")] + except="HirBody,mir_built,optimized_mir,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn change_guard_clause(x: u32, y: bool) -> u32 { match x { @@ -123,7 +123,7 @@ pub fn add_at_binding(x: u32) -> u32 { #[cfg(not(cfail1))] #[rustc_clean(cfg="cfail2", - except="HirBody,mir_built,optimized_mir,TypeckTables")] + except="HirBody,mir_built,optimized_mir,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn add_at_binding(x: u32) -> u32 { match x { @@ -170,7 +170,7 @@ pub fn change_simple_name_to_pattern(x: u32) -> u32 { #[cfg(not(cfail1))] #[rustc_clean(cfg="cfail2", - except="HirBody,mir_built,optimized_mir,TypeckTables")] + except="HirBody,mir_built,optimized_mir,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn change_simple_name_to_pattern(x: u32) -> u32 { match (x, x & 1) { @@ -216,7 +216,7 @@ pub fn change_mutability_of_binding_in_pattern(x: u32) -> u32 { #[cfg(not(cfail1))] #[rustc_clean(cfg="cfail2", - except="HirBody,mir_built,optimized_mir,TypeckTables")] + except="HirBody,mir_built,optimized_mir,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn change_mutability_of_binding_in_pattern(x: u32) -> u32 { match (x, x & 1) { @@ -238,7 +238,7 @@ pub fn add_ref_to_binding_in_pattern(x: u32) -> u32 { #[cfg(not(cfail1))] #[rustc_clean(cfg="cfail2", - except="HirBody,mir_built,optimized_mir,TypeckTables")] + except="HirBody,mir_built,optimized_mir,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn add_ref_to_binding_in_pattern(x: u32) -> u32 { match (x, x & 1) { @@ -260,7 +260,7 @@ pub fn add_amp_to_binding_in_pattern(x: u32) -> u32 { #[cfg(not(cfail1))] #[rustc_clean(cfg="cfail2", -except="HirBody,mir_built,optimized_mir,TypeckTables")] +except="HirBody,mir_built,optimized_mir,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn add_amp_to_binding_in_pattern(x: u32) -> u32 { match (&x, x & 1) { @@ -307,7 +307,7 @@ pub fn add_alternative_to_arm(x: u32) -> u32 { #[cfg(not(cfail1))] #[rustc_clean(cfg="cfail2", - except="HirBody,mir_built,optimized_mir,TypeckTables")] + except="HirBody,mir_built,optimized_mir,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn add_alternative_to_arm(x: u32) -> u32 { match x { diff --git a/src/test/incremental/hashes/struct_constructors.rs b/src/test/incremental/hashes/struct_constructors.rs index 3190f65a817..e478ff96c32 100644 --- a/src/test/incremental/hashes/struct_constructors.rs +++ b/src/test/incremental/hashes/struct_constructors.rs @@ -54,7 +54,7 @@ pub fn change_field_order_regular_struct() -> RegularStruct { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody,TypeckTables")] +#[rustc_clean(cfg="cfail2", except="HirBody,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn change_field_order_regular_struct() -> RegularStruct { RegularStruct { @@ -82,7 +82,7 @@ pub fn add_field_regular_struct() -> RegularStruct { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody,optimized_mir,mir_built,TypeckTables")] +#[rustc_clean(cfg="cfail2", except="HirBody,optimized_mir,mir_built,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn add_field_regular_struct() -> RegularStruct { let struct1 = RegularStruct { @@ -117,7 +117,7 @@ pub fn change_field_label_regular_struct() -> RegularStruct { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody,optimized_mir,mir_built,TypeckTables")] +#[rustc_clean(cfg="cfail2", except="HirBody,optimized_mir,mir_built,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn change_field_label_regular_struct() -> RegularStruct { let struct1 = RegularStruct { @@ -152,7 +152,7 @@ pub fn change_constructor_path_regular_struct() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody,optimized_mir,mir_built,TypeckTables")] +#[rustc_clean(cfg="cfail2", except="HirBody,optimized_mir,mir_built,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn change_constructor_path_regular_struct() { let _ = RegularStruct2 { @@ -173,7 +173,7 @@ pub mod change_constructor_path_indirectly_regular_struct { #[rustc_clean( cfg="cfail2", - except="FnSignature,Hir,HirBody,optimized_mir,mir_built,TypeckTables" + except="fn_sig,Hir,HirBody,optimized_mir,mir_built,typeck_tables_of" )] #[rustc_clean(cfg="cfail3")] pub fn function() -> Struct { @@ -213,7 +213,7 @@ pub fn change_constructor_path_tuple_struct() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody,optimized_mir,mir_built,TypeckTables")] +#[rustc_clean(cfg="cfail2", except="HirBody,optimized_mir,mir_built,typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn change_constructor_path_tuple_struct() { let _ = TupleStruct2(0, 1, 2); @@ -230,7 +230,7 @@ pub mod change_constructor_path_indirectly_tuple_struct { #[rustc_clean( cfg="cfail2", - except="FnSignature,Hir,HirBody,optimized_mir,mir_built,TypeckTables" + except="fn_sig,Hir,HirBody,optimized_mir,mir_built,typeck_tables_of" )] #[rustc_clean(cfg="cfail3")] pub fn function() -> Struct { diff --git a/src/test/incremental/hashes/unary_and_binary_exprs.rs b/src/test/incremental/hashes/unary_and_binary_exprs.rs index f3331ec61cb..8c53ae6a038 100644 --- a/src/test/incremental/hashes/unary_and_binary_exprs.rs +++ b/src/test/incremental/hashes/unary_and_binary_exprs.rs @@ -81,7 +81,7 @@ pub fn var_deref(x: &i32, y: &i32) -> i32 { } #[cfg(not(cfail1))] -#[rustc_clean(except="HirBody,optimized_mir,mir_built,TypeckTables", cfg="cfail2")] +#[rustc_clean(except="HirBody,optimized_mir,mir_built,typeck_tables_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] pub fn var_deref(x: &i32, y: &i32) -> i32 { *y @@ -368,7 +368,7 @@ pub fn type_cast(a: u8) -> u64 { } #[cfg(not(cfail1))] -#[rustc_clean(except="HirBody,optimized_mir,mir_built,TypeckTables", cfg="cfail2")] +#[rustc_clean(except="HirBody,optimized_mir,mir_built,typeck_tables_of", cfg="cfail2")] #[rustc_clean(cfg="cfail3")] pub fn type_cast(a: u8) -> u64 { let b = a as u32; diff --git a/src/test/incremental/hashes/while_let_loops.rs b/src/test/incremental/hashes/while_let_loops.rs index 7e866ae925e..2d48707561c 100644 --- a/src/test/incremental/hashes/while_let_loops.rs +++ b/src/test/incremental/hashes/while_let_loops.rs @@ -70,7 +70,7 @@ pub fn add_break() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir, TypeckTables")] +#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir, typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn add_break() { let mut _x = 0; @@ -141,7 +141,7 @@ pub fn change_break_label() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir, TypeckTables")] +#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir, typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn change_break_label() { let mut _x = 0; @@ -191,7 +191,7 @@ pub fn change_continue_label() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir, TypeckTables")] +#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir, typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn change_continue_label() { let mut _x = 0; diff --git a/src/test/incremental/hashes/while_loops.rs b/src/test/incremental/hashes/while_loops.rs index cbd1341fdd4..79a3bc9b205 100644 --- a/src/test/incremental/hashes/while_loops.rs +++ b/src/test/incremental/hashes/while_loops.rs @@ -70,7 +70,7 @@ pub fn add_break() { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir, TypeckTables")] +#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, optimized_mir, typeck_tables_of")] #[rustc_clean(cfg="cfail3")] pub fn add_break() { let mut _x = 0; diff --git a/src/test/incremental/hello_world.rs b/src/test/incremental/hello_world.rs index e2e15eb958f..e4d8c56752c 100644 --- a/src/test/incremental/hello_world.rs +++ b/src/test/incremental/hello_world.rs @@ -21,7 +21,7 @@ mod x { mod y { use x; - #[rustc_clean(label="TypeckTables", cfg="rpass2")] + #[rustc_clean(label="typeck_tables_of", cfg="rpass2")] pub fn yyyy() { x::xxxx(); } @@ -30,7 +30,7 @@ mod y { mod z { use y; - #[rustc_clean(label="TypeckTables", cfg="rpass2")] + #[rustc_clean(label="typeck_tables_of", cfg="rpass2")] pub fn z() { y::yyyy(); } diff --git a/src/test/incremental/ich_method_call_trait_scope.rs b/src/test/incremental/ich_method_call_trait_scope.rs index d4b170bd277..9dfd2ae2511 100644 --- a/src/test/incremental/ich_method_call_trait_scope.rs +++ b/src/test/incremental/ich_method_call_trait_scope.rs @@ -28,14 +28,14 @@ mod mod3 { #[rustc_clean(label="Hir", cfg="rpass2")] #[rustc_clean(label="HirBody", cfg="rpass2")] - #[rustc_dirty(label="TypeckTables", cfg="rpass2")] + #[rustc_dirty(label="typeck_tables_of", cfg="rpass2")] fn bar() { ().method(); } #[rustc_clean(label="Hir", cfg="rpass2")] #[rustc_clean(label="HirBody", cfg="rpass2")] - #[rustc_clean(label="TypeckTables", cfg="rpass2")] + #[rustc_clean(label="typeck_tables_of", cfg="rpass2")] fn baz() { 22; // no method call, traits in scope don't matter } diff --git a/src/test/incremental/rlib_cross_crate/b.rs b/src/test/incremental/rlib_cross_crate/b.rs index 7c3dcf3a815..81b84ba741d 100644 --- a/src/test/incremental/rlib_cross_crate/b.rs +++ b/src/test/incremental/rlib_cross_crate/b.rs @@ -12,15 +12,15 @@ extern crate a; -#[rustc_dirty(label="TypeckTables", cfg="rpass2")] -#[rustc_clean(label="TypeckTables", cfg="rpass3")] +#[rustc_dirty(label="typeck_tables_of", cfg="rpass2")] +#[rustc_clean(label="typeck_tables_of", cfg="rpass3")] pub fn use_X() -> u32 { let x: a::X = 22; x as u32 } -#[rustc_clean(label="TypeckTables", cfg="rpass2")] -#[rustc_clean(label="TypeckTables", cfg="rpass3")] +#[rustc_clean(label="typeck_tables_of", cfg="rpass2")] +#[rustc_clean(label="typeck_tables_of", cfg="rpass3")] pub fn use_Y() { let x: a::Y = 'c'; } diff --git a/src/test/incremental/string_constant.rs b/src/test/incremental/string_constant.rs index db2660bb661..c39d4145b58 100644 --- a/src/test/incremental/string_constant.rs +++ b/src/test/incremental/string_constant.rs @@ -28,7 +28,7 @@ pub mod x { pub mod y { use x; - #[rustc_clean(label="TypeckTables", cfg="cfail2")] + #[rustc_clean(label="typeck_tables_of", cfg="cfail2")] #[rustc_clean(label="optimized_mir", cfg="cfail2")] pub fn y() { x::x(); @@ -38,7 +38,7 @@ pub mod y { pub mod z { use y; - #[rustc_clean(label="TypeckTables", cfg="cfail2")] + #[rustc_clean(label="typeck_tables_of", cfg="cfail2")] #[rustc_clean(label="optimized_mir", cfg="cfail2")] pub fn z() { y::y(); diff --git a/src/test/incremental/struct_add_field.rs b/src/test/incremental/struct_add_field.rs index d019a3d2ab8..d2e1e7decf5 100644 --- a/src/test/incremental/struct_add_field.rs +++ b/src/test/incremental/struct_add_field.rs @@ -21,17 +21,17 @@ pub struct Y { pub y: char } -#[rustc_dirty(label="TypeckTables", cfg="rpass2")] +#[rustc_dirty(label="typeck_tables_of", cfg="rpass2")] pub fn use_X(x: X) -> u32 { x.x as u32 } -#[rustc_dirty(label="TypeckTables", cfg="rpass2")] +#[rustc_dirty(label="typeck_tables_of", cfg="rpass2")] pub fn use_EmbedX(embed: EmbedX) -> u32 { embed.x.x as u32 } -#[rustc_clean(label="TypeckTables", cfg="rpass2")] +#[rustc_clean(label="typeck_tables_of", cfg="rpass2")] pub fn use_Y() { let x: Y = Y { y: 'c' }; } diff --git a/src/test/incremental/struct_change_field_name.rs b/src/test/incremental/struct_change_field_name.rs index 28011efed9c..68356f703bc 100644 --- a/src/test/incremental/struct_change_field_name.rs +++ b/src/test/incremental/struct_change_field_name.rs @@ -24,7 +24,7 @@ pub struct Y { pub y: char } -#[rustc_dirty(label="TypeckTables", cfg="cfail2")] +#[rustc_dirty(label="typeck_tables_of", cfg="cfail2")] pub fn use_X() -> u32 { let x: X = X { x: 22 }; //[cfail2]~^ ERROR struct `X` has no field named `x` @@ -32,13 +32,13 @@ pub fn use_X() -> u32 { //[cfail2]~^ ERROR no field `x` on type `X` } -#[rustc_dirty(label="TypeckTables", cfg="cfail2")] +#[rustc_dirty(label="typeck_tables_of", cfg="cfail2")] pub fn use_EmbedX(embed: EmbedX) -> u32 { embed.x.x as u32 //[cfail2]~^ ERROR no field `x` on type `X` } -#[rustc_clean(label="TypeckTables", cfg="cfail2")] +#[rustc_clean(label="typeck_tables_of", cfg="cfail2")] pub fn use_Y() { let x: Y = Y { y: 'c' }; } diff --git a/src/test/incremental/struct_change_field_type.rs b/src/test/incremental/struct_change_field_type.rs index cb4a83c2f9a..308ec84fa72 100644 --- a/src/test/incremental/struct_change_field_type.rs +++ b/src/test/incremental/struct_change_field_type.rs @@ -24,19 +24,19 @@ pub struct Y { pub y: char } -#[rustc_dirty(label="TypeckTables", cfg="rpass2")] +#[rustc_dirty(label="typeck_tables_of", cfg="rpass2")] pub fn use_X() -> u32 { let x: X = X { x: 22 }; x.x as u32 } -#[rustc_dirty(label="TypeckTables", cfg="rpass2")] +#[rustc_dirty(label="typeck_tables_of", cfg="rpass2")] pub fn use_EmbedX(x: EmbedX) -> u32 { let x: X = X { x: 22 }; x.x as u32 } -#[rustc_clean(label="TypeckTables", cfg="rpass2")] +#[rustc_clean(label="typeck_tables_of", cfg="rpass2")] pub fn use_Y() { let x: Y = Y { y: 'c' }; } diff --git a/src/test/incremental/struct_change_field_type_cross_crate/b.rs b/src/test/incremental/struct_change_field_type_cross_crate/b.rs index ecfd24cbaf4..9d84c2cf773 100644 --- a/src/test/incremental/struct_change_field_type_cross_crate/b.rs +++ b/src/test/incremental/struct_change_field_type_cross_crate/b.rs @@ -8,18 +8,18 @@ extern crate a; use a::*; -#[rustc_dirty(label="TypeckTables", cfg="rpass2")] +#[rustc_dirty(label="typeck_tables_of", cfg="rpass2")] pub fn use_X() -> u32 { let x: X = X { x: 22 }; x.x as u32 } -#[rustc_dirty(label="TypeckTables", cfg="rpass2")] +#[rustc_dirty(label="typeck_tables_of", cfg="rpass2")] pub fn use_EmbedX(embed: EmbedX) -> u32 { embed.x.x as u32 } -#[rustc_clean(label="TypeckTables", cfg="rpass2")] +#[rustc_clean(label="typeck_tables_of", cfg="rpass2")] pub fn use_Y() { let x: Y = Y { y: 'c' }; } diff --git a/src/test/incremental/struct_change_nothing.rs b/src/test/incremental/struct_change_nothing.rs index e62c004a83d..bbded1da216 100644 --- a/src/test/incremental/struct_change_nothing.rs +++ b/src/test/incremental/struct_change_nothing.rs @@ -24,19 +24,19 @@ pub struct Y { pub y: char } -#[rustc_clean(label="TypeckTables", cfg="rpass2")] +#[rustc_clean(label="typeck_tables_of", cfg="rpass2")] pub fn use_X() -> u32 { let x: X = X { x: 22 }; x.x as u32 } -#[rustc_clean(label="TypeckTables", cfg="rpass2")] +#[rustc_clean(label="typeck_tables_of", cfg="rpass2")] pub fn use_EmbedX(x: EmbedX) -> u32 { let x: X = X { x: 22 }; x.x as u32 } -#[rustc_clean(label="TypeckTables", cfg="rpass2")] +#[rustc_clean(label="typeck_tables_of", cfg="rpass2")] pub fn use_Y() { let x: Y = Y { y: 'c' }; } diff --git a/src/test/incremental/struct_remove_field.rs b/src/test/incremental/struct_remove_field.rs index 572a2c640e6..4c4028bbe5b 100644 --- a/src/test/incremental/struct_remove_field.rs +++ b/src/test/incremental/struct_remove_field.rs @@ -25,17 +25,17 @@ pub struct Y { pub y: char } -#[rustc_dirty(label="TypeckTables", cfg="rpass2")] +#[rustc_dirty(label="typeck_tables_of", cfg="rpass2")] pub fn use_X(x: X) -> u32 { x.x as u32 } -#[rustc_dirty(label="TypeckTables", cfg="rpass2")] +#[rustc_dirty(label="typeck_tables_of", cfg="rpass2")] pub fn use_EmbedX(embed: EmbedX) -> u32 { embed.x.x as u32 } -#[rustc_clean(label="TypeckTables", cfg="rpass2")] +#[rustc_clean(label="typeck_tables_of", cfg="rpass2")] pub fn use_Y() { let x: Y = Y { y: 'c' }; } diff --git a/src/test/incremental/type_alias_cross_crate/b.rs b/src/test/incremental/type_alias_cross_crate/b.rs index 9261a0fb290..cef2e4bab12 100644 --- a/src/test/incremental/type_alias_cross_crate/b.rs +++ b/src/test/incremental/type_alias_cross_crate/b.rs @@ -6,15 +6,15 @@ extern crate a; -#[rustc_dirty(label="TypeckTables", cfg="rpass2")] -#[rustc_clean(label="TypeckTables", cfg="rpass3")] +#[rustc_dirty(label="typeck_tables_of", cfg="rpass2")] +#[rustc_clean(label="typeck_tables_of", cfg="rpass3")] pub fn use_X() -> u32 { let x: a::X = 22; x as u32 } -#[rustc_clean(label="TypeckTables", cfg="rpass2")] -#[rustc_clean(label="TypeckTables", cfg="rpass3")] +#[rustc_clean(label="typeck_tables_of", cfg="rpass2")] +#[rustc_clean(label="typeck_tables_of", cfg="rpass3")] pub fn use_Y() { let x: a::Y = 'c'; } diff --git a/src/test/mir-opt/match_false_edges.rs b/src/test/mir-opt/match_false_edges.rs index 0cbf048697a..7ac36a22274 100644 --- a/src/test/mir-opt/match_false_edges.rs +++ b/src/test/mir-opt/match_false_edges.rs @@ -70,8 +70,8 @@ fn main() { // } // bb8: { // binding1 and guard // StorageLive(_6); -// _6 = &(((promoted[1]: std::option::Option<i32>) as Some).0: i32); -// _4 = &shallow (promoted[0]: std::option::Option<i32>); +// _6 = &(((promoted[0]: std::option::Option<i32>) as Some).0: i32); +// _4 = &shallow _2; // StorageLive(_7); // _7 = const guard() -> [return: bb9, unwind: bb1]; // } diff --git a/src/test/run-make-fulldeps/lto-dylib-dep/Makefile b/src/test/run-make-fulldeps/lto-dylib-dep/Makefile new file mode 100644 index 00000000000..ab8ee6c2ef7 --- /dev/null +++ b/src/test/run-make-fulldeps/lto-dylib-dep/Makefile @@ -0,0 +1,10 @@ +-include ../tools.mk + +# Test that we don't run into an assertion when using a Rust dylib dependency +# while compiling with full LTO. +# See https://github.com/rust-lang/rust/issues/59137 + +all: + $(RUSTC) a_dylib.rs --crate-type=dylib -C prefer-dynamic + $(RUSTC) main.rs -C lto + $(call RUN,main) diff --git a/src/test/run-make-fulldeps/lto-dylib-dep/a_dylib.rs b/src/test/run-make-fulldeps/lto-dylib-dep/a_dylib.rs new file mode 100644 index 00000000000..c5a35296f89 --- /dev/null +++ b/src/test/run-make-fulldeps/lto-dylib-dep/a_dylib.rs @@ -0,0 +1,4 @@ + +pub fn foo() { + println!("bar"); +} diff --git a/src/test/run-make-fulldeps/lto-dylib-dep/main.rs b/src/test/run-make-fulldeps/lto-dylib-dep/main.rs new file mode 100644 index 00000000000..af0955e7f35 --- /dev/null +++ b/src/test/run-make-fulldeps/lto-dylib-dep/main.rs @@ -0,0 +1,6 @@ + +extern crate a_dylib; + +fn main() { + a_dylib::foo(); +} diff --git a/src/test/run-make-fulldeps/pgo-gen-lto/Makefile b/src/test/run-make-fulldeps/pgo-gen-lto/Makefile index e358314c0d0..7c19961b1e4 100644 --- a/src/test/run-make-fulldeps/pgo-gen-lto/Makefile +++ b/src/test/run-make-fulldeps/pgo-gen-lto/Makefile @@ -1,10 +1,8 @@ -include ../tools.mk -# ignore-windows - all: ifeq ($(PROFILER_SUPPORT),1) - $(RUSTC) -Copt-level=3 -Clto=fat -Z pgo-gen="$(TMPDIR)/test.profraw" test.rs + $(RUSTC) -Copt-level=3 -Clto=fat -Z pgo-gen="$(TMPDIR)" test.rs $(call RUN,test) || exit 1 - [ -e "$(TMPDIR)/test.profraw" ] || (echo "No .profraw file"; exit 1) + [ -e "$(TMPDIR)"/default_*.profraw ] || (echo "No .profraw file"; exit 1) endif diff --git a/src/test/run-make-fulldeps/pgo-gen-no-imp-symbols/Makefile b/src/test/run-make-fulldeps/pgo-gen-no-imp-symbols/Makefile new file mode 100644 index 00000000000..dc52e91317a --- /dev/null +++ b/src/test/run-make-fulldeps/pgo-gen-no-imp-symbols/Makefile @@ -0,0 +1,11 @@ +-include ../tools.mk + +all: +ifeq ($(PROFILER_SUPPORT),1) + $(RUSTC) -O -Ccodegen-units=1 -Z pgo-gen="$(TMPDIR)/test.profraw" --emit=llvm-ir test.rs + # We expect symbols starting with "__llvm_profile_". + $(CGREP) "__llvm_profile_" < $(TMPDIR)/test.ll + # We do NOT expect the "__imp_" version of these symbols. + $(CGREP) -v "__imp___llvm_profile_" < $(TMPDIR)/test.ll # 64 bit + $(CGREP) -v "__imp____llvm_profile_" < $(TMPDIR)/test.ll # 32 bit +endif diff --git a/src/test/run-make-fulldeps/pgo-gen-no-imp-symbols/test.rs b/src/test/run-make-fulldeps/pgo-gen-no-imp-symbols/test.rs new file mode 100644 index 00000000000..f328e4d9d04 --- /dev/null +++ b/src/test/run-make-fulldeps/pgo-gen-no-imp-symbols/test.rs @@ -0,0 +1 @@ +fn main() {} diff --git a/src/test/run-make-fulldeps/pgo-gen/Makefile b/src/test/run-make-fulldeps/pgo-gen/Makefile index 1961dff8d78..0469c4443d8 100644 --- a/src/test/run-make-fulldeps/pgo-gen/Makefile +++ b/src/test/run-make-fulldeps/pgo-gen/Makefile @@ -1,10 +1,8 @@ -include ../tools.mk -# ignore-windows - all: ifeq ($(PROFILER_SUPPORT),1) - $(RUSTC) -g -Z pgo-gen="$(TMPDIR)/test.profraw" test.rs + $(RUSTC) -g -Z pgo-gen="$(TMPDIR)" test.rs $(call RUN,test) || exit 1 - [ -e "$(TMPDIR)/test.profraw" ] || (echo "No .profraw file"; exit 1) + [ -e "$(TMPDIR)"/default_*.profraw ] || (echo "No .profraw file"; exit 1) endif diff --git a/src/test/run-make-fulldeps/sysroot-crates-are-unstable/test.py b/src/test/run-make-fulldeps/sysroot-crates-are-unstable/test.py index e0fa4e8f5de..855b6421cf8 100644 --- a/src/test/run-make-fulldeps/sysroot-crates-are-unstable/test.py +++ b/src/test/run-make-fulldeps/sysroot-crates-are-unstable/test.py @@ -7,8 +7,8 @@ from subprocess import PIPE, Popen # This is a whitelist of files which are stable crates or simply are not crates, # we don't check for the instability of these crates as they're all stable! -STABLE_CRATES = ['std', 'core', 'proc_macro', 'rsbegin.o', 'rsend.o', 'dllcrt2.o', 'crt2.o', - 'clang_rt'] +STABLE_CRATES = ['std', 'alloc', 'core', 'proc_macro', + 'rsbegin.o', 'rsend.o', 'dllcrt2.o', 'crt2.o', 'clang_rt'] def convert_to_string(s): diff --git a/src/test/run-pass-fulldeps/auxiliary/issue-40001-plugin.rs b/src/test/run-pass-fulldeps/auxiliary/issue-40001-plugin.rs index 09aa106ebbd..76d0906f97c 100644 --- a/src/test/run-pass-fulldeps/auxiliary/issue-40001-plugin.rs +++ b/src/test/run-pass-fulldeps/auxiliary/issue-40001-plugin.rs @@ -26,21 +26,14 @@ pub fn plugin_registrar(reg: &mut Registry) { reg.register_attribute("whitelisted_attr".to_string(), Whitelisted); } -declare_lint!(MISSING_WHITELISTED_ATTR, Deny, - "Checks for missing `whitelisted_attr` attribute"); - -struct MissingWhitelistedAttrPass; - -impl LintPass for MissingWhitelistedAttrPass { - fn name(&self) -> &'static str { - "MissingWhitelistedAttrPass" - } - - fn get_lints(&self) -> LintArray { - lint_array!(MISSING_WHITELISTED_ATTR) - } +declare_lint! { + MISSING_WHITELISTED_ATTR, + Deny, + "Checks for missing `whitelisted_attr` attribute" } +declare_lint_pass!(MissingWhitelistedAttrPass => [MISSING_WHITELISTED_ATTR]); + impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingWhitelistedAttrPass { fn check_fn(&mut self, cx: &LateContext<'a, 'tcx>, diff --git a/src/test/run-pass/array-slice-vec/vec-macro-no-std.rs b/src/test/run-pass/array-slice-vec/vec-macro-no-std.rs index 7f7f1e43315..443895f7c48 100644 --- a/src/test/run-pass/array-slice-vec/vec-macro-no-std.rs +++ b/src/test/run-pass/array-slice-vec/vec-macro-no-std.rs @@ -2,7 +2,7 @@ // ignore-emscripten no no_std executables -#![feature(lang_items, start, rustc_private, alloc)] +#![feature(lang_items, start, rustc_private)] #![no_std] extern crate std as other; diff --git a/src/test/run-pass/async-await.rs b/src/test/run-pass/async-await.rs index 1843feed927..518452aefc1 100644 --- a/src/test/run-pass/async-await.rs +++ b/src/test/run-pass/async-await.rs @@ -1,7 +1,7 @@ // edition:2018 // aux-build:arc_wake.rs -#![feature(arbitrary_self_types, async_await, await_macro, futures_api)] +#![feature(async_await, await_macro, futures_api)] extern crate arc_wake; @@ -11,9 +11,7 @@ use std::sync::{ Arc, atomic::{self, AtomicUsize}, }; -use std::task::{ - Poll, Waker, -}; +use std::task::{Context, Poll}; use arc_wake::ArcWake; struct Counter { @@ -21,7 +19,10 @@ struct Counter { } impl ArcWake for Counter { - fn wake(arc_self: &Arc<Self>) { + fn wake(self: Arc<Self>) { + Self::wake_by_ref(&self) + } + fn wake_by_ref(arc_self: &Arc<Self>) { arc_self.wakes.fetch_add(1, atomic::Ordering::SeqCst); } } @@ -32,11 +33,11 @@ fn wake_and_yield_once() -> WakeOnceThenComplete { WakeOnceThenComplete(false) } impl Future for WakeOnceThenComplete { type Output = (); - fn poll(mut self: Pin<&mut Self>, waker: &Waker) -> Poll<()> { + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { if self.0 { Poll::Ready(()) } else { - waker.wake(); + cx.waker().wake_by_ref(); self.0 = true; Poll::Pending } @@ -79,6 +80,11 @@ async fn async_fn(x: u8) -> u8 { x } +async fn generic_async_fn<T>(x: T) -> T { + await!(wake_and_yield_once()); + x +} + async fn async_fn_with_borrow(x: &u8) -> u8 { await!(wake_and_yield_once()); *x @@ -96,14 +102,21 @@ fn async_fn_with_impl_future_named_lifetime<'a>(x: &'a u8) -> impl Future<Output } } -async fn async_fn_with_named_lifetime_multiple_args<'a>(x: &'a u8, _y: &'a u8) -> u8 { +/* FIXME(cramertj) support when `existential type T<'a, 'b>:;` works +async fn async_fn_multiple_args(x: &u8, _y: &u8) -> u8 { + await!(wake_and_yield_once()); + *x +} +*/ + +async fn async_fn_multiple_args_named_lifetime<'a>(x: &'a u8, _y: &'a u8) -> u8 { await!(wake_and_yield_once()); *x } fn async_fn_with_internal_borrow(y: u8) -> impl Future<Output = u8> { async move { - await!(async_fn_with_borrow(&y)) + await!(async_fn_with_borrow_named_lifetime(&y)) } } @@ -134,10 +147,11 @@ where let mut fut = Box::pin(f(9)); let counter = Arc::new(Counter { wakes: AtomicUsize::new(0) }); let waker = ArcWake::into_waker(counter.clone()); + let mut cx = Context::from_waker(&waker); assert_eq!(0, counter.wakes.load(atomic::Ordering::SeqCst)); - assert_eq!(Poll::Pending, fut.as_mut().poll(&waker)); + assert_eq!(Poll::Pending, fut.as_mut().poll(&mut cx)); assert_eq!(1, counter.wakes.load(atomic::Ordering::SeqCst)); - assert_eq!(Poll::Ready(9), fut.as_mut().poll(&waker)); + assert_eq!(Poll::Ready(9), fut.as_mut().poll(&mut cx)); } fn main() { @@ -162,6 +176,7 @@ fn main() { async_nonmove_block, async_closure, async_fn, + generic_async_fn, async_fn_with_internal_borrow, Foo::async_method, |x| { @@ -170,7 +185,6 @@ fn main() { } }, } - test_with_borrow! { async_block_with_borrow_named_lifetime, async_fn_with_borrow, @@ -178,7 +192,7 @@ fn main() { async_fn_with_impl_future_named_lifetime, |x| { async move { - await!(async_fn_with_named_lifetime_multiple_args(x, x)) + await!(async_fn_multiple_args_named_lifetime(x, x)) } }, } diff --git a/src/test/run-pass/auxiliary/arc_wake.rs b/src/test/run-pass/auxiliary/arc_wake.rs index 034e378af7f..93e074e7ee5 100644 --- a/src/test/run-pass/auxiliary/arc_wake.rs +++ b/src/test/run-pass/auxiliary/arc_wake.rs @@ -1,36 +1,41 @@ // edition:2018 -#![feature(arbitrary_self_types, futures_api)] +#![feature(futures_api)] use std::sync::Arc; use std::task::{ - Poll, Waker, RawWaker, RawWakerVTable, + Waker, RawWaker, RawWakerVTable, }; macro_rules! waker_vtable { ($ty:ident) => { - &RawWakerVTable { - clone: clone_arc_raw::<$ty>, - drop: drop_arc_raw::<$ty>, - wake: wake_arc_raw::<$ty>, - } + &RawWakerVTable::new( + clone_arc_raw::<$ty>, + wake_arc_raw::<$ty>, + wake_by_ref_arc_raw::<$ty>, + drop_arc_raw::<$ty>, + ) }; } pub trait ArcWake { - fn wake(arc_self: &Arc<Self>); + fn wake(self: Arc<Self>); + + fn wake_by_ref(arc_self: &Arc<Self>) { + arc_self.clone().wake() + } fn into_waker(wake: Arc<Self>) -> Waker where Self: Sized { - let ptr = Arc::into_raw(wake) as *const(); + let ptr = Arc::into_raw(wake) as *const (); unsafe { - Waker::new_unchecked(RawWaker::new(ptr, waker_vtable!(Self))) + Waker::from_raw(RawWaker::new(ptr, waker_vtable!(Self))) } } } -unsafe fn increase_refcount<T: ArcWake>(data: *const()) { +unsafe fn increase_refcount<T: ArcWake>(data: *const ()) { // Retain Arc by creating a copy let arc: Arc<T> = Arc::from_raw(data as *const T); let arc_clone = arc.clone(); @@ -39,18 +44,23 @@ unsafe fn increase_refcount<T: ArcWake>(data: *const()) { let _ = Arc::into_raw(arc_clone); } -unsafe fn clone_arc_raw<T: ArcWake>(data: *const()) -> RawWaker { +unsafe fn clone_arc_raw<T: ArcWake>(data: *const ()) -> RawWaker { increase_refcount::<T>(data); RawWaker::new(data, waker_vtable!(T)) } -unsafe fn drop_arc_raw<T: ArcWake>(data: *const()) { +unsafe fn drop_arc_raw<T: ArcWake>(data: *const ()) { // Drop Arc let _: Arc<T> = Arc::from_raw(data as *const T); } -unsafe fn wake_arc_raw<T: ArcWake>(data: *const()) { +unsafe fn wake_arc_raw<T: ArcWake>(data: *const ()) { + let arc: Arc<T> = Arc::from_raw(data as *const T); + ArcWake::wake(arc); +} + +unsafe fn wake_by_ref_arc_raw<T: ArcWake>(data: *const ()) { let arc: Arc<T> = Arc::from_raw(data as *const T); - ArcWake::wake(&arc); + ArcWake::wake_by_ref(&arc); let _ = Arc::into_raw(arc); } diff --git a/src/test/run-pass/extern/extern-prelude-core.rs b/src/test/run-pass/extern/extern-prelude-core.rs index a5d31009f9c..f0d43404b00 100644 --- a/src/test/run-pass/extern/extern-prelude-core.rs +++ b/src/test/run-pass/extern/extern-prelude-core.rs @@ -1,5 +1,5 @@ // run-pass -#![feature(extern_prelude, lang_items, start, alloc)] +#![feature(extern_prelude, lang_items, start)] #![no_std] extern crate std as other; diff --git a/src/test/run-pass/extern/extern-prelude-core.stderr b/src/test/run-pass/extern/extern-prelude-core.stderr index 417483af707..8d2a0b7425f 100644 --- a/src/test/run-pass/extern/extern-prelude-core.stderr +++ b/src/test/run-pass/extern/extern-prelude-core.stderr @@ -1,7 +1,7 @@ warning: the feature `extern_prelude` has been stable since 1.30.0 and no longer requires an attribute to enable --> $DIR/extern-prelude-core.rs:2:12 | -LL | #![feature(extern_prelude, lang_items, start, alloc)] +LL | #![feature(extern_prelude, lang_items, start)] | ^^^^^^^^^^^^^^ | = note: #[warn(stable_features)] on by default diff --git a/src/test/run-pass/for-loop-while/for-loop-no-std.rs b/src/test/run-pass/for-loop-while/for-loop-no-std.rs index 877429f5d39..65a33c5f16f 100644 --- a/src/test/run-pass/for-loop-while/for-loop-no-std.rs +++ b/src/test/run-pass/for-loop-while/for-loop-no-std.rs @@ -1,6 +1,6 @@ // run-pass #![allow(unused_imports)] -#![feature(lang_items, start, alloc)] +#![feature(lang_items, start)] #![no_std] extern crate std as other; diff --git a/src/test/run-pass/format-no-std.rs b/src/test/run-pass/format-no-std.rs index 0f3a5c277b4..32f7a4a07c4 100644 --- a/src/test/run-pass/format-no-std.rs +++ b/src/test/run-pass/format-no-std.rs @@ -1,6 +1,6 @@ // ignore-emscripten no no_std executables -#![feature(lang_items, start, alloc)] +#![feature(lang_items, start)] #![no_std] extern crate std as other; diff --git a/src/test/run-pass/futures-api.rs b/src/test/run-pass/futures-api.rs index fd4b585d345..6094f15569b 100644 --- a/src/test/run-pass/futures-api.rs +++ b/src/test/run-pass/futures-api.rs @@ -1,7 +1,6 @@ // aux-build:arc_wake.rs -#![feature(arbitrary_self_types, futures_api)] -#![allow(unused)] +#![feature(futures_api)] extern crate arc_wake; @@ -12,7 +11,7 @@ use std::sync::{ atomic::{self, AtomicUsize}, }; use std::task::{ - Poll, Waker, + Context, Poll, }; use arc_wake::ArcWake; @@ -21,7 +20,10 @@ struct Counter { } impl ArcWake for Counter { - fn wake(arc_self: &Arc<Self>) { + fn wake(self: Arc<Self>) { + Self::wake_by_ref(&self) + } + fn wake_by_ref(arc_self: &Arc<Self>) { arc_self.wakes.fetch_add(1, atomic::Ordering::SeqCst); } } @@ -30,10 +32,11 @@ struct MyFuture; impl Future for MyFuture { type Output = (); - fn poll(self: Pin<&mut Self>, waker: &Waker) -> Poll<Self::Output> { + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { // Wake twice - waker.wake(); - waker.wake(); + let waker = cx.waker(); + waker.wake_by_ref(); + waker.wake_by_ref(); Poll::Ready(()) } } @@ -44,10 +47,11 @@ fn test_waker() { }); let waker = ArcWake::into_waker(counter.clone()); assert_eq!(2, Arc::strong_count(&counter)); - - assert_eq!(Poll::Ready(()), Pin::new(&mut MyFuture).poll(&waker)); - assert_eq!(2, counter.wakes.load(atomic::Ordering::SeqCst)); - + { + let mut context = Context::from_waker(&waker); + assert_eq!(Poll::Ready(()), Pin::new(&mut MyFuture).poll(&mut context)); + assert_eq!(2, counter.wakes.load(atomic::Ordering::SeqCst)); + } drop(waker); assert_eq!(1, Arc::strong_count(&counter)); } diff --git a/src/test/run-pass/issue-59020.rs b/src/test/run-pass/issue-59020.rs new file mode 100644 index 00000000000..a2b11764a2f --- /dev/null +++ b/src/test/run-pass/issue-59020.rs @@ -0,0 +1,27 @@ +// edition:2018 +// run-pass +// ignore-emscripten no threads support + +use std::thread; +use std::time::Duration; + +fn main() { + let t1 = thread::spawn(|| { + let sleep = Duration::new(0,100_000); + for _ in 0..100 { + println!("Parking1"); + thread::park_timeout(sleep); + } + }); + + let t2 = thread::spawn(|| { + let sleep = Duration::new(0,100_000); + for _ in 0..100 { + println!("Parking2"); + thread::park_timeout(sleep); + } + }); + + t1.join().expect("Couldn't join thread 1"); + t2.join().expect("Couldn't join thread 2"); +} diff --git a/src/test/run-pass/issues/issue-58463.rs b/src/test/run-pass/issues/issue-58463.rs new file mode 100644 index 00000000000..8ab845366b7 --- /dev/null +++ b/src/test/run-pass/issues/issue-58463.rs @@ -0,0 +1,8 @@ +// run-pass +// compile-flags:-C debuginfo=2 +fn foo() -> impl Copy { + foo +} +fn main() { + foo(); +} diff --git a/src/test/run-pass/structs-enums/unit-like-struct-drop-run.rs b/src/test/run-pass/structs-enums/unit-like-struct-drop-run.rs index dfe73875215..980fd97e2c6 100644 --- a/src/test/run-pass/structs-enums/unit-like-struct-drop-run.rs +++ b/src/test/run-pass/structs-enums/unit-like-struct-drop-run.rs @@ -3,9 +3,6 @@ // Make sure the destructor is run for unit-like structs. - -#![feature(alloc)] - use std::thread; struct Foo; diff --git a/src/test/run-pass/traits/auxiliary/trait_alias.rs b/src/test/run-pass/traits/auxiliary/trait_alias.rs new file mode 100644 index 00000000000..9e412215512 --- /dev/null +++ b/src/test/run-pass/traits/auxiliary/trait_alias.rs @@ -0,0 +1,13 @@ +#![feature(trait_alias)] + +pub trait Hello { + fn hello(&self); +} + +pub struct Hi; + +impl Hello for Hi { + fn hello(&self) {} +} + +pub trait Greet = Hello; diff --git a/src/test/run-pass/traits/trait-alias-import-cross-crate.rs b/src/test/run-pass/traits/trait-alias-import-cross-crate.rs new file mode 100644 index 00000000000..975542ab49b --- /dev/null +++ b/src/test/run-pass/traits/trait-alias-import-cross-crate.rs @@ -0,0 +1,14 @@ +// run-pass +// aux-build:trait_alias.rs + +#![feature(trait_alias)] + +extern crate trait_alias; + +// Import only the alias, not the real trait. +use trait_alias::{Greet, Hi}; + +fn main() { + let hi = Hi; + hi.hello(); // From `Hello`, via `Greet` alias. +} diff --git a/src/test/run-pass/traits/trait-alias-import.rs b/src/test/run-pass/traits/trait-alias-import.rs new file mode 100644 index 00000000000..7d63320b9aa --- /dev/null +++ b/src/test/run-pass/traits/trait-alias-import.rs @@ -0,0 +1,38 @@ +#![feature(trait_alias)] + +mod inner { + pub trait Foo { + fn foo(&self); + } + + pub struct Qux; + + impl Foo for Qux { + fn foo(&self) {} + } + + pub trait Bar = Foo; +} + +mod two { + pub trait A { + fn foo(); + } + + impl A for u8 { + fn foo() {} + } +} + +// Import only the alias, not the `Foo` trait. +use inner::{Bar, Qux}; + +// Declaring an alias also brings in aliased methods. +trait Two = two::A; + +fn main() { + let q = Qux; + q.foo(); // From Bar. + + u8::foo(); // From A. +} diff --git a/src/test/run-pass/unsized-locals/box-fnonce.rs b/src/test/run-pass/unsized-locals/box-fnonce.rs new file mode 100644 index 00000000000..16bdeae4fad --- /dev/null +++ b/src/test/run-pass/unsized-locals/box-fnonce.rs @@ -0,0 +1,8 @@ +fn call_it<T>(f: Box<dyn FnOnce() -> T>) -> T { + f() +} + +fn main() { + let s = "hello".to_owned(); + assert_eq!(&call_it(Box::new(|| s)) as &str, "hello"); +} diff --git a/src/test/run-pass/unsized-locals/fnbox-compat.rs b/src/test/run-pass/unsized-locals/fnbox-compat.rs new file mode 100644 index 00000000000..5ec54ada13b --- /dev/null +++ b/src/test/run-pass/unsized-locals/fnbox-compat.rs @@ -0,0 +1,12 @@ +#![feature(fnbox)] + +use std::boxed::FnBox; + +fn call_it<T>(f: Box<dyn FnBox() -> T>) -> T { + f() +} + +fn main() { + let s = "hello".to_owned(); + assert_eq!(&call_it(Box::new(|| s)) as &str, "hello"); +} diff --git a/src/test/rustdoc-js/search-short-types.js b/src/test/rustdoc-js/search-short-types.js new file mode 100644 index 00000000000..0ebf4860cfa --- /dev/null +++ b/src/test/rustdoc-js/search-short-types.js @@ -0,0 +1,8 @@ +const QUERY = 'P'; + +const EXPECTED = { + 'others': [ + { 'path': 'search_short_types', 'name': 'P' }, + { 'path': 'search_short_types', 'name': 'Ap' }, + ], +}; diff --git a/src/test/rustdoc-js/search-short-types.rs b/src/test/rustdoc-js/search-short-types.rs new file mode 100644 index 00000000000..2eacc0a3582 --- /dev/null +++ b/src/test/rustdoc-js/search-short-types.rs @@ -0,0 +1,68 @@ +macro_rules! imp { + ($name:ident) => { + pub struct $name { + pub op: usize, + } + impl $name { + pub fn op() {} + pub fn cmp() {} + pub fn map() {} + pub fn pop() {} + pub fn ptr() {} + pub fn rpo() {} + pub fn drop() {} + pub fn copy() {} + pub fn zip() {} + pub fn sup() {} + pub fn pa() {} + pub fn pb() {} + pub fn pc() {} + pub fn pd() {} + pub fn pe() {} + pub fn pf() {} + pub fn pg() {} + pub fn ph() {} + pub fn pi() {} + pub fn pj() {} + pub fn pk() {} + pub fn pl() {} + pub fn pm() {} + pub fn pn() {} + pub fn po() {} + } + }; + ($name:ident, $($names:ident),*) => { + imp!($name); + imp!($($names),*); + }; +} +macro_rules! en { + ($name:ident) => { + pub enum $name { + Ptr, + Rp, + Rpo, + Pt, + Drop, + Dr, + Dro, + Sup, + Op, + Cmp, + Map, + Mp, + } + }; + ($name:ident, $($names:ident),*) => { + en!($name); + en!($($names),*); + }; +} + +imp!(Ot, Foo, Cmp, Map, Loc, Lac, Toc, Si, Sig, Sip, Psy, Psi, Py, Pi, Pa, Pb, Pc, Pd); +imp!(Pe, Pf, Pg, Ph, Pj, Pk, Pl, Pm, Pn, Po, Pq, Pr, Ps, Pt, Pu, Pv, Pw, Px, Pz, Ap, Bp, Cp); +imp!(Dp, Ep, Fp, Gp, Hp, Ip, Jp, Kp, Lp, Mp, Np, Op, Pp, Qp, Rp, Sp, Tp, Up, Vp, Wp, Xp, Yp, Zp); + +en!(Place, Plac, Plae, Plce, Pace, Scalar, Scalr, Scaar, Sclar, Salar); + +pub struct P; diff --git a/src/test/rustdoc-js/substring.js b/src/test/rustdoc-js/substring.js new file mode 100644 index 00000000000..af05cd1ad34 --- /dev/null +++ b/src/test/rustdoc-js/substring.js @@ -0,0 +1,8 @@ +const QUERY = 'waker_from'; + +const EXPECTED = { + 'others': [ + { 'path': 'substring::SuperWaker', 'name': 'local_waker_from_nonlocal' }, + { 'path': 'substring::SuperWakerTask', 'name': 'local_waker_from_nonlocal' }, + ], +}; diff --git a/src/test/rustdoc-js/substring.rs b/src/test/rustdoc-js/substring.rs new file mode 100644 index 00000000000..e729c722c79 --- /dev/null +++ b/src/test/rustdoc-js/substring.rs @@ -0,0 +1,21 @@ +pub struct SuperWaker; + +impl SuperWaker { + pub fn local_waker_from_nonlocal() {} + pub fn local_waker_frm_nonlocal() {} + pub fn some_method() {} + pub fn some_other_method() {} + pub fn waker_non_local() {} + pub fn from_non_local() {} +} + +pub struct SuperWakerTask; + +impl SuperWakerTask { + pub fn local_waker_from_nonlocal() {} + pub fn local_waker_frm_nonlocal() {} + pub fn some_method() {} + pub fn some_other_method() {} + pub fn waker_non_local() {} + pub fn from_non_local() {} +} diff --git a/src/test/rustdoc/auxiliary/intra-links-external-traits.rs b/src/test/rustdoc/auxiliary/intra-links-external-traits.rs new file mode 100644 index 00000000000..6142dcda986 --- /dev/null +++ b/src/test/rustdoc/auxiliary/intra-links-external-traits.rs @@ -0,0 +1,6 @@ +pub trait ThisTrait { + fn asdf(&self); + + /// let's link to [`asdf`](ThisTrait::asdf) + fn qwop(&self); +} diff --git a/src/test/rustdoc/intra-links-external-traits.rs b/src/test/rustdoc/intra-links-external-traits.rs new file mode 100644 index 00000000000..d6b4a8ad58a --- /dev/null +++ b/src/test/rustdoc/intra-links-external-traits.rs @@ -0,0 +1,12 @@ +// aux-build:intra-links-external-traits.rs +// ignore-cross-compile + +#![crate_name = "outer"] +#![deny(intra_doc_link_resolution_failure)] + +// using a trait that has intra-doc links on it from another crate (whether re-exporting or just +// implementing it) used to give spurious resolution failure warnings + +extern crate intra_links_external_traits; + +pub use intra_links_external_traits::ThisTrait; diff --git a/src/test/rustdoc/useless_lifetime_bound.rs b/src/test/rustdoc/useless_lifetime_bound.rs new file mode 100644 index 00000000000..f530d8a654f --- /dev/null +++ b/src/test/rustdoc/useless_lifetime_bound.rs @@ -0,0 +1,13 @@ +use std::marker::PhantomData; + +// @has useless_lifetime_bound/struct.Scope.html +// @!has - '//*[@class="rust struct"]' "'env: 'env" +pub struct Scope<'env> { + _marker: PhantomData<&'env mut &'env ()>, +} + +// @has useless_lifetime_bound/struct.Scope.html +// @!has - '//*[@class="rust struct"]' "T: 'a + 'a" +pub struct SomeStruct<'a, T: 'a> { + _marker: PhantomData<&'a T>, +} diff --git a/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs b/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs index 82aa28b26b6..e8f1d2eedf5 100644 --- a/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs +++ b/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs @@ -12,20 +12,14 @@ use rustc_plugin::Registry; use rustc::hir; use syntax::attr; -declare_lint!(CRATE_NOT_OKAY, Warn, "crate not marked with #![crate_okay]"); - -struct Pass; - -impl LintPass for Pass { - fn name(&self) -> &'static str { - "Pass" - } - - fn get_lints(&self) -> LintArray { - lint_array!(CRATE_NOT_OKAY) - } +declare_lint! { + CRATE_NOT_OKAY, + Warn, + "crate not marked with #![crate_okay]" } +declare_lint_pass!(Pass => [CRATE_NOT_OKAY]); + impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { fn check_crate(&mut self, cx: &LateContext, krate: &hir::Crate) { if !attr::contains_name(&krate.attrs, "crate_okay") { diff --git a/src/test/ui-fulldeps/auxiliary/lint-group-plugin-test.rs b/src/test/ui-fulldeps/auxiliary/lint-group-plugin-test.rs index 16630e2b312..941fe25b14c 100644 --- a/src/test/ui-fulldeps/auxiliary/lint-group-plugin-test.rs +++ b/src/test/ui-fulldeps/auxiliary/lint-group-plugin-test.rs @@ -16,17 +16,7 @@ declare_lint!(TEST_LINT, Warn, "Warn about items named 'lintme'"); declare_lint!(PLEASE_LINT, Warn, "Warn about items named 'pleaselintme'"); -struct Pass; - -impl LintPass for Pass { - fn name(&self) -> &'static str { - "Pass" - } - - fn get_lints(&self) -> LintArray { - lint_array!(TEST_LINT, PLEASE_LINT) - } -} +declare_lint_pass!(Pass => [TEST_LINT, PLEASE_LINT]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { diff --git a/src/test/ui-fulldeps/auxiliary/lint-plugin-test.rs b/src/test/ui-fulldeps/auxiliary/lint-plugin-test.rs index 4e45189b424..1d204e7bfcf 100644 --- a/src/test/ui-fulldeps/auxiliary/lint-plugin-test.rs +++ b/src/test/ui-fulldeps/auxiliary/lint-plugin-test.rs @@ -16,17 +16,7 @@ use rustc_plugin::Registry; use syntax::ast; declare_lint!(TEST_LINT, Warn, "Warn about items named 'lintme'"); -struct Pass; - -impl LintPass for Pass { - fn name(&self) -> &'static str { - "Pass" - } - - fn get_lints(&self) -> LintArray { - lint_array!(TEST_LINT) - } -} +declare_lint_pass!(Pass => [TEST_LINT]); impl EarlyLintPass for Pass { fn check_item(&mut self, cx: &EarlyContext, it: &ast::Item) { diff --git a/src/test/ui-fulldeps/auxiliary/lint-tool-test.rs b/src/test/ui-fulldeps/auxiliary/lint-tool-test.rs index d25a5ea3746..182d2899da1 100644 --- a/src/test/ui-fulldeps/auxiliary/lint-tool-test.rs +++ b/src/test/ui-fulldeps/auxiliary/lint-tool-test.rs @@ -19,17 +19,7 @@ declare_tool_lint!( Warn, "Warn about other stuff" ); -struct Pass; - -impl LintPass for Pass { - fn name(&self) -> &'static str { - "Pass" - } - - fn get_lints(&self) -> LintArray { - lint_array!(TEST_LINT, TEST_GROUP) - } -} +declare_lint_pass!(Pass => [TEST_LINT, TEST_GROUP]); impl EarlyLintPass for Pass { fn check_item(&mut self, cx: &EarlyContext, it: &ast::Item) { diff --git a/src/test/ui-fulldeps/gated-plugin.stderr b/src/test/ui-fulldeps/gated-plugin.stderr index 37c2b443247..4f8bcda9020 100644 --- a/src/test/ui-fulldeps/gated-plugin.stderr +++ b/src/test/ui-fulldeps/gated-plugin.stderr @@ -1,9 +1,10 @@ -error[E0658]: compiler plugins are experimental and possibly buggy (see issue #29597) +error[E0658]: compiler plugins are experimental and possibly buggy --> $DIR/gated-plugin.rs:3:1 | LL | #![plugin(attr_plugin_test)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29597 = help: add #![feature(plugin)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui-fulldeps/hash-stable-is-unstable.stderr b/src/test/ui-fulldeps/hash-stable-is-unstable.stderr index e7007204d38..b598c86c0e0 100644 --- a/src/test/ui-fulldeps/hash-stable-is-unstable.stderr +++ b/src/test/ui-fulldeps/hash-stable-is-unstable.stderr @@ -2,44 +2,49 @@ error[E0601]: `main` function not found in crate `hash_stable_is_unstable` | = note: consider adding a `main` function to `$DIR/hash-stable-is-unstable.rs` -error[E0658]: use of unstable library feature 'rustc_private': this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead? (see issue #27812) +error[E0658]: use of unstable library feature 'rustc_private': this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead? --> $DIR/hash-stable-is-unstable.rs:3:1 | LL | extern crate rustc_data_structures; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/27812 = help: add #![feature(rustc_private)] to the crate attributes to enable -error[E0658]: use of unstable library feature 'rustc_private': this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead? (see issue #27812) +error[E0658]: use of unstable library feature 'rustc_private': this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead? --> $DIR/hash-stable-is-unstable.rs:5:1 | LL | extern crate rustc; | ^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/27812 = help: add #![feature(rustc_private)] to the crate attributes to enable -error[E0658]: use of unstable library feature 'rustc_private': this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead? (see issue #27812) +error[E0658]: use of unstable library feature 'rustc_private': this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead? --> $DIR/hash-stable-is-unstable.rs:7:1 | LL | extern crate rustc_macros; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/27812 = help: add #![feature(rustc_private)] to the crate attributes to enable -error[E0658]: use of unstable library feature 'rustc_private': this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead? (see issue #27812) +error[E0658]: use of unstable library feature 'rustc_private': this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead? --> $DIR/hash-stable-is-unstable.rs:10:5 | LL | use rustc_macros::HashStable; | ^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/27812 = help: add #![feature(rustc_private)] to the crate attributes to enable -error[E0658]: use of unstable library feature 'rustc_private': this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead? (see issue #27812) +error[E0658]: use of unstable library feature 'rustc_private': this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead? --> $DIR/hash-stable-is-unstable.rs:13:10 | LL | #[derive(HashStable)] | ^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/27812 = help: add #![feature(rustc_private)] to the crate attributes to enable error: aborting due to 6 previous errors diff --git a/src/test/ui-fulldeps/internal-lints/default_hash_types.rs b/src/test/ui-fulldeps/internal-lints/default_hash_types.rs new file mode 100644 index 00000000000..3264099c876 --- /dev/null +++ b/src/test/ui-fulldeps/internal-lints/default_hash_types.rs @@ -0,0 +1,22 @@ +// compile-flags: -Z unstable-options + +#![feature(rustc_private)] + +extern crate rustc_data_structures; + +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use std::collections::{HashMap, HashSet}; + +#[deny(default_hash_types)] +fn main() { + let _map: HashMap<String, String> = HashMap::default(); + //~^ ERROR Prefer FxHashMap over HashMap, it has better performance + //~^^ ERROR Prefer FxHashMap over HashMap, it has better performance + let _set: HashSet<String> = HashSet::default(); + //~^ ERROR Prefer FxHashSet over HashSet, it has better performance + //~^^ ERROR Prefer FxHashSet over HashSet, it has better performance + + // test that the lint doesn't also match the Fx variants themselves + let _fx_map: FxHashMap<String, String> = FxHashMap::default(); + let _fx_set: FxHashSet<String> = FxHashSet::default(); +} diff --git a/src/test/ui-fulldeps/internal-lints/default_hash_types.stderr b/src/test/ui-fulldeps/internal-lints/default_hash_types.stderr new file mode 100644 index 00000000000..64f322cb0c1 --- /dev/null +++ b/src/test/ui-fulldeps/internal-lints/default_hash_types.stderr @@ -0,0 +1,39 @@ +error: Prefer FxHashMap over HashMap, it has better performance + --> $DIR/default_hash_types.rs:12:15 + | +LL | let _map: HashMap<String, String> = HashMap::default(); + | ^^^^^^^ help: use: `FxHashMap` + | +note: lint level defined here + --> $DIR/default_hash_types.rs:10:8 + | +LL | #[deny(default_hash_types)] + | ^^^^^^^^^^^^^^^^^^ + = note: a `use rustc_data_structures::fx::FxHashMap` may be necessary + +error: Prefer FxHashMap over HashMap, it has better performance + --> $DIR/default_hash_types.rs:12:41 + | +LL | let _map: HashMap<String, String> = HashMap::default(); + | ^^^^^^^ help: use: `FxHashMap` + | + = note: a `use rustc_data_structures::fx::FxHashMap` may be necessary + +error: Prefer FxHashSet over HashSet, it has better performance + --> $DIR/default_hash_types.rs:15:15 + | +LL | let _set: HashSet<String> = HashSet::default(); + | ^^^^^^^ help: use: `FxHashSet` + | + = note: a `use rustc_data_structures::fx::FxHashSet` may be necessary + +error: Prefer FxHashSet over HashSet, it has better performance + --> $DIR/default_hash_types.rs:15:33 + | +LL | let _set: HashSet<String> = HashSet::default(); + | ^^^^^^^ help: use: `FxHashSet` + | + = note: a `use rustc_data_structures::fx::FxHashSet` may be necessary + +error: aborting due to 4 previous errors + diff --git a/src/test/ui-fulldeps/internal-lints/ty_tykind_usage.rs b/src/test/ui-fulldeps/internal-lints/ty_tykind_usage.rs new file mode 100644 index 00000000000..dba0db69b7f --- /dev/null +++ b/src/test/ui-fulldeps/internal-lints/ty_tykind_usage.rs @@ -0,0 +1,49 @@ +// compile-flags: -Z unstable-options + +#![feature(rustc_private)] + +extern crate rustc; + +use rustc::ty::{self, Ty, TyKind}; + +#[deny(usage_of_ty_tykind)] +fn main() { + let sty = TyKind::Bool; //~ ERROR usage of `ty::TyKind::<kind>` + + match sty { + TyKind::Bool => (), //~ ERROR usage of `ty::TyKind::<kind>` + TyKind::Char => (), //~ ERROR usage of `ty::TyKind::<kind>` + TyKind::Int(..) => (), //~ ERROR usage of `ty::TyKind::<kind>` + TyKind::Uint(..) => (), //~ ERROR usage of `ty::TyKind::<kind>` + TyKind::Float(..) => (), //~ ERROR usage of `ty::TyKind::<kind>` + TyKind::Adt(..) => (), //~ ERROR usage of `ty::TyKind::<kind>` + TyKind::Foreign(..) => (), //~ ERROR usage of `ty::TyKind::<kind>` + TyKind::Str => (), //~ ERROR usage of `ty::TyKind::<kind>` + TyKind::Array(..) => (), //~ ERROR usage of `ty::TyKind::<kind>` + TyKind::Slice(..) => (), //~ ERROR usage of `ty::TyKind::<kind>` + TyKind::RawPtr(..) => (), //~ ERROR usage of `ty::TyKind::<kind>` + TyKind::Ref(..) => (), //~ ERROR usage of `ty::TyKind::<kind>` + TyKind::FnDef(..) => (), //~ ERROR usage of `ty::TyKind::<kind>` + TyKind::FnPtr(..) => (), //~ ERROR usage of `ty::TyKind::<kind>` + TyKind::Dynamic(..) => (), //~ ERROR usage of `ty::TyKind::<kind>` + TyKind::Closure(..) => (), //~ ERROR usage of `ty::TyKind::<kind>` + TyKind::Generator(..) => (), //~ ERROR usage of `ty::TyKind::<kind>` + TyKind::GeneratorWitness(..) => (), //~ ERROR usage of `ty::TyKind::<kind>` + TyKind::Never => (), //~ ERROR usage of `ty::TyKind::<kind>` + TyKind::Tuple(..) => (), //~ ERROR usage of `ty::TyKind::<kind>` + TyKind::Projection(..) => (), //~ ERROR usage of `ty::TyKind::<kind>` + TyKind::UnnormalizedProjection(..) => (), //~ ERROR usage of `ty::TyKind::<kind>` + TyKind::Opaque(..) => (), //~ ERROR usage of `ty::TyKind::<kind>` + TyKind::Param(..) => (), //~ ERROR usage of `ty::TyKind::<kind>` + TyKind::Bound(..) => (), //~ ERROR usage of `ty::TyKind::<kind>` + TyKind::Placeholder(..) => (), //~ ERROR usage of `ty::TyKind::<kind>` + TyKind::Infer(..) => (), //~ ERROR usage of `ty::TyKind::<kind>` + TyKind::Error => (), //~ ERROR usage of `ty::TyKind::<kind>` + } + + if let ty::Int(int_ty) = sty {} + + if let TyKind::Int(int_ty) = sty {} //~ ERROR usage of `ty::TyKind::<kind>` + + fn ty_kind(ty_bad: TyKind<'_>, ty_good: Ty<'_>) {} //~ ERROR usage of `ty::TyKind` +} diff --git a/src/test/ui-fulldeps/internal-lints/ty_tykind_usage.stderr b/src/test/ui-fulldeps/internal-lints/ty_tykind_usage.stderr new file mode 100644 index 00000000000..4e94af12453 --- /dev/null +++ b/src/test/ui-fulldeps/internal-lints/ty_tykind_usage.stderr @@ -0,0 +1,196 @@ +error: usage of `ty::TyKind::<kind>` + --> $DIR/ty_tykind_usage.rs:11:15 + | +LL | let sty = TyKind::Bool; + | ^^^^^^ help: try using ty::<kind> directly: `ty` + | +note: lint level defined here + --> $DIR/ty_tykind_usage.rs:9:8 + | +LL | #[deny(usage_of_ty_tykind)] + | ^^^^^^^^^^^^^^^^^^ + +error: usage of `ty::TyKind::<kind>` + --> $DIR/ty_tykind_usage.rs:14:9 + | +LL | TyKind::Bool => (), + | ^^^^^^ help: try using ty::<kind> directly: `ty` + +error: usage of `ty::TyKind::<kind>` + --> $DIR/ty_tykind_usage.rs:15:9 + | +LL | TyKind::Char => (), + | ^^^^^^ help: try using ty::<kind> directly: `ty` + +error: usage of `ty::TyKind::<kind>` + --> $DIR/ty_tykind_usage.rs:16:9 + | +LL | TyKind::Int(..) => (), + | ^^^^^^ help: try using ty::<kind> directly: `ty` + +error: usage of `ty::TyKind::<kind>` + --> $DIR/ty_tykind_usage.rs:17:9 + | +LL | TyKind::Uint(..) => (), + | ^^^^^^ help: try using ty::<kind> directly: `ty` + +error: usage of `ty::TyKind::<kind>` + --> $DIR/ty_tykind_usage.rs:18:9 + | +LL | TyKind::Float(..) => (), + | ^^^^^^ help: try using ty::<kind> directly: `ty` + +error: usage of `ty::TyKind::<kind>` + --> $DIR/ty_tykind_usage.rs:19:9 + | +LL | TyKind::Adt(..) => (), + | ^^^^^^ help: try using ty::<kind> directly: `ty` + +error: usage of `ty::TyKind::<kind>` + --> $DIR/ty_tykind_usage.rs:20:9 + | +LL | TyKind::Foreign(..) => (), + | ^^^^^^ help: try using ty::<kind> directly: `ty` + +error: usage of `ty::TyKind::<kind>` + --> $DIR/ty_tykind_usage.rs:21:9 + | +LL | TyKind::Str => (), + | ^^^^^^ help: try using ty::<kind> directly: `ty` + +error: usage of `ty::TyKind::<kind>` + --> $DIR/ty_tykind_usage.rs:22:9 + | +LL | TyKind::Array(..) => (), + | ^^^^^^ help: try using ty::<kind> directly: `ty` + +error: usage of `ty::TyKind::<kind>` + --> $DIR/ty_tykind_usage.rs:23:9 + | +LL | TyKind::Slice(..) => (), + | ^^^^^^ help: try using ty::<kind> directly: `ty` + +error: usage of `ty::TyKind::<kind>` + --> $DIR/ty_tykind_usage.rs:24:9 + | +LL | TyKind::RawPtr(..) => (), + | ^^^^^^ help: try using ty::<kind> directly: `ty` + +error: usage of `ty::TyKind::<kind>` + --> $DIR/ty_tykind_usage.rs:25:9 + | +LL | TyKind::Ref(..) => (), + | ^^^^^^ help: try using ty::<kind> directly: `ty` + +error: usage of `ty::TyKind::<kind>` + --> $DIR/ty_tykind_usage.rs:26:9 + | +LL | TyKind::FnDef(..) => (), + | ^^^^^^ help: try using ty::<kind> directly: `ty` + +error: usage of `ty::TyKind::<kind>` + --> $DIR/ty_tykind_usage.rs:27:9 + | +LL | TyKind::FnPtr(..) => (), + | ^^^^^^ help: try using ty::<kind> directly: `ty` + +error: usage of `ty::TyKind::<kind>` + --> $DIR/ty_tykind_usage.rs:28:9 + | +LL | TyKind::Dynamic(..) => (), + | ^^^^^^ help: try using ty::<kind> directly: `ty` + +error: usage of `ty::TyKind::<kind>` + --> $DIR/ty_tykind_usage.rs:29:9 + | +LL | TyKind::Closure(..) => (), + | ^^^^^^ help: try using ty::<kind> directly: `ty` + +error: usage of `ty::TyKind::<kind>` + --> $DIR/ty_tykind_usage.rs:30:9 + | +LL | TyKind::Generator(..) => (), + | ^^^^^^ help: try using ty::<kind> directly: `ty` + +error: usage of `ty::TyKind::<kind>` + --> $DIR/ty_tykind_usage.rs:31:9 + | +LL | TyKind::GeneratorWitness(..) => (), + | ^^^^^^ help: try using ty::<kind> directly: `ty` + +error: usage of `ty::TyKind::<kind>` + --> $DIR/ty_tykind_usage.rs:32:9 + | +LL | TyKind::Never => (), + | ^^^^^^ help: try using ty::<kind> directly: `ty` + +error: usage of `ty::TyKind::<kind>` + --> $DIR/ty_tykind_usage.rs:33:9 + | +LL | TyKind::Tuple(..) => (), + | ^^^^^^ help: try using ty::<kind> directly: `ty` + +error: usage of `ty::TyKind::<kind>` + --> $DIR/ty_tykind_usage.rs:34:9 + | +LL | TyKind::Projection(..) => (), + | ^^^^^^ help: try using ty::<kind> directly: `ty` + +error: usage of `ty::TyKind::<kind>` + --> $DIR/ty_tykind_usage.rs:35:9 + | +LL | TyKind::UnnormalizedProjection(..) => (), + | ^^^^^^ help: try using ty::<kind> directly: `ty` + +error: usage of `ty::TyKind::<kind>` + --> $DIR/ty_tykind_usage.rs:36:9 + | +LL | TyKind::Opaque(..) => (), + | ^^^^^^ help: try using ty::<kind> directly: `ty` + +error: usage of `ty::TyKind::<kind>` + --> $DIR/ty_tykind_usage.rs:37:9 + | +LL | TyKind::Param(..) => (), + | ^^^^^^ help: try using ty::<kind> directly: `ty` + +error: usage of `ty::TyKind::<kind>` + --> $DIR/ty_tykind_usage.rs:38:9 + | +LL | TyKind::Bound(..) => (), + | ^^^^^^ help: try using ty::<kind> directly: `ty` + +error: usage of `ty::TyKind::<kind>` + --> $DIR/ty_tykind_usage.rs:39:9 + | +LL | TyKind::Placeholder(..) => (), + | ^^^^^^ help: try using ty::<kind> directly: `ty` + +error: usage of `ty::TyKind::<kind>` + --> $DIR/ty_tykind_usage.rs:40:9 + | +LL | TyKind::Infer(..) => (), + | ^^^^^^ help: try using ty::<kind> directly: `ty` + +error: usage of `ty::TyKind::<kind>` + --> $DIR/ty_tykind_usage.rs:41:9 + | +LL | TyKind::Error => (), + | ^^^^^^ help: try using ty::<kind> directly: `ty` + +error: usage of `ty::TyKind::<kind>` + --> $DIR/ty_tykind_usage.rs:46:12 + | +LL | if let TyKind::Int(int_ty) = sty {} + | ^^^^^^ help: try using ty::<kind> directly: `ty` + +error: usage of `ty::TyKind` + --> $DIR/ty_tykind_usage.rs:48:24 + | +LL | fn ty_kind(ty_bad: TyKind<'_>, ty_good: Ty<'_>) {} + | ^^^^^^^^^^ + | + = help: try using `ty::Ty` instead + +error: aborting due to 31 previous errors + diff --git a/src/test/ui/allocator-submodule.rs b/src/test/ui/allocator-submodule.rs index a1cca50ba98..7a8d86b8da1 100644 --- a/src/test/ui/allocator-submodule.rs +++ b/src/test/ui/allocator-submodule.rs @@ -1,8 +1,6 @@ // Tests that it is possible to create a global allocator in a submodule, rather than in the crate // root. -#![feature(alloc, allocator_api, global_allocator)] - extern crate alloc; use std::{ diff --git a/src/test/ui/allocator-submodule.stderr b/src/test/ui/allocator-submodule.stderr index 26d7aa80eee..91c7c0f6b8e 100644 --- a/src/test/ui/allocator-submodule.stderr +++ b/src/test/ui/allocator-submodule.stderr @@ -1,5 +1,5 @@ error: `global_allocator` cannot be used in submodules - --> $DIR/allocator-submodule.rs:27:5 + --> $DIR/allocator-submodule.rs:25:5 | LL | static MY_HEAP: MyAlloc = MyAlloc; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/associated-item/associated-item-enum.rs b/src/test/ui/associated-item/associated-item-enum.rs new file mode 100644 index 00000000000..30ba258155b --- /dev/null +++ b/src/test/ui/associated-item/associated-item-enum.rs @@ -0,0 +1,20 @@ +enum Enum { Variant } + +impl Enum { + const MISSPELLABLE: i32 = 0; + fn misspellable() {} +} + +trait Trait { + fn misspellable_trait() {} +} + +impl Trait for Enum { + fn misspellable_trait() {} +} + +fn main() { + Enum::mispellable(); //~ ERROR no variant or associated item + Enum::mispellable_trait(); //~ ERROR no variant or associated item + Enum::MISPELLABLE; //~ ERROR no variant or associated item +} diff --git a/src/test/ui/associated-item/associated-item-enum.stderr b/src/test/ui/associated-item/associated-item-enum.stderr new file mode 100644 index 00000000000..5a62b9736de --- /dev/null +++ b/src/test/ui/associated-item/associated-item-enum.stderr @@ -0,0 +1,36 @@ +error[E0599]: no variant or associated item named `mispellable` found for type `Enum` in the current scope + --> $DIR/associated-item-enum.rs:17:11 + | +LL | enum Enum { Variant } + | --------- variant or associated item `mispellable` not found here +... +LL | Enum::mispellable(); + | ^^^^^^^^^^^ + | | + | variant or associated item not found in `Enum` + | help: there is a method with a similar name: `misspellable` + +error[E0599]: no variant or associated item named `mispellable_trait` found for type `Enum` in the current scope + --> $DIR/associated-item-enum.rs:18:11 + | +LL | enum Enum { Variant } + | --------- variant or associated item `mispellable_trait` not found here +... +LL | Enum::mispellable_trait(); + | ^^^^^^^^^^^^^^^^^ variant or associated item not found in `Enum` + +error[E0599]: no variant or associated item named `MISPELLABLE` found for type `Enum` in the current scope + --> $DIR/associated-item-enum.rs:19:11 + | +LL | enum Enum { Variant } + | --------- variant or associated item `MISPELLABLE` not found here +... +LL | Enum::MISPELLABLE; + | ^^^^^^^^^^^ + | | + | variant or associated item not found in `Enum` + | help: there is an associated constant with a similar name: `MISSPELLABLE` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/async-fn-multiple-lifetimes.rs b/src/test/ui/async-fn-multiple-lifetimes.rs index 6156617c4da..fccc4fdb917 100644 --- a/src/test/ui/async-fn-multiple-lifetimes.rs +++ b/src/test/ui/async-fn-multiple-lifetimes.rs @@ -5,7 +5,7 @@ use std::ops::Add; async fn multiple_named_lifetimes<'a, 'b>(_: &'a u8, _: &'b u8) {} -//~^ ERROR multiple different lifetimes used in arguments of `async fn` +//~^ ERROR ambiguous lifetime bound in `async fn` async fn multiple_hrtb_and_single_named_lifetime_ok<'c>( _: impl for<'a> Add<&'a u8>, @@ -14,7 +14,6 @@ async fn multiple_hrtb_and_single_named_lifetime_ok<'c>( ) {} async fn multiple_elided_lifetimes(_: &u8, _: &u8) {} -//~^ ERROR multiple elided lifetimes used -//~^^ ERROR missing lifetime specifier +//~^ ambiguous lifetime bound in `async fn` fn main() {} diff --git a/src/test/ui/async-fn-multiple-lifetimes.stderr b/src/test/ui/async-fn-multiple-lifetimes.stderr index 071349b23fa..8c3ee2bed83 100644 --- a/src/test/ui/async-fn-multiple-lifetimes.stderr +++ b/src/test/ui/async-fn-multiple-lifetimes.stderr @@ -1,32 +1,20 @@ -error[E0709]: multiple different lifetimes used in arguments of `async fn` - --> $DIR/async-fn-multiple-lifetimes.rs:7:47 +error: ambiguous lifetime bound in `async fn` + --> $DIR/async-fn-multiple-lifetimes.rs:7:65 | LL | async fn multiple_named_lifetimes<'a, 'b>(_: &'a u8, _: &'b u8) {} - | ^^ ^^ different lifetime here - | | - | first lifetime here + | ^ neither `'a` nor `'b` outlives the other | - = help: `async fn` can only accept borrowed values with identical lifetimes + = note: multiple unrelated lifetimes are not allowed in `async fn`. + = note: if you're using argument-position elided lifetimes, consider switching to a single named lifetime. -error[E0707]: multiple elided lifetimes used in arguments of `async fn` - --> $DIR/async-fn-multiple-lifetimes.rs:16:39 +error: ambiguous lifetime bound in `async fn` + --> $DIR/async-fn-multiple-lifetimes.rs:16:52 | LL | async fn multiple_elided_lifetimes(_: &u8, _: &u8) {} - | ^ ^ different lifetime here - | | - | first lifetime here + | ^ the elided lifetimes here do not outlive one another | - = help: consider giving these arguments named lifetimes + = note: multiple unrelated lifetimes are not allowed in `async fn`. + = note: if you're using argument-position elided lifetimes, consider switching to a single named lifetime. -error[E0106]: missing lifetime specifier - --> $DIR/async-fn-multiple-lifetimes.rs:16:39 - | -LL | async fn multiple_elided_lifetimes(_: &u8, _: &u8) {} - | ^ expected lifetime parameter - | - = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `_` or `_` - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -Some errors occurred: E0106, E0707, E0709. -For more information about an error, try `rustc --explain E0106`. diff --git a/src/test/ui/auto-ref-slice-plus-ref.stderr b/src/test/ui/auto-ref-slice-plus-ref.stderr index 97b9cd961a0..f2e0d379d1b 100644 --- a/src/test/ui/auto-ref-slice-plus-ref.stderr +++ b/src/test/ui/auto-ref-slice-plus-ref.stderr @@ -2,7 +2,7 @@ error[E0599]: no method named `test_mut` found for type `std::vec::Vec<{integer} --> $DIR/auto-ref-slice-plus-ref.rs:7:7 | LL | a.test_mut(); - | ^^^^^^^^ help: did you mean: `get_mut` + | ^^^^^^^^ help: there is a method with a similar name: `get_mut` | = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `test_mut`, perhaps you need to implement it: diff --git a/src/test/ui/auxiliary/issue-59764.rs b/src/test/ui/auxiliary/issue-59764.rs new file mode 100644 index 00000000000..a92eed968d0 --- /dev/null +++ b/src/test/ui/auxiliary/issue-59764.rs @@ -0,0 +1,18 @@ +pub mod foo { + #[macro_export] + macro_rules! makro { + ($foo:ident) => { + fn $foo() { } + } + } + + pub fn baz() {} + + pub fn foobar() {} + + pub mod barbaz { + pub fn barfoo() {} + } +} + +pub fn foobaz() {} diff --git a/src/test/ui/block-result/issue-3563.stderr b/src/test/ui/block-result/issue-3563.stderr index a6346a5233f..237b8c54ce3 100644 --- a/src/test/ui/block-result/issue-3563.stderr +++ b/src/test/ui/block-result/issue-3563.stderr @@ -2,7 +2,7 @@ error[E0599]: no method named `b` found for type `&Self` in the current scope --> $DIR/issue-3563.rs:3:17 | LL | || self.b() - | ^ help: did you mean: `a` + | ^ help: there is a method with a similar name: `a` error: aborting due to previous error diff --git a/src/test/ui/bogus-tag.stderr b/src/test/ui/bogus-tag.stderr index 0bf0d4b14ee..890f6800c22 100644 --- a/src/test/ui/bogus-tag.stderr +++ b/src/test/ui/bogus-tag.stderr @@ -1,11 +1,11 @@ -error[E0599]: no variant named `Hsl` found for type `Color` in the current scope +error[E0599]: no variant or associated item named `Hsl` found for type `Color` in the current scope --> $DIR/bogus-tag.rs:7:16 | LL | enum Color { Rgb(isize, isize, isize), Rgba(isize, isize, isize, isize), } - | ---------- variant `Hsl` not found here + | ---------- variant or associated item `Hsl` not found here ... LL | Color::Hsl(h, s, l) => { println!("hsl"); } - | ^^^ variant not found in `Color` + | ^^^ variant or associated item not found in `Color` error: aborting due to previous error diff --git a/src/test/ui/borrowck/two-phase-cannot-nest-mut-self-calls.stderr b/src/test/ui/borrowck/two-phase-cannot-nest-mut-self-calls.stderr index 9123e1890fe..9bfd8b994bf 100644 --- a/src/test/ui/borrowck/two-phase-cannot-nest-mut-self-calls.stderr +++ b/src/test/ui/borrowck/two-phase-cannot-nest-mut-self-calls.stderr @@ -7,7 +7,7 @@ LL | vec.get({ | immutable borrow occurs here LL | LL | vec.push(2); - | ^^^^^^^^^^^ mutable borrow occurs here + | ^^^ mutable borrow occurs here error: aborting due to previous error diff --git a/src/test/ui/borrowck/two-phase-nonrecv-autoref.ast.nll.stderr b/src/test/ui/borrowck/two-phase-nonrecv-autoref.ast.nll.stderr index d026f81b7aa..223de36f0df 100644 --- a/src/test/ui/borrowck/two-phase-nonrecv-autoref.ast.nll.stderr +++ b/src/test/ui/borrowck/two-phase-nonrecv-autoref.ast.nll.stderr @@ -7,17 +7,15 @@ LL | f(f(10)); | first mutable borrow occurs here | first borrow later used by call -error[E0382]: use of moved value: `*f` +error[E0382]: use of moved value: `f` --> $DIR/two-phase-nonrecv-autoref.rs:69:11 | LL | fn twice_ten_so<F: FnOnce(i32) -> i32>(f: Box<F>) { - | - consider adding a `Copy` constraint to this type argument + | - move occurs because `f` has type `std::boxed::Box<F>`, which does not implement the `Copy` trait LL | f(f(10)); | - ^ value used here after move | | | value moved here - | - = note: move occurs because `*f` has type `F`, which does not implement the `Copy` trait error[E0499]: cannot borrow `*f` as mutable more than once at a time --> $DIR/two-phase-nonrecv-autoref.rs:76:11 @@ -28,30 +26,18 @@ LL | f(f(10)); | first mutable borrow occurs here | first borrow later used by call -error[E0161]: cannot move a value of type dyn std::ops::FnOnce(i32) -> i32: the size of dyn std::ops::FnOnce(i32) -> i32 cannot be statically determined - --> $DIR/two-phase-nonrecv-autoref.rs:85:9 - | -LL | f(f(10)); - | ^ - -error[E0161]: cannot move a value of type dyn std::ops::FnOnce(i32) -> i32: the size of dyn std::ops::FnOnce(i32) -> i32 cannot be statically determined - --> $DIR/two-phase-nonrecv-autoref.rs:85:11 - | -LL | f(f(10)); - | ^ - -error[E0382]: use of moved value: `*f` +error[E0382]: use of moved value: `f` --> $DIR/two-phase-nonrecv-autoref.rs:85:11 | +LL | fn twice_ten_oo(f: Box<FnOnce(i32) -> i32>) { + | - move occurs because `f` has type `std::boxed::Box<dyn std::ops::FnOnce(i32) -> i32>`, which does not implement the `Copy` trait LL | f(f(10)); | - ^ value used here after move | | | value moved here - | - = note: move occurs because `*f` has type `dyn std::ops::FnOnce(i32) -> i32`, which does not implement the `Copy` trait error[E0502]: cannot borrow `a` as immutable because it is also borrowed as mutable - --> $DIR/two-phase-nonrecv-autoref.rs:129:27 + --> $DIR/two-phase-nonrecv-autoref.rs:125:27 | LL | double_access(&mut a, &a); | ------------- ------ ^^ immutable borrow occurs here @@ -60,7 +46,7 @@ LL | double_access(&mut a, &a); | mutable borrow later used by call error[E0502]: cannot borrow `i` as immutable because it is also borrowed as mutable - --> $DIR/two-phase-nonrecv-autoref.rs:157:7 + --> $DIR/two-phase-nonrecv-autoref.rs:153:7 | LL | i[i[3]] = 4; | --^---- @@ -70,7 +56,7 @@ LL | i[i[3]] = 4; | mutable borrow later used here error[E0502]: cannot borrow `i` as immutable because it is also borrowed as mutable - --> $DIR/two-phase-nonrecv-autoref.rs:163:7 + --> $DIR/two-phase-nonrecv-autoref.rs:159:7 | LL | i[i[3]] = i[4]; | --^---- @@ -79,7 +65,7 @@ LL | i[i[3]] = i[4]; | mutable borrow occurs here | mutable borrow later used here -error: aborting due to 9 previous errors +error: aborting due to 7 previous errors -Some errors occurred: E0161, E0382, E0499, E0502. -For more information about an error, try `rustc --explain E0161`. +Some errors occurred: E0382, E0499, E0502. +For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/two-phase-nonrecv-autoref.ast.stderr b/src/test/ui/borrowck/two-phase-nonrecv-autoref.ast.stderr index 426939f371c..d98b272944f 100644 --- a/src/test/ui/borrowck/two-phase-nonrecv-autoref.ast.stderr +++ b/src/test/ui/borrowck/two-phase-nonrecv-autoref.ast.stderr @@ -15,7 +15,7 @@ LL | f(f(10)); | | second mutable borrow occurs here | first mutable borrow occurs here -error[E0382]: use of moved value: `*f` +error[E0382]: use of moved value: `f` --> $DIR/two-phase-nonrecv-autoref.rs:69:11 | LL | f(f(10)); @@ -23,7 +23,7 @@ LL | f(f(10)); | | | value moved here | - = note: move occurs because `*f` has type `F`, which does not implement the `Copy` trait + = note: move occurs because `f` has type `std::boxed::Box<F>`, which does not implement the `Copy` trait error[E0499]: cannot borrow `*f` as mutable more than once at a time --> $DIR/two-phase-nonrecv-autoref.rs:76:11 @@ -34,7 +34,7 @@ LL | f(f(10)); | | second mutable borrow occurs here | first mutable borrow occurs here -error[E0382]: use of moved value: `*f` +error[E0382]: use of moved value: `f` --> $DIR/two-phase-nonrecv-autoref.rs:85:11 | LL | f(f(10)); @@ -42,10 +42,10 @@ LL | f(f(10)); | | | value moved here | - = note: move occurs because `*f` has type `(dyn std::ops::FnOnce(i32) -> i32 + 'static)`, which does not implement the `Copy` trait + = note: move occurs because `f` has type `std::boxed::Box<(dyn std::ops::FnOnce(i32) -> i32 + 'static)>`, which does not implement the `Copy` trait error[E0502]: cannot borrow `a` as immutable because it is also borrowed as mutable - --> $DIR/two-phase-nonrecv-autoref.rs:129:28 + --> $DIR/two-phase-nonrecv-autoref.rs:125:28 | LL | double_access(&mut a, &a); | - ^- mutable borrow ends here @@ -54,7 +54,7 @@ LL | double_access(&mut a, &a); | mutable borrow occurs here error[E0502]: cannot borrow `a` as immutable because it is also borrowed as mutable - --> $DIR/two-phase-nonrecv-autoref.rs:135:9 + --> $DIR/two-phase-nonrecv-autoref.rs:131:9 | LL | a.m(a.i(10)); | - ^ - mutable borrow ends here @@ -63,7 +63,7 @@ LL | a.m(a.i(10)); | mutable borrow occurs here error[E0502]: cannot borrow `i` as immutable because it is also borrowed as mutable - --> $DIR/two-phase-nonrecv-autoref.rs:157:7 + --> $DIR/two-phase-nonrecv-autoref.rs:153:7 | LL | i[i[3]] = 4; | - ^ - mutable borrow ends here @@ -72,7 +72,7 @@ LL | i[i[3]] = 4; | mutable borrow occurs here error[E0502]: cannot borrow `i` as immutable because it is also borrowed as mutable - --> $DIR/two-phase-nonrecv-autoref.rs:163:7 + --> $DIR/two-phase-nonrecv-autoref.rs:159:7 | LL | i[i[3]] = i[4]; | - ^ - mutable borrow ends here @@ -81,7 +81,7 @@ LL | i[i[3]] = i[4]; | mutable borrow occurs here error[E0502]: cannot borrow `v` as immutable because it is also borrowed as mutable - --> $DIR/two-phase-nonrecv-autoref.rs:172:12 + --> $DIR/two-phase-nonrecv-autoref.rs:168:12 | LL | v.push(v.len()); | - ^ - mutable borrow ends here @@ -90,7 +90,7 @@ LL | v.push(v.len()); | mutable borrow occurs here error[E0502]: cannot borrow `s` as immutable because it is also borrowed as mutable - --> $DIR/two-phase-nonrecv-autoref.rs:183:9 + --> $DIR/two-phase-nonrecv-autoref.rs:179:9 | LL | s.m(s.i(10)); | - ^ - mutable borrow ends here @@ -99,7 +99,7 @@ LL | s.m(s.i(10)); | mutable borrow occurs here error[E0502]: cannot borrow `t` as immutable because it is also borrowed as mutable - --> $DIR/two-phase-nonrecv-autoref.rs:188:9 + --> $DIR/two-phase-nonrecv-autoref.rs:184:9 | LL | t.m(t.i(10)); | - ^ - mutable borrow ends here diff --git a/src/test/ui/borrowck/two-phase-nonrecv-autoref.nll.stderr b/src/test/ui/borrowck/two-phase-nonrecv-autoref.nll.stderr index d026f81b7aa..223de36f0df 100644 --- a/src/test/ui/borrowck/two-phase-nonrecv-autoref.nll.stderr +++ b/src/test/ui/borrowck/two-phase-nonrecv-autoref.nll.stderr @@ -7,17 +7,15 @@ LL | f(f(10)); | first mutable borrow occurs here | first borrow later used by call -error[E0382]: use of moved value: `*f` +error[E0382]: use of moved value: `f` --> $DIR/two-phase-nonrecv-autoref.rs:69:11 | LL | fn twice_ten_so<F: FnOnce(i32) -> i32>(f: Box<F>) { - | - consider adding a `Copy` constraint to this type argument + | - move occurs because `f` has type `std::boxed::Box<F>`, which does not implement the `Copy` trait LL | f(f(10)); | - ^ value used here after move | | | value moved here - | - = note: move occurs because `*f` has type `F`, which does not implement the `Copy` trait error[E0499]: cannot borrow `*f` as mutable more than once at a time --> $DIR/two-phase-nonrecv-autoref.rs:76:11 @@ -28,30 +26,18 @@ LL | f(f(10)); | first mutable borrow occurs here | first borrow later used by call -error[E0161]: cannot move a value of type dyn std::ops::FnOnce(i32) -> i32: the size of dyn std::ops::FnOnce(i32) -> i32 cannot be statically determined - --> $DIR/two-phase-nonrecv-autoref.rs:85:9 - | -LL | f(f(10)); - | ^ - -error[E0161]: cannot move a value of type dyn std::ops::FnOnce(i32) -> i32: the size of dyn std::ops::FnOnce(i32) -> i32 cannot be statically determined - --> $DIR/two-phase-nonrecv-autoref.rs:85:11 - | -LL | f(f(10)); - | ^ - -error[E0382]: use of moved value: `*f` +error[E0382]: use of moved value: `f` --> $DIR/two-phase-nonrecv-autoref.rs:85:11 | +LL | fn twice_ten_oo(f: Box<FnOnce(i32) -> i32>) { + | - move occurs because `f` has type `std::boxed::Box<dyn std::ops::FnOnce(i32) -> i32>`, which does not implement the `Copy` trait LL | f(f(10)); | - ^ value used here after move | | | value moved here - | - = note: move occurs because `*f` has type `dyn std::ops::FnOnce(i32) -> i32`, which does not implement the `Copy` trait error[E0502]: cannot borrow `a` as immutable because it is also borrowed as mutable - --> $DIR/two-phase-nonrecv-autoref.rs:129:27 + --> $DIR/two-phase-nonrecv-autoref.rs:125:27 | LL | double_access(&mut a, &a); | ------------- ------ ^^ immutable borrow occurs here @@ -60,7 +46,7 @@ LL | double_access(&mut a, &a); | mutable borrow later used by call error[E0502]: cannot borrow `i` as immutable because it is also borrowed as mutable - --> $DIR/two-phase-nonrecv-autoref.rs:157:7 + --> $DIR/two-phase-nonrecv-autoref.rs:153:7 | LL | i[i[3]] = 4; | --^---- @@ -70,7 +56,7 @@ LL | i[i[3]] = 4; | mutable borrow later used here error[E0502]: cannot borrow `i` as immutable because it is also borrowed as mutable - --> $DIR/two-phase-nonrecv-autoref.rs:163:7 + --> $DIR/two-phase-nonrecv-autoref.rs:159:7 | LL | i[i[3]] = i[4]; | --^---- @@ -79,7 +65,7 @@ LL | i[i[3]] = i[4]; | mutable borrow occurs here | mutable borrow later used here -error: aborting due to 9 previous errors +error: aborting due to 7 previous errors -Some errors occurred: E0161, E0382, E0499, E0502. -For more information about an error, try `rustc --explain E0161`. +Some errors occurred: E0382, E0499, E0502. +For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/borrowck/two-phase-nonrecv-autoref.rs b/src/test/ui/borrowck/two-phase-nonrecv-autoref.rs index 1a14cb90f38..1005da05297 100644 --- a/src/test/ui/borrowck/two-phase-nonrecv-autoref.rs +++ b/src/test/ui/borrowck/two-phase-nonrecv-autoref.rs @@ -67,9 +67,9 @@ fn overloaded_call_traits() { } fn twice_ten_so<F: FnOnce(i32) -> i32>(f: Box<F>) { f(f(10)); - //[nll]~^ ERROR use of moved value: `*f` - //[g2p]~^^ ERROR use of moved value: `*f` - //[ast]~^^^ ERROR use of moved value: `*f` + //[nll]~^ ERROR use of moved value: `f` + //[g2p]~^^ ERROR use of moved value: `f` + //[ast]~^^^ ERROR use of moved value: `f` } fn twice_ten_om(f: &mut FnMut(i32) -> i32) { @@ -83,13 +83,9 @@ fn overloaded_call_traits() { } fn twice_ten_oo(f: Box<FnOnce(i32) -> i32>) { f(f(10)); - //[nll]~^ ERROR cannot move a value of type - //[nll]~^^ ERROR cannot move a value of type - //[nll]~^^^ ERROR use of moved value: `*f` - //[g2p]~^^^^ ERROR cannot move a value of type - //[g2p]~^^^^^ ERROR cannot move a value of type - //[g2p]~^^^^^^ ERROR use of moved value: `*f` - //[ast]~^^^^^^^ ERROR use of moved value: `*f` + //[nll]~^ ERROR use of moved value: `f` + //[g2p]~^^ ERROR use of moved value: `f` + //[ast]~^^^ ERROR use of moved value: `f` } twice_ten_sm(&mut |x| x + 1); diff --git a/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.ast.stderr b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.ast.stderr new file mode 100644 index 00000000000..28c997efc8a --- /dev/null +++ b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.ast.stderr @@ -0,0 +1,36 @@ +error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable + --> $DIR/two-phase-reservation-sharing-interference-2.rs:19:5 + | +LL | let shared = &v; + | - immutable borrow occurs here +LL | +LL | v.extend(shared); + | ^ mutable borrow occurs here +... +LL | } + | - immutable borrow ends here + +error[E0502]: cannot borrow `v` as immutable because it is also borrowed as mutable + --> $DIR/two-phase-reservation-sharing-interference-2.rs:30:15 + | +LL | v.extend(&v); + | - ^- mutable borrow ends here + | | | + | | immutable borrow occurs here + | mutable borrow occurs here + +error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable + --> $DIR/two-phase-reservation-sharing-interference-2.rs:42:5 + | +LL | let shared = &v; + | - immutable borrow occurs here +LL | +LL | v.push(shared.len()); + | ^ mutable borrow occurs here +... +LL | } + | - immutable borrow ends here + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.migrate2015.stderr b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.migrate2015.stderr new file mode 100644 index 00000000000..bb11b2e4f0f --- /dev/null +++ b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.migrate2015.stderr @@ -0,0 +1,40 @@ +error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable + --> $DIR/two-phase-reservation-sharing-interference-2.rs:19:5 + | +LL | let shared = &v; + | -- immutable borrow occurs here +LL | +LL | v.extend(shared); + | ^^------^^^^^^^^ + | | | + | | immutable borrow later used by call + | mutable borrow occurs here + +error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable + --> $DIR/two-phase-reservation-sharing-interference-2.rs:30:5 + | +LL | v.extend(&v); + | ^^------^--^ + | | | | + | | | immutable borrow occurs here + | | immutable borrow later used by call + | mutable borrow occurs here + +warning: cannot borrow `v` as mutable because it is also borrowed as immutable + --> $DIR/two-phase-reservation-sharing-interference-2.rs:42:5 + | +LL | let shared = &v; + | -- immutable borrow occurs here +LL | +LL | v.push(shared.len()); + | ^ ------ immutable borrow later used here + | | + | mutable borrow occurs here + | + = note: #[warn(mutable_borrow_reservation_conflict)] on by default + = warning: this borrowing pattern was not meant to be accepted, and may become a hard error in the future + = note: for more information, see issue #59159 <https://github.com/rust-lang/rust/issues/59159> + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.migrate2018.stderr b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.migrate2018.stderr new file mode 100644 index 00000000000..bb11b2e4f0f --- /dev/null +++ b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.migrate2018.stderr @@ -0,0 +1,40 @@ +error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable + --> $DIR/two-phase-reservation-sharing-interference-2.rs:19:5 + | +LL | let shared = &v; + | -- immutable borrow occurs here +LL | +LL | v.extend(shared); + | ^^------^^^^^^^^ + | | | + | | immutable borrow later used by call + | mutable borrow occurs here + +error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable + --> $DIR/two-phase-reservation-sharing-interference-2.rs:30:5 + | +LL | v.extend(&v); + | ^^------^--^ + | | | | + | | | immutable borrow occurs here + | | immutable borrow later used by call + | mutable borrow occurs here + +warning: cannot borrow `v` as mutable because it is also borrowed as immutable + --> $DIR/two-phase-reservation-sharing-interference-2.rs:42:5 + | +LL | let shared = &v; + | -- immutable borrow occurs here +LL | +LL | v.push(shared.len()); + | ^ ------ immutable borrow later used here + | | + | mutable borrow occurs here + | + = note: #[warn(mutable_borrow_reservation_conflict)] on by default + = warning: this borrowing pattern was not meant to be accepted, and may become a hard error in the future + = note: for more information, see issue #59159 <https://github.com/rust-lang/rust/issues/59159> + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.nll2015.stderr b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.nll2015.stderr new file mode 100644 index 00000000000..fb3a1fda631 --- /dev/null +++ b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.nll2015.stderr @@ -0,0 +1,35 @@ +error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable + --> $DIR/two-phase-reservation-sharing-interference-2.rs:19:5 + | +LL | let shared = &v; + | -- immutable borrow occurs here +LL | +LL | v.extend(shared); + | ^ ------ immutable borrow later used here + | | + | mutable borrow occurs here + +error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable + --> $DIR/two-phase-reservation-sharing-interference-2.rs:30:5 + | +LL | v.extend(&v); + | ^^------^--^ + | | | | + | | | immutable borrow occurs here + | | immutable borrow later used by call + | mutable borrow occurs here + +error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable + --> $DIR/two-phase-reservation-sharing-interference-2.rs:42:5 + | +LL | let shared = &v; + | -- immutable borrow occurs here +LL | +LL | v.push(shared.len()); + | ^ ------ immutable borrow later used here + | | + | mutable borrow occurs here + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.nll2018.stderr b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.nll2018.stderr new file mode 100644 index 00000000000..fb3a1fda631 --- /dev/null +++ b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.nll2018.stderr @@ -0,0 +1,35 @@ +error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable + --> $DIR/two-phase-reservation-sharing-interference-2.rs:19:5 + | +LL | let shared = &v; + | -- immutable borrow occurs here +LL | +LL | v.extend(shared); + | ^ ------ immutable borrow later used here + | | + | mutable borrow occurs here + +error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable + --> $DIR/two-phase-reservation-sharing-interference-2.rs:30:5 + | +LL | v.extend(&v); + | ^^------^--^ + | | | | + | | | immutable borrow occurs here + | | immutable borrow later used by call + | mutable borrow occurs here + +error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable + --> $DIR/two-phase-reservation-sharing-interference-2.rs:42:5 + | +LL | let shared = &v; + | -- immutable borrow occurs here +LL | +LL | v.push(shared.len()); + | ^ ------ immutable borrow later used here + | | + | mutable borrow occurs here + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.rs b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.rs index 13c1df7db2b..54fad9f66b8 100644 --- a/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.rs +++ b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.rs @@ -1,24 +1,54 @@ -// compile-flags: -Z borrowck=mir -Z two-phase-borrows - -// This is similar to two-phase-reservation-sharing-interference.rs -// in that it shows a reservation that overlaps with a shared borrow. -// -// Currently, this test fails with lexical lifetimes, but succeeds -// with non-lexical lifetimes. (The reason is because the activation -// of the mutable borrow ends up overlapping with a lexically-scoped -// shared borrow; but a non-lexical shared borrow can end before the -// activation occurs.) -// -// So this test is just making a note of the current behavior. - -#![feature(rustc_attrs)] - -#[rustc_error] -fn main() { //~ ERROR compilation successful +// Test for #56254, we previously allowed the last example on the 2018 +// editiion. Make sure that we now emit a warning in that case and an error for +// everyone else. + +//ignore-compare-mode-nll + +//revisions: ast migrate2015 migrate2018 nll2015 nll2018 + +//[migrate2015] compile-flags: -Zborrowck=migrate -Ztwo-phase-borrows +//[migrate2018] edition:2018 +//[nll2018] edition:2018 + +#![cfg_attr(any(nll2015, nll2018), feature(nll))] + +fn double_conflicts() { + let mut v = vec![0, 1, 2]; + let shared = &v; + + v.extend(shared); + //[migrate2015]~^ ERROR cannot borrow `v` as mutable + //[nll2015]~^^ ERROR cannot borrow `v` as mutable + //[migrate2018]~^^^ ERROR cannot borrow `v` as mutable + //[nll2018]~^^^^ ERROR cannot borrow `v` as mutable + //[ast]~^^^^^ ERROR cannot borrow `v` as mutable +} + +fn activation_conflict() { + let mut v = vec![0, 1, 2]; + + v.extend(&v); + //[migrate2015]~^ ERROR cannot borrow `v` as mutable + //[nll2015]~^^ ERROR cannot borrow `v` as mutable + //[migrate2018]~^^^ ERROR cannot borrow `v` as mutable + //[nll2018]~^^^^ ERROR cannot borrow `v` as mutable + //[ast]~^^^^^ ERROR cannot borrow `v` as immutable +} + +fn reservation_conflict() { let mut v = vec![0, 1, 2]; let shared = &v; v.push(shared.len()); + //[nll2015]~^ ERROR cannot borrow `v` as mutable + //[nll2018]~^^ ERROR cannot borrow `v` as mutable + //[migrate2015]~^^^ WARNING cannot borrow `v` as mutable + //[migrate2015]~| WARNING may become a hard error in the future - assert_eq!(v, [0, 1, 2, 3]); + //[migrate2018]~^^^^^^ WARNING cannot borrow `v` as mutable + //[migrate2018]~| WARNING may become a hard error in the future + + //[ast]~^^^^^^^^^ ERROR cannot borrow `v` as mutable } + +fn main() {} diff --git a/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.stderr b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.stderr deleted file mode 100644 index bcd743f47c5..00000000000 --- a/src/test/ui/borrowck/two-phase-reservation-sharing-interference-2.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error: compilation successful - --> $DIR/two-phase-reservation-sharing-interference-2.rs:17:1 - | -LL | / fn main() { -LL | | let mut v = vec![0, 1, 2]; -LL | | let shared = &v; -LL | | -... | -LL | | assert_eq!(v, [0, 1, 2, 3]); -LL | | } - | |_^ - -error: aborting due to previous error - diff --git a/src/test/ui/borrowck/two-phase-reservation-sharing-interference-future-compat-lint.rs b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-future-compat-lint.rs new file mode 100644 index 00000000000..0e1d77ace3f --- /dev/null +++ b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-future-compat-lint.rs @@ -0,0 +1,43 @@ +// Check that the future-compat-lint for the reservation conflict is +// handled like any other lint. + +// edition:2018 + +mod future_compat_allow { + #![allow(mutable_borrow_reservation_conflict)] + + fn reservation_conflict() { + let mut v = vec![0, 1, 2]; + let shared = &v; + + v.push(shared.len()); + } +} + +mod future_compat_warn { + #![warn(mutable_borrow_reservation_conflict)] + + fn reservation_conflict() { + let mut v = vec![0, 1, 2]; + let shared = &v; + + v.push(shared.len()); + //~^ WARNING cannot borrow `v` as mutable + //~| WARNING may become a hard error in the future + } +} + +mod future_compat_deny { + #![deny(mutable_borrow_reservation_conflict)] + + fn reservation_conflict() { + let mut v = vec![0, 1, 2]; + let shared = &v; + + v.push(shared.len()); + //~^ ERROR cannot borrow `v` as mutable + //~| WARNING may become a hard error in the future + } +} + +fn main() {} diff --git a/src/test/ui/borrowck/two-phase-reservation-sharing-interference-future-compat-lint.stderr b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-future-compat-lint.stderr new file mode 100644 index 00000000000..77fbfb37add --- /dev/null +++ b/src/test/ui/borrowck/two-phase-reservation-sharing-interference-future-compat-lint.stderr @@ -0,0 +1,40 @@ +warning: cannot borrow `v` as mutable because it is also borrowed as immutable + --> $DIR/two-phase-reservation-sharing-interference-future-compat-lint.rs:24:9 + | +LL | let shared = &v; + | -- immutable borrow occurs here +LL | +LL | v.push(shared.len()); + | ^ ------ immutable borrow later used here + | | + | mutable borrow occurs here + | +note: lint level defined here + --> $DIR/two-phase-reservation-sharing-interference-future-compat-lint.rs:18:13 + | +LL | #![warn(mutable_borrow_reservation_conflict)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = warning: this borrowing pattern was not meant to be accepted, and may become a hard error in the future + = note: for more information, see issue #59159 <https://github.com/rust-lang/rust/issues/59159> + +error: cannot borrow `v` as mutable because it is also borrowed as immutable + --> $DIR/two-phase-reservation-sharing-interference-future-compat-lint.rs:37:9 + | +LL | let shared = &v; + | -- immutable borrow occurs here +LL | +LL | v.push(shared.len()); + | ^ ------ immutable borrow later used here + | | + | mutable borrow occurs here + | +note: lint level defined here + --> $DIR/two-phase-reservation-sharing-interference-future-compat-lint.rs:31:13 + | +LL | #![deny(mutable_borrow_reservation_conflict)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = warning: this borrowing pattern was not meant to be accepted, and may become a hard error in the future + = note: for more information, see issue #59159 <https://github.com/rust-lang/rust/issues/59159> + +error: aborting due to previous error + diff --git a/src/test/ui/cast/cast-ptr-to-int-const.stderr b/src/test/ui/cast/cast-ptr-to-int-const.stderr index 0d4397c2e2d..c40accfd7c4 100644 --- a/src/test/ui/cast/cast-ptr-to-int-const.stderr +++ b/src/test/ui/cast/cast-ptr-to-int-const.stderr @@ -1,17 +1,19 @@ -error[E0658]: casting pointers to integers in constants is unstable (see issue #51910) +error[E0658]: casting pointers to integers in constants is unstable --> $DIR/cast-ptr-to-int-const.rs:5:9 | LL | main as u32 | ^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/51910 = help: add #![feature(const_raw_ptr_to_usize_cast)] to the crate attributes to enable -error[E0658]: casting pointers to integers in constants is unstable (see issue #51910) +error[E0658]: casting pointers to integers in constants is unstable --> $DIR/cast-ptr-to-int-const.rs:9:9 | LL | &Y as *const u32 as u32 | ^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/51910 = help: add #![feature(const_raw_ptr_to_usize_cast)] to the crate attributes to enable error: aborting due to 2 previous errors diff --git a/src/test/ui/conditional-compilation/cfg-attr-crate-2.stderr b/src/test/ui/conditional-compilation/cfg-attr-crate-2.stderr index 8d308f0c96f..ec77789449a 100644 --- a/src/test/ui/conditional-compilation/cfg-attr-crate-2.stderr +++ b/src/test/ui/conditional-compilation/cfg-attr-crate-2.stderr @@ -1,9 +1,10 @@ -error[E0658]: no_core is experimental (see issue #29639) +error[E0658]: no_core is experimental --> $DIR/cfg-attr-crate-2.rs:6:21 | LL | #![cfg_attr(broken, no_core)] | ^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29639 = help: add #![feature(no_core)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-1.stderr b/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-1.stderr index 8485459ca6b..ad5177dc9c0 100644 --- a/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-1.stderr +++ b/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-1.stderr @@ -1,9 +1,10 @@ -error[E0658]: no_core is experimental (see issue #29639) +error[E0658]: no_core is experimental --> $DIR/cfg-attr-multi-invalid-1.rs:4:21 | LL | #![cfg_attr(broken, no_core, no_std)] | ^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29639 = help: add #![feature(no_core)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-2.stderr b/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-2.stderr index 2a673ea8131..675997758e6 100644 --- a/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-2.stderr +++ b/src/test/ui/conditional-compilation/cfg-attr-multi-invalid-2.stderr @@ -1,9 +1,10 @@ -error[E0658]: no_core is experimental (see issue #29639) +error[E0658]: no_core is experimental --> $DIR/cfg-attr-multi-invalid-2.rs:4:29 | LL | #![cfg_attr(broken, no_std, no_core)] | ^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29639 = help: add #![feature(no_core)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.stderr b/src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.stderr index d0b59c3994c..ca3e3d9eff1 100644 --- a/src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.stderr +++ b/src/test/ui/conditional-compilation/cfg-attr-unknown-attribute-macro-expansion.stderr @@ -1,4 +1,4 @@ -error[E0658]: The attribute `unknown` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `unknown` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/cfg-attr-unknown-attribute-macro-expansion.rs:3:27 | LL | #[cfg_attr(all(), unknown)] @@ -7,6 +7,7 @@ LL | #[cfg_attr(all(), unknown)] LL | foo!(); | ------- in this macro invocation | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/consts/const-deref-ptr.stderr b/src/test/ui/consts/const-deref-ptr.stderr index 8de0f6c1514..23ac3b85ee6 100644 --- a/src/test/ui/consts/const-deref-ptr.stderr +++ b/src/test/ui/consts/const-deref-ptr.stderr @@ -1,9 +1,10 @@ -error[E0658]: dereferencing raw pointers in statics is unstable (see issue #51911) +error[E0658]: dereferencing raw pointers in statics is unstable --> $DIR/const-deref-ptr.rs:4:29 | LL | static C: u64 = unsafe {*(0xdeadbeef as *const u64)}; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/51911 = help: add #![feature(const_raw_ptr_deref)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/consts/const-eval/feature-gate-const_fn_union.stderr b/src/test/ui/consts/const-eval/feature-gate-const_fn_union.stderr index 5a72c8205b6..069a8bfd4e7 100644 --- a/src/test/ui/consts/const-eval/feature-gate-const_fn_union.stderr +++ b/src/test/ui/consts/const-eval/feature-gate-const_fn_union.stderr @@ -1,9 +1,10 @@ -error[E0658]: unions in const fn are unstable (see issue #51909) +error[E0658]: unions in const fn are unstable --> $DIR/feature-gate-const_fn_union.rs:11:5 | LL | Foo { u }.i | ^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/51909 = help: add #![feature(const_fn_union)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/consts/const-eval/feature-gate-const_panic.stderr b/src/test/ui/consts/const-eval/feature-gate-const_panic.stderr index 08103413556..5d3e88e4e58 100644 --- a/src/test/ui/consts/const-eval/feature-gate-const_panic.stderr +++ b/src/test/ui/consts/const-eval/feature-gate-const_panic.stderr @@ -1,27 +1,30 @@ -error[E0658]: panicking in constants is unstable (see issue #51999) +error[E0658]: panicking in constants is unstable --> $DIR/feature-gate-const_panic.rs:3:15 | LL | const Z: () = panic!("cheese"); | ^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/51999 = help: add #![feature(const_panic)] to the crate attributes to enable = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) -error[E0658]: panicking in constants is unstable (see issue #51999) +error[E0658]: panicking in constants is unstable --> $DIR/feature-gate-const_panic.rs:9:15 | LL | const X: () = unimplemented!(); | ^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/51999 = help: add #![feature(const_panic)] to the crate attributes to enable = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) -error[E0658]: panicking in constants is unstable (see issue #51999) +error[E0658]: panicking in constants is unstable --> $DIR/feature-gate-const_panic.rs:6:15 | LL | const Y: () = unreachable!(); | ^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/51999 = help: add #![feature(const_panic)] to the crate attributes to enable = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) diff --git a/src/test/ui/consts/const-eval/match-test-ptr-null.rs b/src/test/ui/consts/const-eval/match-test-ptr-null.rs index b27b816cf50..e0af01aeef4 100644 --- a/src/test/ui/consts/const-eval/match-test-ptr-null.rs +++ b/src/test/ui/consts/const-eval/match-test-ptr-null.rs @@ -3,7 +3,9 @@ fn main() { // that pointer comparison is disallowed, not that parts of a pointer are accessed as raw // bytes. let _: [u8; 0] = [4; { - match &1 as *const i32 as usize { //~ ERROR casting pointers to integers in constants + match &1 as *const i32 as usize { + //~^ ERROR casting pointers to integers in constants + //~| NOTE for more information, see 0 => 42, //~ ERROR constant contains unimplemented expression type //~^ NOTE "pointer arithmetic or comparison" needs an rfc before being allowed //~| ERROR evaluation of constant value failed diff --git a/src/test/ui/consts/const-eval/match-test-ptr-null.stderr b/src/test/ui/consts/const-eval/match-test-ptr-null.stderr index fd5647c9af3..79e278f68ad 100644 --- a/src/test/ui/consts/const-eval/match-test-ptr-null.stderr +++ b/src/test/ui/consts/const-eval/match-test-ptr-null.stderr @@ -1,19 +1,20 @@ -error[E0658]: casting pointers to integers in constants is unstable (see issue #51910) +error[E0658]: casting pointers to integers in constants is unstable --> $DIR/match-test-ptr-null.rs:6:15 | LL | match &1 as *const i32 as usize { | ^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/51910 = help: add #![feature(const_raw_ptr_to_usize_cast)] to the crate attributes to enable error[E0019]: constant contains unimplemented expression type - --> $DIR/match-test-ptr-null.rs:7:13 + --> $DIR/match-test-ptr-null.rs:9:13 | LL | 0 => 42, | ^ error[E0080]: evaluation of constant value failed - --> $DIR/match-test-ptr-null.rs:7:13 + --> $DIR/match-test-ptr-null.rs:9:13 | LL | 0 => 42, | ^ "pointer arithmetic or comparison" needs an rfc before being allowed inside constants diff --git a/src/test/ui/consts/const_arg_local.rs b/src/test/ui/consts/const_arg_local.rs new file mode 100644 index 00000000000..0da4b44a968 --- /dev/null +++ b/src/test/ui/consts/const_arg_local.rs @@ -0,0 +1,13 @@ +// only-x86_64 + +#[cfg(target_arch = "x86")] +use std::arch::x86::*; +#[cfg(target_arch = "x86_64")] +use std::arch::x86_64::*; + +unsafe fn pclmul(a: __m128i, b: __m128i) -> __m128i { + let imm8 = 3; + _mm_clmulepi64_si128(a, b, imm8) //~ ERROR argument 3 is required to be a constant +} + +fn main() {} diff --git a/src/test/ui/consts/const_arg_local.stderr b/src/test/ui/consts/const_arg_local.stderr new file mode 100644 index 00000000000..197b2f082e5 --- /dev/null +++ b/src/test/ui/consts/const_arg_local.stderr @@ -0,0 +1,8 @@ +error: argument 3 is required to be a constant + --> $DIR/const_arg_local.rs:10:5 + | +LL | _mm_clmulepi64_si128(a, b, imm8) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/consts/const_arg_promotable.rs b/src/test/ui/consts/const_arg_promotable.rs new file mode 100644 index 00000000000..25f45104d6a --- /dev/null +++ b/src/test/ui/consts/const_arg_promotable.rs @@ -0,0 +1,12 @@ +// only-x86_64 + +#[cfg(target_arch = "x86")] +use std::arch::x86::*; +#[cfg(target_arch = "x86_64")] +use std::arch::x86_64::*; + +unsafe fn pclmul(a: __m128i, b: __m128i) -> __m128i { + _mm_clmulepi64_si128(a, b, *&mut 42) //~ ERROR argument 3 is required to be a constant +} + +fn main() {} diff --git a/src/test/ui/consts/const_arg_promotable.stderr b/src/test/ui/consts/const_arg_promotable.stderr new file mode 100644 index 00000000000..5de3ee6654a --- /dev/null +++ b/src/test/ui/consts/const_arg_promotable.stderr @@ -0,0 +1,8 @@ +error: argument 3 is required to be a constant + --> $DIR/const_arg_promotable.rs:9:5 + | +LL | _mm_clmulepi64_si128(a, b, *&mut 42) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/consts/const_arg_wrapper.rs b/src/test/ui/consts/const_arg_wrapper.rs new file mode 100644 index 00000000000..92ff264cd2b --- /dev/null +++ b/src/test/ui/consts/const_arg_wrapper.rs @@ -0,0 +1,12 @@ +// only-x86_64 + +#[cfg(target_arch = "x86")] +use std::arch::x86::*; +#[cfg(target_arch = "x86_64")] +use std::arch::x86_64::*; + +unsafe fn pclmul(a: __m128i, b: __m128i, imm8: i32) -> __m128i { + _mm_clmulepi64_si128(a, b, imm8) //~ ERROR argument 3 is required to be a constant +} + +fn main() {} diff --git a/src/test/ui/consts/const_arg_wrapper.stderr b/src/test/ui/consts/const_arg_wrapper.stderr new file mode 100644 index 00000000000..4acf2f0f4d1 --- /dev/null +++ b/src/test/ui/consts/const_arg_wrapper.stderr @@ -0,0 +1,8 @@ +error: argument 3 is required to be a constant + --> $DIR/const_arg_wrapper.rs:9:5 + | +LL | _mm_clmulepi64_si128(a, b, imm8) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.stderr index 48c260644a7..5c1bbc6ba31 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe.stderr @@ -1,33 +1,37 @@ -error[E0658]: dereferencing raw pointers in constant functions is unstable (see issue #51911) +error[E0658]: dereferencing raw pointers in constant functions is unstable --> $DIR/min_const_fn_unsafe.rs:50:77 | LL | const fn bad_const_fn_deref_raw(x: *mut usize) -> &'static usize { unsafe { &*x } } | ^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/51911 = help: add #![feature(const_raw_ptr_deref)] to the crate attributes to enable -error[E0658]: dereferencing raw pointers in constant functions is unstable (see issue #51911) +error[E0658]: dereferencing raw pointers in constant functions is unstable --> $DIR/min_const_fn_unsafe.rs:53:70 | LL | const unsafe fn bad_const_unsafe_deref_raw(x: *mut usize) -> usize { *x } | ^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/51911 = help: add #![feature(const_raw_ptr_deref)] to the crate attributes to enable -error[E0658]: dereferencing raw pointers in constant functions is unstable (see issue #51911) +error[E0658]: dereferencing raw pointers in constant functions is unstable --> $DIR/min_const_fn_unsafe.rs:56:83 | LL | const unsafe fn bad_const_unsafe_deref_raw_ref(x: *mut usize) -> &'static usize { &*x } | ^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/51911 = help: add #![feature(const_raw_ptr_deref)] to the crate attributes to enable -error[E0658]: unions in const fn are unstable (see issue #51909) +error[E0658]: unions in const fn are unstable --> $DIR/min_const_fn_unsafe.rs:63:5 | LL | Foo { x: () }.y | ^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/51909 = help: add #![feature(const_fn_union)] to the crate attributes to enable error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block diff --git a/src/test/ui/consts/projection_qualif.stderr b/src/test/ui/consts/projection_qualif.stderr index 45679e3b962..15d332aba1f 100644 --- a/src/test/ui/consts/projection_qualif.stderr +++ b/src/test/ui/consts/projection_qualif.stderr @@ -10,12 +10,13 @@ error[E0019]: constant contains unimplemented expression type LL | unsafe { *b = 5; } | ^^^^^^ -error[E0658]: dereferencing raw pointers in constants is unstable (see issue #51911) +error[E0658]: dereferencing raw pointers in constants is unstable --> $DIR/projection_qualif.rs:7:18 | LL | unsafe { *b = 5; } | ^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/51911 = help: add #![feature(const_raw_ptr_deref)] to the crate attributes to enable error: aborting due to 3 previous errors diff --git a/src/test/ui/custom_attribute.stderr b/src/test/ui/custom_attribute.stderr index 6608fb53c30..adb05e3fb2a 100644 --- a/src/test/ui/custom_attribute.stderr +++ b/src/test/ui/custom_attribute.stderr @@ -1,25 +1,28 @@ -error[E0658]: The attribute `foo` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `foo` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/custom_attribute.rs:3:3 | LL | #[foo] | ^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `foo` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `foo` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/custom_attribute.rs:5:7 | LL | #[foo] | ^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `foo` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `foo` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/custom_attribute.rs:7:7 | LL | #[foo] | ^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable error: aborting due to 3 previous errors diff --git a/src/test/ui/dep-graph/dep-graph-assoc-type-codegen.rs b/src/test/ui/dep-graph/dep-graph-assoc-type-codegen.rs index f3df57e6ff9..bcf7e3e6608 100644 --- a/src/test/ui/dep-graph/dep-graph-assoc-type-codegen.rs +++ b/src/test/ui/dep-graph/dep-graph-assoc-type-codegen.rs @@ -25,7 +25,7 @@ mod x { mod y { use Foo; - #[rustc_then_this_would_need(TypeckTables)] //~ ERROR OK + #[rustc_then_this_would_need(typeck_tables_of)] //~ ERROR OK pub fn use_char_assoc() { // Careful here: in the representation, <char as Foo>::T gets // normalized away, so at a certain point we had no edge to diff --git a/src/test/ui/dep-graph/dep-graph-assoc-type-codegen.stderr b/src/test/ui/dep-graph/dep-graph-assoc-type-codegen.stderr index db6ee98bb7b..a603d71596b 100644 --- a/src/test/ui/dep-graph/dep-graph-assoc-type-codegen.stderr +++ b/src/test/ui/dep-graph/dep-graph-assoc-type-codegen.stderr @@ -1,8 +1,8 @@ error: OK --> $DIR/dep-graph-assoc-type-codegen.rs:28:5 | -LL | #[rustc_then_this_would_need(TypeckTables)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(typeck_tables_of)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/dep-graph/dep-graph-caller-callee.rs b/src/test/ui/dep-graph/dep-graph-caller-callee.rs index f8276ea3ad6..18b4252a06b 100644 --- a/src/test/ui/dep-graph/dep-graph-caller-callee.rs +++ b/src/test/ui/dep-graph/dep-graph-caller-callee.rs @@ -17,7 +17,7 @@ mod y { use x; // These dependencies SHOULD exist: - #[rustc_then_this_would_need(TypeckTables)] //~ ERROR OK + #[rustc_then_this_would_need(typeck_tables_of)] //~ ERROR OK pub fn y() { x::x(); } @@ -28,7 +28,7 @@ mod z { // These are expected to yield errors, because changes to `x` // affect the BODY of `y`, but not its signature. - #[rustc_then_this_would_need(TypeckTables)] //~ ERROR no path + #[rustc_then_this_would_need(typeck_tables_of)] //~ ERROR no path pub fn z() { y::y(); } diff --git a/src/test/ui/dep-graph/dep-graph-caller-callee.stderr b/src/test/ui/dep-graph/dep-graph-caller-callee.stderr index 2b1b7fe9a56..de041e60067 100644 --- a/src/test/ui/dep-graph/dep-graph-caller-callee.stderr +++ b/src/test/ui/dep-graph/dep-graph-caller-callee.stderr @@ -1,14 +1,14 @@ error: OK --> $DIR/dep-graph-caller-callee.rs:20:5 | -LL | #[rustc_then_this_would_need(TypeckTables)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(typeck_tables_of)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: no path from `x::x` to `TypeckTables` +error: no path from `x::x` to `typeck_tables_of` --> $DIR/dep-graph-caller-callee.rs:31:5 | -LL | #[rustc_then_this_would_need(TypeckTables)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(typeck_tables_of)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/dep-graph/dep-graph-struct-signature.rs b/src/test/ui/dep-graph/dep-graph-struct-signature.rs index bd6d3a7e56f..8b78d39ecae 100644 --- a/src/test/ui/dep-graph/dep-graph-struct-signature.rs +++ b/src/test/ui/dep-graph/dep-graph-struct-signature.rs @@ -25,34 +25,34 @@ mod signatures { use WillChange; #[rustc_then_this_would_need(type_of)] //~ ERROR no path - #[rustc_then_this_would_need(AssociatedItems)] //~ ERROR no path - #[rustc_then_this_would_need(TraitDefOfItem)] //~ ERROR no path + #[rustc_then_this_would_need(associated_item)] //~ ERROR no path + #[rustc_then_this_would_need(trait_def)] //~ ERROR no path trait Bar { - #[rustc_then_this_would_need(FnSignature)] //~ ERROR OK + #[rustc_then_this_would_need(fn_sig)] //~ ERROR OK fn do_something(x: WillChange); } - #[rustc_then_this_would_need(FnSignature)] //~ ERROR OK - #[rustc_then_this_would_need(TypeckTables)] //~ ERROR OK + #[rustc_then_this_would_need(fn_sig)] //~ ERROR OK + #[rustc_then_this_would_need(typeck_tables_of)] //~ ERROR OK fn some_fn(x: WillChange) { } - #[rustc_then_this_would_need(FnSignature)] //~ ERROR OK - #[rustc_then_this_would_need(TypeckTables)] //~ ERROR OK + #[rustc_then_this_would_need(fn_sig)] //~ ERROR OK + #[rustc_then_this_would_need(typeck_tables_of)] //~ ERROR OK fn new_foo(x: u32, y: u32) -> WillChange { WillChange { x: x, y: y } } #[rustc_then_this_would_need(type_of)] //~ ERROR OK impl WillChange { - #[rustc_then_this_would_need(FnSignature)] //~ ERROR OK - #[rustc_then_this_would_need(TypeckTables)] //~ ERROR OK + #[rustc_then_this_would_need(fn_sig)] //~ ERROR OK + #[rustc_then_this_would_need(typeck_tables_of)] //~ ERROR OK fn new(x: u32, y: u32) -> WillChange { loop { } } } #[rustc_then_this_would_need(type_of)] //~ ERROR OK impl WillChange { - #[rustc_then_this_would_need(FnSignature)] //~ ERROR OK - #[rustc_then_this_would_need(TypeckTables)] //~ ERROR OK + #[rustc_then_this_would_need(fn_sig)] //~ ERROR OK + #[rustc_then_this_would_need(typeck_tables_of)] //~ ERROR OK fn method(&self, x: u32) { } } @@ -73,14 +73,14 @@ mod invalid_signatures { #[rustc_then_this_would_need(type_of)] //~ ERROR no path trait A { - #[rustc_then_this_would_need(FnSignature)] //~ ERROR no path + #[rustc_then_this_would_need(fn_sig)] //~ ERROR no path fn do_something_else_twice(x: WontChange); } - #[rustc_then_this_would_need(FnSignature)] //~ ERROR no path + #[rustc_then_this_would_need(fn_sig)] //~ ERROR no path fn b(x: WontChange) { } - #[rustc_then_this_would_need(FnSignature)] //~ ERROR no path from `WillChange` - #[rustc_then_this_would_need(TypeckTables)] //~ ERROR no path from `WillChange` + #[rustc_then_this_would_need(fn_sig)] //~ ERROR no path from `WillChange` + #[rustc_then_this_would_need(typeck_tables_of)] //~ ERROR no path from `WillChange` fn c(x: u32) { } } diff --git a/src/test/ui/dep-graph/dep-graph-struct-signature.stderr b/src/test/ui/dep-graph/dep-graph-struct-signature.stderr index 7aa4251752e..2e00e5a2cbd 100644 --- a/src/test/ui/dep-graph/dep-graph-struct-signature.stderr +++ b/src/test/ui/dep-graph/dep-graph-struct-signature.stderr @@ -4,41 +4,41 @@ error: no path from `WillChange` to `type_of` LL | #[rustc_then_this_would_need(type_of)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: no path from `WillChange` to `AssociatedItems` +error: no path from `WillChange` to `associated_item` --> $DIR/dep-graph-struct-signature.rs:28:5 | -LL | #[rustc_then_this_would_need(AssociatedItems)] +LL | #[rustc_then_this_would_need(associated_item)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: no path from `WillChange` to `TraitDefOfItem` +error: no path from `WillChange` to `trait_def` --> $DIR/dep-graph-struct-signature.rs:29:5 | -LL | #[rustc_then_this_would_need(TraitDefOfItem)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(trait_def)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK --> $DIR/dep-graph-struct-signature.rs:35:5 | -LL | #[rustc_then_this_would_need(FnSignature)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(fn_sig)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK --> $DIR/dep-graph-struct-signature.rs:36:5 | -LL | #[rustc_then_this_would_need(TypeckTables)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(typeck_tables_of)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK --> $DIR/dep-graph-struct-signature.rs:39:5 | -LL | #[rustc_then_this_would_need(FnSignature)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(fn_sig)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK --> $DIR/dep-graph-struct-signature.rs:40:5 | -LL | #[rustc_then_this_would_need(TypeckTables)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(typeck_tables_of)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK --> $DIR/dep-graph-struct-signature.rs:45:5 @@ -76,59 +76,59 @@ error: no path from `WillChange` to `type_of` LL | #[rustc_then_this_would_need(type_of)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: no path from `WillChange` to `FnSignature` +error: no path from `WillChange` to `fn_sig` --> $DIR/dep-graph-struct-signature.rs:80:5 | -LL | #[rustc_then_this_would_need(FnSignature)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(fn_sig)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: no path from `WillChange` to `FnSignature` +error: no path from `WillChange` to `fn_sig` --> $DIR/dep-graph-struct-signature.rs:83:5 | -LL | #[rustc_then_this_would_need(FnSignature)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(fn_sig)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: no path from `WillChange` to `TypeckTables` +error: no path from `WillChange` to `typeck_tables_of` --> $DIR/dep-graph-struct-signature.rs:84:5 | -LL | #[rustc_then_this_would_need(TypeckTables)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(typeck_tables_of)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK --> $DIR/dep-graph-struct-signature.rs:31:9 | -LL | #[rustc_then_this_would_need(FnSignature)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(fn_sig)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: no path from `WillChange` to `FnSignature` +error: no path from `WillChange` to `fn_sig` --> $DIR/dep-graph-struct-signature.rs:76:9 | -LL | #[rustc_then_this_would_need(FnSignature)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(fn_sig)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK --> $DIR/dep-graph-struct-signature.rs:47:9 | -LL | #[rustc_then_this_would_need(FnSignature)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(fn_sig)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK --> $DIR/dep-graph-struct-signature.rs:48:9 | -LL | #[rustc_then_this_would_need(TypeckTables)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(typeck_tables_of)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK --> $DIR/dep-graph-struct-signature.rs:54:9 | -LL | #[rustc_then_this_would_need(FnSignature)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(fn_sig)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK --> $DIR/dep-graph-struct-signature.rs:55:9 | -LL | #[rustc_then_this_would_need(TypeckTables)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(typeck_tables_of)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 22 previous errors diff --git a/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits-same-method.rs b/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits-same-method.rs index 16e5a705d25..38622a754dd 100644 --- a/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits-same-method.rs +++ b/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits-same-method.rs @@ -29,7 +29,7 @@ mod x { mod y { use {Foo, Bar}; - #[rustc_then_this_would_need(TypeckTables)] //~ ERROR OK + #[rustc_then_this_would_need(typeck_tables_of)] //~ ERROR OK pub fn with_char() { char::method('a'); } @@ -38,7 +38,7 @@ mod y { mod z { use y; - #[rustc_then_this_would_need(TypeckTables)] //~ ERROR no path + #[rustc_then_this_would_need(typeck_tables_of)] //~ ERROR no path pub fn z() { y::with_char(); } diff --git a/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits-same-method.stderr b/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits-same-method.stderr index 2df4b9ec39d..3384fd7b4ac 100644 --- a/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits-same-method.stderr +++ b/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits-same-method.stderr @@ -1,14 +1,14 @@ error: OK --> $DIR/dep-graph-trait-impl-two-traits-same-method.rs:32:5 | -LL | #[rustc_then_this_would_need(TypeckTables)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(typeck_tables_of)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: no path from `x::<impl Foo for u32>` to `TypeckTables` +error: no path from `x::<impl Foo for u32>` to `typeck_tables_of` --> $DIR/dep-graph-trait-impl-two-traits-same-method.rs:41:5 | -LL | #[rustc_then_this_would_need(TypeckTables)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(typeck_tables_of)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits.rs b/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits.rs index 064302c9c80..82306b6539c 100644 --- a/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits.rs +++ b/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits.rs @@ -28,7 +28,7 @@ mod x { mod y { use {Foo, Bar}; - #[rustc_then_this_would_need(TypeckTables)] //~ ERROR no path + #[rustc_then_this_would_need(typeck_tables_of)] //~ ERROR no path pub fn call_bar() { char::bar('a'); } @@ -37,7 +37,7 @@ mod y { mod z { use y; - #[rustc_then_this_would_need(TypeckTables)] //~ ERROR no path + #[rustc_then_this_would_need(typeck_tables_of)] //~ ERROR no path pub fn z() { y::call_bar(); } diff --git a/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits.stderr b/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits.stderr index 54125367f90..d8a1f05dcaa 100644 --- a/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits.stderr +++ b/src/test/ui/dep-graph/dep-graph-trait-impl-two-traits.stderr @@ -1,14 +1,14 @@ -error: no path from `x::<impl Foo for char>` to `TypeckTables` +error: no path from `x::<impl Foo for char>` to `typeck_tables_of` --> $DIR/dep-graph-trait-impl-two-traits.rs:31:5 | -LL | #[rustc_then_this_would_need(TypeckTables)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(typeck_tables_of)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: no path from `x::<impl Foo for char>` to `TypeckTables` +error: no path from `x::<impl Foo for char>` to `typeck_tables_of` --> $DIR/dep-graph-trait-impl-two-traits.rs:40:5 | -LL | #[rustc_then_this_would_need(TypeckTables)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(typeck_tables_of)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/dep-graph/dep-graph-trait-impl.rs b/src/test/ui/dep-graph/dep-graph-trait-impl.rs index 7d088082c7a..e4483b9f71d 100644 --- a/src/test/ui/dep-graph/dep-graph-trait-impl.rs +++ b/src/test/ui/dep-graph/dep-graph-trait-impl.rs @@ -24,22 +24,22 @@ mod x { mod y { use Foo; - #[rustc_then_this_would_need(TypeckTables)] //~ ERROR OK + #[rustc_then_this_would_need(typeck_tables_of)] //~ ERROR OK pub fn with_char() { char::method('a'); } - #[rustc_then_this_would_need(TypeckTables)] //~ ERROR OK + #[rustc_then_this_would_need(typeck_tables_of)] //~ ERROR OK pub fn take_foo_with_char() { take_foo::<char>('a'); } - #[rustc_then_this_would_need(TypeckTables)] //~ ERROR OK + #[rustc_then_this_would_need(typeck_tables_of)] //~ ERROR OK pub fn with_u32() { u32::method(22); } - #[rustc_then_this_would_need(TypeckTables)] //~ ERROR OK + #[rustc_then_this_would_need(typeck_tables_of)] //~ ERROR OK pub fn take_foo_with_u32() { take_foo::<u32>(22); } @@ -52,7 +52,7 @@ mod z { // These are expected to yield errors, because changes to `x` // affect the BODY of `y`, but not its signature. - #[rustc_then_this_would_need(TypeckTables)] //~ ERROR no path + #[rustc_then_this_would_need(typeck_tables_of)] //~ ERROR no path pub fn z() { y::with_char(); y::with_u32(); diff --git a/src/test/ui/dep-graph/dep-graph-trait-impl.stderr b/src/test/ui/dep-graph/dep-graph-trait-impl.stderr index 97072e74f42..ca9676a9478 100644 --- a/src/test/ui/dep-graph/dep-graph-trait-impl.stderr +++ b/src/test/ui/dep-graph/dep-graph-trait-impl.stderr @@ -1,32 +1,32 @@ error: OK --> $DIR/dep-graph-trait-impl.rs:27:5 | -LL | #[rustc_then_this_would_need(TypeckTables)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(typeck_tables_of)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK --> $DIR/dep-graph-trait-impl.rs:32:5 | -LL | #[rustc_then_this_would_need(TypeckTables)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(typeck_tables_of)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK --> $DIR/dep-graph-trait-impl.rs:37:5 | -LL | #[rustc_then_this_would_need(TypeckTables)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(typeck_tables_of)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK --> $DIR/dep-graph-trait-impl.rs:42:5 | -LL | #[rustc_then_this_would_need(TypeckTables)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(typeck_tables_of)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: no path from `x::<impl Foo for char>` to `TypeckTables` +error: no path from `x::<impl Foo for char>` to `typeck_tables_of` --> $DIR/dep-graph-trait-impl.rs:55:5 | -LL | #[rustc_then_this_would_need(TypeckTables)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(typeck_tables_of)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 5 previous errors diff --git a/src/test/ui/dep-graph/dep-graph-type-alias.rs b/src/test/ui/dep-graph/dep-graph-type-alias.rs index 5621284fb18..2d4a18f2818 100644 --- a/src/test/ui/dep-graph/dep-graph-type-alias.rs +++ b/src/test/ui/dep-graph/dep-graph-type-alias.rs @@ -32,7 +32,7 @@ enum Enum { #[rustc_then_this_would_need(type_of)] //~ ERROR no path trait Trait { - #[rustc_then_this_would_need(FnSignature)] //~ ERROR OK + #[rustc_then_this_would_need(fn_sig)] //~ ERROR OK fn method(&self, _: TypeAlias); } @@ -40,16 +40,16 @@ struct SomeType; #[rustc_then_this_would_need(type_of)] //~ ERROR no path impl SomeType { - #[rustc_then_this_would_need(FnSignature)] //~ ERROR OK - #[rustc_then_this_would_need(TypeckTables)] //~ ERROR OK + #[rustc_then_this_would_need(fn_sig)] //~ ERROR OK + #[rustc_then_this_would_need(typeck_tables_of)] //~ ERROR OK fn method(&self, _: TypeAlias) {} } #[rustc_then_this_would_need(type_of)] //~ ERROR OK type TypeAlias2 = TypeAlias; -#[rustc_then_this_would_need(FnSignature)] //~ ERROR OK -#[rustc_then_this_would_need(TypeckTables)] //~ ERROR OK +#[rustc_then_this_would_need(fn_sig)] //~ ERROR OK +#[rustc_then_this_would_need(typeck_tables_of)] //~ ERROR OK fn function(_: TypeAlias) { } diff --git a/src/test/ui/dep-graph/dep-graph-type-alias.stderr b/src/test/ui/dep-graph/dep-graph-type-alias.stderr index 520c2a5ed21..393e4badc16 100644 --- a/src/test/ui/dep-graph/dep-graph-type-alias.stderr +++ b/src/test/ui/dep-graph/dep-graph-type-alias.stderr @@ -43,32 +43,32 @@ LL | #[rustc_then_this_would_need(type_of)] error: OK --> $DIR/dep-graph-type-alias.rs:51:1 | -LL | #[rustc_then_this_would_need(FnSignature)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(fn_sig)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK --> $DIR/dep-graph-type-alias.rs:52:1 | -LL | #[rustc_then_this_would_need(TypeckTables)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(typeck_tables_of)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK --> $DIR/dep-graph-type-alias.rs:35:5 | -LL | #[rustc_then_this_would_need(FnSignature)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(fn_sig)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK --> $DIR/dep-graph-type-alias.rs:43:5 | -LL | #[rustc_then_this_would_need(FnSignature)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(fn_sig)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: OK --> $DIR/dep-graph-type-alias.rs:44:5 | -LL | #[rustc_then_this_would_need(TypeckTables)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(typeck_tables_of)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 12 previous errors diff --git a/src/test/ui/dep-graph/dep-graph-variance-alias.rs b/src/test/ui/dep-graph/dep-graph-variance-alias.rs index 0a70bfd08bf..95645687307 100644 --- a/src/test/ui/dep-graph/dep-graph-variance-alias.rs +++ b/src/test/ui/dep-graph/dep-graph-variance-alias.rs @@ -16,7 +16,7 @@ struct Foo<T> { #[rustc_if_this_changed(Krate)] type TypeAlias<T> = Foo<T>; -#[rustc_then_this_would_need(ItemVariances)] //~ ERROR OK +#[rustc_then_this_would_need(variances_of)] //~ ERROR OK struct Use<T> { x: TypeAlias<T> } diff --git a/src/test/ui/dep-graph/dep-graph-variance-alias.stderr b/src/test/ui/dep-graph/dep-graph-variance-alias.stderr index 86cb0f9fe32..554ff455a20 100644 --- a/src/test/ui/dep-graph/dep-graph-variance-alias.stderr +++ b/src/test/ui/dep-graph/dep-graph-variance-alias.stderr @@ -1,8 +1,8 @@ error: OK --> $DIR/dep-graph-variance-alias.rs:19:1 | -LL | #[rustc_then_this_would_need(ItemVariances)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[rustc_then_this_would_need(variances_of)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/empty/empty-struct-braces-expr.rs b/src/test/ui/empty/empty-struct-braces-expr.rs index 2f2f41ae8c1..e33fcb70db7 100644 --- a/src/test/ui/empty/empty-struct-braces-expr.rs +++ b/src/test/ui/empty/empty-struct-braces-expr.rs @@ -19,6 +19,8 @@ fn main() { let xe1 = XEmpty1; //~ ERROR expected value, found struct `XEmpty1` let xe1 = XEmpty1(); //~ ERROR expected function, found struct `XEmpty1` - let xe3 = XE::Empty3; //~ ERROR no variant named `Empty3` found for type - let xe3 = XE::Empty3(); //~ ERROR no variant named `Empty3` found for type + let xe3 = XE::Empty3; //~ ERROR no variant or associated item named `Empty3` found for type + let xe3 = XE::Empty3(); //~ ERROR no variant or associated item named `Empty3` found for type + + XE::Empty1 {}; //~ ERROR no variant `Empty1` in enum `empty_struct::XE` } diff --git a/src/test/ui/empty/empty-struct-braces-expr.stderr b/src/test/ui/empty/empty-struct-braces-expr.stderr index 57c8c1c85dd..f5609c8e1bf 100644 --- a/src/test/ui/empty/empty-struct-braces-expr.stderr +++ b/src/test/ui/empty/empty-struct-braces-expr.stderr @@ -46,25 +46,31 @@ LL | let xe1 = XEmpty1(); | did you mean `XEmpty1 { /* fields */ }`? | help: a unit struct with a similar name exists: `XEmpty2` -error[E0599]: no variant named `Empty3` found for type `empty_struct::XE` in the current scope +error[E0599]: no variant or associated item named `Empty3` found for type `empty_struct::XE` in the current scope --> $DIR/empty-struct-braces-expr.rs:22:19 | LL | let xe3 = XE::Empty3; | ^^^^^^ | | - | variant not found in `empty_struct::XE` - | help: did you mean: `XEmpty3` + | variant or associated item not found in `empty_struct::XE` + | help: there is a variant with a similar name: `XEmpty3` -error[E0599]: no variant named `Empty3` found for type `empty_struct::XE` in the current scope +error[E0599]: no variant or associated item named `Empty3` found for type `empty_struct::XE` in the current scope --> $DIR/empty-struct-braces-expr.rs:23:19 | LL | let xe3 = XE::Empty3(); | ^^^^^^ | | - | variant not found in `empty_struct::XE` - | help: did you mean: `XEmpty3` + | variant or associated item not found in `empty_struct::XE` + | help: there is a variant with a similar name: `XEmpty3` -error: aborting due to 8 previous errors +error: no variant `Empty1` in enum `empty_struct::XE` + --> $DIR/empty-struct-braces-expr.rs:25:9 + | +LL | XE::Empty1 {}; + | ^^^^^^ help: there is a variant with a similar name: `XEmpty3` + +error: aborting due to 9 previous errors Some errors occurred: E0423, E0599. For more information about an error, try `rustc --explain E0423`. diff --git a/src/test/ui/error-codes/E0254.rs b/src/test/ui/error-codes/E0254.rs index 706cd347e13..d166aff5657 100644 --- a/src/test/ui/error-codes/E0254.rs +++ b/src/test/ui/error-codes/E0254.rs @@ -1,4 +1,3 @@ -#![feature(alloc)] #![allow(unused_extern_crates, non_camel_case_types)] extern crate alloc; diff --git a/src/test/ui/error-codes/E0254.stderr b/src/test/ui/error-codes/E0254.stderr index c2d013da417..10456fd5a5d 100644 --- a/src/test/ui/error-codes/E0254.stderr +++ b/src/test/ui/error-codes/E0254.stderr @@ -1,5 +1,5 @@ error[E0254]: the name `alloc` is defined multiple times - --> $DIR/E0254.rs:12:5 + --> $DIR/E0254.rs:11:5 | LL | extern crate alloc; | ------------------- previous import of the extern crate `alloc` here diff --git a/src/test/ui/error-codes/E0259.rs b/src/test/ui/error-codes/E0259.rs index cda3db34dfc..c83561be9c6 100644 --- a/src/test/ui/error-codes/E0259.rs +++ b/src/test/ui/error-codes/E0259.rs @@ -1,4 +1,4 @@ -#![feature(alloc, rustc_private)] +#![feature(rustc_private)] #![allow(unused_extern_crates)] extern crate alloc; diff --git a/src/test/ui/error-codes/E0260.rs b/src/test/ui/error-codes/E0260.rs index 80382c0d2fc..73b8934159f 100644 --- a/src/test/ui/error-codes/E0260.rs +++ b/src/test/ui/error-codes/E0260.rs @@ -1,4 +1,3 @@ -#![feature(alloc)] #![allow(unused_extern_crates)] extern crate alloc; diff --git a/src/test/ui/error-codes/E0260.stderr b/src/test/ui/error-codes/E0260.stderr index bfe2ed0cfc7..7d0b3022914 100644 --- a/src/test/ui/error-codes/E0260.stderr +++ b/src/test/ui/error-codes/E0260.stderr @@ -1,5 +1,5 @@ error[E0260]: the name `alloc` is defined multiple times - --> $DIR/E0260.rs:6:1 + --> $DIR/E0260.rs:5:1 | LL | extern crate alloc; | ------------------- previous import of the extern crate `alloc` here diff --git a/src/test/ui/error-codes/E0395.rs b/src/test/ui/error-codes/E0395.rs index 9657bbdeadc..bbefff27d7f 100644 --- a/src/test/ui/error-codes/E0395.rs +++ b/src/test/ui/error-codes/E0395.rs @@ -3,6 +3,8 @@ static FOO: i32 = 42; static BAR: i32 = 42; -static BAZ: bool = unsafe { (&FOO as *const i32) == (&BAR as *const i32) }; //~ ERROR issue #53020 +static BAZ: bool = unsafe { (&FOO as *const i32) == (&BAR as *const i32) }; +//~^ ERROR comparing raw pointers inside static + fn main() { } diff --git a/src/test/ui/error-codes/E0395.stderr b/src/test/ui/error-codes/E0395.stderr index 9d80acb515d..30a4d4815ff 100644 --- a/src/test/ui/error-codes/E0395.stderr +++ b/src/test/ui/error-codes/E0395.stderr @@ -1,9 +1,10 @@ -error[E0658]: comparing raw pointers inside static (see issue #53020) +error[E0658]: comparing raw pointers inside static --> $DIR/E0395.rs:6:29 | LL | static BAZ: bool = unsafe { (&FOO as *const i32) == (&BAR as *const i32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/53020 = help: add #![feature(const_compare_raw_pointers)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0396.stderr b/src/test/ui/error-codes/E0396.stderr index 1006ff6dc54..6d2d121e91c 100644 --- a/src/test/ui/error-codes/E0396.stderr +++ b/src/test/ui/error-codes/E0396.stderr @@ -1,9 +1,10 @@ -error[E0658]: dereferencing raw pointers in constants is unstable (see issue #51911) +error[E0658]: dereferencing raw pointers in constants is unstable --> $DIR/E0396.rs:5:28 | LL | const VALUE: u8 = unsafe { *REG_ADDR }; | ^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/51911 = help: add #![feature(const_raw_ptr_deref)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0658.stderr b/src/test/ui/error-codes/E0658.stderr index 292c49fa84e..ff3f74addd2 100644 --- a/src/test/ui/error-codes/E0658.stderr +++ b/src/test/ui/error-codes/E0658.stderr @@ -1,4 +1,4 @@ -error[E0658]: repr with 128-bit type is unstable (see issue #35118) +error[E0658]: repr with 128-bit type is unstable --> $DIR/E0658.rs:2:1 | LL | / enum Foo { @@ -6,6 +6,7 @@ LL | | Bar(u64), LL | | } | |_^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/35118 = help: add #![feature(repr128)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/explore-issue-38412.stderr b/src/test/ui/explore-issue-38412.stderr index 5e5d952bcec..eb28ad410fa 100644 --- a/src/test/ui/explore-issue-38412.stderr +++ b/src/test/ui/explore-issue-38412.stderr @@ -1,17 +1,19 @@ -error[E0658]: use of unstable library feature 'unstable_undeclared' (see issue #38412) +error[E0658]: use of unstable library feature 'unstable_undeclared' --> $DIR/explore-issue-38412.rs:21:63 | LL | let Record { a_stable_pub: _, a_unstable_declared_pub: _, a_unstable_undeclared_pub: _, .. } = | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/38412 = help: add #![feature(unstable_undeclared)] to the crate attributes to enable -error[E0658]: use of unstable library feature 'unstable_undeclared' (see issue #38412) +error[E0658]: use of unstable library feature 'unstable_undeclared' --> $DIR/explore-issue-38412.rs:30:5 | LL | r.a_unstable_undeclared_pub; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/38412 = help: add #![feature(unstable_undeclared)] to the crate attributes to enable error[E0616]: field `b_crate` of struct `pub_and_stability::Record` is private @@ -32,12 +34,13 @@ error[E0616]: field `d_priv` of struct `pub_and_stability::Record` is private LL | r.d_priv; | ^^^^^^^^ -error[E0658]: use of unstable library feature 'unstable_undeclared' (see issue #38412) +error[E0658]: use of unstable library feature 'unstable_undeclared' --> $DIR/explore-issue-38412.rs:37:5 | LL | t.2; | ^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/38412 = help: add #![feature(unstable_undeclared)] to the crate attributes to enable error[E0616]: field `3` of struct `pub_and_stability::Tuple` is private @@ -58,20 +61,22 @@ error[E0616]: field `5` of struct `pub_and_stability::Tuple` is private LL | t.5; | ^^^ -error[E0658]: use of unstable library feature 'unstable_undeclared' (see issue #38412) +error[E0658]: use of unstable library feature 'unstable_undeclared' --> $DIR/explore-issue-38412.rs:44:7 | LL | r.unstable_undeclared_trait_method(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/38412 = help: add #![feature(unstable_undeclared)] to the crate attributes to enable -error[E0658]: use of unstable library feature 'unstable_undeclared' (see issue #38412) +error[E0658]: use of unstable library feature 'unstable_undeclared' --> $DIR/explore-issue-38412.rs:48:7 | LL | r.unstable_undeclared(); | ^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/38412 = help: add #![feature(unstable_undeclared)] to the crate attributes to enable error[E0624]: method `pub_crate` is private @@ -92,20 +97,22 @@ error[E0624]: method `private` is private LL | r.private(); | ^^^^^^^ -error[E0658]: use of unstable library feature 'unstable_undeclared' (see issue #38412) +error[E0658]: use of unstable library feature 'unstable_undeclared' --> $DIR/explore-issue-38412.rs:57:7 | LL | t.unstable_undeclared_trait_method(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/38412 = help: add #![feature(unstable_undeclared)] to the crate attributes to enable -error[E0658]: use of unstable library feature 'unstable_undeclared' (see issue #38412) +error[E0658]: use of unstable library feature 'unstable_undeclared' --> $DIR/explore-issue-38412.rs:61:7 | LL | t.unstable_undeclared(); | ^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/38412 = help: add #![feature(unstable_undeclared)] to the crate attributes to enable error[E0624]: method `pub_crate` is private diff --git a/src/test/ui/feature-gate-optimize_attribute.rs b/src/test/ui/feature-gate-optimize_attribute.rs index c1f75100141..f252a3c153d 100644 --- a/src/test/ui/feature-gate-optimize_attribute.rs +++ b/src/test/ui/feature-gate-optimize_attribute.rs @@ -1,17 +1,17 @@ #![crate_type="rlib"] -#![optimize(speed)] //~ ERROR #54882 +#![optimize(speed)] //~ ERROR #[optimize] attribute is an unstable feature -#[optimize(size)] //~ ERROR #54882 +#[optimize(size)] //~ ERROR #[optimize] attribute is an unstable feature mod module { -#[optimize(size)] //~ ERROR #54882 +#[optimize(size)] //~ ERROR #[optimize] attribute is an unstable feature fn size() {} -#[optimize(speed)] //~ ERROR #54882 +#[optimize(speed)] //~ ERROR #[optimize] attribute is an unstable feature fn speed() {} #[optimize(banana)] -//~^ ERROR #54882 +//~^ ERROR #[optimize] attribute is an unstable feature //~| ERROR E0722 fn not_known() {} diff --git a/src/test/ui/feature-gate-optimize_attribute.stderr b/src/test/ui/feature-gate-optimize_attribute.stderr index 7635af6ce46..b4ba3fded15 100644 --- a/src/test/ui/feature-gate-optimize_attribute.stderr +++ b/src/test/ui/feature-gate-optimize_attribute.stderr @@ -1,41 +1,46 @@ -error[E0658]: #[optimize] attribute is an unstable feature (see issue #54882) +error[E0658]: #[optimize] attribute is an unstable feature --> $DIR/feature-gate-optimize_attribute.rs:7:1 | LL | #[optimize(size)] | ^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/54882 = help: add #![feature(optimize_attribute)] to the crate attributes to enable -error[E0658]: #[optimize] attribute is an unstable feature (see issue #54882) +error[E0658]: #[optimize] attribute is an unstable feature --> $DIR/feature-gate-optimize_attribute.rs:10:1 | LL | #[optimize(speed)] | ^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/54882 = help: add #![feature(optimize_attribute)] to the crate attributes to enable -error[E0658]: #[optimize] attribute is an unstable feature (see issue #54882) +error[E0658]: #[optimize] attribute is an unstable feature --> $DIR/feature-gate-optimize_attribute.rs:13:1 | LL | #[optimize(banana)] | ^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/54882 = help: add #![feature(optimize_attribute)] to the crate attributes to enable -error[E0658]: #[optimize] attribute is an unstable feature (see issue #54882) +error[E0658]: #[optimize] attribute is an unstable feature --> $DIR/feature-gate-optimize_attribute.rs:4:1 | LL | #[optimize(size)] | ^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/54882 = help: add #![feature(optimize_attribute)] to the crate attributes to enable -error[E0658]: #[optimize] attribute is an unstable feature (see issue #54882) +error[E0658]: #[optimize] attribute is an unstable feature --> $DIR/feature-gate-optimize_attribute.rs:2:1 | LL | #![optimize(speed)] | ^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/54882 = help: add #![feature(optimize_attribute)] to the crate attributes to enable error[E0722]: invalid argument diff --git a/src/test/ui/feature-gate/feature-gate-c_variadic.stderr b/src/test/ui/feature-gate/feature-gate-c_variadic.stderr index a876e16fdea..a1362901862 100644 --- a/src/test/ui/feature-gate/feature-gate-c_variadic.stderr +++ b/src/test/ui/feature-gate/feature-gate-c_variadic.stderr @@ -1,9 +1,10 @@ -error[E0658]: C-varaidic functions are unstable (see issue #44930) +error[E0658]: C-varaidic functions are unstable --> $DIR/feature-gate-c_variadic.rs:3:1 | LL | pub unsafe extern "C" fn test(_: i32, ap: ...) { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/44930 = help: add #![feature(c_variadic)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gate/feature-gate-static-nobundle-2.stderr b/src/test/ui/feature-gate/feature-gate-static-nobundle-2.stderr index 419c21901a0..4a653265f16 100644 --- a/src/test/ui/feature-gate/feature-gate-static-nobundle-2.stderr +++ b/src/test/ui/feature-gate/feature-gate-static-nobundle-2.stderr @@ -1,5 +1,6 @@ -error[E0658]: kind="static-nobundle" is feature gated (see issue #37403) +error[E0658]: kind="static-nobundle" is feature gated | + = note: for more information, see https://github.com/rust-lang/rust/issues/37403 = help: add #![feature(static_nobundle)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-abi-msp430-interrupt.stderr b/src/test/ui/feature-gates/feature-gate-abi-msp430-interrupt.stderr index 6b3c169c99d..0eb26ec8291 100644 --- a/src/test/ui/feature-gates/feature-gate-abi-msp430-interrupt.stderr +++ b/src/test/ui/feature-gates/feature-gate-abi-msp430-interrupt.stderr @@ -1,9 +1,10 @@ -error[E0658]: msp430-interrupt ABI is experimental and subject to change (see issue #38487) +error[E0658]: msp430-interrupt ABI is experimental and subject to change --> $DIR/feature-gate-abi-msp430-interrupt.rs:4:1 | LL | extern "msp430-interrupt" fn foo() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/38487 = help: add #![feature(abi_msp430_interrupt)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-abi.stderr b/src/test/ui/feature-gates/feature-gate-abi.stderr index 7417f310921..e20ab0cb2f5 100644 --- a/src/test/ui/feature-gates/feature-gate-abi.stderr +++ b/src/test/ui/feature-gates/feature-gate-abi.stderr @@ -6,12 +6,13 @@ LL | extern "rust-intrinsic" fn f1() {} | = help: add #![feature(intrinsics)] to the crate attributes to enable -error[E0658]: platform intrinsics are experimental and possibly buggy (see issue #27731) +error[E0658]: platform intrinsics are experimental and possibly buggy --> $DIR/feature-gate-abi.rs:13:1 | LL | extern "platform-intrinsic" fn f2() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/27731 = help: add #![feature(platform_intrinsics)] to the crate attributes to enable error[E0658]: vectorcall is experimental and subject to change @@ -22,36 +23,40 @@ LL | extern "vectorcall" fn f3() {} | = help: add #![feature(abi_vectorcall)] to the crate attributes to enable -error[E0658]: rust-call ABI is subject to change (see issue #29625) +error[E0658]: rust-call ABI is subject to change --> $DIR/feature-gate-abi.rs:15:1 | LL | extern "rust-call" fn f4() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add #![feature(unboxed_closures)] to the crate attributes to enable -error[E0658]: msp430-interrupt ABI is experimental and subject to change (see issue #38487) +error[E0658]: msp430-interrupt ABI is experimental and subject to change --> $DIR/feature-gate-abi.rs:16:1 | LL | extern "msp430-interrupt" fn f5() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/38487 = help: add #![feature(abi_msp430_interrupt)] to the crate attributes to enable -error[E0658]: PTX ABIs are experimental and subject to change (see issue #38788) +error[E0658]: PTX ABIs are experimental and subject to change --> $DIR/feature-gate-abi.rs:17:1 | LL | extern "ptx-kernel" fn f6() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/38788 = help: add #![feature(abi_ptx)] to the crate attributes to enable -error[E0658]: x86-interrupt ABI is experimental and subject to change (see issue #40180) +error[E0658]: x86-interrupt ABI is experimental and subject to change --> $DIR/feature-gate-abi.rs:18:1 | LL | extern "x86-interrupt" fn f7() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/40180 = help: add #![feature(abi_x86_interrupt)] to the crate attributes to enable error[E0658]: thiscall is experimental and subject to change @@ -62,12 +67,13 @@ LL | extern "thiscall" fn f8() {} | = help: add #![feature(abi_thiscall)] to the crate attributes to enable -error[E0658]: amdgpu-kernel ABI is experimental and subject to change (see issue #51575) +error[E0658]: amdgpu-kernel ABI is experimental and subject to change --> $DIR/feature-gate-abi.rs:20:1 | LL | extern "amdgpu-kernel" fn f9() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/51575 = help: add #![feature(abi_amdgpu_kernel)] to the crate attributes to enable error[E0658]: intrinsics are subject to change @@ -78,12 +84,13 @@ LL | extern "rust-intrinsic" fn m1(); | = help: add #![feature(intrinsics)] to the crate attributes to enable -error[E0658]: platform intrinsics are experimental and possibly buggy (see issue #27731) +error[E0658]: platform intrinsics are experimental and possibly buggy --> $DIR/feature-gate-abi.rs:25:5 | LL | extern "platform-intrinsic" fn m2(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/27731 = help: add #![feature(platform_intrinsics)] to the crate attributes to enable error[E0658]: vectorcall is experimental and subject to change @@ -94,36 +101,40 @@ LL | extern "vectorcall" fn m3(); | = help: add #![feature(abi_vectorcall)] to the crate attributes to enable -error[E0658]: rust-call ABI is subject to change (see issue #29625) +error[E0658]: rust-call ABI is subject to change --> $DIR/feature-gate-abi.rs:27:5 | LL | extern "rust-call" fn m4(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add #![feature(unboxed_closures)] to the crate attributes to enable -error[E0658]: msp430-interrupt ABI is experimental and subject to change (see issue #38487) +error[E0658]: msp430-interrupt ABI is experimental and subject to change --> $DIR/feature-gate-abi.rs:28:5 | LL | extern "msp430-interrupt" fn m5(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/38487 = help: add #![feature(abi_msp430_interrupt)] to the crate attributes to enable -error[E0658]: PTX ABIs are experimental and subject to change (see issue #38788) +error[E0658]: PTX ABIs are experimental and subject to change --> $DIR/feature-gate-abi.rs:29:5 | LL | extern "ptx-kernel" fn m6(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/38788 = help: add #![feature(abi_ptx)] to the crate attributes to enable -error[E0658]: x86-interrupt ABI is experimental and subject to change (see issue #40180) +error[E0658]: x86-interrupt ABI is experimental and subject to change --> $DIR/feature-gate-abi.rs:30:5 | LL | extern "x86-interrupt" fn m7(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/40180 = help: add #![feature(abi_x86_interrupt)] to the crate attributes to enable error[E0658]: thiscall is experimental and subject to change @@ -134,12 +145,13 @@ LL | extern "thiscall" fn m8(); | = help: add #![feature(abi_thiscall)] to the crate attributes to enable -error[E0658]: amdgpu-kernel ABI is experimental and subject to change (see issue #51575) +error[E0658]: amdgpu-kernel ABI is experimental and subject to change --> $DIR/feature-gate-abi.rs:32:5 | LL | extern "amdgpu-kernel" fn m9(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/51575 = help: add #![feature(abi_amdgpu_kernel)] to the crate attributes to enable error[E0658]: intrinsics are subject to change @@ -150,12 +162,13 @@ LL | extern "rust-intrinsic" fn dm1() {} | = help: add #![feature(intrinsics)] to the crate attributes to enable -error[E0658]: platform intrinsics are experimental and possibly buggy (see issue #27731) +error[E0658]: platform intrinsics are experimental and possibly buggy --> $DIR/feature-gate-abi.rs:35:5 | LL | extern "platform-intrinsic" fn dm2() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/27731 = help: add #![feature(platform_intrinsics)] to the crate attributes to enable error[E0658]: vectorcall is experimental and subject to change @@ -166,36 +179,40 @@ LL | extern "vectorcall" fn dm3() {} | = help: add #![feature(abi_vectorcall)] to the crate attributes to enable -error[E0658]: rust-call ABI is subject to change (see issue #29625) +error[E0658]: rust-call ABI is subject to change --> $DIR/feature-gate-abi.rs:37:5 | LL | extern "rust-call" fn dm4() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add #![feature(unboxed_closures)] to the crate attributes to enable -error[E0658]: msp430-interrupt ABI is experimental and subject to change (see issue #38487) +error[E0658]: msp430-interrupt ABI is experimental and subject to change --> $DIR/feature-gate-abi.rs:38:5 | LL | extern "msp430-interrupt" fn dm5() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/38487 = help: add #![feature(abi_msp430_interrupt)] to the crate attributes to enable -error[E0658]: PTX ABIs are experimental and subject to change (see issue #38788) +error[E0658]: PTX ABIs are experimental and subject to change --> $DIR/feature-gate-abi.rs:39:5 | LL | extern "ptx-kernel" fn dm6() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/38788 = help: add #![feature(abi_ptx)] to the crate attributes to enable -error[E0658]: x86-interrupt ABI is experimental and subject to change (see issue #40180) +error[E0658]: x86-interrupt ABI is experimental and subject to change --> $DIR/feature-gate-abi.rs:40:5 | LL | extern "x86-interrupt" fn dm7() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/40180 = help: add #![feature(abi_x86_interrupt)] to the crate attributes to enable error[E0658]: thiscall is experimental and subject to change @@ -206,12 +223,13 @@ LL | extern "thiscall" fn dm8() {} | = help: add #![feature(abi_thiscall)] to the crate attributes to enable -error[E0658]: amdgpu-kernel ABI is experimental and subject to change (see issue #51575) +error[E0658]: amdgpu-kernel ABI is experimental and subject to change --> $DIR/feature-gate-abi.rs:42:5 | LL | extern "amdgpu-kernel" fn dm9() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/51575 = help: add #![feature(abi_amdgpu_kernel)] to the crate attributes to enable error[E0658]: intrinsics are subject to change @@ -222,12 +240,13 @@ LL | extern "rust-intrinsic" fn m1() {} | = help: add #![feature(intrinsics)] to the crate attributes to enable -error[E0658]: platform intrinsics are experimental and possibly buggy (see issue #27731) +error[E0658]: platform intrinsics are experimental and possibly buggy --> $DIR/feature-gate-abi.rs:50:5 | LL | extern "platform-intrinsic" fn m2() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/27731 = help: add #![feature(platform_intrinsics)] to the crate attributes to enable error[E0658]: vectorcall is experimental and subject to change @@ -238,36 +257,40 @@ LL | extern "vectorcall" fn m3() {} | = help: add #![feature(abi_vectorcall)] to the crate attributes to enable -error[E0658]: rust-call ABI is subject to change (see issue #29625) +error[E0658]: rust-call ABI is subject to change --> $DIR/feature-gate-abi.rs:52:5 | LL | extern "rust-call" fn m4() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add #![feature(unboxed_closures)] to the crate attributes to enable -error[E0658]: msp430-interrupt ABI is experimental and subject to change (see issue #38487) +error[E0658]: msp430-interrupt ABI is experimental and subject to change --> $DIR/feature-gate-abi.rs:53:5 | LL | extern "msp430-interrupt" fn m5() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/38487 = help: add #![feature(abi_msp430_interrupt)] to the crate attributes to enable -error[E0658]: PTX ABIs are experimental and subject to change (see issue #38788) +error[E0658]: PTX ABIs are experimental and subject to change --> $DIR/feature-gate-abi.rs:54:5 | LL | extern "ptx-kernel" fn m6() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/38788 = help: add #![feature(abi_ptx)] to the crate attributes to enable -error[E0658]: x86-interrupt ABI is experimental and subject to change (see issue #40180) +error[E0658]: x86-interrupt ABI is experimental and subject to change --> $DIR/feature-gate-abi.rs:55:5 | LL | extern "x86-interrupt" fn m7() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/40180 = help: add #![feature(abi_x86_interrupt)] to the crate attributes to enable error[E0658]: thiscall is experimental and subject to change @@ -278,12 +301,13 @@ LL | extern "thiscall" fn m8() {} | = help: add #![feature(abi_thiscall)] to the crate attributes to enable -error[E0658]: amdgpu-kernel ABI is experimental and subject to change (see issue #51575) +error[E0658]: amdgpu-kernel ABI is experimental and subject to change --> $DIR/feature-gate-abi.rs:57:5 | LL | extern "amdgpu-kernel" fn m9() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/51575 = help: add #![feature(abi_amdgpu_kernel)] to the crate attributes to enable error[E0658]: intrinsics are subject to change @@ -294,12 +318,13 @@ LL | extern "rust-intrinsic" fn im1() {} | = help: add #![feature(intrinsics)] to the crate attributes to enable -error[E0658]: platform intrinsics are experimental and possibly buggy (see issue #27731) +error[E0658]: platform intrinsics are experimental and possibly buggy --> $DIR/feature-gate-abi.rs:63:5 | LL | extern "platform-intrinsic" fn im2() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/27731 = help: add #![feature(platform_intrinsics)] to the crate attributes to enable error[E0658]: vectorcall is experimental and subject to change @@ -310,36 +335,40 @@ LL | extern "vectorcall" fn im3() {} | = help: add #![feature(abi_vectorcall)] to the crate attributes to enable -error[E0658]: rust-call ABI is subject to change (see issue #29625) +error[E0658]: rust-call ABI is subject to change --> $DIR/feature-gate-abi.rs:65:5 | LL | extern "rust-call" fn im4() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add #![feature(unboxed_closures)] to the crate attributes to enable -error[E0658]: msp430-interrupt ABI is experimental and subject to change (see issue #38487) +error[E0658]: msp430-interrupt ABI is experimental and subject to change --> $DIR/feature-gate-abi.rs:66:5 | LL | extern "msp430-interrupt" fn im5() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/38487 = help: add #![feature(abi_msp430_interrupt)] to the crate attributes to enable -error[E0658]: PTX ABIs are experimental and subject to change (see issue #38788) +error[E0658]: PTX ABIs are experimental and subject to change --> $DIR/feature-gate-abi.rs:67:5 | LL | extern "ptx-kernel" fn im6() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/38788 = help: add #![feature(abi_ptx)] to the crate attributes to enable -error[E0658]: x86-interrupt ABI is experimental and subject to change (see issue #40180) +error[E0658]: x86-interrupt ABI is experimental and subject to change --> $DIR/feature-gate-abi.rs:68:5 | LL | extern "x86-interrupt" fn im7() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/40180 = help: add #![feature(abi_x86_interrupt)] to the crate attributes to enable error[E0658]: thiscall is experimental and subject to change @@ -350,12 +379,13 @@ LL | extern "thiscall" fn im8() {} | = help: add #![feature(abi_thiscall)] to the crate attributes to enable -error[E0658]: amdgpu-kernel ABI is experimental and subject to change (see issue #51575) +error[E0658]: amdgpu-kernel ABI is experimental and subject to change --> $DIR/feature-gate-abi.rs:70:5 | LL | extern "amdgpu-kernel" fn im9() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/51575 = help: add #![feature(abi_amdgpu_kernel)] to the crate attributes to enable error[E0658]: intrinsics are subject to change @@ -366,12 +396,13 @@ LL | type A1 = extern "rust-intrinsic" fn(); | = help: add #![feature(intrinsics)] to the crate attributes to enable -error[E0658]: platform intrinsics are experimental and possibly buggy (see issue #27731) +error[E0658]: platform intrinsics are experimental and possibly buggy --> $DIR/feature-gate-abi.rs:75:11 | LL | type A2 = extern "platform-intrinsic" fn(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/27731 = help: add #![feature(platform_intrinsics)] to the crate attributes to enable error[E0658]: vectorcall is experimental and subject to change @@ -382,36 +413,40 @@ LL | type A3 = extern "vectorcall" fn(); | = help: add #![feature(abi_vectorcall)] to the crate attributes to enable -error[E0658]: rust-call ABI is subject to change (see issue #29625) +error[E0658]: rust-call ABI is subject to change --> $DIR/feature-gate-abi.rs:77:11 | LL | type A4 = extern "rust-call" fn(); | ^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add #![feature(unboxed_closures)] to the crate attributes to enable -error[E0658]: msp430-interrupt ABI is experimental and subject to change (see issue #38487) +error[E0658]: msp430-interrupt ABI is experimental and subject to change --> $DIR/feature-gate-abi.rs:78:11 | LL | type A5 = extern "msp430-interrupt" fn(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/38487 = help: add #![feature(abi_msp430_interrupt)] to the crate attributes to enable -error[E0658]: PTX ABIs are experimental and subject to change (see issue #38788) +error[E0658]: PTX ABIs are experimental and subject to change --> $DIR/feature-gate-abi.rs:79:11 | LL | type A6 = extern "ptx-kernel" fn (); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/38788 = help: add #![feature(abi_ptx)] to the crate attributes to enable -error[E0658]: x86-interrupt ABI is experimental and subject to change (see issue #40180) +error[E0658]: x86-interrupt ABI is experimental and subject to change --> $DIR/feature-gate-abi.rs:80:11 | LL | type A7 = extern "x86-interrupt" fn(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/40180 = help: add #![feature(abi_x86_interrupt)] to the crate attributes to enable error[E0658]: thiscall is experimental and subject to change @@ -422,12 +457,13 @@ LL | type A8 = extern "thiscall" fn(); | = help: add #![feature(abi_thiscall)] to the crate attributes to enable -error[E0658]: amdgpu-kernel ABI is experimental and subject to change (see issue #51575) +error[E0658]: amdgpu-kernel ABI is experimental and subject to change --> $DIR/feature-gate-abi.rs:82:11 | LL | type A9 = extern "amdgpu-kernel" fn(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/51575 = help: add #![feature(abi_amdgpu_kernel)] to the crate attributes to enable error[E0658]: intrinsics are subject to change @@ -438,12 +474,13 @@ LL | extern "rust-intrinsic" {} | = help: add #![feature(intrinsics)] to the crate attributes to enable -error[E0658]: platform intrinsics are experimental and possibly buggy (see issue #27731) +error[E0658]: platform intrinsics are experimental and possibly buggy --> $DIR/feature-gate-abi.rs:86:1 | LL | extern "platform-intrinsic" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/27731 = help: add #![feature(platform_intrinsics)] to the crate attributes to enable error[E0658]: vectorcall is experimental and subject to change @@ -454,36 +491,40 @@ LL | extern "vectorcall" {} | = help: add #![feature(abi_vectorcall)] to the crate attributes to enable -error[E0658]: rust-call ABI is subject to change (see issue #29625) +error[E0658]: rust-call ABI is subject to change --> $DIR/feature-gate-abi.rs:88:1 | LL | extern "rust-call" {} | ^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add #![feature(unboxed_closures)] to the crate attributes to enable -error[E0658]: msp430-interrupt ABI is experimental and subject to change (see issue #38487) +error[E0658]: msp430-interrupt ABI is experimental and subject to change --> $DIR/feature-gate-abi.rs:89:1 | LL | extern "msp430-interrupt" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/38487 = help: add #![feature(abi_msp430_interrupt)] to the crate attributes to enable -error[E0658]: PTX ABIs are experimental and subject to change (see issue #38788) +error[E0658]: PTX ABIs are experimental and subject to change --> $DIR/feature-gate-abi.rs:90:1 | LL | extern "ptx-kernel" {} | ^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/38788 = help: add #![feature(abi_ptx)] to the crate attributes to enable -error[E0658]: x86-interrupt ABI is experimental and subject to change (see issue #40180) +error[E0658]: x86-interrupt ABI is experimental and subject to change --> $DIR/feature-gate-abi.rs:91:1 | LL | extern "x86-interrupt" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/40180 = help: add #![feature(abi_x86_interrupt)] to the crate attributes to enable error[E0658]: thiscall is experimental and subject to change @@ -494,12 +535,13 @@ LL | extern "thiscall" {} | = help: add #![feature(abi_thiscall)] to the crate attributes to enable -error[E0658]: amdgpu-kernel ABI is experimental and subject to change (see issue #51575) +error[E0658]: amdgpu-kernel ABI is experimental and subject to change --> $DIR/feature-gate-abi.rs:93:1 | LL | extern "amdgpu-kernel" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/51575 = help: add #![feature(abi_amdgpu_kernel)] to the crate attributes to enable error: aborting due to 63 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-alloc-error-handler.rs b/src/test/ui/feature-gates/feature-gate-alloc-error-handler.rs index daa2bb5d6fa..df7c3ad6b3d 100644 --- a/src/test/ui/feature-gates/feature-gate-alloc-error-handler.rs +++ b/src/test/ui/feature-gates/feature-gate-alloc-error-handler.rs @@ -5,7 +5,7 @@ use core::alloc::Layout; -#[alloc_error_handler] //~ ERROR #[alloc_error_handler] is an unstable feature (see issue #51540) +#[alloc_error_handler] //~ ERROR #[alloc_error_handler] is an unstable feature fn oom(info: Layout) -> ! { loop {} } diff --git a/src/test/ui/feature-gates/feature-gate-alloc-error-handler.stderr b/src/test/ui/feature-gates/feature-gate-alloc-error-handler.stderr index 5e64ac50c3c..cb01b5caf85 100644 --- a/src/test/ui/feature-gates/feature-gate-alloc-error-handler.stderr +++ b/src/test/ui/feature-gates/feature-gate-alloc-error-handler.stderr @@ -1,9 +1,10 @@ -error[E0658]: #[alloc_error_handler] is an unstable feature (see issue #51540) +error[E0658]: #[alloc_error_handler] is an unstable feature --> $DIR/feature-gate-alloc-error-handler.rs:8:1 | LL | #[alloc_error_handler] | ^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/51540 = help: add #![feature(alloc_error_handler)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-allow_fail.stderr b/src/test/ui/feature-gates/feature-gate-allow_fail.stderr index 5de1706dd4a..af7c8de61d5 100644 --- a/src/test/ui/feature-gates/feature-gate-allow_fail.stderr +++ b/src/test/ui/feature-gates/feature-gate-allow_fail.stderr @@ -1,9 +1,10 @@ -error[E0658]: allow_fail attribute is currently unstable (see issue #46488) +error[E0658]: allow_fail attribute is currently unstable --> $DIR/feature-gate-allow_fail.rs:3:1 | LL | #[allow_fail] | ^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/46488 = help: add #![feature(allow_fail)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-arbitrary-self-types.stderr b/src/test/ui/feature-gates/feature-gate-arbitrary-self-types.stderr index e1089bc345e..8d061a95676 100644 --- a/src/test/ui/feature-gates/feature-gate-arbitrary-self-types.stderr +++ b/src/test/ui/feature-gates/feature-gate-arbitrary-self-types.stderr @@ -1,27 +1,30 @@ -error[E0658]: `Ptr<Self>` cannot be used as the type of `self` without the `arbitrary_self_types` feature (see issue #44874) +error[E0658]: `Ptr<Self>` cannot be used as the type of `self` without the `arbitrary_self_types` feature --> $DIR/feature-gate-arbitrary-self-types.rs:16:18 | LL | fn foo(self: Ptr<Self>); | ^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/44874 = help: add #![feature(arbitrary_self_types)] to the crate attributes to enable = help: consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>` -error[E0658]: `Ptr<Bar>` cannot be used as the type of `self` without the `arbitrary_self_types` feature (see issue #44874) +error[E0658]: `Ptr<Bar>` cannot be used as the type of `self` without the `arbitrary_self_types` feature --> $DIR/feature-gate-arbitrary-self-types.rs:22:18 | LL | fn foo(self: Ptr<Self>) {} | ^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/44874 = help: add #![feature(arbitrary_self_types)] to the crate attributes to enable = help: consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>` -error[E0658]: `std::boxed::Box<Ptr<Bar>>` cannot be used as the type of `self` without the `arbitrary_self_types` feature (see issue #44874) +error[E0658]: `std::boxed::Box<Ptr<Bar>>` cannot be used as the type of `self` without the `arbitrary_self_types` feature --> $DIR/feature-gate-arbitrary-self-types.rs:26:18 | LL | fn bar(self: Box<Ptr<Self>>) {} | ^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/44874 = help: add #![feature(arbitrary_self_types)] to the crate attributes to enable = help: consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>` diff --git a/src/test/ui/feature-gates/feature-gate-arbitrary_self_types-raw-pointer.stderr b/src/test/ui/feature-gates/feature-gate-arbitrary_self_types-raw-pointer.stderr index f35438f42f4..eda2403e057 100644 --- a/src/test/ui/feature-gates/feature-gate-arbitrary_self_types-raw-pointer.stderr +++ b/src/test/ui/feature-gates/feature-gate-arbitrary_self_types-raw-pointer.stderr @@ -1,27 +1,30 @@ -error[E0658]: `*const Self` cannot be used as the type of `self` without the `arbitrary_self_types` feature (see issue #44874) +error[E0658]: `*const Self` cannot be used as the type of `self` without the `arbitrary_self_types` feature --> $DIR/feature-gate-arbitrary_self_types-raw-pointer.rs:9:18 | LL | fn bar(self: *const Self); | ^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/44874 = help: add #![feature(arbitrary_self_types)] to the crate attributes to enable = help: consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>` -error[E0658]: `*const Foo` cannot be used as the type of `self` without the `arbitrary_self_types` feature (see issue #44874) +error[E0658]: `*const Foo` cannot be used as the type of `self` without the `arbitrary_self_types` feature --> $DIR/feature-gate-arbitrary_self_types-raw-pointer.rs:4:18 | LL | fn foo(self: *const Self) {} | ^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/44874 = help: add #![feature(arbitrary_self_types)] to the crate attributes to enable = help: consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>` -error[E0658]: `*const ()` cannot be used as the type of `self` without the `arbitrary_self_types` feature (see issue #44874) +error[E0658]: `*const ()` cannot be used as the type of `self` without the `arbitrary_self_types` feature --> $DIR/feature-gate-arbitrary_self_types-raw-pointer.rs:14:18 | LL | fn bar(self: *const Self) {} | ^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/44874 = help: add #![feature(arbitrary_self_types)] to the crate attributes to enable = help: consider changing to `self`, `&self`, `&mut self`, or `self: Box<Self>` diff --git a/src/test/ui/feature-gates/feature-gate-asm.stderr b/src/test/ui/feature-gates/feature-gate-asm.stderr index 6ad0ea67313..ccaf34f0169 100644 --- a/src/test/ui/feature-gates/feature-gate-asm.stderr +++ b/src/test/ui/feature-gates/feature-gate-asm.stderr @@ -1,9 +1,10 @@ -error[E0658]: inline assembly is not stable enough for use and is subject to change (see issue #29722) +error[E0658]: inline assembly is not stable enough for use and is subject to change --> $DIR/feature-gate-asm.rs:3:9 | LL | asm!(""); | ^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29722 = help: add #![feature(asm)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-asm2.stderr b/src/test/ui/feature-gates/feature-gate-asm2.stderr index 466f2028198..cafe2be9d0b 100644 --- a/src/test/ui/feature-gates/feature-gate-asm2.stderr +++ b/src/test/ui/feature-gates/feature-gate-asm2.stderr @@ -1,9 +1,10 @@ -error[E0658]: inline assembly is not stable enough for use and is subject to change (see issue #29722) +error[E0658]: inline assembly is not stable enough for use and is subject to change --> $DIR/feature-gate-asm2.rs:5:26 | LL | println!("{:?}", asm!("")); | ^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29722 = help: add #![feature(asm)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-assoc-type-defaults.stderr b/src/test/ui/feature-gates/feature-gate-assoc-type-defaults.stderr index fe206d3dfca..16b37cf29ca 100644 --- a/src/test/ui/feature-gates/feature-gate-assoc-type-defaults.stderr +++ b/src/test/ui/feature-gates/feature-gate-assoc-type-defaults.stderr @@ -1,9 +1,10 @@ -error[E0658]: associated type defaults are unstable (see issue #29661) +error[E0658]: associated type defaults are unstable --> $DIR/feature-gate-assoc-type-defaults.rs:4:5 | LL | type Bar = u8; | ^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29661 = help: add #![feature(associated_type_defaults)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-async-await-2015-edition.stderr b/src/test/ui/feature-gates/feature-gate-async-await-2015-edition.stderr index b67949b6155..77dc6a486a1 100644 --- a/src/test/ui/feature-gates/feature-gate-async-await-2015-edition.stderr +++ b/src/test/ui/feature-gates/feature-gate-async-await-2015-edition.stderr @@ -16,12 +16,13 @@ error[E0425]: cannot find value `async` in this scope LL | let _ = async || { true }; | ^^^^^ not found in this scope -error[E0658]: async fn is unstable (see issue #50547) +error[E0658]: async fn is unstable --> $DIR/feature-gate-async-await-2015-edition.rs:5:1 | LL | async fn foo() {} | ^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/50547 = help: add #![feature(async_await)] to the crate attributes to enable error: aborting due to 4 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-async-await.stderr b/src/test/ui/feature-gates/feature-gate-async-await.stderr index beec28765c8..6bff254607f 100644 --- a/src/test/ui/feature-gates/feature-gate-async-await.stderr +++ b/src/test/ui/feature-gates/feature-gate-async-await.stderr @@ -1,25 +1,28 @@ -error[E0658]: async fn is unstable (see issue #50547) +error[E0658]: async fn is unstable --> $DIR/feature-gate-async-await.rs:5:1 | LL | async fn foo() {} | ^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/50547 = help: add #![feature(async_await)] to the crate attributes to enable -error[E0658]: async blocks are unstable (see issue #50547) +error[E0658]: async blocks are unstable --> $DIR/feature-gate-async-await.rs:8:13 | LL | let _ = async {}; | ^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/50547 = help: add #![feature(async_await)] to the crate attributes to enable -error[E0658]: async closures are unstable (see issue #50547) +error[E0658]: async closures are unstable --> $DIR/feature-gate-async-await.rs:9:13 | LL | let _ = async || {}; | ^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/50547 = help: add #![feature(async_await)] to the crate attributes to enable error: aborting due to 3 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-box-expr.stderr b/src/test/ui/feature-gates/feature-gate-box-expr.stderr index 7b202042878..9666793313e 100644 --- a/src/test/ui/feature-gates/feature-gate-box-expr.stderr +++ b/src/test/ui/feature-gates/feature-gate-box-expr.stderr @@ -1,9 +1,10 @@ -error[E0658]: box expression syntax is experimental; you can call `Box::new` instead. (see issue #49733) +error[E0658]: box expression syntax is experimental; you can call `Box::new` instead --> $DIR/feature-gate-box-expr.rs:12:13 | LL | let x = box 'c'; | ^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/49733 = help: add #![feature(box_syntax)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-box_patterns.stderr b/src/test/ui/feature-gates/feature-gate-box_patterns.stderr index 39404aa39c8..765b929de8a 100644 --- a/src/test/ui/feature-gates/feature-gate-box_patterns.stderr +++ b/src/test/ui/feature-gates/feature-gate-box_patterns.stderr @@ -1,9 +1,10 @@ -error[E0658]: box pattern syntax is experimental (see issue #29641) +error[E0658]: box pattern syntax is experimental --> $DIR/feature-gate-box_patterns.rs:2:9 | LL | let box x = Box::new('c'); | ^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29641 = help: add #![feature(box_patterns)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-box_syntax.rs b/src/test/ui/feature-gates/feature-gate-box_syntax.rs index df0c604b2a8..778660cc0b5 100644 --- a/src/test/ui/feature-gates/feature-gate-box_syntax.rs +++ b/src/test/ui/feature-gates/feature-gate-box_syntax.rs @@ -2,5 +2,5 @@ fn main() { let x = box 3; - //~^ ERROR box expression syntax is experimental; you can call `Box::new` instead. + //~^ ERROR box expression syntax is experimental; you can call `Box::new` instead } diff --git a/src/test/ui/feature-gates/feature-gate-box_syntax.stderr b/src/test/ui/feature-gates/feature-gate-box_syntax.stderr index f144d11d89b..a9cac7686ea 100644 --- a/src/test/ui/feature-gates/feature-gate-box_syntax.stderr +++ b/src/test/ui/feature-gates/feature-gate-box_syntax.stderr @@ -1,9 +1,10 @@ -error[E0658]: box expression syntax is experimental; you can call `Box::new` instead. (see issue #49733) +error[E0658]: box expression syntax is experimental; you can call `Box::new` instead --> $DIR/feature-gate-box_syntax.rs:4:13 | LL | let x = box 3; | ^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/49733 = help: add #![feature(box_syntax)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.rs b/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.rs index db1a7dad06b..827ac3af8f1 100644 --- a/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.rs +++ b/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.rs @@ -13,78 +13,78 @@ trait Sized {} trait Copy {} #[cfg(target_has_atomic = "8")] -//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change pub unsafe fn atomic_u8(x: *mut u8) { atomic_xadd(x, 1); atomic_xadd(x, 1); } #[cfg(target_has_atomic = "8")] -//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change pub unsafe fn atomic_i8(x: *mut i8) { atomic_xadd(x, 1); } #[cfg(target_has_atomic = "16")] -//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change pub unsafe fn atomic_u16(x: *mut u16) { atomic_xadd(x, 1); } #[cfg(target_has_atomic = "16")] -//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change pub unsafe fn atomic_i16(x: *mut i16) { atomic_xadd(x, 1); } #[cfg(target_has_atomic = "32")] -//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change pub unsafe fn atomic_u32(x: *mut u32) { atomic_xadd(x, 1); } #[cfg(target_has_atomic = "32")] -//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change pub unsafe fn atomic_i32(x: *mut i32) { atomic_xadd(x, 1); } #[cfg(target_has_atomic = "64")] -//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change pub unsafe fn atomic_u64(x: *mut u64) { atomic_xadd(x, 1); } #[cfg(target_has_atomic = "64")] -//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change pub unsafe fn atomic_i64(x: *mut i64) { atomic_xadd(x, 1); } #[cfg(target_has_atomic = "128")] -//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change pub unsafe fn atomic_u128(x: *mut u128) { atomic_xadd(x, 1); } #[cfg(target_has_atomic = "128")] -//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change pub unsafe fn atomic_i128(x: *mut i128) { atomic_xadd(x, 1); } #[cfg(target_has_atomic = "ptr")] -//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change pub unsafe fn atomic_usize(x: *mut usize) { atomic_xadd(x, 1); } #[cfg(target_has_atomic = "ptr")] -//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change pub unsafe fn atomic_isize(x: *mut isize) { atomic_xadd(x, 1); } fn main() { cfg!(target_has_atomic = "8"); - //~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) + //~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change cfg!(target_has_atomic = "16"); - //~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) + //~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change cfg!(target_has_atomic = "32"); - //~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) + //~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change cfg!(target_has_atomic = "64"); - //~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) + //~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change cfg!(target_has_atomic = "128"); - //~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) + //~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change cfg!(target_has_atomic = "ptr"); - //~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) + //~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change } diff --git a/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.stderr b/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.stderr index a2d5669bcdc..995528efdd3 100644 --- a/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.stderr +++ b/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.stderr @@ -1,145 +1,163 @@ -error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change --> $DIR/feature-gate-cfg-target-has-atomic.rs:15:7 | LL | #[cfg(target_has_atomic = "8")] | ^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/32976 = help: add #![feature(cfg_target_has_atomic)] to the crate attributes to enable -error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change --> $DIR/feature-gate-cfg-target-has-atomic.rs:21:7 | LL | #[cfg(target_has_atomic = "8")] | ^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/32976 = help: add #![feature(cfg_target_has_atomic)] to the crate attributes to enable -error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change --> $DIR/feature-gate-cfg-target-has-atomic.rs:26:7 | LL | #[cfg(target_has_atomic = "16")] | ^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/32976 = help: add #![feature(cfg_target_has_atomic)] to the crate attributes to enable -error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change --> $DIR/feature-gate-cfg-target-has-atomic.rs:31:7 | LL | #[cfg(target_has_atomic = "16")] | ^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/32976 = help: add #![feature(cfg_target_has_atomic)] to the crate attributes to enable -error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change --> $DIR/feature-gate-cfg-target-has-atomic.rs:36:7 | LL | #[cfg(target_has_atomic = "32")] | ^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/32976 = help: add #![feature(cfg_target_has_atomic)] to the crate attributes to enable -error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change --> $DIR/feature-gate-cfg-target-has-atomic.rs:41:7 | LL | #[cfg(target_has_atomic = "32")] | ^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/32976 = help: add #![feature(cfg_target_has_atomic)] to the crate attributes to enable -error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change --> $DIR/feature-gate-cfg-target-has-atomic.rs:46:7 | LL | #[cfg(target_has_atomic = "64")] | ^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/32976 = help: add #![feature(cfg_target_has_atomic)] to the crate attributes to enable -error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change --> $DIR/feature-gate-cfg-target-has-atomic.rs:51:7 | LL | #[cfg(target_has_atomic = "64")] | ^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/32976 = help: add #![feature(cfg_target_has_atomic)] to the crate attributes to enable -error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change --> $DIR/feature-gate-cfg-target-has-atomic.rs:56:7 | LL | #[cfg(target_has_atomic = "128")] | ^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/32976 = help: add #![feature(cfg_target_has_atomic)] to the crate attributes to enable -error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change --> $DIR/feature-gate-cfg-target-has-atomic.rs:61:7 | LL | #[cfg(target_has_atomic = "128")] | ^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/32976 = help: add #![feature(cfg_target_has_atomic)] to the crate attributes to enable -error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change --> $DIR/feature-gate-cfg-target-has-atomic.rs:66:7 | LL | #[cfg(target_has_atomic = "ptr")] | ^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/32976 = help: add #![feature(cfg_target_has_atomic)] to the crate attributes to enable -error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change --> $DIR/feature-gate-cfg-target-has-atomic.rs:71:7 | LL | #[cfg(target_has_atomic = "ptr")] | ^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/32976 = help: add #![feature(cfg_target_has_atomic)] to the crate attributes to enable -error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change --> $DIR/feature-gate-cfg-target-has-atomic.rs:78:10 | LL | cfg!(target_has_atomic = "8"); | ^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/32976 = help: add #![feature(cfg_target_has_atomic)] to the crate attributes to enable -error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change --> $DIR/feature-gate-cfg-target-has-atomic.rs:80:10 | LL | cfg!(target_has_atomic = "16"); | ^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/32976 = help: add #![feature(cfg_target_has_atomic)] to the crate attributes to enable -error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change --> $DIR/feature-gate-cfg-target-has-atomic.rs:82:10 | LL | cfg!(target_has_atomic = "32"); | ^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/32976 = help: add #![feature(cfg_target_has_atomic)] to the crate attributes to enable -error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change --> $DIR/feature-gate-cfg-target-has-atomic.rs:84:10 | LL | cfg!(target_has_atomic = "64"); | ^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/32976 = help: add #![feature(cfg_target_has_atomic)] to the crate attributes to enable -error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change --> $DIR/feature-gate-cfg-target-has-atomic.rs:86:10 | LL | cfg!(target_has_atomic = "128"); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/32976 = help: add #![feature(cfg_target_has_atomic)] to the crate attributes to enable -error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change (see issue #32976) +error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change --> $DIR/feature-gate-cfg-target-has-atomic.rs:88:10 | LL | cfg!(target_has_atomic = "ptr"); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/32976 = help: add #![feature(cfg_target_has_atomic)] to the crate attributes to enable error: aborting due to 18 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-cfg-target-thread-local.rs b/src/test/ui/feature-gates/feature-gate-cfg-target-thread-local.rs index 54db7500583..d44f78d4fab 100644 --- a/src/test/ui/feature-gates/feature-gate-cfg-target-thread-local.rs +++ b/src/test/ui/feature-gates/feature-gate-cfg-target-thread-local.rs @@ -7,7 +7,7 @@ extern crate cfg_target_thread_local; extern { #[cfg_attr(target_thread_local, thread_local)] - //~^ `cfg(target_thread_local)` is experimental and subject to change (see issue #29594) + //~^ `cfg(target_thread_local)` is experimental and subject to change static FOO: u32; } diff --git a/src/test/ui/feature-gates/feature-gate-cfg-target-thread-local.stderr b/src/test/ui/feature-gates/feature-gate-cfg-target-thread-local.stderr index 672fb14871a..3d24b218253 100644 --- a/src/test/ui/feature-gates/feature-gate-cfg-target-thread-local.stderr +++ b/src/test/ui/feature-gates/feature-gate-cfg-target-thread-local.stderr @@ -1,9 +1,10 @@ -error[E0658]: `cfg(target_thread_local)` is experimental and subject to change (see issue #29594) +error[E0658]: `cfg(target_thread_local)` is experimental and subject to change --> $DIR/feature-gate-cfg-target-thread-local.rs:9:16 | LL | #[cfg_attr(target_thread_local, thread_local)] | ^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29594 = help: add #![feature(cfg_target_thread_local)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-concat_idents.stderr b/src/test/ui/feature-gates/feature-gate-concat_idents.stderr index 3f4ce6d3b94..be8c727e2be 100644 --- a/src/test/ui/feature-gates/feature-gate-concat_idents.stderr +++ b/src/test/ui/feature-gates/feature-gate-concat_idents.stderr @@ -1,17 +1,19 @@ -error[E0658]: `concat_idents` is not stable enough for use and is subject to change (see issue #29599) +error[E0658]: `concat_idents` is not stable enough for use and is subject to change --> $DIR/feature-gate-concat_idents.rs:5:13 | LL | let a = concat_idents!(X, Y_1); | ^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29599 = help: add #![feature(concat_idents)] to the crate attributes to enable -error[E0658]: `concat_idents` is not stable enough for use and is subject to change (see issue #29599) +error[E0658]: `concat_idents` is not stable enough for use and is subject to change --> $DIR/feature-gate-concat_idents.rs:6:13 | LL | let b = concat_idents!(X, Y_2); | ^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29599 = help: add #![feature(concat_idents)] to the crate attributes to enable error: aborting due to 2 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-concat_idents2.stderr b/src/test/ui/feature-gates/feature-gate-concat_idents2.stderr index 105b3d5cff5..1ef45115bd1 100644 --- a/src/test/ui/feature-gates/feature-gate-concat_idents2.stderr +++ b/src/test/ui/feature-gates/feature-gate-concat_idents2.stderr @@ -1,9 +1,10 @@ -error[E0658]: `concat_idents` is not stable enough for use and is subject to change (see issue #29599) +error[E0658]: `concat_idents` is not stable enough for use and is subject to change --> $DIR/feature-gate-concat_idents2.rs:4:5 | LL | concat_idents!(a, b); | ^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29599 = help: add #![feature(concat_idents)] to the crate attributes to enable error[E0425]: cannot find value `ab` in this scope diff --git a/src/test/ui/feature-gates/feature-gate-concat_idents3.stderr b/src/test/ui/feature-gates/feature-gate-concat_idents3.stderr index 9568b1d8801..cb8725ab566 100644 --- a/src/test/ui/feature-gates/feature-gate-concat_idents3.stderr +++ b/src/test/ui/feature-gates/feature-gate-concat_idents3.stderr @@ -1,17 +1,19 @@ -error[E0658]: `concat_idents` is not stable enough for use and is subject to change (see issue #29599) +error[E0658]: `concat_idents` is not stable enough for use and is subject to change --> $DIR/feature-gate-concat_idents3.rs:7:20 | LL | assert_eq!(10, concat_idents!(X, Y_1)); | ^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29599 = help: add #![feature(concat_idents)] to the crate attributes to enable -error[E0658]: `concat_idents` is not stable enough for use and is subject to change (see issue #29599) +error[E0658]: `concat_idents` is not stable enough for use and is subject to change --> $DIR/feature-gate-concat_idents3.rs:8:20 | LL | assert_eq!(20, concat_idents!(X, Y_2)); | ^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29599 = help: add #![feature(concat_idents)] to the crate attributes to enable error: aborting due to 2 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-const_fn.stderr b/src/test/ui/feature-gates/feature-gate-const_fn.stderr index 7f88d30acc6..0edd4eb7ab0 100644 --- a/src/test/ui/feature-gates/feature-gate-const_fn.stderr +++ b/src/test/ui/feature-gates/feature-gate-const_fn.stderr @@ -16,20 +16,22 @@ error[E0379]: trait fns cannot be declared const LL | const fn foo() -> u32 { 0 } | ^^^^^ trait fns cannot be const -error[E0658]: const fn is unstable (see issue #57563) +error[E0658]: const fn is unstable --> $DIR/feature-gate-const_fn.rs:6:5 | LL | const fn foo() -> u32; | ^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0658]: const fn is unstable (see issue #57563) +error[E0658]: const fn is unstable --> $DIR/feature-gate-const_fn.rs:8:5 | LL | const fn bar() -> u32 { 0 } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable error: aborting due to 5 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-const_generics.stderr b/src/test/ui/feature-gates/feature-gate-const_generics.stderr index dce40002535..9ea04a1e204 100644 --- a/src/test/ui/feature-gates/feature-gate-const_generics.stderr +++ b/src/test/ui/feature-gates/feature-gate-const_generics.stderr @@ -1,17 +1,19 @@ -error[E0658]: const generics are unstable (see issue #44580) +error[E0658]: const generics are unstable --> $DIR/feature-gate-const_generics.rs:1:14 | LL | fn foo<const X: ()>() {} | ^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/44580 = help: add #![feature(const_generics)] to the crate attributes to enable -error[E0658]: const generics are unstable (see issue #44580) +error[E0658]: const generics are unstable --> $DIR/feature-gate-const_generics.rs:3:18 | LL | struct Foo<const X: usize>([(); X]); | ^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/44580 = help: add #![feature(const_generics)] to the crate attributes to enable error: aborting due to 2 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-const_transmute.rs b/src/test/ui/feature-gates/feature-gate-const_transmute.rs index 3c4e6de0b1e..6a5bbec77fd 100644 --- a/src/test/ui/feature-gates/feature-gate-const_transmute.rs +++ b/src/test/ui/feature-gates/feature-gate-const_transmute.rs @@ -4,6 +4,6 @@ use std::mem; struct Foo(u32); const TRANSMUTED_U32: u32 = unsafe { mem::transmute(Foo(3)) }; -//~^ ERROR The use of std::mem::transmute() is gated in constants (see issue #53605) +//~^ ERROR The use of std::mem::transmute() is gated in constants fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-const_transmute.stderr b/src/test/ui/feature-gates/feature-gate-const_transmute.stderr index 2e07a9e7ddb..c3cd3131342 100644 --- a/src/test/ui/feature-gates/feature-gate-const_transmute.stderr +++ b/src/test/ui/feature-gates/feature-gate-const_transmute.stderr @@ -1,9 +1,10 @@ -error[E0658]: The use of std::mem::transmute() is gated in constants (see issue #53605) +error[E0658]: The use of std::mem::transmute() is gated in constants --> $DIR/feature-gate-const_transmute.rs:6:38 | LL | const TRANSMUTED_U32: u32 = unsafe { mem::transmute(Foo(3)) }; | ^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/53605 = help: add #![feature(const_transmute)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-crate_visibility_modifier.stderr b/src/test/ui/feature-gates/feature-gate-crate_visibility_modifier.stderr index 25b26de60ef..4e70870ae72 100644 --- a/src/test/ui/feature-gates/feature-gate-crate_visibility_modifier.stderr +++ b/src/test/ui/feature-gates/feature-gate-crate_visibility_modifier.stderr @@ -1,9 +1,10 @@ -error[E0658]: `crate` visibility modifier is experimental (see issue #53120) +error[E0658]: `crate` visibility modifier is experimental --> $DIR/feature-gate-crate_visibility_modifier.rs:1:1 | LL | crate struct Bender { | ^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/53120 = help: add #![feature(crate_visibility_modifier)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-custom_attribute.stderr b/src/test/ui/feature-gates/feature-gate-custom_attribute.stderr index 8b79c752e45..9b81c38f86b 100644 --- a/src/test/ui/feature-gates/feature-gate-custom_attribute.stderr +++ b/src/test/ui/feature-gates/feature-gate-custom_attribute.stderr @@ -1,105 +1,118 @@ -error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute.rs:7:3 | LL | #[fake_attr] | ^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute.rs:8:3 | LL | #[fake_attr(100)] | ^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute.rs:9:3 | LL | #[fake_attr(1, 2, 3)] | ^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute.rs:10:3 | LL | #[fake_attr("hello")] | ^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute.rs:11:3 | LL | #[fake_attr(name = "hello")] | ^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute.rs:12:3 | LL | #[fake_attr(1, "hi", key = 12, true, false)] | ^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute.rs:13:3 | LL | #[fake_attr(key = "hello", val = 10)] | ^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute.rs:14:3 | LL | #[fake_attr(key("hello"), val(10))] | ^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute.rs:15:3 | LL | #[fake_attr(enabled = true, disabled = false)] | ^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute.rs:16:3 | LL | #[fake_attr(true)] | ^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute.rs:17:3 | LL | #[fake_attr(pi = 3.14159)] | ^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `fake_attr` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute.rs:18:3 | LL | #[fake_attr(b"hi")] | ^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `fake_doc` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `fake_doc` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute.rs:19:3 | LL | #[fake_doc(r"doc")] | ^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable error: aborting due to 13 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-custom_attribute2.stderr b/src/test/ui/feature-gates/feature-gate-custom_attribute2.stderr index 560ceda3486..8c8ac1233a0 100644 --- a/src/test/ui/feature-gates/feature-gate-custom_attribute2.stderr +++ b/src/test/ui/feature-gates/feature-gate-custom_attribute2.stderr @@ -1,137 +1,154 @@ -error[E0658]: The attribute `lt_struct` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `lt_struct` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute2.rs:6:13 | LL | struct StLt<#[lt_struct] 'a>(&'a u32); | ^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `ty_struct` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `ty_struct` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute2.rs:8:13 | LL | struct StTy<#[ty_struct] I>(I); | ^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `lt_enum` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `lt_enum` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute2.rs:11:11 | LL | enum EnLt<#[lt_enum] 'b> { A(&'b u32), B } | ^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `ty_enum` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `ty_enum` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute2.rs:13:11 | LL | enum EnTy<#[ty_enum] J> { A(J), B } | ^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `lt_trait` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `lt_trait` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute2.rs:16:12 | LL | trait TrLt<#[lt_trait] 'c> { fn foo(&self, _: &'c [u32]) -> &'c u32; } | ^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `ty_trait` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `ty_trait` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute2.rs:18:12 | LL | trait TrTy<#[ty_trait] K> { fn foo(&self, _: K); } | ^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `lt_type` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `lt_type` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute2.rs:21:11 | LL | type TyLt<#[lt_type] 'd> = &'d u32; | ^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `ty_type` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `ty_type` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute2.rs:23:11 | LL | type TyTy<#[ty_type] L> = (L, ); | ^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `lt_inherent` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `lt_inherent` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute2.rs:26:6 | LL | impl<#[lt_inherent] 'e> StLt<'e> { } | ^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `ty_inherent` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `ty_inherent` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute2.rs:28:6 | LL | impl<#[ty_inherent] M> StTy<M> { } | ^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `lt_impl_for` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `lt_impl_for` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute2.rs:31:6 | LL | impl<#[lt_impl_for] 'f> TrLt<'f> for StLt<'f> { | ^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `ty_impl_for` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `ty_impl_for` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute2.rs:35:6 | LL | impl<#[ty_impl_for] N> TrTy<N> for StTy<N> { | ^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `lt_fn` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `lt_fn` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute2.rs:40:9 | LL | fn f_lt<#[lt_fn] 'g>(_: &'g [u32]) -> &'g u32 { loop { } } | ^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `ty_fn` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `ty_fn` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute2.rs:42:9 | LL | fn f_ty<#[ty_fn] O>(_: O) { } | ^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `lt_meth` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `lt_meth` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute2.rs:46:13 | LL | fn m_lt<#[lt_meth] 'h>(_: &'h [u32]) -> &'h u32 { loop { } } | ^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `ty_meth` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `ty_meth` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute2.rs:48:13 | LL | fn m_ty<#[ty_meth] P>(_: P) { } | ^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `lt_hof` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `lt_hof` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/feature-gate-custom_attribute2.rs:53:19 | LL | where Q: for <#[lt_hof] 'i> Fn(&'i [u32]) -> &'i u32 | ^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable error: aborting due to 17 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-custom_test_frameworks.stderr b/src/test/ui/feature-gates/feature-gate-custom_test_frameworks.stderr index bac23b3a60d..e288af54cb2 100644 --- a/src/test/ui/feature-gates/feature-gate-custom_test_frameworks.stderr +++ b/src/test/ui/feature-gates/feature-gate-custom_test_frameworks.stderr @@ -1,9 +1,10 @@ -error[E0658]: custom test frameworks are an unstable feature (see issue #50297) +error[E0658]: custom test frameworks are an unstable feature --> $DIR/feature-gate-custom_test_frameworks.rs:1:1 | LL | #![test_runner(main)] | ^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/50297 = help: add #![feature(custom_test_frameworks)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-decl_macro.rs b/src/test/ui/feature-gates/feature-gate-decl_macro.rs index ca0dafd0bf7..d002c5dbbd2 100644 --- a/src/test/ui/feature-gates/feature-gate-decl_macro.rs +++ b/src/test/ui/feature-gates/feature-gate-decl_macro.rs @@ -1,5 +1,5 @@ #![allow(unused_macros)] -macro m() {} //~ ERROR `macro` is experimental (see issue #39412) +macro m() {} //~ ERROR `macro` is experimental fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-decl_macro.stderr b/src/test/ui/feature-gates/feature-gate-decl_macro.stderr index 2d4b622843d..808363a0048 100644 --- a/src/test/ui/feature-gates/feature-gate-decl_macro.stderr +++ b/src/test/ui/feature-gates/feature-gate-decl_macro.stderr @@ -1,9 +1,10 @@ -error[E0658]: `macro` is experimental (see issue #39412) +error[E0658]: `macro` is experimental --> $DIR/feature-gate-decl_macro.rs:3:1 | LL | macro m() {} | ^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/39412 = help: add #![feature(decl_macro)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-doc_alias.stderr b/src/test/ui/feature-gates/feature-gate-doc_alias.stderr index c585a96adf6..be85ae4b137 100644 --- a/src/test/ui/feature-gates/feature-gate-doc_alias.stderr +++ b/src/test/ui/feature-gates/feature-gate-doc_alias.stderr @@ -1,9 +1,10 @@ -error[E0658]: #[doc(alias = "...")] is experimental (see issue #50146) +error[E0658]: #[doc(alias = "...")] is experimental --> $DIR/feature-gate-doc_alias.rs:1:1 | LL | #[doc(alias = "foo")] | ^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/50146 = help: add #![feature(doc_alias)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-doc_cfg-cfg-rustdoc.stderr b/src/test/ui/feature-gates/feature-gate-doc_cfg-cfg-rustdoc.stderr index f018ff4a9d7..0f84a1b11f0 100644 --- a/src/test/ui/feature-gates/feature-gate-doc_cfg-cfg-rustdoc.stderr +++ b/src/test/ui/feature-gates/feature-gate-doc_cfg-cfg-rustdoc.stderr @@ -1,9 +1,10 @@ -error[E0658]: `cfg(rustdoc)` is experimental and subject to change (see issue #43781) +error[E0658]: `cfg(rustdoc)` is experimental and subject to change --> $DIR/feature-gate-doc_cfg-cfg-rustdoc.rs:1:7 | LL | #[cfg(rustdoc)] | ^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/43781 = help: add #![feature(doc_cfg)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-doc_cfg.stderr b/src/test/ui/feature-gates/feature-gate-doc_cfg.stderr index 2a0aa4ff3c2..9e4aa6c7a07 100644 --- a/src/test/ui/feature-gates/feature-gate-doc_cfg.stderr +++ b/src/test/ui/feature-gates/feature-gate-doc_cfg.stderr @@ -1,9 +1,10 @@ -error[E0658]: #[doc(cfg(...))] is experimental (see issue #43781) +error[E0658]: #[doc(cfg(...))] is experimental --> $DIR/feature-gate-doc_cfg.rs:1:1 | LL | #[doc(cfg(unix))] | ^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/43781 = help: add #![feature(doc_cfg)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-doc_keyword.stderr b/src/test/ui/feature-gates/feature-gate-doc_keyword.stderr index c2cc1dceda3..6e464781721 100644 --- a/src/test/ui/feature-gates/feature-gate-doc_keyword.stderr +++ b/src/test/ui/feature-gates/feature-gate-doc_keyword.stderr @@ -1,9 +1,10 @@ -error[E0658]: #[doc(keyword = "...")] is experimental (see issue #51315) +error[E0658]: #[doc(keyword = "...")] is experimental --> $DIR/feature-gate-doc_keyword.rs:1:1 | LL | #[doc(keyword = "match")] | ^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/51315 = help: add #![feature(doc_keyword)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-doc_masked.stderr b/src/test/ui/feature-gates/feature-gate-doc_masked.stderr index 77d3a6f6fb3..d778d4d994c 100644 --- a/src/test/ui/feature-gates/feature-gate-doc_masked.stderr +++ b/src/test/ui/feature-gates/feature-gate-doc_masked.stderr @@ -1,9 +1,10 @@ -error[E0658]: #[doc(masked)] is experimental (see issue #44027) +error[E0658]: #[doc(masked)] is experimental --> $DIR/feature-gate-doc_masked.rs:1:1 | LL | #[doc(masked)] | ^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/44027 = help: add #![feature(doc_masked)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-doc_spotlight.stderr b/src/test/ui/feature-gates/feature-gate-doc_spotlight.stderr index 60f5c082188..2bf201f4907 100644 --- a/src/test/ui/feature-gates/feature-gate-doc_spotlight.stderr +++ b/src/test/ui/feature-gates/feature-gate-doc_spotlight.stderr @@ -1,9 +1,10 @@ -error[E0658]: #[doc(spotlight)] is experimental (see issue #45040) +error[E0658]: #[doc(spotlight)] is experimental --> $DIR/feature-gate-doc_spotlight.rs:1:1 | LL | #[doc(spotlight)] | ^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/45040 = help: add #![feature(doc_spotlight)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-dropck-ugeh.stderr b/src/test/ui/feature-gates/feature-gate-dropck-ugeh.stderr index bc62fc01b44..9c7f7b2178d 100644 --- a/src/test/ui/feature-gates/feature-gate-dropck-ugeh.stderr +++ b/src/test/ui/feature-gates/feature-gate-dropck-ugeh.stderr @@ -1,9 +1,10 @@ -error[E0658]: unsafe_destructor_blind_to_params has been replaced by may_dangle and will be removed in the future (see issue #28498) +error[E0658]: unsafe_destructor_blind_to_params has been replaced by may_dangle and will be removed in the future --> $DIR/feature-gate-dropck-ugeh.rs:16:5 | LL | #[unsafe_destructor_blind_to_params] // This is the UGEH attribute | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/28498 = help: add #![feature(dropck_parametricity)] to the crate attributes to enable warning: use of deprecated attribute `dropck_parametricity`: unsafe_destructor_blind_to_params has been replaced by may_dangle and will be removed in the future. See https://github.com/rust-lang/rust/issues/34761 diff --git a/src/test/ui/feature-gates/feature-gate-exclusive-range-pattern.stderr b/src/test/ui/feature-gates/feature-gate-exclusive-range-pattern.stderr index afb402174fb..0eb6da3b125 100644 --- a/src/test/ui/feature-gates/feature-gate-exclusive-range-pattern.stderr +++ b/src/test/ui/feature-gates/feature-gate-exclusive-range-pattern.stderr @@ -1,9 +1,10 @@ -error[E0658]: exclusive range pattern syntax is experimental (see issue #37854) +error[E0658]: exclusive range pattern syntax is experimental --> $DIR/feature-gate-exclusive-range-pattern.rs:3:9 | LL | 0 .. 3 => {} | ^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/37854 = help: add #![feature(exclusive_range_pattern)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-existential-type.stderr b/src/test/ui/feature-gates/feature-gate-existential-type.stderr index 6b8b850b5cc..efaf29c00da 100644 --- a/src/test/ui/feature-gates/feature-gate-existential-type.stderr +++ b/src/test/ui/feature-gates/feature-gate-existential-type.stderr @@ -1,17 +1,19 @@ -error[E0658]: existential types are unstable (see issue #34511) +error[E0658]: existential types are unstable --> $DIR/feature-gate-existential-type.rs:3:1 | LL | existential type Foo: std::fmt::Debug; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/34511 = help: add #![feature(existential_type)] to the crate attributes to enable -error[E0658]: existential types are unstable (see issue #34511) +error[E0658]: existential types are unstable --> $DIR/feature-gate-existential-type.rs:11:5 | LL | existential type Baa: std::fmt::Debug; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/34511 = help: add #![feature(existential_type)] to the crate attributes to enable error: aborting due to 2 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-extern_types.stderr b/src/test/ui/feature-gates/feature-gate-extern_types.stderr index 7035d85ec2a..18c0bae2c4b 100644 --- a/src/test/ui/feature-gates/feature-gate-extern_types.stderr +++ b/src/test/ui/feature-gates/feature-gate-extern_types.stderr @@ -1,9 +1,10 @@ -error[E0658]: extern types are experimental (see issue #43467) +error[E0658]: extern types are experimental --> $DIR/feature-gate-extern_types.rs:2:5 | LL | type T; | ^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/43467 = help: add #![feature(extern_types)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-external_doc.stderr b/src/test/ui/feature-gates/feature-gate-external_doc.stderr index 16507bf596f..79e4f8e9b62 100644 --- a/src/test/ui/feature-gates/feature-gate-external_doc.stderr +++ b/src/test/ui/feature-gates/feature-gate-external_doc.stderr @@ -1,9 +1,10 @@ -error[E0658]: #[doc(include = "...")] is experimental (see issue #44732) +error[E0658]: #[doc(include = "...")] is experimental --> $DIR/feature-gate-external_doc.rs:1:1 | LL | #[doc(include="asdf.md")] | ^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/44732 = help: add #![feature(external_doc)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-ffi_returns_twice.rs b/src/test/ui/feature-gates/feature-gate-ffi_returns_twice.rs index d3df6e5a852..2ea60029492 100644 --- a/src/test/ui/feature-gates/feature-gate-ffi_returns_twice.rs +++ b/src/test/ui/feature-gates/feature-gate-ffi_returns_twice.rs @@ -2,6 +2,6 @@ #![crate_type = "lib"] extern { - #[ffi_returns_twice] //~ ERROR the `#[ffi_returns_twice]` attribute is an experimental feature (see issue #58314) + #[ffi_returns_twice] //~ ERROR the `#[ffi_returns_twice]` attribute is an experimental feature pub fn foo(); } diff --git a/src/test/ui/feature-gates/feature-gate-ffi_returns_twice.stderr b/src/test/ui/feature-gates/feature-gate-ffi_returns_twice.stderr index f85ce8eeeac..c28d45df7cd 100644 --- a/src/test/ui/feature-gates/feature-gate-ffi_returns_twice.stderr +++ b/src/test/ui/feature-gates/feature-gate-ffi_returns_twice.stderr @@ -1,9 +1,10 @@ -error[E0658]: the `#[ffi_returns_twice]` attribute is an experimental feature (see issue #58314) +error[E0658]: the `#[ffi_returns_twice]` attribute is an experimental feature --> $DIR/feature-gate-ffi_returns_twice.rs:5:5 | LL | #[ffi_returns_twice] | ^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/58314 = help: add #![feature(ffi_returns_twice)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-fundamental.stderr b/src/test/ui/feature-gates/feature-gate-fundamental.stderr index 9faf2a88a6b..265b576bc79 100644 --- a/src/test/ui/feature-gates/feature-gate-fundamental.stderr +++ b/src/test/ui/feature-gates/feature-gate-fundamental.stderr @@ -1,9 +1,10 @@ -error[E0658]: the `#[fundamental]` attribute is an experimental feature (see issue #29635) +error[E0658]: the `#[fundamental]` attribute is an experimental feature --> $DIR/feature-gate-fundamental.rs:1:1 | LL | #[fundamental] | ^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29635 = help: add #![feature(fundamental)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-generators.stderr b/src/test/ui/feature-gates/feature-gate-generators.stderr index 554eeae8dec..b29fe7094f3 100644 --- a/src/test/ui/feature-gates/feature-gate-generators.stderr +++ b/src/test/ui/feature-gates/feature-gate-generators.stderr @@ -1,9 +1,10 @@ -error[E0658]: yield syntax is experimental (see issue #43122) +error[E0658]: yield syntax is experimental --> $DIR/feature-gate-generators.rs:2:5 | LL | yield true; | ^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/43122 = help: add #![feature(generators)] to the crate attributes to enable error[E0627]: yield statement outside of generator literal diff --git a/src/test/ui/feature-gates/feature-gate-generic_associated_types.stderr b/src/test/ui/feature-gates/feature-gate-generic_associated_types.stderr index 8a207c966cd..d37dd93983c 100644 --- a/src/test/ui/feature-gates/feature-gate-generic_associated_types.stderr +++ b/src/test/ui/feature-gates/feature-gate-generic_associated_types.stderr @@ -1,57 +1,64 @@ -error[E0658]: generic associated types are unstable (see issue #44265) +error[E0658]: generic associated types are unstable --> $DIR/feature-gate-generic_associated_types.rs:4:5 | LL | type Pointer<T>: Deref<Target = T>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/44265 = help: add #![feature(generic_associated_types)] to the crate attributes to enable -error[E0658]: generic associated types are unstable (see issue #44265) +error[E0658]: generic associated types are unstable --> $DIR/feature-gate-generic_associated_types.rs:6:5 | LL | type Pointer2<T>: Deref<Target = T> where T: Clone, U: Clone; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/44265 = help: add #![feature(generic_associated_types)] to the crate attributes to enable -error[E0658]: where clauses on associated types are unstable (see issue #44265) +error[E0658]: where clauses on associated types are unstable --> $DIR/feature-gate-generic_associated_types.rs:6:5 | LL | type Pointer2<T>: Deref<Target = T> where T: Clone, U: Clone; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/44265 = help: add #![feature(generic_associated_types)] to the crate attributes to enable -error[E0658]: generic associated types are unstable (see issue #44265) +error[E0658]: generic associated types are unstable --> $DIR/feature-gate-generic_associated_types.rs:14:5 | LL | type Pointer<Usize> = Box<Usize>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/44265 = help: add #![feature(generic_associated_types)] to the crate attributes to enable -error[E0658]: generic associated types are unstable (see issue #44265) +error[E0658]: generic associated types are unstable --> $DIR/feature-gate-generic_associated_types.rs:16:5 | LL | type Pointer2<U32> = Box<U32>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/44265 = help: add #![feature(generic_associated_types)] to the crate attributes to enable -error[E0658]: where clauses on associated types are unstable (see issue #44265) +error[E0658]: where clauses on associated types are unstable --> $DIR/feature-gate-generic_associated_types.rs:21:5 | LL | type Assoc where Self: Sized; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/44265 = help: add #![feature(generic_associated_types)] to the crate attributes to enable -error[E0658]: where clauses on associated types are unstable (see issue #44265) +error[E0658]: where clauses on associated types are unstable --> $DIR/feature-gate-generic_associated_types.rs:26:5 | LL | type Assoc where Self: Sized = Foo; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/44265 = help: add #![feature(generic_associated_types)] to the crate attributes to enable error: aborting due to 7 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-global_asm.stderr b/src/test/ui/feature-gates/feature-gate-global_asm.stderr index fb9b47bd49c..7d8abac3990 100644 --- a/src/test/ui/feature-gates/feature-gate-global_asm.stderr +++ b/src/test/ui/feature-gates/feature-gate-global_asm.stderr @@ -1,9 +1,10 @@ -error[E0658]: `global_asm!` is not stable enough for use and is subject to change (see issue #35119) +error[E0658]: `global_asm!` is not stable enough for use and is subject to change --> $DIR/feature-gate-global_asm.rs:1:1 | LL | global_asm!(""); | ^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/35119 = help: add #![feature(global_asm)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-is_sorted.stderr b/src/test/ui/feature-gates/feature-gate-is_sorted.stderr index 8230c1e3a38..1d5998641be 100644 --- a/src/test/ui/feature-gates/feature-gate-is_sorted.stderr +++ b/src/test/ui/feature-gates/feature-gate-is_sorted.stderr @@ -1,33 +1,37 @@ -error[E0658]: use of unstable library feature 'is_sorted': new API (see issue #53485) +error[E0658]: use of unstable library feature 'is_sorted': new API --> $DIR/feature-gate-is_sorted.rs:3:33 | LL | assert!([1, 2, 2, 9].iter().is_sorted()); | ^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/53485 = help: add #![feature(is_sorted)] to the crate attributes to enable -error[E0658]: use of unstable library feature 'is_sorted': new API (see issue #53485) +error[E0658]: use of unstable library feature 'is_sorted': new API --> $DIR/feature-gate-is_sorted.rs:5:39 | LL | assert!(![-2i32, -1, 0, 3].iter().is_sorted_by_key(|n| n.abs())); | ^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/53485 = help: add #![feature(is_sorted)] to the crate attributes to enable -error[E0658]: use of unstable library feature 'is_sorted': new API (see issue #53485) +error[E0658]: use of unstable library feature 'is_sorted': new API --> $DIR/feature-gate-is_sorted.rs:9:26 | LL | assert!([1, 2, 2, 9].is_sorted()); | ^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/53485 = help: add #![feature(is_sorted)] to the crate attributes to enable -error[E0658]: use of unstable library feature 'is_sorted': new API (see issue #53485) +error[E0658]: use of unstable library feature 'is_sorted': new API --> $DIR/feature-gate-is_sorted.rs:11:32 | LL | assert!(![-2i32, -1, 0, 3].is_sorted_by_key(|n| n.abs())); | ^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/53485 = help: add #![feature(is_sorted)] to the crate attributes to enable error: aborting due to 4 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-label_break_value.stderr b/src/test/ui/feature-gates/feature-gate-label_break_value.stderr index b23db3c216d..40efc4dec4b 100644 --- a/src/test/ui/feature-gates/feature-gate-label_break_value.stderr +++ b/src/test/ui/feature-gates/feature-gate-label_break_value.stderr @@ -1,9 +1,10 @@ -error[E0658]: labels on blocks are unstable (see issue #48594) +error[E0658]: labels on blocks are unstable --> $DIR/feature-gate-label_break_value.rs:2:5 | LL | 'a: { | ^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/48594 = help: add #![feature(label_break_value)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-link_args.stderr b/src/test/ui/feature-gates/feature-gate-link_args.stderr index c43377fe630..5267b56253f 100644 --- a/src/test/ui/feature-gates/feature-gate-link_args.stderr +++ b/src/test/ui/feature-gates/feature-gate-link_args.stderr @@ -1,25 +1,28 @@ -error[E0658]: the `link_args` attribute is experimental and not portable across platforms, it is recommended to use `#[link(name = "foo")] instead (see issue #29596) +error[E0658]: the `link_args` attribute is experimental and not portable across platforms, it is recommended to use `#[link(name = "foo")] instead --> $DIR/feature-gate-link_args.rs:12:1 | LL | #[link_args = "-l expected_use_case"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29596 = help: add #![feature(link_args)] to the crate attributes to enable -error[E0658]: the `link_args` attribute is experimental and not portable across platforms, it is recommended to use `#[link(name = "foo")] instead (see issue #29596) +error[E0658]: the `link_args` attribute is experimental and not portable across platforms, it is recommended to use `#[link(name = "foo")] instead --> $DIR/feature-gate-link_args.rs:16:1 | LL | #[link_args = "-l unexected_use_on_non_extern_item"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29596 = help: add #![feature(link_args)] to the crate attributes to enable -error[E0658]: the `link_args` attribute is experimental and not portable across platforms, it is recommended to use `#[link(name = "foo")] instead (see issue #29596) +error[E0658]: the `link_args` attribute is experimental and not portable across platforms, it is recommended to use `#[link(name = "foo")] instead --> $DIR/feature-gate-link_args.rs:9:1 | LL | #![link_args = "-l unexpected_use_as_inner_attr_on_mod"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29596 = help: add #![feature(link_args)] to the crate attributes to enable error: aborting due to 3 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-link_cfg.stderr b/src/test/ui/feature-gates/feature-gate-link_cfg.stderr index b5ac5fdb86a..1648245d0b8 100644 --- a/src/test/ui/feature-gates/feature-gate-link_cfg.stderr +++ b/src/test/ui/feature-gates/feature-gate-link_cfg.stderr @@ -1,9 +1,10 @@ -error[E0658]: is feature gated (see issue #37406) +error[E0658]: is feature gated --> $DIR/feature-gate-link_cfg.rs:1:1 | LL | #[link(name = "foo", cfg(foo))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/37406 = help: add #![feature(link_cfg)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-link_llvm_intrinsics.stderr b/src/test/ui/feature-gates/feature-gate-link_llvm_intrinsics.stderr index a6cfc99ecd2..903696dc7c2 100644 --- a/src/test/ui/feature-gates/feature-gate-link_llvm_intrinsics.stderr +++ b/src/test/ui/feature-gates/feature-gate-link_llvm_intrinsics.stderr @@ -1,9 +1,10 @@ -error[E0658]: linking to LLVM intrinsics is experimental (see issue #29602) +error[E0658]: linking to LLVM intrinsics is experimental --> $DIR/feature-gate-link_llvm_intrinsics.rs:3:5 | LL | fn sqrt(x: f32) -> f32; | ^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29602 = help: add #![feature(link_llvm_intrinsics)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-linkage.stderr b/src/test/ui/feature-gates/feature-gate-linkage.stderr index 1399a84faf6..872c695120a 100644 --- a/src/test/ui/feature-gates/feature-gate-linkage.stderr +++ b/src/test/ui/feature-gates/feature-gate-linkage.stderr @@ -1,9 +1,10 @@ -error[E0658]: the `linkage` attribute is experimental and not portable across platforms (see issue #29603) +error[E0658]: the `linkage` attribute is experimental and not portable across platforms --> $DIR/feature-gate-linkage.rs:2:5 | LL | #[linkage = "extern_weak"] static foo: isize; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29603 = help: add #![feature(linkage)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-lint-reasons.stderr b/src/test/ui/feature-gates/feature-gate-lint-reasons.stderr index 6a36d9fd5a8..9e814a20d6d 100644 --- a/src/test/ui/feature-gates/feature-gate-lint-reasons.stderr +++ b/src/test/ui/feature-gates/feature-gate-lint-reasons.stderr @@ -1,9 +1,10 @@ -error[E0658]: lint reasons are experimental (see issue #54503) +error[E0658]: lint reasons are experimental --> $DIR/feature-gate-lint-reasons.rs:1:28 | LL | #![warn(nonstandard_style, reason = "the standard should be respected")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/54503 = help: add #![feature(lint_reasons)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-log_syntax.stderr b/src/test/ui/feature-gates/feature-gate-log_syntax.stderr index f29ee0b5a78..67bd48d3bed 100644 --- a/src/test/ui/feature-gates/feature-gate-log_syntax.stderr +++ b/src/test/ui/feature-gates/feature-gate-log_syntax.stderr @@ -1,9 +1,10 @@ -error[E0658]: `log_syntax!` is not stable enough for use and is subject to change (see issue #29598) +error[E0658]: `log_syntax!` is not stable enough for use and is subject to change --> $DIR/feature-gate-log_syntax.rs:2:5 | LL | log_syntax!() | ^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29598 = help: add #![feature(log_syntax)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-log_syntax2.stderr b/src/test/ui/feature-gates/feature-gate-log_syntax2.stderr index c5a9b493728..ff0fa343c84 100644 --- a/src/test/ui/feature-gates/feature-gate-log_syntax2.stderr +++ b/src/test/ui/feature-gates/feature-gate-log_syntax2.stderr @@ -1,9 +1,10 @@ -error[E0658]: `log_syntax!` is not stable enough for use and is subject to change (see issue #29598) +error[E0658]: `log_syntax!` is not stable enough for use and is subject to change --> $DIR/feature-gate-log_syntax2.rs:4:22 | LL | println!("{:?}", log_syntax!()); | ^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29598 = help: add #![feature(log_syntax)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-macros_in_extern.stderr b/src/test/ui/feature-gates/feature-gate-macros_in_extern.stderr index affef0fe7d3..891ed81107f 100644 --- a/src/test/ui/feature-gates/feature-gate-macros_in_extern.stderr +++ b/src/test/ui/feature-gates/feature-gate-macros_in_extern.stderr @@ -1,25 +1,28 @@ -error[E0658]: macro invocations in `extern {}` blocks are experimental (see issue #49476) +error[E0658]: macro invocations in `extern {}` blocks are experimental --> $DIR/feature-gate-macros_in_extern.rs:19:5 | LL | returns_isize!(rust_get_test_int); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/49476 = help: add #![feature(macros_in_extern)] to the crate attributes to enable -error[E0658]: macro invocations in `extern {}` blocks are experimental (see issue #49476) +error[E0658]: macro invocations in `extern {}` blocks are experimental --> $DIR/feature-gate-macros_in_extern.rs:21:5 | LL | takes_u32_returns_u32!(rust_dbg_extern_identity_u32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/49476 = help: add #![feature(macros_in_extern)] to the crate attributes to enable -error[E0658]: macro invocations in `extern {}` blocks are experimental (see issue #49476) +error[E0658]: macro invocations in `extern {}` blocks are experimental --> $DIR/feature-gate-macros_in_extern.rs:23:5 | LL | emits_nothing!(); | ^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/49476 = help: add #![feature(macros_in_extern)] to the crate attributes to enable error: aborting due to 3 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-main.stderr b/src/test/ui/feature-gates/feature-gate-main.stderr index 870cf1aa286..4d2d01b49f3 100644 --- a/src/test/ui/feature-gates/feature-gate-main.stderr +++ b/src/test/ui/feature-gates/feature-gate-main.stderr @@ -1,9 +1,10 @@ -error[E0658]: declaration of a nonstandard #[main] function may change over time, for now a top-level `fn main()` is required (see issue #29634) +error[E0658]: declaration of a nonstandard #[main] function may change over time, for now a top-level `fn main()` is required --> $DIR/feature-gate-main.rs:2:1 | LL | fn foo() {} | ^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29634 = help: add #![feature(main)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-marker_trait_attr.rs b/src/test/ui/feature-gates/feature-gate-marker_trait_attr.rs index 2b1b5bba6e1..ea06c775b1a 100644 --- a/src/test/ui/feature-gates/feature-gate-marker_trait_attr.rs +++ b/src/test/ui/feature-gates/feature-gate-marker_trait_attr.rs @@ -1,7 +1,7 @@ use std::fmt::{Debug, Display}; #[marker] trait ExplicitMarker {} -//~^ ERROR marker traits is an experimental feature (see issue #29864) +//~^ ERROR marker traits is an experimental feature impl<T: Display> ExplicitMarker for T {} impl<T: Debug> ExplicitMarker for T {} diff --git a/src/test/ui/feature-gates/feature-gate-marker_trait_attr.stderr b/src/test/ui/feature-gates/feature-gate-marker_trait_attr.stderr index e916df18b66..3ed43b52e56 100644 --- a/src/test/ui/feature-gates/feature-gate-marker_trait_attr.stderr +++ b/src/test/ui/feature-gates/feature-gate-marker_trait_attr.stderr @@ -1,9 +1,10 @@ -error[E0658]: marker traits is an experimental feature (see issue #29864) +error[E0658]: marker traits is an experimental feature --> $DIR/feature-gate-marker_trait_attr.rs:3:1 | LL | #[marker] trait ExplicitMarker {} | ^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29864 = help: add #![feature(marker_trait_attr)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-may-dangle.stderr b/src/test/ui/feature-gates/feature-gate-may-dangle.stderr index 6d21147c9ee..f93be3ed4e7 100644 --- a/src/test/ui/feature-gates/feature-gate-may-dangle.stderr +++ b/src/test/ui/feature-gates/feature-gate-may-dangle.stderr @@ -1,9 +1,10 @@ -error[E0658]: may_dangle has unstable semantics and may be removed in the future (see issue #34761) +error[E0658]: may_dangle has unstable semantics and may be removed in the future --> $DIR/feature-gate-may-dangle.rs:6:13 | LL | unsafe impl<#[may_dangle] A> Drop for Pt<A> { | ^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/34761 = help: add #![feature(dropck_eyepatch)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-min_const_fn.stderr b/src/test/ui/feature-gates/feature-gate-min_const_fn.stderr index f6666b40f3e..a1c329df63a 100644 --- a/src/test/ui/feature-gates/feature-gate-min_const_fn.stderr +++ b/src/test/ui/feature-gates/feature-gate-min_const_fn.stderr @@ -16,20 +16,22 @@ error[E0379]: trait fns cannot be declared const LL | const fn foo() -> u32 { 0 } | ^^^^^ trait fns cannot be const -error[E0658]: const fn is unstable (see issue #57563) +error[E0658]: const fn is unstable --> $DIR/feature-gate-min_const_fn.rs:6:5 | LL | const fn foo() -> u32; | ^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable -error[E0658]: const fn is unstable (see issue #57563) +error[E0658]: const fn is unstable --> $DIR/feature-gate-min_const_fn.rs:8:5 | LL | const fn bar() -> u32 { 0 } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/57563 = help: add #![feature(const_fn)] to the crate attributes to enable error: aborting due to 5 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-naked_functions.stderr b/src/test/ui/feature-gates/feature-gate-naked_functions.stderr index 2ff5ef101e0..0ba4d551a6d 100644 --- a/src/test/ui/feature-gates/feature-gate-naked_functions.stderr +++ b/src/test/ui/feature-gates/feature-gate-naked_functions.stderr @@ -1,17 +1,19 @@ -error[E0658]: the `#[naked]` attribute is an experimental feature (see issue #32408) +error[E0658]: the `#[naked]` attribute is an experimental feature --> $DIR/feature-gate-naked_functions.rs:1:1 | LL | #[naked] | ^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/32408 = help: add #![feature(naked_functions)] to the crate attributes to enable -error[E0658]: the `#[naked]` attribute is an experimental feature (see issue #32408) +error[E0658]: the `#[naked]` attribute is an experimental feature --> $DIR/feature-gate-naked_functions.rs:5:1 | LL | #[naked] | ^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/32408 = help: add #![feature(naked_functions)] to the crate attributes to enable error: aborting due to 2 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-never_type.stderr b/src/test/ui/feature-gates/feature-gate-never_type.stderr index 13166db213e..45a6e6de18b 100644 --- a/src/test/ui/feature-gates/feature-gate-never_type.stderr +++ b/src/test/ui/feature-gates/feature-gate-never_type.stderr @@ -1,41 +1,46 @@ -error[E0658]: The `!` type is experimental (see issue #35121) +error[E0658]: The `!` type is experimental --> $DIR/feature-gate-never_type.rs:7:17 | LL | type Ma = (u32, !, i32); | ^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/35121 = help: add #![feature(never_type)] to the crate attributes to enable -error[E0658]: The `!` type is experimental (see issue #35121) +error[E0658]: The `!` type is experimental --> $DIR/feature-gate-never_type.rs:8:20 | LL | type Meeshka = Vec<!>; | ^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/35121 = help: add #![feature(never_type)] to the crate attributes to enable -error[E0658]: The `!` type is experimental (see issue #35121) +error[E0658]: The `!` type is experimental --> $DIR/feature-gate-never_type.rs:9:24 | LL | type Mow = &'static fn(!) -> !; | ^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/35121 = help: add #![feature(never_type)] to the crate attributes to enable -error[E0658]: The `!` type is experimental (see issue #35121) +error[E0658]: The `!` type is experimental --> $DIR/feature-gate-never_type.rs:10:27 | LL | type Skwoz = &'static mut !; | ^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/35121 = help: add #![feature(never_type)] to the crate attributes to enable -error[E0658]: The `!` type is experimental (see issue #35121) +error[E0658]: The `!` type is experimental --> $DIR/feature-gate-never_type.rs:13:16 | LL | type Wub = !; | ^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/35121 = help: add #![feature(never_type)] to the crate attributes to enable error: aborting due to 5 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-no-debug.stderr b/src/test/ui/feature-gates/feature-gate-no-debug.stderr index 1ee2ec3c881..a58a75b70c5 100644 --- a/src/test/ui/feature-gates/feature-gate-no-debug.stderr +++ b/src/test/ui/feature-gates/feature-gate-no-debug.stderr @@ -1,9 +1,10 @@ -error[E0658]: the `#[no_debug]` attribute was an experimental feature that has been deprecated due to lack of demand (see issue #29721) +error[E0658]: the `#[no_debug]` attribute was an experimental feature that has been deprecated due to lack of demand --> $DIR/feature-gate-no-debug.rs:3:1 | LL | #[no_debug] | ^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29721 = help: add #![feature(no_debug)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-no_core.stderr b/src/test/ui/feature-gates/feature-gate-no_core.stderr index 279f2198a80..e2f0fd68a7c 100644 --- a/src/test/ui/feature-gates/feature-gate-no_core.stderr +++ b/src/test/ui/feature-gates/feature-gate-no_core.stderr @@ -1,9 +1,10 @@ -error[E0658]: no_core is experimental (see issue #29639) +error[E0658]: no_core is experimental --> $DIR/feature-gate-no_core.rs:3:1 | LL | #![no_core] | ^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29639 = help: add #![feature(no_core)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-non_ascii_idents.stderr b/src/test/ui/feature-gates/feature-gate-non_ascii_idents.stderr index 5e4c4649d01..1d78b87a3e0 100644 --- a/src/test/ui/feature-gates/feature-gate-non_ascii_idents.stderr +++ b/src/test/ui/feature-gates/feature-gate-non_ascii_idents.stderr @@ -1,105 +1,118 @@ -error[E0658]: non-ascii idents are not fully supported. (see issue #55467) +error[E0658]: non-ascii idents are not fully supported --> $DIR/feature-gate-non_ascii_idents.rs:1:22 | LL | extern crate core as bäz; | ^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/55467 = help: add #![feature(non_ascii_idents)] to the crate attributes to enable -error[E0658]: non-ascii idents are not fully supported. (see issue #55467) +error[E0658]: non-ascii idents are not fully supported --> $DIR/feature-gate-non_ascii_idents.rs:3:5 | LL | use föö::bar; | ^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/55467 = help: add #![feature(non_ascii_idents)] to the crate attributes to enable -error[E0658]: non-ascii idents are not fully supported. (see issue #55467) +error[E0658]: non-ascii idents are not fully supported --> $DIR/feature-gate-non_ascii_idents.rs:5:5 | LL | mod föö { | ^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/55467 = help: add #![feature(non_ascii_idents)] to the crate attributes to enable -error[E0658]: non-ascii idents are not fully supported. (see issue #55467) +error[E0658]: non-ascii idents are not fully supported --> $DIR/feature-gate-non_ascii_idents.rs:9:4 | LL | fn bär( | ^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/55467 = help: add #![feature(non_ascii_idents)] to the crate attributes to enable -error[E0658]: non-ascii idents are not fully supported. (see issue #55467) +error[E0658]: non-ascii idents are not fully supported --> $DIR/feature-gate-non_ascii_idents.rs:10:5 | LL | bäz: isize | ^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/55467 = help: add #![feature(non_ascii_idents)] to the crate attributes to enable -error[E0658]: non-ascii idents are not fully supported. (see issue #55467) +error[E0658]: non-ascii idents are not fully supported --> $DIR/feature-gate-non_ascii_idents.rs:12:9 | LL | let _ö: isize; | ^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/55467 = help: add #![feature(non_ascii_idents)] to the crate attributes to enable -error[E0658]: non-ascii idents are not fully supported. (see issue #55467) +error[E0658]: non-ascii idents are not fully supported --> $DIR/feature-gate-non_ascii_idents.rs:15:10 | LL | (_ä, _) => {} | ^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/55467 = help: add #![feature(non_ascii_idents)] to the crate attributes to enable -error[E0658]: non-ascii idents are not fully supported. (see issue #55467) +error[E0658]: non-ascii idents are not fully supported --> $DIR/feature-gate-non_ascii_idents.rs:19:8 | LL | struct Föö { | ^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/55467 = help: add #![feature(non_ascii_idents)] to the crate attributes to enable -error[E0658]: non-ascii idents are not fully supported. (see issue #55467) +error[E0658]: non-ascii idents are not fully supported --> $DIR/feature-gate-non_ascii_idents.rs:20:5 | LL | föö: isize | ^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/55467 = help: add #![feature(non_ascii_idents)] to the crate attributes to enable -error[E0658]: non-ascii idents are not fully supported. (see issue #55467) +error[E0658]: non-ascii idents are not fully supported --> $DIR/feature-gate-non_ascii_idents.rs:23:6 | LL | enum Bär { | ^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/55467 = help: add #![feature(non_ascii_idents)] to the crate attributes to enable -error[E0658]: non-ascii idents are not fully supported. (see issue #55467) +error[E0658]: non-ascii idents are not fully supported --> $DIR/feature-gate-non_ascii_idents.rs:24:5 | LL | Bäz { | ^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/55467 = help: add #![feature(non_ascii_idents)] to the crate attributes to enable -error[E0658]: non-ascii idents are not fully supported. (see issue #55467) +error[E0658]: non-ascii idents are not fully supported --> $DIR/feature-gate-non_ascii_idents.rs:25:9 | LL | qüx: isize | ^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/55467 = help: add #![feature(non_ascii_idents)] to the crate attributes to enable -error[E0658]: non-ascii idents are not fully supported. (see issue #55467) +error[E0658]: non-ascii idents are not fully supported --> $DIR/feature-gate-non_ascii_idents.rs:30:8 | LL | fn qüx(); | ^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/55467 = help: add #![feature(non_ascii_idents)] to the crate attributes to enable error: aborting due to 13 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-non_exhaustive.rs b/src/test/ui/feature-gates/feature-gate-non_exhaustive.rs index b3e2e3d95f5..aca214d1935 100644 --- a/src/test/ui/feature-gates/feature-gate-non_exhaustive.rs +++ b/src/test/ui/feature-gates/feature-gate-non_exhaustive.rs @@ -1,6 +1,6 @@ //#![feature(non_exhaustive)] -#[non_exhaustive] //~ERROR non exhaustive is an experimental feature (see issue #44109) +#[non_exhaustive] //~ERROR non exhaustive is an experimental feature pub enum NonExhaustiveEnum { Unit, Tuple(u32), diff --git a/src/test/ui/feature-gates/feature-gate-non_exhaustive.stderr b/src/test/ui/feature-gates/feature-gate-non_exhaustive.stderr index 524f77902f6..fdb1ffb0a9b 100644 --- a/src/test/ui/feature-gates/feature-gate-non_exhaustive.stderr +++ b/src/test/ui/feature-gates/feature-gate-non_exhaustive.stderr @@ -1,9 +1,10 @@ -error[E0658]: non exhaustive is an experimental feature (see issue #44109) +error[E0658]: non exhaustive is an experimental feature --> $DIR/feature-gate-non_exhaustive.rs:3:1 | LL | #[non_exhaustive] | ^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/44109 = help: add #![feature(non_exhaustive)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-on-unimplemented.stderr b/src/test/ui/feature-gates/feature-gate-on-unimplemented.stderr index 32bfb20d5ed..044a9a398d6 100644 --- a/src/test/ui/feature-gates/feature-gate-on-unimplemented.stderr +++ b/src/test/ui/feature-gates/feature-gate-on-unimplemented.stderr @@ -1,9 +1,10 @@ -error[E0658]: the `#[rustc_on_unimplemented]` attribute is an experimental feature (see issue #29628) +error[E0658]: the `#[rustc_on_unimplemented]` attribute is an experimental feature --> $DIR/feature-gate-on-unimplemented.rs:4:1 | LL | #[rustc_on_unimplemented = "test error `{Self}` with `{Bar}`"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29628 = help: add #![feature(on_unimplemented)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-optin-builtin-traits.stderr b/src/test/ui/feature-gates/feature-gate-optin-builtin-traits.stderr index e5d0a8681fb..baad1627d9c 100644 --- a/src/test/ui/feature-gates/feature-gate-optin-builtin-traits.stderr +++ b/src/test/ui/feature-gates/feature-gate-optin-builtin-traits.stderr @@ -1,17 +1,19 @@ -error[E0658]: auto traits are experimental and possibly buggy (see issue #13231) +error[E0658]: auto traits are experimental and possibly buggy --> $DIR/feature-gate-optin-builtin-traits.rs:6:1 | LL | auto trait AutoDummyTrait {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/13231 = help: add #![feature(optin_builtin_traits)] to the crate attributes to enable -error[E0658]: negative trait bounds are not yet fully implemented; use marker types for now (see issue #13231) +error[E0658]: negative trait bounds are not yet fully implemented; use marker types for now --> $DIR/feature-gate-optin-builtin-traits.rs:9:1 | LL | impl !AutoDummyTrait for DummyStruct {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/13231 = help: add #![feature(optin_builtin_traits)] to the crate attributes to enable error: aborting due to 2 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-plugin.stderr b/src/test/ui/feature-gates/feature-gate-plugin.stderr index 0feebb6f0e0..5ac41201888 100644 --- a/src/test/ui/feature-gates/feature-gate-plugin.stderr +++ b/src/test/ui/feature-gates/feature-gate-plugin.stderr @@ -1,9 +1,10 @@ -error[E0658]: compiler plugins are experimental and possibly buggy (see issue #29597) +error[E0658]: compiler plugins are experimental and possibly buggy --> $DIR/feature-gate-plugin.rs:3:1 | LL | #![plugin(foo)] | ^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29597 = help: add #![feature(plugin)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-plugin_registrar.stderr b/src/test/ui/feature-gates/feature-gate-plugin_registrar.stderr index 6464d4087be..941a6c49d15 100644 --- a/src/test/ui/feature-gates/feature-gate-plugin_registrar.stderr +++ b/src/test/ui/feature-gates/feature-gate-plugin_registrar.stderr @@ -1,9 +1,10 @@ -error[E0658]: compiler plugins are experimental and possibly buggy (see issue #29597) +error[E0658]: compiler plugins are experimental and possibly buggy --> $DIR/feature-gate-plugin_registrar.rs:6:1 | LL | pub fn registrar() {} | ^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29597 = help: add #![feature(plugin_registrar)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-repr-simd.stderr b/src/test/ui/feature-gates/feature-gate-repr-simd.stderr index c47ce70eaae..056bfdd85d1 100644 --- a/src/test/ui/feature-gates/feature-gate-repr-simd.stderr +++ b/src/test/ui/feature-gates/feature-gate-repr-simd.stderr @@ -1,17 +1,19 @@ -error[E0658]: SIMD types are experimental and possibly buggy (see issue #27731) +error[E0658]: SIMD types are experimental and possibly buggy --> $DIR/feature-gate-repr-simd.rs:1:1 | LL | #[repr(simd)] | ^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/27731 = help: add #![feature(repr_simd)] to the crate attributes to enable -error[E0658]: SIMD types are experimental and possibly buggy (see issue #27731) +error[E0658]: SIMD types are experimental and possibly buggy --> $DIR/feature-gate-repr-simd.rs:5:1 | LL | #[repr(simd)] | ^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/27731 = help: add #![feature(repr_simd)] to the crate attributes to enable warning[E0566]: conflicting representation hints diff --git a/src/test/ui/feature-gates/feature-gate-repr128.stderr b/src/test/ui/feature-gates/feature-gate-repr128.stderr index a2fd6593599..30433447a2b 100644 --- a/src/test/ui/feature-gates/feature-gate-repr128.stderr +++ b/src/test/ui/feature-gates/feature-gate-repr128.stderr @@ -1,4 +1,4 @@ -error[E0658]: repr with 128-bit type is unstable (see issue #35118) +error[E0658]: repr with 128-bit type is unstable --> $DIR/feature-gate-repr128.rs:2:1 | LL | / enum A { @@ -6,6 +6,7 @@ LL | | A(u64) LL | | } | |_^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/35118 = help: add #![feature(repr128)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-repr_align_enum.rs b/src/test/ui/feature-gates/feature-gate-repr_align_enum.rs index f8e68a9de01..8b68caa6f5b 100644 --- a/src/test/ui/feature-gates/feature-gate-repr_align_enum.rs +++ b/src/test/ui/feature-gates/feature-gate-repr_align_enum.rs @@ -1,7 +1,7 @@ #[repr(align(16))] struct Foo(u64); -#[repr(align(8))] //~ ERROR `#[repr(align(x))]` on enums is experimental (see issue #57996) +#[repr(align(8))] //~ ERROR `#[repr(align(x))]` on enums is experimental enum Bar { Foo { foo: Foo }, Baz, diff --git a/src/test/ui/feature-gates/feature-gate-repr_align_enum.stderr b/src/test/ui/feature-gates/feature-gate-repr_align_enum.stderr index ae4066ceb80..36924f4c167 100644 --- a/src/test/ui/feature-gates/feature-gate-repr_align_enum.stderr +++ b/src/test/ui/feature-gates/feature-gate-repr_align_enum.stderr @@ -1,9 +1,10 @@ -error[E0658]: `#[repr(align(x))]` on enums is experimental (see issue #57996) +error[E0658]: `#[repr(align(x))]` on enums is experimental --> $DIR/feature-gate-repr_align_enum.rs:4:1 | LL | #[repr(align(8))] | ^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/57996 = help: add #![feature(repr_align_enum)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-rustc-attrs-1.stderr b/src/test/ui/feature-gates/feature-gate-rustc-attrs-1.stderr index 73cd28fe749..882feb87f42 100644 --- a/src/test/ui/feature-gates/feature-gate-rustc-attrs-1.stderr +++ b/src/test/ui/feature-gates/feature-gate-rustc-attrs-1.stderr @@ -1,17 +1,19 @@ -error[E0658]: the `#[rustc_variance]` attribute is just used for rustc unit tests and will never be stable (see issue #29642) +error[E0658]: the `#[rustc_variance]` attribute is just used for rustc unit tests and will never be stable --> $DIR/feature-gate-rustc-attrs-1.rs:5:1 | LL | #[rustc_variance] | ^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(rustc_attrs)] to the crate attributes to enable -error[E0658]: the `#[rustc_error]` attribute is just used for rustc unit tests and will never be stable (see issue #29642) +error[E0658]: the `#[rustc_error]` attribute is just used for rustc unit tests and will never be stable --> $DIR/feature-gate-rustc-attrs-1.rs:6:1 | LL | #[rustc_error] | ^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(rustc_attrs)] to the crate attributes to enable error: aborting due to 2 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-rustc-attrs.stderr b/src/test/ui/feature-gates/feature-gate-rustc-attrs.stderr index 40e6d6d9256..3c823c8d4e2 100644 --- a/src/test/ui/feature-gates/feature-gate-rustc-attrs.stderr +++ b/src/test/ui/feature-gates/feature-gate-rustc-attrs.stderr @@ -1,9 +1,10 @@ -error[E0658]: unless otherwise specified, attributes with the prefix `rustc_` are reserved for internal compiler diagnostics (see issue #29642) +error[E0658]: unless otherwise specified, attributes with the prefix `rustc_` are reserved for internal compiler diagnostics --> $DIR/feature-gate-rustc-attrs.rs:3:3 | LL | #[rustc_foo] | ^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(rustc_attrs)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-simd.stderr b/src/test/ui/feature-gates/feature-gate-simd.stderr index b37f138fbb5..1686a8530fe 100644 --- a/src/test/ui/feature-gates/feature-gate-simd.stderr +++ b/src/test/ui/feature-gates/feature-gate-simd.stderr @@ -1,9 +1,10 @@ -error[E0658]: SIMD types are experimental and possibly buggy (see issue #27731) +error[E0658]: SIMD types are experimental and possibly buggy --> $DIR/feature-gate-simd.rs:3:1 | LL | #[repr(simd)] | ^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/27731 = help: add #![feature(repr_simd)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-slice-patterns.stderr b/src/test/ui/feature-gates/feature-gate-slice-patterns.stderr index 58eb57516eb..fe3c1e0afdd 100644 --- a/src/test/ui/feature-gates/feature-gate-slice-patterns.stderr +++ b/src/test/ui/feature-gates/feature-gate-slice-patterns.stderr @@ -1,49 +1,55 @@ -error[E0658]: syntax for subslices in slice patterns is not yet stabilized (see issue #23121) +error[E0658]: syntax for subslices in slice patterns is not yet stabilized --> $DIR/feature-gate-slice-patterns.rs:6:16 | LL | [1, 2, ..] => {} | ^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/23121 = help: add #![feature(slice_patterns)] to the crate attributes to enable -error[E0658]: syntax for subslices in slice patterns is not yet stabilized (see issue #23121) +error[E0658]: syntax for subslices in slice patterns is not yet stabilized --> $DIR/feature-gate-slice-patterns.rs:7:13 | LL | [1, .., 5] => {} | ^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/23121 = help: add #![feature(slice_patterns)] to the crate attributes to enable -error[E0658]: syntax for subslices in slice patterns is not yet stabilized (see issue #23121) +error[E0658]: syntax for subslices in slice patterns is not yet stabilized --> $DIR/feature-gate-slice-patterns.rs:8:10 | LL | [.., 4, 5] => {} | ^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/23121 = help: add #![feature(slice_patterns)] to the crate attributes to enable -error[E0658]: syntax for subslices in slice patterns is not yet stabilized (see issue #23121) +error[E0658]: syntax for subslices in slice patterns is not yet stabilized --> $DIR/feature-gate-slice-patterns.rs:13:11 | LL | [ xs.., 4, 5 ] => {} | ^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/23121 = help: add #![feature(slice_patterns)] to the crate attributes to enable -error[E0658]: syntax for subslices in slice patterns is not yet stabilized (see issue #23121) +error[E0658]: syntax for subslices in slice patterns is not yet stabilized --> $DIR/feature-gate-slice-patterns.rs:14:14 | LL | [ 1, xs.., 5 ] => {} | ^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/23121 = help: add #![feature(slice_patterns)] to the crate attributes to enable -error[E0658]: syntax for subslices in slice patterns is not yet stabilized (see issue #23121) +error[E0658]: syntax for subslices in slice patterns is not yet stabilized --> $DIR/feature-gate-slice-patterns.rs:15:17 | LL | [ 1, 2, xs.. ] => {} | ^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/23121 = help: add #![feature(slice_patterns)] to the crate attributes to enable error: aborting due to 6 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-start.stderr b/src/test/ui/feature-gates/feature-gate-start.stderr index d39e5f35555..fbe64ea130d 100644 --- a/src/test/ui/feature-gates/feature-gate-start.stderr +++ b/src/test/ui/feature-gates/feature-gate-start.stderr @@ -1,9 +1,10 @@ -error[E0658]: a #[start] function is an experimental feature whose signature may change over time (see issue #29633) +error[E0658]: a #[start] function is an experimental feature whose signature may change over time --> $DIR/feature-gate-start.rs:2:1 | LL | fn foo(_: isize, _: *const *const u8) -> isize { 0 } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29633 = help: add #![feature(start)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-static-nobundle.stderr b/src/test/ui/feature-gates/feature-gate-static-nobundle.stderr index 2e80275f3f7..7d5ed74abd1 100644 --- a/src/test/ui/feature-gates/feature-gate-static-nobundle.stderr +++ b/src/test/ui/feature-gates/feature-gate-static-nobundle.stderr @@ -1,9 +1,10 @@ -error[E0658]: kind="static-nobundle" is feature gated (see issue #37403) +error[E0658]: kind="static-nobundle" is feature gated --> $DIR/feature-gate-static-nobundle.rs:1:1 | LL | #[link(name="foo", kind="static-nobundle")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/37403 = help: add #![feature(static_nobundle)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-stmt_expr_attributes.rs b/src/test/ui/feature-gates/feature-gate-stmt_expr_attributes.rs index 3e5b6260d74..f213e8933bf 100644 --- a/src/test/ui/feature-gates/feature-gate-stmt_expr_attributes.rs +++ b/src/test/ui/feature-gates/feature-gate-stmt_expr_attributes.rs @@ -1,4 +1,4 @@ const X: i32 = #[allow(dead_code)] 8; -//~^ ERROR attributes on expressions are experimental. (see issue #15701) +//~^ ERROR attributes on expressions are experimental fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-stmt_expr_attributes.stderr b/src/test/ui/feature-gates/feature-gate-stmt_expr_attributes.stderr index 4318edd9230..bbf0f66ca54 100644 --- a/src/test/ui/feature-gates/feature-gate-stmt_expr_attributes.stderr +++ b/src/test/ui/feature-gates/feature-gate-stmt_expr_attributes.stderr @@ -1,9 +1,10 @@ -error[E0658]: attributes on expressions are experimental. (see issue #15701) +error[E0658]: attributes on expressions are experimental --> $DIR/feature-gate-stmt_expr_attributes.rs:1:16 | LL | const X: i32 = #[allow(dead_code)] 8; | ^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/15701 = help: add #![feature(stmt_expr_attributes)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-thread_local.stderr b/src/test/ui/feature-gates/feature-gate-thread_local.stderr index 38064a6bc94..95334d23d51 100644 --- a/src/test/ui/feature-gates/feature-gate-thread_local.stderr +++ b/src/test/ui/feature-gates/feature-gate-thread_local.stderr @@ -1,9 +1,10 @@ -error[E0658]: `#[thread_local]` is an experimental feature, and does not currently handle destructors. (see issue #29594) +error[E0658]: `#[thread_local]` is an experimental feature, and does not currently handle destructors --> $DIR/feature-gate-thread_local.rs:8:1 | LL | #[thread_local] | ^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29594 = help: add #![feature(thread_local)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-trace_macros.stderr b/src/test/ui/feature-gates/feature-gate-trace_macros.stderr index ee22bd25091..bcce31d873b 100644 --- a/src/test/ui/feature-gates/feature-gate-trace_macros.stderr +++ b/src/test/ui/feature-gates/feature-gate-trace_macros.stderr @@ -1,9 +1,10 @@ -error[E0658]: `trace_macros` is not stable enough for use and is subject to change (see issue #29598) +error[E0658]: `trace_macros` is not stable enough for use and is subject to change --> $DIR/feature-gate-trace_macros.rs:2:5 | LL | trace_macros!(true); | ^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29598 = help: add #![feature(trace_macros)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-trait-alias.stderr b/src/test/ui/feature-gates/feature-gate-trait-alias.stderr index bb833c4e732..1a9718a6ce4 100644 --- a/src/test/ui/feature-gates/feature-gate-trait-alias.stderr +++ b/src/test/ui/feature-gates/feature-gate-trait-alias.stderr @@ -1,9 +1,10 @@ -error[E0658]: trait aliases are experimental (see issue #41517) +error[E0658]: trait aliases are experimental --> $DIR/feature-gate-trait-alias.rs:1:1 | LL | trait Foo = Default; | ^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/41517 = help: add #![feature(trait_alias)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-try_blocks.stderr b/src/test/ui/feature-gates/feature-gate-try_blocks.stderr index 74ad0e70c96..cb72b067333 100644 --- a/src/test/ui/feature-gates/feature-gate-try_blocks.stderr +++ b/src/test/ui/feature-gates/feature-gate-try_blocks.stderr @@ -1,4 +1,4 @@ -error[E0658]: `try` expression is experimental (see issue #31436) +error[E0658]: `try` expression is experimental --> $DIR/feature-gate-try_blocks.rs:4:33 | LL | let try_result: Option<_> = try { @@ -8,6 +8,7 @@ LL | | x LL | | }; | |_____^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/31436 = help: add #![feature(try_blocks)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-try_reserve.stderr b/src/test/ui/feature-gates/feature-gate-try_reserve.stderr index 61a3249c2ab..f1d82d94a52 100644 --- a/src/test/ui/feature-gates/feature-gate-try_reserve.stderr +++ b/src/test/ui/feature-gates/feature-gate-try_reserve.stderr @@ -1,9 +1,10 @@ -error[E0658]: use of unstable library feature 'try_reserve': new API (see issue #48043) +error[E0658]: use of unstable library feature 'try_reserve': new API --> $DIR/feature-gate-try_reserve.rs:3:7 | LL | v.try_reserve(10); | ^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/48043 = help: add #![feature(try_reserve)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-type_ascription.stderr b/src/test/ui/feature-gates/feature-gate-type_ascription.stderr index 13dbb602967..0e4e25882c8 100644 --- a/src/test/ui/feature-gates/feature-gate-type_ascription.stderr +++ b/src/test/ui/feature-gates/feature-gate-type_ascription.stderr @@ -1,9 +1,10 @@ -error[E0658]: type ascription is experimental (see issue #23416) +error[E0658]: type ascription is experimental --> $DIR/feature-gate-type_ascription.rs:4:13 | LL | let a = 10: u8; | ^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/23416 = help: add #![feature(type_ascription)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr b/src/test/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr index 865b87e7dd5..5fbaf8dd0ba 100644 --- a/src/test/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr +++ b/src/test/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr @@ -1,41 +1,46 @@ -error[E0658]: rust-call ABI is subject to change (see issue #29625) +error[E0658]: rust-call ABI is subject to change --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:11:5 | LL | extern "rust-call" fn call(self, args: ()) -> () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add #![feature(unboxed_closures)] to the crate attributes to enable -error[E0658]: rust-call ABI is subject to change (see issue #29625) +error[E0658]: rust-call ABI is subject to change --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:17:5 | LL | extern "rust-call" fn call_once(self, args: ()) -> () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add #![feature(unboxed_closures)] to the crate attributes to enable -error[E0658]: rust-call ABI is subject to change (see issue #29625) +error[E0658]: rust-call ABI is subject to change --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:23:5 | LL | extern "rust-call" fn call_mut(&self, args: ()) -> () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add #![feature(unboxed_closures)] to the crate attributes to enable -error[E0658]: rust-call ABI is subject to change (see issue #29625) +error[E0658]: rust-call ABI is subject to change --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:29:5 | LL | extern "rust-call" fn call_once(&self, args: ()) -> () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add #![feature(unboxed_closures)] to the crate attributes to enable -error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change. Use parenthetical notation (Fn(Foo, Bar) -> Baz) instead (see issue #29625) +error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change. Use parenthetical notation (Fn(Foo, Bar) -> Baz) instead --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:9:6 | LL | impl Fn<()> for Foo { | ^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add #![feature(unboxed_closures)] to the crate attributes to enable error[E0229]: associated type bindings are not allowed here @@ -44,20 +49,22 @@ error[E0229]: associated type bindings are not allowed here LL | impl FnOnce() for Foo1 { | ^^ associated type not allowed here -error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change. Use parenthetical notation (Fn(Foo, Bar) -> Baz) instead (see issue #29625) +error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change. Use parenthetical notation (Fn(Foo, Bar) -> Baz) instead --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:21:6 | LL | impl FnMut<()> for Bar { | ^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add #![feature(unboxed_closures)] to the crate attributes to enable -error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change. Use parenthetical notation (Fn(Foo, Bar) -> Baz) instead (see issue #29625) +error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change. Use parenthetical notation (Fn(Foo, Bar) -> Baz) instead --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:27:6 | LL | impl FnOnce<()> for Baz { | ^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add #![feature(unboxed_closures)] to the crate attributes to enable error: aborting due to 8 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-unboxed-closures-method-calls.stderr b/src/test/ui/feature-gates/feature-gate-unboxed-closures-method-calls.stderr index 519f6528323..164368cd8ef 100644 --- a/src/test/ui/feature-gates/feature-gate-unboxed-closures-method-calls.stderr +++ b/src/test/ui/feature-gates/feature-gate-unboxed-closures-method-calls.stderr @@ -1,25 +1,28 @@ -error[E0658]: use of unstable library feature 'fn_traits' (see issue #29625) +error[E0658]: use of unstable library feature 'fn_traits' --> $DIR/feature-gate-unboxed-closures-method-calls.rs:4:7 | LL | f.call(()); | ^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add #![feature(fn_traits)] to the crate attributes to enable -error[E0658]: use of unstable library feature 'fn_traits' (see issue #29625) +error[E0658]: use of unstable library feature 'fn_traits' --> $DIR/feature-gate-unboxed-closures-method-calls.rs:5:7 | LL | f.call_mut(()); | ^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add #![feature(fn_traits)] to the crate attributes to enable -error[E0658]: use of unstable library feature 'fn_traits' (see issue #29625) +error[E0658]: use of unstable library feature 'fn_traits' --> $DIR/feature-gate-unboxed-closures-method-calls.rs:6:7 | LL | f.call_once(()); | ^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add #![feature(fn_traits)] to the crate attributes to enable error: aborting due to 3 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-unboxed-closures-ufcs-calls.stderr b/src/test/ui/feature-gates/feature-gate-unboxed-closures-ufcs-calls.stderr index a49a8b4cdb2..ff2629fe421 100644 --- a/src/test/ui/feature-gates/feature-gate-unboxed-closures-ufcs-calls.stderr +++ b/src/test/ui/feature-gates/feature-gate-unboxed-closures-ufcs-calls.stderr @@ -1,25 +1,28 @@ -error[E0658]: use of unstable library feature 'fn_traits' (see issue #29625) +error[E0658]: use of unstable library feature 'fn_traits' --> $DIR/feature-gate-unboxed-closures-ufcs-calls.rs:4:5 | LL | Fn::call(&f, ()); | ^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add #![feature(fn_traits)] to the crate attributes to enable -error[E0658]: use of unstable library feature 'fn_traits' (see issue #29625) +error[E0658]: use of unstable library feature 'fn_traits' --> $DIR/feature-gate-unboxed-closures-ufcs-calls.rs:5:5 | LL | FnMut::call_mut(&mut f, ()); | ^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add #![feature(fn_traits)] to the crate attributes to enable -error[E0658]: use of unstable library feature 'fn_traits' (see issue #29625) +error[E0658]: use of unstable library feature 'fn_traits' --> $DIR/feature-gate-unboxed-closures-ufcs-calls.rs:6:5 | LL | FnOnce::call_once(f, ()); | ^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add #![feature(fn_traits)] to the crate attributes to enable error: aborting due to 3 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-unboxed-closures.rs b/src/test/ui/feature-gates/feature-gate-unboxed-closures.rs index c3f5c99dcb4..b8d3aa4a141 100644 --- a/src/test/ui/feature-gates/feature-gate-unboxed-closures.rs +++ b/src/test/ui/feature-gates/feature-gate-unboxed-closures.rs @@ -9,7 +9,7 @@ impl FnOnce<(u32, u32)> for Test { extern "rust-call" fn call_once(self, (a, b): (u32, u32)) -> u32 { a + b } - //~^^^ ERROR rust-call ABI is subject to change (see issue #29625) + //~^^^ ERROR rust-call ABI is subject to change } fn main() { diff --git a/src/test/ui/feature-gates/feature-gate-unboxed-closures.stderr b/src/test/ui/feature-gates/feature-gate-unboxed-closures.stderr index e7b1fc589bb..872a593f3e4 100644 --- a/src/test/ui/feature-gates/feature-gate-unboxed-closures.stderr +++ b/src/test/ui/feature-gates/feature-gate-unboxed-closures.stderr @@ -1,4 +1,4 @@ -error[E0658]: rust-call ABI is subject to change (see issue #29625) +error[E0658]: rust-call ABI is subject to change --> $DIR/feature-gate-unboxed-closures.rs:9:5 | LL | / extern "rust-call" fn call_once(self, (a, b): (u32, u32)) -> u32 { @@ -6,14 +6,16 @@ LL | | a + b LL | | } | |_____^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add #![feature(unboxed_closures)] to the crate attributes to enable -error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change. Use parenthetical notation (Fn(Foo, Bar) -> Baz) instead (see issue #29625) +error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change. Use parenthetical notation (Fn(Foo, Bar) -> Baz) instead --> $DIR/feature-gate-unboxed-closures.rs:5:6 | LL | impl FnOnce<(u32, u32)> for Test { | ^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add #![feature(unboxed_closures)] to the crate attributes to enable error: aborting due to 2 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-underscore_const_names.stderr b/src/test/ui/feature-gates/feature-gate-underscore_const_names.stderr index ef93bb97ab4..8d925424d8c 100644 --- a/src/test/ui/feature-gates/feature-gate-underscore_const_names.stderr +++ b/src/test/ui/feature-gates/feature-gate-underscore_const_names.stderr @@ -1,4 +1,4 @@ -error[E0658]: naming constants with `_` is unstable (see issue #54912) +error[E0658]: naming constants with `_` is unstable --> $DIR/feature-gate-underscore_const_names.rs:6:1 | LL | / const _ : () = { @@ -10,6 +10,7 @@ LL | | () LL | | }; | |__^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/54912 = help: add #![feature(underscore_const_names)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-unsized_tuple_coercion.stderr b/src/test/ui/feature-gates/feature-gate-unsized_tuple_coercion.stderr index c2f5df48fed..669e87ceada 100644 --- a/src/test/ui/feature-gates/feature-gate-unsized_tuple_coercion.stderr +++ b/src/test/ui/feature-gates/feature-gate-unsized_tuple_coercion.stderr @@ -1,9 +1,10 @@ -error[E0658]: unsized tuple coercion is not stable enough for use and is subject to change (see issue #42877) +error[E0658]: unsized tuple coercion is not stable enough for use and is subject to change --> $DIR/feature-gate-unsized_tuple_coercion.rs:2:24 | LL | let _ : &(Send,) = &((),); | ^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/42877 = help: add #![feature(unsized_tuple_coercion)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr b/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr index 6faa0528dc7..5df3a1d699f 100644 --- a/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr +++ b/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr @@ -1,4 +1,4 @@ -error[E0658]: unions with non-`Copy` fields are unstable (see issue #32836) +error[E0658]: unions with non-`Copy` fields are unstable --> $DIR/feature-gate-untagged_unions.rs:9:1 | LL | / union U3 { @@ -6,9 +6,10 @@ LL | | a: String, LL | | } | |_^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/32836 = help: add #![feature(untagged_unions)] to the crate attributes to enable -error[E0658]: unions with non-`Copy` fields are unstable (see issue #32836) +error[E0658]: unions with non-`Copy` fields are unstable --> $DIR/feature-gate-untagged_unions.rs:13:1 | LL | / union U4<T> { @@ -16,9 +17,10 @@ LL | | a: T, LL | | } | |_^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/32836 = help: add #![feature(untagged_unions)] to the crate attributes to enable -error[E0658]: unions with `Drop` implementations are unstable (see issue #32836) +error[E0658]: unions with `Drop` implementations are unstable --> $DIR/feature-gate-untagged_unions.rs:17:1 | LL | / union U5 { @@ -26,6 +28,7 @@ LL | | a: u8, LL | | } | |_^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/32836 = help: add #![feature(untagged_unions)] to the crate attributes to enable error: aborting due to 3 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-unwind-attributes.stderr b/src/test/ui/feature-gates/feature-gate-unwind-attributes.stderr index 149ce9e4f82..bb55013d638 100644 --- a/src/test/ui/feature-gates/feature-gate-unwind-attributes.stderr +++ b/src/test/ui/feature-gates/feature-gate-unwind-attributes.stderr @@ -1,9 +1,10 @@ -error[E0658]: #[unwind] is experimental (see issue #58760) +error[E0658]: #[unwind] is experimental --> $DIR/feature-gate-unwind-attributes.rs:11:5 | LL | #[unwind(allowed)] | ^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/58760 = help: add #![feature(unwind_attributes)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/feature-gates/underscore_const_names_feature_gate.stderr b/src/test/ui/feature-gates/underscore_const_names_feature_gate.stderr index 83b3017a4cd..0931145a6e2 100644 --- a/src/test/ui/feature-gates/underscore_const_names_feature_gate.stderr +++ b/src/test/ui/feature-gates/underscore_const_names_feature_gate.stderr @@ -1,9 +1,10 @@ -error[E0658]: naming constants with `_` is unstable (see issue #54912) +error[E0658]: naming constants with `_` is unstable --> $DIR/underscore_const_names_feature_gate.rs:1:1 | LL | const _: () = (); | ^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/54912 = help: add #![feature(underscore_const_names)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/fn/fn-compare-mismatch.stderr b/src/test/ui/fn/fn-compare-mismatch.stderr index 07b93d9aae7..74fb00f8ac3 100644 --- a/src/test/ui/fn/fn-compare-mismatch.stderr +++ b/src/test/ui/fn/fn-compare-mismatch.stderr @@ -7,6 +7,14 @@ LL | let x = f == g; | fn() {main::f} | = note: an implementation of `std::cmp::PartialEq` might be missing for `fn() {main::f}` +help: you might have forgotten to call this function + | +LL | let x = f() == g; + | ^^^ +help: you might have forgotten to call this function + | +LL | let x = f == g(); + | ^^^ error[E0308]: mismatched types --> $DIR/fn-compare-mismatch.rs:4:18 diff --git a/src/test/ui/imports/local-modularized-tricky-fail-2.stderr b/src/test/ui/imports/local-modularized-tricky-fail-2.stderr index a26f0cbec72..70d197994f3 100644 --- a/src/test/ui/imports/local-modularized-tricky-fail-2.stderr +++ b/src/test/ui/imports/local-modularized-tricky-fail-2.stderr @@ -1,4 +1,4 @@ -error[E0658]: non-ascii idents are not fully supported. (see issue #55467) +error[E0658]: non-ascii idents are not fully supported --> $DIR/local-modularized-tricky-fail-2.rs:20:32 | LL | exported!(); @@ -7,9 +7,10 @@ LL | exported!(); LL | () => ( struct Б; ) | ^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/55467 = help: add #![feature(non_ascii_idents)] to the crate attributes to enable -error[E0658]: non-ascii idents are not fully supported. (see issue #55467) +error[E0658]: non-ascii idents are not fully supported --> $DIR/local-modularized-tricky-fail-2.rs:36:24 | LL | panic!(); @@ -18,9 +19,10 @@ LL | panic!(); LL | () => ( struct Г; ) | ^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/55467 = help: add #![feature(non_ascii_idents)] to the crate attributes to enable -error[E0658]: non-ascii idents are not fully supported. (see issue #55467) +error[E0658]: non-ascii idents are not fully supported --> $DIR/local-modularized-tricky-fail-2.rs:46:24 | LL | include!(); @@ -29,6 +31,7 @@ LL | include!(); LL | () => ( struct Д; ) | ^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/55467 = help: add #![feature(non_ascii_idents)] to the crate attributes to enable error: aborting due to 3 previous errors diff --git a/src/test/ui/inference/inference_unstable_forced.stderr b/src/test/ui/inference/inference_unstable_forced.stderr index 067bf44bda8..83e27aaf2f8 100644 --- a/src/test/ui/inference/inference_unstable_forced.stderr +++ b/src/test/ui/inference/inference_unstable_forced.stderr @@ -1,9 +1,10 @@ -error[E0658]: use of unstable library feature 'ipu_flatten' (see issue #99999) +error[E0658]: use of unstable library feature 'ipu_flatten' --> $DIR/inference_unstable_forced.rs:11:20 | LL | assert_eq!('x'.ipu_flatten(), 0); | ^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/99999 = help: add #![feature(ipu_flatten)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/issue-59756.fixed b/src/test/ui/issue-59756.fixed new file mode 100644 index 00000000000..7b55d0f17e6 --- /dev/null +++ b/src/test/ui/issue-59756.fixed @@ -0,0 +1,17 @@ +// run-rustfix + +#![allow(warnings)] + +struct A; +struct B; + +fn foo() -> Result<A, B> { + Ok(A) +} + +fn bar() -> Result<A, B> { + foo() + //~^ ERROR try expression alternatives have incompatible types [E0308] +} + +fn main() {} diff --git a/src/test/ui/issue-59756.rs b/src/test/ui/issue-59756.rs new file mode 100644 index 00000000000..cccae396b72 --- /dev/null +++ b/src/test/ui/issue-59756.rs @@ -0,0 +1,17 @@ +// run-rustfix + +#![allow(warnings)] + +struct A; +struct B; + +fn foo() -> Result<A, B> { + Ok(A) +} + +fn bar() -> Result<A, B> { + foo()? + //~^ ERROR try expression alternatives have incompatible types [E0308] +} + +fn main() {} diff --git a/src/test/ui/issue-59756.stderr b/src/test/ui/issue-59756.stderr new file mode 100644 index 00000000000..d46232874fd --- /dev/null +++ b/src/test/ui/issue-59756.stderr @@ -0,0 +1,15 @@ +error[E0308]: try expression alternatives have incompatible types + --> $DIR/issue-59756.rs:13:5 + | +LL | foo()? + | ^^^^^- + | | | + | | help: try removing this `?` + | expected enum `std::result::Result`, found struct `A` + | + = note: expected type `std::result::Result<A, B>` + found type `A` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/issue-59764.rs b/src/test/ui/issue-59764.rs new file mode 100644 index 00000000000..09dee8c2732 --- /dev/null +++ b/src/test/ui/issue-59764.rs @@ -0,0 +1,136 @@ +// aux-build:issue-59764.rs +// compile-flags:--extern issue_59764 +// edition:2018 + +#![allow(warnings)] + +// This tests the suggestion to import macros from the root of a crate. This aims to capture +// the case where a user attempts to import a macro from the definition location instead of the +// root of the crate and the macro is annotated with `#![macro_export]`. + +// Edge cases.. + +mod multiple_imports_same_line_at_end { + use issue_59764::foo::{baz, makro}; + //~^ ERROR unresolved import `issue_59764::foo::makro` [E0432] +} + +mod multiple_imports_multiline_at_end_trailing_comma { + use issue_59764::foo::{ + baz, + makro, //~ ERROR unresolved import `issue_59764::foo::makro` [E0432] + }; +} + +mod multiple_imports_multiline_at_end { + use issue_59764::foo::{ + baz, + makro //~ ERROR unresolved import `issue_59764::foo::makro` [E0432] + }; +} + +mod multiple_imports_same_line_in_middle { + use issue_59764::foo::{baz, makro, foobar}; + //~^ ERROR unresolved import `issue_59764::foo::makro` [E0432] +} + +mod multiple_imports_multiline_in_middle_trailing_comma { + use issue_59764::foo::{ + baz, + makro, //~ ERROR unresolved import `issue_59764::foo::makro` [E0432] + foobar, + }; +} + +mod multiple_imports_multiline_in_middle { + use issue_59764::foo::{ + baz, + makro, //~ ERROR unresolved import `issue_59764::foo::makro` [E0432] + foobar + }; +} + +mod nested_imports { + use issue_59764::{foobaz, foo::makro}; + //~^ ERROR unresolved import `issue_59764::foo::makro` [E0432] +} + +mod nested_multiple_imports { + use issue_59764::{foobaz, foo::{baz, makro}}; + //~^ ERROR unresolved import `issue_59764::foo::makro` [E0432] +} + +mod nested_multiline_multiple_imports_trailing_comma { + use issue_59764::{ + foobaz, + foo::{ + baz, + makro, //~ ERROR unresolved import `issue_59764::foo::makro` [E0432] + }, + }; +} + +mod nested_multiline_multiple_imports { + use issue_59764::{ + foobaz, + foo::{ + baz, + makro //~ ERROR unresolved import `issue_59764::foo::makro` [E0432] + } + }; +} + +mod doubly_nested_multiple_imports { + use issue_59764::{foobaz, foo::{baz, makro, barbaz::{barfoo}}}; + //~^ ERROR unresolved import `issue_59764::foo::makro` [E0432] +} + +mod doubly_multiline_nested_multiple_imports { + use issue_59764::{ + foobaz, + foo::{ + baz, + makro, //~ ERROR unresolved import `issue_59764::foo::makro` [E0432] + barbaz::{ + barfoo, + } + } + }; +} + +mod renamed_import { + use issue_59764::foo::makro as baz; + //~^ ERROR unresolved import `issue_59764::foo::makro` [E0432] +} + +mod renamed_multiple_imports { + use issue_59764::foo::{baz, makro as foobar}; + //~^ ERROR unresolved import `issue_59764::foo::makro` [E0432] +} + +mod lots_of_whitespace { + use + issue_59764::{ + + foobaz, + + + foo::{baz, + + makro as foobar} //~ ERROR unresolved import `issue_59764::foo::makro` [E0432] + + }; +} + +// Simple case.. + +use issue_59764::foo::makro; +//~^ ERROR unresolved import `issue_59764::foo::makro` [E0432] + +makro!(bar); +//~^ ERROR cannot determine resolution for the macro `makro` + +fn main() { + bar(); + //~^ ERROR cannot find function `bar` in this scope [E0425] +} diff --git a/src/test/ui/issue-59764.stderr b/src/test/ui/issue-59764.stderr new file mode 100644 index 00000000000..924e69f5f97 --- /dev/null +++ b/src/test/ui/issue-59764.stderr @@ -0,0 +1,241 @@ +error[E0432]: unresolved import `issue_59764::foo::makro` + --> $DIR/issue-59764.rs:14:33 + | +LL | use issue_59764::foo::{baz, makro}; + | ^^^^^ no `makro` in `foo` + | + = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined +help: a macro with this name exists at the root of the crate + | +LL | use issue_59764::{makro, foo::{baz}}; + | ^^^^^^^^^ --^^ + +error[E0432]: unresolved import `issue_59764::foo::makro` + --> $DIR/issue-59764.rs:21:9 + | +LL | makro, + | ^^^^^ no `makro` in `foo` + | + = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined +help: a macro with this name exists at the root of the crate + | +LL | use issue_59764::{makro, foo::{ +LL | baz, +LL | +LL | }}; + | + +error[E0432]: unresolved import `issue_59764::foo::makro` + --> $DIR/issue-59764.rs:28:9 + | +LL | makro + | ^^^^^ no `makro` in `foo` + | + = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined +help: a macro with this name exists at the root of the crate + | +LL | use issue_59764::{makro, foo::{ +LL | baz, +LL | +LL | }}; + | + +error[E0432]: unresolved import `issue_59764::foo::makro` + --> $DIR/issue-59764.rs:33:33 + | +LL | use issue_59764::foo::{baz, makro, foobar}; + | ^^^^^ no `makro` in `foo` + | + = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined +help: a macro with this name exists at the root of the crate + | +LL | use issue_59764::{makro, foo::{baz, foobar}}; + | ^^^^^^^^^ -- ^^ + +error[E0432]: unresolved import `issue_59764::foo::makro` + --> $DIR/issue-59764.rs:40:9 + | +LL | makro, + | ^^^^^ no `makro` in `foo` + | + = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined +help: a macro with this name exists at the root of the crate + | +LL | use issue_59764::{makro, foo::{ +LL | baz, +LL | +LL | foobar, +LL | }}; + | + +error[E0432]: unresolved import `issue_59764::foo::makro` + --> $DIR/issue-59764.rs:48:9 + | +LL | makro, + | ^^^^^ no `makro` in `foo` + | + = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined +help: a macro with this name exists at the root of the crate + | +LL | use issue_59764::{makro, foo::{ +LL | baz, +LL | +LL | foobar +LL | }}; + | + +error[E0432]: unresolved import `issue_59764::foo::makro` + --> $DIR/issue-59764.rs:54:31 + | +LL | use issue_59764::{foobaz, foo::makro}; + | ^^^^^^^^^^ no `makro` in `foo` + | + = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined +help: a macro with this name exists at the root of the crate + | +LL | use issue_59764::{makro, foobaz}; + | ^^^^^^^ -- + +error[E0432]: unresolved import `issue_59764::foo::makro` + --> $DIR/issue-59764.rs:59:42 + | +LL | use issue_59764::{foobaz, foo::{baz, makro}}; + | ^^^^^ no `makro` in `foo` + | + = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined +help: a macro with this name exists at the root of the crate + | +LL | use issue_59764::{makro, foobaz, foo::{baz}}; + | ^^^^^^^ -- + +error[E0432]: unresolved import `issue_59764::foo::makro` + --> $DIR/issue-59764.rs:68:13 + | +LL | makro, + | ^^^^^ no `makro` in `foo` + | + = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined +help: a macro with this name exists at the root of the crate + | +LL | use issue_59764::{makro, +LL | foobaz, +LL | foo::{ +LL | baz, +LL | + | + +error[E0432]: unresolved import `issue_59764::foo::makro` + --> $DIR/issue-59764.rs:78:13 + | +LL | makro + | ^^^^^ no `makro` in `foo` + | + = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined +help: a macro with this name exists at the root of the crate + | +LL | use issue_59764::{makro, +LL | foobaz, +LL | foo::{ +LL | baz, +LL | + | + +error[E0432]: unresolved import `issue_59764::foo::makro` + --> $DIR/issue-59764.rs:84:42 + | +LL | use issue_59764::{foobaz, foo::{baz, makro, barbaz::{barfoo}}}; + | ^^^^^ no `makro` in `foo` + | + = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined +help: a macro with this name exists at the root of the crate + | +LL | use issue_59764::{makro, foobaz, foo::{baz, barbaz::{barfoo}}}; + | ^^^^^^^ -- + +error[E0432]: unresolved import `issue_59764::foo::makro` + --> $DIR/issue-59764.rs:93:13 + | +LL | makro, + | ^^^^^ no `makro` in `foo` + | + = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined +help: a macro with this name exists at the root of the crate + | +LL | use issue_59764::{makro, +LL | foobaz, +LL | foo::{ +LL | baz, +LL | + | + +error[E0432]: unresolved import `issue_59764::foo::makro` + --> $DIR/issue-59764.rs:102:9 + | +LL | use issue_59764::foo::makro as baz; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `makro` in `foo` + | + = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined +help: a macro with this name exists at the root of the crate + | +LL | use issue_59764::makro as baz; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0432]: unresolved import `issue_59764::foo::makro` + --> $DIR/issue-59764.rs:107:33 + | +LL | use issue_59764::foo::{baz, makro as foobar}; + | ^^^^^^^^^^^^^^^ no `makro` in `foo` + | + = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined +help: a macro with this name exists at the root of the crate + | +LL | use issue_59764::{makro as foobar, foo::{baz}}; + | ^^^^^^^^^^^^^^^^^^^ --^^ + +error[E0432]: unresolved import `issue_59764::foo::makro` + --> $DIR/issue-59764.rs:120:17 + | +LL | makro as foobar} + | ^^^^^^^^^^^^^^^ no `makro` in `foo` + | + = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined +help: a macro with this name exists at the root of the crate + | +LL | issue_59764::{makro as foobar, +LL | +LL | foobaz, +LL | +LL | +LL | foo::{baz} + | + +error[E0432]: unresolved import `issue_59764::foo::makro` + --> $DIR/issue-59764.rs:127:5 + | +LL | use issue_59764::foo::makro; + | ^^^^^^^^^^^^^^^^^^^^^^^ no `makro` in `foo` + | + = note: this could be because a macro annotated with `#[macro_export]` will be exported at the root of the crate instead of the module where it is defined +help: a macro with this name exists at the root of the crate + | +LL | use issue_59764::makro; + | ^^^^^^^^^^^^^^^^^^ + +error: cannot determine resolution for the macro `makro` + --> $DIR/issue-59764.rs:130:1 + | +LL | makro!(bar); + | ^^^^^ + | + = note: import resolution is stuck, try simplifying macro imports + +error[E0425]: cannot find function `bar` in this scope + --> $DIR/issue-59764.rs:134:5 + | +LL | bar(); + | ^^^ not found in this scope + +error: aborting due to 18 previous errors + +Some errors occurred: E0425, E0432. +For more information about an error, try `rustc --explain E0425`. diff --git a/src/test/ui/issues/issue-17458.stderr b/src/test/ui/issues/issue-17458.stderr index a1a8ed9f0cd..69b6ab71e50 100644 --- a/src/test/ui/issues/issue-17458.stderr +++ b/src/test/ui/issues/issue-17458.stderr @@ -1,9 +1,10 @@ -error[E0658]: casting pointers to integers in statics is unstable (see issue #51910) +error[E0658]: casting pointers to integers in statics is unstable --> $DIR/issue-17458.rs:1:28 | LL | static X: usize = unsafe { 0 as *const usize as usize }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/51910 = help: add #![feature(const_raw_ptr_to_usize_cast)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/issues/issue-18294.stderr b/src/test/ui/issues/issue-18294.stderr index a7d0392f7f0..d10242434b0 100644 --- a/src/test/ui/issues/issue-18294.stderr +++ b/src/test/ui/issues/issue-18294.stderr @@ -1,9 +1,10 @@ -error[E0658]: casting pointers to integers in constants is unstable (see issue #51910) +error[E0658]: casting pointers to integers in constants is unstable --> $DIR/issue-18294.rs:3:31 | LL | const Y: usize = unsafe { &X as *const u32 as usize }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/51910 = help: add #![feature(const_raw_ptr_to_usize_cast)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20313.stderr b/src/test/ui/issues/issue-20313.stderr index 87e2e899d3f..405e717c358 100644 --- a/src/test/ui/issues/issue-20313.stderr +++ b/src/test/ui/issues/issue-20313.stderr @@ -1,9 +1,10 @@ -error[E0658]: linking to LLVM intrinsics is experimental (see issue #29602) +error[E0658]: linking to LLVM intrinsics is experimental --> $DIR/issue-20313.rs:3:5 | LL | fn sqrt(x: f32) -> f32; | ^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29602 = help: add #![feature(link_llvm_intrinsics)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/issues/issue-22933-2.rs b/src/test/ui/issues/issue-22933-2.rs index 68d9ef2cfa8..98a354b1bd0 100644 --- a/src/test/ui/issues/issue-22933-2.rs +++ b/src/test/ui/issues/issue-22933-2.rs @@ -2,7 +2,7 @@ enum Delicious { Pie = 0x1, Apple = 0x2, ApplePie = Delicious::Apple as isize | Delicious::PIE as isize, - //~^ ERROR no variant named `PIE` found for type `Delicious` + //~^ ERROR no variant or associated item named `PIE` found for type `Delicious` } fn main() {} diff --git a/src/test/ui/issues/issue-22933-2.stderr b/src/test/ui/issues/issue-22933-2.stderr index 23b1474bde7..72038ea20a3 100644 --- a/src/test/ui/issues/issue-22933-2.stderr +++ b/src/test/ui/issues/issue-22933-2.stderr @@ -1,11 +1,11 @@ -error[E0599]: no variant named `PIE` found for type `Delicious` in the current scope +error[E0599]: no variant or associated item named `PIE` found for type `Delicious` in the current scope --> $DIR/issue-22933-2.rs:4:55 | LL | enum Delicious { - | -------------- variant `PIE` not found here + | -------------- variant or associated item `PIE` not found here ... LL | ApplePie = Delicious::Apple as isize | Delicious::PIE as isize, - | ^^^ variant not found in `Delicious` + | ^^^ variant or associated item not found in `Delicious` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-23024.stderr b/src/test/ui/issues/issue-23024.stderr index a972b36b804..0567dcbec6d 100644 --- a/src/test/ui/issues/issue-23024.stderr +++ b/src/test/ui/issues/issue-23024.stderr @@ -1,9 +1,10 @@ -error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change. Use parenthetical notation (Fn(Foo, Bar) -> Baz) instead (see issue #29625) +error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change. Use parenthetical notation (Fn(Foo, Bar) -> Baz) instead --> $DIR/issue-23024.rs:9:35 | LL | println!("{:?}",(vfnfer[0] as Fn)(3)); | ^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add #![feature(unboxed_closures)] to the crate attributes to enable error[E0107]: wrong number of type arguments: expected 1, found 0 diff --git a/src/test/ui/issues/issue-23173.rs b/src/test/ui/issues/issue-23173.rs index 2922ebddf4c..7c15598448d 100644 --- a/src/test/ui/issues/issue-23173.rs +++ b/src/test/ui/issues/issue-23173.rs @@ -6,12 +6,8 @@ struct Struct { fn use_token(token: &Token) { unimplemented!() } fn main() { - use_token(&Token::Homura); - //~^ ERROR no variant named `Homura` - Struct::method(); - //~^ ERROR no function or associated item named `method` found for type - Struct::method; - //~^ ERROR no function or associated item named `method` found for type - Struct::Assoc; - //~^ ERROR no associated item named `Assoc` found for type `Struct` in + use_token(&Token::Homura); //~ ERROR no variant or associated item named `Homura` + Struct::method(); //~ ERROR no function or associated item named `method` found for type + Struct::method; //~ ERROR no function or associated item named `method` found for type + Struct::Assoc; //~ ERROR no associated item named `Assoc` found for type `Struct` in } diff --git a/src/test/ui/issues/issue-23173.stderr b/src/test/ui/issues/issue-23173.stderr index 75dba883608..699e41156fa 100644 --- a/src/test/ui/issues/issue-23173.stderr +++ b/src/test/ui/issues/issue-23173.stderr @@ -1,14 +1,14 @@ -error[E0599]: no variant named `Homura` found for type `Token` in the current scope +error[E0599]: no variant or associated item named `Homura` found for type `Token` in the current scope --> $DIR/issue-23173.rs:9:23 | LL | enum Token { LeftParen, RightParen, Plus, Minus, /* etc */ } - | ---------- variant `Homura` not found here + | ---------- variant or associated item `Homura` not found here ... LL | use_token(&Token::Homura); - | ^^^^^^ variant not found in `Token` + | ^^^^^^ variant or associated item not found in `Token` error[E0599]: no function or associated item named `method` found for type `Struct` in the current scope - --> $DIR/issue-23173.rs:11:13 + --> $DIR/issue-23173.rs:10:13 | LL | struct Struct { | ------------- function or associated item `method` not found for this @@ -17,7 +17,7 @@ LL | Struct::method(); | ^^^^^^ function or associated item not found in `Struct` error[E0599]: no function or associated item named `method` found for type `Struct` in the current scope - --> $DIR/issue-23173.rs:13:13 + --> $DIR/issue-23173.rs:11:13 | LL | struct Struct { | ------------- function or associated item `method` not found for this @@ -26,7 +26,7 @@ LL | Struct::method; | ^^^^^^ function or associated item not found in `Struct` error[E0599]: no associated item named `Assoc` found for type `Struct` in the current scope - --> $DIR/issue-23173.rs:15:13 + --> $DIR/issue-23173.rs:12:13 | LL | struct Struct { | ------------- associated item `Assoc` not found for this diff --git a/src/test/ui/issues/issue-23217.rs b/src/test/ui/issues/issue-23217.rs index 11426df6177..157f20d22d8 100644 --- a/src/test/ui/issues/issue-23217.rs +++ b/src/test/ui/issues/issue-23217.rs @@ -1,6 +1,5 @@ pub enum SomeEnum { - B = SomeEnum::A, - //~^ ERROR no variant named `A` found for type `SomeEnum` + B = SomeEnum::A, //~ ERROR no variant or associated item named `A` found for type `SomeEnum` } fn main() {} diff --git a/src/test/ui/issues/issue-23217.stderr b/src/test/ui/issues/issue-23217.stderr index 2a982422cab..97100ed3753 100644 --- a/src/test/ui/issues/issue-23217.stderr +++ b/src/test/ui/issues/issue-23217.stderr @@ -1,13 +1,13 @@ -error[E0599]: no variant named `A` found for type `SomeEnum` in the current scope +error[E0599]: no variant or associated item named `A` found for type `SomeEnum` in the current scope --> $DIR/issue-23217.rs:2:19 | LL | pub enum SomeEnum { - | ----------------- variant `A` not found here + | ----------------- variant or associated item `A` not found here LL | B = SomeEnum::A, | ^ | | - | variant not found in `SomeEnum` - | help: did you mean: `B` + | variant or associated item not found in `SomeEnum` + | help: there is a variant with a similar name: `B` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-23302-1.stderr b/src/test/ui/issues/issue-23302-1.stderr index 43effc0b3b9..bbdb13a9500 100644 --- a/src/test/ui/issues/issue-23302-1.stderr +++ b/src/test/ui/issues/issue-23302-1.stderr @@ -5,7 +5,7 @@ LL | A = X::A as isize, | ^^^^^^^^^^^^^ | = note: ...which again requires processing `X::A::{{constant}}#0`, completing the cycle -note: cycle used when const-evaluating `X::A::{{constant}}#0` +note: cycle used when processing `X::A::{{constant}}#0` --> $DIR/issue-23302-1.rs:4:9 | LL | A = X::A as isize, diff --git a/src/test/ui/issues/issue-23302-2.stderr b/src/test/ui/issues/issue-23302-2.stderr index 707d4fa7ed3..03afd82211a 100644 --- a/src/test/ui/issues/issue-23302-2.stderr +++ b/src/test/ui/issues/issue-23302-2.stderr @@ -5,7 +5,7 @@ LL | A = Y::B as isize, | ^^^^^^^^^^^^^ | = note: ...which again requires processing `Y::A::{{constant}}#0`, completing the cycle -note: cycle used when const-evaluating `Y::A::{{constant}}#0` +note: cycle used when processing `Y::A::{{constant}}#0` --> $DIR/issue-23302-2.rs:4:9 | LL | A = Y::B as isize, diff --git a/src/test/ui/issues/issue-25826.stderr b/src/test/ui/issues/issue-25826.stderr index dc547f7c32c..a800f787e38 100644 --- a/src/test/ui/issues/issue-25826.stderr +++ b/src/test/ui/issues/issue-25826.stderr @@ -1,9 +1,10 @@ -error[E0658]: comparing raw pointers inside constant (see issue #53020) +error[E0658]: comparing raw pointers inside constant --> $DIR/issue-25826.rs:3:30 | LL | const A: bool = unsafe { id::<u8> as *const () < id::<u16> as *const () }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/53020 = help: add #![feature(const_compare_raw_pointers)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/issues/issue-28344.stderr b/src/test/ui/issues/issue-28344.stderr index fcd98b111cf..f3a8019e232 100644 --- a/src/test/ui/issues/issue-28344.stderr +++ b/src/test/ui/issues/issue-28344.stderr @@ -11,7 +11,7 @@ LL | let x: u8 = BitXor::bitor(0 as u8, 0 as u8); | ^^^^^ | | | function or associated item not found in `dyn std::ops::BitXor<_>` - | help: did you mean: `bitxor` + | help: there is a method with a similar name: `bitxor` error[E0191]: the value of the associated type `Output` (from the trait `std::ops::BitXor`) must be specified --> $DIR/issue-28344.rs:8:13 @@ -26,7 +26,7 @@ LL | let g = BitXor::bitor; | ^^^^^ | | | function or associated item not found in `dyn std::ops::BitXor<_>` - | help: did you mean: `bitxor` + | help: there is a method with a similar name: `bitxor` error: aborting due to 4 previous errors diff --git a/src/test/ui/issues/issue-28971.rs b/src/test/ui/issues/issue-28971.rs index 3f0d2fafb04..6493565d216 100644 --- a/src/test/ui/issues/issue-28971.rs +++ b/src/test/ui/issues/issue-28971.rs @@ -1,5 +1,3 @@ -// This should not cause an ICE - enum Foo { Bar(u8) } @@ -7,7 +5,7 @@ fn main(){ foo(|| { match Foo::Bar(1) { Foo::Baz(..) => (), - //~^ ERROR no variant named `Baz` found for type `Foo` + //~^ ERROR no variant or associated item named `Baz` found for type `Foo` _ => (), } }); diff --git a/src/test/ui/issues/issue-28971.stderr b/src/test/ui/issues/issue-28971.stderr index 4781f7abe81..7411896443d 100644 --- a/src/test/ui/issues/issue-28971.stderr +++ b/src/test/ui/issues/issue-28971.stderr @@ -1,14 +1,14 @@ -error[E0599]: no variant named `Baz` found for type `Foo` in the current scope - --> $DIR/issue-28971.rs:9:18 +error[E0599]: no variant or associated item named `Baz` found for type `Foo` in the current scope + --> $DIR/issue-28971.rs:7:18 | LL | enum Foo { - | -------- variant `Baz` not found here + | -------- variant or associated item `Baz` not found here ... LL | Foo::Baz(..) => (), | ^^^ | | - | variant not found in `Foo` - | help: did you mean: `Bar` + | variant or associated item not found in `Foo` + | help: there is a variant with a similar name: `Bar` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-30560.rs b/src/test/ui/issues/issue-30560.rs index c848a1c51ca..d8d4ca608f1 100644 --- a/src/test/ui/issues/issue-30560.rs +++ b/src/test/ui/issues/issue-30560.rs @@ -1,10 +1,7 @@ type Alias = (); -use Alias::*; -//~^ ERROR unresolved import `Alias` [E0432] -//~| not a module `Alias` -use std::io::Result::*; -//~^ ERROR unresolved import `std::io::Result` [E0432] -//~| not a module `Result` +use Alias::*; //~ ERROR unresolved import `Alias` [E0432] + +use std::io::Result::*; //~ ERROR unresolved import `std::io::Result` [E0432] trait T {} use T::*; //~ ERROR items in traits are not importable diff --git a/src/test/ui/issues/issue-30560.stderr b/src/test/ui/issues/issue-30560.stderr index 5225f190f9e..b74134aaccc 100644 --- a/src/test/ui/issues/issue-30560.stderr +++ b/src/test/ui/issues/issue-30560.stderr @@ -1,5 +1,5 @@ error: items in traits are not importable. - --> $DIR/issue-30560.rs:10:5 + --> $DIR/issue-30560.rs:7:5 | LL | use T::*; | ^^^^ @@ -8,13 +8,13 @@ error[E0432]: unresolved import `Alias` --> $DIR/issue-30560.rs:2:5 | LL | use Alias::*; - | ^^^^^ not a module `Alias` + | ^^^^^ `Alias` is a type alias, not a module error[E0432]: unresolved import `std::io::Result` - --> $DIR/issue-30560.rs:5:14 + --> $DIR/issue-30560.rs:4:14 | LL | use std::io::Result::*; - | ^^^^^^ not a module `Result` + | ^^^^^^ `Result` is a type alias, not a module error: aborting due to 3 previous errors diff --git a/src/test/ui/issues/issue-32655.stderr b/src/test/ui/issues/issue-32655.stderr index 7b3c8e75beb..3ab934f6ca5 100644 --- a/src/test/ui/issues/issue-32655.stderr +++ b/src/test/ui/issues/issue-32655.stderr @@ -1,4 +1,4 @@ -error[E0658]: The attribute `derive_Clone` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `derive_Clone` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/issue-32655.rs:6:11 | LL | #[derive_Clone] @@ -7,14 +7,16 @@ LL | #[derive_Clone] LL | foo!(); | ------- in this macro invocation | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `derive_Clone` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `derive_Clone` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/issue-32655.rs:18:7 | LL | #[derive_Clone] | ^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-32829.stderr b/src/test/ui/issues/issue-32829.stderr index 037f5416fa5..157c8c85af0 100644 --- a/src/test/ui/issues/issue-32829.stderr +++ b/src/test/ui/issues/issue-32829.stderr @@ -1,9 +1,10 @@ -error[E0658]: panicking in statics is unstable (see issue #51999) +error[E0658]: panicking in statics is unstable --> $DIR/issue-32829.rs:1:22 | LL | static S : u64 = { { panic!("foo"); 0 } }; | ^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/51999 = help: add #![feature(const_panic)] to the crate attributes to enable = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) diff --git a/src/test/ui/issues/issue-34209.rs b/src/test/ui/issues/issue-34209.rs index 50095be7740..fc2c3679e13 100644 --- a/src/test/ui/issues/issue-34209.rs +++ b/src/test/ui/issues/issue-34209.rs @@ -4,8 +4,7 @@ enum S { fn bug(l: S) { match l { - S::B { } => { }, - //~^ ERROR no variant `B` on enum `S` + S::B {} => {}, //~ ERROR no variant `B` in enum `S` } } diff --git a/src/test/ui/issues/issue-34209.stderr b/src/test/ui/issues/issue-34209.stderr index 79aba89c148..194bb2bfab8 100644 --- a/src/test/ui/issues/issue-34209.stderr +++ b/src/test/ui/issues/issue-34209.stderr @@ -1,8 +1,11 @@ -error: no variant `B` on enum `S` - --> $DIR/issue-34209.rs:7:9 +error: no variant `B` in enum `S` + --> $DIR/issue-34209.rs:7:12 | -LL | S::B { } => { }, - | ^^^^ help: did you mean: `S::A` +LL | enum S { + | ------ variant `B` not found here +... +LL | S::B {} => {}, + | ^ help: there is a variant with a similar name: `A` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-36163.stderr b/src/test/ui/issues/issue-36163.stderr index 4c3f726180d..50e8cf6e88c 100644 --- a/src/test/ui/issues/issue-36163.stderr +++ b/src/test/ui/issues/issue-36163.stderr @@ -10,7 +10,7 @@ note: ...which requires processing `A`... LL | const A: isize = Foo::B as isize; | ^^^^^^^^^^^^^^^ = note: ...which again requires processing `Foo::B::{{constant}}#0`, completing the cycle -note: cycle used when const-evaluating `Foo::B::{{constant}}#0` +note: cycle used when processing `Foo::B::{{constant}}#0` --> $DIR/issue-36163.rs:4:9 | LL | B = A, diff --git a/src/test/ui/issues/issue-37887.stderr b/src/test/ui/issues/issue-37887.stderr index 24543a5efaf..9cac105bab5 100644 --- a/src/test/ui/issues/issue-37887.stderr +++ b/src/test/ui/issues/issue-37887.stderr @@ -4,12 +4,13 @@ error[E0432]: unresolved import `libc` LL | use libc::*; | ^^^^ maybe a missing `extern crate libc;`? -error[E0658]: use of unstable library feature 'rustc_private': this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead? (see issue #27812) +error[E0658]: use of unstable library feature 'rustc_private': this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead? --> $DIR/issue-37887.rs:2:5 | LL | extern crate libc; | ^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/27812 = help: add #![feature(rustc_private)] to the crate attributes to enable error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-49074.stderr b/src/test/ui/issues/issue-49074.stderr index b41d9130f12..29e10f1bf41 100644 --- a/src/test/ui/issues/issue-49074.stderr +++ b/src/test/ui/issues/issue-49074.stderr @@ -1,9 +1,10 @@ -error[E0658]: The attribute `marco_use` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `marco_use` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/issue-49074.rs:3:3 | LL | #[marco_use] // typo | ^^^^^^^^^ help: a built-in attribute with a similar name exists: `macro_use` | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable error: cannot find macro `bar!` in this scope diff --git a/src/test/ui/issues/issue-50264-inner-deref-trait/result-deref-err.stderr b/src/test/ui/issues/issue-50264-inner-deref-trait/result-deref-err.stderr index 96d6814b0fe..333036127ea 100644 --- a/src/test/ui/issues/issue-50264-inner-deref-trait/result-deref-err.stderr +++ b/src/test/ui/issues/issue-50264-inner-deref-trait/result-deref-err.stderr @@ -2,7 +2,7 @@ error[E0599]: no method named `deref_err` found for type `std::result::Result<_, --> $DIR/result-deref-err.rs:4:28 | LL | let _result = &Err(41).deref_err(); - | ^^^^^^^^^ help: did you mean: `deref_ok` + | ^^^^^^^^^ help: there is a method with a similar name: `deref_ok` | = note: the method `deref_err` exists but the following trait bounds were not satisfied: `{integer} : std::ops::Deref` diff --git a/src/test/ui/issues/issue-51279.stderr b/src/test/ui/issues/issue-51279.stderr index bc33eacac99..9dd4a9f2381 100644 --- a/src/test/ui/issues/issue-51279.stderr +++ b/src/test/ui/issues/issue-51279.stderr @@ -46,12 +46,13 @@ error: #[cfg] cannot be applied on a generic parameter LL | type Z<#[ignored] 'a, #[cfg(none)] T> = X<'a, T>; | ^^^^^^^^^^^^ -error[E0658]: The attribute `ignored` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `ignored` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/issue-51279.rs:23:8 | LL | type Z<#[ignored] 'a, #[cfg(none)] T> = X<'a, T>; | ^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable error: aborting due to 9 previous errors diff --git a/src/test/ui/issues/issue-51632-try-desugar-incompatible-types.stderr b/src/test/ui/issues/issue-51632-try-desugar-incompatible-types.stderr index 8f36a3f9618..bf453571479 100644 --- a/src/test/ui/issues/issue-51632-try-desugar-incompatible-types.stderr +++ b/src/test/ui/issues/issue-51632-try-desugar-incompatible-types.stderr @@ -2,7 +2,10 @@ error[E0308]: try expression alternatives have incompatible types --> $DIR/issue-51632-try-desugar-incompatible-types.rs:8:5 | LL | missing_discourses()? - | ^^^^^^^^^^^^^^^^^^^^^ expected enum `std::result::Result`, found isize + | ^^^^^^^^^^^^^^^^^^^^- + | | | + | | help: try removing this `?` + | expected enum `std::result::Result`, found isize | = note: expected type `std::result::Result<isize, ()>` found type `isize` diff --git a/src/test/ui/issues/issue-51714.rs b/src/test/ui/issues/issue-51714.rs index 4885e4a2db7..0dc588d75c6 100644 --- a/src/test/ui/issues/issue-51714.rs +++ b/src/test/ui/issues/issue-51714.rs @@ -10,5 +10,4 @@ fn main() { [(); return while let Some(n) = Some(0) {}]; //~^ ERROR return statement outside of function body - //~^^ WARN irrefutable while-let pattern } diff --git a/src/test/ui/issues/issue-51714.stderr b/src/test/ui/issues/issue-51714.stderr index df11f6b7f5a..023d9013ab4 100644 --- a/src/test/ui/issues/issue-51714.stderr +++ b/src/test/ui/issues/issue-51714.stderr @@ -22,14 +22,6 @@ error[E0572]: return statement outside of function body LL | [(); return while let Some(n) = Some(0) {}]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -warning: irrefutable while-let pattern - --> $DIR/issue-51714.rs:11:17 - | -LL | [(); return while let Some(n) = Some(0) {}]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: #[warn(irrefutable_let_patterns)] on by default - error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0572`. diff --git a/src/test/ui/issues/issue-52023-array-size-pointer-cast.stderr b/src/test/ui/issues/issue-52023-array-size-pointer-cast.stderr index 60e0792954a..f57697e5892 100644 --- a/src/test/ui/issues/issue-52023-array-size-pointer-cast.stderr +++ b/src/test/ui/issues/issue-52023-array-size-pointer-cast.stderr @@ -1,9 +1,10 @@ -error[E0658]: casting pointers to integers in constants is unstable (see issue #51910) +error[E0658]: casting pointers to integers in constants is unstable --> $DIR/issue-52023-array-size-pointer-cast.rs:2:17 | LL | let _ = [0; (&0 as *const i32) as usize]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/51910 = help: add #![feature(const_raw_ptr_to_usize_cast)] to the crate attributes to enable error[E0080]: it is undefined behavior to use this value diff --git a/src/test/ui/issues/issue-54974.rs b/src/test/ui/issues/issue-54974.rs new file mode 100644 index 00000000000..b2624ec92a1 --- /dev/null +++ b/src/test/ui/issues/issue-54974.rs @@ -0,0 +1,16 @@ +// compile-pass +// edition:2018 + +#![feature(async_await, await_macro, futures_api)] + +use std::sync::Arc; + +trait SomeTrait: Send + Sync + 'static { + fn do_something(&self); +} + +async fn my_task(obj: Arc<SomeTrait>) { + unimplemented!() +} + +fn main() {} diff --git a/src/test/ui/issues/issue-55324.rs b/src/test/ui/issues/issue-55324.rs new file mode 100644 index 00000000000..6160fbabd96 --- /dev/null +++ b/src/test/ui/issues/issue-55324.rs @@ -0,0 +1,14 @@ +// compile-pass +// edition:2018 + +#![feature(async_await, await_macro, futures_api)] + +use std::future::Future; + +#[allow(unused)] +async fn foo<F: Future<Output = i32>>(x: &i32, future: F) -> i32 { + let y = await!(future); + *x + y +} + +fn main() {} diff --git a/src/test/ui/issues/issue-58885.rs b/src/test/ui/issues/issue-58885.rs new file mode 100644 index 00000000000..559899194fb --- /dev/null +++ b/src/test/ui/issues/issue-58885.rs @@ -0,0 +1,21 @@ +// compile-pass +// edition:2018 + +#![feature(async_await, await_macro, futures_api)] + +struct Xyz { + a: u64, +} + +trait Foo {} + +impl Xyz { + async fn do_sth<'a>( + &'a self, foo: &'a dyn Foo + ) -> bool + { + true + } +} + +fn main() {} diff --git a/src/test/ui/issues/issue-59001.rs b/src/test/ui/issues/issue-59001.rs new file mode 100644 index 00000000000..a310653fbce --- /dev/null +++ b/src/test/ui/issues/issue-59001.rs @@ -0,0 +1,17 @@ +// compile-pass +// edition:2018 + +#![feature(async_await, await_macro, futures_api)] + +use std::future::Future; + +#[allow(unused)] +async fn enter<'a, F, R>(mut callback: F) +where + F: FnMut(&'a mut i32) -> R, + R: Future<Output = ()> + 'a, +{ + unimplemented!() +} + +fn main() {} diff --git a/src/test/ui/issues/issue-59488.rs b/src/test/ui/issues/issue-59488.rs new file mode 100644 index 00000000000..27cf16a821f --- /dev/null +++ b/src/test/ui/issues/issue-59488.rs @@ -0,0 +1,26 @@ +// ignore-tidy-linelength + +fn foo() -> i32 { + 42 +} + +fn bar(a: i64) -> i64 { + 43 +} + +fn main() { + foo > 12; + //~^ ERROR 12:9: 12:10: binary operation `>` cannot be applied to type `fn() -> i32 {foo}` [E0369] + //~| ERROR 12:11: 12:13: mismatched types [E0308] + + bar > 13; + //~^ ERROR 16:9: 16:10: binary operation `>` cannot be applied to type `fn(i64) -> i64 {bar}` [E0369] + //~| ERROR 16:11: 16:13: mismatched types [E0308] + + foo > foo; + //~^ ERROR 20:9: 20:10: binary operation `>` cannot be applied to type `fn() -> i32 {foo}` [E0369] + + foo > bar; + //~^ ERROR 23:9: 23:10: binary operation `>` cannot be applied to type `fn() -> i32 {foo}` [E0369] + //~| ERROR 23:11: 23:14: mismatched types [E0308] +} diff --git a/src/test/ui/issues/issue-59488.stderr b/src/test/ui/issues/issue-59488.stderr new file mode 100644 index 00000000000..b49f5e35f42 --- /dev/null +++ b/src/test/ui/issues/issue-59488.stderr @@ -0,0 +1,81 @@ +error[E0369]: binary operation `>` cannot be applied to type `fn() -> i32 {foo}` + --> $DIR/issue-59488.rs:12:9 + | +LL | foo > 12; + | --- ^ -- {integer} + | | + | fn() -> i32 {foo} + | help: you might have forgotten to call this function: `foo()` + | + = note: an implementation of `std::cmp::PartialOrd` might be missing for `fn() -> i32 {foo}` + +error[E0308]: mismatched types + --> $DIR/issue-59488.rs:12:11 + | +LL | foo > 12; + | ^^ expected fn item, found integer + | + = note: expected type `fn() -> i32 {foo}` + found type `i32` + +error[E0369]: binary operation `>` cannot be applied to type `fn(i64) -> i64 {bar}` + --> $DIR/issue-59488.rs:16:9 + | +LL | bar > 13; + | --- ^ -- {integer} + | | + | fn(i64) -> i64 {bar} + | help: you might have forgotten to call this function: `bar( /* arguments */ )` + | + = note: an implementation of `std::cmp::PartialOrd` might be missing for `fn(i64) -> i64 {bar}` + +error[E0308]: mismatched types + --> $DIR/issue-59488.rs:16:11 + | +LL | bar > 13; + | ^^ expected fn item, found integer + | + = note: expected type `fn(i64) -> i64 {bar}` + found type `i64` + +error[E0369]: binary operation `>` cannot be applied to type `fn() -> i32 {foo}` + --> $DIR/issue-59488.rs:20:9 + | +LL | foo > foo; + | --- ^ --- fn() -> i32 {foo} + | | + | fn() -> i32 {foo} + | + = note: an implementation of `std::cmp::PartialOrd` might be missing for `fn() -> i32 {foo}` +help: you might have forgotten to call this function + | +LL | foo() > foo; + | ^^^^^ +help: you might have forgotten to call this function + | +LL | foo > foo(); + | ^^^^^ + +error[E0369]: binary operation `>` cannot be applied to type `fn() -> i32 {foo}` + --> $DIR/issue-59488.rs:23:9 + | +LL | foo > bar; + | --- ^ --- fn(i64) -> i64 {bar} + | | + | fn() -> i32 {foo} + | + = note: an implementation of `std::cmp::PartialOrd` might be missing for `fn() -> i32 {foo}` + +error[E0308]: mismatched types + --> $DIR/issue-59488.rs:23:11 + | +LL | foo > bar; + | ^^^ expected fn item, found a different fn item + | + = note: expected type `fn() -> i32 {foo}` + found type `fn(i64) -> i64 {bar}` + +error: aborting due to 7 previous errors + +Some errors occurred: E0308, E0369. +For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/linkage4.stderr b/src/test/ui/linkage4.stderr index fd86671204e..f2aab164bd7 100644 --- a/src/test/ui/linkage4.stderr +++ b/src/test/ui/linkage4.stderr @@ -1,9 +1,10 @@ -error[E0658]: the `linkage` attribute is experimental and not portable across platforms (see issue #29603) +error[E0658]: the `linkage` attribute is experimental and not portable across platforms --> $DIR/linkage4.rs:1:1 | LL | #[linkage = "external"] | ^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29603 = help: add #![feature(linkage)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/macros/macro-multiple-matcher-bindings.rs b/src/test/ui/macros/macro-multiple-matcher-bindings.rs index 23d566780c8..7d39dc0a52f 100644 --- a/src/test/ui/macros/macro-multiple-matcher-bindings.rs +++ b/src/test/ui/macros/macro-multiple-matcher-bindings.rs @@ -1,16 +1,11 @@ // Test that duplicate matcher binding names are caught at declaration time, rather than at macro // invocation time. -// -// FIXME(mark-i-m): Update this when it becomes a hard error. - -// compile-pass #![allow(unused_macros)] -#![warn(duplicate_matcher_binding_name)] macro_rules! foo1 { - ($a:ident, $a:ident) => {}; //~WARNING duplicate matcher binding - ($a:ident, $a:path) => {}; //~WARNING duplicate matcher binding + ($a:ident, $a:ident) => {}; //~ERROR duplicate matcher binding + ($a:ident, $a:path) => {}; //~ERROR duplicate matcher binding } macro_rules! foo2 { @@ -19,8 +14,8 @@ macro_rules! foo2 { } macro_rules! foo3 { - ($a:ident, $($a:ident),*) => {}; //~WARNING duplicate matcher binding - ($($a:ident)+ # $($($a:path),+);*) => {}; //~WARNING duplicate matcher binding + ($a:ident, $($a:ident),*) => {}; //~ERROR duplicate matcher binding + ($($a:ident)+ # $($($a:path),+);*) => {}; //~ERROR duplicate matcher binding } fn main() {} diff --git a/src/test/ui/macros/macro-multiple-matcher-bindings.stderr b/src/test/ui/macros/macro-multiple-matcher-bindings.stderr index f7970dbd2eb..65362388d7d 100644 --- a/src/test/ui/macros/macro-multiple-matcher-bindings.stderr +++ b/src/test/ui/macros/macro-multiple-matcher-bindings.stderr @@ -1,41 +1,50 @@ -warning: duplicate matcher binding - --> $DIR/macro-multiple-matcher-bindings.rs:12:6 +error: duplicate matcher binding + --> $DIR/macro-multiple-matcher-bindings.rs:7:16 | LL | ($a:ident, $a:ident) => {}; - | ^^^^^^^^ ^^^^^^^^ + | ^^^^^^^^ | -note: lint level defined here - --> $DIR/macro-multiple-matcher-bindings.rs:9:9 +note: previous declaration was here + --> $DIR/macro-multiple-matcher-bindings.rs:7:6 | -LL | #![warn(duplicate_matcher_binding_name)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #57593 <https://github.com/rust-lang/rust/issues/57593> +LL | ($a:ident, $a:ident) => {}; + | ^^^^^^^^ -warning: duplicate matcher binding - --> $DIR/macro-multiple-matcher-bindings.rs:13:6 +error: duplicate matcher binding + --> $DIR/macro-multiple-matcher-bindings.rs:8:16 | LL | ($a:ident, $a:path) => {}; - | ^^^^^^^^ ^^^^^^^ + | ^^^^^^^ + | +note: previous declaration was here + --> $DIR/macro-multiple-matcher-bindings.rs:8:6 | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #57593 <https://github.com/rust-lang/rust/issues/57593> +LL | ($a:ident, $a:path) => {}; + | ^^^^^^^^ -warning: duplicate matcher binding - --> $DIR/macro-multiple-matcher-bindings.rs:22:6 +error: duplicate matcher binding + --> $DIR/macro-multiple-matcher-bindings.rs:17:18 | LL | ($a:ident, $($a:ident),*) => {}; - | ^^^^^^^^ ^^^^^^^^ + | ^^^^^^^^ + | +note: previous declaration was here + --> $DIR/macro-multiple-matcher-bindings.rs:17:6 | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #57593 <https://github.com/rust-lang/rust/issues/57593> +LL | ($a:ident, $($a:ident),*) => {}; + | ^^^^^^^^ -warning: duplicate matcher binding - --> $DIR/macro-multiple-matcher-bindings.rs:23:8 +error: duplicate matcher binding + --> $DIR/macro-multiple-matcher-bindings.rs:18:25 | LL | ($($a:ident)+ # $($($a:path),+);*) => {}; - | ^^^^^^^^ ^^^^^^^ + | ^^^^^^^ + | +note: previous declaration was here + --> $DIR/macro-multiple-matcher-bindings.rs:18:8 | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #57593 <https://github.com/rust-lang/rust/issues/57593> +LL | ($($a:ident)+ # $($($a:path),+);*) => {}; + | ^^^^^^^^ + +error: aborting due to 4 previous errors diff --git a/src/test/ui/macros/macro-path-prelude-fail-1.rs b/src/test/ui/macros/macro-path-prelude-fail-1.rs index 354c2bf8571..cd695ca916e 100644 --- a/src/test/ui/macros/macro-path-prelude-fail-1.rs +++ b/src/test/ui/macros/macro-path-prelude-fail-1.rs @@ -2,8 +2,8 @@ mod m { fn check() { - Vec::clone!(); //~ ERROR failed to resolve: not a module `Vec` - u8::clone!(); //~ ERROR failed to resolve: not a module `u8` + Vec::clone!(); //~ ERROR failed to resolve: `Vec` is a struct, not a module + u8::clone!(); //~ ERROR failed to resolve: `u8` is a builtin type, not a module } } diff --git a/src/test/ui/macros/macro-path-prelude-fail-1.stderr b/src/test/ui/macros/macro-path-prelude-fail-1.stderr index 551d2fe8ce0..b68e89f07f6 100644 --- a/src/test/ui/macros/macro-path-prelude-fail-1.stderr +++ b/src/test/ui/macros/macro-path-prelude-fail-1.stderr @@ -1,14 +1,14 @@ -error[E0433]: failed to resolve: not a module `Vec` +error[E0433]: failed to resolve: `Vec` is a struct, not a module --> $DIR/macro-path-prelude-fail-1.rs:5:9 | LL | Vec::clone!(); - | ^^^ not a module `Vec` + | ^^^ `Vec` is a struct, not a module -error[E0433]: failed to resolve: not a module `u8` +error[E0433]: failed to resolve: `u8` is a builtin type, not a module --> $DIR/macro-path-prelude-fail-1.rs:6:9 | LL | u8::clone!(); - | ^^ not a module `u8` + | ^^ `u8` is a builtin type, not a module error: aborting due to 2 previous errors diff --git a/src/test/ui/macros/macro-reexport-removed.stderr b/src/test/ui/macros/macro-reexport-removed.stderr index 302952909be..600d5d4cc9a 100644 --- a/src/test/ui/macros/macro-reexport-removed.stderr +++ b/src/test/ui/macros/macro-reexport-removed.stderr @@ -10,12 +10,13 @@ note: subsumed by `pub use` LL | #![feature(macro_reexport)] | ^^^^^^^^^^^^^^ -error[E0658]: The attribute `macro_reexport` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `macro_reexport` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/macro-reexport-removed.rs:5:3 | LL | #[macro_reexport(macro_one)] | ^^^^^^^^^^^^^^ help: a built-in attribute with a similar name exists: `macro_export` | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable error: aborting due to 2 previous errors diff --git a/src/test/ui/macros/macros-in-extern.stderr b/src/test/ui/macros/macros-in-extern.stderr index 1d0c28752bc..ec7c37402d4 100644 --- a/src/test/ui/macros/macros-in-extern.stderr +++ b/src/test/ui/macros/macros-in-extern.stderr @@ -1,25 +1,28 @@ -error[E0658]: macro invocations in `extern {}` blocks are experimental (see issue #49476) +error[E0658]: macro invocations in `extern {}` blocks are experimental --> $DIR/macros-in-extern.rs:26:5 | LL | returns_isize!(rust_get_test_int); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/49476 = help: add #![feature(macros_in_extern)] to the crate attributes to enable -error[E0658]: macro invocations in `extern {}` blocks are experimental (see issue #49476) +error[E0658]: macro invocations in `extern {}` blocks are experimental --> $DIR/macros-in-extern.rs:28:5 | LL | takes_u32_returns_u32!(rust_dbg_extern_identity_u32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/49476 = help: add #![feature(macros_in_extern)] to the crate attributes to enable -error[E0658]: macro invocations in `extern {}` blocks are experimental (see issue #49476) +error[E0658]: macro invocations in `extern {}` blocks are experimental --> $DIR/macros-in-extern.rs:30:5 | LL | emits_nothing!(); | ^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/49476 = help: add #![feature(macros_in_extern)] to the crate attributes to enable error: aborting due to 3 previous errors diff --git a/src/test/ui/missing/missing-alloc_error_handler.rs b/src/test/ui/missing/missing-alloc_error_handler.rs index 1a9e8688e8a..ae0c067bb5f 100644 --- a/src/test/ui/missing/missing-alloc_error_handler.rs +++ b/src/test/ui/missing/missing-alloc_error_handler.rs @@ -3,7 +3,7 @@ #![no_std] #![crate_type = "staticlib"] -#![feature(panic_handler, alloc_error_handler, alloc)] +#![feature(panic_handler, alloc_error_handler)] #[panic_handler] fn panic(_: &core::panic::PanicInfo) -> ! { diff --git a/src/test/ui/missing/missing-allocator.rs b/src/test/ui/missing/missing-allocator.rs index dbb10d1e7b9..6d867e2e8b4 100644 --- a/src/test/ui/missing/missing-allocator.rs +++ b/src/test/ui/missing/missing-allocator.rs @@ -3,7 +3,7 @@ #![no_std] #![crate_type = "staticlib"] -#![feature(panic_handler, alloc_error_handler, alloc)] +#![feature(panic_handler, alloc_error_handler)] #[panic_handler] fn panic(_: &core::panic::PanicInfo) -> ! { diff --git a/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr b/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr index 46de13dbbbd..20041389b3c 100644 --- a/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr +++ b/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr @@ -6,7 +6,7 @@ LL | let mut closure = expect_sig(|p, y| *p = y); | = note: defining type: DefId(0/1:9 ~ escape_argument_callee[317d]::test[0]::{{closure}}[0]) with closure substs [ i16, - for<'r, 's, 't0> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) mut &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) i32, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't0)) i32)) + for<'r, 's, 't0> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) mut &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) i32, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't0)) i32)), ] error: lifetime may not live long enough diff --git a/src/test/ui/nll/closure-requirements/escape-argument.stderr b/src/test/ui/nll/closure-requirements/escape-argument.stderr index d47b326f48e..b08ec953931 100644 --- a/src/test/ui/nll/closure-requirements/escape-argument.stderr +++ b/src/test/ui/nll/closure-requirements/escape-argument.stderr @@ -6,7 +6,7 @@ LL | let mut closure = expect_sig(|p, y| *p = y); | = note: defining type: DefId(0/1:9 ~ escape_argument[317d]::test[0]::{{closure}}[0]) with closure substs [ i16, - for<'r, 's> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) mut &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) i32, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) i32)) + for<'r, 's> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) mut &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) i32, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) i32)), ] note: No external requirements diff --git a/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr b/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr index dec4a6b811f..7178b22bb5f 100644 --- a/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr +++ b/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr @@ -8,7 +8,7 @@ LL | let mut closure1 = || p = &y; i16, extern "rust-call" fn(()), &'_#1r mut &'_#2r i32, - &'_#3r i32 + &'_#3r i32, ] = note: number of external vids: 4 = note: where '_#3r: '_#2r @@ -27,7 +27,7 @@ LL | | }; i16, extern "rust-call" fn(()), &'_#1r mut &'_#2r i32, - &'_#3r i32 + &'_#3r i32, ] = note: number of external vids: 4 = note: where '_#3r: '_#2r diff --git a/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr b/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr index 55ede6ed4aa..d129f945f25 100644 --- a/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr +++ b/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr @@ -8,7 +8,7 @@ LL | let mut closure = || p = &y; i16, extern "rust-call" fn(()), &'_#1r mut &'_#2r i32, - &'_#3r i32 + &'_#3r i32, ] = note: number of external vids: 4 = note: where '_#3r: '_#2r diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr index 7eb4d96fc5f..4db1f040770 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr @@ -10,7 +10,7 @@ LL | | }, | = note: defining type: DefId(0/1:20 ~ propagate_approximated_fail_no_postdom[317d]::supply[0]::{{closure}}[0]) with closure substs [ i16, - for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) &'_#3r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>)) + for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) &'_#3r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>)), ] = note: late-bound region is '_#4r = note: late-bound region is '_#5r diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr index a1a1024bccd..7dedae715be 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr @@ -11,7 +11,7 @@ LL | | }); | = note: defining type: DefId(0/1:18 ~ propagate_approximated_ref[317d]::supply[0]::{{closure}}[0]) with closure substs [ i16, - for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't1)) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't3)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't1)) u32>)) + for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't1)) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't3)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't1)) u32>)), ] = note: late-bound region is '_#3r = note: late-bound region is '_#4r diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr index ad2a5cae62e..b2d7fd8df6d 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr @@ -10,7 +10,7 @@ LL | | }) | = note: defining type: DefId(0/1:12 ~ propagate_approximated_shorter_to_static_comparing_against_free[317d]::case1[0]::{{closure}}[0]) with closure substs [ i32, - for<'r> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>)) + for<'r> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>)), ] error[E0521]: borrowed data escapes outside of closure @@ -48,7 +48,7 @@ LL | | }) | = note: defining type: DefId(0/1:13 ~ propagate_approximated_shorter_to_static_comparing_against_free[317d]::case2[0]::{{closure}}[0]) with closure substs [ i32, - for<'r> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>)) + for<'r> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>)), ] = note: number of external vids: 2 = note: where '_#1r: '_#0r diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr index f5167c2197b..e30e2dfee63 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr @@ -12,7 +12,7 @@ LL | | }); | = note: defining type: DefId(0/1:18 ~ propagate_approximated_shorter_to_static_no_bound[317d]::supply[0]::{{closure}}[0]) with closure substs [ i16, - for<'r, 's, 't0, 't1, 't2> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't1)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't2)) u32>)) + for<'r, 's, 't0, 't1, 't2> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't1)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't2)) u32>)), ] = note: late-bound region is '_#2r = note: late-bound region is '_#3r diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr index b4e1b0d2247..ec608590a71 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr @@ -12,7 +12,7 @@ LL | | }); | = note: defining type: DefId(0/1:18 ~ propagate_approximated_shorter_to_static_wrong_bound[317d]::supply[0]::{{closure}}[0]) with closure substs [ i16, - for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't0)) std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't1)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't3)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't1)) u32>)) + for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't0)) std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't1)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't3)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't1)) u32>)), ] = note: late-bound region is '_#3r = note: late-bound region is '_#4r diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr index 6ab2104a51c..223c29f5969 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr @@ -11,7 +11,7 @@ LL | | }); | = note: defining type: DefId(0/1:18 ~ propagate_approximated_val[317d]::test[0]::{{closure}}[0]) with closure substs [ i16, - for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>)) + for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>)), ] = note: late-bound region is '_#3r = note: late-bound region is '_#4r diff --git a/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr b/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr index 79f0df9a688..d618b4d06a1 100644 --- a/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr @@ -10,7 +10,7 @@ LL | | }, | = note: defining type: DefId(0/1:16 ~ propagate_despite_same_free_region[317d]::supply[0]::{{closure}}[0]) with closure substs [ i16, - for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>)) + for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>)), ] = note: late-bound region is '_#3r = note: number of external vids: 4 diff --git a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr index f8b6bfa003b..07fb4d0d5e3 100644 --- a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr @@ -11,7 +11,7 @@ LL | | }); | = note: defining type: DefId(0/1:18 ~ propagate_fail_to_approximate_longer_no_bounds[317d]::supply[0]::{{closure}}[0]) with closure substs [ i16, - for<'r, 's, 't0, 't1, 't2> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't1)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>)) + for<'r, 's, 't0, 't1, 't2> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't1)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>)), ] = note: late-bound region is '_#2r = note: late-bound region is '_#3r diff --git a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr index 7e7429405fa..a0744c27db7 100644 --- a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr @@ -11,7 +11,7 @@ LL | | }); | = note: defining type: DefId(0/1:18 ~ propagate_fail_to_approximate_longer_wrong_bounds[317d]::supply[0]::{{closure}}[0]) with closure substs [ i16, - for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't1)) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't3)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't1)) u32>)) + for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't1)) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't3)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't1)) u32>)), ] = note: late-bound region is '_#3r = note: late-bound region is '_#4r diff --git a/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr b/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr index c2bbd813814..282246f8166 100644 --- a/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr @@ -15,7 +15,7 @@ LL | | }); '_#1r, T, i32, - extern "rust-call" fn((T,)) + extern "rust-call" fn((T,)), ] = note: number of external vids: 2 = note: where T: '_#1r @@ -34,7 +34,7 @@ LL | | } | = note: defining type: DefId(0/0:6 ~ propagate_from_trait_match[317d]::supply[0]) with substs [ '_#1r, - T + T, ] error[E0309]: the parameter type `T` may not live long enough diff --git a/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr b/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr index d5bfa3f9894..c5645413c77 100644 --- a/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr +++ b/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr @@ -6,7 +6,7 @@ LL | expect_sig(|a, b| b); // ought to return `a` | = note: defining type: DefId(0/1:9 ~ return_wrong_bound_region[317d]::test[0]::{{closure}}[0]) with closure substs [ i16, - for<'r, 's> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) i32, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) i32)) -> &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) i32 + for<'r, 's> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) i32, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) i32)) -> &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) i32, ] error: lifetime may not live long enough diff --git a/src/test/ui/nll/extra-unused-mut.rs b/src/test/ui/nll/extra-unused-mut.rs index d5f0b0ddf18..6d0d6e16a67 100644 --- a/src/test/ui/nll/extra-unused-mut.rs +++ b/src/test/ui/nll/extra-unused-mut.rs @@ -1,6 +1,6 @@ // extra unused mut lint tests for #51918 -// run-pass +// compile-pass #![feature(generators, nll)] #![deny(unused_mut)] @@ -53,11 +53,14 @@ fn if_guard(x: Result<i32, i32>) { } } -fn main() { - ref_argument(0); - mutable_upvar(); - generator_mutable_upvar(); - ref_closure_argument(); - parse_dot_or_call_expr_with(Vec::new()); - if_guard(Ok(0)); +// #59620 +fn nested_closures() { + let mut i = 0; + [].iter().for_each(|_: &i32| { + [].iter().for_each(move |_: &i32| { + i += 1; + }); + }); } + +fn main() {} diff --git a/src/test/ui/nll/get_default.nll.stderr b/src/test/ui/nll/get_default.nll.stderr deleted file mode 100644 index 0f71452805d..00000000000 --- a/src/test/ui/nll/get_default.nll.stderr +++ /dev/null @@ -1,84 +0,0 @@ -error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Ast) - --> $DIR/get_default.rs:23:17 - | -LL | match map.get() { - | --- immutable borrow occurs here -... -LL | map.set(String::new()); // Ideally, this would not error. - | ^^^ mutable borrow occurs here -... -LL | } - | - immutable borrow ends here - -error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Ast) - --> $DIR/get_default.rs:35:17 - | -LL | match map.get() { - | --- immutable borrow occurs here -LL | Some(v) => { -LL | map.set(String::new()); // Both AST and MIR error here - | ^^^ mutable borrow occurs here -... -LL | } - | - immutable borrow ends here - -error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Ast) - --> $DIR/get_default.rs:41:17 - | -LL | match map.get() { - | --- immutable borrow occurs here -... -LL | map.set(String::new()); // Ideally, just AST would error here - | ^^^ mutable borrow occurs here -... -LL | } - | - immutable borrow ends here - -error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Mir) - --> $DIR/get_default.rs:23:17 - | -LL | fn ok(map: &mut Map) -> &String { - | - let's call the lifetime of this reference `'1` -LL | loop { -LL | match map.get() { - | --- immutable borrow occurs here -LL | Some(v) => { -LL | return v; - | - returning this value requires that `*map` is borrowed for `'1` -... -LL | map.set(String::new()); // Ideally, this would not error. - | ^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here - -error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Mir) - --> $DIR/get_default.rs:35:17 - | -LL | fn err(map: &mut Map) -> &String { - | - let's call the lifetime of this reference `'1` -LL | loop { -LL | match map.get() { - | --- immutable borrow occurs here -LL | Some(v) => { -LL | map.set(String::new()); // Both AST and MIR error here - | ^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here -... -LL | return v; - | - returning this value requires that `*map` is borrowed for `'1` - -error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Mir) - --> $DIR/get_default.rs:41:17 - | -LL | fn err(map: &mut Map) -> &String { - | - let's call the lifetime of this reference `'1` -LL | loop { -LL | match map.get() { - | --- immutable borrow occurs here -... -LL | return v; - | - returning this value requires that `*map` is borrowed for `'1` -... -LL | map.set(String::new()); // Ideally, just AST would error here - | ^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here - -error: aborting due to 6 previous errors - -For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/nll/region-ends-after-if-condition.nll.stderr b/src/test/ui/nll/region-ends-after-if-condition.nll.stderr deleted file mode 100644 index ab8d96d4e99..00000000000 --- a/src/test/ui/nll/region-ends-after-if-condition.nll.stderr +++ /dev/null @@ -1,39 +0,0 @@ -error[E0502]: cannot borrow `my_struct.field` as mutable because it is also borrowed as immutable (Ast) - --> $DIR/region-ends-after-if-condition.rs:19:9 - | -LL | let value = &my_struct.field; - | --------------- immutable borrow occurs here -LL | if value.is_empty() { -LL | my_struct.field.push_str("Hello, world!"); - | ^^^^^^^^^^^^^^^ mutable borrow occurs here -... -LL | } - | - immutable borrow ends here - -error[E0502]: cannot borrow `my_struct.field` as mutable because it is also borrowed as immutable (Ast) - --> $DIR/region-ends-after-if-condition.rs:29:9 - | -LL | let value = &my_struct.field; - | --------------- immutable borrow occurs here -LL | if value.is_empty() { -LL | my_struct.field.push_str("Hello, world!"); - | ^^^^^^^^^^^^^^^ mutable borrow occurs here -... -LL | } - | - immutable borrow ends here - -error[E0502]: cannot borrow `my_struct.field` as mutable because it is also borrowed as immutable (Mir) - --> $DIR/region-ends-after-if-condition.rs:29:9 - | -LL | let value = &my_struct.field; - | ---------------- immutable borrow occurs here -LL | if value.is_empty() { -LL | my_struct.field.push_str("Hello, world!"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here -... -LL | drop(value); - | ----- immutable borrow later used here - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr b/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr index a7679aac219..cda1f7d3631 100644 --- a/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr @@ -8,7 +8,7 @@ LL | with_signature(x, |mut y| Box::new(y.next())) '_#1r, T, i32, - extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn Anything + '_#2r)> + extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn Anything + '_#2r)>, ] = note: number of external vids: 3 = note: where <T as std::iter::Iterator>::Item: '_#2r @@ -27,7 +27,7 @@ LL | | } | = note: defining type: DefId(0/0:6 ~ projection_no_regions_closure[317d]::no_region[0]) with substs [ '_#1r, - T + T, ] error[E0309]: the associated type `<T as std::iter::Iterator>::Item` may not live long enough @@ -48,7 +48,7 @@ LL | with_signature(x, |mut y| Box::new(y.next())) '_#1r, T, i32, - extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn Anything + '_#2r)> + extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn Anything + '_#2r)>, ] = note: number of external vids: 3 = note: where <T as std::iter::Iterator>::Item: '_#2r @@ -66,7 +66,7 @@ LL | | } | = note: defining type: DefId(0/0:7 ~ projection_no_regions_closure[317d]::correct_region[0]) with substs [ '_#1r, - T + T, ] note: External requirements @@ -80,7 +80,7 @@ LL | with_signature(x, |mut y| Box::new(y.next())) '_#2r, T, i32, - extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn Anything + '_#3r)> + extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn Anything + '_#3r)>, ] = note: number of external vids: 4 = note: where <T as std::iter::Iterator>::Item: '_#3r @@ -100,7 +100,7 @@ LL | | } = note: defining type: DefId(0/0:8 ~ projection_no_regions_closure[317d]::wrong_region[0]) with substs [ '_#1r, '_#2r, - T + T, ] error[E0309]: the associated type `<T as std::iter::Iterator>::Item` may not live long enough @@ -122,7 +122,7 @@ LL | with_signature(x, |mut y| Box::new(y.next())) '_#2r, T, i32, - extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn Anything + '_#3r)> + extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn Anything + '_#3r)>, ] = note: number of external vids: 4 = note: where <T as std::iter::Iterator>::Item: '_#3r @@ -142,7 +142,7 @@ LL | | } = note: defining type: DefId(0/0:9 ~ projection_no_regions_closure[317d]::outlives_region[0]) with substs [ '_#1r, '_#2r, - T + T, ] error: aborting due to 2 previous errors diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr index 7ba7164b35b..9d716006500 100644 --- a/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr @@ -8,7 +8,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); '_#1r, T, i32, - extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)) + extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)), ] = note: late-bound region is '_#3r = note: number of external vids: 4 @@ -29,7 +29,7 @@ LL | | } | = note: defining type: DefId(0/0:8 ~ projection_one_region_closure[317d]::no_relationships_late[0]) with substs [ '_#1r, - T + T, ] error[E0309]: the parameter type `T` may not live long enough @@ -62,7 +62,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); '_#2r, T, i32, - extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) + extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), ] = note: number of external vids: 4 = note: where T: '_#3r @@ -83,7 +83,7 @@ LL | | } = note: defining type: DefId(0/0:9 ~ projection_one_region_closure[317d]::no_relationships_early[0]) with substs [ '_#1r, '_#2r, - T + T, ] error[E0309]: the parameter type `T` may not live long enough @@ -116,7 +116,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); '_#2r, T, i32, - extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) + extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), ] = note: number of external vids: 4 = note: where <T as Anything<ReClosureBound('_#2r)>>::AssocType: '_#3r @@ -136,7 +136,7 @@ LL | | } = note: defining type: DefId(0/0:10 ~ projection_one_region_closure[317d]::projection_outlives[0]) with substs [ '_#1r, '_#2r, - T + T, ] note: External requirements @@ -150,7 +150,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); '_#2r, T, i32, - extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) + extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), ] = note: number of external vids: 4 = note: where T: '_#3r @@ -171,7 +171,7 @@ LL | | } = note: defining type: DefId(0/0:11 ~ projection_one_region_closure[317d]::elements_outlive[0]) with substs [ '_#1r, '_#2r, - T + T, ] error: aborting due to 4 previous errors diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr index 63ead49adfc..0fa4060137a 100644 --- a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr @@ -8,7 +8,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); '_#1r, T, i32, - extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)) + extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)), ] = note: late-bound region is '_#3r = note: number of external vids: 4 @@ -28,7 +28,7 @@ LL | | } | = note: defining type: DefId(0/0:8 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_late[0]) with substs [ '_#1r, - T + T, ] error: lifetime may not live long enough @@ -53,7 +53,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); '_#2r, T, i32, - extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) + extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), ] = note: number of external vids: 4 = note: where '_#2r: '_#3r @@ -73,7 +73,7 @@ LL | | } = note: defining type: DefId(0/0:9 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_early[0]) with substs [ '_#1r, '_#2r, - T + T, ] error: lifetime may not live long enough @@ -98,7 +98,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); '_#2r, T, i32, - extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) + extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), ] = note: number of external vids: 4 = note: where <T as Anything<ReClosureBound('_#2r)>>::AssocType: '_#3r @@ -118,7 +118,7 @@ LL | | } = note: defining type: DefId(0/0:10 ~ projection_one_region_trait_bound_closure[317d]::projection_outlives[0]) with substs [ '_#1r, '_#2r, - T + T, ] note: External requirements @@ -132,7 +132,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); '_#2r, T, i32, - extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) + extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), ] = note: number of external vids: 4 = note: where '_#2r: '_#3r @@ -152,7 +152,7 @@ LL | | } = note: defining type: DefId(0/0:11 ~ projection_one_region_trait_bound_closure[317d]::elements_outlive[0]) with substs [ '_#1r, '_#2r, - T + T, ] note: External requirements @@ -165,7 +165,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); '_#1r, T, i32, - extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)) + extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)), ] = note: number of external vids: 3 = note: where '_#1r: '_#2r @@ -184,7 +184,7 @@ LL | | } | = note: defining type: DefId(0/0:12 ~ projection_one_region_trait_bound_closure[317d]::one_region[0]) with substs [ '_#1r, - T + T, ] error: aborting due to 2 previous errors diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr index 61f8132cf49..f616a7feae3 100644 --- a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr @@ -8,7 +8,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); '_#1r, T, i32, - extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)) + extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)), ] = note: late-bound region is '_#3r @@ -25,7 +25,7 @@ LL | | } | = note: defining type: DefId(0/0:8 ~ projection_one_region_trait_bound_static_closure[317d]::no_relationships_late[0]) with substs [ '_#1r, - T + T, ] note: No external requirements @@ -39,7 +39,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); '_#2r, T, i32, - extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) + extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), ] note: No external requirements @@ -57,7 +57,7 @@ LL | | } = note: defining type: DefId(0/0:9 ~ projection_one_region_trait_bound_static_closure[317d]::no_relationships_early[0]) with substs [ '_#1r, '_#2r, - T + T, ] note: No external requirements @@ -71,7 +71,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); '_#2r, T, i32, - extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) + extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), ] note: No external requirements @@ -89,7 +89,7 @@ LL | | } = note: defining type: DefId(0/0:10 ~ projection_one_region_trait_bound_static_closure[317d]::projection_outlives[0]) with substs [ '_#1r, '_#2r, - T + T, ] note: No external requirements @@ -103,7 +103,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); '_#2r, T, i32, - extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) + extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), ] note: No external requirements @@ -121,7 +121,7 @@ LL | | } = note: defining type: DefId(0/0:11 ~ projection_one_region_trait_bound_static_closure[317d]::elements_outlive[0]) with substs [ '_#1r, '_#2r, - T + T, ] note: No external requirements @@ -134,7 +134,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); '_#1r, T, i32, - extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)) + extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)), ] note: No external requirements @@ -151,6 +151,6 @@ LL | | } | = note: defining type: DefId(0/0:12 ~ projection_one_region_trait_bound_static_closure[317d]::one_region[0]) with substs [ '_#1r, - T + T, ] diff --git a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr index f5daae28670..b761b031444 100644 --- a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr @@ -9,7 +9,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); '_#2r, T, i32, - extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) + extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), ] = note: late-bound region is '_#4r = note: number of external vids: 5 @@ -30,7 +30,7 @@ LL | | } = note: defining type: DefId(0/0:8 ~ projection_two_region_trait_bound_closure[317d]::no_relationships_late[0]) with substs [ '_#1r, '_#2r, - T + T, ] error[E0309]: the associated type `<T as Anything<'_#5r, '_#6r>>::AssocType` may not live long enough @@ -53,7 +53,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); '_#3r, T, i32, - extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)) + extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)), ] = note: number of external vids: 5 = note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#3r)>>::AssocType: '_#4r @@ -74,7 +74,7 @@ LL | | } '_#1r, '_#2r, '_#3r, - T + T, ] error[E0309]: the associated type `<T as Anything<'_#6r, '_#7r>>::AssocType` may not live long enough @@ -97,7 +97,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); '_#3r, T, i32, - extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)) + extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)), ] = note: number of external vids: 5 = note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#3r)>>::AssocType: '_#4r @@ -118,7 +118,7 @@ LL | | } '_#1r, '_#2r, '_#3r, - T + T, ] note: External requirements @@ -133,7 +133,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); '_#3r, T, i32, - extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)) + extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)), ] = note: number of external vids: 5 = note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#3r)>>::AssocType: '_#4r @@ -154,7 +154,7 @@ LL | | } '_#1r, '_#2r, '_#3r, - T + T, ] note: External requirements @@ -169,7 +169,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); '_#3r, T, i32, - extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)) + extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)), ] = note: number of external vids: 5 = note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#3r)>>::AssocType: '_#4r @@ -190,7 +190,7 @@ LL | | } '_#1r, '_#2r, '_#3r, - T + T, ] note: External requirements @@ -203,7 +203,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); '_#1r, T, i32, - extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)) + extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)), ] = note: late-bound region is '_#3r = note: number of external vids: 4 @@ -223,7 +223,7 @@ LL | | } | = note: defining type: DefId(0/0:13 ~ projection_two_region_trait_bound_closure[317d]::two_regions[0]) with substs [ '_#1r, - T + T, ] error: lifetime may not live long enough @@ -248,7 +248,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); '_#2r, T, i32, - extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) + extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), ] = note: number of external vids: 4 = note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#2r)>>::AssocType: '_#3r @@ -268,7 +268,7 @@ LL | | } = note: defining type: DefId(0/0:14 ~ projection_two_region_trait_bound_closure[317d]::two_regions_outlive[0]) with substs [ '_#1r, '_#2r, - T + T, ] note: External requirements @@ -281,7 +281,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); '_#1r, T, i32, - extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)) + extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)), ] = note: number of external vids: 3 = note: where <T as Anything<ReClosureBound('_#1r), ReClosureBound('_#1r)>>::AssocType: '_#2r @@ -300,7 +300,7 @@ LL | | } | = note: defining type: DefId(0/0:15 ~ projection_two_region_trait_bound_closure[317d]::one_region[0]) with substs [ '_#1r, - T + T, ] error: aborting due to 3 previous errors diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr b/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr index 41c2916dca3..6f3071becfd 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr +++ b/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr @@ -7,7 +7,7 @@ LL | twice(cell, value, |a, b| invoke(a, b)); = note: defining type: DefId(0/1:14 ~ ty_param_closure_approximate_lower_bound[317d]::generic[0]::{{closure}}[0]) with closure substs [ T, i16, - for<'r, 's> extern "rust-call" fn((std::option::Option<std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) ()>>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) T)) + for<'r, 's> extern "rust-call" fn((std::option::Option<std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) ()>>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) T)), ] = note: number of external vids: 2 = note: where T: '_#1r @@ -22,7 +22,7 @@ LL | | } | |_^ | = note: defining type: DefId(0/0:5 ~ ty_param_closure_approximate_lower_bound[317d]::generic[0]) with substs [ - T + T, ] note: External requirements @@ -34,7 +34,7 @@ LL | twice(cell, value, |a, b| invoke(a, b)); = note: defining type: DefId(0/1:17 ~ ty_param_closure_approximate_lower_bound[317d]::generic_fail[0]::{{closure}}[0]) with closure substs [ T, i16, - for<'r, 's> extern "rust-call" fn((std::option::Option<std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) ()>>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) T)) + for<'r, 's> extern "rust-call" fn((std::option::Option<std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) ()>>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) T)), ] = note: late-bound region is '_#2r = note: number of external vids: 3 @@ -50,7 +50,7 @@ LL | | } | |_^ | = note: defining type: DefId(0/0:6 ~ ty_param_closure_approximate_lower_bound[317d]::generic_fail[0]) with substs [ - T + T, ] error[E0309]: the parameter type `T` may not live long enough diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr index 6a201b8523a..cdb71576203 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr +++ b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr @@ -8,7 +8,7 @@ LL | with_signature(x, |y| y) '_#1r, T, i32, - extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn std::fmt::Debug + '_#2r)> + extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn std::fmt::Debug + '_#2r)>, ] = note: number of external vids: 3 = note: where T: '_#2r @@ -27,7 +27,7 @@ LL | | } | = note: defining type: DefId(0/0:5 ~ ty_param_closure_outlives_from_return_type[317d]::no_region[0]) with substs [ '_#1r, - T + T, ] error[E0309]: the parameter type `T` may not live long enough diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr index 4ddc54717fb..68798a335f9 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr +++ b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr @@ -14,7 +14,7 @@ LL | | }) = note: defining type: DefId(0/1:16 ~ ty_param_closure_outlives_from_where_clause[317d]::no_region[0]::{{closure}}[0]) with closure substs [ T, i32, - extern "rust-call" fn((std::cell::Cell<&'_#1r ()>, T)) + extern "rust-call" fn((std::cell::Cell<&'_#1r ()>, T)), ] = note: late-bound region is '_#2r = note: number of external vids: 3 @@ -33,7 +33,7 @@ LL | | } | |_^ | = note: defining type: DefId(0/0:6 ~ ty_param_closure_outlives_from_where_clause[317d]::no_region[0]) with substs [ - T + T, ] error[E0309]: the parameter type `T` may not live long enough @@ -68,7 +68,7 @@ LL | | }) '_#1r, T, i32, - extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)) + extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)), ] = note: number of external vids: 3 = note: where T: '_#2r @@ -87,7 +87,7 @@ LL | | } | = note: defining type: DefId(0/0:7 ~ ty_param_closure_outlives_from_where_clause[317d]::correct_region[0]) with substs [ '_#1r, - T + T, ] note: External requirements @@ -105,7 +105,7 @@ LL | | }) '_#1r, T, i32, - extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)) + extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)), ] = note: late-bound region is '_#3r = note: number of external vids: 4 @@ -125,7 +125,7 @@ LL | | } | = note: defining type: DefId(0/0:8 ~ ty_param_closure_outlives_from_where_clause[317d]::wrong_region[0]) with substs [ '_#1r, - T + T, ] error[E0309]: the parameter type `T` may not live long enough @@ -156,7 +156,7 @@ LL | | }) '_#2r, T, i32, - extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)) + extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), ] = note: number of external vids: 4 = note: where T: '_#3r @@ -176,7 +176,7 @@ LL | | } = note: defining type: DefId(0/0:9 ~ ty_param_closure_outlives_from_where_clause[317d]::outlives_region[0]) with substs [ '_#1r, '_#2r, - T + T, ] error: aborting due to 2 previous errors diff --git a/src/test/ui/panic-runtime/needs-gate.stderr b/src/test/ui/panic-runtime/needs-gate.stderr index 5b8ff82d1fd..72999a0de89 100644 --- a/src/test/ui/panic-runtime/needs-gate.stderr +++ b/src/test/ui/panic-runtime/needs-gate.stderr @@ -1,17 +1,19 @@ -error[E0658]: the `#[panic_runtime]` attribute is an experimental feature (see issue #32837) +error[E0658]: the `#[panic_runtime]` attribute is an experimental feature --> $DIR/needs-gate.rs:4:1 | LL | #![panic_runtime] | ^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/32837 = help: add #![feature(panic_runtime)] to the crate attributes to enable -error[E0658]: the `#[needs_panic_runtime]` attribute is an experimental feature (see issue #32837) +error[E0658]: the `#[needs_panic_runtime]` attribute is an experimental feature --> $DIR/needs-gate.rs:5:1 | LL | #![needs_panic_runtime] | ^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/32837 = help: add #![feature(needs_panic_runtime)] to the crate attributes to enable error: aborting due to 2 previous errors diff --git a/src/test/ui/parser/recover-missing-semi.rs b/src/test/ui/parser/recover-missing-semi.rs new file mode 100644 index 00000000000..1893dc716be --- /dev/null +++ b/src/test/ui/parser/recover-missing-semi.rs @@ -0,0 +1,13 @@ +fn main() { + let _: usize = () + //~^ ERROR mismatched types + let _ = 3; + //~^ ERROR expected one of +} + +fn foo() -> usize { + let _: usize = () + //~^ ERROR mismatched types + return 3; + //~^ ERROR expected one of +} diff --git a/src/test/ui/parser/recover-missing-semi.stderr b/src/test/ui/parser/recover-missing-semi.stderr new file mode 100644 index 00000000000..99339e4dd50 --- /dev/null +++ b/src/test/ui/parser/recover-missing-semi.stderr @@ -0,0 +1,39 @@ +error: expected one of `.`, `;`, `?`, or an operator, found `let` + --> $DIR/recover-missing-semi.rs:4:5 + | +LL | let _: usize = () + | - help: a semicolon may be missing here +LL | +LL | let _ = 3; + | ^^^ + +error: expected one of `.`, `;`, `?`, or an operator, found `return` + --> $DIR/recover-missing-semi.rs:11:5 + | +LL | let _: usize = () + | - help: a semicolon may be missing here +LL | +LL | return 3; + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/recover-missing-semi.rs:2:20 + | +LL | let _: usize = () + | ^^ expected usize, found () + | + = note: expected type `usize` + found type `()` + +error[E0308]: mismatched types + --> $DIR/recover-missing-semi.rs:9:20 + | +LL | let _: usize = () + | ^^ expected usize, found () + | + = note: expected type `usize` + found type `()` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/print_type_sizes/multiple_types.stdout b/src/test/ui/print_type_sizes/multiple_types.stdout index eed9af26987..64118815458 100644 --- a/src/test/ui/print_type_sizes/multiple_types.stdout +++ b/src/test/ui/print_type_sizes/multiple_types.stdout @@ -1,9 +1,9 @@ print-type-size type: `Enum`: 51 bytes, alignment: 1 bytes print-type-size discriminant: 1 bytes -print-type-size variant `Small`: 7 bytes -print-type-size field `.0`: 7 bytes print-type-size variant `Large`: 50 bytes print-type-size field `.0`: 50 bytes +print-type-size variant `Small`: 7 bytes +print-type-size field `.0`: 7 bytes print-type-size type: `FiftyBytes`: 50 bytes, alignment: 1 bytes print-type-size field `.0`: 50 bytes print-type-size type: `SevenBytes`: 7 bytes, alignment: 1 bytes diff --git a/src/test/ui/print_type_sizes/niche-filling.stdout b/src/test/ui/print_type_sizes/niche-filling.stdout index 0789c6d7f34..9cdb2ae4f57 100644 --- a/src/test/ui/print_type_sizes/niche-filling.stdout +++ b/src/test/ui/print_type_sizes/niche-filling.stdout @@ -4,15 +4,15 @@ print-type-size field `.post`: 2 bytes print-type-size field `.pre`: 1 bytes print-type-size end padding: 1 bytes print-type-size type: `MyOption<IndirectNonZero>`: 12 bytes, alignment: 4 bytes -print-type-size variant `None`: 0 bytes print-type-size variant `Some`: 12 bytes print-type-size field `.0`: 12 bytes -print-type-size type: `EmbeddedDiscr`: 8 bytes, alignment: 4 bytes print-type-size variant `None`: 0 bytes +print-type-size type: `EmbeddedDiscr`: 8 bytes, alignment: 4 bytes print-type-size variant `Record`: 7 bytes print-type-size field `.val`: 4 bytes print-type-size field `.post`: 2 bytes print-type-size field `.pre`: 1 bytes +print-type-size variant `None`: 0 bytes print-type-size end padding: 1 bytes print-type-size type: `NestedNonZero`: 8 bytes, alignment: 4 bytes print-type-size field `.val`: 4 bytes @@ -20,59 +20,59 @@ print-type-size field `.post`: 2 bytes print-type-size field `.pre`: 1 bytes print-type-size end padding: 1 bytes print-type-size type: `Enum4<(), char, (), ()>`: 4 bytes, alignment: 4 bytes -print-type-size variant `One`: 0 bytes -print-type-size field `.0`: 0 bytes print-type-size variant `Two`: 4 bytes print-type-size field `.0`: 4 bytes +print-type-size variant `One`: 0 bytes +print-type-size field `.0`: 0 bytes print-type-size variant `Three`: 0 bytes print-type-size field `.0`: 0 bytes print-type-size variant `Four`: 0 bytes print-type-size field `.0`: 0 bytes print-type-size type: `MyOption<char>`: 4 bytes, alignment: 4 bytes -print-type-size variant `None`: 0 bytes print-type-size variant `Some`: 4 bytes print-type-size field `.0`: 4 bytes -print-type-size type: `MyOption<std::num::NonZeroU32>`: 4 bytes, alignment: 4 bytes print-type-size variant `None`: 0 bytes +print-type-size type: `MyOption<std::num::NonZeroU32>`: 4 bytes, alignment: 4 bytes print-type-size variant `Some`: 4 bytes print-type-size field `.0`: 4 bytes +print-type-size variant `None`: 0 bytes print-type-size type: `std::num::NonZeroU32`: 4 bytes, alignment: 4 bytes print-type-size field `.0`: 4 bytes print-type-size type: `Enum4<(), (), (), MyOption<u8>>`: 2 bytes, alignment: 1 bytes +print-type-size variant `Four`: 2 bytes +print-type-size field `.0`: 2 bytes print-type-size variant `One`: 0 bytes print-type-size field `.0`: 0 bytes print-type-size variant `Two`: 0 bytes print-type-size field `.0`: 0 bytes print-type-size variant `Three`: 0 bytes print-type-size field `.0`: 0 bytes -print-type-size variant `Four`: 2 bytes -print-type-size field `.0`: 2 bytes print-type-size type: `MyOption<MyOption<u8>>`: 2 bytes, alignment: 1 bytes -print-type-size variant `None`: 0 bytes print-type-size variant `Some`: 2 bytes print-type-size field `.0`: 2 bytes +print-type-size variant `None`: 0 bytes print-type-size type: `MyOption<u8>`: 2 bytes, alignment: 1 bytes print-type-size discriminant: 1 bytes -print-type-size variant `None`: 0 bytes print-type-size variant `Some`: 1 bytes print-type-size field `.0`: 1 bytes +print-type-size variant `None`: 0 bytes print-type-size type: `Enum4<(), (), bool, ()>`: 1 bytes, alignment: 1 bytes +print-type-size variant `Three`: 1 bytes +print-type-size field `.0`: 1 bytes print-type-size variant `One`: 0 bytes print-type-size field `.0`: 0 bytes print-type-size variant `Two`: 0 bytes print-type-size field `.0`: 0 bytes -print-type-size variant `Three`: 1 bytes -print-type-size field `.0`: 1 bytes print-type-size variant `Four`: 0 bytes print-type-size field `.0`: 0 bytes print-type-size type: `MyOption<bool>`: 1 bytes, alignment: 1 bytes -print-type-size variant `None`: 0 bytes print-type-size variant `Some`: 1 bytes print-type-size field `.0`: 1 bytes -print-type-size type: `MyOption<std::cmp::Ordering>`: 1 bytes, alignment: 1 bytes print-type-size variant `None`: 0 bytes +print-type-size type: `MyOption<std::cmp::Ordering>`: 1 bytes, alignment: 1 bytes print-type-size variant `Some`: 1 bytes print-type-size field `.0`: 1 bytes +print-type-size variant `None`: 0 bytes print-type-size type: `std::cmp::Ordering`: 1 bytes, alignment: 1 bytes print-type-size discriminant: 1 bytes print-type-size variant `Less`: 0 bytes diff --git a/src/test/ui/print_type_sizes/padding.stdout b/src/test/ui/print_type_sizes/padding.stdout index 0eaff7118b3..9afdf76245d 100644 --- a/src/test/ui/print_type_sizes/padding.stdout +++ b/src/test/ui/print_type_sizes/padding.stdout @@ -1,21 +1,21 @@ print-type-size type: `E1`: 12 bytes, alignment: 4 bytes print-type-size discriminant: 1 bytes +print-type-size variant `B`: 11 bytes +print-type-size padding: 3 bytes +print-type-size field `.0`: 8 bytes, alignment: 4 bytes print-type-size variant `A`: 7 bytes print-type-size field `.1`: 1 bytes print-type-size padding: 2 bytes print-type-size field `.0`: 4 bytes, alignment: 4 bytes +print-type-size type: `E2`: 12 bytes, alignment: 4 bytes +print-type-size discriminant: 1 bytes print-type-size variant `B`: 11 bytes print-type-size padding: 3 bytes print-type-size field `.0`: 8 bytes, alignment: 4 bytes -print-type-size type: `E2`: 12 bytes, alignment: 4 bytes -print-type-size discriminant: 1 bytes print-type-size variant `A`: 7 bytes print-type-size field `.0`: 1 bytes print-type-size padding: 2 bytes print-type-size field `.1`: 4 bytes, alignment: 4 bytes -print-type-size variant `B`: 11 bytes -print-type-size padding: 3 bytes -print-type-size field `.0`: 8 bytes, alignment: 4 bytes print-type-size type: `S`: 8 bytes, alignment: 4 bytes print-type-size field `.g`: 4 bytes print-type-size field `.a`: 1 bytes diff --git a/src/test/ui/print_type_sizes/repr-align.stdout b/src/test/ui/print_type_sizes/repr-align.stdout index 7df12f040b1..33671bd8e14 100644 --- a/src/test/ui/print_type_sizes/repr-align.stdout +++ b/src/test/ui/print_type_sizes/repr-align.stdout @@ -1,10 +1,10 @@ print-type-size type: `E`: 32 bytes, alignment: 16 bytes print-type-size discriminant: 4 bytes -print-type-size variant `A`: 4 bytes -print-type-size field `.0`: 4 bytes print-type-size variant `B`: 28 bytes print-type-size padding: 12 bytes print-type-size field `.0`: 16 bytes, alignment: 16 bytes +print-type-size variant `A`: 4 bytes +print-type-size field `.0`: 4 bytes print-type-size type: `S`: 32 bytes, alignment: 16 bytes print-type-size field `.c`: 16 bytes print-type-size field `.a`: 4 bytes diff --git a/src/test/ui/print_type_sizes/variants.stdout b/src/test/ui/print_type_sizes/variants.stdout index eed9af26987..64118815458 100644 --- a/src/test/ui/print_type_sizes/variants.stdout +++ b/src/test/ui/print_type_sizes/variants.stdout @@ -1,9 +1,9 @@ print-type-size type: `Enum`: 51 bytes, alignment: 1 bytes print-type-size discriminant: 1 bytes -print-type-size variant `Small`: 7 bytes -print-type-size field `.0`: 7 bytes print-type-size variant `Large`: 50 bytes print-type-size field `.0`: 50 bytes +print-type-size variant `Small`: 7 bytes +print-type-size field `.0`: 7 bytes print-type-size type: `FiftyBytes`: 50 bytes, alignment: 1 bytes print-type-size field `.0`: 50 bytes print-type-size type: `SevenBytes`: 7 bytes, alignment: 1 bytes diff --git a/src/test/ui/proc-macro/attr-stmt-expr.stderr b/src/test/ui/proc-macro/attr-stmt-expr.stderr index 34ee012ab31..3928a973eab 100644 --- a/src/test/ui/proc-macro/attr-stmt-expr.stderr +++ b/src/test/ui/proc-macro/attr-stmt-expr.stderr @@ -1,17 +1,19 @@ -error[E0658]: attributes on expressions are experimental. (see issue #15701) +error[E0658]: attributes on expressions are experimental --> $DIR/attr-stmt-expr.rs:10:5 | LL | #[expect_print_expr] | ^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/15701 = help: add #![feature(stmt_expr_attributes)] to the crate attributes to enable -error[E0658]: attributes on expressions are experimental. (see issue #15701) +error[E0658]: attributes on expressions are experimental --> $DIR/attr-stmt-expr.rs:23:5 | LL | #[expect_expr] | ^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/15701 = help: add #![feature(stmt_expr_attributes)] to the crate attributes to enable error: aborting due to 2 previous errors diff --git a/src/test/ui/proc-macro/derive-helper-shadowing.stderr b/src/test/ui/proc-macro/derive-helper-shadowing.stderr index 5f2009b384b..58139353492 100644 --- a/src/test/ui/proc-macro/derive-helper-shadowing.stderr +++ b/src/test/ui/proc-macro/derive-helper-shadowing.stderr @@ -1,9 +1,10 @@ -error[E0658]: The attribute `my_attr` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `my_attr` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/derive-helper-shadowing.rs:20:15 | LL | #[my_attr] | ^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable error[E0659]: `my_attr` is ambiguous (derive helper attribute vs any other name) diff --git a/src/test/ui/proc-macro/derive-still-gated.stderr b/src/test/ui/proc-macro/derive-still-gated.stderr index f7c8960372e..d235343ff16 100644 --- a/src/test/ui/proc-macro/derive-still-gated.stderr +++ b/src/test/ui/proc-macro/derive-still-gated.stderr @@ -1,9 +1,10 @@ -error[E0658]: The attribute `derive_A` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `derive_A` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/derive-still-gated.rs:8:3 | LL | #[derive_A] | ^^^^^^^^ help: a built-in attribute with a similar name exists: `derive` | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/proc-macro/dollar-crate-issue-57089.stdout b/src/test/ui/proc-macro/dollar-crate-issue-57089.stdout index 09340988c89..618380d7f0b 100644 --- a/src/test/ui/proc-macro/dollar-crate-issue-57089.stdout +++ b/src/test/ui/proc-macro/dollar-crate-issue-57089.stdout @@ -2,79 +2,79 @@ PROC MACRO INPUT (PRETTY-PRINTED): struct M ( $crate :: S ) ; PROC MACRO INPUT: TokenStream [ Ident { ident: "struct", - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Ident { ident: "M", - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Punct { ch: ':', spacing: Joint, - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Punct { ch: ':', spacing: Alone, - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Ident { ident: "S", - span: #2 bytes(LO..HI) - } + span: #2 bytes(LO..HI), + }, ], - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Punct { ch: ';', spacing: Alone, - span: #2 bytes(LO..HI) - } + span: #2 bytes(LO..HI), + }, ] ATTRIBUTE INPUT (PRETTY-PRINTED): struct A(crate::S); ATTRIBUTE INPUT: TokenStream [ Ident { ident: "struct", - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Ident { ident: "A", - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Punct { ch: ':', spacing: Joint, - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Punct { ch: ':', spacing: Alone, - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Ident { ident: "S", - span: #2 bytes(LO..HI) - } + span: #2 bytes(LO..HI), + }, ], - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Punct { ch: ';', spacing: Alone, - span: #2 bytes(LO..HI) - } + span: #2 bytes(LO..HI), + }, ] diff --git a/src/test/ui/proc-macro/dollar-crate.stdout b/src/test/ui/proc-macro/dollar-crate.stdout index c47b3603f41..454da539430 100644 --- a/src/test/ui/proc-macro/dollar-crate.stdout +++ b/src/test/ui/proc-macro/dollar-crate.stdout @@ -2,239 +2,239 @@ PROC MACRO INPUT (PRETTY-PRINTED): struct M ( $crate :: S ) ; PROC MACRO INPUT: TokenStream [ Ident { ident: "struct", - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Ident { ident: "M", - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Punct { ch: ':', spacing: Joint, - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Punct { ch: ':', spacing: Alone, - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Ident { ident: "S", - span: #2 bytes(LO..HI) - } + span: #2 bytes(LO..HI), + }, ], - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Punct { ch: ';', spacing: Alone, - span: #2 bytes(LO..HI) - } + span: #2 bytes(LO..HI), + }, ] ATTRIBUTE INPUT (PRETTY-PRINTED): struct A(crate::S); ATTRIBUTE INPUT: TokenStream [ Ident { ident: "struct", - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Ident { ident: "A", - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Punct { ch: ':', spacing: Joint, - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Punct { ch: ':', spacing: Alone, - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Ident { ident: "S", - span: #2 bytes(LO..HI) - } + span: #2 bytes(LO..HI), + }, ], - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Punct { ch: ';', spacing: Alone, - span: #2 bytes(LO..HI) - } + span: #2 bytes(LO..HI), + }, ] DERIVE INPUT (PRETTY-PRINTED): struct D(crate::S); DERIVE INPUT: TokenStream [ Ident { ident: "struct", - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Ident { ident: "D", - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Punct { ch: ':', spacing: Joint, - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Punct { ch: ':', spacing: Alone, - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Ident { ident: "S", - span: #2 bytes(LO..HI) - } + span: #2 bytes(LO..HI), + }, ], - span: #2 bytes(LO..HI) + span: #2 bytes(LO..HI), }, Punct { ch: ';', spacing: Alone, - span: #2 bytes(LO..HI) - } + span: #2 bytes(LO..HI), + }, ] PROC MACRO INPUT (PRETTY-PRINTED): struct M ( $crate :: S ) ; PROC MACRO INPUT: TokenStream [ Ident { ident: "struct", - span: #10 bytes(LO..HI) + span: #10 bytes(LO..HI), }, Ident { ident: "M", - span: #10 bytes(LO..HI) + span: #10 bytes(LO..HI), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: #10 bytes(LO..HI) + span: #10 bytes(LO..HI), }, Punct { ch: ':', spacing: Joint, - span: #10 bytes(LO..HI) + span: #10 bytes(LO..HI), }, Punct { ch: ':', spacing: Alone, - span: #10 bytes(LO..HI) + span: #10 bytes(LO..HI), }, Ident { ident: "S", - span: #10 bytes(LO..HI) - } + span: #10 bytes(LO..HI), + }, ], - span: #10 bytes(LO..HI) + span: #10 bytes(LO..HI), }, Punct { ch: ';', spacing: Alone, - span: #10 bytes(LO..HI) - } + span: #10 bytes(LO..HI), + }, ] ATTRIBUTE INPUT (PRETTY-PRINTED): struct A(::dollar_crate_external::S); ATTRIBUTE INPUT: TokenStream [ Ident { ident: "struct", - span: #10 bytes(LO..HI) + span: #10 bytes(LO..HI), }, Ident { ident: "A", - span: #10 bytes(LO..HI) + span: #10 bytes(LO..HI), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: #10 bytes(LO..HI) + span: #10 bytes(LO..HI), }, Punct { ch: ':', spacing: Joint, - span: #10 bytes(LO..HI) + span: #10 bytes(LO..HI), }, Punct { ch: ':', spacing: Alone, - span: #10 bytes(LO..HI) + span: #10 bytes(LO..HI), }, Ident { ident: "S", - span: #10 bytes(LO..HI) - } + span: #10 bytes(LO..HI), + }, ], - span: #10 bytes(LO..HI) + span: #10 bytes(LO..HI), }, Punct { ch: ';', spacing: Alone, - span: #10 bytes(LO..HI) - } + span: #10 bytes(LO..HI), + }, ] DERIVE INPUT (PRETTY-PRINTED): struct D(::dollar_crate_external::S); DERIVE INPUT: TokenStream [ Ident { ident: "struct", - span: #10 bytes(LO..HI) + span: #10 bytes(LO..HI), }, Ident { ident: "D", - span: #10 bytes(LO..HI) + span: #10 bytes(LO..HI), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: #10 bytes(LO..HI) + span: #10 bytes(LO..HI), }, Punct { ch: ':', spacing: Joint, - span: #10 bytes(LO..HI) + span: #10 bytes(LO..HI), }, Punct { ch: ':', spacing: Alone, - span: #10 bytes(LO..HI) + span: #10 bytes(LO..HI), }, Ident { ident: "S", - span: #10 bytes(LO..HI) - } + span: #10 bytes(LO..HI), + }, ], - span: #10 bytes(LO..HI) + span: #10 bytes(LO..HI), }, Punct { ch: ';', spacing: Alone, - span: #10 bytes(LO..HI) - } + span: #10 bytes(LO..HI), + }, ] diff --git a/src/test/ui/proc-macro/expand-to-unstable-2.stderr b/src/test/ui/proc-macro/expand-to-unstable-2.stderr index b322f8e9d56..e2f51dd3d5d 100644 --- a/src/test/ui/proc-macro/expand-to-unstable-2.stderr +++ b/src/test/ui/proc-macro/expand-to-unstable-2.stderr @@ -1,9 +1,10 @@ -error[E0658]: unless otherwise specified, attributes with the prefix `rustc_` are reserved for internal compiler diagnostics (see issue #29642) +error[E0658]: unless otherwise specified, attributes with the prefix `rustc_` are reserved for internal compiler diagnostics --> $DIR/expand-to-unstable-2.rs:8:10 | LL | #[derive(Unstable)] | ^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(rustc_attrs)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/proc-macro/issue-41211.stderr b/src/test/ui/proc-macro/issue-41211.stderr index f75481e4829..dfb2f6f63d8 100644 --- a/src/test/ui/proc-macro/issue-41211.stderr +++ b/src/test/ui/proc-macro/issue-41211.stderr @@ -1,9 +1,10 @@ -error[E0658]: The attribute `emit_unchanged` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `emit_unchanged` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/issue-41211.rs:8:4 | LL | #![emit_unchanged] | ^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable error: inconsistent resolution for a macro: first custom attribute, then attribute macro diff --git a/src/test/ui/proc-macro/macros-in-extern.stderr b/src/test/ui/proc-macro/macros-in-extern.stderr index 8a48656d087..61571650f2f 100644 --- a/src/test/ui/proc-macro/macros-in-extern.stderr +++ b/src/test/ui/proc-macro/macros-in-extern.stderr @@ -1,25 +1,28 @@ -error[E0658]: macro invocations in `extern {}` blocks are experimental (see issue #49476) +error[E0658]: macro invocations in `extern {}` blocks are experimental --> $DIR/macros-in-extern.rs:15:5 | LL | #[no_output] | ^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/49476 = help: add #![feature(macros_in_extern)] to the crate attributes to enable -error[E0658]: macro invocations in `extern {}` blocks are experimental (see issue #49476) +error[E0658]: macro invocations in `extern {}` blocks are experimental --> $DIR/macros-in-extern.rs:19:5 | LL | #[nop_attr] | ^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/49476 = help: add #![feature(macros_in_extern)] to the crate attributes to enable -error[E0658]: macro invocations in `extern {}` blocks are experimental (see issue #49476) +error[E0658]: macro invocations in `extern {}` blocks are experimental --> $DIR/macros-in-extern.rs:23:5 | LL | emit_input!(fn rust_dbg_extern_identity_u32(arg: u32) -> u32;); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/49476 = help: add #![feature(macros_in_extern)] to the crate attributes to enable error: aborting due to 3 previous errors diff --git a/src/test/ui/proc-macro/more-gates.stderr b/src/test/ui/proc-macro/more-gates.stderr index c6c2954f939..80985ce7523 100644 --- a/src/test/ui/proc-macro/more-gates.stderr +++ b/src/test/ui/proc-macro/more-gates.stderr @@ -1,41 +1,46 @@ -error[E0658]: procedural macros cannot expand to macro definitions (see issue #54727) +error[E0658]: procedural macros cannot expand to macro definitions --> $DIR/more-gates.rs:9:1 | LL | #[attr2mac1] | ^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/54727 = help: add #![feature(proc_macro_hygiene)] to the crate attributes to enable -error[E0658]: procedural macros cannot expand to macro definitions (see issue #54727) +error[E0658]: procedural macros cannot expand to macro definitions --> $DIR/more-gates.rs:12:1 | LL | #[attr2mac2] | ^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/54727 = help: add #![feature(proc_macro_hygiene)] to the crate attributes to enable -error[E0658]: procedural macros cannot expand to macro definitions (see issue #54727) +error[E0658]: procedural macros cannot expand to macro definitions --> $DIR/more-gates.rs:16:1 | LL | mac2mac1!(); | ^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/54727 = help: add #![feature(proc_macro_hygiene)] to the crate attributes to enable -error[E0658]: procedural macros cannot expand to macro definitions (see issue #54727) +error[E0658]: procedural macros cannot expand to macro definitions --> $DIR/more-gates.rs:17:1 | LL | mac2mac2!(); | ^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/54727 = help: add #![feature(proc_macro_hygiene)] to the crate attributes to enable -error[E0658]: procedural macros cannot expand to macro definitions (see issue #54727) +error[E0658]: procedural macros cannot expand to macro definitions --> $DIR/more-gates.rs:19:1 | LL | tricky!(); | ^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/54727 = help: add #![feature(proc_macro_hygiene)] to the crate attributes to enable error: aborting due to 5 previous errors diff --git a/src/test/ui/proc-macro/proc-macro-attributes.stderr b/src/test/ui/proc-macro/proc-macro-attributes.stderr index f8f1e7cd988..084c7289d04 100644 --- a/src/test/ui/proc-macro/proc-macro-attributes.stderr +++ b/src/test/ui/proc-macro/proc-macro-attributes.stderr @@ -1,9 +1,10 @@ -error[E0658]: The attribute `C` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `C` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/proc-macro-attributes.rs:7:3 | LL | #[C] | ^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable error[E0659]: `B` is ambiguous (derive helper attribute vs any other name) diff --git a/src/test/ui/proc-macro/proc-macro-gates.stderr b/src/test/ui/proc-macro/proc-macro-gates.stderr index 4ae8e63df72..1bb864b52ea 100644 --- a/src/test/ui/proc-macro/proc-macro-gates.stderr +++ b/src/test/ui/proc-macro/proc-macro-gates.stderr @@ -1,33 +1,37 @@ -error[E0658]: non-builtin inner attributes are unstable (see issue #54726) +error[E0658]: non-builtin inner attributes are unstable --> $DIR/proc-macro-gates.rs:11:5 | LL | #![a] | ^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/54726 = help: add #![feature(custom_inner_attributes)] to the crate attributes to enable -error[E0658]: non-builtin inner attributes are unstable (see issue #54726) +error[E0658]: non-builtin inner attributes are unstable --> $DIR/proc-macro-gates.rs:18:5 | LL | #![a] | ^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/54726 = help: add #![feature(custom_inner_attributes)] to the crate attributes to enable -error[E0658]: custom attributes cannot be applied to modules (see issue #54727) +error[E0658]: custom attributes cannot be applied to modules --> $DIR/proc-macro-gates.rs:14:1 | LL | #[a] | ^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/54727 = help: add #![feature(proc_macro_hygiene)] to the crate attributes to enable -error[E0658]: custom attributes cannot be applied to modules (see issue #54727) +error[E0658]: custom attributes cannot be applied to modules --> $DIR/proc-macro-gates.rs:18:5 | LL | #![a] | ^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/54727 = help: add #![feature(proc_macro_hygiene)] to the crate attributes to enable error: custom attribute invocations must be of the form #[foo] or #[foo(..)], the macro name must only be followed by a delimiter token @@ -36,100 +40,112 @@ error: custom attribute invocations must be of the form #[foo] or #[foo(..)], th LL | #[a = "y"] | ^^^^^^^^^^ -error[E0658]: custom attributes cannot be applied to statements (see issue #54727) +error[E0658]: custom attributes cannot be applied to statements --> $DIR/proc-macro-gates.rs:31:5 | LL | #[a] | ^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/54727 = help: add #![feature(proc_macro_hygiene)] to the crate attributes to enable -error[E0658]: custom attributes cannot be applied to statements (see issue #54727) +error[E0658]: custom attributes cannot be applied to statements --> $DIR/proc-macro-gates.rs:35:5 | LL | #[a] | ^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/54727 = help: add #![feature(proc_macro_hygiene)] to the crate attributes to enable -error[E0658]: custom attributes cannot be applied to statements (see issue #54727) +error[E0658]: custom attributes cannot be applied to statements --> $DIR/proc-macro-gates.rs:39:5 | LL | #[a] | ^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/54727 = help: add #![feature(proc_macro_hygiene)] to the crate attributes to enable -error[E0658]: custom attributes cannot be applied to expressions (see issue #54727) +error[E0658]: custom attributes cannot be applied to expressions --> $DIR/proc-macro-gates.rs:43:14 | LL | let _x = #[a] 2; | ^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/54727 = help: add #![feature(proc_macro_hygiene)] to the crate attributes to enable -error[E0658]: custom attributes cannot be applied to expressions (see issue #54727) +error[E0658]: custom attributes cannot be applied to expressions --> $DIR/proc-macro-gates.rs:46:15 | LL | let _x = [#[a] 2]; | ^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/54727 = help: add #![feature(proc_macro_hygiene)] to the crate attributes to enable -error[E0658]: custom attributes cannot be applied to expressions (see issue #54727) +error[E0658]: custom attributes cannot be applied to expressions --> $DIR/proc-macro-gates.rs:49:14 | LL | let _x = #[a] println!(); | ^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/54727 = help: add #![feature(proc_macro_hygiene)] to the crate attributes to enable -error[E0658]: procedural macros cannot be expanded to types (see issue #54727) +error[E0658]: procedural macros cannot be expanded to types --> $DIR/proc-macro-gates.rs:53:13 | LL | let _x: m!(u32) = 3; | ^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/54727 = help: add #![feature(proc_macro_hygiene)] to the crate attributes to enable -error[E0658]: procedural macros cannot be expanded to patterns (see issue #54727) +error[E0658]: procedural macros cannot be expanded to patterns --> $DIR/proc-macro-gates.rs:54:12 | LL | if let m!(Some(_x)) = Some(3) {} | ^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/54727 = help: add #![feature(proc_macro_hygiene)] to the crate attributes to enable -error[E0658]: procedural macros cannot be expanded to statements (see issue #54727) +error[E0658]: procedural macros cannot be expanded to statements --> $DIR/proc-macro-gates.rs:56:5 | LL | m!(struct S;); | ^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/54727 = help: add #![feature(proc_macro_hygiene)] to the crate attributes to enable -error[E0658]: procedural macros cannot be expanded to statements (see issue #54727) +error[E0658]: procedural macros cannot be expanded to statements --> $DIR/proc-macro-gates.rs:57:5 | LL | m!(let _x = 3;); | ^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/54727 = help: add #![feature(proc_macro_hygiene)] to the crate attributes to enable -error[E0658]: procedural macros cannot be expanded to expressions (see issue #54727) +error[E0658]: procedural macros cannot be expanded to expressions --> $DIR/proc-macro-gates.rs:59:14 | LL | let _x = m!(3); | ^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/54727 = help: add #![feature(proc_macro_hygiene)] to the crate attributes to enable -error[E0658]: procedural macros cannot be expanded to expressions (see issue #54727) +error[E0658]: procedural macros cannot be expanded to expressions --> $DIR/proc-macro-gates.rs:60:15 | LL | let _x = [m!(3)]; | ^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/54727 = help: add #![feature(proc_macro_hygiene)] to the crate attributes to enable error: aborting due to 17 previous errors diff --git a/src/test/ui/proc-macro/proc-macro-gates2.stderr b/src/test/ui/proc-macro/proc-macro-gates2.stderr index 89ad527a43c..0e8236f460f 100644 --- a/src/test/ui/proc-macro/proc-macro-gates2.stderr +++ b/src/test/ui/proc-macro/proc-macro-gates2.stderr @@ -1,17 +1,19 @@ -error[E0658]: The attribute `a` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `a` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/proc-macro-gates2.rs:13:11 | LL | fn _test6<#[a] T>() {} | ^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `a` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `a` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/proc-macro-gates2.rs:18:9 | LL | #[a] | ^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable error: aborting due to 2 previous errors diff --git a/src/test/ui/reserved/reserved-attr-on-macro.stderr b/src/test/ui/reserved/reserved-attr-on-macro.stderr index 3e082e53ca8..c8738d1ed34 100644 --- a/src/test/ui/reserved/reserved-attr-on-macro.stderr +++ b/src/test/ui/reserved/reserved-attr-on-macro.stderr @@ -1,9 +1,10 @@ -error[E0658]: unless otherwise specified, attributes with the prefix `rustc_` are reserved for internal compiler diagnostics (see issue #29642) +error[E0658]: unless otherwise specified, attributes with the prefix `rustc_` are reserved for internal compiler diagnostics --> $DIR/reserved-attr-on-macro.rs:1:3 | LL | #[rustc_attribute_should_be_reserved] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(rustc_attrs)] to the crate attributes to enable error: cannot determine resolution for the macro `foo` diff --git a/src/test/ui/resolve/resolve-variant-assoc-item.rs b/src/test/ui/resolve/resolve-variant-assoc-item.rs index f0f55c0c667..db4fedfb0bd 100644 --- a/src/test/ui/resolve/resolve-variant-assoc-item.rs +++ b/src/test/ui/resolve/resolve-variant-assoc-item.rs @@ -2,6 +2,6 @@ enum E { V } use E::V; fn main() { - E::V::associated_item; //~ ERROR failed to resolve: not a module `V` - V::associated_item; //~ ERROR failed to resolve: not a module `V` + E::V::associated_item; //~ ERROR failed to resolve: `V` is a variant, not a module + V::associated_item; //~ ERROR failed to resolve: `V` is a variant, not a module } diff --git a/src/test/ui/resolve/resolve-variant-assoc-item.stderr b/src/test/ui/resolve/resolve-variant-assoc-item.stderr index 173976d707c..4be1019968b 100644 --- a/src/test/ui/resolve/resolve-variant-assoc-item.stderr +++ b/src/test/ui/resolve/resolve-variant-assoc-item.stderr @@ -1,14 +1,14 @@ -error[E0433]: failed to resolve: not a module `V` +error[E0433]: failed to resolve: `V` is a variant, not a module --> $DIR/resolve-variant-assoc-item.rs:5:8 | LL | E::V::associated_item; - | ^ not a module `V` + | ^ `V` is a variant, not a module -error[E0433]: failed to resolve: not a module `V` +error[E0433]: failed to resolve: `V` is a variant, not a module --> $DIR/resolve-variant-assoc-item.rs:6:5 | LL | V::associated_item; - | ^ not a module `V` + | ^ `V` is a variant, not a module error: aborting due to 2 previous errors diff --git a/src/test/ui/resolve_self_super_hint.rs b/src/test/ui/resolve_self_super_hint.rs index 91a01cc0fa2..a9423830d90 100644 --- a/src/test/ui/resolve_self_super_hint.rs +++ b/src/test/ui/resolve_self_super_hint.rs @@ -1,4 +1,3 @@ -#![feature(alloc)] #![allow(unused_extern_crates)] mod a { diff --git a/src/test/ui/resolve_self_super_hint.stderr b/src/test/ui/resolve_self_super_hint.stderr index 03214cad8e4..14cdae97d14 100644 --- a/src/test/ui/resolve_self_super_hint.stderr +++ b/src/test/ui/resolve_self_super_hint.stderr @@ -1,17 +1,17 @@ error[E0432]: unresolved import `alloc` - --> $DIR/resolve_self_super_hint.rs:6:9 + --> $DIR/resolve_self_super_hint.rs:5:9 | LL | use alloc::HashMap; | ^^^^^ help: a similar path exists: `self::alloc` error[E0432]: unresolved import `alloc` - --> $DIR/resolve_self_super_hint.rs:11:13 + --> $DIR/resolve_self_super_hint.rs:10:13 | LL | use alloc::HashMap; | ^^^^^ help: a similar path exists: `super::alloc` error[E0432]: unresolved import `alloc` - --> $DIR/resolve_self_super_hint.rs:16:17 + --> $DIR/resolve_self_super_hint.rs:15:17 | LL | use alloc::HashMap; | ^^^^^ @@ -20,7 +20,7 @@ LL | use alloc::HashMap; | help: a similar path exists: `a::alloc` error[E0432]: unresolved import `alloc` - --> $DIR/resolve_self_super_hint.rs:21:21 + --> $DIR/resolve_self_super_hint.rs:20:21 | LL | use alloc::HashMap; | ^^^^^ diff --git a/src/test/ui/rfc-2361-dbg-macro/dbg-macro-expected-behavior.rs b/src/test/ui/rfc-2361-dbg-macro/dbg-macro-expected-behavior.rs index 67f7f80a9e2..f1b73ee115d 100644 --- a/src/test/ui/rfc-2361-dbg-macro/dbg-macro-expected-behavior.rs +++ b/src/test/ui/rfc-2361-dbg-macro/dbg-macro-expected-behavior.rs @@ -64,22 +64,22 @@ fn validate_stderr(stderr: Vec<String>) { ":28] Point{x: 42, y: 24,} = Point {", " x: 42,", - " y: 24", + " y: 24,", "}", ":29] b = Point {", " x: 42,", - " y: 24", + " y: 24,", "}", ":37]", ":41] &a = NoCopy(", - " 1337", + " 1337,", ")", ":41] dbg!(& a) = NoCopy(", - " 1337", + " 1337,", ")", ":46] f(&42) = 42", diff --git a/src/test/ui/rfc1445/feature-gate.no_gate.stderr b/src/test/ui/rfc1445/feature-gate.no_gate.stderr index 370b74b8779..3a2014fab09 100644 --- a/src/test/ui/rfc1445/feature-gate.no_gate.stderr +++ b/src/test/ui/rfc1445/feature-gate.no_gate.stderr @@ -1,9 +1,10 @@ -error[E0658]: the semantics of constant patterns is not yet settled (see issue #31434) +error[E0658]: the semantics of constant patterns is not yet settled --> $DIR/feature-gate.rs:13:1 | LL | #[structural_match] | ^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/31434 = help: add #![feature(structural_match)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/rust-2018/remove-extern-crate.fixed b/src/test/ui/rust-2018/remove-extern-crate.fixed index a977e00c013..17449caf84f 100644 --- a/src/test/ui/rust-2018/remove-extern-crate.fixed +++ b/src/test/ui/rust-2018/remove-extern-crate.fixed @@ -4,7 +4,6 @@ // aux-build:remove-extern-crate.rs // compile-flags:--extern remove_extern_crate -#![feature(alloc)] #![warn(rust_2018_idioms)] diff --git a/src/test/ui/rust-2018/remove-extern-crate.rs b/src/test/ui/rust-2018/remove-extern-crate.rs index cafe82d846e..fb2217df000 100644 --- a/src/test/ui/rust-2018/remove-extern-crate.rs +++ b/src/test/ui/rust-2018/remove-extern-crate.rs @@ -4,7 +4,6 @@ // aux-build:remove-extern-crate.rs // compile-flags:--extern remove_extern_crate -#![feature(alloc)] #![warn(rust_2018_idioms)] extern crate core; diff --git a/src/test/ui/rust-2018/remove-extern-crate.stderr b/src/test/ui/rust-2018/remove-extern-crate.stderr index 4e08b7aa6a0..549693201b7 100644 --- a/src/test/ui/rust-2018/remove-extern-crate.stderr +++ b/src/test/ui/rust-2018/remove-extern-crate.stderr @@ -1,24 +1,24 @@ warning: unused extern crate - --> $DIR/remove-extern-crate.rs:10:1 + --> $DIR/remove-extern-crate.rs:9:1 | LL | extern crate core; | ^^^^^^^^^^^^^^^^^^ help: remove it | note: lint level defined here - --> $DIR/remove-extern-crate.rs:8:9 + --> $DIR/remove-extern-crate.rs:7:9 | LL | #![warn(rust_2018_idioms)] | ^^^^^^^^^^^^^^^^ = note: #[warn(unused_extern_crates)] implied by #[warn(rust_2018_idioms)] warning: `extern crate` is not idiomatic in the new edition - --> $DIR/remove-extern-crate.rs:11:1 + --> $DIR/remove-extern-crate.rs:10:1 | LL | extern crate core as another_name; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: convert it to a `use` warning: `extern crate` is not idiomatic in the new edition - --> $DIR/remove-extern-crate.rs:29:5 + --> $DIR/remove-extern-crate.rs:28:5 | LL | extern crate core; | ^^^^^^^^^^^^^^^^^^ help: convert it to a `use` diff --git a/src/test/ui/rust-2018/uniform-paths/prelude-fail.stderr b/src/test/ui/rust-2018/uniform-paths/prelude-fail.stderr index a61af699cdc..42daf7c6fb1 100644 --- a/src/test/ui/rust-2018/uniform-paths/prelude-fail.stderr +++ b/src/test/ui/rust-2018/uniform-paths/prelude-fail.stderr @@ -8,7 +8,7 @@ error[E0432]: unresolved import `rustfmt` --> $DIR/prelude-fail.rs:7:5 | LL | use rustfmt::skip as imported_rustfmt_skip; - | ^^^^^^^ not a module `rustfmt` + | ^^^^^^^ `rustfmt` is a tool module, not a module error: aborting due to 2 previous errors diff --git a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.nll.stderr b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.nll.stderr index 1a5ab7a7d56..4e2ab59f822 100644 --- a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.nll.stderr +++ b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.nll.stderr @@ -18,7 +18,7 @@ LL | fn test2<F>(f: &F) where F: FnMut() { LL | (*f)(); | ^^^^ `f` is a `&` reference, so the data it refers to cannot be borrowed as mutable -error[E0596]: cannot borrow `*f.f` as mutable, as it is behind a `&` reference +error[E0596]: cannot borrow `f.f` as mutable, as it is behind a `&` reference --> $DIR/borrowck-call-is-borrow-issue-12224.rs:34:5 | LL | fn test4(f: &Test) { diff --git a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.rs b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.rs index cfebd6f7003..f246f1118bf 100644 --- a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.rs +++ b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.rs @@ -32,7 +32,7 @@ fn test3<F>(f: &mut F) where F: FnMut() { fn test4(f: &Test) { f.f.call_mut(()) - //~^ ERROR: cannot borrow `Box` content `*f.f` of immutable binding as mutable + //~^ ERROR: cannot borrow field `f.f` of immutable binding as mutable } fn test5(f: &mut Test) { diff --git a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr index 6c8f477e310..a61ee8334af 100644 --- a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr +++ b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr @@ -19,13 +19,13 @@ LL | fn test2<F>(f: &F) where F: FnMut() { LL | (*f)(); | ^^^^ cannot borrow as mutable -error[E0596]: cannot borrow `Box` content `*f.f` of immutable binding as mutable +error[E0596]: cannot borrow field `f.f` of immutable binding as mutable --> $DIR/borrowck-call-is-borrow-issue-12224.rs:34:5 | LL | fn test4(f: &Test) { | ----- use `&mut Test` here to make mutable LL | f.f.call_mut(()) - | ^^^ cannot borrow as mutable + | ^^^ cannot mutably borrow field of immutable binding error[E0504]: cannot move `f` into closure because it is borrowed --> $DIR/borrowck-call-is-borrow-issue-12224.rs:56:13 diff --git a/src/test/ui/span/gated-features-attr-spans.stderr b/src/test/ui/span/gated-features-attr-spans.stderr index 45d14f32f96..938edbe463f 100644 --- a/src/test/ui/span/gated-features-attr-spans.stderr +++ b/src/test/ui/span/gated-features-attr-spans.stderr @@ -1,9 +1,10 @@ -error[E0658]: SIMD types are experimental and possibly buggy (see issue #27731) +error[E0658]: SIMD types are experimental and possibly buggy --> $DIR/gated-features-attr-spans.rs:1:1 | LL | #[repr(simd)] | ^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/27731 = help: add #![feature(repr_simd)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/span/issue-36530.stderr b/src/test/ui/span/issue-36530.stderr index 05b2ca90570..ee479d6c791 100644 --- a/src/test/ui/span/issue-36530.stderr +++ b/src/test/ui/span/issue-36530.stderr @@ -1,25 +1,28 @@ -error[E0658]: The attribute `foo` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `foo` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/issue-36530.rs:3:3 | LL | #[foo] | ^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: non-builtin inner attributes are unstable (see issue #54726) +error[E0658]: non-builtin inner attributes are unstable --> $DIR/issue-36530.rs:5:5 | LL | #![foo] | ^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/54726 = help: add #![feature(custom_inner_attributes)] to the crate attributes to enable -error[E0658]: The attribute `foo` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `foo` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/issue-36530.rs:5:8 | LL | #![foo] | ^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable error: aborting due to 3 previous errors diff --git a/src/test/ui/specialization/defaultimpl/specialization-feature-gate-default.stderr b/src/test/ui/specialization/defaultimpl/specialization-feature-gate-default.stderr index 0b20a19d2e1..b95e62edaaa 100644 --- a/src/test/ui/specialization/defaultimpl/specialization-feature-gate-default.stderr +++ b/src/test/ui/specialization/defaultimpl/specialization-feature-gate-default.stderr @@ -1,4 +1,4 @@ -error[E0658]: specialization is unstable (see issue #31844) +error[E0658]: specialization is unstable --> $DIR/specialization-feature-gate-default.rs:7:1 | LL | / default impl<T> Foo for T { @@ -6,6 +6,7 @@ LL | | fn foo(&self) {} LL | | } | |_^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/31844 = help: add #![feature(specialization)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/specialization/specialization-feature-gate-default.stderr b/src/test/ui/specialization/specialization-feature-gate-default.stderr index ad33908eff6..e649f2aa47a 100644 --- a/src/test/ui/specialization/specialization-feature-gate-default.stderr +++ b/src/test/ui/specialization/specialization-feature-gate-default.stderr @@ -1,9 +1,10 @@ -error[E0658]: specialization is unstable (see issue #31844) +error[E0658]: specialization is unstable --> $DIR/specialization-feature-gate-default.rs:10:5 | LL | default fn foo(&self) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/31844 = help: add #![feature(specialization)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/stability-attribute/stability-attribute-issue.rs b/src/test/ui/stability-attribute/stability-attribute-issue.rs index fc4a7dab1af..ca4d7cc6a6c 100644 --- a/src/test/ui/stability-attribute/stability-attribute-issue.rs +++ b/src/test/ui/stability-attribute/stability-attribute-issue.rs @@ -8,7 +8,7 @@ use stability_attribute_issue::*; fn main() { unstable(); - //~^ ERROR use of unstable library feature 'unstable_test_feature' (see issue #1) + //~^ ERROR use of unstable library feature 'unstable_test_feature' unstable_msg(); - //~^ ERROR use of unstable library feature 'unstable_test_feature': message (see issue #2) + //~^ ERROR use of unstable library feature 'unstable_test_feature': message } diff --git a/src/test/ui/stability-attribute/stability-attribute-issue.stderr b/src/test/ui/stability-attribute/stability-attribute-issue.stderr index 94fdc0db3d9..36e192e583e 100644 --- a/src/test/ui/stability-attribute/stability-attribute-issue.stderr +++ b/src/test/ui/stability-attribute/stability-attribute-issue.stderr @@ -1,17 +1,19 @@ -error[E0658]: use of unstable library feature 'unstable_test_feature' (see issue #1) +error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/stability-attribute-issue.rs:10:5 | LL | unstable(); | ^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/1 = help: add #![feature(unstable_test_feature)] to the crate attributes to enable -error[E0658]: use of unstable library feature 'unstable_test_feature': message (see issue #2) +error[E0658]: use of unstable library feature 'unstable_test_feature': message --> $DIR/stability-attribute-issue.rs:12:5 | LL | unstable_msg(); | ^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/2 = help: add #![feature(unstable_test_feature)] to the crate attributes to enable error: aborting due to 2 previous errors diff --git a/src/test/ui/stmt_expr_attrs_no_feature.rs b/src/test/ui/stmt_expr_attrs_no_feature.rs index 0a71d8d1333..8952175e425 100644 --- a/src/test/ui/stmt_expr_attrs_no_feature.rs +++ b/src/test/ui/stmt_expr_attrs_no_feature.rs @@ -91,42 +91,42 @@ item_mac!(e); extern { #[cfg(unset)] fn x(a: [u8; #[attr] 5]); - fn y(a: [u8; #[attr] 5]); //~ ERROR 15701 + fn y(a: [u8; #[attr] 5]); //~ ERROR attributes on expressions are experimental } struct Foo; impl Foo { #[cfg(unset)] const X: u8 = #[attr] 5; - const Y: u8 = #[attr] 5; //~ ERROR 15701 + const Y: u8 = #[attr] 5; //~ ERROR attributes on expressions are experimental } trait Bar { #[cfg(unset)] const X: [u8; #[attr] 5]; - const Y: [u8; #[attr] 5]; //~ ERROR 15701 + const Y: [u8; #[attr] 5]; //~ ERROR attributes on expressions are experimental } struct Joyce { #[cfg(unset)] field: [u8; #[attr] 5], - field2: [u8; #[attr] 5] //~ ERROR 15701 + field2: [u8; #[attr] 5] //~ ERROR attributes on expressions are experimental } struct Walky( #[cfg(unset)] [u8; #[attr] 5], - [u8; #[attr] 5] //~ ERROR 15701 + [u8; #[attr] 5] //~ ERROR attributes on expressions are experimental ); enum Mike { Happy( #[cfg(unset)] [u8; #[attr] 5], - [u8; #[attr] 5] //~ ERROR 15701 + [u8; #[attr] 5] //~ ERROR attributes on expressions are experimental ), Angry { #[cfg(unset)] field: [u8; #[attr] 5], - field2: [u8; #[attr] 5] //~ ERROR 15701 + field2: [u8; #[attr] 5] //~ ERROR attributes on expressions are experimental } } @@ -134,7 +134,7 @@ fn pat() { match 5 { #[cfg(unset)] 5 => #[attr] (), - 6 => #[attr] (), //~ ERROR 15701 + 6 => #[attr] (), //~ ERROR attributes on expressions are experimental _ => (), } } diff --git a/src/test/ui/stmt_expr_attrs_no_feature.stderr b/src/test/ui/stmt_expr_attrs_no_feature.stderr index c644126535d..1b5e989af7b 100644 --- a/src/test/ui/stmt_expr_attrs_no_feature.stderr +++ b/src/test/ui/stmt_expr_attrs_no_feature.stderr @@ -1,73 +1,82 @@ -error[E0658]: attributes on expressions are experimental. (see issue #15701) +error[E0658]: attributes on expressions are experimental --> $DIR/stmt_expr_attrs_no_feature.rs:13:5 | LL | #[attr] | ^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/15701 = help: add #![feature(stmt_expr_attributes)] to the crate attributes to enable -error[E0658]: attributes on expressions are experimental. (see issue #15701) +error[E0658]: attributes on expressions are experimental --> $DIR/stmt_expr_attrs_no_feature.rs:94:18 | LL | fn y(a: [u8; #[attr] 5]); | ^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/15701 = help: add #![feature(stmt_expr_attributes)] to the crate attributes to enable -error[E0658]: attributes on expressions are experimental. (see issue #15701) +error[E0658]: attributes on expressions are experimental --> $DIR/stmt_expr_attrs_no_feature.rs:101:19 | LL | const Y: u8 = #[attr] 5; | ^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/15701 = help: add #![feature(stmt_expr_attributes)] to the crate attributes to enable -error[E0658]: attributes on expressions are experimental. (see issue #15701) +error[E0658]: attributes on expressions are experimental --> $DIR/stmt_expr_attrs_no_feature.rs:107:19 | LL | const Y: [u8; #[attr] 5]; | ^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/15701 = help: add #![feature(stmt_expr_attributes)] to the crate attributes to enable -error[E0658]: attributes on expressions are experimental. (see issue #15701) +error[E0658]: attributes on expressions are experimental --> $DIR/stmt_expr_attrs_no_feature.rs:113:18 | LL | field2: [u8; #[attr] 5] | ^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/15701 = help: add #![feature(stmt_expr_attributes)] to the crate attributes to enable -error[E0658]: attributes on expressions are experimental. (see issue #15701) +error[E0658]: attributes on expressions are experimental --> $DIR/stmt_expr_attrs_no_feature.rs:118:10 | LL | [u8; #[attr] 5] | ^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/15701 = help: add #![feature(stmt_expr_attributes)] to the crate attributes to enable -error[E0658]: attributes on expressions are experimental. (see issue #15701) +error[E0658]: attributes on expressions are experimental --> $DIR/stmt_expr_attrs_no_feature.rs:124:14 | LL | [u8; #[attr] 5] | ^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/15701 = help: add #![feature(stmt_expr_attributes)] to the crate attributes to enable -error[E0658]: attributes on expressions are experimental. (see issue #15701) +error[E0658]: attributes on expressions are experimental --> $DIR/stmt_expr_attrs_no_feature.rs:129:22 | LL | field2: [u8; #[attr] 5] | ^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/15701 = help: add #![feature(stmt_expr_attributes)] to the crate attributes to enable -error[E0658]: attributes on expressions are experimental. (see issue #15701) +error[E0658]: attributes on expressions are experimental --> $DIR/stmt_expr_attrs_no_feature.rs:137:14 | LL | 6 => #[attr] (), | ^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/15701 = help: add #![feature(stmt_expr_attributes)] to the crate attributes to enable error: aborting due to 9 previous errors diff --git a/src/test/ui/suggestions/attribute-typos.stderr b/src/test/ui/suggestions/attribute-typos.stderr index 077c955431a..8367ff20aa4 100644 --- a/src/test/ui/suggestions/attribute-typos.stderr +++ b/src/test/ui/suggestions/attribute-typos.stderr @@ -1,25 +1,28 @@ -error[E0658]: unless otherwise specified, attributes with the prefix `rustc_` are reserved for internal compiler diagnostics (see issue #29642) +error[E0658]: unless otherwise specified, attributes with the prefix `rustc_` are reserved for internal compiler diagnostics --> $DIR/attribute-typos.rs:11:3 | LL | #[rustc_err] | ^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(rustc_attrs)] to the crate attributes to enable -error[E0658]: The attribute `tests` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `tests` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/attribute-typos.rs:6:3 | LL | #[tests] | ^^^^^ help: a built-in attribute with a similar name exists: `test` | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable -error[E0658]: The attribute `deprcated` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642) +error[E0658]: The attribute `deprcated` is currently unknown to the compiler and may have meaning added to it in the future --> $DIR/attribute-typos.rs:1:3 | LL | #[deprcated] | ^^^^^^^^^ help: a built-in attribute with a similar name exists: `deprecated` | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable error: aborting due to 3 previous errors diff --git a/src/test/ui/suggestions/suggest-methods.stderr b/src/test/ui/suggestions/suggest-methods.stderr index 09d58575d97..ad4a4deb5a8 100644 --- a/src/test/ui/suggestions/suggest-methods.stderr +++ b/src/test/ui/suggestions/suggest-methods.stderr @@ -5,19 +5,19 @@ LL | struct Foo; | ----------- method `bat` not found for this ... LL | f.bat(1.0); - | ^^^ help: did you mean: `bar` + | ^^^ help: there is a method with a similar name: `bar` error[E0599]: no method named `is_emtpy` found for type `std::string::String` in the current scope --> $DIR/suggest-methods.rs:21:15 | LL | let _ = s.is_emtpy(); - | ^^^^^^^^ help: did you mean: `is_empty` + | ^^^^^^^^ help: there is a method with a similar name: `is_empty` error[E0599]: no method named `count_eos` found for type `u32` in the current scope --> $DIR/suggest-methods.rs:25:19 | LL | let _ = 63u32.count_eos(); - | ^^^^^^^^^ help: did you mean: `count_zeros` + | ^^^^^^^^^ help: there is a method with a similar name: `count_zeros` error[E0599]: no method named `count_o` found for type `u32` in the current scope --> $DIR/suggest-methods.rs:28:19 diff --git a/src/test/ui/suggestions/suggest-variants.rs b/src/test/ui/suggestions/suggest-variants.rs index 6d6e280d965..d418834432e 100644 --- a/src/test/ui/suggestions/suggest-variants.rs +++ b/src/test/ui/suggestions/suggest-variants.rs @@ -12,4 +12,7 @@ fn main() { println!("My shape is {:?}", Shape::Squareee { size: 5}); //~ ERROR no variant `Squareee` println!("My shape is {:?}", Shape::Circl { size: 5}); //~ ERROR no variant `Circl` println!("My shape is {:?}", Shape::Rombus{ size: 5}); //~ ERROR no variant `Rombus` + Shape::Squareee; //~ ERROR no variant + Shape::Circl; //~ ERROR no variant + Shape::Rombus; //~ ERROR no variant } diff --git a/src/test/ui/suggestions/suggest-variants.stderr b/src/test/ui/suggestions/suggest-variants.stderr index 08ae68ea713..ef0ba70c340 100644 --- a/src/test/ui/suggestions/suggest-variants.stderr +++ b/src/test/ui/suggestions/suggest-variants.stderr @@ -1,20 +1,65 @@ -error: no variant `Squareee` on enum `Shape` - --> $DIR/suggest-variants.rs:12:34 +error: no variant `Squareee` in enum `Shape` + --> $DIR/suggest-variants.rs:12:41 | +LL | enum Shape { + | ---------- variant `Squareee` not found here +... LL | println!("My shape is {:?}", Shape::Squareee { size: 5}); - | ^^^^^^^^^^^^^^^ help: did you mean: `Shape::Square` + | ^^^^^^^^ help: there is a variant with a similar name: `Square` -error: no variant `Circl` on enum `Shape` - --> $DIR/suggest-variants.rs:13:34 +error: no variant `Circl` in enum `Shape` + --> $DIR/suggest-variants.rs:13:41 | +LL | enum Shape { + | ---------- variant `Circl` not found here +... LL | println!("My shape is {:?}", Shape::Circl { size: 5}); - | ^^^^^^^^^^^^ help: did you mean: `Shape::Circle` + | ^^^^^ help: there is a variant with a similar name: `Circle` -error: no variant `Rombus` on enum `Shape` - --> $DIR/suggest-variants.rs:14:34 +error: no variant `Rombus` in enum `Shape` + --> $DIR/suggest-variants.rs:14:41 | +LL | enum Shape { + | ---------- variant `Rombus` not found here +... LL | println!("My shape is {:?}", Shape::Rombus{ size: 5}); - | ^^^^^^^^^^^^^ unknown variant + | -------^^^^^^ + | | + | variant not found in `Shape` -error: aborting due to 3 previous errors +error[E0599]: no variant or associated item named `Squareee` found for type `Shape` in the current scope + --> $DIR/suggest-variants.rs:15:12 + | +LL | enum Shape { + | ---------- variant or associated item `Squareee` not found here +... +LL | Shape::Squareee; + | ^^^^^^^^ + | | + | variant or associated item not found in `Shape` + | help: there is a variant with a similar name: `Square` + +error[E0599]: no variant or associated item named `Circl` found for type `Shape` in the current scope + --> $DIR/suggest-variants.rs:16:12 + | +LL | enum Shape { + | ---------- variant or associated item `Circl` not found here +... +LL | Shape::Circl; + | ^^^^^ + | | + | variant or associated item not found in `Shape` + | help: there is a variant with a similar name: `Circle` + +error[E0599]: no variant or associated item named `Rombus` found for type `Shape` in the current scope + --> $DIR/suggest-variants.rs:17:12 + | +LL | enum Shape { + | ---------- variant or associated item `Rombus` not found here +... +LL | Shape::Rombus; + | ^^^^^^ variant or associated item not found in `Shape` + +error: aborting due to 6 previous errors +For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/syntax-trait-polarity-feature-gate.stderr b/src/test/ui/syntax-trait-polarity-feature-gate.stderr index 7b9c3da3712..86b4bc1157b 100644 --- a/src/test/ui/syntax-trait-polarity-feature-gate.stderr +++ b/src/test/ui/syntax-trait-polarity-feature-gate.stderr @@ -1,9 +1,10 @@ -error[E0658]: negative trait bounds are not yet fully implemented; use marker types for now (see issue #13231) +error[E0658]: negative trait bounds are not yet fully implemented; use marker types for now --> $DIR/syntax-trait-polarity-feature-gate.rs:7:1 | LL | impl !Send for TestType {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/13231 = help: add #![feature(optin_builtin_traits)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/target-feature-gate.stderr b/src/test/ui/target-feature-gate.stderr index 24141d0064f..155298e5062 100644 --- a/src/test/ui/target-feature-gate.stderr +++ b/src/test/ui/target-feature-gate.stderr @@ -1,9 +1,10 @@ -error[E0658]: the target feature `avx512bw` is currently unstable (see issue #44839) +error[E0658]: the target feature `avx512bw` is currently unstable --> $DIR/target-feature-gate.rs:28:18 | LL | #[target_feature(enable = "avx512bw")] | ^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/44839 = help: add #![feature(avx512_target_feature)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/trace_macros-gate.stderr b/src/test/ui/trace_macros-gate.stderr index 4d2fd554a06..e0ffcfe295f 100644 --- a/src/test/ui/trace_macros-gate.stderr +++ b/src/test/ui/trace_macros-gate.stderr @@ -1,9 +1,10 @@ -error[E0658]: `trace_macros` is not stable enough for use and is subject to change (see issue #29598) +error[E0658]: `trace_macros` is not stable enough for use and is subject to change --> $DIR/trace_macros-gate.rs:4:5 | LL | trace_macros!(); | ^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29598 = help: add #![feature(trace_macros)] to the crate attributes to enable error: trace_macros! accepts only `true` or `false` @@ -12,23 +13,25 @@ error: trace_macros! accepts only `true` or `false` LL | trace_macros!(); | ^^^^^^^^^^^^^^^^ -error[E0658]: `trace_macros` is not stable enough for use and is subject to change (see issue #29598) +error[E0658]: `trace_macros` is not stable enough for use and is subject to change --> $DIR/trace_macros-gate.rs:6:5 | LL | trace_macros!(true); | ^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29598 = help: add #![feature(trace_macros)] to the crate attributes to enable -error[E0658]: `trace_macros` is not stable enough for use and is subject to change (see issue #29598) +error[E0658]: `trace_macros` is not stable enough for use and is subject to change --> $DIR/trace_macros-gate.rs:7:5 | LL | trace_macros!(false); | ^^^^^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29598 = help: add #![feature(trace_macros)] to the crate attributes to enable -error[E0658]: `trace_macros` is not stable enough for use and is subject to change (see issue #29598) +error[E0658]: `trace_macros` is not stable enough for use and is subject to change --> $DIR/trace_macros-gate.rs:10:26 | LL | ($x: ident) => { trace_macros!($x) } @@ -37,6 +40,7 @@ LL | ($x: ident) => { trace_macros!($x) } LL | expando!(true); | --------------- in this macro invocation | + = note: for more information, see https://github.com/rust-lang/rust/issues/29598 = help: add #![feature(trace_macros)] to the crate attributes to enable error: aborting due to 5 previous errors diff --git a/src/test/ui/traits/trait-alias-ambiguous.rs b/src/test/ui/traits/trait-alias-ambiguous.rs new file mode 100644 index 00000000000..28409e0c662 --- /dev/null +++ b/src/test/ui/traits/trait-alias-ambiguous.rs @@ -0,0 +1,24 @@ +#![feature(trait_alias)] + +mod inner { + pub trait A { fn foo(&self); } + pub trait B { fn foo(&self); } + + impl A for u8 { + fn foo(&self) {} + } + impl B for u8 { + fn foo(&self) {} + } + + pub trait C = A + B; +} + +use inner::C; + +fn main() { + let t = 1u8; + t.foo(); //~ ERROR E0034 + + inner::A::foo(&t); // ok +} diff --git a/src/test/ui/traits/trait-alias-ambiguous.stderr b/src/test/ui/traits/trait-alias-ambiguous.stderr new file mode 100644 index 00000000000..b7443269b88 --- /dev/null +++ b/src/test/ui/traits/trait-alias-ambiguous.stderr @@ -0,0 +1,20 @@ +error[E0034]: multiple applicable items in scope + --> $DIR/trait-alias-ambiguous.rs:21:7 + | +LL | t.foo(); + | ^^^ multiple `foo` found + | +note: candidate #1 is defined in an impl of the trait `inner::A` for the type `u8` + --> $DIR/trait-alias-ambiguous.rs:8:9 + | +LL | fn foo(&self) {} + | ^^^^^^^^^^^^^ +note: candidate #2 is defined in an impl of the trait `inner::B` for the type `u8` + --> $DIR/trait-alias-ambiguous.rs:11:9 + | +LL | fn foo(&self) {} + | ^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0034`. diff --git a/src/test/ui/try-block/try-block-bad-type.stderr b/src/test/ui/try-block/try-block-bad-type.stderr index 6687bd9d9e1..07e7149793c 100644 --- a/src/test/ui/try-block/try-block-bad-type.stderr +++ b/src/test/ui/try-block/try-block-bad-type.stderr @@ -6,9 +6,9 @@ LL | Err("")?; | = help: the following implementations were found: <i32 as std::convert::From<bool>> - <i32 as std::convert::From<core::num::NonZeroI32>> <i32 as std::convert::From<i16>> <i32 as std::convert::From<i8>> + <i32 as std::convert::From<std::num::NonZeroI32>> and 2 others = note: required by `std::convert::From::from` diff --git a/src/test/ui/try-block/try-block-catch.rs b/src/test/ui/try-block/try-block-catch.rs new file mode 100644 index 00000000000..d165015611d --- /dev/null +++ b/src/test/ui/try-block/try-block-catch.rs @@ -0,0 +1,10 @@ +// compile-flags: --edition 2018 + +#![feature(try_blocks)] + +fn main() { + let res: Option<bool> = try { + true + } catch { }; + //~^ ERROR keyword `catch` cannot follow a `try` block +} diff --git a/src/test/ui/try-block/try-block-catch.stderr b/src/test/ui/try-block/try-block-catch.stderr new file mode 100644 index 00000000000..39cf943f4d8 --- /dev/null +++ b/src/test/ui/try-block/try-block-catch.stderr @@ -0,0 +1,10 @@ +error: keyword `catch` cannot follow a `try` block + --> $DIR/try-block-catch.rs:8:7 + | +LL | } catch { }; + | ^^^^^ + | + = help: try using `match` on the result of the `try` block instead + +error: aborting due to previous error + diff --git a/src/test/ui/ufcs/ufcs-partially-resolved.rs b/src/test/ui/ufcs/ufcs-partially-resolved.rs index 4efded8b376..82a593ff16c 100644 --- a/src/test/ui/ufcs/ufcs-partially-resolved.rs +++ b/src/test/ui/ufcs/ufcs-partially-resolved.rs @@ -45,9 +45,9 @@ fn main() { <u8 as E::N>::NN; //~ ERROR cannot find method or associated constant `NN` in `E::N` <u8 as A::N>::NN; //~ ERROR cannot find method or associated constant `NN` in `A::N` let _: <u8 as Tr::Y>::NN; //~ ERROR cannot find associated type `NN` in `Tr::Y` - let _: <u8 as E::Y>::NN; //~ ERROR failed to resolve: not a module `Y` + let _: <u8 as E::Y>::NN; //~ ERROR failed to resolve: `Y` is a variant, not a module <u8 as Tr::Y>::NN; //~ ERROR cannot find method or associated constant `NN` in `Tr::Y` - <u8 as E::Y>::NN; //~ ERROR failed to resolve: not a module `Y` + <u8 as E::Y>::NN; //~ ERROR failed to resolve: `Y` is a variant, not a module let _: <u8 as Dr>::Z; //~ ERROR expected associated type, found method `Dr::Z` <u8 as Dr>::X; //~ ERROR expected method or associated constant, found associated type `Dr::X` diff --git a/src/test/ui/ufcs/ufcs-partially-resolved.stderr b/src/test/ui/ufcs/ufcs-partially-resolved.stderr index 900c7297211..c399a32bc56 100644 --- a/src/test/ui/ufcs/ufcs-partially-resolved.stderr +++ b/src/test/ui/ufcs/ufcs-partially-resolved.stderr @@ -1,14 +1,14 @@ -error[E0433]: failed to resolve: not a module `Y` +error[E0433]: failed to resolve: `Y` is a variant, not a module --> $DIR/ufcs-partially-resolved.rs:48:22 | LL | let _: <u8 as E::Y>::NN; - | ^ not a module `Y` + | ^ `Y` is a variant, not a module -error[E0433]: failed to resolve: not a module `Y` +error[E0433]: failed to resolve: `Y` is a variant, not a module --> $DIR/ufcs-partially-resolved.rs:50:15 | LL | <u8 as E::Y>::NN; - | ^ not a module `Y` + | ^ `Y` is a variant, not a module error[E0576]: cannot find associated type `N` in trait `Tr` --> $DIR/ufcs-partially-resolved.rs:19:24 diff --git a/src/test/ui/unboxed-closures/unboxed-closure-feature-gate.stderr b/src/test/ui/unboxed-closures/unboxed-closure-feature-gate.stderr index 038167ae9d7..1604aa4a0f7 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-feature-gate.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closure-feature-gate.stderr @@ -1,9 +1,10 @@ -error[E0658]: parenthetical notation is only stable when used with `Fn`-family traits (see issue #29625) +error[E0658]: parenthetical notation is only stable when used with `Fn`-family traits --> $DIR/unboxed-closure-feature-gate.rs:13:16 | LL | let x: Box<Foo(isize)>; | ^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add #![feature(unboxed_closures)] to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/unboxed-closures/unboxed-closure-sugar-not-used-on-fn.stderr b/src/test/ui/unboxed-closures/unboxed-closure-sugar-not-used-on-fn.stderr index 90f04a52d37..0901126a3fe 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-sugar-not-used-on-fn.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closure-sugar-not-used-on-fn.stderr @@ -1,17 +1,19 @@ -error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change. Use parenthetical notation (Fn(Foo, Bar) -> Baz) instead (see issue #29625) +error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change. Use parenthetical notation (Fn(Foo, Bar) -> Baz) instead --> $DIR/unboxed-closure-sugar-not-used-on-fn.rs:3:13 | LL | fn bar1(x: &Fn<(), Output=()>) { | ^^^^^^^^^^^^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add #![feature(unboxed_closures)] to the crate attributes to enable -error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change. Use parenthetical notation (Fn(Foo, Bar) -> Baz) instead (see issue #29625) +error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change. Use parenthetical notation (Fn(Foo, Bar) -> Baz) instead --> $DIR/unboxed-closure-sugar-not-used-on-fn.rs:7:28 | LL | fn bar2<T>(x: &T) where T: Fn<()> { | ^^^^^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/29625 = help: add #![feature(unboxed_closures)] to the crate attributes to enable error: aborting due to 2 previous errors diff --git a/src/test/ui/unnecessary-extern-crate.rs b/src/test/ui/unnecessary-extern-crate.rs index e25b99bcb61..67eaaf4b6c2 100644 --- a/src/test/ui/unnecessary-extern-crate.rs +++ b/src/test/ui/unnecessary-extern-crate.rs @@ -1,7 +1,7 @@ // edition:2018 #![deny(unused_extern_crates)] -#![feature(alloc, test, rustc_private, crate_visibility_modifier)] +#![feature(test, rustc_private, crate_visibility_modifier)] extern crate libc; //~^ ERROR unused extern crate diff --git a/src/test/ui/use/use-associated-const.rs b/src/test/ui/use/use-associated-const.rs new file mode 100644 index 00000000000..714fbdabb81 --- /dev/null +++ b/src/test/ui/use/use-associated-const.rs @@ -0,0 +1,13 @@ +#![allow(unused_imports)] + +pub mod foo { + pub struct Foo; + + impl Foo { + pub const BAR: i32 = 0; + } +} + +use foo::Foo::BAR; //~ ERROR unresolved import `foo::Foo` + +fn main() {} diff --git a/src/test/ui/use/use-associated-const.stderr b/src/test/ui/use/use-associated-const.stderr new file mode 100644 index 00000000000..4bc0d7e61cb --- /dev/null +++ b/src/test/ui/use/use-associated-const.stderr @@ -0,0 +1,9 @@ +error[E0432]: unresolved import `foo::Foo` + --> $DIR/use-associated-const.rs:11:10 + | +LL | use foo::Foo::BAR; + | ^^^ `Foo` is a struct, not a module + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0432`. diff --git a/src/test/ui/use/use-from-trait-xc.stderr b/src/test/ui/use/use-from-trait-xc.stderr index 97dc603f9eb..faa4829bfdd 100644 --- a/src/test/ui/use/use-from-trait-xc.stderr +++ b/src/test/ui/use/use-from-trait-xc.stderr @@ -20,19 +20,19 @@ error[E0432]: unresolved import `use_from_trait_xc::Foo` --> $DIR/use-from-trait-xc.rs:14:24 | LL | use use_from_trait_xc::Foo::new; - | ^^^ not a module `Foo` + | ^^^ `Foo` is a struct, not a module error[E0432]: unresolved import `use_from_trait_xc::Foo` --> $DIR/use-from-trait-xc.rs:17:24 | LL | use use_from_trait_xc::Foo::C; - | ^^^ not a module `Foo` + | ^^^ `Foo` is a struct, not a module error[E0432]: unresolved import `use_from_trait_xc::Bar` --> $DIR/use-from-trait-xc.rs:20:24 | LL | use use_from_trait_xc::Bar::new as bnew; - | ^^^ not a module `Bar` + | ^^^ `Bar` is a struct, not a module error[E0432]: unresolved import `use_from_trait_xc::Baz::new` --> $DIR/use-from-trait-xc.rs:23:5 diff --git a/src/test/ui/use/use-from-trait.rs b/src/test/ui/use/use-from-trait.rs index fe578723bd3..eab4bb6e3b5 100644 --- a/src/test/ui/use/use-from-trait.rs +++ b/src/test/ui/use/use-from-trait.rs @@ -1,17 +1,10 @@ -use Trait::foo; -//~^ ERROR `foo` is not directly importable -use Trait::Assoc; -//~^ ERROR `Assoc` is not directly importable -use Trait::C; -//~^ ERROR `C` is not directly importable +use Trait::foo; //~ ERROR `foo` is not directly importable +use Trait::Assoc; //~ ERROR `Assoc` is not directly importable +use Trait::C; //~ ERROR `C` is not directly importable -use Foo::new; -//~^ ERROR unresolved import `Foo` [E0432] -//~| not a module `Foo` +use Foo::new; //~ ERROR unresolved import `Foo` [E0432] -use Foo::C2; -//~^ ERROR unresolved import `Foo` [E0432] -//~| not a module `Foo` +use Foo::C2; //~ ERROR unresolved import `Foo` [E0432] pub trait Trait { fn foo(); diff --git a/src/test/ui/use/use-from-trait.stderr b/src/test/ui/use/use-from-trait.stderr index 9e138422a2f..af4b3b0c455 100644 --- a/src/test/ui/use/use-from-trait.stderr +++ b/src/test/ui/use/use-from-trait.stderr @@ -5,28 +5,28 @@ LL | use Trait::foo; | ^^^^^^^^^^ cannot be imported directly error[E0253]: `Assoc` is not directly importable - --> $DIR/use-from-trait.rs:3:5 + --> $DIR/use-from-trait.rs:2:5 | LL | use Trait::Assoc; | ^^^^^^^^^^^^ cannot be imported directly error[E0253]: `C` is not directly importable - --> $DIR/use-from-trait.rs:5:5 + --> $DIR/use-from-trait.rs:3:5 | LL | use Trait::C; | ^^^^^^^^ cannot be imported directly error[E0432]: unresolved import `Foo` - --> $DIR/use-from-trait.rs:8:5 + --> $DIR/use-from-trait.rs:5:5 | LL | use Foo::new; - | ^^^ not a module `Foo` + | ^^^ `Foo` is a struct, not a module error[E0432]: unresolved import `Foo` - --> $DIR/use-from-trait.rs:12:5 + --> $DIR/use-from-trait.rs:7:5 | LL | use Foo::C2; - | ^^^ not a module `Foo` + | ^^^ `Foo` is a struct, not a module error: aborting due to 5 previous errors diff --git a/src/test/ui/utf8_idents.stderr b/src/test/ui/utf8_idents.stderr index 330ba3e0a8c..b65848cc58f 100644 --- a/src/test/ui/utf8_idents.stderr +++ b/src/test/ui/utf8_idents.stderr @@ -1,33 +1,37 @@ -error[E0658]: non-ascii idents are not fully supported. (see issue #55467) +error[E0658]: non-ascii idents are not fully supported --> $DIR/utf8_idents.rs:2:5 | LL | 'β, | ^^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/55467 = help: add #![feature(non_ascii_idents)] to the crate attributes to enable -error[E0658]: non-ascii idents are not fully supported. (see issue #55467) +error[E0658]: non-ascii idents are not fully supported --> $DIR/utf8_idents.rs:3:5 | LL | γ | ^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/55467 = help: add #![feature(non_ascii_idents)] to the crate attributes to enable -error[E0658]: non-ascii idents are not fully supported. (see issue #55467) +error[E0658]: non-ascii idents are not fully supported --> $DIR/utf8_idents.rs:8:5 | LL | δ: usize | ^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/55467 = help: add #![feature(non_ascii_idents)] to the crate attributes to enable -error[E0658]: non-ascii idents are not fully supported. (see issue #55467) +error[E0658]: non-ascii idents are not fully supported --> $DIR/utf8_idents.rs:12:9 | LL | let α = 0.00001f64; | ^ | + = note: for more information, see https://github.com/rust-lang/rust/issues/55467 = help: add #![feature(non_ascii_idents)] to the crate attributes to enable warning: type parameter `γ` should have an upper camel case name diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index 0611e53d092..61cc78ad807 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -103,7 +103,9 @@ static TARGETS: &[&str] = &[ "thumbv7em-none-eabi", "thumbv7em-none-eabihf", "thumbv7m-none-eabi", + "thumbv8m.base-none-eabi", "thumbv8m.main-none-eabi", + "thumbv8m.main-none-eabihf", "wasm32-unknown-emscripten", "wasm32-unknown-unknown", "wasm32-unknown-wasi", diff --git a/src/tools/cargo b/src/tools/cargo -Subproject 63231f438a2b5b84ccf319a5de22343ee031632 +Subproject 6f3e9c367abb497c64f360c3839dab5e74928d5 diff --git a/src/tools/clippy b/src/tools/clippy -Subproject 92612c9de159889f77f05855a77482ee1d895f5 +Subproject abf7f911d88e9209b54cfba2776d7dbca5a440c diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index d735d3351e6..2fe837e99d3 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -303,6 +303,10 @@ pub struct TestProps { // For UI tests, allows compiler to generate arbitrary output to stderr pub dont_check_compiler_stderr: bool, // Don't force a --crate-type=dylib flag on the command line + // + // Set this for example if you have an auxiliary test file that contains + // a proc-macro and needs `#![crate_type = "proc-macro"]`. This ensures + // that the aux file is compiled as a `proc-macro` and not as a `dylib`. pub no_prefer_dynamic: bool, // Run --pretty expanded when running pretty printing tests pub pretty_expanded: bool, @@ -490,7 +494,7 @@ impl TestProps { } if !self.compile_pass { - // run-pass implies must_compile_successfully + // run-pass implies compile_pass self.compile_pass = config.parse_compile_pass(ln) || self.run_pass; } diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 35f8dca79b5..2021dd513aa 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2820,12 +2820,15 @@ impl<'test> TestCx<'test> { // don't test rustfix with nll right now } else if self.config.rustfix_coverage { // Find out which tests have `MachineApplicable` suggestions but are missing - // `run-rustfix` or `run-rustfix-only-machine-applicable` headers + // `run-rustfix` or `run-rustfix-only-machine-applicable` headers. + // + // This will return an empty `Vec` in case the executed test file has a + // `compile-flags: --error-format=xxxx` header with a value other than `json`. let suggestions = get_suggestions_from_json( &proc_res.stderr, &HashSet::new(), Filter::MachineApplicableOnly - ).unwrap(); + ).unwrap_or_default(); if suggestions.len() > 0 && !self.props.run_rustfix && !self.props.rustfix_only_machine_applicable { diff --git a/src/tools/miri b/src/tools/miri -Subproject 72b4ee0381decf609204e5548c1f5e79bdfb18b +Subproject 7c06679f93df53f83bbf61b197f2e5c39f5d763 diff --git a/src/tools/rls b/src/tools/rls -Subproject 90f7ab070321ebc5ad217dc0d6db163c029dffd +Subproject b202e14dbf53949d05822e680ee5166b3346885 diff --git a/src/tools/rustc-workspace-hack/Cargo.toml b/src/tools/rustc-workspace-hack/Cargo.toml index 1aba52bafbb..d51841cd650 100644 --- a/src/tools/rustc-workspace-hack/Cargo.toml +++ b/src/tools/rustc-workspace-hack/Cargo.toml @@ -57,7 +57,7 @@ features = [ [dependencies] curl-sys = { version = "0.4.13", features = ["http2", "libnghttp2-sys"], optional = true } parking_lot = { version = "0.7", features = ['nightly'] } -rand = { version = "0.5.5", features = ["i128_support"] } +rand = { version = "0.6.1", features = ["i128_support"] } serde = { version = "1.0.82", features = ['derive'] } serde_json = { version = "1.0.31", features = ["raw_value"] } smallvec = { version = "0.6", features = ['union', 'may_dangle'] } diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 30fe327cac4..411961d70bf 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -96,6 +96,7 @@ const WHITELIST: &[Crate<'_>] = &[ Crate("lock_api"), Crate("log"), Crate("log_settings"), + Crate("measureme"), Crate("memchr"), Crate("memmap"), Crate("memoffset"), diff --git a/src/tools/tidy/src/unstable_book.rs b/src/tools/tidy/src/unstable_book.rs index cd60f36b1d2..f7e40ce4bae 100644 --- a/src/tools/tidy/src/unstable_book.rs +++ b/src/tools/tidy/src/unstable_book.rs @@ -3,13 +3,13 @@ use std::fs; use std::path; use crate::features::{collect_lang_features, collect_lib_features, Features, Status}; -pub const PATH_STR: &str = "doc/unstable-book/src"; +pub const PATH_STR: &str = "doc/unstable-book"; -pub const COMPILER_FLAGS_DIR: &str = "compiler-flags"; +pub const COMPILER_FLAGS_DIR: &str = "src/compiler-flags"; -pub const LANG_FEATURES_DIR: &str = "language-features"; +pub const LANG_FEATURES_DIR: &str = "src/language-features"; -pub const LIB_FEATURES_DIR: &str = "library-features"; +pub const LIB_FEATURES_DIR: &str = "src/library-features"; /// Builds the path to the Unstable Book source directory from the Rust 'src' directory. pub fn unstable_book_path(base_src_path: &path::Path) -> path::PathBuf { diff --git a/src/tools/unstable-book-gen/src/main.rs b/src/tools/unstable-book-gen/src/main.rs index 427014ce7fe..e92d174a4e1 100644 --- a/src/tools/unstable-book-gen/src/main.rs +++ b/src/tools/unstable-book-gen/src/main.rs @@ -52,7 +52,7 @@ fn set_to_summary_str(set: &BTreeSet<String>, dir: &str fn generate_summary(path: &Path, lang_features: &Features, lib_features: &Features) { let compiler_flags = collect_unstable_book_section_file_names( - &path.join("compiler-flags")); + &path.join("src/compiler-flags")); let compiler_flags_str = set_to_summary_str(&compiler_flags, "compiler-flags"); @@ -61,11 +61,11 @@ fn generate_summary(path: &Path, lang_features: &Features, lib_features: &Featur let unstable_lib_features = collect_unstable_feature_names(&lib_features); let lang_features_str = set_to_summary_str(&unstable_lang_features, - LANG_FEATURES_DIR); + "language-features"); let lib_features_str = set_to_summary_str(&unstable_lib_features, - LIB_FEATURES_DIR); + "library-features"); - let mut file = t!(File::create(&path.join("SUMMARY.md"))); + let mut file = t!(File::create(&path.join("src/SUMMARY.md"))); t!(file.write_fmt(format_args!(include_str!("SUMMARY.md"), compiler_flags = compiler_flags_str, language_features = lang_features_str, @@ -102,8 +102,8 @@ fn generate_unstable_book_files(src :&Path, out: &Path, features :&Features) { } } -fn copy_recursive(path: &Path, to: &Path) { - for entry in t!(fs::read_dir(path)) { +fn copy_recursive(from: &Path, to: &Path) { + for entry in t!(fs::read_dir(from)) { let e = t!(entry); let t = t!(e.metadata()); let dest = &to.join(e.file_name()); @@ -120,7 +120,7 @@ fn main() { let src_path_str = env::args_os().skip(1).next().expect("source path required"); let dest_path_str = env::args_os().skip(2).next().expect("destination path required"); let src_path = Path::new(&src_path_str); - let dest_path = Path::new(&dest_path_str).join("src"); + let dest_path = Path::new(&dest_path_str); let lang_features = collect_lang_features(src_path, &mut false); let lib_features = collect_lib_features(src_path).into_iter().filter(|&(ref name, _)| { |
