diff options
845 files changed, 18675 insertions, 11934 deletions
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 73d4188d695..e7041dcddc4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -47,6 +47,12 @@ as it's possible that someone else has already reported your error. This doesn't always work, and sometimes it's hard to know what to search for, so consider this extra credit. We won't mind if you accidentally file a duplicate report. +Similarly, to help others who encountered the bug find your issue, +consider filing an issue with with a descriptive title, which contains information that might be unique to it. +This can be the language or compiler feature used, the conditions that trigger the bug, +or part of the error message if there is any. +An example could be: **"impossible case reached" on lifetime inference for impl Trait in return position**. + Opening an issue is as easy as following [this link](https://github.com/rust-lang/rust/issues/new) and filling out the fields. Here's a template that you can use to file a bug, though it's not necessary to @@ -136,6 +142,8 @@ file. If you still have a `config.mk` file in your directory - from ### Building [building]: #building +A default configuration shall use around 3.5 GB of disk space, whereas building a debug configuration may require more than 30 GB. + Dependencies - [build dependencies](README.md#building-from-source) - `gdb` 6.2.0 minimum, 7.1 or later recommended for test builds diff --git a/src/Cargo.lock b/src/Cargo.lock index 4f979b7e9f4..a6f78a7e6b4 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -19,9 +19,8 @@ dependencies = [ name = "alloc_jemalloc" version = "0.0.0" dependencies = [ - "alloc_system 0.0.0", "build_helper 0.1.0", - "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "compiler_builtins 0.0.0", "core 0.0.0", "libc 0.0.0", @@ -79,6 +78,19 @@ dependencies = [ ] [[package]] +name = "assert_cli" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "colored 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "difference 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "environment 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", + "skeptic 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "atty" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -90,7 +102,7 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "backtrace-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", @@ -105,7 +117,7 @@ name = "backtrace-sys" version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -133,8 +145,8 @@ name = "bootstrap" version = "0.0.0" dependencies = [ "build_helper 0.1.0", - "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", - "cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cmake 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.1.15 (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)", @@ -142,11 +154,11 @@ dependencies = [ "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "petgraph 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "pretty_assertions 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -162,9 +174,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "build-manifest" version = "0.1.0" dependencies = [ - "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -172,13 +184,18 @@ name = "build_helper" version = "0.1.0" [[package]] +name = "bytecount" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] name = "byteorder" version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cargo" -version = "0.27.0" +version = "0.28.0" dependencies = [ "atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "bufstream 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -187,10 +204,10 @@ dependencies = [ "crates-io 0.16.0", "crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "crypto-hash 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "curl 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", + "curl 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "filetime 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", + "filetime 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "fs2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "git2 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -210,27 +227,29 @@ dependencies = [ "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "serde_ignored 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "tar 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tar 0.4.15 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cargo_metadata" -version = "0.2.3" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "semver 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -240,9 +259,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -251,7 +270,7 @@ version = "0.1.0" [[package]] name = "cc" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -286,18 +305,18 @@ dependencies = [ [[package]] name = "clippy" -version = "0.0.193" +version = "0.0.195" dependencies = [ "cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "clippy-mini-macro-test 0.2.0", - "clippy_lints 0.0.193", + "clippy_lints 0.0.195", "compiletest_rs 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "derive-new 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -306,7 +325,7 @@ version = "0.2.0" [[package]] name = "clippy_lints" -version = "0.0.193" +version = "0.0.195" dependencies = [ "if_chain 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -314,21 +333,29 @@ dependencies = [ "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cmake" -version = "0.1.29" +version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "colored" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -351,7 +378,7 @@ dependencies = [ name = "compiler_builtins" version = "0.0.0" dependencies = [ - "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", ] @@ -360,16 +387,16 @@ name = "compiletest" version = "0.0.0" dependencies = [ "diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -384,10 +411,10 @@ dependencies = [ "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -423,11 +450,11 @@ dependencies = [ name = "crates-io" version = "0.16.0" dependencies = [ - "curl 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "curl 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -474,36 +501,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "commoncrypto 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl 0.10.5 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl 0.10.6 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "curl" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "curl-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "curl-sys 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", "openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.27 (registry+https://github.com/rust-lang/crates.io-index)", - "schannel 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "socket2 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.28 (registry+https://github.com/rust-lang/crates.io-index)", + "schannel 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "socket2 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "curl-sys" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", "libz-sys 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.27 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.28 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "vcpkg 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -536,6 +563,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "difference" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "difference" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -559,16 +591,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "elasticlunr-rs" -version = "1.0.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "phf 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)", - "phf_codegen 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", + "strum 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "strum_macros 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -594,7 +626,7 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.5.6" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -605,11 +637,16 @@ dependencies = [ ] [[package]] +name = "environment" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] name = "error-chain" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -624,7 +661,7 @@ name = "failure" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -653,6 +690,16 @@ dependencies = [ ] [[package]] +name = "filetime" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "find_all_refs_no_cfg_test" version = "0.1.0" @@ -748,7 +795,7 @@ dependencies = [ "libgit2-sys 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.27 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.28 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -757,7 +804,7 @@ name = "git2-curl" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "curl 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "curl 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "git2 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -795,8 +842,8 @@ dependencies = [ "pest_derive 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -887,7 +934,7 @@ dependencies = [ "flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tar 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)", + "tar 0.4.15 (registry+https://github.com/rust-lang/crates.io-index)", "walkdir 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "xz2 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -933,9 +980,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "futures 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -949,13 +996,13 @@ dependencies = [ [[package]] name = "languageserver-types" -version = "0.35.0" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "url_serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -993,13 +1040,13 @@ name = "libgit2-sys" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", - "cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "curl-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cmake 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", + "curl-sys 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", "libssh2-sys 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "libz-sys 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.27 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.28 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1008,10 +1055,10 @@ name = "libssh2-sys" version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "cmake 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", "libz-sys 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.27 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.28 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1020,10 +1067,10 @@ name = "libz-sys" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "vcpkg 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1059,7 +1106,7 @@ name = "lzma-sys" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1082,9 +1129,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "phf 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)", "phf_codegen 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "string_cache 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "string_cache_codegen 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "tendril 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1097,14 +1144,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "mdbook" -version = "0.1.5" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ammonia 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)", - "elasticlunr-rs 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", + "elasticlunr-rs 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "handlebars 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1114,12 +1161,12 @@ dependencies = [ "open 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "toml-query 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1141,7 +1188,7 @@ name = "miniz-sys" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1150,7 +1197,7 @@ name = "miow" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "socket2 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "socket2 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1159,9 +1206,11 @@ name = "miri" version = "0.1.0" dependencies = [ "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cargo_metadata 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "compiletest_rs 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1215,14 +1264,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "openssl" -version = "0.10.5" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.27 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.28 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1232,13 +1281,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "openssl-sys" -version = "0.9.27" +version = "0.9.28" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "vcpkg 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1276,16 +1325,16 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot_core 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "parking_lot_core" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1386,7 +1435,7 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "0.3.1" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1406,7 +1455,7 @@ dependencies = [ name = "profiler_builtins" version = "0.0.0" dependencies = [ - "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "compiler_builtins 0.0.0", "core 0.0.0", ] @@ -1448,7 +1497,7 @@ name = "quote" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1457,7 +1506,7 @@ version = "2.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "syntex_errors 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1543,14 +1592,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "regex-syntax" -version = "0.5.3" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1566,7 +1615,7 @@ version = "0.1.0" [[package]] name = "remove_dir_all" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1576,39 +1625,39 @@ dependencies = [ name = "rls" version = "0.126.0" dependencies = [ - "cargo 0.27.0", + "cargo 0.28.0", "cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", - "clippy_lints 0.0.193", - "env_logger 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy_lints 0.0.195", + "env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "json 0.11.13 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 8.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "languageserver-types 0.35.0 (registry+https://github.com/rust-lang/crates.io-index)", + "languageserver-types 0.36.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "racer 2.0.13 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-analysis 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-blacklist 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-analysis 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-blacklist 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "rls-data 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "rls-rustc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rls-vfs 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "rustfmt-nightly 0.4.2", - "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "rustfmt-nightly 0.6.0", + "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rls-analysis" -version = "0.11.3" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "derive-new 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "radix_trie 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "rls-data 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1617,7 +1666,7 @@ dependencies = [ [[package]] name = "rls-blacklist" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1627,8 +1676,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1642,8 +1691,8 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1660,7 +1709,7 @@ name = "rustbook" version = "0.1.0" dependencies = [ "clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)", - "mdbook 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "mdbook 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1668,7 +1717,7 @@ name = "rustc" version = "0.0.0" dependencies = [ "arena 0.0.0", - "backtrace 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1679,10 +1728,10 @@ dependencies = [ "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "proc_macro 0.0.0", "rustc_apfloat 0.0.0", - "rustc_back 0.0.0", "rustc_const_math 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", + "rustc_target 0.0.0", "serialize 0.0.0", "syntax 0.0.0", "syntax_pos 0.0.0", @@ -1691,7 +1740,7 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_cratesio_shim" -version = "103.0.0" +version = "110.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1700,28 +1749,28 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_data_structures" -version = "103.0.0" +version = "110.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "ena 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot_core 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-serialize 103.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-serialize 110.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rustc-ap-rustc_errors" -version = "103.0.0" +version = "110.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-rustc_data_structures 103.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-serialize 103.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-syntax_pos 103.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-rustc_data_structures 110.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-serialize 110.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-syntax_pos 110.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1729,32 +1778,32 @@ dependencies = [ [[package]] name = "rustc-ap-serialize" -version = "103.0.0" +version = "110.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rustc-ap-syntax" -version = "103.0.0" +version = "110.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-rustc_cratesio_shim 103.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-rustc_data_structures 103.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-rustc_errors 103.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-serialize 103.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-syntax_pos 103.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-rustc_cratesio_shim 110.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-rustc_data_structures 110.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-rustc_errors 110.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-serialize 110.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-syntax_pos 110.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "scoped-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rustc-ap-syntax_pos" -version = "103.0.0" +version = "110.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rustc-ap-rustc_data_structures 103.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-serialize 103.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-rustc_data_structures 110.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-serialize 110.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "scoped-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1769,8 +1818,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "rustc-main" version = "0.0.0" dependencies = [ - "rustc_back 0.0.0", "rustc_driver 0.0.0", + "rustc_target 0.0.0", ] [[package]] @@ -1784,6 +1833,7 @@ version = "0.0.0" dependencies = [ "rustc 0.0.0", "rustc_errors 0.0.0", + "rustc_target 0.0.0", "syntax 0.0.0", "syntax_pos 0.0.0", ] @@ -1803,22 +1853,12 @@ dependencies = [ "alloc 0.0.0", "alloc_system 0.0.0", "build_helper 0.1.0", - "cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "cmake 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", "compiler_builtins 0.0.0", "core 0.0.0", ] [[package]] -name = "rustc_back" -version = "0.0.0" -dependencies = [ - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serialize 0.0.0", - "syntax 0.0.0", -] - -[[package]] name = "rustc_borrowck" version = "0.0.0" dependencies = [ @@ -1846,6 +1886,7 @@ name = "rustc_cratesio_shim" version = "0.0.0" dependencies = [ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1855,8 +1896,9 @@ dependencies = [ "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "ena 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot_core 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_cratesio_shim 0.0.0", "serialize 0.0.0", "stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1867,12 +1909,11 @@ version = "0.0.0" dependencies = [ "ar 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "arena 0.0.0", - "env_logger 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", "graphviz 0.0.0", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_allocator 0.0.0", - "rustc_back 0.0.0", "rustc_borrowck 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", @@ -1885,6 +1926,7 @@ dependencies = [ "rustc_privacy 0.0.0", "rustc_resolve 0.0.0", "rustc_save_analysis 0.0.0", + "rustc_target 0.0.0", "rustc_traits 0.0.0", "rustc_trans_utils 0.0.0", "rustc_typeck 0.0.0", @@ -1927,6 +1969,7 @@ dependencies = [ "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_mir 0.0.0", + "rustc_target 0.0.0", "syntax 0.0.0", "syntax_pos 0.0.0", ] @@ -1937,7 +1980,7 @@ version = "0.0.0" dependencies = [ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "build_helper 0.1.0", - "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_cratesio_shim 0.0.0", ] @@ -1949,7 +1992,7 @@ dependencies = [ "alloc 0.0.0", "alloc_system 0.0.0", "build_helper 0.1.0", - "cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "cmake 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", "compiler_builtins 0.0.0", "core 0.0.0", ] @@ -1962,9 +2005,9 @@ dependencies = [ "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "proc_macro 0.0.0", "rustc 0.0.0", - "rustc_back 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", + "rustc_target 0.0.0", "serialize 0.0.0", "syntax 0.0.0", "syntax_ext 0.0.0", @@ -1983,10 +2026,10 @@ dependencies = [ "log_settings 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_apfloat 0.0.0", - "rustc_back 0.0.0", "rustc_const_math 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", + "rustc_target 0.0.0", "serialize 0.0.0", "syntax 0.0.0", "syntax_pos 0.0.0", @@ -1999,7 +2042,7 @@ dependencies = [ "alloc 0.0.0", "alloc_system 0.0.0", "build_helper 0.1.0", - "cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "cmake 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", "compiler_builtins 0.0.0", "core 0.0.0", ] @@ -2067,12 +2110,23 @@ dependencies = [ "rustc 0.0.0", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_data_structures 0.0.0", + "rustc_target 0.0.0", "rustc_typeck 0.0.0", "syntax 0.0.0", "syntax_pos 0.0.0", ] [[package]] +name = "rustc_target" +version = "0.0.0" +dependencies = [ + "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_cratesio_shim 0.0.0", + "serialize 0.0.0", +] + +[[package]] name = "rustc_traits" version = "0.0.0" dependencies = [ @@ -2089,9 +2143,8 @@ dependencies = [ name = "rustc_trans" version = "0.0.0" dependencies = [ - "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", "flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "jobserver 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2101,7 +2154,6 @@ dependencies = [ "rustc-demangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_allocator 0.0.0", "rustc_apfloat 0.0.0", - "rustc_back 0.0.0", "rustc_const_math 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", @@ -2109,6 +2161,7 @@ dependencies = [ "rustc_llvm 0.0.0", "rustc_mir 0.0.0", "rustc_platform_intrinsics 0.0.0", + "rustc_target 0.0.0", "rustc_trans_utils 0.0.0", "serialize 0.0.0", "syntax 0.0.0", @@ -2124,10 +2177,10 @@ dependencies = [ "flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", - "rustc_back 0.0.0", "rustc_data_structures 0.0.0", "rustc_incremental 0.0.0", "rustc_mir 0.0.0", + "rustc_target 0.0.0", "syntax 0.0.0", "syntax_pos 0.0.0", ] @@ -2139,7 +2192,7 @@ dependencies = [ "alloc 0.0.0", "alloc_system 0.0.0", "build_helper 0.1.0", - "cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "cmake 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", "compiler_builtins 0.0.0", "core 0.0.0", ] @@ -2156,6 +2209,7 @@ dependencies = [ "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", "rustc_platform_intrinsics 0.0.0", + "rustc_target 0.0.0", "syntax 0.0.0", "syntax_pos 0.0.0", ] @@ -2181,30 +2235,40 @@ dependencies = [ [[package]] name = "rustfmt-nightly" -version = "0.4.2" +version = "0.6.0" dependencies = [ + "assert_cli 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "derive-new 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-syntax 103.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-syntax 110.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "term 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-segmentation 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "same-file" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "same-file" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ @@ -2213,7 +2277,7 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.11" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2232,11 +2296,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "semver" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "semver" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2246,26 +2319,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.37" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde_derive" -version = "1.0.37" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive_internals 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive_internals 0.23.1 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_derive_internals" -version = "0.23.0" +version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2274,18 +2347,18 @@ name = "serde_ignored" version = "0.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_json" -version = "1.0.13" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2308,13 +2381,28 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] +name = "skeptic" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytecount 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cargo_metadata 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", + "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "smallvec" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "socket2" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2367,7 +2455,7 @@ dependencies = [ "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)", "precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "string_cache_codegen 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2394,6 +2482,20 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] +name = "strum" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "strum_macros" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "syn" version = "0.11.11" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2418,7 +2520,7 @@ name = "syn" version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2446,9 +2548,9 @@ version = "0.0.0" dependencies = [ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_cratesio_shim 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", + "rustc_target 0.0.0", "scoped-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "serialize 0.0.0", "syntax_pos 0.0.0", @@ -2462,6 +2564,7 @@ dependencies = [ "proc_macro 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", + "rustc_target 0.0.0", "syntax 0.0.0", "syntax_pos 0.0.0", ] @@ -2514,13 +2617,13 @@ dependencies = [ [[package]] name = "tar" -version = "0.4.14" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "filetime 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", + "filetime 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", - "xattr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "xattr 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2529,18 +2632,18 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "remove_dir_all 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tempfile" -version = "3.0.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", - "remove_dir_all 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2623,9 +2726,9 @@ dependencies = [ name = "tidy" version = "0.1.0" dependencies = [ - "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2648,10 +2751,10 @@ dependencies = [ [[package]] name = "toml" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2663,7 +2766,7 @@ dependencies = [ "is-match 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2757,7 +2860,7 @@ name = "url_serde" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2782,7 +2885,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "vcpkg" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -2797,6 +2900,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "walkdir" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "walkdir" version = "2.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ @@ -2847,7 +2960,7 @@ version = "0.1.0" [[package]] name = "xattr" -version = "0.1.11" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2872,21 +2985,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" "checksum ar 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "35c7a5669cb64f085739387e1308b74e6d44022464b7f1b63bbd4ceb6379ec31" "checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef" +"checksum assert_cli 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "72342c21057a3cb5f7c2d849bf7999a83795434dd36d74fa8c24680581bd1930" "checksum atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "af80143d6f7608d746df1520709e5d141c96f240b0e62b0aa41bdfb53374d9d4" -"checksum backtrace 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ebbbf59b1c43eefa8c3ede390fcc36820b4999f7914104015be25025e0d62af2" +"checksum backtrace 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ebbe525f66f42d207968308ee86bc2dd60aa5fab535b22e616323a173d097d8e" "checksum backtrace-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "44585761d6161b0f57afc49482ab6bd067e4edef48c12a152c237eb0203f7661" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" "checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" "checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf" "checksum bufstream 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f2f382711e76b9de6c744cc00d0497baba02fb00a787f088c879f01d09468e32" +"checksum bytecount 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "af27422163679dea46a1a7239dffff64d3dcdc3ba5fe9c49c789fbfe0eb949de" "checksum byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "73b5bdfe7ee3ad0b99c9801d58807a9dbc9e09196365b0203853b99889ab3c87" -"checksum cargo_metadata 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "be1057b8462184f634c3a208ee35b0f935cfd94b694b26deadccd98732088d7b" +"checksum cargo_metadata 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1f56ec3e469bca7c276f2eea015aa05c5e381356febdbb0683c2580189604537" "checksum cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6ebd6272a2ca4fd39dbabbd6611eb03df45c2259b3b80b39a9ff8fbdcf42a4b3" -"checksum cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "2b4911e4bdcb4100c7680e7e854ff38e23f1b34d4d9e079efae3da2801341ffc" +"checksum cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "8b9d2900f78631a5876dc5d6c9033ede027253efcd33dd36b1309fc6cab97ee0" "checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" "checksum chrono 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ba5f60682a4c264e7f8d77b82e7788938a76befdf949d4a98026d19099c9d873" "checksum clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f0f16b89cbb9ee36d87483dc939fe9f1e13c05898d56d7b230a0d4dff033a536" -"checksum cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)" = "56d741ea7a69e577f6d06b36b7dff4738f680593dc27a701ffa8506b73ce28bb" +"checksum cmake 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)" = "5cf678ceebedde428000cb3a34465cf3606d1a48da17014948a916deac39da7c" +"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 compiletest_rs 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "608d9d3ccc45b63bf337d2ff5e65def5a5a52c187122232509f6b72707f61b1b" @@ -2897,23 +3013,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150" "checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9" "checksum crypto-hash 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "09de9ee0fc255ace04c7fa0763c9395a945c37c8292bb554f8d48361d1dcf1b4" -"checksum curl 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b70fd6394677d3c0e239ff4be6f2b3176e171ffd1c23ffdc541e78dea2b8bb5e" -"checksum curl-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f46e49c7125131f5afaded06944d6888b55cbdf8eba05dae73c954019b907961" +"checksum curl 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "aaf20bbe084f285f215eef2165feed70d6b75ba29cad24469badb853a4a287d0" +"checksum curl-sys 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f3f7738d877ec81040305d5bb91976ac594f564f5e455dc02a29a23c1d00fe6f" "checksum debug_unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9a032eac705ca39214d169f83e3d3da290af06d8d1d344d1baad2fd002dca4b3" "checksum derive-new 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6fcb923bab47a948f1b01cec2f758fdebba95c9ebc255458654b2b88efe59d71" "checksum diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3c2b69f912779fbb121ceb775d74d51e915af17aaebc38d28a592843a2dd0a3a" +"checksum difference 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b3304d19798a8e067e48d8e69b2c37f0b5e9b4e462504ad9e27e9f3fce02bba8" "checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" "checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab" "checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0" -"checksum elasticlunr-rs 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "19ab5f8db0ffb76b5d87454566ceb502c3650e29057c053f93e884d3b884e344" +"checksum elasticlunr-rs 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4511b63d69dd5d31e8e29aed2c132c413f87acea8035d0584801feaab9dd1f0f" "checksum ena 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f8b449f3b18c89d2dbe40548d2ee4fa58ea0a08b761992da6ecb9788e4688834" "checksum endian-type 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" "checksum enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "be4551092f4d519593039259a9ed8daedf0da12e5109c5280338073eaeb81180" -"checksum env_logger 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0561146661ae44c579e993456bc76d11ce1e0c7d745e57b2fa7146b6e49fa2ad" +"checksum env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)" = "be27f8ea102a7182093a80d98f0b78623b580eda8791cbe8e2345fe6e57567a6" +"checksum environment 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1f4b14e20978669064c33b4c1e0fb4083412e40fe56cbea2eae80fd7591503ee" "checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3" "checksum failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "934799b6c1de475a012a02dab0ace1ace43789ee4b99bcfbf1a2e3e8ced5de82" "checksum failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c7cdda555bb90c9bb67a3b670a0f42de8e73f5981524123ad8578aafec8ddb8b" "checksum filetime 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "714653f3e34871534de23771ac7b26e999651a0a228f47beb324dfdf1dd4b10f" +"checksum filetime 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "08530a39af0bd442c40aabb9e854f442a83bd2403feb1ed58fbe982dec2385f3" "checksum fixedbitset 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "86d4de0081402f5e88cdac65c8dcdcc73118c1a7a465e2a05f0da05843a8ea33" "checksum flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9fac2277e84e5e858483756647a9d0aa8d9a2b7cba517fd84325a0aaa69a0909" "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" @@ -2944,7 +3063,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum json 0.11.13 (registry+https://github.com/rust-lang/crates.io-index)" = "9ad0485404155f45cce53a40d4b2d6ac356418300daed05273d9e26f91c390be" "checksum jsonrpc-core 8.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ddf83704f4e79979a424d1082dd2c1e52683058056c9280efa19ac5f6bc9033c" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -"checksum languageserver-types 0.35.0 (registry+https://github.com/rust-lang/crates.io-index)" = "36e264ab825353617bbc80844717555be6e9e1d403474b1d0a3b8e190440b13e" +"checksum languageserver-types 0.36.0 (registry+https://github.com/rust-lang/crates.io-index)" = "174cdfb8bed13225bb419bec66ee1c970099c875688645f9c4a82e3af43ba69d" "checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" "checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d" "checksum lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a6f08839bc70ef4a3fe1d566d5350f519c5912ea86be0df1740a7d247c7fc0ef" @@ -2960,7 +3079,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum maplit 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08cbb6b4fef96b6d77bfc40ec491b1690c779e77b05cd9f07f787ed376fd4c43" "checksum markup5ever 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfedc97d5a503e96816d10fedcd5b42f760b2e525ce2f7ec71f6a41780548475" "checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376" -"checksum mdbook 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "326d0861da5681a13c19a00952a56c254dd04f00eb944e506fdb36e93ae6f1ca" +"checksum mdbook 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "90b5a8d7e341ceee5db3882a06078d42661ddcfa2b3687319cc5da76ec4e782f" "checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d" "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" "checksum miniz-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "609ce024854aeb19a0ef7567d348aaa5a746b32fb72e336df7fcc16869d7e2b4" @@ -2972,13 +3091,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum num-traits 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dee092fcdf725aee04dd7da1d21debff559237d49ef1cb3e69bcb8ece44c7364" "checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" "checksum open 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c281318d992e4432cfa799969467003d05921582a7489a8325e37f8a450d5113" -"checksum openssl 0.10.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1636c9f1d78af9cbcc50e523bfff4a30274108aad5e86761afd4d31e4e184fa7" +"checksum openssl 0.10.6 (registry+https://github.com/rust-lang/crates.io-index)" = "63246f69962e8d5ef865f82a65241d6483c8a2905a1801e2f7feb5d187d51320" "checksum openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" -"checksum openssl-sys 0.9.27 (registry+https://github.com/rust-lang/crates.io-index)" = "d6fdc5c4a02e69ce65046f1763a0181107038e02176233acb0b3351d7cc588f9" +"checksum openssl-sys 0.9.28 (registry+https://github.com/rust-lang/crates.io-index)" = "0bbd90640b148b46305c1691eed6039b5c8509bed16991e3562a01eeb76902a3" "checksum ordermap 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a86ed3f5f244b372d6b1a00b72ef7f8876d0bc6a78a4c9985c53614041512063" "checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37" -"checksum parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9fd9d732f2de194336fb02fe11f9eed13d9e76f13f4315b4d88a14ca411750cd" -"checksum parking_lot_core 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "538ef00b7317875071d5e00f603f24d16f0b474c1a5fc0ccb8b454ca72eafa79" +"checksum parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d4d05f1349491390b1730afba60bb20d55761bef489a954546b58b4b34e1e2ac" +"checksum parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "4db1a8ccf734a7bce794cc19b3df06ed87ab2f3907036b693c68f56b4d4537fa" "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" "checksum pest 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0fce5d8b5cc33983fc74f78ad552b5522ab41442c4ca91606e4236eb4b5ceefc" "checksum pest_derive 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "ab94faafeb93f4c5e3ce81ca0e5a779529a602ad5d09ae6d21996bfb8b6a52bf" @@ -2991,7 +3110,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" "checksum pretty_assertions 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a029430f0d744bc3d15dd474d591bed2402b645d024583082b9f63bb936dac6" "checksum proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cd07deb3c6d1d9ff827999c7f9b04cdfd66b1b17ae508e14fe47b620f2282ae0" -"checksum proc-macro2 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "388d7ea47318c5ccdeb9ba6312cee7d3f65dd2804be8580a170fce410d50b786" +"checksum proc-macro2 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "49b6a521dc81b643e9a51e0d1cf05df46d5a2f3c0280ea72bcb68276ba64a118" "checksum pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d6fdf85cda6cadfae5428a54661d431330b312bc767ddbc57adbedc24da66e32" "checksum quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eda5fe9b71976e62bc81b781206aaa076401769b2143379d3eb2118388babac4" "checksum quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "07589615d719a60c8dd8a4622e7946465dfef20d1a428f969e3443e7386d5f45" @@ -3007,43 +3126,48 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "0d92eecebad22b767915e4d529f89f28ee96dbbf5a4810d2b844373f136417fd" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" "checksum regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "aec3f58d903a7d2a9dc2bf0e41a746f4530e0cab6b615494e058f67a3ef947fb" -"checksum regex-syntax 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b2550876c31dc914696a6c2e01cbce8afba79a93c8ae979d2fe051c0230b3756" -"checksum remove_dir_all 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dfc5b3ce5d5ea144bb04ebd093a9e14e9765bcfec866aecda9b6dec43b3d1e24" -"checksum rls-analysis 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fd4b9a3a3f2345854e39768e6425d1c893855da217183d1c0b3ff6f1664b6b6d" -"checksum rls-blacklist 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "156cee9c1750b2e97d404dd0506c4780b7a2d615164f49874013807fb3cbfe5e" +"checksum regex-syntax 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "bd90079345f4a4c3409214734ae220fd773c6f2e8a543d07370c6c1c369cfbfb" +"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" +"checksum rls-analysis 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b339561571efd8d2d4ae1b16eb27f760cad46907d49e9726242844dbbde14e79" +"checksum rls-blacklist 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e4a9cc2545ccb7e05b355bfe047b8039a6ec12270d5f3c996b766b340a50f7d2" "checksum rls-data 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bea04462e94b5512a78499837eecb7db182ff082144cd1b4bc32ef5d43de6510" "checksum rls-rustc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "885f66b92757420572cbb02e033d4a9558c7413ca9b7ac206f28fd58ffdb44ea" "checksum rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d7c7046dc6a92f2ae02ed302746db4382e75131b9ce20ce967259f6b5867a6a" "checksum rls-vfs 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "be231e1e559c315bc60ced5ad2cc2d7a9c208ed7d4e2c126500149836fda19bb" -"checksum rustc-ap-rustc_cratesio_shim 103.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "463834ac5ea777cb56c073586675fac37292f8425aafb3757efca7e6a76545aa" -"checksum rustc-ap-rustc_data_structures 103.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d256eeab1b8639c2a1fd341e54f3613f8150bc262e4ec9361a29bbcb162906d" -"checksum rustc-ap-rustc_errors 103.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cf6dd73033bb512845a6df347174c65ad430c92ecd35527e24d8bb186f5664ee" -"checksum rustc-ap-serialize 103.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "356d338dbe538c7d6428296872d5d68da8f091e34eb89bca3b3f245ed0785e5e" -"checksum rustc-ap-syntax 103.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0f02edede4ba70963a7dac2308876f03f76f9edd48a035e5abc8fa37c57a77c8" -"checksum rustc-ap-syntax_pos 103.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ad8e50d4c38121fa8ded3ffbf94926ec74c95f24316c3b80de84fbfb42c005cf" +"checksum rustc-ap-rustc_cratesio_shim 110.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0256e318ad99c467d24bd7188f2d4a3028360621bb92d769b4b65fc44717d514" +"checksum rustc-ap-rustc_data_structures 110.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "83430df7f76ea85c1f70fe145041576eee8fd5d77053bf426df24b480918d185" +"checksum rustc-ap-rustc_errors 110.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2b03f874277103039816f6467b1ff30a81b1d6a29d4de6efccefe4c488f6535a" +"checksum rustc-ap-serialize 110.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a2e47cf949f06b0c7ab7566c2f69d49f28cb3ecf1bb8bf0bda48b1ba5b7945ae" +"checksum rustc-ap-syntax 110.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "625e6fb41fde299082cda3bceb08f81c9ba56b14a2ec737b4366f9c3c9be07d8" +"checksum rustc-ap-syntax_pos 110.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "474a23ef1a1245ae02c5fd6a1e9a0725ce6fd25ca2294703c03bddce041f867b" "checksum rustc-demangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11fb43a206a04116ffd7cfcf9bcb941f8eb6cc7ff667272246b0a1c74259a3cb" "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" +"checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7" "checksum same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cfb6eded0b06a0b512c8ddbcf04089138c9b4362c2f696f3c3d76039d68f3637" -"checksum schannel 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "fbaffce35eb61c5b00846e73128b0cd62717e7c0ec46abbec132370d013975b4" +"checksum schannel 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "85fd9df495640643ad2d00443b3d78aae69802ad488debab4f1dd52fc1806ade" "checksum scoped-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8674d439c964889e2476f474a3bf198cc9e199e77499960893bac5de7e9218a4" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" +"checksum semver 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bee2bc909ab2d8d60dab26e8cad85b25d795b14603a0dcb627b78b9d30b6454b" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)" = "d3bcee660dcde8f52c3765dd9ca5ee36b4bf35470a738eb0bd5a8752b0389645" -"checksum serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)" = "f1711ab8b208541fa8de00425f6a577d90f27bb60724d2bb5fd911314af9668f" -"checksum serde_derive_internals 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)" = "89b340a48245bc03ddba31d0ff1709c118df90edc6adabaca4aac77aea181cce" +"checksum serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "29465552c9b767d0cb44be3ddf4c3214be15d34975a7750f6cf4f409835f0248" +"checksum serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "fb88f3c93214390ed9ef3ad15ce303c36684a915a97a30883ac6ca261bf67dc7" +"checksum serde_derive_internals 0.23.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9d30c4596450fd7bbda79ef15559683f9a79ac0193ea819db90000d7e1cae794" "checksum serde_ignored 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "190e9765dcedb56be63b6e0993a006c7e3b071a016a304736e4a315dc01fb142" -"checksum serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "5c508584d9913df116b91505eec55610a2f5b16e9ed793c46e4d0152872b3e74" +"checksum serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7bf1cbb1387028a13739cb018ee0d9b3db534f22ca3c84a5904f7eadfde14e75" "checksum shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "170a13e64f2a51b77a45702ba77287f5c6829375b04a69cf2222acd17d0cfab9" "checksum shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" "checksum siphasher 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0df90a788073e8d0235a67e50441d47db7c8ad9debd91cbf43736a2a92d36537" +"checksum skeptic 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c8431f8fca168e2db4be547bd8329eac70d095dff1444fee4b0fa0fabc7df75a" "checksum smallvec 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44db0ecb22921ef790d17ae13a3f6d15784183ff5f2a01aa32098c7498d2b4b9" -"checksum socket2 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "71ebbe82fcdd697244ba7fe6e05e63b5c45910c3927e28469a04947494ff48d8" +"checksum socket2 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ff606e0486e88f5fc6cfeb3966e434fb409abbc7a3ab495238f70a1ca97f789d" "checksum stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "15132e0e364248108c5e2c02e3ab539be8d6f5d52a01ca9bbf27ed657316f02b" "checksum string_cache 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39cb4173bcbd1319da31faa5468a7e3870683d7a237150b0b0aaafd546f6ad12" "checksum string_cache_codegen 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "479cde50c3539481f33906a387f2bd17c8e87cb848c35b6021d41fb81ff9b4d7" "checksum string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b1884d1bc09741d466d9b14e6d37ac89d6909cbcac41dd9ae982d4d063bbedfc" "checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" +"checksum strum 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "099e21b5dd6dd07b5adcf8c4b723a7c0b7efd7a9359bf963d58c0caae8532545" +"checksum strum_macros 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0dd9bd569e88028750e3ae5c25616b8278ac16a8e61aba4339195c72396d49e1" "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" "checksum syn 0.12.15 (registry+https://github.com/rust-lang/crates.io-index)" = "c97c05b8ebc34ddd6b967994d5c6e9852fa92f8b82b3858c39451f97346dcce5" "checksum syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "91b52877572087400e83d24b9178488541e3d535259e04ff17a63df1e5ceff59" @@ -3052,9 +3176,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum syntex_errors 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9e52bffe6202cfb67587784cf23e0ec5bf26d331eef4922a16d5c42e12aa1e9b" "checksum syntex_pos 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)" = "955ef4b16af4c468e4680d1497f873ff288f557d338180649e18f915af5e15ac" "checksum syntex_syntax 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)" = "76a302e717e348aa372ff577791c3832395650073b8d8432f8b3cb170b34afde" -"checksum tar 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)" = "1605d3388ceb50252952ffebab4b5dc43017ead7e4481b175961c283bb951195" +"checksum tar 0.4.15 (registry+https://github.com/rust-lang/crates.io-index)" = "6af6b94659f9a571bf769a5b71f54079393585ee0bfdd71b691be22d7d6b1d18" "checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" -"checksum tempfile 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "439d9a7c00f98b1b5ee730039bf5b1f9203d508690e3c76b509e7ad59f8f7c99" +"checksum tempfile 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8cddbd26c5686ece823b507f304c8f188daef548b4cb753512d929ce478a093c" "checksum tendril 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9de21546595a0873061940d994bbbc5c35f024ae4fd61ec5c5b159115684f508" "checksum term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "fa63644f74ce96fbeb9b794f66aff2a52d601cbd5e80f4b97123e3899f4570f1" "checksum term 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5e6b677dd1e8214ea1ef4297f85dbcbed8e8cdddb561040cc998ca2551c37561" @@ -3064,7 +3188,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279ef31c19ededf577bfd12dfae728040a21f635b06a24cd670ff510edd38963" "checksum time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "a15375f1df02096fb3317256ce2cee6a1f42fc84ea5ad5fc8c421cfe40c73098" "checksum toml 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "736b60249cb25337bc196faa43ee12c705e426f3d55c214d73a4e7be06f92cb4" -"checksum toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a7540f4ffc193e0d3c94121edb19b055670d369f77d5804db11ae053a45b6e7e" +"checksum toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a0263c6c02c4db6c8f7681f9fd35e90de799ebd4cfdeab77a38f4ff6b3d8c0d9" "checksum toml-query 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6854664bfc6df0360c695480836ee90e2d0c965f06db291d10be9344792d43e8" "checksum ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d" "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" @@ -3081,9 +3205,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum userenv-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "71d28ea36bbd9192d75bd9fa9b39f96ddb986eaee824adae5d53b6e51919b2f3" "checksum utf-8 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f1262dfab4c30d5cb7c07026be00ee343a6cf5027fdc0104a9160f354e5db75c" "checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122" -"checksum vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9e0a7d8bed3178a8fb112199d466eeca9ed09a14ba8ad67718179b4fd5487d0b" +"checksum vcpkg 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7ed0f6789c8a85ca41bbc1c9d175422116a9869bd1cf31bb08e1493ecce60380" "checksum vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "887b5b631c2ad01628bbbaa7dd4c869f80d3186688f8d0b6f58774fbe324988c" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" +"checksum walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "bb08f9e670fab86099470b97cd2b252d6527f0b3cc1401acdb595ffc9dd288ff" "checksum walkdir 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "63636bd0eb3d00ccb8b9036381b526efac53caf112b7783b730ab3f8e44da369" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "04e3bd221fcbe8a271359c04f21a76db7d0c6028862d1bb5512d85e1e2eb5bb3" @@ -3091,6 +3216,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" "checksum wincolor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eeb06499a3a4d44302791052df005d5232b927ed1a9658146d842165c4de7767" -"checksum xattr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "5f04de8a1346489a2f9e9bd8526b73d135ec554227b17568456e86aa35b6f3fc" +"checksum xattr 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "abb373b92de38a4301d66bec009929b4fb83120ea1c4a401be89dbe0b9777443" "checksum xz2 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "98df591c3504d014dd791d998123ed00a476c7e26dc6b2e873cb55c6ac9e59fa" "checksum yaml-rust 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e66366e18dc58b46801afbf2ca7661a9f59cc8c5962c29892b6039b4f86fa992" diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index b29ac0e1efc..08bb8ab4815 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -154,18 +154,17 @@ impl StepDescription { eprintln!("{:?} not skipped for {:?} -- not in {:?}", pathset, self.name, builder.config.exclude); } - let build = builder.build; - let hosts = &build.hosts; + let hosts = &builder.hosts; // Determine the targets participating in this rule. let targets = if self.only_hosts { - if !build.config.run_host_only { + if !builder.config.run_host_only { return; // don't run anything } else { - &build.hosts + &builder.hosts } } else { - &build.targets + &builder.targets }; for host in hosts { @@ -311,7 +310,8 @@ impl<'a> Builder<'a> { tool::Compiletest, tool::RemoteTestServer, tool::RemoteTestClient, tool::RustInstaller, tool::Cargo, tool::Rls, tool::Rustdoc, tool::Clippy, native::Llvm, tool::Rustfmt, tool::Miri, native::Lld), - Kind::Check => describe!(check::Std, check::Test, check::Rustc), + Kind::Check => describe!(check::Std, check::Test, check::Rustc, check::CodegenBackend, + check::Rustdoc), Kind::Test => describe!(test::Tidy, test::Bootstrap, test::Ui, test::RunPass, test::CompileFail, test::ParseFail, test::RunFail, test::RunPassValgrind, test::MirOpt, test::Codegen, test::CodegenUnits, test::Incremental, test::Debuginfo, @@ -323,7 +323,7 @@ impl<'a> Builder<'a> { test::Cargotest, test::Cargo, test::Rls, test::ErrorIndex, test::Distcheck, test::RunMakeFullDeps, test::Nomicon, test::Reference, test::RustdocBook, test::RustByExample, - test::TheBook, test::UnstableBook, + test::TheBook, test::UnstableBook, test::RustcBook, test::Rustfmt, test::Miri, test::Clippy, test::RustdocJS, test::RustdocTheme, // Run run-make last, since these won't pass without make on Windows test::RunMake, test::RustdocUi), @@ -331,7 +331,7 @@ impl<'a> Builder<'a> { Kind::Doc => describe!(doc::UnstableBook, doc::UnstableBookGen, doc::TheBook, doc::Standalone, doc::Std, doc::Test, doc::WhitelistedRustc, doc::Rustc, doc::ErrorIndex, doc::Nomicon, doc::Reference, doc::Rustdoc, doc::RustByExample, - doc::CargoBook), + doc::RustcBook, doc::CargoBook), Kind::Dist => describe!(dist::Docs, dist::RustcDocs, dist::Mingw, dist::Rustc, dist::DebuggerScripts, dist::Std, dist::Analysis, dist::Src, dist::PlainSourceTarball, dist::Cargo, dist::Rls, dist::Rustfmt, dist::Extended, @@ -476,7 +476,7 @@ impl<'a> Builder<'a> { pub fn sysroot_codegen_backends(&self, compiler: Compiler) -> PathBuf { self.sysroot_libdir(compiler, compiler.host) - .with_file_name(self.build.config.rust_codegen_backends_dir.clone()) + .with_file_name(self.config.rust_codegen_backends_dir.clone()) } /// Returns the compiler's libdir where it stores the dynamic libraries that @@ -486,7 +486,7 @@ impl<'a> Builder<'a> { /// Windows. pub fn rustc_libdir(&self, compiler: Compiler) -> PathBuf { if compiler.is_snapshot(self) { - self.build.rustc_snapshot_libdir() + self.rustc_snapshot_libdir() } else { self.sysroot(compiler).join(libdir(&compiler.host)) } @@ -523,12 +523,12 @@ impl<'a> Builder<'a> { let compiler = self.compiler(self.top_stage, host); cmd.env("RUSTC_STAGE", compiler.stage.to_string()) .env("RUSTC_SYSROOT", self.sysroot(compiler)) - .env("RUSTDOC_LIBDIR", self.sysroot_libdir(compiler, self.build.build)) - .env("CFG_RELEASE_CHANNEL", &self.build.config.channel) + .env("RUSTDOC_LIBDIR", self.sysroot_libdir(compiler, self.config.build)) + .env("CFG_RELEASE_CHANNEL", &self.config.channel) .env("RUSTDOC_REAL", self.rustdoc(host)) - .env("RUSTDOC_CRATE_VERSION", self.build.rust_version()) + .env("RUSTDOC_CRATE_VERSION", self.rust_version()) .env("RUSTC_BOOTSTRAP", "1"); - if let Some(linker) = self.build.linker(host) { + if let Some(linker) = self.linker(host) { cmd.env("RUSTC_TARGET_LINKER", linker); } cmd @@ -553,6 +553,12 @@ impl<'a> Builder<'a> { .arg("--target") .arg(target); + // Set a flag for `check` so that certain build scripts can do less work + // (e.g. not building/requiring LLVM). + if cmd == "check" { + cargo.env("RUST_CHECK", "1"); + } + // If we were invoked from `make` then that's already got a jobserver // set up for us so no need to tell Cargo about jobs all over again. if env::var_os("MAKEFLAGS").is_none() && env::var_os("MFLAGS").is_none() { @@ -609,17 +615,17 @@ impl<'a> Builder<'a> { .env("TEST_MIRI", self.config.test_miri.to_string()) .env("RUSTC_ERROR_METADATA_DST", self.extended_error_dir()); - if let Some(host_linker) = self.build.linker(compiler.host) { + if let Some(host_linker) = self.linker(compiler.host) { cargo.env("RUSTC_HOST_LINKER", host_linker); } - if let Some(target_linker) = self.build.linker(target) { + if let Some(target_linker) = self.linker(target) { cargo.env("RUSTC_TARGET_LINKER", target_linker); } if let Some(ref error_format) = self.config.rustc_error_format { cargo.env("RUSTC_ERROR_FORMAT", error_format); } if cmd != "build" && cmd != "check" { - cargo.env("RUSTDOC_LIBDIR", self.rustc_libdir(self.compiler(2, self.build.build))); + cargo.env("RUSTDOC_LIBDIR", self.rustc_libdir(self.compiler(2, self.config.build))); } if mode == Mode::Tool { @@ -677,7 +683,7 @@ impl<'a> Builder<'a> { // // If LLVM support is disabled we need to use the snapshot compiler to compile // build scripts, as the new compiler doesn't support executables. - if mode == Mode::Libstd || !self.build.config.llvm_enabled { + if mode == Mode::Libstd || !self.config.llvm_enabled { cargo.env("RUSTC_SNAPSHOT", &self.initial_rustc) .env("RUSTC_SNAPSHOT_LIBDIR", self.rustc_snapshot_libdir()); } else { @@ -756,12 +762,14 @@ impl<'a> Builder<'a> { } } - if mode == Mode::Libstd && self.config.extended && compiler.is_final_stage(self) { + if cmd == "build" && mode == Mode::Libstd + && self.config.extended && compiler.is_final_stage(self) + { cargo.env("RUSTC_SAVE_ANALYSIS", "api".to_string()); } // For `cargo doc` invocations, make rustdoc print the Rust version into the docs - cargo.env("RUSTDOC_CRATE_VERSION", self.build.rust_version()); + cargo.env("RUSTDOC_CRATE_VERSION", self.rust_version()); // Environment variables *required* throughout the build // @@ -769,7 +777,7 @@ impl<'a> Builder<'a> { cargo.env("CFG_COMPILER_HOST_TRIPLE", target); // Set this for all builds to make sure doc builds also get it. - cargo.env("CFG_RELEASE_CHANNEL", &self.build.config.channel); + cargo.env("CFG_RELEASE_CHANNEL", &self.config.channel); // This one's a bit tricky. As of the time of this writing the compiler // links to the `winapi` crate on crates.io. This crate provides raw @@ -835,7 +843,7 @@ impl<'a> Builder<'a> { cargo } - /// Ensure that a given step is built, returning it's output. This will + /// Ensure that a given step is built, returning its output. This will /// cache the step, so it is safe (and good!) to call this as often as /// needed to ensure that all dependencies are built. pub fn ensure<S: Step>(&'a self, step: S) -> S::Output { @@ -854,7 +862,7 @@ impl<'a> Builder<'a> { panic!(out); } if let Some(out) = self.cache.get(&step) { - self.build.verbose(&format!("{}c {:?}", " ".repeat(stack.len()), step)); + self.verbose(&format!("{}c {:?}", " ".repeat(stack.len()), step)); { let mut graph = self.graph.borrow_mut(); @@ -869,7 +877,7 @@ impl<'a> Builder<'a> { return out; } - self.build.verbose(&format!("{}> {:?}", " ".repeat(stack.len()), step)); + self.verbose(&format!("{}> {:?}", " ".repeat(stack.len()), step)); stack.push(Box::new(step.clone())); } @@ -899,7 +907,7 @@ impl<'a> Builder<'a> { self.parent.set(prev_parent); - if self.build.config.print_step_timings && dur > Duration::from_millis(100) { + if self.config.print_step_timings && dur > Duration::from_millis(100) { println!("[TIMING] {:?} -- {}.{:03}", step, dur.as_secs(), @@ -911,7 +919,7 @@ impl<'a> Builder<'a> { let cur_step = stack.pop().expect("step stack empty"); assert_eq!(cur_step.downcast_ref(), Some(&step)); } - self.build.verbose(&format!("{}< {:?}", " ".repeat(self.stack.borrow().len()), step)); + self.verbose(&format!("{}< {:?}", " ".repeat(self.stack.borrow().len()), step)); self.cache.put(step, out.clone()); out } diff --git a/src/bootstrap/cc_detect.rs b/src/bootstrap/cc_detect.rs index 8f393a4c573..698903f128d 100644 --- a/src/bootstrap/cc_detect.rs +++ b/src/bootstrap/cc_detect.rs @@ -79,8 +79,16 @@ pub fn find(build: &mut Build) { let mut cfg = cc::Build::new(); cfg.cargo_metadata(false).opt_level(2).warnings(false).debug(false) .target(&target).host(&build.build); - if target.contains("msvc") { - cfg.static_crt(true); + match build.crt_static(target) { + Some(a) => { cfg.static_crt(a); } + None => { + if target.contains("msvc") { + cfg.static_crt(true); + } + if target.contains("musl") { + cfg.static_flag(true); + } + } } let config = build.config.target_config.get(&target); @@ -97,8 +105,9 @@ pub fn find(build: &mut Build) { cc2ar(compiler.path(), &target) }; - build.verbose(&format!("CC_{} = {:?}", &target, compiler.path())); build.cc.insert(target, compiler); + build.verbose(&format!("CC_{} = {:?}", &target, build.cc(target))); + build.verbose(&format!("CFLAGS_{} = {:?}", &target, build.cflags(target))); if let Some(ar) = ar { build.verbose(&format!("AR_{} = {:?}", &target, ar)); build.ar.insert(target, ar); diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index a39fad67ebe..64354ae29aa 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -10,10 +10,11 @@ //! Implementation of compiling the compiler and standard library, in "check" mode. -use compile::{run_cargo, std_cargo, test_cargo, rustc_cargo, add_to_sysroot}; +use compile::{run_cargo, std_cargo, test_cargo, rustc_cargo, rustc_cargo_env, add_to_sysroot}; use builder::{RunConfig, Builder, ShouldRun, Step}; -use {Build, Compiler, Mode}; -use cache::Interned; +use tool::{self, prepare_tool_cargo}; +use {Compiler, Mode}; +use cache::{INTERNER, Interned}; use std::path::PathBuf; #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] @@ -36,24 +37,24 @@ impl Step for Std { } fn run(self, builder: &Builder) { - let build = builder.build; let target = self.target; - let compiler = builder.compiler(0, build.build); + let compiler = builder.compiler(0, builder.config.build); + + let out_dir = builder.stage_out(compiler, Mode::Libstd); + builder.clear_if_dirty(&out_dir, &builder.rustc(compiler)); - let out_dir = build.stage_out(compiler, Mode::Libstd); - build.clear_if_dirty(&out_dir, &builder.rustc(compiler)); let mut cargo = builder.cargo(compiler, Mode::Libstd, target, "check"); std_cargo(builder, &compiler, target, &mut cargo); - let _folder = build.fold_output(|| format!("stage{}-std", compiler.stage)); + let _folder = builder.fold_output(|| format!("stage{}-std", compiler.stage)); println!("Checking std artifacts ({} -> {})", &compiler.host, target); - run_cargo(build, + run_cargo(builder, &mut cargo, - &libstd_stamp(build, compiler, target), + &libstd_stamp(builder, compiler, target), true); let libdir = builder.sysroot_libdir(compiler, target); - add_to_sysroot(&build, &libdir, &libstd_stamp(build, compiler, target)); + add_to_sysroot(&builder, &libdir, &libstd_stamp(builder, compiler, target)); } } @@ -83,26 +84,71 @@ impl Step for Rustc { /// the `compiler` targeting the `target` architecture. The artifacts /// created will also be linked into the sysroot directory. fn run(self, builder: &Builder) { - let build = builder.build; - let compiler = builder.compiler(0, build.build); + let compiler = builder.compiler(0, builder.config.build); let target = self.target; let stage_out = builder.stage_out(compiler, Mode::Librustc); - build.clear_if_dirty(&stage_out, &libstd_stamp(build, compiler, target)); - build.clear_if_dirty(&stage_out, &libtest_stamp(build, compiler, target)); + builder.clear_if_dirty(&stage_out, &libstd_stamp(builder, compiler, target)); + builder.clear_if_dirty(&stage_out, &libtest_stamp(builder, compiler, target)); let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "check"); - rustc_cargo(build, &mut cargo); + rustc_cargo(builder, &mut cargo); - let _folder = build.fold_output(|| format!("stage{}-rustc", compiler.stage)); + let _folder = builder.fold_output(|| format!("stage{}-rustc", compiler.stage)); println!("Checking compiler artifacts ({} -> {})", &compiler.host, target); - run_cargo(build, + run_cargo(builder, &mut cargo, - &librustc_stamp(build, compiler, target), + &librustc_stamp(builder, compiler, target), true); let libdir = builder.sysroot_libdir(compiler, target); - add_to_sysroot(&build, &libdir, &librustc_stamp(build, compiler, target)); + add_to_sysroot(&builder, &libdir, &librustc_stamp(builder, compiler, target)); + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub struct CodegenBackend { + pub target: Interned<String>, + pub backend: Interned<String>, +} + +impl Step for CodegenBackend { + type Output = (); + const ONLY_HOSTS: bool = true; + const DEFAULT: bool = true; + + fn should_run(run: ShouldRun) -> ShouldRun { + run.all_krates("rustc_trans") + } + + fn make_run(run: RunConfig) { + let backend = run.builder.config.rust_codegen_backends.get(0); + let backend = backend.cloned().unwrap_or_else(|| { + INTERNER.intern_str("llvm") + }); + run.builder.ensure(CodegenBackend { + target: run.target, + backend, + }); + } + + fn run(self, builder: &Builder) { + let compiler = builder.compiler(0, builder.config.build); + let target = self.target; + let backend = self.backend; + + let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "check"); + let features = builder.rustc_features().to_string(); + cargo.arg("--manifest-path").arg(builder.src.join("src/librustc_trans/Cargo.toml")); + rustc_cargo_env(builder, &mut cargo); + + // We won't build LLVM if it's not available, as it shouldn't affect `check`. + + let _folder = builder.fold_output(|| format!("stage{}-rustc_trans", compiler.stage)); + run_cargo(builder, + cargo.arg("--features").arg(features), + &codegen_backend_stamp(builder, compiler, target, backend), + true); } } @@ -126,41 +172,105 @@ impl Step for Test { } fn run(self, builder: &Builder) { - let build = builder.build; + let compiler = builder.compiler(0, builder.config.build); let target = self.target; - let compiler = builder.compiler(0, build.build); - let out_dir = build.stage_out(compiler, Mode::Libtest); - build.clear_if_dirty(&out_dir, &libstd_stamp(build, compiler, target)); + let out_dir = builder.stage_out(compiler, Mode::Libtest); + builder.clear_if_dirty(&out_dir, &libstd_stamp(builder, compiler, target)); + let mut cargo = builder.cargo(compiler, Mode::Libtest, target, "check"); - test_cargo(build, &compiler, target, &mut cargo); + test_cargo(builder, &compiler, target, &mut cargo); - let _folder = build.fold_output(|| format!("stage{}-test", compiler.stage)); + let _folder = builder.fold_output(|| format!("stage{}-test", compiler.stage)); println!("Checking test artifacts ({} -> {})", &compiler.host, target); - run_cargo(build, + run_cargo(builder, &mut cargo, - &libtest_stamp(build, compiler, target), + &libtest_stamp(builder, compiler, target), true); let libdir = builder.sysroot_libdir(compiler, target); - add_to_sysroot(&build, &libdir, &libtest_stamp(build, compiler, target)); + add_to_sysroot(builder, &libdir, &libtest_stamp(builder, compiler, target)); + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub struct Rustdoc { + pub target: Interned<String>, +} + +impl Step for Rustdoc { + type Output = (); + const ONLY_HOSTS: bool = true; + const DEFAULT: bool = true; + + fn should_run(run: ShouldRun) -> ShouldRun { + run.path("src/tools/rustdoc") + } + + fn make_run(run: RunConfig) { + run.builder.ensure(Rustdoc { + target: run.target, + }); + } + + fn run(self, builder: &Builder) { + let compiler = builder.compiler(0, builder.config.build); + let target = self.target; + + let mut cargo = prepare_tool_cargo(builder, + compiler, + target, + "check", + "src/tools/rustdoc"); + + let _folder = builder.fold_output(|| format!("stage{}-rustdoc", compiler.stage)); + println!("Checking rustdoc artifacts ({} -> {})", &compiler.host, target); + run_cargo(builder, + &mut cargo, + &rustdoc_stamp(builder, compiler, target), + true); + + let libdir = builder.sysroot_libdir(compiler, target); + add_to_sysroot(&builder, &libdir, &rustdoc_stamp(builder, compiler, target)); + + builder.ensure(tool::CleanTools { + compiler, + target, + mode: Mode::Tool, + }); } } /// Cargo's output path for the standard library in a given stage, compiled /// by a particular compiler for the specified target. -pub fn libstd_stamp(build: &Build, compiler: Compiler, target: Interned<String>) -> PathBuf { - build.cargo_out(compiler, Mode::Libstd, target).join(".libstd-check.stamp") +pub fn libstd_stamp(builder: &Builder, compiler: Compiler, target: Interned<String>) -> PathBuf { + builder.cargo_out(compiler, Mode::Libstd, target).join(".libstd-check.stamp") } /// Cargo's output path for libtest in a given stage, compiled by a particular /// compiler for the specified target. -pub fn libtest_stamp(build: &Build, compiler: Compiler, target: Interned<String>) -> PathBuf { - build.cargo_out(compiler, Mode::Libtest, target).join(".libtest-check.stamp") +pub fn libtest_stamp(builder: &Builder, compiler: Compiler, target: Interned<String>) -> PathBuf { + builder.cargo_out(compiler, Mode::Libtest, target).join(".libtest-check.stamp") } /// Cargo's output path for librustc in a given stage, compiled by a particular /// compiler for the specified target. -pub fn librustc_stamp(build: &Build, compiler: Compiler, target: Interned<String>) -> PathBuf { - build.cargo_out(compiler, Mode::Librustc, target).join(".librustc-check.stamp") +pub fn librustc_stamp(builder: &Builder, compiler: Compiler, target: Interned<String>) -> PathBuf { + builder.cargo_out(compiler, Mode::Librustc, target).join(".librustc-check.stamp") +} + +/// Cargo's output path for librustc_trans in a given stage, compiled by a particular +/// compiler for the specified target and backend. +fn codegen_backend_stamp(builder: &Builder, + compiler: Compiler, + target: Interned<String>, + backend: Interned<String>) -> PathBuf { + builder.cargo_out(compiler, Mode::Librustc, target) + .join(format!(".librustc_trans-{}-check.stamp", backend)) +} + +/// Cargo's output path for rustdoc in a given stage, compiled by a particular +/// compiler for the specified target. +pub fn rustdoc_stamp(builder: &Builder, compiler: Compiler, target: Interned<String>) -> PathBuf { + builder.cargo_out(compiler, Mode::Tool, target).join(".rustdoc-check.stamp") } diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index b411b19bd53..1248c2b50be 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -31,7 +31,7 @@ use filetime::FileTime; use serde_json; use util::{exe, libdir, is_dylib, CiEnv}; -use {Build, Compiler, Mode}; +use {Compiler, Mode}; use native; use tool; @@ -65,14 +65,13 @@ impl Step for Std { /// using the `compiler` targeting the `target` architecture. The artifacts /// created will also be linked into the sysroot directory. fn run(self, builder: &Builder) { - let build = builder.build; let target = self.target; let compiler = self.compiler; builder.ensure(StartupObjects { compiler, target }); - if build.force_use_stage1(compiler, target) { - let from = builder.compiler(1, build.build); + if builder.force_use_stage1(compiler, target) { + let from = builder.compiler(1, builder.config.build); builder.ensure(Std { compiler: from, target, @@ -83,7 +82,7 @@ impl Step for Std { // still contain the musl startup objects. if target.contains("musl") { let libdir = builder.sysroot_libdir(compiler, target); - copy_musl_third_party_objects(build, target, &libdir); + copy_musl_third_party_objects(builder, target, &libdir); } builder.ensure(StdLink { @@ -96,24 +95,24 @@ impl Step for Std { if target.contains("musl") { let libdir = builder.sysroot_libdir(compiler, target); - copy_musl_third_party_objects(build, target, &libdir); + copy_musl_third_party_objects(builder, target, &libdir); } - let out_dir = build.cargo_out(compiler, Mode::Libstd, target); - build.clear_if_dirty(&out_dir, &builder.rustc(compiler)); + let out_dir = builder.cargo_out(compiler, Mode::Libstd, target); + builder.clear_if_dirty(&out_dir, &builder.rustc(compiler)); let mut cargo = builder.cargo(compiler, Mode::Libstd, target, "build"); std_cargo(builder, &compiler, target, &mut cargo); - let _folder = build.fold_output(|| format!("stage{}-std", compiler.stage)); - build.info(&format!("Building stage{} std artifacts ({} -> {})", compiler.stage, + let _folder = builder.fold_output(|| format!("stage{}-std", compiler.stage)); + builder.info(&format!("Building stage{} std artifacts ({} -> {})", compiler.stage, &compiler.host, target)); - run_cargo(build, + run_cargo(builder, &mut cargo, - &libstd_stamp(build, compiler, target), + &libstd_stamp(builder, compiler, target), false); builder.ensure(StdLink { - compiler: builder.compiler(compiler.stage, build.build), + compiler: builder.compiler(compiler.stage, builder.config.build), target_compiler: compiler, target, }); @@ -126,17 +125,17 @@ impl Step for Std { /// with a glibc-targeting toolchain, given we have the appropriate startup /// files. As those shipped with glibc won't work, copy the ones provided by /// musl so we have them on linux-gnu hosts. -fn copy_musl_third_party_objects(build: &Build, +fn copy_musl_third_party_objects(builder: &Builder, target: Interned<String>, into: &Path) { for &obj in &["crt1.o", "crti.o", "crtn.o"] { - build.copy(&build.musl_root(target).unwrap().join("lib").join(obj), &into.join(obj)); + builder.copy(&builder.musl_root(target).unwrap().join("lib").join(obj), &into.join(obj)); } } /// Configure cargo to compile the standard library, adding appropriate env vars /// and such. -pub fn std_cargo(build: &Builder, +pub fn std_cargo(builder: &Builder, compiler: &Compiler, target: Interned<String>, cargo: &mut Command) { @@ -144,27 +143,27 @@ pub fn std_cargo(build: &Builder, cargo.env("MACOSX_DEPLOYMENT_TARGET", target); } - if build.no_std(target) == Some(true) { + if builder.no_std(target) == Some(true) { // for no-std targets we only compile a few no_std crates cargo.arg("--features").arg("c mem") .args(&["-p", "alloc"]) .args(&["-p", "compiler_builtins"]) .args(&["-p", "std_unicode"]) .arg("--manifest-path") - .arg(build.src.join("src/rustc/compiler_builtins_shim/Cargo.toml")); + .arg(builder.src.join("src/rustc/compiler_builtins_shim/Cargo.toml")); } else { - let mut features = build.std_features(); + let mut features = builder.std_features(); // When doing a local rebuild we tell cargo that we're stage1 rather than // stage0. This works fine if the local rust and being-built rust have the // same view of what the default allocator is, but fails otherwise. Since // we don't have a way to express an allocator preference yet, work // around the issue in the case of a local rebuild with jemalloc disabled. - if compiler.stage == 0 && build.local_rebuild && !build.config.use_jemalloc { + if compiler.stage == 0 && builder.local_rebuild && !builder.config.use_jemalloc { features.push_str(" force_alloc_system"); } - if compiler.stage != 0 && build.config.sanitizers { + if compiler.stage != 0 && builder.config.sanitizers { // This variable is used by the sanitizer runtime crates, e.g. // rustc_lsan, to build the sanitizer runtime from C code // When this variable is missing, those crates won't compile the C code, @@ -172,8 +171,8 @@ pub fn std_cargo(build: &Builder, // missing // We also only build the runtimes when --enable-sanitizers (or its // config.toml equivalent) is used - let llvm_config = build.ensure(native::Llvm { - target: build.config.build, + let llvm_config = builder.ensure(native::Llvm { + target: builder.config.build, emscripten: false, }); cargo.env("LLVM_CONFIG", llvm_config); @@ -181,15 +180,15 @@ pub fn std_cargo(build: &Builder, cargo.arg("--features").arg(features) .arg("--manifest-path") - .arg(build.src.join("src/libstd/Cargo.toml")); + .arg(builder.src.join("src/libstd/Cargo.toml")); - if let Some(target) = build.config.target_config.get(&target) { + if let Some(target) = builder.config.target_config.get(&target) { if let Some(ref jemalloc) = target.jemalloc { cargo.env("JEMALLOC_OVERRIDE", jemalloc); } } if target.contains("musl") { - if let Some(p) = build.musl_root(target) { + if let Some(p) = builder.musl_root(target) { cargo.env("MUSL_ROOT", p); } } @@ -219,24 +218,23 @@ impl Step for StdLink { /// libraries for `target`, and this method will find them in the relevant /// output directory. fn run(self, builder: &Builder) { - let build = builder.build; let compiler = self.compiler; let target_compiler = self.target_compiler; let target = self.target; - build.info(&format!("Copying stage{} std from stage{} ({} -> {} / {})", + builder.info(&format!("Copying stage{} std from stage{} ({} -> {} / {})", target_compiler.stage, compiler.stage, &compiler.host, target_compiler.host, target)); let libdir = builder.sysroot_libdir(target_compiler, target); - add_to_sysroot(&build, &libdir, &libstd_stamp(build, compiler, target)); + add_to_sysroot(builder, &libdir, &libstd_stamp(builder, compiler, target)); - if build.config.sanitizers && compiler.stage != 0 && target == "x86_64-apple-darwin" { + if builder.config.sanitizers && compiler.stage != 0 && target == "x86_64-apple-darwin" { // The sanitizers are only built in stage1 or above, so the dylibs will // be missing in stage0 and causes panic. See the `std()` function above // for reason why the sanitizers are not built in stage0. - copy_apple_sanitizer_dylibs(&build, &build.native_dir(target), "osx", &libdir); + copy_apple_sanitizer_dylibs(builder, &builder.native_dir(target), "osx", &libdir); } builder.ensure(tool::CleanTools { @@ -247,7 +245,7 @@ impl Step for StdLink { } } -fn copy_apple_sanitizer_dylibs(build: &Build, native_dir: &Path, platform: &str, into: &Path) { +fn copy_apple_sanitizer_dylibs(builder: &Builder, native_dir: &Path, platform: &str, into: &Path) { for &sanitizer in &["asan", "tsan"] { let filename = format!("libclang_rt.{}_{}_dynamic.dylib", sanitizer, platform); let mut src_path = native_dir.join(sanitizer); @@ -255,7 +253,7 @@ fn copy_apple_sanitizer_dylibs(build: &Build, native_dir: &Path, platform: &str, src_path.push("lib"); src_path.push("darwin"); src_path.push(&filename); - build.copy(&src_path, &into.join(filename)); + builder.copy(&src_path, &into.join(filename)); } } @@ -286,15 +284,14 @@ impl Step for StartupObjects { /// files, so we just use the nightly snapshot compiler to always build them (as /// no other compilers are guaranteed to be available). fn run(self, builder: &Builder) { - let build = builder.build; let for_compiler = self.compiler; let target = self.target; if !target.contains("pc-windows-gnu") { return } - let src_dir = &build.src.join("src/rtstartup"); - let dst_dir = &build.native_dir(target).join("rtstartup"); + let src_dir = &builder.src.join("src/rtstartup"); + let dst_dir = &builder.native_dir(target).join("rtstartup"); let sysroot_dir = &builder.sysroot_libdir(for_compiler, target); t!(fs::create_dir_all(dst_dir)); @@ -302,8 +299,8 @@ impl Step for StartupObjects { let src_file = &src_dir.join(file.to_string() + ".rs"); let dst_file = &dst_dir.join(file.to_string() + ".o"); if !up_to_date(src_file, dst_file) { - let mut cmd = Command::new(&build.initial_rustc); - build.run(cmd.env("RUSTC_BOOTSTRAP", "1") + let mut cmd = Command::new(&builder.initial_rustc); + builder.run(cmd.env("RUSTC_BOOTSTRAP", "1") .arg("--cfg").arg("stage0") .arg("--target").arg(target) .arg("--emit=obj") @@ -311,15 +308,15 @@ impl Step for StartupObjects { .arg(src_file)); } - build.copy(dst_file, &sysroot_dir.join(file.to_string() + ".o")); + builder.copy(dst_file, &sysroot_dir.join(file.to_string() + ".o")); } for obj in ["crt2.o", "dllcrt2.o"].iter() { - let src = compiler_file(build, - build.cc(target), + let src = compiler_file(builder, + builder.cc(target), target, obj); - build.copy(&src, &sysroot_dir.join(obj)); + builder.copy(&src, &sysroot_dir.join(obj)); } } } @@ -351,41 +348,41 @@ impl Step for Test { /// the build using the `compiler` targeting the `target` architecture. The /// artifacts created will also be linked into the sysroot directory. fn run(self, builder: &Builder) { - let build = builder.build; let target = self.target; let compiler = self.compiler; builder.ensure(Std { compiler, target }); - if build.force_use_stage1(compiler, target) { + if builder.force_use_stage1(compiler, target) { builder.ensure(Test { - compiler: builder.compiler(1, build.build), + compiler: builder.compiler(1, builder.config.build), target, }); - build.info(&format!("Uplifting stage1 test ({} -> {})", &build.build, target)); + builder.info( + &format!("Uplifting stage1 test ({} -> {})", builder.config.build, target)); builder.ensure(TestLink { - compiler: builder.compiler(1, build.build), + compiler: builder.compiler(1, builder.config.build), target_compiler: compiler, target, }); return; } - let out_dir = build.cargo_out(compiler, Mode::Libtest, target); - build.clear_if_dirty(&out_dir, &libstd_stamp(build, compiler, target)); + let out_dir = builder.cargo_out(compiler, Mode::Libtest, target); + builder.clear_if_dirty(&out_dir, &libstd_stamp(builder, compiler, target)); let mut cargo = builder.cargo(compiler, Mode::Libtest, target, "build"); - test_cargo(build, &compiler, target, &mut cargo); + test_cargo(builder, &compiler, target, &mut cargo); - let _folder = build.fold_output(|| format!("stage{}-test", compiler.stage)); - build.info(&format!("Building stage{} test artifacts ({} -> {})", compiler.stage, + let _folder = builder.fold_output(|| format!("stage{}-test", compiler.stage)); + builder.info(&format!("Building stage{} test artifacts ({} -> {})", compiler.stage, &compiler.host, target)); - run_cargo(build, + run_cargo(builder, &mut cargo, - &libtest_stamp(build, compiler, target), + &libtest_stamp(builder, compiler, target), false); builder.ensure(TestLink { - compiler: builder.compiler(compiler.stage, build.build), + compiler: builder.compiler(compiler.stage, builder.config.build), target_compiler: compiler, target, }); @@ -393,7 +390,7 @@ impl Step for Test { } /// Same as `std_cargo`, but for libtest -pub fn test_cargo(build: &Build, +pub fn test_cargo(builder: &Builder, _compiler: &Compiler, _target: Interned<String>, cargo: &mut Command) { @@ -401,7 +398,7 @@ pub fn test_cargo(build: &Build, cargo.env("MACOSX_DEPLOYMENT_TARGET", target); } cargo.arg("--manifest-path") - .arg(build.src.join("src/libtest/Cargo.toml")); + .arg(builder.src.join("src/libtest/Cargo.toml")); } #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] @@ -420,18 +417,17 @@ impl Step for TestLink { /// Same as `std_link`, only for libtest fn run(self, builder: &Builder) { - let build = builder.build; let compiler = self.compiler; let target_compiler = self.target_compiler; let target = self.target; - build.info(&format!("Copying stage{} test from stage{} ({} -> {} / {})", + builder.info(&format!("Copying stage{} test from stage{} ({} -> {} / {})", target_compiler.stage, compiler.stage, &compiler.host, target_compiler.host, target)); - add_to_sysroot(&build, &builder.sysroot_libdir(target_compiler, target), - &libtest_stamp(build, compiler, target)); + add_to_sysroot(builder, &builder.sysroot_libdir(target_compiler, target), + &libtest_stamp(builder, compiler, target)); builder.ensure(tool::CleanTools { compiler: target_compiler, target, @@ -468,20 +464,20 @@ impl Step for Rustc { /// the `compiler` targeting the `target` architecture. The artifacts /// created will also be linked into the sysroot directory. fn run(self, builder: &Builder) { - let build = builder.build; let compiler = self.compiler; let target = self.target; builder.ensure(Test { compiler, target }); - if build.force_use_stage1(compiler, target) { + if builder.force_use_stage1(compiler, target) { builder.ensure(Rustc { - compiler: builder.compiler(1, build.build), + compiler: builder.compiler(1, builder.config.build), target, }); - build.info(&format!("Uplifting stage1 rustc ({} -> {})", &build.build, target)); + builder.info(&format!("Uplifting stage1 rustc ({} -> {})", + builder.config.build, target)); builder.ensure(RustcLink { - compiler: builder.compiler(1, build.build), + compiler: builder.compiler(1, builder.config.build), target_compiler: compiler, target, }); @@ -490,71 +486,71 @@ impl Step for Rustc { // Ensure that build scripts have a std to link against. builder.ensure(Std { - compiler: builder.compiler(self.compiler.stage, build.build), - target: build.build, + compiler: builder.compiler(self.compiler.stage, builder.config.build), + target: builder.config.build, }); let cargo_out = builder.cargo_out(compiler, Mode::Librustc, target); - build.clear_if_dirty(&cargo_out, &libstd_stamp(build, compiler, target)); - build.clear_if_dirty(&cargo_out, &libtest_stamp(build, compiler, target)); + builder.clear_if_dirty(&cargo_out, &libstd_stamp(builder, compiler, target)); + builder.clear_if_dirty(&cargo_out, &libtest_stamp(builder, compiler, target)); let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "build"); - rustc_cargo(build, &mut cargo); + rustc_cargo(builder, &mut cargo); - let _folder = build.fold_output(|| format!("stage{}-rustc", compiler.stage)); - build.info(&format!("Building stage{} compiler artifacts ({} -> {})", + let _folder = builder.fold_output(|| format!("stage{}-rustc", compiler.stage)); + builder.info(&format!("Building stage{} compiler artifacts ({} -> {})", compiler.stage, &compiler.host, target)); - run_cargo(build, + run_cargo(builder, &mut cargo, - &librustc_stamp(build, compiler, target), + &librustc_stamp(builder, compiler, target), false); builder.ensure(RustcLink { - compiler: builder.compiler(compiler.stage, build.build), + compiler: builder.compiler(compiler.stage, builder.config.build), target_compiler: compiler, target, }); } } -pub fn rustc_cargo(build: &Build, cargo: &mut Command) { - cargo.arg("--features").arg(build.rustc_features()) +pub fn rustc_cargo(builder: &Builder, cargo: &mut Command) { + cargo.arg("--features").arg(builder.rustc_features()) .arg("--manifest-path") - .arg(build.src.join("src/rustc/Cargo.toml")); - rustc_cargo_env(build, cargo); + .arg(builder.src.join("src/rustc/Cargo.toml")); + rustc_cargo_env(builder, cargo); } -fn rustc_cargo_env(build: &Build, cargo: &mut Command) { +pub fn rustc_cargo_env(builder: &Builder, cargo: &mut Command) { // Set some configuration variables picked up by build scripts and // the compiler alike - cargo.env("CFG_RELEASE", build.rust_release()) - .env("CFG_RELEASE_CHANNEL", &build.config.channel) - .env("CFG_VERSION", build.rust_version()) - .env("CFG_PREFIX", build.config.prefix.clone().unwrap_or_default()) - .env("CFG_CODEGEN_BACKENDS_DIR", &build.config.rust_codegen_backends_dir); + cargo.env("CFG_RELEASE", builder.rust_release()) + .env("CFG_RELEASE_CHANNEL", &builder.config.channel) + .env("CFG_VERSION", builder.rust_version()) + .env("CFG_PREFIX", builder.config.prefix.clone().unwrap_or_default()) + .env("CFG_CODEGEN_BACKENDS_DIR", &builder.config.rust_codegen_backends_dir); - let libdir_relative = build.config.libdir_relative().unwrap_or(Path::new("lib")); + let libdir_relative = builder.config.libdir_relative().unwrap_or(Path::new("lib")); cargo.env("CFG_LIBDIR_RELATIVE", libdir_relative); // If we're not building a compiler with debugging information then remove // these two env vars which would be set otherwise. - if build.config.rust_debuginfo_only_std { + if builder.config.rust_debuginfo_only_std { cargo.env_remove("RUSTC_DEBUGINFO"); cargo.env_remove("RUSTC_DEBUGINFO_LINES"); } - if let Some(ref ver_date) = build.rust_info.commit_date() { + if let Some(ref ver_date) = builder.rust_info.commit_date() { cargo.env("CFG_VER_DATE", ver_date); } - if let Some(ref ver_hash) = build.rust_info.sha() { + if let Some(ref ver_hash) = builder.rust_info.sha() { cargo.env("CFG_VER_HASH", ver_hash); } - if !build.unstable_features() { + if !builder.unstable_features() { cargo.env("CFG_DISABLE_UNSTABLE_FEATURES", "1"); } - if let Some(ref s) = build.config.rustc_default_linker { + if let Some(ref s) = builder.config.rustc_default_linker { cargo.env("CFG_DEFAULT_LINKER", s); } - if build.config.rustc_parallel_queries { + if builder.config.rustc_parallel_queries { cargo.env("RUSTC_PARALLEL_QUERIES", "1"); } } @@ -575,18 +571,17 @@ impl Step for RustcLink { /// Same as `std_link`, only for librustc fn run(self, builder: &Builder) { - let build = builder.build; let compiler = self.compiler; let target_compiler = self.target_compiler; let target = self.target; - build.info(&format!("Copying stage{} rustc from stage{} ({} -> {} / {})", + builder.info(&format!("Copying stage{} rustc from stage{} ({} -> {} / {})", target_compiler.stage, compiler.stage, &compiler.host, target_compiler.host, target)); - add_to_sysroot(&build, &builder.sysroot_libdir(target_compiler, target), - &librustc_stamp(build, compiler, target)); + add_to_sysroot(builder, &builder.sysroot_libdir(target_compiler, target), + &librustc_stamp(builder, compiler, target)); builder.ensure(tool::CleanTools { compiler: target_compiler, target, @@ -619,84 +614,39 @@ impl Step for CodegenBackend { run.builder.ensure(CodegenBackend { compiler: run.builder.compiler(run.builder.top_stage, run.host), target: run.target, - backend + backend, }); } fn run(self, builder: &Builder) { - let build = builder.build; let compiler = self.compiler; let target = self.target; + let backend = self.backend; builder.ensure(Rustc { compiler, target }); - if build.force_use_stage1(compiler, target) { + if builder.force_use_stage1(compiler, target) { builder.ensure(CodegenBackend { - compiler: builder.compiler(1, build.build), + compiler: builder.compiler(1, builder.config.build), target, - backend: self.backend, + backend, }); return; } let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "build"); - let mut features = build.rustc_features().to_string(); + let mut features = builder.rustc_features().to_string(); cargo.arg("--manifest-path") - .arg(build.src.join("src/librustc_trans/Cargo.toml")); - rustc_cargo_env(build, &mut cargo); - - match &*self.backend { - "llvm" | "emscripten" => { - // Build LLVM for our target. This will implicitly build the - // host LLVM if necessary. - let llvm_config = builder.ensure(native::Llvm { - target, - emscripten: self.backend == "emscripten", - }); - - if self.backend == "emscripten" { - features.push_str(" emscripten"); - } - - build.info(&format!("Building stage{} codegen artifacts ({} -> {}, {})", - compiler.stage, &compiler.host, target, self.backend)); + .arg(builder.src.join("src/librustc_trans/Cargo.toml")); + rustc_cargo_env(builder, &mut cargo); - // Pass down configuration from the LLVM build into the build of - // librustc_llvm and librustc_trans. - if build.is_rust_llvm(target) { - cargo.env("LLVM_RUSTLLVM", "1"); - } - cargo.env("LLVM_CONFIG", &llvm_config); - if self.backend != "emscripten" { - let target_config = build.config.target_config.get(&target); - if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) { - cargo.env("CFG_LLVM_ROOT", s); - } - } - // Building with a static libstdc++ is only supported on linux right now, - // not for MSVC or macOS - if build.config.llvm_static_stdcpp && - !target.contains("freebsd") && - !target.contains("windows") && - !target.contains("apple") { - let file = compiler_file(build, - build.cxx(target).unwrap(), - target, - "libstdc++.a"); - cargo.env("LLVM_STATIC_STDCPP", file); - } - if build.config.llvm_link_shared { - cargo.env("LLVM_LINK_SHARED", "1"); - } - } - _ => panic!("unknown backend: {}", self.backend), - } + features += &build_codegen_backend(&builder, &mut cargo, &compiler, target, backend); - let tmp_stamp = build.cargo_out(compiler, Mode::Librustc, target) + let tmp_stamp = builder.cargo_out(compiler, Mode::Librustc, target) .join(".tmp.stamp"); - let _folder = build.fold_output(|| format!("stage{}-rustc_trans", compiler.stage)); - let files = run_cargo(build, + let _folder = builder.fold_output(|| format!("stage{}-rustc_trans", compiler.stage)); + let files = run_cargo(builder, cargo.arg("--features").arg(features), &tmp_stamp, false); @@ -717,12 +667,69 @@ impl Step for CodegenBackend { codegen_backend.display(), f.display()); } - let stamp = codegen_backend_stamp(build, compiler, target, self.backend); + let stamp = codegen_backend_stamp(builder, compiler, target, backend); let codegen_backend = codegen_backend.to_str().unwrap(); t!(t!(File::create(&stamp)).write_all(codegen_backend.as_bytes())); } } +pub fn build_codegen_backend(builder: &Builder, + cargo: &mut Command, + compiler: &Compiler, + target: Interned<String>, + backend: Interned<String>) -> String { + let mut features = String::new(); + + match &*backend { + "llvm" | "emscripten" => { + // Build LLVM for our target. This will implicitly build the + // host LLVM if necessary. + let llvm_config = builder.ensure(native::Llvm { + target, + emscripten: backend == "emscripten", + }); + + if backend == "emscripten" { + features.push_str(" emscripten"); + } + + builder.info(&format!("Building stage{} codegen artifacts ({} -> {}, {})", + compiler.stage, &compiler.host, target, backend)); + + // Pass down configuration from the LLVM build into the build of + // librustc_llvm and librustc_trans. + if builder.is_rust_llvm(target) { + cargo.env("LLVM_RUSTLLVM", "1"); + } + cargo.env("LLVM_CONFIG", &llvm_config); + if backend != "emscripten" { + let target_config = builder.config.target_config.get(&target); + if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) { + cargo.env("CFG_LLVM_ROOT", s); + } + } + // Building with a static libstdc++ is only supported on linux right now, + // not for MSVC or macOS + if builder.config.llvm_static_stdcpp && + !target.contains("freebsd") && + !target.contains("windows") && + !target.contains("apple") { + let file = compiler_file(builder, + builder.cxx(target).unwrap(), + target, + "libstdc++.a"); + cargo.env("LLVM_STATIC_STDCPP", file); + } + if builder.config.llvm_link_shared { + cargo.env("LLVM_LINK_SHARED", "1"); + } + } + _ => panic!("unknown backend: {}", backend), + } + + features +} + /// Creates the `codegen-backends` folder for a compiler that's about to be /// assembled as a complete compiler. /// @@ -732,7 +739,6 @@ impl Step for CodegenBackend { fn copy_codegen_backends_to_sysroot(builder: &Builder, compiler: Compiler, target_compiler: Compiler) { - let build = builder.build; let target = target_compiler.host; // Note that this step is different than all the other `*Link` steps in @@ -751,7 +757,7 @@ fn copy_codegen_backends_to_sysroot(builder: &Builder, } for backend in builder.config.rust_codegen_backends.iter() { - let stamp = codegen_backend_stamp(build, compiler, target, *backend); + let stamp = codegen_backend_stamp(builder, compiler, target, *backend); let mut dylib = String::new(); t!(t!(File::open(&stamp)).read_to_string(&mut dylib)); let file = Path::new(&dylib); @@ -765,7 +771,7 @@ fn copy_codegen_backends_to_sysroot(builder: &Builder, backend, &filename[dot..]) }; - build.copy(&file, &dst.join(target_filename)); + builder.copy(&file, &dst.join(target_filename)); } } @@ -786,36 +792,38 @@ fn copy_lld_to_sysroot(builder: &Builder, /// Cargo's output path for the standard library in a given stage, compiled /// by a particular compiler for the specified target. -pub fn libstd_stamp(build: &Build, compiler: Compiler, target: Interned<String>) -> PathBuf { - build.cargo_out(compiler, Mode::Libstd, target).join(".libstd.stamp") +pub fn libstd_stamp(builder: &Builder, compiler: Compiler, target: Interned<String>) -> PathBuf { + builder.cargo_out(compiler, Mode::Libstd, target).join(".libstd.stamp") } /// Cargo's output path for libtest in a given stage, compiled by a particular /// compiler for the specified target. -pub fn libtest_stamp(build: &Build, compiler: Compiler, target: Interned<String>) -> PathBuf { - build.cargo_out(compiler, Mode::Libtest, target).join(".libtest.stamp") +pub fn libtest_stamp(builder: &Builder, compiler: Compiler, target: Interned<String>) -> PathBuf { + builder.cargo_out(compiler, Mode::Libtest, target).join(".libtest.stamp") } /// Cargo's output path for librustc in a given stage, compiled by a particular /// compiler for the specified target. -pub fn librustc_stamp(build: &Build, compiler: Compiler, target: Interned<String>) -> PathBuf { - build.cargo_out(compiler, Mode::Librustc, target).join(".librustc.stamp") +pub fn librustc_stamp(builder: &Builder, compiler: Compiler, target: Interned<String>) -> PathBuf { + builder.cargo_out(compiler, Mode::Librustc, target).join(".librustc.stamp") } -fn codegen_backend_stamp(build: &Build, +/// Cargo's output path for librustc_trans in a given stage, compiled by a particular +/// compiler for the specified target and backend. +fn codegen_backend_stamp(builder: &Builder, compiler: Compiler, target: Interned<String>, backend: Interned<String>) -> PathBuf { - build.cargo_out(compiler, Mode::Librustc, target) + builder.cargo_out(compiler, Mode::Librustc, target) .join(format!(".librustc_trans-{}.stamp", backend)) } -fn compiler_file(build: &Build, +pub fn compiler_file(builder: &Builder, compiler: &Path, target: Interned<String>, file: &str) -> PathBuf { let mut cmd = Command::new(compiler); - cmd.args(build.cflags(target)); + cmd.args(builder.cflags(target)); cmd.arg(format!("-print-file-name={}", file)); let out = output(&mut cmd); PathBuf::from(out.trim()) @@ -840,12 +848,11 @@ impl Step for Sysroot { /// thinks it is by default, but it's the same as the default for stages /// 1-3. fn run(self, builder: &Builder) -> Interned<PathBuf> { - let build = builder.build; let compiler = self.compiler; let sysroot = if compiler.stage == 0 { - build.out.join(&compiler.host).join("stage0-sysroot") + builder.out.join(&compiler.host).join("stage0-sysroot") } else { - build.out.join(&compiler.host).join(format!("stage{}", compiler.stage)) + builder.out.join(&compiler.host).join(format!("stage{}", compiler.stage)) }; let _ = fs::remove_dir_all(&sysroot); t!(fs::create_dir_all(&sysroot)); @@ -872,14 +879,13 @@ impl Step for Assemble { /// Prepare a new compiler from the artifacts in `stage` /// /// This will assemble a compiler in `build/$host/stage$stage`. The compiler - /// must have been previously produced by the `stage - 1` build.build + /// must have been previously produced by the `stage - 1` builder.build /// compiler. fn run(self, builder: &Builder) -> Compiler { - let build = builder.build; let target_compiler = self.target_compiler; if target_compiler.stage == 0 { - assert_eq!(build.build, target_compiler.host, + assert_eq!(builder.config.build, target_compiler.host, "Cannot obtain compiler for non-native build triple at stage 0"); // The stage 0 compiler for the build triple is always pre-built. return target_compiler; @@ -902,14 +908,14 @@ impl Step for Assemble { // FIXME: It may be faster if we build just a stage 1 compiler and then // use that to bootstrap this compiler forward. let build_compiler = - builder.compiler(target_compiler.stage - 1, build.build); + builder.compiler(target_compiler.stage - 1, builder.config.build); // Build the libraries for this compiler to link to (i.e., the libraries // it uses at runtime). NOTE: Crates the target compiler compiles don't // link to these. (FIXME: Is that correct? It seems to be correct most // of the time but I think we do link to these for stage2/bin compilers // when not performing a full bootstrap). - if builder.build.config.keep_stage.map_or(false, |s| target_compiler.stage <= s) { + if builder.config.keep_stage.map_or(false, |s| target_compiler.stage <= s) { builder.verbose("skipping compilation of compiler due to --keep-stage"); let compiler = build_compiler; for stage in 0..min(target_compiler.stage, builder.config.keep_stage.unwrap()) { @@ -924,7 +930,7 @@ impl Step for Assemble { compiler: build_compiler, target: target_compiler.host, }); - for &backend in build.config.rust_codegen_backends.iter() { + for &backend in builder.config.rust_codegen_backends.iter() { builder.ensure(CodegenBackend { compiler: build_compiler, target: target_compiler.host, @@ -933,7 +939,7 @@ impl Step for Assemble { } } - let lld_install = if build.config.lld_enabled { + let lld_install = if builder.config.lld_enabled { Some(builder.ensure(native::Lld { target: target_compiler.host, })) @@ -943,7 +949,7 @@ impl Step for Assemble { let stage = target_compiler.stage; let host = target_compiler.host; - build.info(&format!("Assembling stage{} compiler ({})", stage, host)); + builder.info(&format!("Assembling stage{} compiler ({})", stage, host)); // Link in all dylibs to the libdir let sysroot = builder.sysroot(target_compiler); @@ -965,7 +971,7 @@ impl Step for Assemble { } // Link the compiler binary itself into place - let out_dir = build.cargo_out(build_compiler, Mode::Librustc, host); + let out_dir = builder.cargo_out(build_compiler, Mode::Librustc, host); let rustc = out_dir.join(exe("rustc", &*host)); let bindir = sysroot.join("bin"); t!(fs::create_dir_all(&bindir)); @@ -981,10 +987,10 @@ impl Step for Assemble { /// /// For a particular stage this will link the file listed in `stamp` into the /// `sysroot_dst` provided. -pub fn add_to_sysroot(build: &Build, sysroot_dst: &Path, stamp: &Path) { +pub fn add_to_sysroot(builder: &Builder, sysroot_dst: &Path, stamp: &Path) { t!(fs::create_dir_all(&sysroot_dst)); - for path in build.read_stamp_file(stamp) { - build.copy(&path, &sysroot_dst.join(path.file_name().unwrap())); + for path in builder.read_stamp_file(stamp) { + builder.copy(&path, &sysroot_dst.join(path.file_name().unwrap())); } } @@ -1011,10 +1017,10 @@ fn stderr_isatty() -> bool { } } -pub fn run_cargo(build: &Build, cargo: &mut Command, stamp: &Path, is_check: bool) +pub fn run_cargo(builder: &Builder, cargo: &mut Command, stamp: &Path, is_check: bool) -> Vec<PathBuf> { - if build.config.dry_run { + if builder.config.dry_run { return Vec::new(); } @@ -1032,7 +1038,7 @@ pub fn run_cargo(build: &Build, cargo: &mut Command, stamp: &Path, is_check: boo // files we need to probe for later. let mut deps = Vec::new(); let mut toplevel = Vec::new(); - let ok = stream_cargo(build, cargo, &mut |msg| { + let ok = stream_cargo(builder, cargo, &mut |msg| { let filenames = match msg { CargoMessage::CompilerArtifact { filenames, .. } => filenames, _ => return, @@ -1141,25 +1147,25 @@ pub fn run_cargo(build: &Build, cargo: &mut Command, stamp: &Path, is_check: boo let max = max.unwrap(); let max_path = max_path.unwrap(); if stamp_contents == new_contents && max <= stamp_mtime { - build.verbose(&format!("not updating {:?}; contents equal and {:?} <= {:?}", + builder.verbose(&format!("not updating {:?}; contents equal and {:?} <= {:?}", stamp, max, stamp_mtime)); return deps } if max > stamp_mtime { - build.verbose(&format!("updating {:?} as {:?} changed", stamp, max_path)); + builder.verbose(&format!("updating {:?} as {:?} changed", stamp, max_path)); } else { - build.verbose(&format!("updating {:?} as deps changed", stamp)); + builder.verbose(&format!("updating {:?} as deps changed", stamp)); } t!(t!(File::create(stamp)).write_all(&new_contents)); deps } pub fn stream_cargo( - build: &Build, + builder: &Builder, cargo: &mut Command, cb: &mut FnMut(CargoMessage), ) -> bool { - if build.config.dry_run { + if builder.config.dry_run { return true; } // Instruct Cargo to give us json messages on stdout, critically leaving @@ -1167,7 +1173,7 @@ pub fn stream_cargo( cargo.arg("--message-format").arg("json") .stdout(Stdio::piped()); - if stderr_isatty() && build.ci_env == CiEnv::None && + if stderr_isatty() && builder.ci_env == CiEnv::None && // if the terminal is reported as dumb, then we don't want to enable color for rustc env::var_os("TERM").map(|t| t != *"dumb").unwrap_or(true) { // since we pass message-format=json to cargo, we need to tell the rustc @@ -1176,7 +1182,7 @@ pub fn stream_cargo( cargo.env("RUSTC_COLOR", "1"); } - build.verbose(&format!("running: {:?}", cargo)); + builder.verbose(&format!("running: {:?}", cargo)); let mut child = match cargo.spawn() { Ok(child) => child, Err(e) => panic!("failed to execute command: {:?}\nerror: {}", cargo, e), diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index e1f5d34bf67..e21a59390b7 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -26,7 +26,7 @@ use std::process::{Command, Stdio}; use build_helper::output; -use {Build, Compiler, Mode}; +use {Compiler, Mode}; use channel; use util::{libdir, is_dylib, exe}; use builder::{Builder, RunConfig, ShouldRun, Step}; @@ -36,25 +36,25 @@ use tool::{self, Tool}; use cache::{INTERNER, Interned}; use time; -pub fn pkgname(build: &Build, component: &str) -> String { +pub fn pkgname(builder: &Builder, component: &str) -> String { if component == "cargo" { - format!("{}-{}", component, build.cargo_package_vers()) + format!("{}-{}", component, builder.cargo_package_vers()) } else if component == "rls" { - format!("{}-{}", component, build.rls_package_vers()) + format!("{}-{}", component, builder.rls_package_vers()) } else if component == "rustfmt" { - format!("{}-{}", component, build.rustfmt_package_vers()) + format!("{}-{}", component, builder.rustfmt_package_vers()) } else { assert!(component.starts_with("rust")); - format!("{}-{}", component, build.rust_package_vers()) + format!("{}-{}", component, builder.rust_package_vers()) } } -fn distdir(build: &Build) -> PathBuf { - build.out.join("dist") +fn distdir(builder: &Builder) -> PathBuf { + builder.out.join("dist") } -pub fn tmpdir(build: &Build) -> PathBuf { - build.out.join("tmp/dist") +pub fn tmpdir(builder: &Builder) -> PathBuf { + builder.out.join("tmp/dist") } fn rust_installer(builder: &Builder) -> Command { @@ -84,26 +84,25 @@ impl Step for Docs { /// Builds the `rust-docs` installer component. fn run(self, builder: &Builder) -> PathBuf { - let build = builder.build; let host = self.host; - let name = pkgname(build, "rust-docs"); + let name = pkgname(builder, "rust-docs"); - build.info(&format!("Dist docs ({})", host)); - if !build.config.docs { - build.info(&format!("\tskipping - docs disabled")); - return distdir(build).join(format!("{}-{}.tar.gz", name, host)); + builder.info(&format!("Dist docs ({})", host)); + if !builder.config.docs { + builder.info(&format!("\tskipping - docs disabled")); + return distdir(builder).join(format!("{}-{}.tar.gz", name, host)); } builder.default_doc(None); - let image = tmpdir(build).join(format!("{}-{}-image", name, host)); + let image = tmpdir(builder).join(format!("{}-{}-image", name, host)); let _ = fs::remove_dir_all(&image); let dst = image.join("share/doc/rust/html"); t!(fs::create_dir_all(&dst)); - let src = build.doc_out(host); - build.cp_r(&src, &dst); + let src = builder.doc_out(host); + builder.cp_r(&src, &dst); let mut cmd = rust_installer(builder); cmd.arg("generate") @@ -111,16 +110,16 @@ impl Step for Docs { .arg("--rel-manifest-dir=rustlib") .arg("--success-message=Rust-documentation-is-installed.") .arg("--image-dir").arg(&image) - .arg("--work-dir").arg(&tmpdir(build)) - .arg("--output-dir").arg(&distdir(build)) + .arg("--work-dir").arg(&tmpdir(builder)) + .arg("--output-dir").arg(&distdir(builder)) .arg(format!("--package-name={}-{}", name, host)) .arg("--component-name=rust-docs") .arg("--legacy-manifest-dirs=rustlib,cargo") .arg("--bulk-dirs=share/doc/rust/html"); - build.run(&mut cmd); - build.remove_dir(&image); + builder.run(&mut cmd); + builder.remove_dir(&image); - distdir(build).join(format!("{}-{}.tar.gz", name, host)) + distdir(builder).join(format!("{}-{}.tar.gz", name, host)) } } @@ -147,26 +146,25 @@ impl Step for RustcDocs { /// Builds the `rustc-docs` installer component. fn run(self, builder: &Builder) -> PathBuf { - let build = builder.build; let host = self.host; - let name = pkgname(build, "rustc-docs"); + let name = pkgname(builder, "rustc-docs"); - build.info(&format!("Dist compiler docs ({})", host)); - if !build.config.compiler_docs { - build.info(&format!("\tskipping - compiler docs disabled")); - return distdir(build).join(format!("{}-{}.tar.gz", name, host)); + builder.info(&format!("Dist compiler docs ({})", host)); + if !builder.config.compiler_docs { + builder.info(&format!("\tskipping - compiler docs disabled")); + return distdir(builder).join(format!("{}-{}.tar.gz", name, host)); } builder.default_doc(None); - let image = tmpdir(build).join(format!("{}-{}-image", name, host)); + let image = tmpdir(builder).join(format!("{}-{}-image", name, host)); let _ = fs::remove_dir_all(&image); let dst = image.join("share/doc/rust/html"); t!(fs::create_dir_all(&dst)); - let src = build.compiler_doc_out(host); - build.cp_r(&src, &dst); + let src = builder.compiler_doc_out(host); + builder.cp_r(&src, &dst); let mut cmd = rust_installer(builder); cmd.arg("generate") @@ -174,16 +172,16 @@ impl Step for RustcDocs { .arg("--rel-manifest-dir=rustlib") .arg("--success-message=Rustc-documentation-is-installed.") .arg("--image-dir").arg(&image) - .arg("--work-dir").arg(&tmpdir(build)) - .arg("--output-dir").arg(&distdir(build)) + .arg("--work-dir").arg(&tmpdir(builder)) + .arg("--output-dir").arg(&distdir(builder)) .arg(format!("--package-name={}-{}", name, host)) .arg("--component-name=rustc-docs") .arg("--legacy-manifest-dirs=rustlib,cargo") .arg("--bulk-dirs=share/doc/rust/html"); - build.run(&mut cmd); - build.remove_dir(&image); + builder.run(&mut cmd); + builder.remove_dir(&image); - distdir(build).join(format!("{}-{}.tar.gz", name, host)) + distdir(builder).join(format!("{}-{}.tar.gz", name, host)) } } @@ -207,10 +205,10 @@ fn find_files(files: &[&str], path: &[PathBuf]) -> Vec<PathBuf> { } fn make_win_dist( - rust_root: &Path, plat_root: &Path, target_triple: Interned<String>, build: &Build + rust_root: &Path, plat_root: &Path, target_triple: Interned<String>, builder: &Builder ) { //Ask gcc where it keeps its stuff - let mut cmd = Command::new(build.cc(target_triple)); + let mut cmd = Command::new(builder.cc(target_triple)); cmd.arg("-print-search-dirs"); let gcc_out = output(&mut cmd); @@ -296,21 +294,21 @@ fn make_win_dist( let dist_bin_dir = rust_root.join("bin/"); fs::create_dir_all(&dist_bin_dir).expect("creating dist_bin_dir failed"); for src in rustc_dlls { - build.copy_to_folder(&src, &dist_bin_dir); + builder.copy_to_folder(&src, &dist_bin_dir); } //Copy platform tools to platform-specific bin directory let target_bin_dir = plat_root.join("lib").join("rustlib").join(target_triple).join("bin"); fs::create_dir_all(&target_bin_dir).expect("creating target_bin_dir failed"); for src in target_tools { - build.copy_to_folder(&src, &target_bin_dir); + builder.copy_to_folder(&src, &target_bin_dir); } //Copy platform libs to platform-specific lib directory let target_lib_dir = plat_root.join("lib").join("rustlib").join(target_triple).join("lib"); fs::create_dir_all(&target_lib_dir).expect("creating target_lib_dir failed"); for src in target_libs { - build.copy_to_folder(&src, &target_lib_dir); + builder.copy_to_folder(&src, &target_lib_dir); } } @@ -336,16 +334,15 @@ impl Step for Mingw { /// This contains all the bits and pieces to run the MinGW Windows targets /// without any extra installed software (e.g. we bundle gcc, libraries, etc). fn run(self, builder: &Builder) -> Option<PathBuf> { - let build = builder.build; let host = self.host; if !host.contains("pc-windows-gnu") { return None; } - build.info(&format!("Dist mingw ({})", host)); - let name = pkgname(build, "rust-mingw"); - let image = tmpdir(build).join(format!("{}-{}-image", name, host)); + builder.info(&format!("Dist mingw ({})", host)); + let name = pkgname(builder, "rust-mingw"); + let image = tmpdir(builder).join(format!("{}-{}-image", name, host)); let _ = fs::remove_dir_all(&image); t!(fs::create_dir_all(&image)); @@ -353,7 +350,7 @@ impl Step for Mingw { // thrown away (this contains the runtime DLLs included in the rustc package // above) and the second argument is where to place all the MinGW components // (which is what we want). - make_win_dist(&tmpdir(build), &image, host, &build); + make_win_dist(&tmpdir(builder), &image, host, &builder); let mut cmd = rust_installer(builder); cmd.arg("generate") @@ -361,14 +358,14 @@ impl Step for Mingw { .arg("--rel-manifest-dir=rustlib") .arg("--success-message=Rust-MinGW-is-installed.") .arg("--image-dir").arg(&image) - .arg("--work-dir").arg(&tmpdir(build)) - .arg("--output-dir").arg(&distdir(build)) + .arg("--work-dir").arg(&tmpdir(builder)) + .arg("--output-dir").arg(&distdir(builder)) .arg(format!("--package-name={}-{}", name, host)) .arg("--component-name=rust-mingw") .arg("--legacy-manifest-dirs=rustlib,cargo"); - build.run(&mut cmd); + builder.run(&mut cmd); t!(fs::remove_dir_all(&image)); - Some(distdir(build).join(format!("{}-{}.tar.gz", name, host))) + Some(distdir(builder).join(format!("{}-{}.tar.gz", name, host))) } } @@ -394,15 +391,14 @@ impl Step for Rustc { /// Creates the `rustc` installer component. fn run(self, builder: &Builder) -> PathBuf { - let build = builder.build; let compiler = self.compiler; let host = self.compiler.host; - build.info(&format!("Dist rustc stage{} ({})", compiler.stage, compiler.host)); - let name = pkgname(build, "rustc"); - let image = tmpdir(build).join(format!("{}-{}-image", name, host)); + builder.info(&format!("Dist rustc stage{} ({})", compiler.stage, compiler.host)); + let name = pkgname(builder, "rustc"); + let image = tmpdir(builder).join(format!("{}-{}-image", name, host)); let _ = fs::remove_dir_all(&image); - let overlay = tmpdir(build).join(format!("{}-{}-overlay", name, host)); + let overlay = tmpdir(builder).join(format!("{}-{}-overlay", name, host)); let _ = fs::remove_dir_all(&overlay); // Prepare the rustc "image", what will actually end up getting installed @@ -411,17 +407,17 @@ impl Step for Rustc { // Prepare the overlay which is part of the tarball but won't actually be // installed let cp = |file: &str| { - build.install(&build.src.join(file), &overlay, 0o644); + builder.install(&builder.src.join(file), &overlay, 0o644); }; cp("COPYRIGHT"); cp("LICENSE-APACHE"); cp("LICENSE-MIT"); cp("README.md"); // tiny morsel of metadata is used by rust-packaging - let version = build.rust_version(); - build.create(&overlay.join("version"), &version); - if let Some(sha) = build.rust_sha() { - build.create(&overlay.join("git-commit-hash"), &sha); + let version = builder.rust_version(); + builder.create(&overlay.join("version"), &version); + if let Some(sha) = builder.rust_sha() { + builder.create(&overlay.join("git-commit-hash"), &sha); } // On MinGW we've got a few runtime DLL dependencies that we need to @@ -435,11 +431,11 @@ impl Step for Rustc { // install will *also* include the rust-mingw package, which also needs // licenses, so to be safe we just include it here in all MinGW packages. if host.contains("pc-windows-gnu") { - make_win_dist(&image, &tmpdir(build), host, build); + make_win_dist(&image, &tmpdir(builder), host, builder); let dst = image.join("share/doc"); t!(fs::create_dir_all(&dst)); - build.cp_r(&build.src.join("src/etc/third-party"), &dst); + builder.cp_r(&builder.src.join("src/etc/third-party"), &dst); } // Finally, wrap everything up in a nice tarball! @@ -449,37 +445,36 @@ impl Step for Rustc { .arg("--rel-manifest-dir=rustlib") .arg("--success-message=Rust-is-ready-to-roll.") .arg("--image-dir").arg(&image) - .arg("--work-dir").arg(&tmpdir(build)) - .arg("--output-dir").arg(&distdir(build)) + .arg("--work-dir").arg(&tmpdir(builder)) + .arg("--output-dir").arg(&distdir(builder)) .arg("--non-installed-overlay").arg(&overlay) .arg(format!("--package-name={}-{}", name, host)) .arg("--component-name=rustc") .arg("--legacy-manifest-dirs=rustlib,cargo"); - build.run(&mut cmd); - build.remove_dir(&image); - build.remove_dir(&overlay); + builder.run(&mut cmd); + builder.remove_dir(&image); + builder.remove_dir(&overlay); - return distdir(build).join(format!("{}-{}.tar.gz", name, host)); + return distdir(builder).join(format!("{}-{}.tar.gz", name, host)); fn prepare_image(builder: &Builder, compiler: Compiler, image: &Path) { let host = compiler.host; - let build = builder.build; let src = builder.sysroot(compiler); let libdir = libdir(&host); // Copy rustc/rustdoc binaries t!(fs::create_dir_all(image.join("bin"))); - build.cp_r(&src.join("bin"), &image.join("bin")); + builder.cp_r(&src.join("bin"), &image.join("bin")); - build.install(&builder.rustdoc(compiler.host), &image.join("bin"), 0o755); + builder.install(&builder.rustdoc(compiler.host), &image.join("bin"), 0o755); // Copy runtime DLLs needed by the compiler if libdir != "bin" { - for entry in build.read_dir(&src.join(libdir)) { + for entry in builder.read_dir(&src.join(libdir)) { let name = entry.file_name(); if let Some(s) = name.to_str() { if is_dylib(s) { - build.install(&entry.path(), &image.join(libdir), 0o644); + builder.install(&entry.path(), &image.join(libdir), 0o644); } } } @@ -490,7 +485,7 @@ impl Step for Rustc { let backends_rel = backends_src.strip_prefix(&src).unwrap(); let backends_dst = image.join(&backends_rel); t!(fs::create_dir_all(&backends_dst)); - build.cp_r(&backends_src, &backends_dst); + builder.cp_r(&backends_src, &backends_dst); // Copy over lld if it's there if builder.config.lld_enabled { @@ -505,22 +500,22 @@ impl Step for Rustc { .join("bin") .join(&exe); t!(fs::create_dir_all(&dst.parent().unwrap())); - build.copy(&src, &dst); + builder.copy(&src, &dst); } // Man pages t!(fs::create_dir_all(image.join("share/man/man1"))); - let man_src = build.src.join("src/doc/man"); + let man_src = builder.src.join("src/doc/man"); let man_dst = image.join("share/man/man1"); let month_year = t!(time::strftime("%B %Y", &time::now())); // don't use our `bootstrap::util::{copy, cp_r}`, because those try // to hardlink, and we don't want to edit the source templates - for file_entry in build.read_dir(&man_src) { + for file_entry in builder.read_dir(&man_src) { let page_src = file_entry.path(); let page_dst = man_dst.join(file_entry.file_name()); t!(fs::copy(&page_src, &page_dst)); // template in month/year and version number - build.replace_in_file(&page_dst, + builder.replace_in_file(&page_dst, &[("<INSERT DATE HERE>", &month_year), ("<INSERT VERSION HERE>", channel::CFG_RELEASE_NUM)]); } @@ -533,7 +528,7 @@ impl Step for Rustc { // Misc license info let cp = |file: &str| { - build.install(&build.src.join(file), &image.join("share/doc/rust"), 0o644); + builder.install(&builder.src.join(file), &image.join("share/doc/rust"), 0o644); }; cp("COPYRIGHT"); cp("LICENSE-APACHE"); @@ -565,17 +560,16 @@ impl Step for DebuggerScripts { /// Copies debugger scripts for `target` into the `sysroot` specified. fn run(self, builder: &Builder) { - let build = builder.build; let host = self.host; let sysroot = self.sysroot; let dst = sysroot.join("lib/rustlib/etc"); t!(fs::create_dir_all(&dst)); let cp_debugger_script = |file: &str| { - build.install(&build.src.join("src/etc/").join(file), &dst, 0o644); + builder.install(&builder.src.join("src/etc/").join(file), &dst, 0o644); }; if host.contains("windows-msvc") { // windbg debugger scripts - build.install(&build.src.join("src/etc/rust-windbg.cmd"), &sysroot.join("bin"), + builder.install(&builder.src.join("src/etc/rust-windbg.cmd"), &sysroot.join("bin"), 0o755); cp_debugger_script("natvis/intrinsic.natvis"); @@ -585,14 +579,14 @@ impl Step for DebuggerScripts { cp_debugger_script("debugger_pretty_printers_common.py"); // gdb debugger scripts - build.install(&build.src.join("src/etc/rust-gdb"), &sysroot.join("bin"), + builder.install(&builder.src.join("src/etc/rust-gdb"), &sysroot.join("bin"), 0o755); cp_debugger_script("gdb_load_rust_pretty_printers.py"); cp_debugger_script("gdb_rust_pretty_printing.py"); // lldb debugger scripts - build.install(&build.src.join("src/etc/rust-lldb"), &sysroot.join("bin"), + builder.install(&builder.src.join("src/etc/rust-lldb"), &sysroot.join("bin"), 0o755); cp_debugger_script("lldb_rust_formatters.py"); @@ -616,33 +610,33 @@ impl Step for Std { fn make_run(run: RunConfig) { run.builder.ensure(Std { - compiler: run.builder.compiler(run.builder.top_stage, run.builder.build.build), + compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build), target: run.target, }); } fn run(self, builder: &Builder) -> PathBuf { - let build = builder.build; let compiler = self.compiler; let target = self.target; - let name = pkgname(build, "rust-std"); - build.info(&format!("Dist std stage{} ({} -> {})", compiler.stage, &compiler.host, target)); + let name = pkgname(builder, "rust-std"); + builder.info(&format!("Dist std stage{} ({} -> {})", + compiler.stage, &compiler.host, target)); // The only true set of target libraries came from the build triple, so // let's reduce redundant work by only producing archives from that host. - if compiler.host != build.build { - build.info(&format!("\tskipping, not a build host")); - return distdir(build).join(format!("{}-{}.tar.gz", name, target)); + if compiler.host != builder.config.build { + builder.info(&format!("\tskipping, not a build host")); + return distdir(builder).join(format!("{}-{}.tar.gz", name, target)); } // We want to package up as many target libraries as possible // for the `rust-std` package, so if this is a host target we // depend on librustc and otherwise we just depend on libtest. - if build.hosts.iter().any(|t| t == target) { + if builder.hosts.iter().any(|t| t == target) { builder.ensure(compile::Rustc { compiler, target }); } else { - if build.no_std(target) == Some(true) { + if builder.no_std(target) == Some(true) { // the `test` doesn't compile for no-std targets builder.ensure(compile::Std { compiler, target }); } else { @@ -650,16 +644,16 @@ impl Step for Std { } } - let image = tmpdir(build).join(format!("{}-{}-image", name, target)); + let image = tmpdir(builder).join(format!("{}-{}-image", name, target)); let _ = fs::remove_dir_all(&image); let dst = image.join("lib/rustlib").join(target); t!(fs::create_dir_all(&dst)); let mut src = builder.sysroot_libdir(compiler, target).to_path_buf(); src.pop(); // Remove the trailing /lib folder from the sysroot_libdir - build.cp_filtered(&src, &dst, &|path| { + builder.cp_filtered(&src, &dst, &|path| { let name = path.file_name().and_then(|s| s.to_str()); - name != Some(build.config.rust_codegen_backends_dir.as_str()) && + name != Some(builder.config.rust_codegen_backends_dir.as_str()) && name != Some("bin") }); @@ -670,14 +664,14 @@ impl Step for Std { .arg("--rel-manifest-dir=rustlib") .arg("--success-message=std-is-standing-at-the-ready.") .arg("--image-dir").arg(&image) - .arg("--work-dir").arg(&tmpdir(build)) - .arg("--output-dir").arg(&distdir(build)) + .arg("--work-dir").arg(&tmpdir(builder)) + .arg("--output-dir").arg(&distdir(builder)) .arg(format!("--package-name={}-{}", name, target)) .arg(format!("--component-name=rust-std-{}", target)) .arg("--legacy-manifest-dirs=rustlib,cargo"); - build.run(&mut cmd); - build.remove_dir(&image); - distdir(build).join(format!("{}-{}.tar.gz", name, target)) + builder.run(&mut cmd); + builder.remove_dir(&image); + distdir(builder).join(format!("{}-{}.tar.gz", name, target)) } } @@ -693,50 +687,49 @@ impl Step for Analysis { fn should_run(run: ShouldRun) -> ShouldRun { let builder = run.builder; - run.path("analysis").default_condition(builder.build.config.extended) + run.path("analysis").default_condition(builder.config.extended) } fn make_run(run: RunConfig) { run.builder.ensure(Analysis { - compiler: run.builder.compiler(run.builder.top_stage, run.builder.build.build), + compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build), target: run.target, }); } /// Creates a tarball of save-analysis metadata, if available. fn run(self, builder: &Builder) -> PathBuf { - let build = builder.build; let compiler = self.compiler; let target = self.target; - assert!(build.config.extended); - build.info(&format!("Dist analysis")); - let name = pkgname(build, "rust-analysis"); + assert!(builder.config.extended); + builder.info(&format!("Dist analysis")); + let name = pkgname(builder, "rust-analysis"); - if &compiler.host != build.build { - build.info(&format!("\tskipping, not a build host")); - return distdir(build).join(format!("{}-{}.tar.gz", name, target)); + if &compiler.host != builder.config.build { + builder.info(&format!("\tskipping, not a build host")); + return distdir(builder).join(format!("{}-{}.tar.gz", name, target)); } builder.ensure(Std { compiler, target }); // Package save-analysis from stage1 if not doing a full bootstrap, as the // stage2 artifacts is simply copied from stage1 in that case. - let compiler = if build.force_use_stage1(compiler, target) { + let compiler = if builder.force_use_stage1(compiler, target) { builder.compiler(1, compiler.host) } else { compiler.clone() }; - let image = tmpdir(build).join(format!("{}-{}-image", name, target)); + let image = tmpdir(builder).join(format!("{}-{}-image", name, target)); - let src = build.stage_out(compiler, Mode::Libstd) - .join(target).join(build.cargo_dir()).join("deps"); + let src = builder.stage_out(compiler, Mode::Libstd) + .join(target).join(builder.cargo_dir()).join("deps"); let image_src = src.join("save-analysis"); let dst = image.join("lib/rustlib").join(target).join("analysis"); t!(fs::create_dir_all(&dst)); - build.info(&format!("image_src: {:?}, dst: {:?}", image_src, dst)); - build.cp_r(&image_src, &dst); + builder.info(&format!("image_src: {:?}, dst: {:?}", image_src, dst)); + builder.cp_r(&image_src, &dst); let mut cmd = rust_installer(builder); cmd.arg("generate") @@ -744,18 +737,18 @@ impl Step for Analysis { .arg("--rel-manifest-dir=rustlib") .arg("--success-message=save-analysis-saved.") .arg("--image-dir").arg(&image) - .arg("--work-dir").arg(&tmpdir(build)) - .arg("--output-dir").arg(&distdir(build)) + .arg("--work-dir").arg(&tmpdir(builder)) + .arg("--output-dir").arg(&distdir(builder)) .arg(format!("--package-name={}-{}", name, target)) .arg(format!("--component-name=rust-analysis-{}", target)) .arg("--legacy-manifest-dirs=rustlib,cargo"); - build.run(&mut cmd); - build.remove_dir(&image); - distdir(build).join(format!("{}-{}.tar.gz", name, target)) + builder.run(&mut cmd); + builder.remove_dir(&image); + distdir(builder).join(format!("{}-{}.tar.gz", name, target)) } } -fn copy_src_dirs(build: &Build, src_dirs: &[&str], exclude_dirs: &[&str], dst_dir: &Path) { +fn copy_src_dirs(builder: &Builder, src_dirs: &[&str], exclude_dirs: &[&str], dst_dir: &Path) { fn filter_fn(exclude_dirs: &[&str], dir: &str, path: &Path) -> bool { let spath = match path.to_str() { Some(path) => path, @@ -794,7 +787,8 @@ fn copy_src_dirs(build: &Build, src_dirs: &[&str], exclude_dirs: &[&str], dst_di for item in src_dirs { let dst = &dst_dir.join(item); t!(fs::create_dir_all(dst)); - build.cp_filtered(&build.src.join(item), dst, &|path| filter_fn(exclude_dirs, item, path)); + builder.cp_filtered( + &builder.src.join(item), dst, &|path| filter_fn(exclude_dirs, item, path)); } } @@ -817,11 +811,10 @@ impl Step for Src { /// Creates the `rust-src` installer component fn run(self, builder: &Builder) -> PathBuf { - let build = builder.build; - build.info(&format!("Dist src")); + builder.info(&format!("Dist src")); - let name = pkgname(build, "rust-src"); - let image = tmpdir(build).join(format!("{}-image", name)); + let name = pkgname(builder, "rust-src"); + let image = tmpdir(builder).join(format!("{}-image", name)); let _ = fs::remove_dir_all(&image); let dst = image.join("lib/rustlib/src"); @@ -866,9 +859,9 @@ impl Step for Src { "src/jemalloc/test/unit", ]; - copy_src_dirs(build, &std_src_dirs[..], &std_src_dirs_exclude[..], &dst_src); + copy_src_dirs(builder, &std_src_dirs[..], &std_src_dirs_exclude[..], &dst_src); for file in src_files.iter() { - build.copy(&build.src.join(file), &dst_src.join(file)); + builder.copy(&builder.src.join(file), &dst_src.join(file)); } // Create source tarball in rust-installer format @@ -878,15 +871,15 @@ impl Step for Src { .arg("--rel-manifest-dir=rustlib") .arg("--success-message=Awesome-Source.") .arg("--image-dir").arg(&image) - .arg("--work-dir").arg(&tmpdir(build)) - .arg("--output-dir").arg(&distdir(build)) + .arg("--work-dir").arg(&tmpdir(builder)) + .arg("--output-dir").arg(&distdir(builder)) .arg(format!("--package-name={}", name)) .arg("--component-name=rust-src") .arg("--legacy-manifest-dirs=rustlib,cargo"); - build.run(&mut cmd); + builder.run(&mut cmd); - build.remove_dir(&image); - distdir(build).join(&format!("{}.tar.gz", name)) + builder.remove_dir(&image); + distdir(builder).join(&format!("{}.tar.gz", name)) } } @@ -912,12 +905,11 @@ impl Step for PlainSourceTarball { /// Creates the plain source tarball fn run(self, builder: &Builder) -> PathBuf { - let build = builder.build; - build.info(&format!("Create plain source tarball")); + builder.info(&format!("Create plain source tarball")); // Make sure that the root folder of tarball has the correct name - let plain_name = format!("{}-src", pkgname(build, "rustc")); - let plain_dst_src = tmpdir(build).join(&plain_name); + let plain_name = format!("{}-src", pkgname(builder, "rustc")); + let plain_dst_src = tmpdir(builder).join(&plain_name); let _ = fs::remove_dir_all(&plain_dst_src); t!(fs::create_dir_all(&plain_dst_src)); @@ -937,68 +929,68 @@ impl Step for PlainSourceTarball { "src", ]; - copy_src_dirs(build, &src_dirs[..], &[], &plain_dst_src); + copy_src_dirs(builder, &src_dirs[..], &[], &plain_dst_src); // Copy the files normally for item in &src_files { - build.copy(&build.src.join(item), &plain_dst_src.join(item)); + builder.copy(&builder.src.join(item), &plain_dst_src.join(item)); } // Create the version file - build.create(&plain_dst_src.join("version"), &build.rust_version()); - if let Some(sha) = build.rust_sha() { - build.create(&plain_dst_src.join("git-commit-hash"), &sha); + builder.create(&plain_dst_src.join("version"), &builder.rust_version()); + if let Some(sha) = builder.rust_sha() { + builder.create(&plain_dst_src.join("git-commit-hash"), &sha); } // If we're building from git sources, we need to vendor a complete distribution. - if build.rust_info.is_git() { + if builder.rust_info.is_git() { // Get cargo-vendor installed, if it isn't already. let mut has_cargo_vendor = false; - let mut cmd = Command::new(&build.initial_cargo); + let mut cmd = Command::new(&builder.initial_cargo); for line in output(cmd.arg("install").arg("--list")).lines() { has_cargo_vendor |= line.starts_with("cargo-vendor "); } if !has_cargo_vendor { - let mut cmd = Command::new(&build.initial_cargo); + let mut cmd = Command::new(&builder.initial_cargo); cmd.arg("install") .arg("--force") .arg("--debug") .arg("--vers").arg(CARGO_VENDOR_VERSION) .arg("cargo-vendor") - .env("RUSTC", &build.initial_rustc); - if let Some(dir) = build.openssl_install_dir(build.config.build) { + .env("RUSTC", &builder.initial_rustc); + if let Some(dir) = builder.openssl_install_dir(builder.config.build) { builder.ensure(native::Openssl { - target: build.config.build, + target: builder.config.build, }); cmd.env("OPENSSL_DIR", dir); } - build.run(&mut cmd); + builder.run(&mut cmd); } // Vendor all Cargo dependencies - let mut cmd = Command::new(&build.initial_cargo); + let mut cmd = Command::new(&builder.initial_cargo); cmd.arg("vendor") .current_dir(&plain_dst_src.join("src")); - build.run(&mut cmd); + builder.run(&mut cmd); } // Create plain source tarball - let plain_name = format!("rustc-{}-src", build.rust_package_vers()); - let mut tarball = distdir(build).join(&format!("{}.tar.gz", plain_name)); + let plain_name = format!("rustc-{}-src", builder.rust_package_vers()); + let mut tarball = distdir(builder).join(&format!("{}.tar.gz", plain_name)); tarball.set_extension(""); // strip .gz tarball.set_extension(""); // strip .tar if let Some(dir) = tarball.parent() { - build.create_dir(&dir); + builder.create_dir(&dir); } - build.info(&format!("running installer")); + builder.info(&format!("running installer")); let mut cmd = rust_installer(builder); cmd.arg("tarball") .arg("--input").arg(&plain_name) .arg("--output").arg(&tarball) .arg("--work-dir=.") - .current_dir(tmpdir(build)); - build.run(&mut cmd); - distdir(build).join(&format!("{}.tar.gz", plain_name)) + .current_dir(tmpdir(builder)); + builder.run(&mut cmd); + distdir(builder).join(&format!("{}.tar.gz", plain_name)) } } @@ -1043,52 +1035,51 @@ impl Step for Cargo { } fn run(self, builder: &Builder) -> PathBuf { - let build = builder.build; let stage = self.stage; let target = self.target; - build.info(&format!("Dist cargo stage{} ({})", stage, target)); - let src = build.src.join("src/tools/cargo"); + builder.info(&format!("Dist cargo stage{} ({})", stage, target)); + let src = builder.src.join("src/tools/cargo"); let etc = src.join("src/etc"); - let release_num = build.release_num("cargo"); - let name = pkgname(build, "cargo"); - let version = builder.cargo_info.version(build, &release_num); + let release_num = builder.release_num("cargo"); + let name = pkgname(builder, "cargo"); + let version = builder.cargo_info.version(builder, &release_num); - let tmp = tmpdir(build); + let tmp = tmpdir(builder); let image = tmp.join("cargo-image"); drop(fs::remove_dir_all(&image)); - build.create_dir(&image); + builder.create_dir(&image); // Prepare the image directory - build.create_dir(&image.join("share/zsh/site-functions")); - build.create_dir(&image.join("etc/bash_completion.d")); + builder.create_dir(&image.join("share/zsh/site-functions")); + builder.create_dir(&image.join("etc/bash_completion.d")); let cargo = builder.ensure(tool::Cargo { - compiler: builder.compiler(stage, build.build), + compiler: builder.compiler(stage, builder.config.build), target }); - build.install(&cargo, &image.join("bin"), 0o755); + builder.install(&cargo, &image.join("bin"), 0o755); for man in t!(etc.join("man").read_dir()) { let man = t!(man); - build.install(&man.path(), &image.join("share/man/man1"), 0o644); + builder.install(&man.path(), &image.join("share/man/man1"), 0o644); } - build.install(&etc.join("_cargo"), &image.join("share/zsh/site-functions"), 0o644); - build.copy(&etc.join("cargo.bashcomp.sh"), + builder.install(&etc.join("_cargo"), &image.join("share/zsh/site-functions"), 0o644); + builder.copy(&etc.join("cargo.bashcomp.sh"), &image.join("etc/bash_completion.d/cargo")); let doc = image.join("share/doc/cargo"); - build.install(&src.join("README.md"), &doc, 0o644); - build.install(&src.join("LICENSE-MIT"), &doc, 0o644); - build.install(&src.join("LICENSE-APACHE"), &doc, 0o644); - build.install(&src.join("LICENSE-THIRD-PARTY"), &doc, 0o644); + builder.install(&src.join("README.md"), &doc, 0o644); + builder.install(&src.join("LICENSE-MIT"), &doc, 0o644); + builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644); + builder.install(&src.join("LICENSE-THIRD-PARTY"), &doc, 0o644); // Prepare the overlay let overlay = tmp.join("cargo-overlay"); drop(fs::remove_dir_all(&overlay)); - build.create_dir(&overlay); - build.install(&src.join("README.md"), &overlay, 0o644); - build.install(&src.join("LICENSE-MIT"), &overlay, 0o644); - build.install(&src.join("LICENSE-APACHE"), &overlay, 0o644); - build.install(&src.join("LICENSE-THIRD-PARTY"), &overlay, 0o644); - build.create(&overlay.join("version"), &version); + builder.create_dir(&overlay); + builder.install(&src.join("README.md"), &overlay, 0o644); + builder.install(&src.join("LICENSE-MIT"), &overlay, 0o644); + builder.install(&src.join("LICENSE-APACHE"), &overlay, 0o644); + builder.install(&src.join("LICENSE-THIRD-PARTY"), &overlay, 0o644); + builder.create(&overlay.join("version"), &version); // Generate the installer tarball let mut cmd = rust_installer(builder); @@ -1097,14 +1088,14 @@ impl Step for Cargo { .arg("--rel-manifest-dir=rustlib") .arg("--success-message=Rust-is-ready-to-roll.") .arg("--image-dir").arg(&image) - .arg("--work-dir").arg(&tmpdir(build)) - .arg("--output-dir").arg(&distdir(build)) + .arg("--work-dir").arg(&tmpdir(builder)) + .arg("--output-dir").arg(&distdir(builder)) .arg("--non-installed-overlay").arg(&overlay) .arg(format!("--package-name={}-{}", name, target)) .arg("--component-name=cargo") .arg("--legacy-manifest-dirs=rustlib,cargo"); - build.run(&mut cmd); - distdir(build).join(format!("{}-{}.tar.gz", name, target)) + builder.run(&mut cmd); + distdir(builder).join(format!("{}-{}.tar.gz", name, target)) } } @@ -1130,18 +1121,17 @@ impl Step for Rls { } fn run(self, builder: &Builder) -> Option<PathBuf> { - let build = builder.build; let stage = self.stage; let target = self.target; - assert!(build.config.extended); + assert!(builder.config.extended); - build.info(&format!("Dist RLS stage{} ({})", stage, target)); - let src = build.src.join("src/tools/rls"); - let release_num = build.release_num("rls"); - let name = pkgname(build, "rls"); - let version = build.rls_info.version(build, &release_num); + builder.info(&format!("Dist RLS stage{} ({})", stage, target)); + let src = builder.src.join("src/tools/rls"); + let release_num = builder.release_num("rls"); + let name = pkgname(builder, "rls"); + let version = builder.rls_info.version(builder, &release_num); - let tmp = tmpdir(build); + let tmp = tmpdir(builder); let image = tmp.join("rls-image"); drop(fs::remove_dir_all(&image)); t!(fs::create_dir_all(&image)); @@ -1150,24 +1140,24 @@ impl Step for Rls { // We expect RLS to build, because we've exited this step above if tool // state for RLS isn't testing. let rls = builder.ensure(tool::Rls { - compiler: builder.compiler(stage, build.build), + compiler: builder.compiler(stage, builder.config.build), target, extra_features: Vec::new() }).or_else(|| { println!("Unable to build RLS, skipping dist"); None })?; - build.install(&rls, &image.join("bin"), 0o755); + builder.install(&rls, &image.join("bin"), 0o755); let doc = image.join("share/doc/rls"); - build.install(&src.join("README.md"), &doc, 0o644); - build.install(&src.join("LICENSE-MIT"), &doc, 0o644); - build.install(&src.join("LICENSE-APACHE"), &doc, 0o644); + builder.install(&src.join("README.md"), &doc, 0o644); + builder.install(&src.join("LICENSE-MIT"), &doc, 0o644); + builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644); // Prepare the overlay let overlay = tmp.join("rls-overlay"); drop(fs::remove_dir_all(&overlay)); t!(fs::create_dir_all(&overlay)); - build.install(&src.join("README.md"), &overlay, 0o644); - build.install(&src.join("LICENSE-MIT"), &overlay, 0o644); - build.install(&src.join("LICENSE-APACHE"), &overlay, 0o644); - build.create(&overlay.join("version"), &version); + builder.install(&src.join("README.md"), &overlay, 0o644); + builder.install(&src.join("LICENSE-MIT"), &overlay, 0o644); + builder.install(&src.join("LICENSE-APACHE"), &overlay, 0o644); + builder.create(&overlay.join("version"), &version); // Generate the installer tarball let mut cmd = rust_installer(builder); @@ -1176,15 +1166,15 @@ impl Step for Rls { .arg("--rel-manifest-dir=rustlib") .arg("--success-message=RLS-ready-to-serve.") .arg("--image-dir").arg(&image) - .arg("--work-dir").arg(&tmpdir(build)) - .arg("--output-dir").arg(&distdir(build)) + .arg("--work-dir").arg(&tmpdir(builder)) + .arg("--output-dir").arg(&distdir(builder)) .arg("--non-installed-overlay").arg(&overlay) .arg(format!("--package-name={}-{}", name, target)) .arg("--legacy-manifest-dirs=rustlib,cargo") .arg("--component-name=rls-preview"); - build.run(&mut cmd); - Some(distdir(build).join(format!("{}-{}.tar.gz", name, target))) + builder.run(&mut cmd); + Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target))) } } @@ -1211,46 +1201,45 @@ impl Step for Rustfmt { } fn run(self, builder: &Builder) -> Option<PathBuf> { - let build = builder.build; let stage = self.stage; let target = self.target; - build.info(&format!("Dist Rustfmt stage{} ({})", stage, target)); - let src = build.src.join("src/tools/rustfmt"); - let release_num = build.release_num("rustfmt"); - let name = pkgname(build, "rustfmt"); - let version = build.rustfmt_info.version(build, &release_num); + builder.info(&format!("Dist Rustfmt stage{} ({})", stage, target)); + let src = builder.src.join("src/tools/rustfmt"); + let release_num = builder.release_num("rustfmt"); + let name = pkgname(builder, "rustfmt"); + let version = builder.rustfmt_info.version(builder, &release_num); - let tmp = tmpdir(build); + let tmp = tmpdir(builder); let image = tmp.join("rustfmt-image"); drop(fs::remove_dir_all(&image)); - build.create_dir(&image); + builder.create_dir(&image); // Prepare the image directory let rustfmt = builder.ensure(tool::Rustfmt { - compiler: builder.compiler(stage, build.build), + compiler: builder.compiler(stage, builder.config.build), target, extra_features: Vec::new() }).or_else(|| { println!("Unable to build Rustfmt, skipping dist"); None })?; let cargofmt = builder.ensure(tool::Cargofmt { - compiler: builder.compiler(stage, build.build), + compiler: builder.compiler(stage, builder.config.build), target, extra_features: Vec::new() }).or_else(|| { println!("Unable to build Cargofmt, skipping dist"); None })?; - build.install(&rustfmt, &image.join("bin"), 0o755); - build.install(&cargofmt, &image.join("bin"), 0o755); + builder.install(&rustfmt, &image.join("bin"), 0o755); + builder.install(&cargofmt, &image.join("bin"), 0o755); let doc = image.join("share/doc/rustfmt"); - build.install(&src.join("README.md"), &doc, 0o644); - build.install(&src.join("LICENSE-MIT"), &doc, 0o644); - build.install(&src.join("LICENSE-APACHE"), &doc, 0o644); + builder.install(&src.join("README.md"), &doc, 0o644); + builder.install(&src.join("LICENSE-MIT"), &doc, 0o644); + builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644); // Prepare the overlay let overlay = tmp.join("rustfmt-overlay"); drop(fs::remove_dir_all(&overlay)); - build.create_dir(&overlay); - build.install(&src.join("README.md"), &overlay, 0o644); - build.install(&src.join("LICENSE-MIT"), &overlay, 0o644); - build.install(&src.join("LICENSE-APACHE"), &overlay, 0o644); - build.create(&overlay.join("version"), &version); + builder.create_dir(&overlay); + builder.install(&src.join("README.md"), &overlay, 0o644); + builder.install(&src.join("LICENSE-MIT"), &overlay, 0o644); + builder.install(&src.join("LICENSE-APACHE"), &overlay, 0o644); + builder.create(&overlay.join("version"), &version); // Generate the installer tarball let mut cmd = rust_installer(builder); @@ -1259,15 +1248,15 @@ impl Step for Rustfmt { .arg("--rel-manifest-dir=rustlib") .arg("--success-message=rustfmt-ready-to-fmt.") .arg("--image-dir").arg(&image) - .arg("--work-dir").arg(&tmpdir(build)) - .arg("--output-dir").arg(&distdir(build)) + .arg("--work-dir").arg(&tmpdir(builder)) + .arg("--output-dir").arg(&distdir(builder)) .arg("--non-installed-overlay").arg(&overlay) .arg(format!("--package-name={}-{}", name, target)) .arg("--legacy-manifest-dirs=rustlib,cargo") .arg("--component-name=rustfmt-preview"); - build.run(&mut cmd); - Some(distdir(build).join(format!("{}-{}.tar.gz", name, target))) + builder.run(&mut cmd); + Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target))) } } @@ -1291,18 +1280,17 @@ impl Step for Extended { fn make_run(run: RunConfig) { run.builder.ensure(Extended { stage: run.builder.top_stage, - host: run.builder.build.build, + host: run.builder.config.build, target: run.target, }); } /// Creates a combined installer for the specified target in the provided stage. fn run(self, builder: &Builder) { - let build = builder.build; let stage = self.stage; let target = self.target; - build.info(&format!("Dist extended stage{} ({})", stage, target)); + builder.info(&format!("Dist extended stage{} ({})", stage, target)); let rustc_installer = builder.ensure(Rustc { compiler: builder.compiler(stage, target), @@ -1322,21 +1310,21 @@ impl Step for Extended { target, }); - let tmp = tmpdir(build); + let tmp = tmpdir(builder); let overlay = tmp.join("extended-overlay"); - let etc = build.src.join("src/etc/installer"); + let etc = builder.src.join("src/etc/installer"); let work = tmp.join("work"); let _ = fs::remove_dir_all(&overlay); - build.install(&build.src.join("COPYRIGHT"), &overlay, 0o644); - build.install(&build.src.join("LICENSE-APACHE"), &overlay, 0o644); - build.install(&build.src.join("LICENSE-MIT"), &overlay, 0o644); - let version = build.rust_version(); - build.create(&overlay.join("version"), &version); - if let Some(sha) = build.rust_sha() { - build.create(&overlay.join("git-commit-hash"), &sha); + builder.install(&builder.src.join("COPYRIGHT"), &overlay, 0o644); + builder.install(&builder.src.join("LICENSE-APACHE"), &overlay, 0o644); + builder.install(&builder.src.join("LICENSE-MIT"), &overlay, 0o644); + let version = builder.rust_version(); + builder.create(&overlay.join("version"), &version); + if let Some(sha) = builder.rust_sha() { + builder.create(&overlay.join("git-commit-hash"), &sha); } - build.install(&etc.join("README.md"), &overlay, 0o644); + builder.install(&etc.join("README.md"), &overlay, 0o644); // When rust-std package split from rustc, we needed to ensure that during // upgrades rustc was upgraded before rust-std. To avoid rustc clobbering @@ -1349,7 +1337,7 @@ impl Step for Extended { tarballs.extend(rustfmt_installer.clone()); tarballs.push(analysis_installer); tarballs.push(std_installer); - if build.config.docs { + if builder.config.docs { tarballs.push(docs_installer); } if target.contains("pc-windows-gnu") { @@ -1367,17 +1355,17 @@ impl Step for Extended { .arg("--rel-manifest-dir=rustlib") .arg("--success-message=Rust-is-ready-to-roll.") .arg("--work-dir").arg(&work) - .arg("--output-dir").arg(&distdir(build)) - .arg(format!("--package-name={}-{}", pkgname(build, "rust"), target)) + .arg("--output-dir").arg(&distdir(builder)) + .arg(format!("--package-name={}-{}", pkgname(builder, "rust"), target)) .arg("--legacy-manifest-dirs=rustlib,cargo") .arg("--input-tarballs").arg(input_tarballs) .arg("--non-installed-overlay").arg(&overlay); - build.run(&mut cmd); + builder.run(&mut cmd); let mut license = String::new(); - license += &build.read(&build.src.join("COPYRIGHT")); - license += &build.read(&build.src.join("LICENSE-APACHE")); - license += &build.read(&build.src.join("LICENSE-MIT")); + license += &builder.read(&builder.src.join("COPYRIGHT")); + license += &builder.read(&builder.src.join("LICENSE-APACHE")); + license += &builder.read(&builder.src.join("LICENSE-MIT")); license.push_str("\n"); license.push_str("\n"); @@ -1432,14 +1420,14 @@ impl Step for Extended { .arg("--scripts").arg(pkg.join(component)) .arg("--nopayload") .arg(pkg.join(component).with_extension("pkg")); - build.run(&mut cmd); + builder.run(&mut cmd); }; let prepare = |name: &str| { - build.create_dir(&pkg.join(name)); - build.cp_r(&work.join(&format!("{}-{}", pkgname(build, name), target)), + builder.create_dir(&pkg.join(name)); + builder.cp_r(&work.join(&format!("{}-{}", pkgname(builder, name), target)), &pkg.join(name)); - build.install(&etc.join("pkg/postinstall"), &pkg.join(name), 0o755); + builder.install(&etc.join("pkg/postinstall"), &pkg.join(name), 0o755); pkgbuild(name); }; prepare("rustc"); @@ -1453,20 +1441,20 @@ impl Step for Extended { } // create an 'uninstall' package - build.install(&etc.join("pkg/postinstall"), &pkg.join("uninstall"), 0o755); + builder.install(&etc.join("pkg/postinstall"), &pkg.join("uninstall"), 0o755); pkgbuild("uninstall"); - build.create_dir(&pkg.join("res")); - build.create(&pkg.join("res/LICENSE.txt"), &license); - build.install(&etc.join("gfx/rust-logo.png"), &pkg.join("res"), 0o644); + builder.create_dir(&pkg.join("res")); + builder.create(&pkg.join("res/LICENSE.txt"), &license); + builder.install(&etc.join("gfx/rust-logo.png"), &pkg.join("res"), 0o644); let mut cmd = Command::new("productbuild"); cmd.arg("--distribution").arg(xform(&etc.join("pkg/Distribution.xml"))) .arg("--resources").arg(pkg.join("res")) - .arg(distdir(build).join(format!("{}-{}.pkg", - pkgname(build, "rust"), + .arg(distdir(builder).join(format!("{}-{}.pkg", + pkgname(builder, "rust"), target))) .arg("--package-path").arg(&pkg); - build.run(&mut cmd); + builder.run(&mut cmd); } if target.contains("windows") { @@ -1474,7 +1462,7 @@ impl Step for Extended { let _ = fs::remove_dir_all(&exe); let prepare = |name: &str| { - build.create_dir(&exe.join(name)); + builder.create_dir(&exe.join(name)); let dir = if name == "rust-std" || name == "rust-analysis" { format!("{}-{}", name, target) } else if name == "rls" { @@ -1482,10 +1470,10 @@ impl Step for Extended { } else { name.to_string() }; - build.cp_r(&work.join(&format!("{}-{}", pkgname(build, name), target)) + builder.cp_r(&work.join(&format!("{}-{}", pkgname(builder, name), target)) .join(dir), &exe.join(name)); - build.remove(&exe.join(name).join("manifest.in")); + builder.remove(&exe.join(name).join("manifest.in")); }; prepare("rustc"); prepare("cargo"); @@ -1499,11 +1487,11 @@ impl Step for Extended { prepare("rust-mingw"); } - build.install(&xform(&etc.join("exe/rust.iss")), &exe, 0o644); - build.install(&etc.join("exe/modpath.iss"), &exe, 0o644); - build.install(&etc.join("exe/upgrade.iss"), &exe, 0o644); - build.install(&etc.join("gfx/rust-logo.ico"), &exe, 0o644); - build.create(&exe.join("LICENSE.txt"), &license); + builder.install(&xform(&etc.join("exe/rust.iss")), &exe, 0o644); + builder.install(&etc.join("exe/modpath.iss"), &exe, 0o644); + builder.install(&etc.join("exe/upgrade.iss"), &exe, 0o644); + builder.install(&etc.join("gfx/rust-logo.ico"), &exe, 0o644); + builder.create(&exe.join("LICENSE.txt"), &license); // Generate exe installer let mut cmd = Command::new("iscc"); @@ -1512,10 +1500,10 @@ impl Step for Extended { if target.contains("windows-gnu") { cmd.arg("/dMINGW"); } - add_env(build, &mut cmd, target); - build.run(&mut cmd); - build.install(&exe.join(format!("{}-{}.exe", pkgname(build, "rust"), target)), - &distdir(build), + add_env(builder, &mut cmd, target); + builder.run(&mut cmd); + builder.install(&exe.join(format!("{}-{}.exe", pkgname(builder, "rust"), target)), + &distdir(builder), 0o755); // Generate msi installer @@ -1525,7 +1513,7 @@ impl Step for Extended { let light = wix.join("bin/light.exe"); let heat_flags = ["-nologo", "-gg", "-sfrag", "-srd", "-sreg"]; - build.run(Command::new(&heat) + builder.run(Command::new(&heat) .current_dir(&exe) .arg("dir") .arg("rustc") @@ -1534,7 +1522,7 @@ impl Step for Extended { .arg("-dr").arg("Rustc") .arg("-var").arg("var.RustcDir") .arg("-out").arg(exe.join("RustcGroup.wxs"))); - build.run(Command::new(&heat) + builder.run(Command::new(&heat) .current_dir(&exe) .arg("dir") .arg("rust-docs") @@ -1544,7 +1532,7 @@ impl Step for Extended { .arg("-var").arg("var.DocsDir") .arg("-out").arg(exe.join("DocsGroup.wxs")) .arg("-t").arg(etc.join("msi/squash-components.xsl"))); - build.run(Command::new(&heat) + builder.run(Command::new(&heat) .current_dir(&exe) .arg("dir") .arg("cargo") @@ -1554,7 +1542,7 @@ impl Step for Extended { .arg("-var").arg("var.CargoDir") .arg("-out").arg(exe.join("CargoGroup.wxs")) .arg("-t").arg(etc.join("msi/remove-duplicates.xsl"))); - build.run(Command::new(&heat) + builder.run(Command::new(&heat) .current_dir(&exe) .arg("dir") .arg("rust-std") @@ -1564,7 +1552,7 @@ impl Step for Extended { .arg("-var").arg("var.StdDir") .arg("-out").arg(exe.join("StdGroup.wxs"))); if rls_installer.is_some() { - build.run(Command::new(&heat) + builder.run(Command::new(&heat) .current_dir(&exe) .arg("dir") .arg("rls") @@ -1575,7 +1563,7 @@ impl Step for Extended { .arg("-out").arg(exe.join("RlsGroup.wxs")) .arg("-t").arg(etc.join("msi/remove-duplicates.xsl"))); } - build.run(Command::new(&heat) + builder.run(Command::new(&heat) .current_dir(&exe) .arg("dir") .arg("rust-analysis") @@ -1586,7 +1574,7 @@ impl Step for Extended { .arg("-out").arg(exe.join("AnalysisGroup.wxs")) .arg("-t").arg(etc.join("msi/remove-duplicates.xsl"))); if target.contains("windows-gnu") { - build.run(Command::new(&heat) + builder.run(Command::new(&heat) .current_dir(&exe) .arg("dir") .arg("rust-mingw") @@ -1612,7 +1600,7 @@ impl Step for Extended { .arg("-arch").arg(&arch) .arg("-out").arg(&output) .arg(&input); - add_env(build, &mut cmd, target); + add_env(builder, &mut cmd, target); if rls_installer.is_some() { cmd.arg("-dRlsDir=rls"); @@ -1620,7 +1608,7 @@ impl Step for Extended { if target.contains("windows-gnu") { cmd.arg("-dGccDir=rust-mingw"); } - build.run(&mut cmd); + builder.run(&mut cmd); }; candle(&xform(&etc.join("msi/rust.wxs"))); candle(&etc.join("msi/ui.wxs")); @@ -1638,11 +1626,11 @@ impl Step for Extended { candle("GccGroup.wxs".as_ref()); } - build.create(&exe.join("LICENSE.rtf"), &rtf); - build.install(&etc.join("gfx/banner.bmp"), &exe, 0o644); - build.install(&etc.join("gfx/dialogbg.bmp"), &exe, 0o644); + builder.create(&exe.join("LICENSE.rtf"), &rtf); + builder.install(&etc.join("gfx/banner.bmp"), &exe, 0o644); + builder.install(&etc.join("gfx/dialogbg.bmp"), &exe, 0o644); - let filename = format!("{}-{}.msi", pkgname(build, "rust"), target); + let filename = format!("{}-{}.msi", pkgname(builder, "rust"), target); let mut cmd = Command::new(&light); cmd.arg("-nologo") .arg("-ext").arg("WixUIExtension") @@ -1668,28 +1656,28 @@ impl Step for Extended { // ICE57 wrongly complains about the shortcuts cmd.arg("-sice:ICE57"); - build.run(&mut cmd); + builder.run(&mut cmd); - if !build.config.dry_run { - t!(fs::rename(exe.join(&filename), distdir(build).join(&filename))); + if !builder.config.dry_run { + t!(fs::rename(exe.join(&filename), distdir(builder).join(&filename))); } } } } -fn add_env(build: &Build, cmd: &mut Command, target: Interned<String>) { +fn add_env(builder: &Builder, cmd: &mut Command, target: Interned<String>) { let mut parts = channel::CFG_RELEASE_NUM.split('.'); - cmd.env("CFG_RELEASE_INFO", build.rust_version()) + cmd.env("CFG_RELEASE_INFO", builder.rust_version()) .env("CFG_RELEASE_NUM", channel::CFG_RELEASE_NUM) - .env("CFG_RELEASE", build.rust_release()) + .env("CFG_RELEASE", builder.rust_release()) .env("CFG_VER_MAJOR", parts.next().unwrap()) .env("CFG_VER_MINOR", parts.next().unwrap()) .env("CFG_VER_PATCH", parts.next().unwrap()) .env("CFG_VER_BUILD", "0") // just needed to build - .env("CFG_PACKAGE_VERS", build.rust_package_vers()) - .env("CFG_PACKAGE_NAME", pkgname(build, "rust")) + .env("CFG_PACKAGE_VERS", builder.rust_package_vers()) + .env("CFG_PACKAGE_NAME", pkgname(builder, "rust")) .env("CFG_BUILD", target) - .env("CFG_CHANNEL", &build.config.channel); + .env("CFG_CHANNEL", &builder.config.channel); if target.contains("windows-gnu") { cmd.env("CFG_MINGW", "1") @@ -1722,18 +1710,17 @@ impl Step for HashSign { } fn run(self, builder: &Builder) { - let build = builder.build; let mut cmd = builder.tool_cmd(Tool::BuildManifest); - if build.config.dry_run { + if builder.config.dry_run { return; } - let sign = build.config.dist_sign_folder.as_ref().unwrap_or_else(|| { + let sign = builder.config.dist_sign_folder.as_ref().unwrap_or_else(|| { panic!("\n\nfailed to specify `dist.sign-folder` in `config.toml`\n\n") }); - let addr = build.config.dist_upload_addr.as_ref().unwrap_or_else(|| { + let addr = builder.config.dist_upload_addr.as_ref().unwrap_or_else(|| { panic!("\n\nfailed to specify `dist.upload-addr` in `config.toml`\n\n") }); - let file = build.config.dist_gpg_password_file.as_ref().unwrap_or_else(|| { + let file = builder.config.dist_gpg_password_file.as_ref().unwrap_or_else(|| { panic!("\n\nfailed to specify `dist.gpg-password-file` in `config.toml`\n\n") }); let mut pass = String::new(); @@ -1742,15 +1729,15 @@ impl Step for HashSign { let today = output(Command::new("date").arg("+%Y-%m-%d")); cmd.arg(sign); - cmd.arg(distdir(build)); + cmd.arg(distdir(builder)); cmd.arg(today.trim()); - cmd.arg(build.rust_package_vers()); - cmd.arg(build.package_vers(&build.release_num("cargo"))); - cmd.arg(build.package_vers(&build.release_num("rls"))); - cmd.arg(build.package_vers(&build.release_num("rustfmt"))); + cmd.arg(builder.rust_package_vers()); + cmd.arg(builder.package_vers(&builder.release_num("cargo"))); + cmd.arg(builder.package_vers(&builder.release_num("rls"))); + cmd.arg(builder.package_vers(&builder.release_num("rustfmt"))); cmd.arg(addr); - build.create_dir(&distdir(build)); + builder.create_dir(&distdir(builder)); let mut child = t!(cmd.stdin(Stdio::piped()).spawn()); t!(child.stdin.take().unwrap().write_all(pass.as_bytes())); diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 620e125a43d..16f4b29dcce 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Documentation generation for rustbuild. +//! Documentation generation for rustbuilder. //! //! This module implements generation for all bits and pieces of documentation //! for the Rust project. This notably includes suites like the rust book, the @@ -23,7 +23,7 @@ use std::io::prelude::*; use std::io; use std::path::{PathBuf, Path}; -use {Build, Mode}; +use Mode; use build_helper::up_to_date; use util::symlink_dir; @@ -47,7 +47,7 @@ macro_rules! book { fn should_run(run: ShouldRun) -> ShouldRun { let builder = run.builder; - run.path($path).default_condition(builder.build.config.docs) + run.path($path).default_condition(builder.config.docs) } fn make_run(run: RunConfig) { @@ -71,6 +71,7 @@ book!( Nomicon, "src/doc/nomicon", "nomicon"; Reference, "src/doc/reference", "reference"; Rustdoc, "src/doc/rustdoc", "rustdoc"; + RustcBook, "src/doc/rustc", "rustc"; RustByExample, "src/doc/rust-by-example", "rust-by-example"; ); @@ -94,7 +95,7 @@ impl Step for Rustbook { /// This will not actually generate any documentation if the documentation has /// already been generated. fn run(self, builder: &Builder) { - let src = builder.build.src.join("src/doc"); + let src = builder.src.join("src/doc"); builder.ensure(RustbookSrc { target: self.target, name: self.name, @@ -114,7 +115,7 @@ impl Step for UnstableBook { fn should_run(run: ShouldRun) -> ShouldRun { let builder = run.builder; - run.path("src/doc/unstable-book").default_condition(builder.build.config.docs) + run.path("src/doc/unstable-book").default_condition(builder.config.docs) } fn make_run(run: RunConfig) { @@ -130,7 +131,7 @@ impl Step for UnstableBook { builder.ensure(RustbookSrc { target: self.target, name: INTERNER.intern_str("unstable-book"), - src: builder.build.md_doc_out(self.target), + src: builder.md_doc_out(self.target), }) } } @@ -147,7 +148,7 @@ impl Step for CargoBook { fn should_run(run: ShouldRun) -> ShouldRun { let builder = run.builder; - run.path("src/tools/cargo/src/doc/book").default_condition(builder.build.config.docs) + run.path("src/tools/cargo/src/doc/book").default_condition(builder.config.docs) } fn make_run(run: RunConfig) { @@ -158,22 +159,20 @@ impl Step for CargoBook { } fn run(self, builder: &Builder) { - let build = builder.build; - let target = self.target; let name = self.name; - let src = build.src.join("src/tools/cargo/src/doc"); + let src = builder.src.join("src/tools/cargo/src/doc"); - let out = build.doc_out(target); + let out = builder.doc_out(target); t!(fs::create_dir_all(&out)); let out = out.join(name); - build.info(&format!("Cargo Book ({}) - {}", target, name)); + builder.info(&format!("Cargo Book ({}) - {}", target, name)); let _ = fs::remove_dir_all(&out); - build.run(builder.tool_cmd(Tool::Rustbook) + builder.run(builder.tool_cmd(Tool::Rustbook) .arg("build") .arg(&src) .arg("-d") @@ -200,11 +199,10 @@ impl Step for RustbookSrc { /// This will not actually generate any documentation if the documentation has /// already been generated. fn run(self, builder: &Builder) { - let build = builder.build; let target = self.target; let name = self.name; let src = self.src; - let out = build.doc_out(target); + let out = builder.doc_out(target); t!(fs::create_dir_all(&out)); let out = out.join(name); @@ -215,9 +213,9 @@ impl Step for RustbookSrc { if up_to_date(&src, &index) && up_to_date(&rustbook, &index) { return } - build.info(&format!("Rustbook ({}) - {}", target, name)); + builder.info(&format!("Rustbook ({}) - {}", target, name)); let _ = fs::remove_dir_all(&out); - build.run(rustbook_cmd + builder.run(rustbook_cmd .arg("build") .arg(&src) .arg("-d") @@ -238,12 +236,12 @@ impl Step for TheBook { fn should_run(run: ShouldRun) -> ShouldRun { let builder = run.builder; - run.path("src/doc/book").default_condition(builder.build.config.docs) + run.path("src/doc/book").default_condition(builder.config.docs) } fn make_run(run: RunConfig) { run.builder.ensure(TheBook { - compiler: run.builder.compiler(run.builder.top_stage, run.builder.build.build), + compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build), target: run.target, name: "book", }); @@ -259,7 +257,6 @@ impl Step for TheBook { /// * Index page /// * Redirect pages fn run(self, builder: &Builder) { - let build = builder.build; let compiler = self.compiler; let target = self.target; let name = self.name; @@ -283,12 +280,12 @@ impl Step for TheBook { // build the index page let index = format!("{}/index.md", name); - build.info(&format!("Documenting book index ({})", target)); + builder.info(&format!("Documenting book index ({})", target)); invoke_rustdoc(builder, compiler, target, &index); // build the redirect pages - build.info(&format!("Documenting book redirect pages ({})", target)); - for file in t!(fs::read_dir(build.src.join("src/doc/book/redirects"))) { + builder.info(&format!("Documenting book redirect pages ({})", target)); + for file in t!(fs::read_dir(builder.src.join("src/doc/book/redirects"))) { let file = t!(file); let path = file.path(); let path = path.to_str().unwrap(); @@ -299,13 +296,12 @@ impl Step for TheBook { } fn invoke_rustdoc(builder: &Builder, compiler: Compiler, target: Interned<String>, markdown: &str) { - let build = builder.build; - let out = build.doc_out(target); + let out = builder.doc_out(target); - let path = build.src.join("src/doc").join(markdown); + let path = builder.src.join("src/doc").join(markdown); - let favicon = build.src.join("src/doc/favicon.inc"); - let footer = build.src.join("src/doc/footer.inc"); + let favicon = builder.src.join("src/doc/favicon.inc"); + let footer = builder.src.join("src/doc/footer.inc"); let version_info = out.join("version_info.html"); let mut cmd = builder.rustdoc_cmd(compiler.host); @@ -323,7 +319,7 @@ fn invoke_rustdoc(builder: &Builder, compiler: Compiler, target: Interned<String .arg("--markdown-css") .arg("../rust.css"); - build.run(&mut cmd); + builder.run(&mut cmd); } #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] @@ -338,12 +334,12 @@ impl Step for Standalone { fn should_run(run: ShouldRun) -> ShouldRun { let builder = run.builder; - run.path("src/doc").default_condition(builder.build.config.docs) + run.path("src/doc").default_condition(builder.config.docs) } fn make_run(run: RunConfig) { run.builder.ensure(Standalone { - compiler: run.builder.compiler(run.builder.top_stage, run.builder.build.build), + compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build), target: run.target, }); } @@ -357,31 +353,30 @@ impl Step for Standalone { /// /// In the end, this is just a glorified wrapper around rustdoc! fn run(self, builder: &Builder) { - let build = builder.build; let target = self.target; let compiler = self.compiler; - build.info(&format!("Documenting standalone ({})", target)); - let out = build.doc_out(target); + builder.info(&format!("Documenting standalone ({})", target)); + let out = builder.doc_out(target); t!(fs::create_dir_all(&out)); - let favicon = build.src.join("src/doc/favicon.inc"); - let footer = build.src.join("src/doc/footer.inc"); - let full_toc = build.src.join("src/doc/full-toc.inc"); - t!(fs::copy(build.src.join("src/doc/rust.css"), out.join("rust.css"))); + let favicon = builder.src.join("src/doc/favicon.inc"); + let footer = builder.src.join("src/doc/footer.inc"); + let full_toc = builder.src.join("src/doc/full-toc.inc"); + t!(fs::copy(builder.src.join("src/doc/rust.css"), out.join("rust.css"))); - let version_input = build.src.join("src/doc/version_info.html.template"); + let version_input = builder.src.join("src/doc/version_info.html.template"); let version_info = out.join("version_info.html"); - if !build.config.dry_run && !up_to_date(&version_input, &version_info) { + if !builder.config.dry_run && !up_to_date(&version_input, &version_info) { let mut info = String::new(); t!(t!(File::open(&version_input)).read_to_string(&mut info)); - let info = info.replace("VERSION", &build.rust_release()) - .replace("SHORT_HASH", build.rust_info.sha_short().unwrap_or("")) - .replace("STAMP", build.rust_info.sha().unwrap_or("")); + let info = info.replace("VERSION", &builder.rust_release()) + .replace("SHORT_HASH", builder.rust_info.sha_short().unwrap_or("")) + .replace("STAMP", builder.rust_info.sha().unwrap_or("")); t!(t!(File::create(&version_info)).write_all(info.as_bytes())); } - for file in t!(fs::read_dir(build.src.join("src/doc"))) { + for file in t!(fs::read_dir(builder.src.join("src/doc"))) { let file = t!(file); let path = file.path(); let filename = path.file_name().unwrap().to_str().unwrap(); @@ -396,7 +391,7 @@ impl Step for Standalone { up_to_date(&favicon, &html) && up_to_date(&full_toc, &html) && up_to_date(&version_info, &html) && - (build.config.dry_run || up_to_date(&rustdoc, &html)) { + (builder.config.dry_run || up_to_date(&rustdoc, &html)) { continue } @@ -416,7 +411,7 @@ impl Step for Standalone { } else { cmd.arg("--markdown-css").arg("rust.css"); } - build.run(&mut cmd); + builder.run(&mut cmd); } } } @@ -433,7 +428,7 @@ impl Step for Std { fn should_run(run: ShouldRun) -> ShouldRun { let builder = run.builder; - run.all_krates("std").default_condition(builder.build.config.docs) + run.all_krates("std").default_condition(builder.config.docs) } fn make_run(run: RunConfig) { @@ -448,22 +443,21 @@ impl Step for Std { /// This will generate all documentation for the standard library and its /// dependencies. This is largely just a wrapper around `cargo doc`. fn run(self, builder: &Builder) { - let build = builder.build; let stage = self.stage; let target = self.target; - build.info(&format!("Documenting stage{} std ({})", stage, target)); - let out = build.doc_out(target); + builder.info(&format!("Documenting stage{} std ({})", stage, target)); + let out = builder.doc_out(target); t!(fs::create_dir_all(&out)); - let compiler = builder.compiler(stage, build.build); + let compiler = builder.compiler(stage, builder.config.build); let rustdoc = builder.rustdoc(compiler.host); - let compiler = if build.force_use_stage1(compiler, target) { + let compiler = if builder.force_use_stage1(compiler, target) { builder.compiler(1, compiler.host) } else { compiler }; builder.ensure(compile::Std { compiler, target }); - let out_dir = build.stage_out(compiler, Mode::Libstd) + let out_dir = builder.stage_out(compiler, Mode::Libstd) .join(target).join("doc"); // Here what we're doing is creating a *symlink* (directory junction on @@ -479,9 +473,9 @@ impl Step for Std { // // This way rustdoc generates output directly into the output, and rustdoc // will also directly handle merging. - let my_out = build.crate_doc_out(target); - build.clear_if_dirty(&my_out, &rustdoc); - t!(symlink_dir_force(&build.config, &my_out, &out_dir)); + let my_out = builder.crate_doc_out(target); + builder.clear_if_dirty(&my_out, &rustdoc); + t!(symlink_dir_force(&builder.config, &my_out, &out_dir)); let mut cargo = builder.cargo(compiler, Mode::Libstd, target, "doc"); compile::std_cargo(builder, &compiler, target, &mut cargo); @@ -497,8 +491,8 @@ impl Step for Std { t!(fs::create_dir_all(out_dir.join(krate))); } - build.run(&mut cargo); - build.cp_r(&my_out, &out); + builder.run(&mut cargo); + builder.cp_r(&my_out, &out); } } @@ -514,7 +508,7 @@ impl Step for Test { fn should_run(run: ShouldRun) -> ShouldRun { let builder = run.builder; - run.krate("test").default_condition(builder.build.config.docs) + run.krate("test").default_condition(builder.config.docs) } fn make_run(run: RunConfig) { @@ -529,15 +523,14 @@ impl Step for Test { /// This will generate all documentation for libtest and its dependencies. This /// is largely just a wrapper around `cargo doc`. fn run(self, builder: &Builder) { - let build = builder.build; let stage = self.stage; let target = self.target; - build.info(&format!("Documenting stage{} test ({})", stage, target)); - let out = build.doc_out(target); + builder.info(&format!("Documenting stage{} test ({})", stage, target)); + let out = builder.doc_out(target); t!(fs::create_dir_all(&out)); - let compiler = builder.compiler(stage, build.build); + let compiler = builder.compiler(stage, builder.config.build); let rustdoc = builder.rustdoc(compiler.host); - let compiler = if build.force_use_stage1(compiler, target) { + let compiler = if builder.force_use_stage1(compiler, target) { builder.compiler(1, compiler.host) } else { compiler @@ -547,21 +540,21 @@ impl Step for Test { builder.ensure(Std { stage, target }); builder.ensure(compile::Test { compiler, target }); - let out_dir = build.stage_out(compiler, Mode::Libtest) + let out_dir = builder.stage_out(compiler, Mode::Libtest) .join(target).join("doc"); // See docs in std above for why we symlink - let my_out = build.crate_doc_out(target); - build.clear_if_dirty(&my_out, &rustdoc); + let my_out = builder.crate_doc_out(target); + builder.clear_if_dirty(&my_out, &rustdoc); t!(symlink_dir_force(&builder.config, &my_out, &out_dir)); let mut cargo = builder.cargo(compiler, Mode::Libtest, target, "doc"); - compile::test_cargo(build, &compiler, target, &mut cargo); + compile::test_cargo(builder, &compiler, target, &mut cargo); cargo.arg("--no-deps").arg("-p").arg("test"); - build.run(&mut cargo); - build.cp_r(&my_out, &out); + builder.run(&mut cargo); + builder.cp_r(&my_out, &out); } } @@ -578,7 +571,7 @@ impl Step for WhitelistedRustc { fn should_run(run: ShouldRun) -> ShouldRun { let builder = run.builder; - run.krate("rustc-main").default_condition(builder.build.config.docs) + run.krate("rustc-main").default_condition(builder.config.docs) } fn make_run(run: RunConfig) { @@ -598,15 +591,14 @@ impl Step for WhitelistedRustc { /// here as we want to be able to keep it separate from the standard /// documentation. This is largely just a wrapper around `cargo doc`. fn run(self, builder: &Builder) { - let build = builder.build; let stage = self.stage; let target = self.target; - build.info(&format!("Documenting stage{} whitelisted compiler ({})", stage, target)); - let out = build.doc_out(target); + builder.info(&format!("Documenting stage{} whitelisted compiler ({})", stage, target)); + let out = builder.doc_out(target); t!(fs::create_dir_all(&out)); - let compiler = builder.compiler(stage, build.build); + let compiler = builder.compiler(stage, builder.config.build); let rustdoc = builder.rustdoc(compiler.host); - let compiler = if build.force_use_stage1(compiler, target) { + let compiler = if builder.force_use_stage1(compiler, target) { builder.compiler(1, compiler.host) } else { compiler @@ -616,16 +608,16 @@ impl Step for WhitelistedRustc { builder.ensure(Std { stage, target }); builder.ensure(compile::Rustc { compiler, target }); - let out_dir = build.stage_out(compiler, Mode::Librustc) + let out_dir = builder.stage_out(compiler, Mode::Librustc) .join(target).join("doc"); // See docs in std above for why we symlink - let my_out = build.crate_doc_out(target); - build.clear_if_dirty(&my_out, &rustdoc); + let my_out = builder.crate_doc_out(target); + builder.clear_if_dirty(&my_out, &rustdoc); t!(symlink_dir_force(&builder.config, &my_out, &out_dir)); let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "doc"); - compile::rustc_cargo(build, &mut cargo); + compile::rustc_cargo(builder, &mut cargo); // We don't want to build docs for internal compiler dependencies in this // step (there is another step for that). Therefore, we whitelist the crates @@ -635,8 +627,8 @@ impl Step for WhitelistedRustc { cargo.arg("-p").arg(krate); } - build.run(&mut cargo); - build.cp_r(&my_out, &out); + builder.run(&mut cargo); + builder.cp_r(&my_out, &out); } } @@ -653,7 +645,7 @@ impl Step for Rustc { fn should_run(run: ShouldRun) -> ShouldRun { let builder = run.builder; - run.krate("rustc-main").default_condition(builder.build.config.docs) + run.krate("rustc-main").default_condition(builder.config.docs) } fn make_run(run: RunConfig) { @@ -670,22 +662,21 @@ impl Step for Rustc { /// we do not merge it with the other documentation from std, test and /// proc_macros. This is largely just a wrapper around `cargo doc`. fn run(self, builder: &Builder) { - let build = builder.build; let stage = self.stage; let target = self.target; - build.info(&format!("Documenting stage{} compiler ({})", stage, target)); - let out = build.compiler_doc_out(target); + builder.info(&format!("Documenting stage{} compiler ({})", stage, target)); + let out = builder.compiler_doc_out(target); t!(fs::create_dir_all(&out)); - let compiler = builder.compiler(stage, build.build); + let compiler = builder.compiler(stage, builder.config.build); let rustdoc = builder.rustdoc(compiler.host); - let compiler = if build.force_use_stage1(compiler, target) { + let compiler = if builder.force_use_stage1(compiler, target) { builder.compiler(1, compiler.host) } else { compiler }; - if !build.config.compiler_docs { - build.info(&format!("\tskipping - compiler docs disabled")); + if !builder.config.compiler_docs { + builder.info(&format!("\tskipping - compiler docs disabled")); return; } @@ -693,16 +684,16 @@ impl Step for Rustc { builder.ensure(Std { stage, target }); builder.ensure(compile::Rustc { compiler, target }); - let out_dir = build.stage_out(compiler, Mode::Librustc) + let out_dir = builder.stage_out(compiler, Mode::Librustc) .join(target).join("doc"); // We do not symlink to the same shared folder that already contains std library // documentation from previous steps as we do not want to include that. - build.clear_if_dirty(&out, &rustdoc); + builder.clear_if_dirty(&out, &rustdoc); t!(symlink_dir_force(&builder.config, &out, &out_dir)); let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "doc"); cargo.env("RUSTDOCFLAGS", "--document-private-items"); - compile::rustc_cargo(build, &mut cargo); + compile::rustc_cargo(builder, &mut cargo); // Only include compiler crates, no dependencies of those, such as `libc`. cargo.arg("--no-deps"); @@ -711,19 +702,19 @@ impl Step for Rustc { let mut compiler_crates = HashSet::new(); for root_crate in &["rustc", "rustc_driver"] { let interned_root_crate = INTERNER.intern_str(root_crate); - find_compiler_crates(&build, &interned_root_crate, &mut compiler_crates); + find_compiler_crates(builder, &interned_root_crate, &mut compiler_crates); } for krate in &compiler_crates { cargo.arg("-p").arg(krate); } - build.run(&mut cargo); + builder.run(&mut cargo); } } fn find_compiler_crates( - build: &Build, + builder: &Builder, name: &Interned<String>, crates: &mut HashSet<Interned<String>> ) { @@ -731,9 +722,9 @@ fn find_compiler_crates( crates.insert(*name); // Look for dependencies. - for dep in build.crates.get(name).unwrap().deps.iter() { - if build.crates.get(dep).unwrap().is_local(build) { - find_compiler_crates(build, dep, crates); + for dep in builder.crates.get(name).unwrap().deps.iter() { + if builder.crates.get(dep).unwrap().is_local(builder) { + find_compiler_crates(builder, dep, crates); } } } @@ -750,7 +741,7 @@ impl Step for ErrorIndex { fn should_run(run: ShouldRun) -> ShouldRun { let builder = run.builder; - run.path("src/tools/error_index_generator").default_condition(builder.build.config.docs) + run.path("src/tools/error_index_generator").default_condition(builder.config.docs) } fn make_run(run: RunConfig) { @@ -762,21 +753,20 @@ impl Step for ErrorIndex { /// Generates the HTML rendered error-index by running the /// `error_index_generator` tool. fn run(self, builder: &Builder) { - let build = builder.build; let target = self.target; - build.info(&format!("Documenting error index ({})", target)); - let out = build.doc_out(target); + builder.info(&format!("Documenting error index ({})", target)); + let out = builder.doc_out(target); t!(fs::create_dir_all(&out)); let mut index = builder.tool_cmd(Tool::ErrorIndex); index.arg("html"); index.arg(out.join("error-index.html")); // FIXME: shouldn't have to pass this env var - index.env("CFG_BUILD", &build.build) - .env("RUSTC_ERROR_METADATA_DST", build.extended_error_dir()); + index.env("CFG_BUILD", &builder.config.build) + .env("RUSTC_ERROR_METADATA_DST", builder.extended_error_dir()); - build.run(&mut index); + builder.run(&mut index); } } @@ -792,7 +782,7 @@ impl Step for UnstableBookGen { fn should_run(run: ShouldRun) -> ShouldRun { let builder = run.builder; - run.path("src/tools/unstable-book-gen").default_condition(builder.build.config.docs) + run.path("src/tools/unstable-book-gen").default_condition(builder.config.docs) } fn make_run(run: RunConfig) { @@ -802,23 +792,22 @@ impl Step for UnstableBookGen { } fn run(self, builder: &Builder) { - let build = builder.build; let target = self.target; builder.ensure(compile::Std { - compiler: builder.compiler(builder.top_stage, build.build), + compiler: builder.compiler(builder.top_stage, builder.config.build), target, }); - build.info(&format!("Generating unstable book md files ({})", target)); - let out = build.md_doc_out(target).join("unstable-book"); - build.create_dir(&out); - build.remove_dir(&out); + builder.info(&format!("Generating unstable book md files ({})", target)); + let out = builder.md_doc_out(target).join("unstable-book"); + builder.create_dir(&out); + builder.remove_dir(&out); let mut cmd = builder.tool_cmd(Tool::UnstableBookGen); - cmd.arg(build.src.join("src")); + cmd.arg(builder.src.join("src")); cmd.arg(out); - build.run(&mut cmd); + builder.run(&mut cmd); } } diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs index d71fdb8a30c..b37a007e863 100644 --- a/src/bootstrap/install.rs +++ b/src/bootstrap/install.rs @@ -62,8 +62,7 @@ fn install_sh( stage: u32, host: Option<Interned<String>> ) { - let build = builder.build; - build.info(&format!("Install {} stage{} ({:?})", package, stage, host)); + builder.info(&format!("Install {} stage{} ({:?})", package, stage, host)); let prefix_default = PathBuf::from("/usr/local"); let sysconfdir_default = PathBuf::from("/etc"); @@ -72,15 +71,15 @@ fn install_sh( let bindir_default = PathBuf::from("bin"); let libdir_default = PathBuf::from("lib"); let mandir_default = datadir_default.join("man"); - let prefix = build.config.prefix.as_ref().map_or(prefix_default, |p| { + let prefix = builder.config.prefix.as_ref().map_or(prefix_default, |p| { fs::canonicalize(p).expect(&format!("could not canonicalize {}", p.display())) }); - let sysconfdir = build.config.sysconfdir.as_ref().unwrap_or(&sysconfdir_default); - let datadir = build.config.datadir.as_ref().unwrap_or(&datadir_default); - let docdir = build.config.docdir.as_ref().unwrap_or(&docdir_default); - let bindir = build.config.bindir.as_ref().unwrap_or(&bindir_default); - let libdir = build.config.libdir.as_ref().unwrap_or(&libdir_default); - let mandir = build.config.mandir.as_ref().unwrap_or(&mandir_default); + let sysconfdir = builder.config.sysconfdir.as_ref().unwrap_or(&sysconfdir_default); + let datadir = builder.config.datadir.as_ref().unwrap_or(&datadir_default); + let docdir = builder.config.docdir.as_ref().unwrap_or(&docdir_default); + let bindir = builder.config.bindir.as_ref().unwrap_or(&bindir_default); + let libdir = builder.config.libdir.as_ref().unwrap_or(&libdir_default); + let mandir = builder.config.mandir.as_ref().unwrap_or(&mandir_default); let sysconfdir = prefix.join(sysconfdir); let datadir = prefix.join(datadir); @@ -99,18 +98,18 @@ fn install_sh( let libdir = add_destdir(&libdir, &destdir); let mandir = add_destdir(&mandir, &destdir); - let empty_dir = build.out.join("tmp/empty_dir"); + let empty_dir = builder.out.join("tmp/empty_dir"); t!(fs::create_dir_all(&empty_dir)); let package_name = if let Some(host) = host { - format!("{}-{}", pkgname(build, name), host) + format!("{}-{}", pkgname(builder, name), host) } else { - pkgname(build, name) + pkgname(builder, name) }; let mut cmd = Command::new("sh"); cmd.current_dir(&empty_dir) - .arg(sanitize_sh(&tmpdir(build).join(&package_name).join("install.sh"))) + .arg(sanitize_sh(&tmpdir(builder).join(&package_name).join("install.sh"))) .arg(format!("--prefix={}", sanitize_sh(&prefix))) .arg(format!("--sysconfdir={}", sanitize_sh(&sysconfdir))) .arg(format!("--datadir={}", sanitize_sh(&datadir))) @@ -119,7 +118,7 @@ fn install_sh( .arg(format!("--libdir={}", sanitize_sh(&libdir))) .arg(format!("--mandir={}", sanitize_sh(&mandir))) .arg("--disable-ldconfig"); - build.run(&mut cmd); + builder.run(&mut cmd); t!(fs::remove_dir_all(&empty_dir)); } @@ -180,7 +179,7 @@ macro_rules! install { run.builder.ensure($name { stage: run.builder.top_stage, target: run.target, - host: run.builder.build.build, + host: run.builder.config.build, }); } @@ -197,7 +196,7 @@ install!((self, builder, _config), install_docs(builder, self.stage, self.target); }; Std, "src/libstd", true, only_hosts: true, { - for target in &builder.build.targets { + for target in &builder.targets { builder.ensure(dist::Std { compiler: builder.compiler(self.stage, self.host), target: *target diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index db5891afd6b..d952cb5bfc4 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -29,7 +29,6 @@ use build_helper::output; use cmake; use cc; -use Build; use util::{self, exe}; use build_helper::up_to_date; use builder::{Builder, RunConfig, ShouldRun, Step}; @@ -60,39 +59,38 @@ impl Step for Llvm { /// Compile LLVM for `target`. fn run(self, builder: &Builder) -> PathBuf { - let build = builder.build; let target = self.target; let emscripten = self.emscripten; // If we're using a custom LLVM bail out here, but we can only use a // custom LLVM for the build triple. if !self.emscripten { - if let Some(config) = build.config.target_config.get(&target) { + if let Some(config) = builder.config.target_config.get(&target) { if let Some(ref s) = config.llvm_config { - check_llvm_version(build, s); + check_llvm_version(builder, s); return s.to_path_buf() } } } - let rebuild_trigger = build.src.join("src/rustllvm/llvm-rebuild-trigger"); + let rebuild_trigger = builder.src.join("src/rustllvm/llvm-rebuild-trigger"); let mut rebuild_trigger_contents = String::new(); t!(t!(File::open(&rebuild_trigger)).read_to_string(&mut rebuild_trigger_contents)); let (out_dir, llvm_config_ret_dir) = if emscripten { - let dir = build.emscripten_llvm_out(target); + let dir = builder.emscripten_llvm_out(target); let config_dir = dir.join("bin"); (dir, config_dir) } else { - let mut dir = build.llvm_out(build.config.build); - if !build.config.build.contains("msvc") || build.config.ninja { + let mut dir = builder.llvm_out(builder.config.build); + if !builder.config.build.contains("msvc") || builder.config.ninja { dir.push("build"); } - (build.llvm_out(target), dir.join("bin")) + (builder.llvm_out(target), dir.join("bin")) }; let done_stamp = out_dir.join("llvm-finished-building"); let build_llvm_config = llvm_config_ret_dir - .join(exe("llvm-config", &*build.config.build)); + .join(exe("llvm-config", &*builder.config.build)); if done_stamp.exists() { let mut done_contents = String::new(); t!(t!(File::open(&done_stamp)).read_to_string(&mut done_contents)); @@ -104,17 +102,17 @@ impl Step for Llvm { } } - let _folder = build.fold_output(|| "llvm"); + let _folder = builder.fold_output(|| "llvm"); let descriptor = if emscripten { "Emscripten " } else { "" }; - build.info(&format!("Building {}LLVM for {}", descriptor, target)); - let _time = util::timeit(&build); + builder.info(&format!("Building {}LLVM for {}", descriptor, target)); + let _time = util::timeit(&builder); t!(fs::create_dir_all(&out_dir)); // http://llvm.org/docs/CMake.html let root = if self.emscripten { "src/llvm-emscripten" } else { "src/llvm" }; - let mut cfg = cmake::Config::new(build.src.join(root)); + let mut cfg = cmake::Config::new(builder.src.join(root)); - let profile = match (build.config.llvm_optimize, build.config.llvm_release_debuginfo) { + let profile = match (builder.config.llvm_optimize, builder.config.llvm_release_debuginfo) { (false, _) => "Debug", (true, false) => "Release", (true, true) => "RelWithDebInfo", @@ -125,7 +123,7 @@ impl Step for Llvm { let llvm_targets = if self.emscripten { "JSBackend" } else { - match build.config.llvm_targets { + match builder.config.llvm_targets { Some(ref s) => s, None => "X86;ARM;AArch64;Mips;PowerPC;SystemZ;MSP430;Sparc;NVPTX;Hexagon", } @@ -134,10 +132,10 @@ impl Step for Llvm { let llvm_exp_targets = if self.emscripten { "" } else { - &build.config.llvm_experimental_targets[..] + &builder.config.llvm_experimental_targets[..] }; - let assertions = if build.config.llvm_assertions {"ON"} else {"OFF"}; + let assertions = if builder.config.llvm_assertions {"ON"} else {"OFF"}; cfg.out_dir(&out_dir) .profile(profile) @@ -151,7 +149,8 @@ impl Step for Llvm { .define("WITH_POLLY", "OFF") .define("LLVM_ENABLE_TERMINFO", "OFF") .define("LLVM_ENABLE_LIBEDIT", "OFF") - .define("LLVM_PARALLEL_COMPILE_JOBS", build.jobs().to_string()) + .define("LLVM_ENABLE_LIBXML2", "OFF") + .define("LLVM_PARALLEL_COMPILE_JOBS", builder.jobs().to_string()) .define("LLVM_TARGET_ARCH", target.split('-').next().unwrap()) .define("LLVM_DEFAULT_TARGET_TRIPLE", target); @@ -183,22 +182,22 @@ impl Step for Llvm { cfg.define("LLVM_BUILD_32_BITS", "ON"); } - if let Some(num_linkers) = build.config.llvm_link_jobs { + if let Some(num_linkers) = builder.config.llvm_link_jobs { if num_linkers > 0 { cfg.define("LLVM_PARALLEL_LINK_JOBS", num_linkers.to_string()); } } // http://llvm.org/docs/HowToCrossCompileLLVM.html - if target != build.build && !emscripten { + if target != builder.config.build && !emscripten { builder.ensure(Llvm { - target: build.build, + target: builder.config.build, emscripten: false, }); // FIXME: if the llvm root for the build triple is overridden then we // should use llvm-tblgen from there, also should verify that it // actually exists most of the time in normal installs of LLVM. - let host = build.llvm_out(build.build).join("bin/llvm-tblgen"); + let host = builder.llvm_out(builder.config.build).join("bin/llvm-tblgen"); cfg.define("CMAKE_CROSSCOMPILING", "True") .define("LLVM_TABLEGEN", &host); @@ -208,10 +207,10 @@ impl Step for Llvm { cfg.define("CMAKE_SYSTEM_NAME", "FreeBSD"); } - cfg.define("LLVM_NATIVE_BUILD", build.llvm_out(build.build).join("build")); + cfg.define("LLVM_NATIVE_BUILD", builder.llvm_out(builder.config.build).join("build")); } - configure_cmake(build, target, &mut cfg, false); + configure_cmake(builder, target, &mut cfg, false); // FIXME: we don't actually need to build all LLVM tools and all LLVM // libraries here, e.g. we just want a few components and a few @@ -230,12 +229,12 @@ impl Step for Llvm { } } -fn check_llvm_version(build: &Build, llvm_config: &Path) { - if !build.config.llvm_version_check { +fn check_llvm_version(builder: &Builder, llvm_config: &Path) { + if !builder.config.llvm_version_check { return } - if build.config.dry_run { + if builder.config.dry_run { return; } @@ -251,15 +250,15 @@ fn check_llvm_version(build: &Build, llvm_config: &Path) { panic!("\n\nbad LLVM version: {}, need >=3.9\n\n", version) } -fn configure_cmake(build: &Build, +fn configure_cmake(builder: &Builder, target: Interned<String>, cfg: &mut cmake::Config, building_dist_binaries: bool) { - if build.config.ninja { + if builder.config.ninja { cfg.generator("Ninja"); } cfg.target(&target) - .host(&build.config.build); + .host(&builder.config.build); let sanitize_cc = |cc: &Path| { if target.contains("msvc") { @@ -272,29 +271,29 @@ fn configure_cmake(build: &Build, // MSVC with CMake uses msbuild by default which doesn't respect these // vars that we'd otherwise configure. In that case we just skip this // entirely. - if target.contains("msvc") && !build.config.ninja { + if target.contains("msvc") && !builder.config.ninja { return } - let cc = build.cc(target); - let cxx = build.cxx(target).unwrap(); + let cc = builder.cc(target); + let cxx = builder.cxx(target).unwrap(); // Handle msvc + ninja + ccache specially (this is what the bots use) if target.contains("msvc") && - build.config.ninja && - build.config.ccache.is_some() { + builder.config.ninja && + builder.config.ccache.is_some() { let mut cc = env::current_exe().expect("failed to get cwd"); cc.set_file_name("sccache-plus-cl.exe"); cfg.define("CMAKE_C_COMPILER", sanitize_cc(&cc)) .define("CMAKE_CXX_COMPILER", sanitize_cc(&cc)); cfg.env("SCCACHE_PATH", - build.config.ccache.as_ref().unwrap()) + builder.config.ccache.as_ref().unwrap()) .env("SCCACHE_TARGET", target); // If ccache is configured we inform the build a little differently hwo // to invoke ccache while also invoking our compilers. - } else if let Some(ref ccache) = build.config.ccache { + } else if let Some(ref ccache) = builder.config.ccache { cfg.define("CMAKE_C_COMPILER", ccache) .define("CMAKE_C_COMPILER_ARG1", sanitize_cc(cc)) .define("CMAKE_CXX_COMPILER", ccache) @@ -304,16 +303,16 @@ fn configure_cmake(build: &Build, .define("CMAKE_CXX_COMPILER", sanitize_cc(cxx)); } - cfg.build_arg("-j").build_arg(build.jobs().to_string()); - cfg.define("CMAKE_C_FLAGS", build.cflags(target).join(" ")); - let mut cxxflags = build.cflags(target).join(" "); + cfg.build_arg("-j").build_arg(builder.jobs().to_string()); + cfg.define("CMAKE_C_FLAGS", builder.cflags(target).join(" ")); + let mut cxxflags = builder.cflags(target).join(" "); if building_dist_binaries { - if build.config.llvm_static_stdcpp && !target.contains("windows") { + if builder.config.llvm_static_stdcpp && !target.contains("windows") { cxxflags.push_str(" -static-libstdc++"); } } cfg.define("CMAKE_CXX_FLAGS", cxxflags); - if let Some(ar) = build.ar(target) { + if let Some(ar) = builder.ar(target) { if ar.is_absolute() { // LLVM build breaks if `CMAKE_AR` is a relative path, for some reason it // tries to resolve this path in the LLVM build directory. @@ -349,26 +348,25 @@ impl Step for Lld { return PathBuf::from("lld-out-dir-test-gen"); } let target = self.target; - let build = builder.build; let llvm_config = builder.ensure(Llvm { target: self.target, emscripten: false, }); - let out_dir = build.lld_out(target); + let out_dir = builder.lld_out(target); let done_stamp = out_dir.join("lld-finished-building"); if done_stamp.exists() { return out_dir } - let _folder = build.fold_output(|| "lld"); - build.info(&format!("Building LLD for {}", target)); - let _time = util::timeit(&build); + let _folder = builder.fold_output(|| "lld"); + builder.info(&format!("Building LLD for {}", target)); + let _time = util::timeit(&builder); t!(fs::create_dir_all(&out_dir)); - let mut cfg = cmake::Config::new(build.src.join("src/tools/lld")); - configure_cmake(build, target, &mut cfg, true); + let mut cfg = cmake::Config::new(builder.src.join("src/tools/lld")); + configure_cmake(builder, target, &mut cfg, true); cfg.out_dir(&out_dir) .profile("Release") @@ -404,16 +402,15 @@ impl Step for TestHelpers { if builder.config.dry_run { return; } - let build = builder.build; let target = self.target; - let dst = build.test_helpers_out(target); - let src = build.src.join("src/test/auxiliary/rust_test_helpers.c"); + let dst = builder.test_helpers_out(target); + let src = builder.src.join("src/test/auxiliary/rust_test_helpers.c"); if up_to_date(&src, &dst.join("librust_test_helpers.a")) { return } - let _folder = build.fold_output(|| "build_test_helpers"); - build.info(&format!("Building test helpers")); + let _folder = builder.fold_output(|| "build_test_helpers"); + builder.info(&format!("Building test helpers")); t!(fs::create_dir_all(&dst)); let mut cfg = cc::Build::new(); @@ -421,20 +418,20 @@ impl Step for TestHelpers { // extra configuration, so inform gcc of these compilers. Note, though, that // on MSVC we still need gcc's detection of env vars (ugh). if !target.contains("msvc") { - if let Some(ar) = build.ar(target) { + if let Some(ar) = builder.ar(target) { cfg.archiver(ar); } - cfg.compiler(build.cc(target)); + cfg.compiler(builder.cc(target)); } cfg.cargo_metadata(false) .out_dir(&dst) .target(&target) - .host(&build.build) + .host(&builder.config.build) .opt_level(0) .warnings(false) .debug(false) - .file(build.src.join("src/test/auxiliary/rust_test_helpers.c")) + .file(builder.src.join("src/test/auxiliary/rust_test_helpers.c")) .compile("rust_test_helpers"); } } @@ -459,9 +456,8 @@ impl Step for Openssl { if builder.config.dry_run { return; } - let build = builder.build; let target = self.target; - let out = match build.openssl_dir(target) { + let out = match builder.openssl_dir(target) { Some(dir) => dir, None => return, }; @@ -497,7 +493,8 @@ impl Step for Openssl { } // Ensure the hash is correct. - let mut shasum = if target.contains("apple") || build.build.contains("netbsd") { + let mut shasum = if target.contains("apple") || + builder.config.build.contains("netbsd") { let mut cmd = Command::new("shasum"); cmd.arg("-a").arg("256"); cmd @@ -530,10 +527,10 @@ impl Step for Openssl { t!(fs::rename(&tmp, &tarball)); } let obj = out.join(format!("openssl-{}", OPENSSL_VERS)); - let dst = build.openssl_install_dir(target).unwrap(); + let dst = builder.openssl_install_dir(target).unwrap(); drop(fs::remove_dir_all(&obj)); drop(fs::remove_dir_all(&dst)); - build.run(Command::new("tar").arg("zxf").arg(&tarball).current_dir(&out)); + builder.run(Command::new("tar").arg("zxf").arg(&tarball).current_dir(&out)); let mut configure = Command::new("perl"); configure.arg(obj.join("Configure")); @@ -583,8 +580,8 @@ impl Step for Openssl { _ => panic!("don't know how to configure OpenSSL for {}", target), }; configure.arg(os); - configure.env("CC", build.cc(target)); - for flag in build.cflags(target) { + configure.env("CC", builder.cc(target)); + for flag in builder.cflags(target) { configure.arg(flag); } // There is no specific os target for android aarch64 or x86_64, @@ -596,7 +593,7 @@ impl Step for Openssl { if target == "sparc64-unknown-netbsd" { // Need -m64 to get assembly generated correctly for sparc64. configure.arg("-m64"); - if build.build.contains("netbsd") { + if builder.config.build.contains("netbsd") { // Disable sparc64 asm on NetBSD builders, it uses // m4(1)'s -B flag, which NetBSD m4 does not support. configure.arg("no-asm"); @@ -609,12 +606,12 @@ impl Step for Openssl { configure.arg("no-asm"); } configure.current_dir(&obj); - build.info(&format!("Configuring openssl for {}", target)); - build.run_quiet(&mut configure); - build.info(&format!("Building openssl for {}", target)); - build.run_quiet(Command::new("make").arg("-j1").current_dir(&obj)); - build.info(&format!("Installing openssl for {}", target)); - build.run_quiet(Command::new("make").arg("install").arg("-j1").current_dir(&obj)); + builder.info(&format!("Configuring openssl for {}", target)); + builder.run_quiet(&mut configure); + builder.info(&format!("Building openssl for {}", target)); + builder.run_quiet(Command::new("make").arg("-j1").current_dir(&obj)); + builder.info(&format!("Installing openssl for {}", target)); + builder.run_quiet(Command::new("make").arg("install").arg("-j1").current_dir(&obj)); let mut f = t!(File::create(&stamp)); t!(f.write_all(OPENSSL_VERS.as_bytes())); diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index e6af4202c19..e8c40dfdb0a 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -32,7 +32,7 @@ use dist; use native; use tool::{self, Tool}; use util::{self, dylib_path, dylib_path_var}; -use {Build, Mode}; +use Mode; use toolstate::ToolState; const ADB_TEST_DIR: &str = "/data/tmp/work"; @@ -65,28 +65,28 @@ impl fmt::Display for TestKind { } } -fn try_run(build: &Build, cmd: &mut Command) -> bool { - if !build.fail_fast { - if !build.try_run(cmd) { - let mut failures = build.delayed_failures.borrow_mut(); +fn try_run(builder: &Builder, cmd: &mut Command) -> bool { + if !builder.fail_fast { + if !builder.try_run(cmd) { + let mut failures = builder.delayed_failures.borrow_mut(); failures.push(format!("{:?}", cmd)); return false; } } else { - build.run(cmd); + builder.run(cmd); } true } -fn try_run_quiet(build: &Build, cmd: &mut Command) -> bool { - if !build.fail_fast { - if !build.try_run_quiet(cmd) { - let mut failures = build.delayed_failures.borrow_mut(); +fn try_run_quiet(builder: &Builder, cmd: &mut Command) -> bool { + if !builder.fail_fast { + if !builder.try_run_quiet(cmd) { + let mut failures = builder.delayed_failures.borrow_mut(); failures.push(format!("{:?}", cmd)); return false; } } else { - build.run_quiet(cmd); + builder.run_quiet(cmd); } true } @@ -106,21 +106,20 @@ impl Step for Linkcheck { /// This tool in `src/tools` will verify the validity of all our links in the /// documentation to ensure we don't have a bunch of dead ones. fn run(self, builder: &Builder) { - let build = builder.build; let host = self.host; - build.info(&format!("Linkcheck ({})", host)); + builder.info(&format!("Linkcheck ({})", host)); builder.default_doc(None); - let _time = util::timeit(&build); - try_run(build, builder.tool_cmd(Tool::Linkchecker) - .arg(build.out.join(host).join("doc"))); + let _time = util::timeit(&builder); + try_run(builder, builder.tool_cmd(Tool::Linkchecker) + .arg(builder.out.join(host).join("doc"))); } fn should_run(run: ShouldRun) -> ShouldRun { let builder = run.builder; - run.path("src/tools/linkchecker").default_condition(builder.build.config.docs) + run.path("src/tools/linkchecker").default_condition(builder.config.docs) } fn make_run(run: RunConfig) { @@ -154,19 +153,18 @@ impl Step for Cargotest { /// This tool in `src/tools` will check out a few Rust projects and run `cargo /// test` to ensure that we don't regress the test suites there. fn run(self, builder: &Builder) { - let build = builder.build; let compiler = builder.compiler(self.stage, self.host); builder.ensure(compile::Rustc { compiler, target: compiler.host }); // Note that this is a short, cryptic, and not scoped directory name. This // is currently to minimize the length of path on Windows where we otherwise // quickly run into path name limit constraints. - let out_dir = build.out.join("ct"); + let out_dir = builder.out.join("ct"); t!(fs::create_dir_all(&out_dir)); - let _time = util::timeit(&build); + let _time = util::timeit(&builder); let mut cmd = builder.tool_cmd(Tool::CargoTest); - try_run(build, cmd.arg(&build.initial_cargo) + try_run(builder, cmd.arg(&builder.initial_cargo) .arg(&out_dir) .env("RUSTC", builder.rustc(compiler)) .env("RUSTDOC", builder.rustdoc(compiler.host))); @@ -196,13 +194,12 @@ impl Step for Cargo { /// Runs `cargo test` for `cargo` packaged with Rust. fn run(self, builder: &Builder) { - let build = builder.build; let compiler = builder.compiler(self.stage, self.host); builder.ensure(tool::Cargo { compiler, target: self.host }); let mut cargo = builder.cargo(compiler, Mode::Tool, self.host, "test"); - cargo.arg("--manifest-path").arg(build.src.join("src/tools/cargo/Cargo.toml")); - if !build.fail_fast { + cargo.arg("--manifest-path").arg(builder.src.join("src/tools/cargo/Cargo.toml")); + if !builder.fail_fast { cargo.arg("--no-fail-fast"); } @@ -213,7 +210,7 @@ impl Step for Cargo { // available. cargo.env("CFG_DISABLE_CROSS_TESTS", "1"); - try_run(build, cargo.env("PATH", &path_for_cargo(builder, compiler))); + try_run(builder, cargo.env("PATH", &path_for_cargo(builder, compiler))); } } @@ -240,12 +237,20 @@ impl Step for Rls { /// Runs `cargo test` for the rls. fn run(self, builder: &Builder) { - let build = builder.build; let stage = self.stage; let host = self.host; let compiler = builder.compiler(stage, host); - builder.ensure(tool::Rls { compiler, target: self.host, extra_features: Vec::new() }); + let build_result = builder.ensure(tool::Rls { + compiler, + target: self.host, + extra_features: Vec::new(), + }); + if build_result.is_none() { + eprintln!("failed to test rls: could not build"); + return; + } + let mut cargo = tool::prepare_tool_cargo(builder, compiler, host, @@ -257,8 +262,8 @@ impl Step for Rls { builder.add_rustc_lib_path(compiler, &mut cargo); - if try_run(build, &mut cargo) { - build.save_toolstate("rls", ToolState::TestPass); + if try_run(builder, &mut cargo) { + builder.save_toolstate("rls", ToolState::TestPass); } } } @@ -286,12 +291,20 @@ impl Step for Rustfmt { /// Runs `cargo test` for rustfmt. fn run(self, builder: &Builder) { - let build = builder.build; let stage = self.stage; let host = self.host; let compiler = builder.compiler(stage, host); - builder.ensure(tool::Rustfmt { compiler, target: self.host, extra_features: Vec::new() }); + let build_result = builder.ensure(tool::Rustfmt { + compiler, + target: self.host, + extra_features: Vec::new(), + }); + if build_result.is_none() { + eprintln!("failed to test rustfmt: could not build"); + return; + } + let mut cargo = tool::prepare_tool_cargo(builder, compiler, host, @@ -303,8 +316,8 @@ impl Step for Rustfmt { builder.add_rustc_lib_path(compiler, &mut cargo); - if try_run(build, &mut cargo) { - build.save_toolstate("rustfmt", ToolState::TestPass); + if try_run(builder, &mut cargo) { + builder.save_toolstate("rustfmt", ToolState::TestPass); } } } @@ -321,7 +334,7 @@ impl Step for Miri { const DEFAULT: bool = true; fn should_run(run: ShouldRun) -> ShouldRun { - let test_miri = run.builder.build.config.test_miri; + let test_miri = run.builder.config.test_miri; run.path("src/tools/miri").default_condition(test_miri) } @@ -334,7 +347,6 @@ impl Step for Miri { /// Runs `cargo test` for miri. fn run(self, builder: &Builder) { - let build = builder.build; let stage = self.stage; let host = self.host; let compiler = builder.compiler(stage, host); @@ -346,7 +358,7 @@ impl Step for Miri { }); if let Some(miri) = miri { let mut cargo = builder.cargo(compiler, Mode::Tool, host, "test"); - cargo.arg("--manifest-path").arg(build.src.join("src/tools/miri/Cargo.toml")); + cargo.arg("--manifest-path").arg(builder.src.join("src/tools/miri/Cargo.toml")); // Don't build tests dynamically, just a pain to work with cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1"); @@ -358,8 +370,8 @@ impl Step for Miri { builder.add_rustc_lib_path(compiler, &mut cargo); - if try_run(build, &mut cargo) { - build.save_toolstate("miri", ToolState::TestPass); + if try_run(builder, &mut cargo) { + builder.save_toolstate("miri", ToolState::TestPass); } } else { eprintln!("failed to test miri: could not build"); @@ -391,7 +403,6 @@ impl Step for Clippy { /// Runs `cargo test` for clippy. fn run(self, builder: &Builder) { - let build = builder.build; let stage = self.stage; let host = self.host; let compiler = builder.compiler(stage, host); @@ -403,7 +414,7 @@ impl Step for Clippy { }); if let Some(clippy) = clippy { let mut cargo = builder.cargo(compiler, Mode::Tool, host, "test"); - cargo.arg("--manifest-path").arg(build.src.join("src/tools/clippy/Cargo.toml")); + cargo.arg("--manifest-path").arg(builder.src.join("src/tools/clippy/Cargo.toml")); // Don't build tests dynamically, just a pain to work with cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1"); @@ -418,8 +429,8 @@ impl Step for Clippy { builder.add_rustc_lib_path(compiler, &mut cargo); - if try_run(build, &mut cargo) { - build.save_toolstate("clippy-driver", ToolState::TestPass); + if try_run(builder, &mut cargo) { + builder.save_toolstate("clippy-driver", ToolState::TestPass); } } else { eprintln!("failed to test clippy: could not build"); @@ -466,14 +477,14 @@ impl Step for RustdocTheme { .env("RUSTC_STAGE", self.compiler.stage.to_string()) .env("RUSTC_SYSROOT", builder.sysroot(self.compiler)) .env("RUSTDOC_LIBDIR", builder.sysroot_libdir(self.compiler, self.compiler.host)) - .env("CFG_RELEASE_CHANNEL", &builder.build.config.channel) + .env("CFG_RELEASE_CHANNEL", &builder.config.channel) .env("RUSTDOC_REAL", builder.rustdoc(self.compiler.host)) - .env("RUSTDOC_CRATE_VERSION", builder.build.rust_version()) + .env("RUSTDOC_CRATE_VERSION", builder.rust_version()) .env("RUSTC_BOOTSTRAP", "1"); - if let Some(linker) = builder.build.linker(self.compiler.host) { + if let Some(linker) = builder.linker(self.compiler.host) { cmd.env("RUSTC_TARGET_LINKER", linker); } - try_run(builder.build, &mut cmd); + try_run(builder, &mut cmd); } } @@ -545,6 +556,7 @@ impl Step for RustdocUi { target: self.target, mode: "ui", suite: "rustdoc-ui", + compare_mode: None, }) } } @@ -563,21 +575,19 @@ impl Step for Tidy { /// otherwise just implements a few lint-like checks that are specific to the /// compiler itself. fn run(self, builder: &Builder) { - let build = builder.build; - let mut cmd = builder.tool_cmd(Tool::Tidy); - cmd.arg(build.src.join("src")); - cmd.arg(&build.initial_cargo); - if !build.config.vendor { + cmd.arg(builder.src.join("src")); + cmd.arg(&builder.initial_cargo); + if !builder.config.vendor { cmd.arg("--no-vendor"); } - if build.config.quiet_tests { + if builder.config.quiet_tests { cmd.arg("--quiet"); } - let _folder = build.fold_output(|| "tidy"); + let _folder = builder.fold_output(|| "tidy"); builder.info(&format!("tidy check")); - try_run(build, &mut cmd); + try_run(builder, &mut cmd); } fn should_run(run: ShouldRun) -> ShouldRun { @@ -589,8 +599,8 @@ impl Step for Tidy { } } -fn testdir(build: &Build, host: Interned<String>) -> PathBuf { - build.out.join(host).join("test") +fn testdir(builder: &Builder, host: Interned<String>) -> PathBuf { + builder.out.join(host).join("test") } macro_rules! default_test { @@ -599,6 +609,14 @@ macro_rules! default_test { } } +macro_rules! default_test_with_compare_mode { + ($name:ident { path: $path:expr, mode: $mode:expr, suite: $suite:expr, + compare_mode: $compare_mode:expr }) => { + test_with_compare_mode!($name { path: $path, mode: $mode, suite: $suite, default: true, + host: false, compare_mode: $compare_mode }); + } +} + macro_rules! host_test { ($name:ident { path: $path:expr, mode: $mode:expr, suite: $suite:expr }) => { test!($name { path: $path, mode: $mode, suite: $suite, default: true, host: true }); @@ -606,12 +624,29 @@ macro_rules! host_test { } macro_rules! test { + ($name:ident { path: $path:expr, mode: $mode:expr, suite: $suite:expr, default: $default:expr, + host: $host:expr }) => { + test_definitions!($name { path: $path, mode: $mode, suite: $suite, default: $default, + host: $host, compare_mode: None }); + } +} + +macro_rules! test_with_compare_mode { + ($name:ident { path: $path:expr, mode: $mode:expr, suite: $suite:expr, default: $default:expr, + host: $host:expr, compare_mode: $compare_mode:expr }) => { + test_definitions!($name { path: $path, mode: $mode, suite: $suite, default: $default, + host: $host, compare_mode: Some($compare_mode) }); + } +} + +macro_rules! test_definitions { ($name:ident { path: $path:expr, mode: $mode:expr, suite: $suite:expr, default: $default:expr, - host: $host:expr + host: $host:expr, + compare_mode: $compare_mode:expr }) => { #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct $name { @@ -643,16 +678,18 @@ macro_rules! test { target: self.target, mode: $mode, suite: $suite, + compare_mode: $compare_mode, }) } } } } -default_test!(Ui { +default_test_with_compare_mode!(Ui { path: "src/test/ui", mode: "ui", - suite: "ui" + suite: "ui", + compare_mode: "nll" }); default_test!(RunPass { @@ -813,6 +850,7 @@ struct Compiletest { target: Interned<String>, mode: &'static str, suite: &'static str, + compare_mode: Option<&'static str>, } impl Step for Compiletest { @@ -828,25 +866,25 @@ impl Step for Compiletest { /// compiletest `mode` and `suite` arguments. For example `mode` can be /// "run-pass" or `suite` can be something like `debuginfo`. fn run(self, builder: &Builder) { - let build = builder.build; let compiler = self.compiler; let target = self.target; let mode = self.mode; let suite = self.suite; + let compare_mode = self.compare_mode; // Skip codegen tests if they aren't enabled in configuration. - if !build.config.codegen_tests && suite == "codegen" { + if !builder.config.codegen_tests && suite == "codegen" { return; } if suite == "debuginfo" { // Skip debuginfo tests on MSVC - if build.build.contains("msvc") { + if builder.config.build.contains("msvc") { return; } if mode == "debuginfo-XXX" { - return if build.build.contains("apple") { + return if builder.config.build.contains("apple") { builder.ensure(Compiletest { mode: "debuginfo-lldb", ..self @@ -895,15 +933,15 @@ impl Step for Compiletest { cmd.arg("--rustdoc-path").arg(builder.rustdoc(compiler.host)); } - cmd.arg("--src-base").arg(build.src.join("src/test").join(suite)); - cmd.arg("--build-base").arg(testdir(build, compiler.host).join(suite)); + cmd.arg("--src-base").arg(builder.src.join("src/test").join(suite)); + cmd.arg("--build-base").arg(testdir(builder, compiler.host).join(suite)); cmd.arg("--stage-id").arg(format!("stage{}-{}", compiler.stage, target)); cmd.arg("--mode").arg(mode); cmd.arg("--target").arg(target); cmd.arg("--host").arg(&*compiler.host); - cmd.arg("--llvm-filecheck").arg(build.llvm_filecheck(build.build)); + cmd.arg("--llvm-filecheck").arg(builder.llvm_filecheck(builder.config.build)); - if let Some(ref nodejs) = build.config.nodejs { + if let Some(ref nodejs) = builder.config.nodejs { cmd.arg("--nodejs").arg(nodejs); } @@ -913,17 +951,17 @@ impl Step for Compiletest { vec!["-Crpath".to_string()] }; if !is_rustdoc_ui { - if build.config.rust_optimize_tests { + if builder.config.rust_optimize_tests { flags.push("-O".to_string()); } - if build.config.rust_debuginfo_tests { + if builder.config.rust_debuginfo_tests { flags.push("-g".to_string()); } } flags.push("-Zunstable-options".to_string()); - flags.push(build.config.cmd.rustc_args().join(" ")); + flags.push(builder.config.cmd.rustc_args().join(" ")); - if let Some(linker) = build.linker(target) { + if let Some(linker) = builder.linker(target) { cmd.arg("--linker").arg(linker); } @@ -932,69 +970,69 @@ impl Step for Compiletest { let mut targetflags = flags.clone(); targetflags.push(format!("-Lnative={}", - build.test_helpers_out(target).display())); + builder.test_helpers_out(target).display())); cmd.arg("--target-rustcflags").arg(targetflags.join(" ")); - cmd.arg("--docck-python").arg(build.python()); + cmd.arg("--docck-python").arg(builder.python()); - if build.build.ends_with("apple-darwin") { + if builder.config.build.ends_with("apple-darwin") { // Force /usr/bin/python on macOS for LLDB tests because we're loading the // LLDB plugin's compiled module which only works with the system python // (namely not Homebrew-installed python) cmd.arg("--lldb-python").arg("/usr/bin/python"); } else { - cmd.arg("--lldb-python").arg(build.python()); + cmd.arg("--lldb-python").arg(builder.python()); } - if let Some(ref gdb) = build.config.gdb { + if let Some(ref gdb) = builder.config.gdb { cmd.arg("--gdb").arg(gdb); } - if let Some(ref vers) = build.lldb_version { + if let Some(ref vers) = builder.lldb_version { cmd.arg("--lldb-version").arg(vers); } - if let Some(ref dir) = build.lldb_python_dir { + if let Some(ref dir) = builder.lldb_python_dir { cmd.arg("--lldb-python-dir").arg(dir); } - cmd.args(&build.config.cmd.test_args()); + cmd.args(&builder.config.cmd.test_args()); - if build.is_verbose() { + if builder.is_verbose() { cmd.arg("--verbose"); } - if build.config.quiet_tests { + if builder.config.quiet_tests { cmd.arg("--quiet"); } - if build.config.llvm_enabled { + if builder.config.llvm_enabled { let llvm_config = builder.ensure(native::Llvm { - target: build.config.build, + target: builder.config.build, emscripten: false, }); - if !build.config.dry_run { + if !builder.config.dry_run { let llvm_version = output(Command::new(&llvm_config).arg("--version")); cmd.arg("--llvm-version").arg(llvm_version); } - if !build.is_rust_llvm(target) { + if !builder.is_rust_llvm(target) { cmd.arg("--system-llvm"); } // Only pass correct values for these flags for the `run-make` suite as it // requires that a C++ compiler was configured which isn't always the case. - if !build.config.dry_run && suite == "run-make-fulldeps" { + if !builder.config.dry_run && suite == "run-make-fulldeps" { let llvm_components = output(Command::new(&llvm_config).arg("--components")); let llvm_cxxflags = output(Command::new(&llvm_config).arg("--cxxflags")); - cmd.arg("--cc").arg(build.cc(target)) - .arg("--cxx").arg(build.cxx(target).unwrap()) - .arg("--cflags").arg(build.cflags(target).join(" ")) + cmd.arg("--cc").arg(builder.cc(target)) + .arg("--cxx").arg(builder.cxx(target).unwrap()) + .arg("--cflags").arg(builder.cflags(target).join(" ")) .arg("--llvm-components").arg(llvm_components.trim()) .arg("--llvm-cxxflags").arg(llvm_cxxflags.trim()); - if let Some(ar) = build.ar(target) { + if let Some(ar) = builder.ar(target) { cmd.arg("--ar").arg(ar); } } } - if suite == "run-make-fulldeps" && !build.config.llvm_enabled { + if suite == "run-make-fulldeps" && !builder.config.llvm_enabled { builder.info( &format!("Ignoring run-make test suite as they generally don't work without LLVM")); return; @@ -1008,7 +1046,7 @@ impl Step for Compiletest { .arg("--llvm-cxxflags").arg(""); } - if build.remote_tested(target) { + if builder.remote_tested(target) { cmd.arg("--remote-test-client").arg(builder.tool_exe(Tool::RemoteTestClient)); } @@ -1018,42 +1056,51 @@ impl Step for Compiletest { // Note that if we encounter `PATH` we make sure to append to our own `PATH` // rather than stomp over it. if target.contains("msvc") { - for &(ref k, ref v) in build.cc[&target].env() { + for &(ref k, ref v) in builder.cc[&target].env() { if k != "PATH" { cmd.env(k, v); } } } cmd.env("RUSTC_BOOTSTRAP", "1"); - build.add_rust_test_threads(&mut cmd); + builder.add_rust_test_threads(&mut cmd); - if build.config.sanitizers { + if builder.config.sanitizers { cmd.env("SANITIZER_SUPPORT", "1"); } - if build.config.profiler { + if builder.config.profiler { cmd.env("PROFILER_SUPPORT", "1"); } - cmd.env("RUST_TEST_TMPDIR", build.out.join("tmp")); + cmd.env("RUST_TEST_TMPDIR", builder.out.join("tmp")); cmd.arg("--adb-path").arg("adb"); cmd.arg("--adb-test-dir").arg(ADB_TEST_DIR); if target.contains("android") { // Assume that cc for this target comes from the android sysroot cmd.arg("--android-cross-path") - .arg(build.cc(target).parent().unwrap().parent().unwrap()); + .arg(builder.cc(target).parent().unwrap().parent().unwrap()); } else { cmd.arg("--android-cross-path").arg(""); } - build.ci_env.force_coloring_in_ci(&mut cmd); + builder.ci_env.force_coloring_in_ci(&mut cmd); - let _folder = build.fold_output(|| format!("test_{}", suite)); + let _folder = builder.fold_output(|| format!("test_{}", suite)); builder.info(&format!("Check compiletest suite={} mode={} ({} -> {})", suite, mode, &compiler.host, target)); - let _time = util::timeit(&build); - try_run(build, &mut cmd); + let _time = util::timeit(&builder); + try_run(builder, &mut cmd); + + if let Some(compare_mode) = compare_mode { + cmd.arg("--compare-mode").arg(compare_mode); + let _folder = builder.fold_output(|| format!("test_{}_{}", suite, compare_mode)); + builder.info(&format!("Check compiletest suite={} mode={} compare_mode={} ({} -> {})", + suite, mode, compare_mode, &compiler.host, target)); + let _time = util::timeit(&builder); + try_run(builder, &mut cmd); + } } } @@ -1079,16 +1126,15 @@ impl Step for DocTest { /// located in `src/doc`. The `rustdoc` that's run is the one that sits next to /// `compiler`. fn run(self, builder: &Builder) { - let build = builder.build; let compiler = self.compiler; builder.ensure(compile::Test { compiler, target: compiler.host }); // Do a breadth-first traversal of the `src/doc` directory and just run // tests for all files that end in `*.md` - let mut stack = vec![build.src.join(self.path)]; - let _time = util::timeit(&build); - let _folder = build.fold_output(|| format!("test_{}", self.name)); + let mut stack = vec![builder.src.join(self.path)]; + let _time = util::timeit(&builder); + let _folder = builder.fold_output(|| format!("test_{}", self.name)); let mut files = Vec::new(); while let Some(p) = stack.pop() { @@ -1102,7 +1148,7 @@ impl Step for DocTest { } // The nostarch directory in the book is for no starch, and so isn't - // guaranteed to build. We don't care if it doesn't build, so skip it. + // guaranteed to builder. We don't care if it doesn't build, so skip it. if p.to_str().map_or(false, |p| p.contains("nostarch")) { continue; } @@ -1120,7 +1166,7 @@ impl Step for DocTest { } else { ToolState::TestFail }; - build.save_toolstate(self.name, toolstate); + builder.save_toolstate(self.name, toolstate); } } } @@ -1166,6 +1212,7 @@ test_book!( Nomicon, "src/doc/nomicon", "nomicon", default=false; Reference, "src/doc/reference", "reference", default=false; RustdocBook, "src/doc/rustdoc", "rustdoc", default=true; + RustcBook, "src/doc/rustc", "rustc", default=true; RustByExample, "src/doc/rust-by-example", "rust-by-example", default=false; TheBook, "src/doc/book", "book", default=false; UnstableBook, "src/doc/unstable-book", "unstable-book", default=true; @@ -1198,32 +1245,30 @@ impl Step for ErrorIndex { /// generate a markdown file from the error indexes of the code base which is /// then passed to `rustdoc --test`. fn run(self, builder: &Builder) { - let build = builder.build; let compiler = self.compiler; builder.ensure(compile::Std { compiler, target: compiler.host }); - let dir = testdir(build, compiler.host); + let dir = testdir(builder, compiler.host); t!(fs::create_dir_all(&dir)); let output = dir.join("error-index.md"); let mut tool = builder.tool_cmd(Tool::ErrorIndex); tool.arg("markdown") .arg(&output) - .env("CFG_BUILD", &build.build) - .env("RUSTC_ERROR_METADATA_DST", build.extended_error_dir()); + .env("CFG_BUILD", &builder.config.build) + .env("RUSTC_ERROR_METADATA_DST", builder.extended_error_dir()); - let _folder = build.fold_output(|| "test_error_index"); - build.info(&format!("Testing error-index stage{}", compiler.stage)); - let _time = util::timeit(&build); - build.run(&mut tool); + let _folder = builder.fold_output(|| "test_error_index"); + builder.info(&format!("Testing error-index stage{}", compiler.stage)); + let _time = util::timeit(&builder); + builder.run(&mut tool); markdown_test(builder, compiler, &output); } } fn markdown_test(builder: &Builder, compiler: Compiler, markdown: &Path) -> bool { - let build = builder.build; match File::open(markdown) { Ok(mut file) => { let mut contents = String::new(); @@ -1235,20 +1280,20 @@ fn markdown_test(builder: &Builder, compiler: Compiler, markdown: &Path) -> bool Err(_) => {}, } - build.info(&format!("doc tests for: {}", markdown.display())); + builder.info(&format!("doc tests for: {}", markdown.display())); let mut cmd = builder.rustdoc_cmd(compiler.host); - build.add_rust_test_threads(&mut cmd); + builder.add_rust_test_threads(&mut cmd); cmd.arg("--test"); cmd.arg(markdown); cmd.env("RUSTC_BOOTSTRAP", "1"); - let test_args = build.config.cmd.test_args().join(" "); + let test_args = builder.config.cmd.test_args().join(" "); cmd.arg("--test-args").arg(test_args); - if build.config.quiet_tests { - try_run_quiet(build, &mut cmd) + if builder.config.quiet_tests { + try_run_quiet(builder, &mut cmd) } else { - try_run(build, &mut cmd) + try_run(builder, &mut cmd) } } @@ -1432,7 +1477,6 @@ impl Step for Crate { /// Currently this runs all tests for a DAG by passing a bunch of `-p foo` /// arguments, and those arguments are discovered from `cargo metadata`. fn run(self, builder: &Builder) { - let build = builder.build; let compiler = self.compiler; let target = self.target; let mode = self.mode; @@ -1446,7 +1490,7 @@ impl Step for Crate { // libstd, then what we're actually testing is the libstd produced in // stage1. Reflect that here by updating the compiler that we're working // with automatically. - let compiler = if build.force_use_stage1(compiler, target) { + let compiler = if builder.force_use_stage1(compiler, target) { builder.compiler(1, compiler.host) } else { compiler.clone() @@ -1458,11 +1502,11 @@ impl Step for Crate { compile::std_cargo(builder, &compiler, target, &mut cargo); } Mode::Libtest => { - compile::test_cargo(build, &compiler, target, &mut cargo); + compile::test_cargo(builder, &compiler, target, &mut cargo); } Mode::Librustc => { builder.ensure(compile::Rustc { compiler, target }); - compile::rustc_cargo(build, &mut cargo); + compile::rustc_cargo(builder, &mut cargo); } _ => panic!("can only test libraries"), }; @@ -1472,10 +1516,10 @@ impl Step for Crate { // Pass in some standard flags then iterate over the graph we've discovered // in `cargo metadata` with the maps above and figure out what `-p` // arguments need to get passed. - if test_kind.subcommand() == "test" && !build.fail_fast { + if test_kind.subcommand() == "test" && !builder.fail_fast { cargo.arg("--no-fail-fast"); } - if build.doc_tests { + if builder.doc_tests { cargo.arg("--doc"); } @@ -1491,21 +1535,21 @@ impl Step for Crate { cargo.env(dylib_path_var(), env::join_paths(&dylib_path).unwrap()); cargo.arg("--"); - cargo.args(&build.config.cmd.test_args()); + cargo.args(&builder.config.cmd.test_args()); - if build.config.quiet_tests { + if builder.config.quiet_tests { cargo.arg("--quiet"); } if target.contains("emscripten") { cargo.env(format!("CARGO_TARGET_{}_RUNNER", envify(&target)), - build.config.nodejs.as_ref().expect("nodejs not configured")); + builder.config.nodejs.as_ref().expect("nodejs not configured")); } else if target.starts_with("wasm32") { // Warn about running tests without the `wasm_syscall` feature enabled. // The javascript shim implements the syscall interface so that test // output can be correctly reported. - if !build.config.wasm_syscall { - build.info(&format!("Libstd was built without `wasm_syscall` feature enabled: \ + if !builder.config.wasm_syscall { + builder.info(&format!("Libstd was built without `wasm_syscall` feature enabled: \ test output may not be visible.")); } @@ -1513,25 +1557,25 @@ impl Step for Crate { // incompatible with `-C prefer-dynamic`, so disable that here cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1"); - let node = build.config.nodejs.as_ref() + let node = builder.config.nodejs.as_ref() .expect("nodejs not configured"); let runner = format!("{} {}/src/etc/wasm32-shim.js", node.display(), - build.src.display()); + builder.src.display()); cargo.env(format!("CARGO_TARGET_{}_RUNNER", envify(&target)), &runner); - } else if build.remote_tested(target) { + } else if builder.remote_tested(target) { cargo.env(format!("CARGO_TARGET_{}_RUNNER", envify(&target)), format!("{} run", builder.tool_exe(Tool::RemoteTestClient).display())); } - let _folder = build.fold_output(|| { + let _folder = builder.fold_output(|| { format!("{}_stage{}-{}", test_kind.subcommand(), compiler.stage, krate) }); - build.info(&format!("{} {} stage{} ({} -> {})", test_kind, krate, compiler.stage, + builder.info(&format!("{} {} stage{} ({} -> {})", test_kind, krate, compiler.stage, &compiler.host, target)); - let _time = util::timeit(&build); - try_run(build, &mut cargo); + let _time = util::timeit(&builder); + try_run(builder, &mut cargo); } } @@ -1568,7 +1612,6 @@ impl Step for CrateRustdoc { } fn run(self, builder: &Builder) { - let build = builder.build; let test_kind = self.test_kind; let compiler = builder.compiler(builder.top_stage, self.host); @@ -1579,27 +1622,27 @@ impl Step for CrateRustdoc { target, test_kind.subcommand(), "src/tools/rustdoc"); - if test_kind.subcommand() == "test" && !build.fail_fast { + if test_kind.subcommand() == "test" && !builder.fail_fast { cargo.arg("--no-fail-fast"); } cargo.arg("-p").arg("rustdoc:0.0.0"); cargo.arg("--"); - cargo.args(&build.config.cmd.test_args()); + cargo.args(&builder.config.cmd.test_args()); - if build.config.quiet_tests { + if builder.config.quiet_tests { cargo.arg("--quiet"); } - let _folder = build.fold_output(|| { + let _folder = builder.fold_output(|| { format!("{}_stage{}-rustdoc", test_kind.subcommand(), compiler.stage) }); - build.info(&format!("{} rustdoc stage{} ({} -> {})", test_kind, compiler.stage, + builder.info(&format!("{} rustdoc stage{} ({} -> {})", test_kind, compiler.stage, &compiler.host, target)); - let _time = util::timeit(&build); + let _time = util::timeit(&builder); - try_run(build, &mut cargo); + try_run(builder, &mut cargo); } } @@ -1635,17 +1678,16 @@ impl Step for RemoteCopyLibs { } fn run(self, builder: &Builder) { - let build = builder.build; let compiler = self.compiler; let target = self.target; - if !build.remote_tested(target) { + if !builder.remote_tested(target) { return } builder.ensure(compile::Test { compiler, target }); - build.info(&format!("REMOTE copy libs to emulator ({})", target)); - t!(fs::create_dir_all(build.out.join("tmp"))); + builder.info(&format!("REMOTE copy libs to emulator ({})", target)); + t!(fs::create_dir_all(builder.out.join("tmp"))); let server = builder.ensure(tool::RemoteTestServer { compiler, target }); @@ -1655,18 +1697,18 @@ impl Step for RemoteCopyLibs { cmd.arg("spawn-emulator") .arg(target) .arg(&server) - .arg(build.out.join("tmp")); - if let Some(rootfs) = build.qemu_rootfs(target) { + .arg(builder.out.join("tmp")); + if let Some(rootfs) = builder.qemu_rootfs(target) { cmd.arg(rootfs); } - build.run(&mut cmd); + builder.run(&mut cmd); // Push all our dylibs to the emulator for f in t!(builder.sysroot_libdir(compiler, target).read_dir()) { let f = t!(f); let name = f.file_name().into_string().unwrap(); if util::is_dylib(&name) { - build.run(Command::new(&tool) + builder.run(Command::new(&tool) .arg("push") .arg(f.path())); } @@ -1690,10 +1732,8 @@ impl Step for Distcheck { /// Run "distcheck", a 'make check' from a tarball fn run(self, builder: &Builder) { - let build = builder.build; - - build.info(&format!("Distcheck")); - let dir = build.out.join("tmp").join("distcheck"); + builder.info(&format!("Distcheck")); + let dir = builder.out.join("tmp").join("distcheck"); let _ = fs::remove_dir_all(&dir); t!(fs::create_dir_all(&dir)); @@ -1706,18 +1746,18 @@ impl Step for Distcheck { .arg(builder.ensure(dist::PlainSourceTarball)) .arg("--strip-components=1") .current_dir(&dir); - build.run(&mut cmd); - build.run(Command::new("./configure") - .args(&build.config.configure_args) + builder.run(&mut cmd); + builder.run(Command::new("./configure") + .args(&builder.config.configure_args) .arg("--enable-vendor") .current_dir(&dir)); - build.run(Command::new(build_helper::make(&build.build)) + builder.run(Command::new(build_helper::make(&builder.config.build)) .arg("check") .current_dir(&dir)); // Now make sure that rust-src has all of libstd's dependencies - build.info(&format!("Distcheck rust-src")); - let dir = build.out.join("tmp").join("distcheck-src"); + builder.info(&format!("Distcheck rust-src")); + let dir = builder.out.join("tmp").join("distcheck-src"); let _ = fs::remove_dir_all(&dir); t!(fs::create_dir_all(&dir)); @@ -1726,10 +1766,10 @@ impl Step for Distcheck { .arg(builder.ensure(dist::Src)) .arg("--strip-components=1") .current_dir(&dir); - build.run(&mut cmd); + builder.run(&mut cmd); let toml = dir.join("rust-src/lib/rustlib/src/rust/src/libstd/Cargo.toml"); - build.run(Command::new(&build.initial_cargo) + builder.run(Command::new(&builder.initial_cargo) .arg("generate-lockfile") .arg("--manifest-path") .arg(&toml) @@ -1747,25 +1787,24 @@ impl Step for Bootstrap { /// Test the build system itself fn run(self, builder: &Builder) { - let build = builder.build; - let mut cmd = Command::new(&build.initial_cargo); + let mut cmd = Command::new(&builder.initial_cargo); cmd.arg("test") - .current_dir(build.src.join("src/bootstrap")) + .current_dir(builder.src.join("src/bootstrap")) .env("RUSTFLAGS", "-Cdebuginfo=2") - .env("CARGO_TARGET_DIR", build.out.join("bootstrap")) + .env("CARGO_TARGET_DIR", builder.out.join("bootstrap")) .env("RUSTC_BOOTSTRAP", "1") - .env("RUSTC", &build.initial_rustc); + .env("RUSTC", &builder.initial_rustc); if let Some(flags) = option_env!("RUSTFLAGS") { // Use the same rustc flags for testing as for "normal" compilation, // so that Cargo doesn’t recompile the entire dependency graph every time: // https://github.com/rust-lang/rust/issues/49215 cmd.env("RUSTFLAGS", flags); } - if !build.fail_fast { + if !builder.fail_fast { cmd.arg("--no-fail-fast"); } - cmd.arg("--").args(&build.config.cmd.test_args()); - try_run(build, &mut cmd); + cmd.arg("--").args(&builder.config.cmd.test_args()); + try_run(builder, &mut cmd); } fn should_run(run: ShouldRun) -> ShouldRun { diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 97507bc0869..6c29bd84fe4 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -38,7 +38,6 @@ impl Step for CleanTools { } fn run(self, builder: &Builder) { - let build = builder.build; let compiler = self.compiler; let target = self.target; let mode = self.mode; @@ -46,7 +45,7 @@ impl Step for CleanTools { // This is for the original compiler, but if we're forced to use stage 1, then // std/test/rustc stamps won't exist in stage 2, so we need to get those from stage 1, since // we copy the libs forward. - let tools_dir = build.stage_out(compiler, Mode::Tool); + let tools_dir = builder.stage_out(compiler, Mode::Tool); let compiler = if builder.force_use_stage1(compiler, target) { builder.compiler(1, compiler.host) } else { @@ -55,13 +54,13 @@ impl Step for CleanTools { for &cur_mode in &[Mode::Libstd, Mode::Libtest, Mode::Librustc] { let stamp = match cur_mode { - Mode::Libstd => libstd_stamp(build, compiler, target), - Mode::Libtest => libtest_stamp(build, compiler, target), - Mode::Librustc => librustc_stamp(build, compiler, target), + Mode::Libstd => libstd_stamp(builder, compiler, target), + Mode::Libtest => libtest_stamp(builder, compiler, target), + Mode::Librustc => librustc_stamp(builder, compiler, target), _ => panic!(), }; - if build.clear_if_dirty(&tools_dir, &stamp) { + if builder.clear_if_dirty(&tools_dir, &stamp) { break; } @@ -97,7 +96,6 @@ impl Step for ToolBuild { /// This will build the specified tool with the specified `host` compiler in /// `stage` into the normal cargo output directory. fn run(self, builder: &Builder) -> Option<PathBuf> { - let build = builder.build; let compiler = self.compiler; let target = self.target; let tool = self.tool; @@ -114,10 +112,10 @@ impl Step for ToolBuild { let mut cargo = prepare_tool_cargo(builder, compiler, target, "build", path); cargo.arg("--features").arg(self.extra_features.join(" ")); - let _folder = build.fold_output(|| format!("stage{}-{}", compiler.stage, tool)); - build.info(&format!("Building stage{} tool {} ({})", compiler.stage, tool, target)); + let _folder = builder.fold_output(|| format!("stage{}-{}", compiler.stage, tool)); + builder.info(&format!("Building stage{} tool {} ({})", compiler.stage, tool, target)); let mut duplicates = Vec::new(); - let is_expected = compile::stream_cargo(build, &mut cargo, &mut |msg| { + let is_expected = compile::stream_cargo(builder, &mut cargo, &mut |msg| { // Only care about big things like the RLS/Cargo for now if tool != "rls" && tool != "cargo" { return @@ -156,7 +154,7 @@ impl Step for ToolBuild { } } - let mut artifacts = build.tool_artifacts.borrow_mut(); + let mut artifacts = builder.tool_artifacts.borrow_mut(); let prev_artifacts = artifacts .entry(target) .or_insert_with(Default::default); @@ -190,7 +188,7 @@ impl Step for ToolBuild { panic!("tools should not compile multiple copies of the same crate"); } - build.save_toolstate(tool, if is_expected { + builder.save_toolstate(tool, if is_expected { ToolState::TestFail } else { ToolState::BuildFail @@ -203,10 +201,10 @@ impl Step for ToolBuild { return None; } } else { - let cargo_out = build.cargo_out(compiler, Mode::Tool, target) + let cargo_out = builder.cargo_out(compiler, Mode::Tool, target) .join(exe(tool, &compiler.host)); - let bin = build.tools_dir(compiler).join(exe(tool, &compiler.host)); - build.copy(&cargo_out, &bin); + let bin = builder.tools_dir(compiler).join(exe(tool, &compiler.host)); + builder.copy(&cargo_out, &bin); Some(bin) } } @@ -219,16 +217,15 @@ pub fn prepare_tool_cargo( command: &'static str, path: &'static str, ) -> Command { - let build = builder.build; let mut cargo = builder.cargo(compiler, Mode::Tool, target, command); - let dir = build.src.join(path); + let dir = builder.src.join(path); cargo.arg("--manifest-path").arg(dir.join("Cargo.toml")); // We don't want to build tools dynamically as they'll be running across // stages and such and it's just easier if they're not dynamically linked. cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1"); - if let Some(dir) = build.openssl_install_dir(target) { + if let Some(dir) = builder.openssl_install_dir(target) { cargo.env("OPENSSL_STATIC", "1"); cargo.env("OPENSSL_DIR", dir); cargo.env("LIBZ_SYS_STATIC", "1"); @@ -238,10 +235,10 @@ pub fn prepare_tool_cargo( // own copy cargo.env("LZMA_API_STATIC", "1"); - cargo.env("CFG_RELEASE_CHANNEL", &build.config.channel); - cargo.env("CFG_VERSION", build.rust_version()); + cargo.env("CFG_RELEASE_CHANNEL", &builder.config.channel); + cargo.env("CFG_VERSION", builder.rust_version()); - let info = GitInfo::new(&build.config, &dir); + let info = GitInfo::new(&builder.config, &dir); if let Some(sha) = info.sha() { cargo.env("CFG_COMMIT_HASH", sha); } @@ -269,8 +266,8 @@ macro_rules! tool { match tool { $(Tool::$name => self.ensure($name { - compiler: self.compiler(stage, self.build.build), - target: self.build.build, + compiler: self.compiler(stage, self.config.build), + target: self.config.build, }), )+ } @@ -304,7 +301,7 @@ macro_rules! tool { fn make_run(run: RunConfig) { run.builder.ensure($name { - compiler: run.builder.compiler(run.builder.top_stage, run.builder.build.build), + compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build), target: run.target, }); } @@ -354,7 +351,7 @@ impl Step for RemoteTestServer { fn make_run(run: RunConfig) { run.builder.ensure(RemoteTestServer { - compiler: run.builder.compiler(run.builder.top_stage, run.builder.build.build), + compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build), target: run.target, }); } @@ -393,26 +390,25 @@ impl Step for Rustdoc { } fn run(self, builder: &Builder) -> PathBuf { - let build = builder.build; let target_compiler = builder.compiler(builder.top_stage, self.host); let target = target_compiler.host; let build_compiler = if target_compiler.stage == 0 { - builder.compiler(0, builder.build.build) + builder.compiler(0, builder.config.build) } else if target_compiler.stage >= 2 { // Past stage 2, we consider the compiler to be ABI-compatible and hence capable of // building rustdoc itself. - builder.compiler(target_compiler.stage, builder.build.build) + builder.compiler(target_compiler.stage, builder.config.build) } else { // Similar to `compile::Assemble`, build with the previous stage's compiler. Otherwise // we'd have stageN/bin/rustc and stageN/bin/rustdoc be effectively different stage // compilers, which isn't what we want. - builder.compiler(target_compiler.stage - 1, builder.build.build) + builder.compiler(target_compiler.stage - 1, builder.config.build) }; builder.ensure(compile::Rustc { compiler: build_compiler, target }); builder.ensure(compile::Rustc { compiler: build_compiler, - target: builder.build.build, + target: builder.config.build, }); let mut cargo = prepare_tool_cargo(builder, @@ -425,15 +421,15 @@ impl Step for Rustdoc { cargo.env("RUSTC_DEBUGINFO", builder.config.rust_debuginfo.to_string()) .env("RUSTC_DEBUGINFO_LINES", builder.config.rust_debuginfo_lines.to_string()); - let _folder = build.fold_output(|| format!("stage{}-rustdoc", target_compiler.stage)); - build.info(&format!("Building rustdoc for stage{} ({})", + let _folder = builder.fold_output(|| format!("stage{}-rustdoc", target_compiler.stage)); + builder.info(&format!("Building rustdoc for stage{} ({})", target_compiler.stage, target_compiler.host)); - build.run(&mut cargo); + builder.run(&mut cargo); // Cargo adds a number of paths to the dylib search path on windows, which results in // the wrong rustdoc being executed. To avoid the conflicting rustdocs, we name the "tool" // rustdoc a different name. - let tool_rustdoc = build.cargo_out(build_compiler, Mode::Tool, target) + let tool_rustdoc = builder.cargo_out(build_compiler, Mode::Tool, target) .join(exe("rustdoc-tool-binary", &target_compiler.host)); // don't create a stage0-sysroot/bin directory. @@ -443,7 +439,7 @@ impl Step for Rustdoc { t!(fs::create_dir_all(&bindir)); let bin_rustdoc = bindir.join(exe("rustdoc", &*target_compiler.host)); let _ = fs::remove_file(&bin_rustdoc); - build.copy(&tool_rustdoc, &bin_rustdoc); + builder.copy(&tool_rustdoc, &bin_rustdoc); bin_rustdoc } else { tool_rustdoc @@ -464,12 +460,12 @@ impl Step for Cargo { fn should_run(run: ShouldRun) -> ShouldRun { let builder = run.builder; - run.path("src/tools/cargo").default_condition(builder.build.config.extended) + run.path("src/tools/cargo").default_condition(builder.config.extended) } fn make_run(run: RunConfig) { run.builder.ensure(Cargo { - compiler: run.builder.compiler(run.builder.top_stage, run.builder.build.build), + compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build), target: run.target, }); } @@ -482,7 +478,7 @@ impl Step for Cargo { // compiler to be available, so we need to depend on that. builder.ensure(compile::Rustc { compiler: self.compiler, - target: builder.build.build, + target: builder.config.build, }); builder.ensure(ToolBuild { compiler: self.compiler, @@ -518,12 +514,12 @@ macro_rules! tool_extended { fn should_run(run: ShouldRun) -> ShouldRun { let builder = run.builder; - run.path($path).default_condition(builder.build.config.extended) + run.path($path).default_condition(builder.config.extended) } fn make_run(run: RunConfig) { run.builder.ensure($name { - compiler: run.builder.compiler(run.builder.top_stage, run.builder.build.build), + compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build), target: run.target, extra_features: Vec::new(), }); @@ -554,7 +550,7 @@ tool_extended!((self, builder), // compiler to be available, so we need to depend on that. builder.ensure(compile::Rustc { compiler: self.compiler, - target: builder.build.build, + target: builder.config.build, }); }; Miri, miri, "src/tools/miri", "miri", {}; @@ -575,7 +571,7 @@ tool_extended!((self, builder), // compiler to be available, so we need to depend on that. builder.ensure(compile::Rustc { compiler: self.compiler, - target: builder.build.build, + target: builder.config.build, }); }; Rustfmt, rustfmt, "src/tools/rustfmt", "rustfmt", {}; @@ -586,7 +582,7 @@ impl<'a> Builder<'a> { /// `host`. pub fn tool_cmd(&self, tool: Tool) -> Command { let mut cmd = Command::new(self.tool_exe(tool)); - let compiler = self.compiler(self.tool_default_stage(tool), self.build.build); + let compiler = self.compiler(self.tool_default_stage(tool), self.config.build); self.prepare_tool_cmd(compiler, &mut cmd); cmd } diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs index f8c70323698..9a2b9e90440 100644 --- a/src/bootstrap/util.rs +++ b/src/bootstrap/util.rs @@ -22,7 +22,7 @@ use std::process::Command; use std::time::{SystemTime, Instant}; use config::Config; -use Build; +use builder::Builder; /// Returns the `name` as the filename of a static library for `target`. pub fn staticlib(name: &str, target: &str) -> String { @@ -104,8 +104,8 @@ pub fn push_exe_path(mut buf: PathBuf, components: &[&str]) -> PathBuf { pub struct TimeIt(bool, Instant); /// Returns an RAII structure that prints out how long it took to drop. -pub fn timeit(build: &Build) -> TimeIt { - TimeIt(build.config.dry_run, Instant::now()) +pub fn timeit(builder: &Builder) -> TimeIt { + TimeIt(builder.config.dry_run, Instant::now()) } impl Drop for TimeIt { diff --git a/src/ci/docker/x86_64-gnu-tools/checktools.sh b/src/ci/docker/x86_64-gnu-tools/checktools.sh index da89aa9423b..3fed0175371 100755 --- a/src/ci/docker/x86_64-gnu-tools/checktools.sh +++ b/src/ci/docker/x86_64-gnu-tools/checktools.sh @@ -67,7 +67,7 @@ verify_status rust-by-example src/doc/rust-by-example verify_status rls src/tool/rls verify_status rustfmt src/tool/rustfmt verify_status clippy-driver src/tool/clippy -#verify_status miri src/tool/miri +verify_status miri src/tool/miri if [ "$RUST_RELEASE_CHANNEL" = nightly -a -n "${TOOLSTATE_REPO_ACCESS_TOKEN+is_set}" ]; then . "$(dirname $0)/repo.sh" diff --git a/src/doc/index.md b/src/doc/index.md index 2ea889da1fd..3a4f51069fc 100644 --- a/src/doc/index.md +++ b/src/doc/index.md @@ -43,6 +43,10 @@ Rust's standard library has [extensive API documentation](std/index.html), with explanations of how to use various things, as well as example code for accomplishing various tasks. +## The Rustc Book + +[The Rustc Book](rustc/index.html) describes the Rust compiler, `rustc`. + ## The Cargo Book [The Cargo Book](cargo/index.html) is a guide to Cargo, Rust's build tool and dependency manager. diff --git a/src/doc/rustc/.gitignore b/src/doc/rustc/.gitignore new file mode 100644 index 00000000000..7585238efed --- /dev/null +++ b/src/doc/rustc/.gitignore @@ -0,0 +1 @@ +book diff --git a/src/doc/rustc/book.toml b/src/doc/rustc/book.toml new file mode 100644 index 00000000000..8adc05c5137 --- /dev/null +++ b/src/doc/rustc/book.toml @@ -0,0 +1,5 @@ +[book] +authors = ["The Rust Project Developers"] +multilingual = false +src = "src" +title = "The rustc book" diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md new file mode 100644 index 00000000000..e4c0939fd46 --- /dev/null +++ b/src/doc/rustc/src/SUMMARY.md @@ -0,0 +1,16 @@ +# The Rustc Book + +- [What is rustc?](what-is-rustc.md) +- [Command-line arguments](command-line-arguments.md) +- [Lints](lints/index.md) + - [Lint levels](lints/levels.md) + - [Lint Groups](lints/groups.md) + - [Lint listing](lints/listing/index.md) + - [Allowed-by-default lints](lints/listing/allowed-by-default.md) + - [Warn-by-default lints](lints/listing/warn-by-default.md) + - [Deny-by-default lints](lints/listing/deny-by-default.md) +- [Codegen options](codegen-options/index.md) +- [Targets](targets/index.md) + - [Built-in Targets](targets/built-in.md) + - [Custom Targets](targets/custom.md) +- [Contributing to `rustc`](contributing.md) \ No newline at end of file diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md new file mode 100644 index 00000000000..eff09428902 --- /dev/null +++ b/src/doc/rustc/src/codegen-options/index.md @@ -0,0 +1,209 @@ +# Codegen options + +All of these options are passed to `rustc` via the `-C` flag, short for "codegen." You can see +a version of this list for your exact compiler by running `rustc -C help`. + +## ar + +This option is deprecated and does nothing. + +## linker + +This flag lets you control which linker `rustc` invokes to link your code. + +## link-arg=val + +This flag lets you append a single extra argument to the linker invocation. + +"Append" is significant; you can pass this flag multiple times to add multiple arguments. + +## link-args + +This flag lets you append multiple extra arguments to the linker invocation. The +options should be separated by spaces. + +## link-dead-code + +Normally, the linker will remove dead code. This flag disables this behavior. + +An example of when this flag might be useful is when trying to construct code coverage +metrics. + +## lto + +This flag instructs LLVM to use [link time +optimizations](https://llvm.org/docs/LinkTimeOptimization.html). + +It takes one of two values, `thin` and `fat`. 'thin' LTO [is a new feature of +LLVM](http://blog.llvm.org/2016/06/thinlto-scalable-and-incremental-lto.html), +'fat' referring to the classic version of LTO. + +## target-cpu + +This instructs `rustc` to generate code specifically for a particular processor. + +You can run `rustc --print target-cpus` to see the valid options to pass +here. Additionally, `native` can be passed to use the processor of the host +machine. + +## target-feature + +Individual targets will support different features; this flag lets you control +enabling or disabling a feature. + +To see the valid options and an example of use, run `rustc --print +target-features`. + +## passes + +This flag can be used to add extra LLVM passes to the compilation. + +The list must be separated by spaces. + +## llvm-args + +This flag can be used to pass a list of arguments directly to LLVM. + +The list must be separated by spaces. + +## save-temps + +`rustc` will generate temporary files during compilation; normally it will +delete them after it's done with its work. This option will cause them to be +preserved instead of removed. + +## rpath + +This option allows you to set the value of +[`rpath`](https://en.wikipedia.org/wiki/Rpath). + +## overflow-checks + +This flag allows you to control the behavior of integer overflow. This flag +can be passed many options: + +* To turn overflow checks on: `y`, `yes`, or `on`. +* To turn overflow checks off: `n`, `no`, or `off`. + +## no-prepopulate-passes + +The pass manager comes pre-populated with a list of passes; this flag +ensures that list is empty. + +## no-vectorize-loops + +By default, `rustc` will attempt to [vectorize +loops](https://llvm.org/docs/Vectorizers.html#the-loop-vectorizer). This +flag will turn that behavior off. + +## no-vectorize-slp + +By default, `rustc` will attempt to vectorize loops using [superword-level +parallelism](https://llvm.org/docs/Vectorizers.html#the-slp-vectorizer). This +flag will turn that behavior off. + +## soft-float + +This option will make `rustc` generate code using "soft floats." By default, +a lot of hardware supports floating point instructions, and so the code generated +will take advantage of this. "soft floats" emulate floating point instructions +in software. + +## prefer-dynamic + +By default, `rustc` prefers to statically link dependencies. This option will +make it use dynamic linking instead. + +## no-integrated-as + +LLVM comes with an internal assembler; this option will let you use an +external assembler instead. + +## no-redzone + +This flag allows you to disable [the +red zone](https://en.wikipedia.org/wiki/Red_zone_\(computing\)). This flag can +be passed many options: + +* To enable the red zone: `y`, `yes`, or `on`. +* To disable it: `n`, `no`, or `off`. + +## relocation-model + +This option lets you choose which relocation model to use. + +To find the valid options for this flag, run `rustc --print relocation-models`. + +## code-model=val + +This option lets you choose which code model to use. + +To find the valid options for this flag, run `rustc --print code-models`. + +## metadata + +This option allows you to control the metadata used for symbol mangling. + +## extra-filename + +This option allows you to put extra data in each output filename. + +## codegen-units + +This flag lets you control how many threads are used when doing +code generation. + +Increasing paralellism may speed up compile times, but may also +produce slower code. + +## remark + +This flag lets you print remarks for these optimization passes. + +The list of passes should be separated by spaces. + +`all` will remark on every pass. + +## no-stack-check + +This option is deprecated and does nothing. + +## debuginfo + +This flag lets you control debug information: + +* `0`: no debug info at all +* `1`: line tables only +* `2`: full debug info + +## opt-level + +This flag lets you control the optimization level. + +* `0`: no optimizations +* `1`: basic optimizations +* `2`: some optimizations +* `3`: all optimizations +* `s`: optimize for binary size +* `z`: optimize for binary size, but also turn off loop vectorization. + +## debug-assertions + +This flag lets you turn `cfg(debug_assertions)` on or off. + +## inline-threshold + +This option lets you set the threshold for inlining a function. + +The default is 225. + +## panic + +This option lets you control what happens when the code panics. + +* `abort`: terminate the process upon panic +* `unwind`: unwind the stack upon panic + +## incremental + +This flag allows you to enable incremental compilation. diff --git a/src/doc/rustc/src/command-line-arguments.md b/src/doc/rustc/src/command-line-arguments.md new file mode 100644 index 00000000000..e2b001832fe --- /dev/null +++ b/src/doc/rustc/src/command-line-arguments.md @@ -0,0 +1,116 @@ +# Command-line arguments + +Here's a list of command-line arguments to `rustc` and what they do. + +## `-h`/`--help`: get help + +This flag will print out help information for `rustc`. + +## `--cfg`: configure the compilation environment + +This flag can turn on or off various `#[cfg]` settings. + +## `-L`: add a directory to the library search path + +When looking for external crates, a directory passed to this flag will be searched. + +## `-l`: link the generated crate to a native library + +This flag allows you to specify linking to a specific native library when building +a crate. + +## `--crate-type`: a list of types of crates for the compiler to emit + +This instructs `rustc` on which crate type to build. + +## `--crate-name`: specify the name of the crate being built + +This informs `rustc` of the name of your crate. + +## `--emit`: emit output other than a crate + +Instead of producing a crate, this flag can print out things like the assembly or LLVM-IR. + +## `--print`: print compiler information + +This flag prints out various information about the compiler. + +## `-g`: include debug information + +A synonym for `-C debug-level=2`. + +## `-O`: optimize your code + +A synonym for `-C opt-level=2`. + +## `-o`: filename of the output + +This flag controls the output filename. + +## `--out-dir`: directory to write the output in + +The outputted crate will be written to this directory. + +## `--explain`: provide a detailed explanation of an error message + +Each error of `rustc`'s comes with an error code; this will print +out a longer explanation of a given error. + +## `--test`: build a test harness + +When compiling this crate, `rustc` will ignore your `main` function +and instead produce a test harness. + +## `--target`: select a target triple to build + +This controls which [target](targets/index.html) to produce. + +## `-W`: set lint warnings + +This flag will set which lints should be set to the [warn level](lints/levels.html#warn). + +## `-A`: set lint allowed + +This flag will set which lints should be set to the [allow level](lints/levels.html#allow). + +## `-D`: set lint denied + +This flag will set which lints should be set to the [deny level](lints/levels.html#deny). + +## `-F`: set lint forbidden + +This flag will set which lints should be set to the [forbid level](lints/levels.html#forbid). + +## `--cap-lints`: set the most restrictive lint level + +This flag lets you 'cap' lints, for more, [see here](lints/levels.html#capping-lints). + +## `-C`/`--codegen`: code generation options + +This flag will allow you to set [codegen options](codegen-options/index.html). + +## `-V`/`--version`: print a version + +This flag will print out `rustc`'s version. + +## `-v`/`--verbose`: use verbose output + +This flag, when combined with other flags, makes them produce extra output. + +## `--extern`: specify where an external library is located + +This flag allows you to pass the name and location of an external crate that will +be linked into the crate you're buildling. + +## `--sysroot`: Override the system root + +The "sysroot" is where `rustc` looks for the crates that come with the Rust +distribution; this flag allows that to be overridden. + +## `--error-format`: control how errors are produced + +This flag lets you control the format of errors. + +## `--color`: configure coloring of output + +This flag lets you control color settings of the output. diff --git a/src/doc/rustc/src/contributing.md b/src/doc/rustc/src/contributing.md new file mode 100644 index 00000000000..fcb8e6b27db --- /dev/null +++ b/src/doc/rustc/src/contributing.md @@ -0,0 +1,6 @@ +# Contributing to rustc + +We'd love to have your help improving `rustc`! To that end, we've written [a +whole book](https://rust-lang-nursery.github.io/rustc-guide/) on its +internals, how it works, and how to get started working on it. To learn +more, you'll want to check that out. \ No newline at end of file diff --git a/src/doc/rustc/src/lints/groups.md b/src/doc/rustc/src/lints/groups.md new file mode 100644 index 00000000000..46b717f3387 --- /dev/null +++ b/src/doc/rustc/src/lints/groups.md @@ -0,0 +1,29 @@ +# Lint Groups + +`rustc` has the concept of a "lint group", where you can toggle several warnings +through one name. + +For example, the `nonstandard-style` lint sets `non-camel-case-types`, +`non-snake-case`, and `non-upper-case-globals` all at once. So these are +equivalent: + +```bash +$ rustc -D nonstandard-style +$ rustc -D non-camel-case-types -D non-snake-case -D non-upper-case-globals +``` + +Here's a list of each lint group, and the lints that they are made up of: + +| group | description | lints | +|---------------------|---------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| nonstandard-style | Violation of standard naming conventions | non-camel-case-types, non-snake-case, non-upper-case-globals | +| warnings | all lints that would be issuing warnings | all lints that would be issuing warnings | +| edition-2018 | Lints that will be turned into errors in Rust 2018 | tyvar-behind-raw-pointer | +| rust-2018-idioms | Lints to nudge you toward idiomatic features of Rust 2018 | bare-trait-object, unreachable-pub | +| unused | These lints detect things being declared but not used | unused-imports, unused-variables, unused-assignments, dead-code, unused-mut, unreachable-code, unreachable-patterns, unused-must-use, unused-unsafe, path-statements, unused-attributes, unused-macros, unused-allocation, unused-doc-comment, unused-extern-crates, unused-features, unused-parens | +| future-incompatible | Lints that detect code that has future-compatibility problems | private-in-public, pub-use-of-private-extern-crate, patterns-in-fns-without-body, safe-extern-statics, invalid-type-param-default, legacy-directory-ownership, legacy-imports, legacy-constructor-visibility, missing-fragment-specifier, illegal-floating-point-literal-pattern, anonymous-parameters, parenthesized-params-in-types-and-modules, late-bound-lifetime-arguments, safe-packed-borrows, incoherent-fundamental-impls, tyvar-behind-raw-pointer, unstable-name-collision | + +Additionally, there's a `bad-style` lint group that's a deprecated alias for `nonstandard-style`. + +Finally, you can also see the table above by invoking `rustc -W help`. This will give you the exact values for the specific +compiler you have installed. \ No newline at end of file diff --git a/src/doc/rustc/src/lints/index.md b/src/doc/rustc/src/lints/index.md new file mode 100644 index 00000000000..bf345a24389 --- /dev/null +++ b/src/doc/rustc/src/lints/index.md @@ -0,0 +1,28 @@ +# Lints + +In software, a "lint" is a tool used to help improve your source code. The +Rust compiler contains a number of lints, and when it compiles your code, it will +also run the lints. These lints may produce a warning, an error, or nothing at all, +depending on how you've configured things. + +Here's a small example: + +```bash +$ cat main.rs +fn main() { + let x = 5; +} +> rustc main.rs +warning: unused variable: `x` + --> main.rs:2:9 + | +2 | let x = 5; + | ^ + | + = note: #[warn(unused_variables)] on by default + = note: to avoid this warning, consider using `_x` instead +``` + +This is the `unused_variables` lint, and it tells you that you've introduced +a variable that you don't use in your code. That's not *wrong*, so it's not +an error, but it might be a bug, so you get a warning. diff --git a/src/doc/rustc/src/lints/levels.md b/src/doc/rustc/src/lints/levels.md new file mode 100644 index 00000000000..19bb6707d22 --- /dev/null +++ b/src/doc/rustc/src/lints/levels.md @@ -0,0 +1,252 @@ +# Lint levels + +In `rustc`, lints are divided into four *levels*: + +1. allow +2. warn +3. deny +4. forbid + +Each lint has a default level (explained in the lint listing later in this +chapter), and the compiler has a default warning level. First, let's explain +what these levels mean, and then we'll talk about configuration. + +## allow + +These lints exist, but by default, do nothing. For example, consider this +source: + +```rust +pub fn foo() {} +``` + +Compiling this file produces no warnings: + +```bash +$ rustc lib.rs --crate-type=lib +$ +``` + +But this code violates the `missing_docs` lint. + +These lints exist mostly to be manually turned on via configuration, as we'll +talk about later in this section. + +## warn + +The 'warn' lint level will produce a warning if you violate the lint. For example, +this code runs afoul of the `unused_variable` lint: + +```rust +pub fn foo() { + let x = 5; +} +``` + +This will produce this warning: + +```console +$ rustc lib.rs --crate-type=lib +warning: unused variable: `x` + --> lib.rs:2:9 + | +2 | let x = 5; + | ^ + | + = note: #[warn(unused_variables)] on by default + = note: to avoid this warning, consider using `_x` instead +``` + +## deny + +A 'deny' lint produces an error if you violate it. For example, this code +runs into the `exceeding_bitshifts` lint. + +```rust,ignore +fn main() { + 100u8 << 10; +} +``` + +```bash +> rustc main.rs +error: bitshift exceeds the type's number of bits + --> main.rs:2:13 + | +2 | 100u8 << 10; + | ^^^^^^^^^^^ + | + = note: #[deny(exceeding_bitshifts)] on by default +``` + +What's the difference between an error from a lint and a regular old error? +Lints are configurable via levels, so in a similar way to 'allow' lints, +warnings that are 'deny' by default let you allow them. Similarly, you may +wish to set up a lint that is `warn` by default to produce an error instead. +This lint level gives you that. + +## forbid + +'forbid' is a special lint level that's stronger than 'deny'. It's the same +as 'deny' in that a lint at this level will produce an error, but unlike the +'deny' level, the 'forbid' level can not be overridden to be anything lower +than an error. + +## Configuring warning levels + +Remember our `missing_docs` example from the 'allow' lint level? + +```bash +$ cat lib.rs +pub fn foo() {} +$ rustc lib.rs --crate-type=lib +$ +``` + +We can configure this lint to operate at a higher level, both with +compiler flags, as well as with an attribute in the source code. + +You can also "cap" lints so that the compiler can choose to ignore +certain lint levels. We'll talk about that last. + +### Via compiler flag + +The `-A`, `-W`, `-D`, and `-F` flags let you turn one or more lints +into allowed, warning, deny, or forbid levels, like this: + +```bash +$ rustc lib.rs --crate-type=lib -W missing-docs +warning: missing documentation for crate + --> lib.rs:1:1 + | +1 | pub fn foo() {} + | ^^^^^^^^^^^^ + | + = note: requested on the command line with `-W missing-docs` + +warning: missing documentation for a function + --> lib.rs:1:1 + | +1 | pub fn foo() {} + | ^^^^^^^^^^^^ +> rustc lib.rs --crate-type=lib -D missing-docs +error: missing documentation for crate + --> lib.rs:1:1 + | +1 | pub fn foo() {} + | ^^^^^^^^^^^^ + | + = note: requested on the command line with `-D missing-docs` + +error: missing documentation for a function + --> lib.rs:1:1 + | +1 | pub fn foo() {} + | ^^^^^^^^^^^^ + +error: aborting due to 2 previous errors +``` + +You can also pass each flag more than once for changing multiple lints: + +```bash +rustc lib.rs --crate-type=lib -D missing-docs -D unused-variables +``` + +And of course, you can mix these four flags together: + +```bash +rustc lib.rs --crate-type=lib -D missing-docs -A unused-variables +``` + +### Via an attribute + +You can also modify the lint level with a crate-wide attribute: + +```bash +> cat lib.rs +#![warn(missing_docs)] + +pub fn foo() {} +$ rustc lib.rs --crate-type=lib +warning: missing documentation for crate + --> lib.rs:1:1 + | +1 | / #![warn(missing_docs)] +2 | | +3 | | pub fn foo() {} + | |_______________^ + | +note: lint level defined here + --> lib.rs:1:9 + | +1 | #![warn(missing_docs)] + | ^^^^^^^^^^^^ + +warning: missing documentation for a function + --> lib.rs:3:1 + | +3 | pub fn foo() {} + | ^^^^^^^^^^^^ +``` + +All four, `warn`, `allow`, `deny`, and `forbid` all work this way. + +You can also pass in multiple lints per attribute: + +```rust +#![warn(missing_docs, unused_variables)] + +pub fn foo() {} +``` + +And use multiple attributes together: + +```rust +#![warn(missing_docs)] +#![deny(unused_variables)] + +pub fn foo() {} +``` + +### Capping lints + +`rustc` supports a flag, `--cap-lints LEVEL` that sets the "lint cap level." +This is the maximum level for all lints. So for example, if we take our +code sample from the "deny" lint level above: + +```rust,ignore +fn main() { + 100u8 << 10; +} +``` + +And we compile it, capping lints to warn: + +```bash +$ rustc lib.rs --cap-lints warn +warning: bitshift exceeds the type's number of bits + --> lib.rs:2:5 + | +2 | 100u8 << 10; + | ^^^^^^^^^^^ + | + = note: #[warn(exceeding_bitshifts)] on by default + +warning: this expression will panic at run-time + --> lib.rs:2:5 + | +2 | 100u8 << 10; + | ^^^^^^^^^^^ attempt to shift left with overflow +``` + +It now only warns, rather than errors. We can go further and allow all lints: + +```bash +$ rustc lib.rs --cap-lints allow +$ +``` + +This feature is used heavily by Cargo; it will pass `--cap-lints allow` when +compiling your dependencies, so that if they have any warnings, they do not +pollute the output of your build. diff --git a/src/doc/rustc/src/lints/listing/allowed-by-default.md b/src/doc/rustc/src/lints/listing/allowed-by-default.md new file mode 100644 index 00000000000..e1a3f96a6fe --- /dev/null +++ b/src/doc/rustc/src/lints/listing/allowed-by-default.md @@ -0,0 +1,453 @@ +# Allowed-by-default lints + +These lints are all set to the 'allow' level by default. As such, they won't show up +unless you set them to a higher lint level with a flag or attribute. + +## anonymous-parameters + +This lint detects anonymous parameters. Some example code that triggers this lint: + +```rust +trait Foo { + fn foo(usize); +} +``` + +When set to 'deny', this will produce: + +```text +error: use of deprecated anonymous parameter + --> src/lib.rs:5:11 + | +5 | fn foo(usize); + | ^ + | + = 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 #41686 <https://github.com/rust-lang/rust/issues/41686> +``` + +This syntax is mostly a historical accident, and can be worked around quite +easily: + +```rust +trait Foo { + fn foo(_: usize); +} +``` + +## bare-trait-object + +This lint suggests using `dyn Trait` for trait objects. Some example code +that triggers this lint: + +```rust +#![feature(dyn_trait)] + +trait Trait { } + +fn takes_trait_object(_: Box<Trait>) { +} +``` + +When set to 'deny', this will produce: + +```text +error: trait objects without an explicit `dyn` are deprecated + --> src/lib.rs:7:30 + | +7 | fn takes_trait_object(_: Box<Trait>) { + | ^^^^^ help: use `dyn`: `dyn Trait` + | +``` + +To fix it, do as the help message suggests: + +```rust +#![feature(dyn_trait)] +#![deny(bare_trait_object)] + +trait Trait { } + +fn takes_trait_object(_: Box<dyn Trait>) { +} +``` + +## box-pointers + +This lints use of the Box type. Some example code that triggers this lint: + +```rust +struct Foo { + x: Box<isize>, +} +``` + +When set to 'deny', this will produce: + +```text +error: type uses owned (Box type) pointers: std::boxed::Box<isize> + --> src/lib.rs:6:5 + | +6 | x: Box<isize> //~ ERROR type uses owned + | ^^^^^^^^^^^^^ + | +``` + +This lint is mostly historical, and not particularly useful. `Box<T>` used to +be built into the language, and the only way to do heap allocation. Today's +Rust can call into other allocators, etc. + +## elided-lifetime-in-path + +This lint detects the use of hidden lifetime parameters. Some example code +that triggers this lint: + +```rust +struct Foo<'a> { + x: &'a u32 +} + +fn foo(x: &Foo) { +} +``` + +When set to 'deny', this will produce: + +```text +error: hidden lifetime parameters are deprecated, try `Foo<'_>` + --> src/lib.rs:5:12 + | +5 | fn foo(x: &Foo) { + | ^^^ + | +``` + +Lifetime elision elides this lifetime, but that is being deprecated. + +## missing-copy-implementations + +This lint detects potentially-forgotten implementations of `Copy`. Some +example code that triggers this lint: + +```rust +pub struct Foo { + pub field: i32 +} +``` + +When set to 'deny', this will produce: + +```text +error: type could implement `Copy`; consider adding `impl Copy` + --> src/main.rs:3:1 + | +3 | / pub struct Foo { //~ ERROR type could implement `Copy`; consider adding `impl Copy` +4 | | pub field: i32 +5 | | } + | |_^ + | +``` + +You can fix the lint by deriving `Copy`. + +This lint is set to 'allow' because this code isn't bad; it's common to write +newtypes like this specifically so that a `Copy` type is no longer `Copy`. + +## missing-debug-implementations + +This lint detects missing implementations of `fmt::Debug`. Some example code +that triggers this lint: + +```rust +pub struct Foo; +``` + +When set to 'deny', this will produce: + +```text +error: type does not implement `fmt::Debug`; consider adding #[derive(Debug)] or a manual implementation + --> src/main.rs:3:1 + | +3 | pub struct Foo; + | ^^^^^^^^^^^^^^^ + | +``` + +You can fix the lint by deriving `Debug`. + +## missing-docs + +This lint detects missing documentation for public items. Some example code +that triggers this lint: + +```rust +pub fn foo() {} +``` + +When set to 'deny', this will produce: + +```text +error: missing documentation for crate + --> src/main.rs:1:1 + | +1 | / #![deny(missing_docs)] +2 | | +3 | | pub fn foo() {} +4 | | +5 | | fn main() {} + | |____________^ + | + +error: missing documentation for a function + --> src/main.rs:3:1 + | +3 | pub fn foo() {} + | ^^^^^^^^^^^^ + +``` + +To fix the lint, add documentation to all items. + +## single-use-lifetime + +This lint detects lifetimes that are only used once. Some example code that +triggers this lint: + +```rust +struct Foo<'x> { + x: &'x u32 +} +``` + +When set to 'deny', this will produce: + +```text +error: lifetime name `'x` only used once + --> src/main.rs:3:12 + | +3 | struct Foo<'x> { + | ^^ + | +``` + +## trivial-casts + +This lint detects trivial casts which could be removed. Some example code +that triggers this lint: + +```rust +let x: &u32 = &42; +let _ = x as *const u32; +``` + +When set to 'deny', this will produce: + +```text +error: trivial cast: `&u32` as `*const u32`. Cast can be replaced by coercion, this might require type ascription or a temporary variable + --> src/main.rs:5:13 + | +5 | let _ = x as *const u32; + | ^^^^^^^^^^^^^^^ + | +note: lint level defined here + --> src/main.rs:1:9 + | +1 | #![deny(trivial_casts)] + | ^^^^^^^^^^^^^ +``` + +## trivial-numeric-casts + +This lint detects trivial casts of numeric types which could be removed. Some +example code that triggers this lint: + +```rust +let x = 42i32 as i32; +``` + +When set to 'deny', this will produce: + +```text +error: trivial numeric cast: `i32` as `i32`. Cast can be replaced by coercion, this might require type ascription or a temporary variable + --> src/main.rs:4:13 + | +4 | let x = 42i32 as i32; + | ^^^^^^^^^^^^ + | +``` + +## unreachable-pub + +This lint triggers for `pub` items not reachable from the crate root. Some +example code that triggers this lint: + +```rust +mod foo { + pub mod bar { + + } +} +``` + +When set to 'deny', this will produce: + +```text +error: unreachable `pub` item + --> src/main.rs:4:5 + | +4 | pub mod bar { + | ---^^^^^^^^ + | | + | help: consider restricting its visibility: `pub(crate)` + | +``` + +## unsafe-code + +This lint catches usage of `unsafe` code. Some example code that triggers this lint: + +```rust +fn main() { + unsafe { + + } +} +``` + +When set to 'deny', this will produce: + +```text +error: usage of an `unsafe` block + --> src/main.rs:4:5 + | +4 | / unsafe { +5 | | +6 | | } + | |_____^ + | +``` + +## unstable-features + +This lint is deprecated and no longer used. + +## unused-extern-crates + +This lint guards against `extern crate` items that are never used. Some +example code that triggers this lint: + +```rust,ignore +extern crate semver; +``` + +When set to 'deny', this will produce: + +```text +error: unused extern crate + --> src/main.rs:3:1 + | +3 | extern crate semver; + | ^^^^^^^^^^^^^^^^^^^^ + | +``` + +## unused-import-braces + +This lint catches unnecessary braces around an imported item. Some example +code that triggers this lint: + +```rust +use test::{A}; + +pub mod test { + pub struct A; +} +# fn main() {} +``` + +When set to 'deny', this will produce: + +```text +error: braces around A is unnecessary + --> src/main.rs:3:1 + | +3 | use test::{A}; + | ^^^^^^^^^^^^^^ + | +``` + +To fix it, `use test::A;` + +## unused-qualifications + +This lint detects unnecessarily qualified names. Some example code that triggers this lint: + +```rust +mod foo { + pub fn bar() {} +} + +fn main() { + use foo::bar; + foo::bar(); +} +``` + +When set to 'deny', this will produce: + +```text +error: unnecessary qualification + --> src/main.rs:9:5 + | +9 | foo::bar(); + | ^^^^^^^^ + | +``` + +You can call `bar()` directly, without the `foo::`. + +## unused-results + +This lint checks for the unused result of an expression in a statement. Some +example code that triggers this lint: + +```rust,no_run +fn foo<T>() -> T { panic!() } + +fn main() { + foo::<usize>(); +} +``` + +When set to 'deny', this will produce: + +```text +error: unused result + --> src/main.rs:6:5 + | +6 | foo::<usize>(); + | ^^^^^^^^^^^^^^^ + | +``` + +## variant-size-differences + +This lint detects enums with widely varying variant sizes. Some example code that triggers this lint: + +```rust +enum En { + V0(u8), + VBig([u8; 1024]), +} +``` + +When set to 'deny', this will produce: + +```text +error: enum variant is more than three times larger (1024 bytes) than the next largest + --> src/main.rs:5:5 + | +5 | VBig([u8; 1024]), //~ ERROR variant is more than three times larger + | ^^^^^^^^^^^^^^^^ + | +``` diff --git a/src/doc/rustc/src/lints/listing/deny-by-default.md b/src/doc/rustc/src/lints/listing/deny-by-default.md new file mode 100644 index 00000000000..e7ec6af8be1 --- /dev/null +++ b/src/doc/rustc/src/lints/listing/deny-by-default.md @@ -0,0 +1,241 @@ +# Deny-by-default lints + +These lints are all set to the 'deny' level by default. + +## exceeding-bitshifts + +This lint detects that a shift exceeds the type's number of bits. Some +example code that triggers this lint: + +```rust,ignore +1_i32 << 32; +``` + +This will produce: + +```text +error: bitshift exceeds the type's number of bits + --> src/main.rs:2:5 + | +2 | 1_i32 << 32; + | ^^^^^^^^^^^ + | +``` + +## invalid-type-param-default + +This lint detects type parameter default erroneously allowed in invalid location. Some +example code that triggers this lint: + +```rust,ignore +fn foo<T=i32>(t: T) {} +``` + +This will produce: + +```text +error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions. + --> src/main.rs:4:8 + | +4 | fn foo<T=i32>(t: T) {} + | ^ + | + = note: #[deny(invalid_type_param_default)] on by default + = 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 #36887 <https://github.com/rust-lang/rust/issues/36887> +``` + +## legacy-constructor-visibility + +[RFC 1506](https://github.com/rust-lang/rfcs/blob/master/text/1506-adt-kinds.md) modified some +visibility rules, and changed the visibility of struct constructors. Some +example code that triggers this lint: + +```rust,ignore +mod m { + pub struct S(u8); + + fn f() { + // this is trying to use S from the 'use' line, but becuase the `u8` is + // not pub, it is private + ::S; + } +} + +use m::S; +``` + +This will produce: + +```text +error: private struct constructors are not usable through re-exports in outer modules + --> src/main.rs:5:9 + | +5 | ::S; + | ^^^ + | + = note: #[deny(legacy_constructor_visibility)] on by default + = 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 #39207 <https://github.com/rust-lang/rust/issues/39207> +``` + + +## legacy-directory-ownership + +The legacy_directory_ownership warning is issued when + +* There is a non-inline module with a #[path] attribute (e.g. #[path = "foo.rs"] mod bar;), +* The module's file ("foo.rs" in the above example) is not named "mod.rs", and +* The module's file contains a non-inline child module without a #[path] attribute. + +The warning can be fixed by renaming the parent module to "mod.rs" and moving +it into its own directory if appropriate. + +## legacy-imports + +This lint detects names that resolve to ambiguous glob imports. Some example +code that triggers this lint: + +```rust,ignore +pub struct Foo; + +mod bar { + struct Foo; + + mod baz { + use *; + use bar::*; + fn f(_: Foo) {} + } +} +``` + +This will produce: + +```text +error: `Foo` is ambiguous + --> src/main.rs:9:17 + | +7 | use *; + | - `Foo` could refer to the name imported here +8 | use bar::*; + | ------ `Foo` could also refer to the name imported here +9 | fn f(_: Foo) {} + | ^^^ + | + = note: #[deny(legacy_imports)] on by default + = 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 #38260 <https://github.com/rust-lang/rust/issues/38260> +``` + + +## missing-fragment-specifier + +The missing_fragment_specifier warning is issued when an unused pattern in a +`macro_rules!` macro definition has a meta-variable (e.g. `$e`) that is not +followed by a fragment specifier (e.g. `:expr`). + +This warning can always be fixed by removing the unused pattern in the +`macro_rules!` macro definition. + +## mutable-transmutes + +This lint catches transmuting from `&T` to `&mut T` becuase it is undefined +behavior. Some example code that triggers this lint: + +```rust,ignore +unsafe { + let y = std::mem::transmute::<&i32, &mut i32>(&5); +} +``` + +This will produce: + +```text +error: mutating transmuted &mut T from &T may cause undefined behavior, consider instead using an UnsafeCell + --> src/main.rs:3:17 + | +3 | let y = std::mem::transmute::<&i32, &mut i32>(&5); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +``` + + +## no-mangle-const-items + +This lint detects any `const` items with the `#[no_mangle]` attribute. +Constants do not have their symbols exported, and therefore, this probably +means you meant to use a `static`, not a `const`. Some example code that +triggers this lint: + +```rust,ignore +#[no_mangle] +const FOO: i32 = 5; +``` + +This will produce: + +```text +error: const items should never be #[no_mangle] + --> src/main.rs:3:1 + | +3 | const FOO: i32 = 5; + | -----^^^^^^^^^^^^^^ + | | + | help: try a static value: `pub static` + | +``` + +## parenthesized-params-in-types-and-modules + +This lint detects incorrect parentheses. Some example code that triggers this +lint: + +```rust,ignore +let x = 5 as usize(); +``` + +This will produce: + +```text +error: parenthesized parameters may only be used with a trait + --> src/main.rs:2:21 + | +2 | let x = 5 as usize(); + | ^^ + | + = note: #[deny(parenthesized_params_in_types_and_modules)] on by default + = 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 #42238 <https://github.com/rust-lang/rust/issues/42238> +``` + +To fix it, remove the `()`s. + +## pub-use-of-private-extern-crate + +This lint detects a specific situation of re-exporting a private `extern crate`; + +## safe-extern-statics + +In older versions of Rust, there was a soundness issue where `extern static`s were allowed +to be accessed in safe code. This lint now catches and denies this kind of code. + +## unknown-crate-types + +This lint detects an unknown crate type found in a `#[crate_type]` directive. Some +example code that triggers this lint: + +```rust,ignore +#![crate_type="lol"] +``` + +This will produce: + +```text +error: invalid `crate_type` value + --> src/lib.rs:1:1 + | +1 | #![crate_type="lol"] + | ^^^^^^^^^^^^^^^^^^^^ + | +``` diff --git a/src/doc/rustc/src/lints/listing/index.md b/src/doc/rustc/src/lints/listing/index.md new file mode 100644 index 00000000000..18cd2fe32a3 --- /dev/null +++ b/src/doc/rustc/src/lints/listing/index.md @@ -0,0 +1,5 @@ +# Lint listing + +This section lists out all of the lints, grouped by their default lint levels. + +You can also see this list by running `rustc -W help`. \ No newline at end of file diff --git a/src/doc/rustc/src/lints/listing/warn-by-default.md b/src/doc/rustc/src/lints/listing/warn-by-default.md new file mode 100644 index 00000000000..1171f75caa1 --- /dev/null +++ b/src/doc/rustc/src/lints/listing/warn-by-default.md @@ -0,0 +1,1039 @@ +# Warn-by-default lints + +These lints are all set to the 'warn' level by default. + +## const-err + +This lint detects an erroneous expression while doing constant evaluation. Some +example code that triggers this lint: + +```rust,ignore +let b = 200u8 + 200u8; +``` + +This will produce: + +```text +warning: attempt to add with overflow + --> src/main.rs:2:9 + | +2 | let b = 200u8 + 200u8; + | ^^^^^^^^^^^^^ + | +``` + +## dead-code + +This lint detects detect unused, unexported items. Some +example code that triggers this lint: + +```rust +fn foo() {} +``` + +This will produce: + +```text +warning: function is never used: `foo` + --> src/lib.rs:2:1 + | +2 | fn foo() {} + | ^^^^^^^^ + | +``` + +## deprecated + +This lint detects detects use of deprecated items. Some +example code that triggers this lint: + +```rust +#[deprecated] +fn foo() {} + +fn bar() { + foo(); +} +``` + +This will produce: + +```text +warning: use of deprecated item 'foo' + --> src/lib.rs:7:5 + | +7 | foo(); + | ^^^ + | +``` + +## illegal-floating-point-literal-pattern + +This lint detects floating-point literals used in patterns. Some example code +that triggers this lint: + +```rust +let x = 42.0; + +match x { + 5.0 => {}, + _ => {}, +} +``` + +This will produce: + +```text +warning: floating-point literals cannot be used in patterns + --> src/main.rs:4:9 + | +4 | 5.0 => {}, + | ^^^ + | + = note: #[warn(illegal_floating_point_literal_pattern)] on by default + = 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 #41620 <https://github.com/rust-lang/rust/issues/41620> +``` + +## improper-ctypes + +This lint detects proper use of libc types in foreign modules. Some +example code that triggers this lint: + +```rust +extern "C" { + static STATIC: String; +} +``` + +This will produce: + +```text +warning: found struct without foreign-function-safe representation annotation in foreign module, consider adding a #[repr(C)] attribute to the type + --> src/main.rs:2:20 + | +2 | static STATIC: String; + | ^^^^^^ + | +``` + +## incoherent-fundamental-impls + +This lint detects potentially-conflicting impls that were erroneously allowed. Some +example code that triggers this lint: + +```rust +pub trait Trait1<X> { + type Output; +} + +pub trait Trait2<X> {} + +pub struct A; + +impl<X, T> Trait1<X> for T where T: Trait2<X> { + type Output = (); +} + +impl<X> Trait1<Box<X>> for A { + type Output = i32; +} +``` + +This will produce: + +```text +warning: conflicting implementations of trait `Trait1<std::boxed::Box<_>>` for type `A`: (E0119) + --> src/main.rs:13:1 + | +9 | impl<X, T> Trait1<X> for T where T: Trait2<X> { + | --------------------------------------------- first implementation here +... +13 | impl<X> Trait1<Box<X>> for A { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `A` + | + = note: #[warn(incoherent_fundamental_impls)] on by default + = 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 #46205 <https://github.com/rust-lang/rust/issues/46205> + = note: downstream crates may implement trait `Trait2<std::boxed::Box<_>>` for type `A` +``` + +## late-bound-lifetime-arguments + +This lint detects detects generic lifetime arguments in path segments with +late bound lifetime parameters. Some example code that triggers this lint: + +```rust +struct S; + +impl S { + fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {} +} + +fn main() { + S.late::<'static>(&0, &0); +} +``` + +This will produce: + +```text +warning: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present + --> src/main.rs:8:14 + | +4 | fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {} + | -- the late bound lifetime parameter is introduced here +... +8 | S.late::<'static>(&0, &0); + | ^^^^^^^ + | + = note: #[warn(late_bound_lifetime_arguments)] on by default + = 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 #42868 <https://github.com/rust-lang/rust/issues/42868> +``` + +## non-camel-case-types + +This lint detects types, variants, traits and type parameters that don't have +camel case names. Some example code that triggers this lint: + +```rust +struct s; +``` + +This will produce: + +```text +warning: type `s` should have a camel case name such as `S` + --> src/main.rs:1:1 + | +1 | struct s; + | ^^^^^^^^^ + | +``` + +## non-shorthand-field-patterns + +This lint detects using `Struct { x: x }` instead of `Struct { x }` in a pattern. Some +example code that triggers this lint: + +```rust +struct Point { + x: i32, + y: i32, +} + + +fn main() { + let p = Point { + x: 5, + y: 5, + }; + + match p { + Point { x: x, y: y } => (), + } +} +``` + +This will produce: + +```text +warning: the `x:` in this pattern is redundant + --> src/main.rs:14:17 + | +14 | Point { x: x, y: y } => (), + | --^^ + | | + | help: remove this + | + +warning: the `y:` in this pattern is redundant + --> src/main.rs:14:23 + | +14 | Point { x: x, y: y } => (), + | --^^ + | | + | help: remove this + +``` + +## non-snake-case + +This lint detects variables, methods, functions, lifetime parameters and +modules that don't have snake case names. Some example code that triggers +this lint: + +```rust +let X = 5; +``` + +This will produce: + +```text +warning: variable `X` should have a snake case name such as `x` + --> src/main.rs:2:9 + | +2 | let X = 5; + | ^ + | +``` + +## non-upper-case-globals + +This lint detects static constants that don't have uppercase identifiers. +Some example code that triggers this lint: + +```rust +static x: i32 = 5; +``` + +This will produce: + +```text +warning: static variable `x` should have an upper case name such as `X` + --> src/main.rs:1:1 + | +1 | static x: i32 = 5; + | ^^^^^^^^^^^^^^^^^^ + | +``` + +## no-mangle-generic-items + +This lint detects generic items must be mangled. Some +example code that triggers this lint: + +```rust +#[no_mangle] +fn foo<T>(t: T) { + +} +``` + +This will produce: + +```text +warning: functions generic over types must be mangled + --> src/main.rs:2:1 + | +1 | #[no_mangle] + | ------------ help: remove this attribute +2 | / fn foo<T>(t: T) { +3 | | +4 | | } + | |_^ + | +``` + +## overflowing-literals + +This lint detects literal out of range for its type. Some +example code that triggers this lint: + +```rust +let x: u8 = 1000; +``` + +This will produce: + +```text +warning: literal out of range for u8 + --> src/main.rs:2:17 + | +2 | let x: u8 = 1000; + | ^^^^ + | +``` + +## path-statements + +This lint detects path statements with no effect. Some example code that +triggers this lint: + +```rust +let x = 42; + +x; +``` + +This will produce: + +```text +warning: path statement with no effect + --> src/main.rs:3:5 + | +3 | x; + | ^^ + | +``` + +## patterns-in-fns-without-body + +This lint detects patterns in functions without body were that were +previously erroneously allowed. Some example code that triggers this lint: + +```rust +trait Trait { + fn foo(mut arg: u8); +} +``` + +This will produce: + +```text +warning: patterns aren't allowed in methods without bodies + --> src/main.rs:2:12 + | +2 | fn foo(mut arg: u8); + | ^^^^^^^ + | + = note: #[warn(patterns_in_fns_without_body)] on by default + = 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 #35203 <https://github.com/rust-lang/rust/issues/35203> +``` + +To fix this, remove the pattern; it can be used in the implementation without +being used in the definition. That is: + +```rust +trait Trait { + fn foo(arg: u8); +} + +impl Trait for i32 { + fn foo(mut arg: u8) { + + } +} +``` + +## plugin-as-library + +This lint detects when compiler plugins are used as ordinary library in +non-plugin crate. Some example code that triggers this lint: + +```rust,ignore +#![feature(plugin)] +#![plugin(macro_crate_test)] + +extern crate macro_crate_test; +``` + +## private-in-public + +This lint detects detect private items in public interfaces not caught by the old implementation. Some +example code that triggers this lint: + +```rust,ignore +pub trait Trait { + type A; +} + +pub struct S; + +mod foo { + struct Z; + + impl ::Trait for ::S { + type A = Z; + } +} +# fn main() {} +``` + +This will produce: + +```text +error[E0446]: private type `foo::Z` in public interface + --> src/main.rs:11:9 + | +11 | type A = Z; + | ^^^^^^^^^^^ can't leak private type +``` + +## private-no-mangle-fns + +This lint detects functions marked `#[no_mangle]` that are also private. +Given that private functions aren't exposed publicly, and `#[no_mangle]` +controls the public symbol, this combination is erroneous. Some example code +that triggers this lint: + +```rust +#[no_mangle] +fn foo() {} +``` + +This will produce: + +```text +warning: function is marked #[no_mangle], but not exported + --> src/main.rs:2:1 + | +2 | fn foo() {} + | -^^^^^^^^^^ + | | + | help: try making it public: `pub` + | +``` + +To fix this, either make it public or remove the `#[no_mangle]`. + +## private-no-mangle-statics + +This lint detects any statics marked `#[no_mangle]` that are private. +Given that private statics aren't exposed publicly, and `#[no_mangle]` +controls the public symbol, this combination is erroneous. Some example code +that triggers this lint: + +```rust +#[no_mangle] +static X: i32 = 4; +``` + +This will produce: + +```text +warning: static is marked #[no_mangle], but not exported + --> src/main.rs:2:1 + | +2 | static X: i32 = 4; + | -^^^^^^^^^^^^^^^^^ + | | + | help: try making it public: `pub` + | +``` + +To fix this, either make it public or remove the `#[no_mangle]`. + +## renamed-and-removed-lints + +This lint detects lints that have been renamed or removed. Some +example code that triggers this lint: + +```rust +#![deny(raw_pointer_derive)] +``` + +This will produce: + +```text +warning: lint raw_pointer_derive has been removed: using derive with raw pointers is ok + --> src/main.rs:1:9 + | +1 | #![deny(raw_pointer_derive)] + | ^^^^^^^^^^^^^^^^^^ + | +``` + +To fix this, either remove the lint or use the new name. + +## safe-packed-borrows + +This lint detects borrowing a field in the interior of a packed structure +with alignment other than 1. Some example code that triggers this lint: + +```rust +#[repr(packed)] +pub struct Unaligned<T>(pub T); + +pub struct Foo { + start: u8, + data: Unaligned<u32>, +} + +fn main() { + let x = Foo { start: 0, data: Unaligned(1) }; + let y = &x.data.0; +} +``` + +This will produce: + +```text +warning: borrow of packed field requires unsafe function or block (error E0133) + --> src/main.rs:11:13 + | +11 | let y = &x.data.0; + | ^^^^^^^^^ + | + = note: #[warn(safe_packed_borrows)] on by default + = 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 #46043 <https://github.com/rust-lang/rust/issues/46043> +``` + +## stable-features + +This lint detects a `#[feature]` attribute that's since been made stable. Some +example code that triggers this lint: + +```rust +#![feature(test_accepted_feature)] +``` + +This will produce: + +```text +warning: this feature has been stable since 1.0.0. Attribute no longer needed + --> src/main.rs:1:12 + | +1 | #![feature(test_accepted_feature)] + | ^^^^^^^^^^^^^^^^^^^^^ + | +``` + +To fix, simply remove the `#![feature]` attribute, as it's no longer needed. + +## type-alias-bounds + +This lint detects bounds in type aliases. These are not currently enforced. +Some example code that triggers this lint: + +```rust +type SendVec<T: Send> = Vec<T>; +``` + +This will produce: + +```text +warning: type alias is never used: `SendVec` + --> src/main.rs:1:1 + | +1 | type SendVec<T: Send> = Vec<T>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +``` + +## tyvar-behind-raw-pointer + +This lint detects raw pointer to an inference variable. Some +example code that triggers this lint: + +```rust +let data = std::ptr::null(); +let _ = &data as *const *const (); + +if data.is_null() {} +``` + +This will produce: + +```text +warning: type annotations needed + --> src/main.rs:4:13 + | +4 | if data.is_null() {} + | ^^^^^^^ + | + = note: #[warn(tyvar_behind_raw_pointer)] on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition! + = note: for more information, see issue #46906 <https://github.com/rust-lang/rust/issues/46906> +``` + +## unconditional-recursion + +This lint detects functions that cannot return without calling themselves. +Some example code that triggers this lint: + +```rust +fn foo() { + foo(); +} +``` + +This will produce: + +```text +warning: function cannot return without recurring + --> src/main.rs:1:1 + | +1 | fn foo() { + | ^^^^^^^^ cannot return without recurring +2 | foo(); + | ----- recursive call site + | +``` + +## unions-with-drop-fields + +This lint detects use of unions that contain fields with possibly non-trivial drop code. Some +example code that triggers this lint: + +```rust +#![feature(untagged_unions)] + +union U { + s: String, +} +``` + +This will produce: + +```text +warning: union contains a field with possibly non-trivial drop code, drop code of union fields is ignored when dropping the union + --> src/main.rs:4:5 + | +4 | s: String, + | ^^^^^^^^^ + | +``` + +## unknown-lints + +This lint detects unrecognized lint attribute. Some +example code that triggers this lint: + +```rust,ignore +#[allow(not_a_real_lint)] +``` + +This will produce: + +```text +warning: unknown lint: `not_a_real_lint` + --> src/main.rs:1:10 + | +1 | #![allow(not_a_real_lint)] + | ^^^^^^^^^^^^^^^ + | +``` + +## unreachable-code + +This lint detects detects unreachable code paths. Some example code that +triggers this lint: + +```rust,no_run +panic!("we never go past here!"); + +let x = 5; +``` + +This will produce: + +```text +warning: unreachable statement + --> src/main.rs:4:5 + | +4 | let x = 5; + | ^^^^^^^^^^ + | +``` + +## unreachable-patterns + +This lint detects detects unreachable patterns. Some +example code that triggers this lint: + +```rust +let x = 5; +match x { + y => (), + 5 => (), +} +``` + +This will produce: + +```text +warning: unreachable pattern + --> src/main.rs:5:5 + | +5 | 5 => (), + | ^ + | +``` + +The `y` pattern will always match, so the five is impossible to reach. +Remember, match arms match in order, you probably wanted to put the `5` case +above the `y` case. + +## unstable-name-collision + +This lint detects that you've used a name that the standard library plans to +add in the future, which means that your code may fail to compile without +additional type annotations in the future. Either rename, or add those +annotations now. + +## unused-allocation + +This lint detects detects unnecessary allocations that can be eliminated. + +## unused-assignments + +This lint detects detect assignments that will never be read. Some +example code that triggers this lint: + +```rust +let mut x = 5; +x = 6; +``` + +This will produce: + +```text +warning: value assigned to `x` is never read + --> src/main.rs:4:5 + | +4 | x = 6; + | ^ + | +``` + +## unused-attributes + +This lint detects detects attributes that were not used by the compiler. Some +example code that triggers this lint: + +```rust +#![feature(custom_attribute)] + +#![mutable_doc] +``` + +This will produce: + +```text +warning: unused attribute + --> src/main.rs:4:1 + | +4 | #![mutable_doc] + | ^^^^^^^^^^^^^^^ + | +``` + +## unused-comparisons + +This lint detects comparisons made useless by limits of the types involved. Some +example code that triggers this lint: + +```rust +fn foo(x: u8) { + x >= 0; +} +``` + +This will produce: + +```text +warning: comparison is useless due to type limits + --> src/main.rs:6:5 + | +6 | x >= 0; + | ^^^^^^ + | +``` + +## unused-doc-comment + +This lint detects detects doc comments that aren't used by rustdoc. Some +example code that triggers this lint: + +```rust +/// docs for x +let x = 12; +``` + +This will produce: + +```text +warning: doc comment not used by rustdoc + --> src/main.rs:2:5 + | +2 | /// docs for x + | ^^^^^^^^^^^^^^ + | +``` + +## unused-features + +This lint detects unused or unknown features found in crate-level #[feature] directives. +To fix this, simply remove the feature flag. + +## unused-imports + +This lint detects imports that are never used. Some +example code that triggers this lint: + +```rust +use std::collections::HashMap; +``` + +This will produce: + +```text +warning: unused import: `std::collections::HashMap` + --> src/main.rs:1:5 + | +1 | use std::collections::HashMap; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +``` + +## unused-macros + +This lint detects detects macros that were not used. Some example code that +triggers this lint: + +```rust +macro_rules! unused { + () => {}; +} + +fn main() { +} +``` + +This will produce: + +```text +warning: unused macro definition + --> src/main.rs:1:1 + | +1 | / macro_rules! unused { +2 | | () => {}; +3 | | } + | |_^ + | +``` + +## unused-must-use + +This lint detects unused result of a type flagged as #[must_use]. Some +example code that triggers this lint: + +```rust +fn returns_result() -> Result<(), ()> { + Ok(()) +} + +fn main() { + returns_result(); +} +``` + +This will produce: + +```text +warning: unused `std::result::Result` which must be used + --> src/main.rs:6:5 + | +6 | returns_result(); + | ^^^^^^^^^^^^^^^^^ + | +``` + +## unused-mut + +This lint detects detect mut variables which don't need to be mutable. Some +example code that triggers this lint: + +```rust +let mut x = 5; +``` + +This will produce: + +```text +warning: variable does not need to be mutable + --> src/main.rs:2:9 + | +2 | let mut x = 5; + | ----^ + | | + | help: remove this `mut` + | +``` + +## unused-parens + +This lint detects `if`, `match`, `while` and `return` with parentheses; they +do not need them. Some example code that triggers this lint: + +```rust +if(true) {} +``` + +This will produce: + +```text +warning: unnecessary parentheses around `if` condition + --> src/main.rs:2:7 + | +2 | if(true) {} + | ^^^^^^ help: remove these parentheses + | +``` + +## unused-unsafe + +This lint detects unnecessary use of an `unsafe` block. Some +example code that triggers this lint: + +```rust +unsafe {} +``` + +This will produce: + +```text +warning: unnecessary `unsafe` block + --> src/main.rs:2:5 + | +2 | unsafe {} + | ^^^^^^ unnecessary `unsafe` block + | +``` + +## unused-variables + +This lint detects detect variables which are not used in any way. Some +example code that triggers this lint: + +```rust +let x = 5; +``` + +This will produce: + +```text +warning: unused variable: `x` + --> src/main.rs:2:9 + | +2 | let x = 5; + | ^ help: consider using `_x` instead + | +``` + +## warnings + +This lint is a bit special; by changing its level, you change every other warning +that would produce a warning to whatever value you'd like: + +```rust +#![deny(warnings)] +``` + +As such, you won't ever trigger this lint in your code directly. + +## while-true + +This lint detects `while true { }`. Some example code that triggers this +lint: + +```rust,no_run +while true { + +} +``` + +This will produce: + +```text +warning: denote infinite loops with `loop { ... }` + --> src/main.rs:2:5 + | +2 | while true { + | ^^^^^^^^^^ help: use `loop` + | +``` diff --git a/src/doc/rustc/src/targets/built-in.md b/src/doc/rustc/src/targets/built-in.md new file mode 100644 index 00000000000..8620346e5b7 --- /dev/null +++ b/src/doc/rustc/src/targets/built-in.md @@ -0,0 +1,10 @@ +# Built-in Targets + +`rustc` ships with the ability to compile to many targets automatically, we +call these "built-in" targets, and they generally correspond to targets that +the team is supporting directly. + +To see the list of built-in targets, you can run `rustc --print target-list`, +or look at [the API +docs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_back/target/#modules). +Each module there defines a builder for a particular target. \ No newline at end of file diff --git a/src/doc/rustc/src/targets/custom.md b/src/doc/rustc/src/targets/custom.md new file mode 100644 index 00000000000..0691afc60ea --- /dev/null +++ b/src/doc/rustc/src/targets/custom.md @@ -0,0 +1,17 @@ +# Custom Targets + +If you'd like to build for a target that is not yet supported by `rustc`, you can use a +"custom target specification" to define a target. These target specification files +are JSON. To see the JSON for the host target, you can run: + +```bash +$ rustc +nightly -Z unstable-options --print target-spec-json +``` + +To see it for a different target, add the `--target` flag: + +```bash +$ rustc +nightly -Z unstable-options --target=wasm32-unknown-unknown --print target-spec-json +``` + +To use a custom target, see [`xargo`](https://github.com/japaric/xargo). \ No newline at end of file diff --git a/src/doc/rustc/src/targets/index.md b/src/doc/rustc/src/targets/index.md new file mode 100644 index 00000000000..07e3a79471f --- /dev/null +++ b/src/doc/rustc/src/targets/index.md @@ -0,0 +1,13 @@ +# Targets + +`rustc` is a cross-compiler by default. This means that you can use any compiler to build for any +architecture. The list of *targets* are the possible architectures that you can build for. + +To see all the options that you can set with a target, see the docs +[here](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_back/target/struct.Target.html). + +To compile to a particular target, use the `--target` flag: + +```bash +$ rustc src/main.rs --target=wasm32-unknown-unknown +``` diff --git a/src/doc/rustc/src/what-is-rustc.md b/src/doc/rustc/src/what-is-rustc.md new file mode 100644 index 00000000000..bed1b71c24e --- /dev/null +++ b/src/doc/rustc/src/what-is-rustc.md @@ -0,0 +1,68 @@ +# What is rustc? + +Welcome to "The rustc book"! `rustc` is the compiler for the Rust programming +language, provided by the project itself. Compilers take your source code and +produce binary code, either as a library or executable. + +Most Rust programmers don't invoke `rustc` directly, but instead do it through +[Cargo](../cargo/index.html). It's all in service of `rustc` though! If you +want to see how Cargo calls `rustc`, you can + +```bash +$ cargo build --verbose +``` + +And it will print out each `rustc` invocation. This book can help you +understand what each of these options does. Additionally, while most +Rustaceans use Cargo, not all do: sometimes they integrate `rustc` into other +build systems. This book should provide a guide to all of the options you'd +need to do so. + +## Basic usage + +Let's say you've got a little hello world program in a file `hello.rs`: + +```rust +fn main() { + println!("Hello, world!"); +} +``` + +To turn this source code into an executable, you can use `rustc`: + +```bash +$ rustc hello.rs +$ ./hello # on a *NIX +$ .\hello.exe # on Windows +``` + +Note that we only ever pass `rustc` the *crate root*, not every file we wish +to compile. For example, if we had a `main.rs` that looked like this: + +```rust,ignore +mod foo; + +fn main() { + foo::hello(); +} +``` + +And a `foo.rs` that had this: + +```rust,ignore +fn hello() { + println!("Hello, world!"); +} +``` + +To compile this, we'd run this command: + +```bash +$ rustc main.rs +``` + +No need to tell `rustc` about `foo.rs`; the `mod` statements give it +everything that it needs. This is different than how you would use a C +compiler, where you invoke the compiler on each file, and then link +everything together. In other words, the *crate* is a translation unit, not a +particular module. \ No newline at end of file diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md index bf97fb46861..7f110d6a3d2 100644 --- a/src/doc/rustdoc/src/unstable-features.md +++ b/src/doc/rustdoc/src/unstable-features.md @@ -373,3 +373,19 @@ This is an internal flag intended for the standard library and compiler that app `#[unstable]` attribute to any dependent crate that doesn't have another stability attribute. This allows `rustdoc` to be able to generate documentation for the compiler crates and the standard library, as an equivalent command-line argument is provided to `rustc` when building those crates. + +### `doc_alias` feature + +This feature allows you to add alias(es) to an item when using the `rustdoc` search through the +`doc(alias)` attribute. Example: + +```rust,no_run +#![feature(doc_alias)] + +#[doc(alias = "x")] +#[doc(alias = "big")] +pub struct BigX; +``` + +Then, when looking for it through the `rustdoc` search, if you enter "x" or +"big", search will show the `BigX` struct first. diff --git a/src/doc/unstable-book/src/language-features/doc-alias.md b/src/doc/unstable-book/src/language-features/doc-alias.md new file mode 100644 index 00000000000..647ac0cf663 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/doc-alias.md @@ -0,0 +1,23 @@ +# `doc_alias` + +The tracking issue for this feature is: [#50146] + +[#50146]: https://github.com/rust-lang/rust/issues/50146 + +------------------------ + +You can add alias(es) to an item when using the `rustdoc` search through the +`doc(alias)` attribute. Example: + +```rust,no_run +#![feature(doc_alias)] + +#[doc(alias = "x")] +#[doc(alias = "big")] +pub struct BigX; +``` + +Then, when looking for it through the `rustdoc` search, if you enter "x" or +"big", search will show the `BigX` struct first. + +Note that this feature is currently hidden behind the `feature(doc_alias)` gate. diff --git a/src/doc/unstable-book/src/library-features/slice-rsplit.md b/src/doc/unstable-book/src/library-features/slice-rsplit.md deleted file mode 100644 index 8c2954f7294..00000000000 --- a/src/doc/unstable-book/src/library-features/slice-rsplit.md +++ /dev/null @@ -1,10 +0,0 @@ -# `slice_rsplit` - -The tracking issue for this feature is: [#41020] - -[#41020]: https://github.com/rust-lang/rust/issues/41020 - ------------------------- - -The `slice_rsplit` feature enables two methods on slices: -`slice.rsplit(predicate)` and `slice.rsplit_mut(predicate)`. diff --git a/src/liballoc/alloc.rs b/src/liballoc/alloc.rs index 68a617e0ffe..f59c9f7fd61 100644 --- a/src/liballoc/alloc.rs +++ b/src/liballoc/alloc.rs @@ -16,7 +16,7 @@ issue = "32838")] use core::intrinsics::{min_align_of_val, size_of_val}; -use core::ptr::NonNull; +use core::ptr::{NonNull, Unique}; use core::usize; #[doc(inline)] @@ -48,9 +48,6 @@ extern "Rust" { #[allocator] #[rustc_allocator_nounwind] fn __rust_alloc(size: usize, align: usize) -> *mut u8; - #[cold] - #[rustc_allocator_nounwind] - fn __rust_oom() -> !; #[rustc_allocator_nounwind] fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize); #[rustc_allocator_nounwind] @@ -107,16 +104,6 @@ unsafe impl GlobalAlloc for Global { let ptr = __rust_alloc_zeroed(layout.size(), layout.align(), &mut 0); ptr as *mut Opaque } - - #[inline] - fn oom(&self) -> ! { - unsafe { - #[cfg(not(stage0))] - __rust_oom(); - #[cfg(stage0)] - __rust_oom(&mut 0); - } - } } unsafe impl Alloc for Global { @@ -144,11 +131,6 @@ unsafe impl Alloc for Global { unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<NonNull<Opaque>, AllocErr> { NonNull::new(GlobalAlloc::alloc_zeroed(self, layout)).ok_or(AllocErr) } - - #[inline] - fn oom(&mut self) -> ! { - GlobalAlloc::oom(self) - } } /// The allocator for unique pointers. @@ -165,14 +147,22 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { if !ptr.is_null() { ptr as *mut u8 } else { - Global.oom() + oom() } } } -#[cfg_attr(not(test), lang = "box_free")] +#[cfg(stage0)] +#[lang = "box_free"] #[inline] -pub(crate) unsafe fn box_free<T: ?Sized>(ptr: *mut T) { +unsafe fn old_box_free<T: ?Sized>(ptr: *mut T) { + box_free(Unique::new_unchecked(ptr)) +} + +#[cfg_attr(not(any(test, stage0)), lang = "box_free")] +#[inline] +pub(crate) unsafe fn box_free<T: ?Sized>(ptr: Unique<T>) { + let ptr = ptr.as_ptr(); let size = size_of_val(&*ptr); let align = min_align_of_val(&*ptr); // We do not allocate for Box<T> when T is ZST, so deallocation is also not necessary. @@ -182,19 +172,33 @@ pub(crate) unsafe fn box_free<T: ?Sized>(ptr: *mut T) { } } +#[cfg(stage0)] +pub fn oom() -> ! { + unsafe { ::core::intrinsics::abort() } +} + +#[cfg(not(stage0))] +pub fn oom() -> ! { + extern { + #[lang = "oom"] + fn oom_impl() -> !; + } + unsafe { oom_impl() } +} + #[cfg(test)] mod tests { extern crate test; use self::test::Bencher; use boxed::Box; - use alloc::{Global, Alloc, Layout}; + use alloc::{Global, Alloc, Layout, oom}; #[test] fn allocate_zeroed() { unsafe { let layout = Layout::from_size_align(1024, 1).unwrap(); let ptr = Global.alloc_zeroed(layout.clone()) - .unwrap_or_else(|_| Global.oom()); + .unwrap_or_else(|_| oom()); let mut i = ptr.cast::<u8>().as_ptr(); let end = i.offset(layout.size() as isize); diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 225b055d8ee..d0950bff9ce 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -31,7 +31,7 @@ use core::hash::{Hash, Hasher}; use core::{isize, usize}; use core::convert::From; -use alloc::{Global, Alloc, Layout, box_free}; +use alloc::{Global, Alloc, Layout, box_free, oom}; use boxed::Box; use string::String; use vec::Vec; @@ -60,7 +60,7 @@ const MAX_REFCOUNT: usize = (isize::MAX) as usize; /// ## Thread Safety /// /// Unlike [`Rc<T>`], `Arc<T>` uses atomic operations for its reference -/// counting This means that it is thread-safe. The disadvantage is that +/// counting. This means that it is thread-safe. The disadvantage is that /// atomic operations are more expensive than ordinary memory accesses. If you /// are not sharing reference-counted values between threads, consider using /// [`Rc<T>`] for lower overhead. [`Rc<T>`] is a safe default, because the @@ -553,7 +553,7 @@ impl<T: ?Sized> Arc<T> { let layout = Layout::for_value(&*fake_ptr); let mem = Global.alloc(layout) - .unwrap_or_else(|_| Global.oom()); + .unwrap_or_else(|_| oom()); // Initialize the real ArcInner let inner = set_data_ptr(ptr as *mut T, mem.as_ptr() as *mut u8) as *mut ArcInner<T>; @@ -566,7 +566,8 @@ impl<T: ?Sized> Arc<T> { fn from_box(v: Box<T>) -> Arc<T> { unsafe { - let bptr = Box::into_raw(v); + let box_unique = Box::into_unique(v); + let bptr = box_unique.as_ptr(); let value_size = size_of_val(&*bptr); let ptr = Self::allocate_for_ptr(bptr); @@ -578,7 +579,7 @@ impl<T: ?Sized> Arc<T> { value_size); // Free the allocation without dropping its contents - box_free(bptr); + box_free(box_unique); Arc { ptr: NonNull::new_unchecked(ptr), phantom: PhantomData } } diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 5ebd2cc6146..1b4f86dcfac 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -184,6 +184,7 @@ impl<T: ?Sized> Box<T> { #[unstable(feature = "ptr_internals", issue = "0", reason = "use into_raw_non_null instead")] #[inline] + #[doc(hidden)] pub fn into_unique(b: Box<T>) -> Unique<T> { let unique = b.0; mem::forget(b); diff --git a/src/liballoc/btree/map.rs b/src/liballoc/btree/map.rs index 82cbec0517e..3984379ea86 100644 --- a/src/liballoc/btree/map.rs +++ b/src/liballoc/btree/map.rs @@ -2155,8 +2155,8 @@ impl<'a, K: Ord, V> Entry<'a, K, V> { /// assert_eq!(map["poneyland"], 43); /// ``` #[stable(feature = "entry_and_modify", since = "1.26.0")] - pub fn and_modify<F>(self, mut f: F) -> Self - where F: FnMut(&mut V) + pub fn and_modify<F>(self, f: F) -> Self + where F: FnOnce(&mut V) { match self { Occupied(mut entry) => { diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs index faac38ca7ce..16f0630b911 100644 --- a/src/liballoc/heap.rs +++ b/src/liballoc/heap.rs @@ -59,7 +59,7 @@ unsafe impl<T> Alloc for T where T: CoreAlloc { } fn oom(&mut self, _: AllocErr) -> ! { - CoreAlloc::oom(self) + unsafe { ::core::intrinsics::abort() } } fn usable_size(&self, layout: &Layout) -> (usize, usize) { diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 3a106a2ff5c..021395d0c82 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -75,7 +75,7 @@ #![deny(missing_debug_implementations)] #![cfg_attr(test, allow(deprecated))] // rand -#![cfg_attr(not(test), feature(core_float))] +#![cfg_attr(all(not(test), stage0), feature(float_internals))] #![cfg_attr(not(test), feature(exact_size_is_empty))] #![cfg_attr(not(test), feature(generator_trait))] #![cfg_attr(test, feature(rand, test))] @@ -90,16 +90,18 @@ #![feature(collections_range)] #![feature(const_fn)] #![feature(core_intrinsics)] +#![cfg_attr(stage0, feature(core_slice_ext))] +#![cfg_attr(stage0, feature(core_str_ext))] #![feature(custom_attribute)] #![feature(dropck_eyepatch)] #![feature(exact_size_is_empty)] #![feature(fmt_internals)] +#![feature(fn_must_use)] #![feature(from_ref)] #![feature(fundamental)] #![feature(lang_items)] #![feature(libc)] #![feature(needs_allocator)] -#![feature(nonnull_cast)] #![feature(nonzero)] #![feature(optin_builtin_traits)] #![feature(pattern)] @@ -108,7 +110,6 @@ #![feature(ptr_offset_from)] #![feature(rustc_attrs)] #![feature(slice_get_slice)] -#![feature(slice_rsplit)] #![feature(specialization)] #![feature(staged_api)] #![feature(str_internals)] @@ -124,7 +125,7 @@ #![feature(inclusive_range_fields)] #![cfg_attr(stage0, feature(generic_param_attrs))] -#![cfg_attr(not(test), feature(fn_traits, swap_with_slice, i128))] +#![cfg_attr(not(test), feature(fn_traits, i128))] #![cfg_attr(test, feature(test))] // Allow testing this library diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index 24b7cd3db0c..7ef0a27fc72 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -14,7 +14,7 @@ use core::ops::Drop; use core::ptr::{self, NonNull, Unique}; use core::slice; -use alloc::{Alloc, Layout, Global}; +use alloc::{Alloc, Layout, Global, oom}; use alloc::CollectionAllocErr; use alloc::CollectionAllocErr::*; use boxed::Box; @@ -101,7 +101,7 @@ impl<T, A: Alloc> RawVec<T, A> { }; match result { Ok(ptr) => ptr, - Err(_) => a.oom(), + Err(_) => oom(), } }; @@ -316,7 +316,7 @@ impl<T, A: Alloc> RawVec<T, A> { new_size); match ptr_res { Ok(ptr) => (new_cap, ptr.cast().into()), - Err(_) => self.a.oom(), + Err(_) => oom(), } } None => { @@ -325,7 +325,7 @@ impl<T, A: Alloc> RawVec<T, A> { let new_cap = if elem_size > (!0) / 8 { 1 } else { 4 }; match self.a.alloc_array::<T>(new_cap) { Ok(ptr) => (new_cap, ptr.into()), - Err(_) => self.a.oom(), + Err(_) => oom(), } } }; @@ -442,7 +442,7 @@ impl<T, A: Alloc> RawVec<T, A> { pub fn reserve_exact(&mut self, used_cap: usize, needed_extra_cap: usize) { match self.try_reserve_exact(used_cap, needed_extra_cap) { Err(CapacityOverflow) => capacity_overflow(), - Err(AllocErr) => self.a.oom(), + Err(AllocErr) => oom(), Ok(()) => { /* yay */ } } } @@ -552,7 +552,7 @@ impl<T, A: Alloc> RawVec<T, A> { pub fn reserve(&mut self, used_cap: usize, needed_extra_cap: usize) { match self.try_reserve(used_cap, needed_extra_cap) { Err(CapacityOverflow) => capacity_overflow(), - Err(AllocErr) => self.a.oom(), + Err(AllocErr) => oom(), Ok(()) => { /* yay */ } } } @@ -667,7 +667,7 @@ impl<T, A: Alloc> RawVec<T, A> { old_layout, new_size) { Ok(p) => self.ptr = p.cast().into(), - Err(_) => self.a.oom(), + Err(_) => oom(), } } self.cap = amount; diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index de0422d82bb..d0188c6e828 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -259,7 +259,7 @@ use core::ops::CoerceUnsized; use core::ptr::{self, NonNull}; use core::convert::From; -use alloc::{Global, Alloc, Layout, Opaque, box_free}; +use alloc::{Global, Alloc, Layout, Opaque, box_free, oom}; use string::String; use vec::Vec; @@ -668,7 +668,7 @@ impl<T: ?Sized> Rc<T> { let layout = Layout::for_value(&*fake_ptr); let mem = Global.alloc(layout) - .unwrap_or_else(|_| Global.oom()); + .unwrap_or_else(|_| oom()); // Initialize the real RcBox let inner = set_data_ptr(ptr as *mut T, mem.as_ptr() as *mut u8) as *mut RcBox<T>; @@ -681,7 +681,8 @@ impl<T: ?Sized> Rc<T> { fn from_box(v: Box<T>) -> Rc<T> { unsafe { - let bptr = Box::into_raw(v); + let box_unique = Box::into_unique(v); + let bptr = box_unique.as_ptr(); let value_size = size_of_val(&*bptr); let ptr = Self::allocate_for_ptr(bptr); @@ -693,7 +694,7 @@ impl<T: ?Sized> Rc<T> { value_size); // Free the allocation without dropping its contents - box_free(bptr); + box_free(box_unique); Rc { ptr: NonNull::new_unchecked(ptr), phantom: PhantomData } } diff --git a/src/liballoc/repeat-generic-slice.rs b/src/liballoc/repeat-generic-slice.rs new file mode 100644 index 00000000000..5c14ee4fd83 --- /dev/null +++ b/src/liballoc/repeat-generic-slice.rs @@ -0,0 +1,19 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(repeat_generic_slice)] + +fn main() { + assert_eq!([1, 2].repeat(2), vec![1, 2, 1, 2]); + assert_eq!([1, 2, 3, 4].repeat(0), vec![]); + assert_eq!([1, 2, 3, 4].repeat(1), vec![1, 2, 3, 4]); + assert_eq!([1, 2, 3, 4].repeat(3), + vec![1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4]); +} diff --git a/src/liballoc/slice.rs b/src/liballoc/slice.rs index 56c53fca62c..d50a3458f20 100644 --- a/src/liballoc/slice.rs +++ b/src/liballoc/slice.rs @@ -101,7 +101,7 @@ use core::cmp::Ordering::{self, Less}; use core::mem::size_of; use core::mem; use core::ptr; -use core::slice as core_slice; +#[cfg(stage0)] use core::slice::SliceExt; use core::{u8, u16, u32}; use borrow::{Borrow, BorrowMut, ToOwned}; @@ -116,7 +116,7 @@ pub use core::slice::{Iter, IterMut}; pub use core::slice::{SplitMut, ChunksMut, Split}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::slice::{SplitN, RSplitN, SplitNMut, RSplitNMut}; -#[unstable(feature = "slice_rsplit", issue = "41020")] +#[stable(feature = "slice_rsplit", since = "1.27.0")] pub use core::slice::{RSplit, RSplitMut}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::slice::{from_raw_parts, from_raw_parts_mut}; @@ -171,1064 +171,12 @@ mod hack { } } -#[lang = "slice"] +#[cfg_attr(stage0, lang = "slice")] +#[cfg_attr(not(stage0), lang = "slice_alloc")] #[cfg(not(test))] impl<T> [T] { - /// Returns the number of elements in the slice. - /// - /// # Examples - /// - /// ``` - /// let a = [1, 2, 3]; - /// assert_eq!(a.len(), 3); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn len(&self) -> usize { - core_slice::SliceExt::len(self) - } - - /// Returns `true` if the slice has a length of 0. - /// - /// # Examples - /// - /// ``` - /// let a = [1, 2, 3]; - /// assert!(!a.is_empty()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_empty(&self) -> bool { - core_slice::SliceExt::is_empty(self) - } - - /// Returns the first element of the slice, or `None` if it is empty. - /// - /// # Examples - /// - /// ``` - /// let v = [10, 40, 30]; - /// assert_eq!(Some(&10), v.first()); - /// - /// let w: &[i32] = &[]; - /// assert_eq!(None, w.first()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn first(&self) -> Option<&T> { - core_slice::SliceExt::first(self) - } - - /// Returns a mutable pointer to the first element of the slice, or `None` if it is empty. - /// - /// # Examples - /// - /// ``` - /// let x = &mut [0, 1, 2]; - /// - /// if let Some(first) = x.first_mut() { - /// *first = 5; - /// } - /// assert_eq!(x, &[5, 1, 2]); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn first_mut(&mut self) -> Option<&mut T> { - core_slice::SliceExt::first_mut(self) - } - - /// Returns the first and all the rest of the elements of the slice, or `None` if it is empty. - /// - /// # Examples - /// - /// ``` - /// let x = &[0, 1, 2]; - /// - /// if let Some((first, elements)) = x.split_first() { - /// assert_eq!(first, &0); - /// assert_eq!(elements, &[1, 2]); - /// } - /// ``` - #[stable(feature = "slice_splits", since = "1.5.0")] - #[inline] - pub fn split_first(&self) -> Option<(&T, &[T])> { - core_slice::SliceExt::split_first(self) - } - - /// Returns the first and all the rest of the elements of the slice, or `None` if it is empty. - /// - /// # Examples - /// - /// ``` - /// let x = &mut [0, 1, 2]; - /// - /// if let Some((first, elements)) = x.split_first_mut() { - /// *first = 3; - /// elements[0] = 4; - /// elements[1] = 5; - /// } - /// assert_eq!(x, &[3, 4, 5]); - /// ``` - #[stable(feature = "slice_splits", since = "1.5.0")] - #[inline] - pub fn split_first_mut(&mut self) -> Option<(&mut T, &mut [T])> { - core_slice::SliceExt::split_first_mut(self) - } - - /// Returns the last and all the rest of the elements of the slice, or `None` if it is empty. - /// - /// # Examples - /// - /// ``` - /// let x = &[0, 1, 2]; - /// - /// if let Some((last, elements)) = x.split_last() { - /// assert_eq!(last, &2); - /// assert_eq!(elements, &[0, 1]); - /// } - /// ``` - #[stable(feature = "slice_splits", since = "1.5.0")] - #[inline] - pub fn split_last(&self) -> Option<(&T, &[T])> { - core_slice::SliceExt::split_last(self) - - } - - /// Returns the last and all the rest of the elements of the slice, or `None` if it is empty. - /// - /// # Examples - /// - /// ``` - /// let x = &mut [0, 1, 2]; - /// - /// if let Some((last, elements)) = x.split_last_mut() { - /// *last = 3; - /// elements[0] = 4; - /// elements[1] = 5; - /// } - /// assert_eq!(x, &[4, 5, 3]); - /// ``` - #[stable(feature = "slice_splits", since = "1.5.0")] - #[inline] - pub fn split_last_mut(&mut self) -> Option<(&mut T, &mut [T])> { - core_slice::SliceExt::split_last_mut(self) - } - - /// Returns the last element of the slice, or `None` if it is empty. - /// - /// # Examples - /// - /// ``` - /// let v = [10, 40, 30]; - /// assert_eq!(Some(&30), v.last()); - /// - /// let w: &[i32] = &[]; - /// assert_eq!(None, w.last()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn last(&self) -> Option<&T> { - core_slice::SliceExt::last(self) - } - - /// Returns a mutable pointer to the last item in the slice. - /// - /// # Examples - /// - /// ``` - /// let x = &mut [0, 1, 2]; - /// - /// if let Some(last) = x.last_mut() { - /// *last = 10; - /// } - /// assert_eq!(x, &[0, 1, 10]); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn last_mut(&mut self) -> Option<&mut T> { - core_slice::SliceExt::last_mut(self) - } - - /// Returns a reference to an element or subslice depending on the type of - /// index. - /// - /// - If given a position, returns a reference to the element at that - /// position or `None` if out of bounds. - /// - If given a range, returns the subslice corresponding to that range, - /// or `None` if out of bounds. - /// - /// # Examples - /// - /// ``` - /// let v = [10, 40, 30]; - /// assert_eq!(Some(&40), v.get(1)); - /// assert_eq!(Some(&[10, 40][..]), v.get(0..2)); - /// assert_eq!(None, v.get(3)); - /// assert_eq!(None, v.get(0..4)); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn get<I>(&self, index: I) -> Option<&I::Output> - where I: SliceIndex<Self> - { - core_slice::SliceExt::get(self, index) - } - - /// Returns a mutable reference to an element or subslice depending on the - /// type of index (see [`get`]) or `None` if the index is out of bounds. - /// - /// [`get`]: #method.get - /// - /// # Examples - /// - /// ``` - /// let x = &mut [0, 1, 2]; - /// - /// if let Some(elem) = x.get_mut(1) { - /// *elem = 42; - /// } - /// assert_eq!(x, &[0, 42, 2]); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn get_mut<I>(&mut self, index: I) -> Option<&mut I::Output> - where I: SliceIndex<Self> - { - core_slice::SliceExt::get_mut(self, index) - } - - /// Returns a reference to an element or subslice, without doing bounds - /// checking. - /// - /// This is generally not recommended, use with caution! For a safe - /// alternative see [`get`]. - /// - /// [`get`]: #method.get - /// - /// # Examples - /// - /// ``` - /// let x = &[1, 2, 4]; - /// - /// unsafe { - /// assert_eq!(x.get_unchecked(1), &2); - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub unsafe fn get_unchecked<I>(&self, index: I) -> &I::Output - where I: SliceIndex<Self> - { - core_slice::SliceExt::get_unchecked(self, index) - } - - /// Returns a mutable reference to an element or subslice, without doing - /// bounds checking. - /// - /// This is generally not recommended, use with caution! For a safe - /// alternative see [`get_mut`]. - /// - /// [`get_mut`]: #method.get_mut - /// - /// # Examples - /// - /// ``` - /// let x = &mut [1, 2, 4]; - /// - /// unsafe { - /// let elem = x.get_unchecked_mut(1); - /// *elem = 13; - /// } - /// assert_eq!(x, &[1, 13, 4]); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub unsafe fn get_unchecked_mut<I>(&mut self, index: I) -> &mut I::Output - where I: SliceIndex<Self> - { - core_slice::SliceExt::get_unchecked_mut(self, index) - } - - /// Returns a raw pointer to the slice's buffer. - /// - /// The caller must ensure that the slice outlives the pointer this - /// function returns, or else it will end up pointing to garbage. - /// - /// Modifying the container referenced by this slice may cause its buffer - /// to be reallocated, which would also make any pointers to it invalid. - /// - /// # Examples - /// - /// ``` - /// let x = &[1, 2, 4]; - /// let x_ptr = x.as_ptr(); - /// - /// unsafe { - /// for i in 0..x.len() { - /// assert_eq!(x.get_unchecked(i), &*x_ptr.offset(i as isize)); - /// } - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn as_ptr(&self) -> *const T { - core_slice::SliceExt::as_ptr(self) - } - - /// Returns an unsafe mutable pointer to the slice's buffer. - /// - /// The caller must ensure that the slice outlives the pointer this - /// function returns, or else it will end up pointing to garbage. - /// - /// Modifying the container referenced by this slice may cause its buffer - /// to be reallocated, which would also make any pointers to it invalid. - /// - /// # Examples - /// - /// ``` - /// let x = &mut [1, 2, 4]; - /// let x_ptr = x.as_mut_ptr(); - /// - /// unsafe { - /// for i in 0..x.len() { - /// *x_ptr.offset(i as isize) += 2; - /// } - /// } - /// assert_eq!(x, &[3, 4, 6]); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn as_mut_ptr(&mut self) -> *mut T { - core_slice::SliceExt::as_mut_ptr(self) - } - - /// Swaps two elements in the slice. - /// - /// # Arguments - /// - /// * a - The index of the first element - /// * b - The index of the second element - /// - /// # Panics - /// - /// Panics if `a` or `b` are out of bounds. - /// - /// # Examples - /// - /// ``` - /// let mut v = ["a", "b", "c", "d"]; - /// v.swap(1, 3); - /// assert!(v == ["a", "d", "c", "b"]); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn swap(&mut self, a: usize, b: usize) { - core_slice::SliceExt::swap(self, a, b) - } - - /// Reverses the order of elements in the slice, in place. - /// - /// # Examples - /// - /// ``` - /// let mut v = [1, 2, 3]; - /// v.reverse(); - /// assert!(v == [3, 2, 1]); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn reverse(&mut self) { - core_slice::SliceExt::reverse(self) - } - - /// Returns an iterator over the slice. - /// - /// # Examples - /// - /// ``` - /// let x = &[1, 2, 4]; - /// let mut iterator = x.iter(); - /// - /// assert_eq!(iterator.next(), Some(&1)); - /// assert_eq!(iterator.next(), Some(&2)); - /// assert_eq!(iterator.next(), Some(&4)); - /// assert_eq!(iterator.next(), None); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn iter(&self) -> Iter<T> { - core_slice::SliceExt::iter(self) - } - - /// Returns an iterator that allows modifying each value. - /// - /// # Examples - /// - /// ``` - /// let x = &mut [1, 2, 4]; - /// for elem in x.iter_mut() { - /// *elem += 2; - /// } - /// assert_eq!(x, &[3, 4, 6]); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn iter_mut(&mut self) -> IterMut<T> { - core_slice::SliceExt::iter_mut(self) - } - - /// Returns an iterator over all contiguous windows of length - /// `size`. The windows overlap. If the slice is shorter than - /// `size`, the iterator returns no values. - /// - /// # Panics - /// - /// Panics if `size` is 0. - /// - /// # Examples - /// - /// ``` - /// let slice = ['r', 'u', 's', 't']; - /// let mut iter = slice.windows(2); - /// assert_eq!(iter.next().unwrap(), &['r', 'u']); - /// assert_eq!(iter.next().unwrap(), &['u', 's']); - /// assert_eq!(iter.next().unwrap(), &['s', 't']); - /// assert!(iter.next().is_none()); - /// ``` - /// - /// If the slice is shorter than `size`: - /// - /// ``` - /// let slice = ['f', 'o', 'o']; - /// let mut iter = slice.windows(4); - /// assert!(iter.next().is_none()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn windows(&self, size: usize) -> Windows<T> { - core_slice::SliceExt::windows(self, size) - } - - /// Returns an iterator over `chunk_size` elements of the slice at a - /// time. The chunks are slices and do not overlap. If `chunk_size` does - /// not divide the length of the slice, then the last chunk will - /// not have length `chunk_size`. - /// - /// See [`exact_chunks`] for a variant of this iterator that returns chunks - /// of always exactly `chunk_size` elements. - /// - /// # Panics - /// - /// Panics if `chunk_size` is 0. - /// - /// # Examples - /// - /// ``` - /// let slice = ['l', 'o', 'r', 'e', 'm']; - /// let mut iter = slice.chunks(2); - /// assert_eq!(iter.next().unwrap(), &['l', 'o']); - /// assert_eq!(iter.next().unwrap(), &['r', 'e']); - /// assert_eq!(iter.next().unwrap(), &['m']); - /// assert!(iter.next().is_none()); - /// ``` - /// - /// [`exact_chunks`]: #method.exact_chunks - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn chunks(&self, chunk_size: usize) -> Chunks<T> { - core_slice::SliceExt::chunks(self, chunk_size) - } - - /// Returns an iterator over `chunk_size` elements of the slice at a - /// time. The chunks are slices and do not overlap. If `chunk_size` does - /// not divide the length of the slice, then the last up to `chunk_size-1` - /// elements will be omitted. - /// - /// Due to each chunk having exactly `chunk_size` elements, the compiler - /// can often optimize the resulting code better than in the case of - /// [`chunks`]. - /// - /// # Panics - /// - /// Panics if `chunk_size` is 0. - /// - /// # Examples - /// - /// ``` - /// #![feature(exact_chunks)] - /// - /// let slice = ['l', 'o', 'r', 'e', 'm']; - /// let mut iter = slice.exact_chunks(2); - /// assert_eq!(iter.next().unwrap(), &['l', 'o']); - /// assert_eq!(iter.next().unwrap(), &['r', 'e']); - /// assert!(iter.next().is_none()); - /// ``` - /// - /// [`chunks`]: #method.chunks - #[unstable(feature = "exact_chunks", issue = "47115")] - #[inline] - pub fn exact_chunks(&self, chunk_size: usize) -> ExactChunks<T> { - core_slice::SliceExt::exact_chunks(self, chunk_size) - } - - /// Returns an iterator over `chunk_size` elements of the slice at a time. - /// The chunks are mutable slices, and do not overlap. If `chunk_size` does - /// not divide the length of the slice, then the last chunk will not - /// have length `chunk_size`. - /// - /// See [`exact_chunks_mut`] for a variant of this iterator that returns chunks - /// of always exactly `chunk_size` elements. - /// - /// # Panics - /// - /// Panics if `chunk_size` is 0. - /// - /// # Examples - /// - /// ``` - /// let v = &mut [0, 0, 0, 0, 0]; - /// let mut count = 1; - /// - /// for chunk in v.chunks_mut(2) { - /// for elem in chunk.iter_mut() { - /// *elem += count; - /// } - /// count += 1; - /// } - /// assert_eq!(v, &[1, 1, 2, 2, 3]); - /// ``` - /// - /// [`exact_chunks_mut`]: #method.exact_chunks_mut - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn chunks_mut(&mut self, chunk_size: usize) -> ChunksMut<T> { - core_slice::SliceExt::chunks_mut(self, chunk_size) - } - - /// Returns an iterator over `chunk_size` elements of the slice at a time. - /// The chunks are mutable slices, and do not overlap. If `chunk_size` does - /// not divide the length of the slice, then the last up to `chunk_size-1` - /// elements will be omitted. - /// - /// - /// Due to each chunk having exactly `chunk_size` elements, the compiler - /// can often optimize the resulting code better than in the case of - /// [`chunks_mut`]. - /// - /// # Panics - /// - /// Panics if `chunk_size` is 0. - /// - /// # Examples - /// - /// ``` - /// #![feature(exact_chunks)] - /// - /// let v = &mut [0, 0, 0, 0, 0]; - /// let mut count = 1; - /// - /// for chunk in v.exact_chunks_mut(2) { - /// for elem in chunk.iter_mut() { - /// *elem += count; - /// } - /// count += 1; - /// } - /// assert_eq!(v, &[1, 1, 2, 2, 0]); - /// ``` - /// - /// [`chunks_mut`]: #method.chunks_mut - #[unstable(feature = "exact_chunks", issue = "47115")] - #[inline] - pub fn exact_chunks_mut(&mut self, chunk_size: usize) -> ExactChunksMut<T> { - core_slice::SliceExt::exact_chunks_mut(self, chunk_size) - } - - /// Divides one slice into two at an index. - /// - /// The first will contain all indices from `[0, mid)` (excluding - /// the index `mid` itself) and the second will contain all - /// indices from `[mid, len)` (excluding the index `len` itself). - /// - /// # Panics - /// - /// Panics if `mid > len`. - /// - /// # Examples - /// - /// ``` - /// let v = [1, 2, 3, 4, 5, 6]; - /// - /// { - /// let (left, right) = v.split_at(0); - /// assert!(left == []); - /// assert!(right == [1, 2, 3, 4, 5, 6]); - /// } - /// - /// { - /// let (left, right) = v.split_at(2); - /// assert!(left == [1, 2]); - /// assert!(right == [3, 4, 5, 6]); - /// } - /// - /// { - /// let (left, right) = v.split_at(6); - /// assert!(left == [1, 2, 3, 4, 5, 6]); - /// assert!(right == []); - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn split_at(&self, mid: usize) -> (&[T], &[T]) { - core_slice::SliceExt::split_at(self, mid) - } - - /// Divides one mutable slice into two at an index. - /// - /// The first will contain all indices from `[0, mid)` (excluding - /// the index `mid` itself) and the second will contain all - /// indices from `[mid, len)` (excluding the index `len` itself). - /// - /// # Panics - /// - /// Panics if `mid > len`. - /// - /// # Examples - /// - /// ``` - /// let mut v = [1, 0, 3, 0, 5, 6]; - /// // scoped to restrict the lifetime of the borrows - /// { - /// let (left, right) = v.split_at_mut(2); - /// assert!(left == [1, 0]); - /// assert!(right == [3, 0, 5, 6]); - /// left[1] = 2; - /// right[1] = 4; - /// } - /// assert!(v == [1, 2, 3, 4, 5, 6]); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) { - core_slice::SliceExt::split_at_mut(self, mid) - } - - /// Returns an iterator over subslices separated by elements that match - /// `pred`. The matched element is not contained in the subslices. - /// - /// # Examples - /// - /// ``` - /// let slice = [10, 40, 33, 20]; - /// let mut iter = slice.split(|num| num % 3 == 0); - /// - /// assert_eq!(iter.next().unwrap(), &[10, 40]); - /// assert_eq!(iter.next().unwrap(), &[20]); - /// assert!(iter.next().is_none()); - /// ``` - /// - /// If the first element is matched, an empty slice will be the first item - /// returned by the iterator. Similarly, if the last element in the slice - /// is matched, an empty slice will be the last item returned by the - /// iterator: - /// - /// ``` - /// let slice = [10, 40, 33]; - /// let mut iter = slice.split(|num| num % 3 == 0); - /// - /// assert_eq!(iter.next().unwrap(), &[10, 40]); - /// assert_eq!(iter.next().unwrap(), &[]); - /// assert!(iter.next().is_none()); - /// ``` - /// - /// If two matched elements are directly adjacent, an empty slice will be - /// present between them: - /// - /// ``` - /// let slice = [10, 6, 33, 20]; - /// let mut iter = slice.split(|num| num % 3 == 0); - /// - /// assert_eq!(iter.next().unwrap(), &[10]); - /// assert_eq!(iter.next().unwrap(), &[]); - /// assert_eq!(iter.next().unwrap(), &[20]); - /// assert!(iter.next().is_none()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn split<F>(&self, pred: F) -> Split<T, F> - where F: FnMut(&T) -> bool - { - core_slice::SliceExt::split(self, pred) - } - - /// Returns an iterator over mutable subslices separated by elements that - /// match `pred`. The matched element is not contained in the subslices. - /// - /// # Examples - /// - /// ``` - /// let mut v = [10, 40, 30, 20, 60, 50]; - /// - /// for group in v.split_mut(|num| *num % 3 == 0) { - /// group[0] = 1; - /// } - /// assert_eq!(v, [1, 40, 30, 1, 60, 1]); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn split_mut<F>(&mut self, pred: F) -> SplitMut<T, F> - where F: FnMut(&T) -> bool - { - core_slice::SliceExt::split_mut(self, pred) - } - - /// Returns an iterator over subslices separated by elements that match - /// `pred`, starting at the end of the slice and working backwards. - /// The matched element is not contained in the subslices. - /// - /// # Examples - /// - /// ``` - /// #![feature(slice_rsplit)] - /// - /// let slice = [11, 22, 33, 0, 44, 55]; - /// let mut iter = slice.rsplit(|num| *num == 0); - /// - /// assert_eq!(iter.next().unwrap(), &[44, 55]); - /// assert_eq!(iter.next().unwrap(), &[11, 22, 33]); - /// assert_eq!(iter.next(), None); - /// ``` - /// - /// As with `split()`, if the first or last element is matched, an empty - /// slice will be the first (or last) item returned by the iterator. - /// - /// ``` - /// #![feature(slice_rsplit)] - /// - /// let v = &[0, 1, 1, 2, 3, 5, 8]; - /// let mut it = v.rsplit(|n| *n % 2 == 0); - /// assert_eq!(it.next().unwrap(), &[]); - /// assert_eq!(it.next().unwrap(), &[3, 5]); - /// assert_eq!(it.next().unwrap(), &[1, 1]); - /// assert_eq!(it.next().unwrap(), &[]); - /// assert_eq!(it.next(), None); - /// ``` - #[unstable(feature = "slice_rsplit", issue = "41020")] - #[inline] - pub fn rsplit<F>(&self, pred: F) -> RSplit<T, F> - where F: FnMut(&T) -> bool - { - core_slice::SliceExt::rsplit(self, pred) - } - - /// Returns an iterator over mutable subslices separated by elements that - /// match `pred`, starting at the end of the slice and working - /// backwards. The matched element is not contained in the subslices. - /// - /// # Examples - /// - /// ``` - /// #![feature(slice_rsplit)] - /// - /// let mut v = [100, 400, 300, 200, 600, 500]; - /// - /// let mut count = 0; - /// for group in v.rsplit_mut(|num| *num % 3 == 0) { - /// count += 1; - /// group[0] = count; - /// } - /// assert_eq!(v, [3, 400, 300, 2, 600, 1]); - /// ``` - /// - #[unstable(feature = "slice_rsplit", issue = "41020")] - #[inline] - pub fn rsplit_mut<F>(&mut self, pred: F) -> RSplitMut<T, F> - where F: FnMut(&T) -> bool - { - core_slice::SliceExt::rsplit_mut(self, pred) - } - - /// Returns an iterator over subslices separated by elements that match - /// `pred`, limited to returning at most `n` items. The matched element is - /// not contained in the subslices. - /// - /// The last element returned, if any, will contain the remainder of the - /// slice. - /// - /// # Examples - /// - /// Print the slice split once by numbers divisible by 3 (i.e. `[10, 40]`, - /// `[20, 60, 50]`): - /// - /// ``` - /// let v = [10, 40, 30, 20, 60, 50]; - /// - /// for group in v.splitn(2, |num| *num % 3 == 0) { - /// println!("{:?}", group); - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn splitn<F>(&self, n: usize, pred: F) -> SplitN<T, F> - where F: FnMut(&T) -> bool - { - core_slice::SliceExt::splitn(self, n, pred) - } - - /// Returns an iterator over subslices separated by elements that match - /// `pred`, limited to returning at most `n` items. The matched element is - /// not contained in the subslices. - /// - /// The last element returned, if any, will contain the remainder of the - /// slice. - /// - /// # Examples - /// - /// ``` - /// let mut v = [10, 40, 30, 20, 60, 50]; - /// - /// for group in v.splitn_mut(2, |num| *num % 3 == 0) { - /// group[0] = 1; - /// } - /// assert_eq!(v, [1, 40, 30, 1, 60, 50]); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn splitn_mut<F>(&mut self, n: usize, pred: F) -> SplitNMut<T, F> - where F: FnMut(&T) -> bool - { - core_slice::SliceExt::splitn_mut(self, n, pred) - } - - /// Returns an iterator over subslices separated by elements that match - /// `pred` limited to returning at most `n` items. This starts at the end of - /// the slice and works backwards. The matched element is not contained in - /// the subslices. - /// - /// The last element returned, if any, will contain the remainder of the - /// slice. - /// - /// # Examples - /// - /// Print the slice split once, starting from the end, by numbers divisible - /// by 3 (i.e. `[50]`, `[10, 40, 30, 20]`): - /// - /// ``` - /// let v = [10, 40, 30, 20, 60, 50]; - /// - /// for group in v.rsplitn(2, |num| *num % 3 == 0) { - /// println!("{:?}", group); - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn rsplitn<F>(&self, n: usize, pred: F) -> RSplitN<T, F> - where F: FnMut(&T) -> bool - { - core_slice::SliceExt::rsplitn(self, n, pred) - } - - /// Returns an iterator over subslices separated by elements that match - /// `pred` limited to returning at most `n` items. This starts at the end of - /// the slice and works backwards. The matched element is not contained in - /// the subslices. - /// - /// The last element returned, if any, will contain the remainder of the - /// slice. - /// - /// # Examples - /// - /// ``` - /// let mut s = [10, 40, 30, 20, 60, 50]; - /// - /// for group in s.rsplitn_mut(2, |num| *num % 3 == 0) { - /// group[0] = 1; - /// } - /// assert_eq!(s, [1, 40, 30, 20, 60, 1]); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn rsplitn_mut<F>(&mut self, n: usize, pred: F) -> RSplitNMut<T, F> - where F: FnMut(&T) -> bool - { - core_slice::SliceExt::rsplitn_mut(self, n, pred) - } - - /// Returns `true` if the slice contains an element with the given value. - /// - /// # Examples - /// - /// ``` - /// let v = [10, 40, 30]; - /// assert!(v.contains(&30)); - /// assert!(!v.contains(&50)); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn contains(&self, x: &T) -> bool - where T: PartialEq - { - core_slice::SliceExt::contains(self, x) - } - - /// Returns `true` if `needle` is a prefix of the slice. - /// - /// # Examples - /// - /// ``` - /// let v = [10, 40, 30]; - /// assert!(v.starts_with(&[10])); - /// assert!(v.starts_with(&[10, 40])); - /// assert!(!v.starts_with(&[50])); - /// assert!(!v.starts_with(&[10, 50])); - /// ``` - /// - /// Always returns `true` if `needle` is an empty slice: - /// - /// ``` - /// let v = &[10, 40, 30]; - /// assert!(v.starts_with(&[])); - /// let v: &[u8] = &[]; - /// assert!(v.starts_with(&[])); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn starts_with(&self, needle: &[T]) -> bool - where T: PartialEq - { - core_slice::SliceExt::starts_with(self, needle) - } - - /// Returns `true` if `needle` is a suffix of the slice. - /// - /// # Examples - /// - /// ``` - /// let v = [10, 40, 30]; - /// assert!(v.ends_with(&[30])); - /// assert!(v.ends_with(&[40, 30])); - /// assert!(!v.ends_with(&[50])); - /// assert!(!v.ends_with(&[50, 30])); - /// ``` - /// - /// Always returns `true` if `needle` is an empty slice: - /// - /// ``` - /// let v = &[10, 40, 30]; - /// assert!(v.ends_with(&[])); - /// let v: &[u8] = &[]; - /// assert!(v.ends_with(&[])); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn ends_with(&self, needle: &[T]) -> bool - where T: PartialEq - { - core_slice::SliceExt::ends_with(self, needle) - } - - /// Binary searches this sorted slice for a given element. - /// - /// If the value is found then `Ok` is returned, containing the - /// index of the matching element; if the value is not found then - /// `Err` is returned, containing the index where a matching - /// element could be inserted while maintaining sorted order. - /// - /// # Examples - /// - /// Looks up a series of four elements. The first is found, with a - /// uniquely determined position; the second and third are not - /// found; the fourth could match any position in `[1, 4]`. - /// - /// ``` - /// let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]; - /// - /// assert_eq!(s.binary_search(&13), Ok(9)); - /// assert_eq!(s.binary_search(&4), Err(7)); - /// assert_eq!(s.binary_search(&100), Err(13)); - /// let r = s.binary_search(&1); - /// assert!(match r { Ok(1...4) => true, _ => false, }); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn binary_search(&self, x: &T) -> Result<usize, usize> - where T: Ord - { - core_slice::SliceExt::binary_search(self, x) - } - - /// Binary searches this sorted slice with a comparator function. - /// - /// The comparator function should implement an order consistent - /// with the sort order of the underlying slice, returning an - /// order code that indicates whether its argument is `Less`, - /// `Equal` or `Greater` the desired target. - /// - /// If a matching value is found then returns `Ok`, containing - /// the index for the matched element; if no match is found then - /// `Err` is returned, containing the index where a matching - /// element could be inserted while maintaining sorted order. - /// - /// # Examples - /// - /// Looks up a series of four elements. The first is found, with a - /// uniquely determined position; the second and third are not - /// found; the fourth could match any position in `[1, 4]`. - /// - /// ``` - /// let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]; - /// - /// let seek = 13; - /// assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Ok(9)); - /// let seek = 4; - /// assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Err(7)); - /// let seek = 100; - /// assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Err(13)); - /// let seek = 1; - /// let r = s.binary_search_by(|probe| probe.cmp(&seek)); - /// assert!(match r { Ok(1...4) => true, _ => false, }); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn binary_search_by<'a, F>(&'a self, f: F) -> Result<usize, usize> - where F: FnMut(&'a T) -> Ordering - { - core_slice::SliceExt::binary_search_by(self, f) - } - - /// Binary searches this sorted slice with a key extraction function. - /// - /// Assumes that the slice is sorted by the key, for instance with - /// [`sort_by_key`] using the same key extraction function. - /// - /// If a matching value is found then returns `Ok`, containing the - /// index for the matched element; if no match is found then `Err` - /// is returned, containing the index where a matching element could - /// be inserted while maintaining sorted order. - /// - /// [`sort_by_key`]: #method.sort_by_key - /// - /// # Examples - /// - /// Looks up a series of four elements in a slice of pairs sorted by - /// their second elements. The first is found, with a uniquely - /// determined position; the second and third are not found; the - /// fourth could match any position in `[1, 4]`. - /// - /// ``` - /// let s = [(0, 0), (2, 1), (4, 1), (5, 1), (3, 1), - /// (1, 2), (2, 3), (4, 5), (5, 8), (3, 13), - /// (1, 21), (2, 34), (4, 55)]; - /// - /// assert_eq!(s.binary_search_by_key(&13, |&(a,b)| b), Ok(9)); - /// assert_eq!(s.binary_search_by_key(&4, |&(a,b)| b), Err(7)); - /// assert_eq!(s.binary_search_by_key(&100, |&(a,b)| b), Err(13)); - /// let r = s.binary_search_by_key(&1, |&(a,b)| b); - /// assert!(match r { Ok(1...4) => true, _ => false, }); - /// ``` - #[stable(feature = "slice_binary_search_by_key", since = "1.10.0")] - #[inline] - pub fn binary_search_by_key<'a, B, F>(&'a self, b: &B, f: F) -> Result<usize, usize> - where F: FnMut(&'a T) -> B, - B: Ord - { - core_slice::SliceExt::binary_search_by_key(self, b, f) - } + #[cfg(stage0)] + slice_core_methods!(); /// Sorts the slice. /// @@ -1407,351 +355,6 @@ impl<T> [T] { sort_by_key!(usize, self, f) } - /// Sorts the slice, but may not preserve the order of equal elements. - /// - /// This sort is unstable (i.e. may reorder equal elements), in-place (i.e. does not allocate), - /// and `O(n log n)` worst-case. - /// - /// # Current implementation - /// - /// The current algorithm is based on [pattern-defeating quicksort][pdqsort] by Orson Peters, - /// which combines the fast average case of randomized quicksort with the fast worst case of - /// heapsort, while achieving linear time on slices with certain patterns. It uses some - /// randomization to avoid degenerate cases, but with a fixed seed to always provide - /// deterministic behavior. - /// - /// It is typically faster than stable sorting, except in a few special cases, e.g. when the - /// slice consists of several concatenated sorted sequences. - /// - /// # Examples - /// - /// ``` - /// let mut v = [-5, 4, 1, -3, 2]; - /// - /// v.sort_unstable(); - /// assert!(v == [-5, -3, 1, 2, 4]); - /// ``` - /// - /// [pdqsort]: https://github.com/orlp/pdqsort - #[stable(feature = "sort_unstable", since = "1.20.0")] - #[inline] - pub fn sort_unstable(&mut self) - where T: Ord - { - core_slice::SliceExt::sort_unstable(self); - } - - /// Sorts the slice with a comparator function, but may not preserve the order of equal - /// elements. - /// - /// This sort is unstable (i.e. may reorder equal elements), in-place (i.e. does not allocate), - /// and `O(n log n)` worst-case. - /// - /// # Current implementation - /// - /// The current algorithm is based on [pattern-defeating quicksort][pdqsort] by Orson Peters, - /// which combines the fast average case of randomized quicksort with the fast worst case of - /// heapsort, while achieving linear time on slices with certain patterns. It uses some - /// randomization to avoid degenerate cases, but with a fixed seed to always provide - /// deterministic behavior. - /// - /// It is typically faster than stable sorting, except in a few special cases, e.g. when the - /// slice consists of several concatenated sorted sequences. - /// - /// # Examples - /// - /// ``` - /// let mut v = [5, 4, 1, 3, 2]; - /// v.sort_unstable_by(|a, b| a.cmp(b)); - /// assert!(v == [1, 2, 3, 4, 5]); - /// - /// // reverse sorting - /// v.sort_unstable_by(|a, b| b.cmp(a)); - /// assert!(v == [5, 4, 3, 2, 1]); - /// ``` - /// - /// [pdqsort]: https://github.com/orlp/pdqsort - #[stable(feature = "sort_unstable", since = "1.20.0")] - #[inline] - pub fn sort_unstable_by<F>(&mut self, compare: F) - where F: FnMut(&T, &T) -> Ordering - { - core_slice::SliceExt::sort_unstable_by(self, compare); - } - - /// Sorts the slice with a key extraction function, but may not preserve the order of equal - /// elements. - /// - /// This sort is unstable (i.e. may reorder equal elements), in-place (i.e. does not allocate), - /// and `O(m n log(m n))` worst-case, where the key function is `O(m)`. - /// - /// # Current implementation - /// - /// The current algorithm is based on [pattern-defeating quicksort][pdqsort] by Orson Peters, - /// which combines the fast average case of randomized quicksort with the fast worst case of - /// heapsort, while achieving linear time on slices with certain patterns. It uses some - /// randomization to avoid degenerate cases, but with a fixed seed to always provide - /// deterministic behavior. - /// - /// # Examples - /// - /// ``` - /// let mut v = [-5i32, 4, 1, -3, 2]; - /// - /// v.sort_unstable_by_key(|k| k.abs()); - /// assert!(v == [1, 2, -3, 4, -5]); - /// ``` - /// - /// [pdqsort]: https://github.com/orlp/pdqsort - #[stable(feature = "sort_unstable", since = "1.20.0")] - #[inline] - pub fn sort_unstable_by_key<K, F>(&mut self, f: F) - where F: FnMut(&T) -> K, K: Ord - { - core_slice::SliceExt::sort_unstable_by_key(self, f); - } - - /// Rotates the slice in-place such that the first `mid` elements of the - /// slice move to the end while the last `self.len() - mid` elements move to - /// the front. After calling `rotate_left`, the element previously at index - /// `mid` will become the first element in the slice. - /// - /// # Panics - /// - /// This function will panic if `mid` is greater than the length of the - /// slice. Note that `mid == self.len()` does _not_ panic and is a no-op - /// rotation. - /// - /// # Complexity - /// - /// Takes linear (in `self.len()`) time. - /// - /// # Examples - /// - /// ``` - /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f']; - /// a.rotate_left(2); - /// assert_eq!(a, ['c', 'd', 'e', 'f', 'a', 'b']); - /// ``` - /// - /// Rotating a subslice: - /// - /// ``` - /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f']; - /// a[1..5].rotate_left(1); - /// assert_eq!(a, ['a', 'c', 'd', 'e', 'b', 'f']); - /// ``` - #[stable(feature = "slice_rotate", since = "1.26.0")] - pub fn rotate_left(&mut self, mid: usize) { - core_slice::SliceExt::rotate_left(self, mid); - } - - /// Rotates the slice in-place such that the first `self.len() - k` - /// elements of the slice move to the end while the last `k` elements move - /// to the front. After calling `rotate_right`, the element previously at - /// index `self.len() - k` will become the first element in the slice. - /// - /// # Panics - /// - /// This function will panic if `k` is greater than the length of the - /// slice. Note that `k == self.len()` does _not_ panic and is a no-op - /// rotation. - /// - /// # Complexity - /// - /// Takes linear (in `self.len()`) time. - /// - /// # Examples - /// - /// ``` - /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f']; - /// a.rotate_right(2); - /// assert_eq!(a, ['e', 'f', 'a', 'b', 'c', 'd']); - /// ``` - /// - /// Rotate a subslice: - /// - /// ``` - /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f']; - /// a[1..5].rotate_right(1); - /// assert_eq!(a, ['a', 'e', 'b', 'c', 'd', 'f']); - /// ``` - #[stable(feature = "slice_rotate", since = "1.26.0")] - pub fn rotate_right(&mut self, k: usize) { - core_slice::SliceExt::rotate_right(self, k); - } - - /// Copies the elements from `src` into `self`. - /// - /// The length of `src` must be the same as `self`. - /// - /// If `src` implements `Copy`, it can be more performant to use - /// [`copy_from_slice`]. - /// - /// # Panics - /// - /// This function will panic if the two slices have different lengths. - /// - /// # Examples - /// - /// Cloning two elements from a slice into another: - /// - /// ``` - /// let src = [1, 2, 3, 4]; - /// let mut dst = [0, 0]; - /// - /// dst.clone_from_slice(&src[2..]); - /// - /// assert_eq!(src, [1, 2, 3, 4]); - /// assert_eq!(dst, [3, 4]); - /// ``` - /// - /// Rust enforces that there can only be one mutable reference with no - /// immutable references to a particular piece of data in a particular - /// scope. Because of this, attempting to use `clone_from_slice` on a - /// single slice will result in a compile failure: - /// - /// ```compile_fail - /// let mut slice = [1, 2, 3, 4, 5]; - /// - /// slice[..2].clone_from_slice(&slice[3..]); // compile fail! - /// ``` - /// - /// To work around this, we can use [`split_at_mut`] to create two distinct - /// sub-slices from a slice: - /// - /// ``` - /// let mut slice = [1, 2, 3, 4, 5]; - /// - /// { - /// let (left, right) = slice.split_at_mut(2); - /// left.clone_from_slice(&right[1..]); - /// } - /// - /// assert_eq!(slice, [4, 5, 3, 4, 5]); - /// ``` - /// - /// [`copy_from_slice`]: #method.copy_from_slice - /// [`split_at_mut`]: #method.split_at_mut - #[stable(feature = "clone_from_slice", since = "1.7.0")] - pub fn clone_from_slice(&mut self, src: &[T]) where T: Clone { - core_slice::SliceExt::clone_from_slice(self, src) - } - - /// Copies all elements from `src` into `self`, using a memcpy. - /// - /// The length of `src` must be the same as `self`. - /// - /// If `src` does not implement `Copy`, use [`clone_from_slice`]. - /// - /// # Panics - /// - /// This function will panic if the two slices have different lengths. - /// - /// # Examples - /// - /// Copying two elements from a slice into another: - /// - /// ``` - /// let src = [1, 2, 3, 4]; - /// let mut dst = [0, 0]; - /// - /// dst.copy_from_slice(&src[2..]); - /// - /// assert_eq!(src, [1, 2, 3, 4]); - /// assert_eq!(dst, [3, 4]); - /// ``` - /// - /// Rust enforces that there can only be one mutable reference with no - /// immutable references to a particular piece of data in a particular - /// scope. Because of this, attempting to use `copy_from_slice` on a - /// single slice will result in a compile failure: - /// - /// ```compile_fail - /// let mut slice = [1, 2, 3, 4, 5]; - /// - /// slice[..2].copy_from_slice(&slice[3..]); // compile fail! - /// ``` - /// - /// To work around this, we can use [`split_at_mut`] to create two distinct - /// sub-slices from a slice: - /// - /// ``` - /// let mut slice = [1, 2, 3, 4, 5]; - /// - /// { - /// let (left, right) = slice.split_at_mut(2); - /// left.copy_from_slice(&right[1..]); - /// } - /// - /// assert_eq!(slice, [4, 5, 3, 4, 5]); - /// ``` - /// - /// [`clone_from_slice`]: #method.clone_from_slice - /// [`split_at_mut`]: #method.split_at_mut - #[stable(feature = "copy_from_slice", since = "1.9.0")] - pub fn copy_from_slice(&mut self, src: &[T]) where T: Copy { - core_slice::SliceExt::copy_from_slice(self, src) - } - - /// Swaps all elements in `self` with those in `other`. - /// - /// The length of `other` must be the same as `self`. - /// - /// # Panics - /// - /// This function will panic if the two slices have different lengths. - /// - /// # Example - /// - /// Swapping two elements across slices: - /// - /// ``` - /// #![feature(swap_with_slice)] - /// - /// let mut slice1 = [0, 0]; - /// let mut slice2 = [1, 2, 3, 4]; - /// - /// slice1.swap_with_slice(&mut slice2[2..]); - /// - /// assert_eq!(slice1, [3, 4]); - /// assert_eq!(slice2, [1, 2, 0, 0]); - /// ``` - /// - /// Rust enforces that there can only be one mutable reference to a - /// particular piece of data in a particular scope. Because of this, - /// attempting to use `swap_with_slice` on a single slice will result in - /// a compile failure: - /// - /// ```compile_fail - /// #![feature(swap_with_slice)] - /// - /// let mut slice = [1, 2, 3, 4, 5]; - /// slice[..2].swap_with_slice(&mut slice[3..]); // compile fail! - /// ``` - /// - /// To work around this, we can use [`split_at_mut`] to create two distinct - /// mutable sub-slices from a slice: - /// - /// ``` - /// #![feature(swap_with_slice)] - /// - /// let mut slice = [1, 2, 3, 4, 5]; - /// - /// { - /// let (left, right) = slice.split_at_mut(2); - /// left.swap_with_slice(&mut right[1..]); - /// } - /// - /// assert_eq!(slice, [4, 5, 3, 1, 2]); - /// ``` - /// - /// [`split_at_mut`]: #method.split_at_mut - #[unstable(feature = "swap_with_slice", issue = "44030")] - pub fn swap_with_slice(&mut self, other: &mut [T]) { - core_slice::SliceExt::swap_with_slice(self, other) - } - /// Copies `self` into a new `Vec`. /// /// # Examples @@ -1791,18 +394,83 @@ impl<T> [T] { // NB see hack module in this file hack::into_vec(self) } + + /// Creates a vector by repeating a slice `n` times. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(repeat_generic_slice)] + /// + /// fn main() { + /// assert_eq!([1, 2].repeat(3), vec![1, 2, 1, 2, 1, 2]); + /// } + /// ``` + #[unstable(feature = "repeat_generic_slice", + reason = "it's on str, why not on slice?", + issue = "48784")] + pub fn repeat(&self, n: usize) -> Vec<T> where T: Copy { + if n == 0 { + return Vec::new(); + } + + // If `n` is larger than zero, it can be split as + // `n = 2^expn + rem (2^expn > rem, expn >= 0, rem >= 0)`. + // `2^expn` is the number represented by the leftmost '1' bit of `n`, + // and `rem` is the remaining part of `n`. + + // Using `Vec` to access `set_len()`. + let mut buf = Vec::with_capacity(self.len() * n); + + // `2^expn` repetition is done by doubling `buf` `expn`-times. + buf.extend(self); + { + let mut m = n >> 1; + // If `m > 0`, there are remaining bits up to the leftmost '1'. + while m > 0 { + // `buf.extend(buf)`: + unsafe { + ptr::copy_nonoverlapping( + buf.as_ptr(), + (buf.as_mut_ptr() as *mut T).add(buf.len()), + buf.len(), + ); + // `buf` has capacity of `self.len() * n`. + let buf_len = buf.len(); + buf.set_len(buf_len * 2); + } + + m >>= 1; + } + } + + // `rem` (`= n - 2^expn`) repetition is done by copying + // first `rem` repetitions from `buf` itself. + let rem_len = self.len() * n - buf.len(); // `self.len() * rem` + if rem_len > 0 { + // `buf.extend(buf[0 .. rem_len])`: + unsafe { + // This is non-overlapping since `2^expn > rem`. + ptr::copy_nonoverlapping( + buf.as_ptr(), + (buf.as_mut_ptr() as *mut T).add(buf.len()), + rem_len, + ); + // `buf.len() + rem_len` equals to `buf.capacity()` (`= self.len() * n`). + let buf_cap = buf.capacity(); + buf.set_len(buf_cap); + } + } + buf + } } -#[lang = "slice_u8"] +#[cfg_attr(stage0, lang = "slice_u8")] +#[cfg_attr(not(stage0), lang = "slice_u8_alloc")] #[cfg(not(test))] impl [u8] { - /// Checks if all bytes in this slice are within the ASCII range. - #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] - #[inline] - pub fn is_ascii(&self) -> bool { - self.iter().all(|b| b.is_ascii()) - } - /// Returns a vector containing a copy of this slice where each byte /// is mapped to its ASCII upper case equivalent. /// @@ -1837,52 +505,8 @@ impl [u8] { me } - /// Checks that two slices are an ASCII case-insensitive match. - /// - /// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`, - /// but without allocating and copying temporaries. - #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] - #[inline] - pub fn eq_ignore_ascii_case(&self, other: &[u8]) -> bool { - self.len() == other.len() && - self.iter().zip(other).all(|(a, b)| { - a.eq_ignore_ascii_case(b) - }) - } - - /// Converts this slice to its ASCII upper case equivalent in-place. - /// - /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', - /// but non-ASCII letters are unchanged. - /// - /// To return a new uppercased value without modifying the existing one, use - /// [`to_ascii_uppercase`]. - /// - /// [`to_ascii_uppercase`]: #method.to_ascii_uppercase - #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] - #[inline] - pub fn make_ascii_uppercase(&mut self) { - for byte in self { - byte.make_ascii_uppercase(); - } - } - - /// Converts this slice to its ASCII lower case equivalent in-place. - /// - /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', - /// but non-ASCII letters are unchanged. - /// - /// To return a new lowercased value without modifying the existing one, use - /// [`to_ascii_lowercase`]. - /// - /// [`to_ascii_lowercase`]: #method.to_ascii_lowercase - #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] - #[inline] - pub fn make_ascii_lowercase(&mut self) { - for byte in self { - byte.make_ascii_lowercase(); - } - } + #[cfg(stage0)] + slice_u8_core_methods!(); } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/liballoc/str.rs b/src/liballoc/str.rs index 0e708465332..0cbe65db53c 100644 --- a/src/liballoc/str.rs +++ b/src/liballoc/str.rs @@ -40,6 +40,7 @@ use core::fmt; use core::str as core_str; +#[cfg(stage0)] use core::str::StrExt; use core::str::pattern::Pattern; use core::str::pattern::{Searcher, ReverseSearcher, DoubleEndedSearcher}; use core::mem; @@ -76,7 +77,8 @@ pub use core::str::{from_utf8_unchecked, from_utf8_unchecked_mut, ParseBoolError pub use core::str::SplitWhitespace; #[stable(feature = "rust1", since = "1.0.0")] pub use core::str::pattern; - +#[stable(feature = "encode_utf16", since = "1.8.0")] +pub use core::str::EncodeUtf16; #[unstable(feature = "slice_concat_ext", reason = "trait should not have to exist", @@ -133,64 +135,6 @@ impl<S: Borrow<str>> SliceConcatExt<str> for [S] { } } -/// An iterator of [`u16`] over the string encoded as UTF-16. -/// -/// [`u16`]: ../../std/primitive.u16.html -/// -/// This struct is created by the [`encode_utf16`] method on [`str`]. -/// See its documentation for more. -/// -/// [`encode_utf16`]: ../../std/primitive.str.html#method.encode_utf16 -/// [`str`]: ../../std/primitive.str.html -#[derive(Clone)] -#[stable(feature = "encode_utf16", since = "1.8.0")] -pub struct EncodeUtf16<'a> { - chars: Chars<'a>, - extra: u16, -} - -#[stable(feature = "collection_debug", since = "1.17.0")] -impl<'a> fmt::Debug for EncodeUtf16<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.pad("EncodeUtf16 { .. }") - } -} - -#[stable(feature = "encode_utf16", since = "1.8.0")] -impl<'a> Iterator for EncodeUtf16<'a> { - type Item = u16; - - #[inline] - fn next(&mut self) -> Option<u16> { - if self.extra != 0 { - let tmp = self.extra; - self.extra = 0; - return Some(tmp); - } - - let mut buf = [0; 2]; - self.chars.next().map(|ch| { - let n = ch.encode_utf16(&mut buf).len(); - if n == 2 { - self.extra = buf[1]; - } - buf[0] - }) - } - - #[inline] - fn size_hint(&self) -> (usize, Option<usize>) { - let (low, high) = self.chars.size_hint(); - // every char gets either one u16 or two u16, - // so this iterator is between 1 or 2 times as - // long as the underlying iterator. - (low, high.and_then(|n| n.checked_mul(2))) - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl<'a> FusedIterator for EncodeUtf16<'a> {} - #[stable(feature = "rust1", since = "1.0.0")] impl Borrow<str> for String { #[inline] @@ -214,1605 +158,12 @@ impl ToOwned for str { } /// Methods for string slices. -#[lang = "str"] +#[cfg_attr(stage0, lang = "str")] +#[cfg_attr(not(stage0), lang = "str_alloc")] #[cfg(not(test))] impl str { - /// Returns the length of `self`. - /// - /// This length is in bytes, not [`char`]s or graphemes. In other words, - /// it may not be what a human considers the length of the string. - /// - /// [`char`]: primitive.char.html - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let len = "foo".len(); - /// assert_eq!(3, len); - /// - /// let len = "ƒoo".len(); // fancy f! - /// assert_eq!(4, len); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn len(&self) -> usize { - core_str::StrExt::len(self) - } - - /// Returns `true` if `self` has a length of zero bytes. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let s = ""; - /// assert!(s.is_empty()); - /// - /// let s = "not empty"; - /// assert!(!s.is_empty()); - /// ``` - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn is_empty(&self) -> bool { - core_str::StrExt::is_empty(self) - } - - /// Checks that `index`-th byte lies at the start and/or end of a - /// UTF-8 code point sequence. - /// - /// The start and end of the string (when `index == self.len()`) are - /// considered to be - /// boundaries. - /// - /// Returns `false` if `index` is greater than `self.len()`. - /// - /// # Examples - /// - /// ``` - /// let s = "Löwe 老虎 Léopard"; - /// assert!(s.is_char_boundary(0)); - /// // start of `老` - /// assert!(s.is_char_boundary(6)); - /// assert!(s.is_char_boundary(s.len())); - /// - /// // second byte of `ö` - /// assert!(!s.is_char_boundary(2)); - /// - /// // third byte of `老` - /// assert!(!s.is_char_boundary(8)); - /// ``` - #[stable(feature = "is_char_boundary", since = "1.9.0")] - #[inline] - pub fn is_char_boundary(&self, index: usize) -> bool { - core_str::StrExt::is_char_boundary(self, index) - } - - /// Converts a string slice to a byte slice. To convert the byte slice back - /// into a string slice, use the [`str::from_utf8`] function. - /// - /// [`str::from_utf8`]: ./str/fn.from_utf8.html - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let bytes = "bors".as_bytes(); - /// assert_eq!(b"bors", bytes); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline(always)] - pub fn as_bytes(&self) -> &[u8] { - core_str::StrExt::as_bytes(self) - } - - /// Converts a mutable string slice to a mutable byte slice. To convert the - /// mutable byte slice back into a mutable string slice, use the - /// [`str::from_utf8_mut`] function. - /// - /// [`str::from_utf8_mut`]: ./str/fn.from_utf8_mut.html - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let mut s = String::from("Hello"); - /// let bytes = unsafe { s.as_bytes_mut() }; - /// - /// assert_eq!(b"Hello", bytes); - /// ``` - /// - /// Mutability: - /// - /// ``` - /// let mut s = String::from("🗻∈🌏"); - /// - /// unsafe { - /// let bytes = s.as_bytes_mut(); - /// - /// bytes[0] = 0xF0; - /// bytes[1] = 0x9F; - /// bytes[2] = 0x8D; - /// bytes[3] = 0x94; - /// } - /// - /// assert_eq!("🍔∈🌏", s); - /// ``` - #[stable(feature = "str_mut_extras", since = "1.20.0")] - #[inline(always)] - pub unsafe fn as_bytes_mut(&mut self) -> &mut [u8] { - core_str::StrExt::as_bytes_mut(self) - } - - /// Converts a string slice to a raw pointer. - /// - /// As string slices are a slice of bytes, the raw pointer points to a - /// [`u8`]. This pointer will be pointing to the first byte of the string - /// slice. - /// - /// [`u8`]: primitive.u8.html - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let s = "Hello"; - /// let ptr = s.as_ptr(); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn as_ptr(&self) -> *const u8 { - core_str::StrExt::as_ptr(self) - } - - /// Returns a subslice of `str`. - /// - /// This is the non-panicking alternative to indexing the `str`. Returns - /// [`None`] whenever equivalent indexing operation would panic. - /// - /// [`None`]: option/enum.Option.html#variant.None - /// - /// # Examples - /// - /// ``` - /// let v = String::from("🗻∈🌏"); - /// - /// assert_eq!(Some("🗻"), v.get(0..4)); - /// - /// // indices not on UTF-8 sequence boundaries - /// assert!(v.get(1..).is_none()); - /// assert!(v.get(..8).is_none()); - /// - /// // out of bounds - /// assert!(v.get(..42).is_none()); - /// ``` - #[stable(feature = "str_checked_slicing", since = "1.20.0")] - #[inline] - pub fn get<I: SliceIndex<str>>(&self, i: I) -> Option<&I::Output> { - core_str::StrExt::get(self, i) - } - - /// Returns a mutable subslice of `str`. - /// - /// This is the non-panicking alternative to indexing the `str`. Returns - /// [`None`] whenever equivalent indexing operation would panic. - /// - /// [`None`]: option/enum.Option.html#variant.None - /// - /// # Examples - /// - /// ``` - /// let mut v = String::from("hello"); - /// // correct length - /// assert!(v.get_mut(0..5).is_some()); - /// // out of bounds - /// assert!(v.get_mut(..42).is_none()); - /// assert_eq!(Some("he"), v.get_mut(0..2).map(|v| &*v)); - /// - /// assert_eq!("hello", v); - /// { - /// let s = v.get_mut(0..2); - /// let s = s.map(|s| { - /// s.make_ascii_uppercase(); - /// &*s - /// }); - /// assert_eq!(Some("HE"), s); - /// } - /// assert_eq!("HEllo", v); - /// ``` - #[stable(feature = "str_checked_slicing", since = "1.20.0")] - #[inline] - pub fn get_mut<I: SliceIndex<str>>(&mut self, i: I) -> Option<&mut I::Output> { - core_str::StrExt::get_mut(self, i) - } - - /// Returns a unchecked subslice of `str`. - /// - /// This is the unchecked alternative to indexing the `str`. - /// - /// # Safety - /// - /// Callers of this function are responsible that these preconditions are - /// satisfied: - /// - /// * The starting index must come before the ending index; - /// * Indexes must be within bounds of the original slice; - /// * Indexes must lie on UTF-8 sequence boundaries. - /// - /// Failing that, the returned string slice may reference invalid memory or - /// violate the invariants communicated by the `str` type. - /// - /// # Examples - /// - /// ``` - /// let v = "🗻∈🌏"; - /// unsafe { - /// assert_eq!("🗻", v.get_unchecked(0..4)); - /// assert_eq!("∈", v.get_unchecked(4..7)); - /// assert_eq!("🌏", v.get_unchecked(7..11)); - /// } - /// ``` - #[stable(feature = "str_checked_slicing", since = "1.20.0")] - #[inline] - pub unsafe fn get_unchecked<I: SliceIndex<str>>(&self, i: I) -> &I::Output { - core_str::StrExt::get_unchecked(self, i) - } - - /// Returns a mutable, unchecked subslice of `str`. - /// - /// This is the unchecked alternative to indexing the `str`. - /// - /// # Safety - /// - /// Callers of this function are responsible that these preconditions are - /// satisfied: - /// - /// * The starting index must come before the ending index; - /// * Indexes must be within bounds of the original slice; - /// * Indexes must lie on UTF-8 sequence boundaries. - /// - /// Failing that, the returned string slice may reference invalid memory or - /// violate the invariants communicated by the `str` type. - /// - /// # Examples - /// - /// ``` - /// let mut v = String::from("🗻∈🌏"); - /// unsafe { - /// assert_eq!("🗻", v.get_unchecked_mut(0..4)); - /// assert_eq!("∈", v.get_unchecked_mut(4..7)); - /// assert_eq!("🌏", v.get_unchecked_mut(7..11)); - /// } - /// ``` - #[stable(feature = "str_checked_slicing", since = "1.20.0")] - #[inline] - pub unsafe fn get_unchecked_mut<I: SliceIndex<str>>(&mut self, i: I) -> &mut I::Output { - core_str::StrExt::get_unchecked_mut(self, i) - } - - /// Creates a string slice from another string slice, bypassing safety - /// checks. - /// - /// This is generally not recommended, use with caution! For a safe - /// alternative see [`str`] and [`Index`]. - /// - /// [`str`]: primitive.str.html - /// [`Index`]: ops/trait.Index.html - /// - /// This new slice goes from `begin` to `end`, including `begin` but - /// excluding `end`. - /// - /// To get a mutable string slice instead, see the - /// [`slice_mut_unchecked`] method. - /// - /// [`slice_mut_unchecked`]: #method.slice_mut_unchecked - /// - /// # Safety - /// - /// Callers of this function are responsible that three preconditions are - /// satisfied: - /// - /// * `begin` must come before `end`. - /// * `begin` and `end` must be byte positions within the string slice. - /// * `begin` and `end` must lie on UTF-8 sequence boundaries. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let s = "Löwe 老虎 Léopard"; - /// - /// unsafe { - /// assert_eq!("Löwe 老虎 Léopard", s.slice_unchecked(0, 21)); - /// } - /// - /// let s = "Hello, world!"; - /// - /// unsafe { - /// assert_eq!("world", s.slice_unchecked(7, 12)); - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str { - core_str::StrExt::slice_unchecked(self, begin, end) - } - - /// Creates a string slice from another string slice, bypassing safety - /// checks. - /// This is generally not recommended, use with caution! For a safe - /// alternative see [`str`] and [`IndexMut`]. - /// - /// [`str`]: primitive.str.html - /// [`IndexMut`]: ops/trait.IndexMut.html - /// - /// This new slice goes from `begin` to `end`, including `begin` but - /// excluding `end`. - /// - /// To get an immutable string slice instead, see the - /// [`slice_unchecked`] method. - /// - /// [`slice_unchecked`]: #method.slice_unchecked - /// - /// # Safety - /// - /// Callers of this function are responsible that three preconditions are - /// satisfied: - /// - /// * `begin` must come before `end`. - /// * `begin` and `end` must be byte positions within the string slice. - /// * `begin` and `end` must lie on UTF-8 sequence boundaries. - #[stable(feature = "str_slice_mut", since = "1.5.0")] - #[inline] - pub unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut str { - core_str::StrExt::slice_mut_unchecked(self, begin, end) - } - - /// Divide one string slice into two at an index. - /// - /// The argument, `mid`, should be a byte offset from the start of the - /// string. It must also be on the boundary of a UTF-8 code point. - /// - /// The two slices returned go from the start of the string slice to `mid`, - /// and from `mid` to the end of the string slice. - /// - /// To get mutable string slices instead, see the [`split_at_mut`] - /// method. - /// - /// [`split_at_mut`]: #method.split_at_mut - /// - /// # Panics - /// - /// Panics if `mid` is not on a UTF-8 code point boundary, or if it is - /// beyond the last code point of the string slice. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let s = "Per Martin-Löf"; - /// - /// let (first, last) = s.split_at(3); - /// - /// assert_eq!("Per", first); - /// assert_eq!(" Martin-Löf", last); - /// ``` - #[inline] - #[stable(feature = "str_split_at", since = "1.4.0")] - pub fn split_at(&self, mid: usize) -> (&str, &str) { - core_str::StrExt::split_at(self, mid) - } - - /// Divide one mutable string slice into two at an index. - /// - /// The argument, `mid`, should be a byte offset from the start of the - /// string. It must also be on the boundary of a UTF-8 code point. - /// - /// The two slices returned go from the start of the string slice to `mid`, - /// and from `mid` to the end of the string slice. - /// - /// To get immutable string slices instead, see the [`split_at`] method. - /// - /// [`split_at`]: #method.split_at - /// - /// # Panics - /// - /// Panics if `mid` is not on a UTF-8 code point boundary, or if it is - /// beyond the last code point of the string slice. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let mut s = "Per Martin-Löf".to_string(); - /// { - /// let (first, last) = s.split_at_mut(3); - /// first.make_ascii_uppercase(); - /// assert_eq!("PER", first); - /// assert_eq!(" Martin-Löf", last); - /// } - /// assert_eq!("PER Martin-Löf", s); - /// ``` - #[inline] - #[stable(feature = "str_split_at", since = "1.4.0")] - pub fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str) { - core_str::StrExt::split_at_mut(self, mid) - } - - /// Returns an iterator over the [`char`]s of a string slice. - /// - /// As a string slice consists of valid UTF-8, we can iterate through a - /// string slice by [`char`]. This method returns such an iterator. - /// - /// It's important to remember that [`char`] represents a Unicode Scalar - /// Value, and may not match your idea of what a 'character' is. Iteration - /// over grapheme clusters may be what you actually want. - /// - /// [`char`]: primitive.char.html - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let word = "goodbye"; - /// - /// let count = word.chars().count(); - /// assert_eq!(7, count); - /// - /// let mut chars = word.chars(); - /// - /// assert_eq!(Some('g'), chars.next()); - /// assert_eq!(Some('o'), chars.next()); - /// assert_eq!(Some('o'), chars.next()); - /// assert_eq!(Some('d'), chars.next()); - /// assert_eq!(Some('b'), chars.next()); - /// assert_eq!(Some('y'), chars.next()); - /// assert_eq!(Some('e'), chars.next()); - /// - /// assert_eq!(None, chars.next()); - /// ``` - /// - /// Remember, [`char`]s may not match your human intuition about characters: - /// - /// ``` - /// let y = "y̆"; - /// - /// let mut chars = y.chars(); - /// - /// assert_eq!(Some('y'), chars.next()); // not 'y̆' - /// assert_eq!(Some('\u{0306}'), chars.next()); - /// - /// assert_eq!(None, chars.next()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn chars(&self) -> Chars { - core_str::StrExt::chars(self) - } - /// Returns an iterator over the [`char`]s of a string slice, and their - /// positions. - /// - /// As a string slice consists of valid UTF-8, we can iterate through a - /// string slice by [`char`]. This method returns an iterator of both - /// these [`char`]s, as well as their byte positions. - /// - /// The iterator yields tuples. The position is first, the [`char`] is - /// second. - /// - /// [`char`]: primitive.char.html - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let word = "goodbye"; - /// - /// let count = word.char_indices().count(); - /// assert_eq!(7, count); - /// - /// let mut char_indices = word.char_indices(); - /// - /// assert_eq!(Some((0, 'g')), char_indices.next()); - /// assert_eq!(Some((1, 'o')), char_indices.next()); - /// assert_eq!(Some((2, 'o')), char_indices.next()); - /// assert_eq!(Some((3, 'd')), char_indices.next()); - /// assert_eq!(Some((4, 'b')), char_indices.next()); - /// assert_eq!(Some((5, 'y')), char_indices.next()); - /// assert_eq!(Some((6, 'e')), char_indices.next()); - /// - /// assert_eq!(None, char_indices.next()); - /// ``` - /// - /// Remember, [`char`]s may not match your human intuition about characters: - /// - /// ``` - /// let yes = "y̆es"; - /// - /// let mut char_indices = yes.char_indices(); - /// - /// assert_eq!(Some((0, 'y')), char_indices.next()); // not (0, 'y̆') - /// assert_eq!(Some((1, '\u{0306}')), char_indices.next()); - /// - /// // note the 3 here - the last character took up two bytes - /// assert_eq!(Some((3, 'e')), char_indices.next()); - /// assert_eq!(Some((4, 's')), char_indices.next()); - /// - /// assert_eq!(None, char_indices.next()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn char_indices(&self) -> CharIndices { - core_str::StrExt::char_indices(self) - } - - /// An iterator over the bytes of a string slice. - /// - /// As a string slice consists of a sequence of bytes, we can iterate - /// through a string slice by byte. This method returns such an iterator. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let mut bytes = "bors".bytes(); - /// - /// assert_eq!(Some(b'b'), bytes.next()); - /// assert_eq!(Some(b'o'), bytes.next()); - /// assert_eq!(Some(b'r'), bytes.next()); - /// assert_eq!(Some(b's'), bytes.next()); - /// - /// assert_eq!(None, bytes.next()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn bytes(&self) -> Bytes { - core_str::StrExt::bytes(self) - } - - /// Split a string slice by whitespace. - /// - /// The iterator returned will return string slices that are sub-slices of - /// the original string slice, separated by any amount of whitespace. - /// - /// 'Whitespace' is defined according to the terms of the Unicode Derived - /// Core Property `White_Space`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let mut iter = "A few words".split_whitespace(); - /// - /// assert_eq!(Some("A"), iter.next()); - /// assert_eq!(Some("few"), iter.next()); - /// assert_eq!(Some("words"), iter.next()); - /// - /// assert_eq!(None, iter.next()); - /// ``` - /// - /// All kinds of whitespace are considered: - /// - /// ``` - /// let mut iter = " Mary had\ta\u{2009}little \n\t lamb".split_whitespace(); - /// assert_eq!(Some("Mary"), iter.next()); - /// assert_eq!(Some("had"), iter.next()); - /// assert_eq!(Some("a"), iter.next()); - /// assert_eq!(Some("little"), iter.next()); - /// assert_eq!(Some("lamb"), iter.next()); - /// - /// assert_eq!(None, iter.next()); - /// ``` - #[stable(feature = "split_whitespace", since = "1.1.0")] - #[inline] - pub fn split_whitespace(&self) -> SplitWhitespace { - StrExt::split_whitespace(self) - } - - /// An iterator over the lines of a string, as string slices. - /// - /// Lines are ended with either a newline (`\n`) or a carriage return with - /// a line feed (`\r\n`). - /// - /// The final line ending is optional. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let text = "foo\r\nbar\n\nbaz\n"; - /// let mut lines = text.lines(); - /// - /// assert_eq!(Some("foo"), lines.next()); - /// assert_eq!(Some("bar"), lines.next()); - /// assert_eq!(Some(""), lines.next()); - /// assert_eq!(Some("baz"), lines.next()); - /// - /// assert_eq!(None, lines.next()); - /// ``` - /// - /// The final line ending isn't required: - /// - /// ``` - /// let text = "foo\nbar\n\r\nbaz"; - /// let mut lines = text.lines(); - /// - /// assert_eq!(Some("foo"), lines.next()); - /// assert_eq!(Some("bar"), lines.next()); - /// assert_eq!(Some(""), lines.next()); - /// assert_eq!(Some("baz"), lines.next()); - /// - /// assert_eq!(None, lines.next()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn lines(&self) -> Lines { - core_str::StrExt::lines(self) - } - - /// An iterator over the lines of a string. - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_deprecated(since = "1.4.0", reason = "use lines() instead now")] - #[inline] - #[allow(deprecated)] - pub fn lines_any(&self) -> LinesAny { - core_str::StrExt::lines_any(self) - } - - /// Returns an iterator of `u16` over the string encoded as UTF-16. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let text = "Zażółć gęślą jaźń"; - /// - /// let utf8_len = text.len(); - /// let utf16_len = text.encode_utf16().count(); - /// - /// assert!(utf16_len <= utf8_len); - /// ``` - #[stable(feature = "encode_utf16", since = "1.8.0")] - pub fn encode_utf16(&self) -> EncodeUtf16 { - EncodeUtf16 { chars: self[..].chars(), extra: 0 } - } - - /// Returns `true` if the given pattern matches a sub-slice of - /// this string slice. - /// - /// Returns `false` if it does not. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let bananas = "bananas"; - /// - /// assert!(bananas.contains("nana")); - /// assert!(!bananas.contains("apples")); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn contains<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool { - core_str::StrExt::contains(self, pat) - } - - /// Returns `true` if the given pattern matches a prefix of this - /// string slice. - /// - /// Returns `false` if it does not. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let bananas = "bananas"; - /// - /// assert!(bananas.starts_with("bana")); - /// assert!(!bananas.starts_with("nana")); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn starts_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool { - core_str::StrExt::starts_with(self, pat) - } - - /// Returns `true` if the given pattern matches a suffix of this - /// string slice. - /// - /// Returns `false` if it does not. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let bananas = "bananas"; - /// - /// assert!(bananas.ends_with("anas")); - /// assert!(!bananas.ends_with("nana")); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn ends_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool - where P::Searcher: ReverseSearcher<'a> - { - core_str::StrExt::ends_with(self, pat) - } - - /// Returns the byte index of the first character of this string slice that - /// matches the pattern. - /// - /// Returns [`None`] if the pattern doesn't match. - /// - /// The pattern can be a `&str`, [`char`], or a closure that determines if - /// a character matches. - /// - /// [`char`]: primitive.char.html - /// [`None`]: option/enum.Option.html#variant.None - /// - /// # Examples - /// - /// Simple patterns: - /// - /// ``` - /// let s = "Löwe 老虎 Léopard"; - /// - /// assert_eq!(s.find('L'), Some(0)); - /// assert_eq!(s.find('é'), Some(14)); - /// assert_eq!(s.find("Léopard"), Some(13)); - /// ``` - /// - /// More complex patterns using point-free style and closures: - /// - /// ``` - /// let s = "Löwe 老虎 Léopard"; - /// - /// assert_eq!(s.find(char::is_whitespace), Some(5)); - /// assert_eq!(s.find(char::is_lowercase), Some(1)); - /// assert_eq!(s.find(|c: char| c.is_whitespace() || c.is_lowercase()), Some(1)); - /// assert_eq!(s.find(|c: char| (c < 'o') && (c > 'a')), Some(4)); - /// ``` - /// - /// Not finding the pattern: - /// - /// ``` - /// let s = "Löwe 老虎 Léopard"; - /// let x: &[_] = &['1', '2']; - /// - /// assert_eq!(s.find(x), None); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize> { - core_str::StrExt::find(self, pat) - } - - /// Returns the byte index of the last character of this string slice that - /// matches the pattern. - /// - /// Returns [`None`] if the pattern doesn't match. - /// - /// The pattern can be a `&str`, [`char`], or a closure that determines if - /// a character matches. - /// - /// [`char`]: primitive.char.html - /// [`None`]: option/enum.Option.html#variant.None - /// - /// # Examples - /// - /// Simple patterns: - /// - /// ``` - /// let s = "Löwe 老虎 Léopard"; - /// - /// assert_eq!(s.rfind('L'), Some(13)); - /// assert_eq!(s.rfind('é'), Some(14)); - /// ``` - /// - /// More complex patterns with closures: - /// - /// ``` - /// let s = "Löwe 老虎 Léopard"; - /// - /// assert_eq!(s.rfind(char::is_whitespace), Some(12)); - /// assert_eq!(s.rfind(char::is_lowercase), Some(20)); - /// ``` - /// - /// Not finding the pattern: - /// - /// ``` - /// let s = "Löwe 老虎 Léopard"; - /// let x: &[_] = &['1', '2']; - /// - /// assert_eq!(s.rfind(x), None); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn rfind<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize> - where P::Searcher: ReverseSearcher<'a> - { - core_str::StrExt::rfind(self, pat) - } - - /// An iterator over substrings of this string slice, separated by - /// characters matched by a pattern. - /// - /// The pattern can be a `&str`, [`char`], or a closure that determines the - /// split. - /// - /// # Iterator behavior - /// - /// The returned iterator will be a [`DoubleEndedIterator`] if the pattern - /// allows a reverse search and forward/reverse search yields the same - /// elements. This is true for, eg, [`char`] but not for `&str`. - /// - /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html - /// - /// If the pattern allows a reverse search but its results might differ - /// from a forward search, the [`rsplit`] method can be used. - /// - /// [`char`]: primitive.char.html - /// [`rsplit`]: #method.rsplit - /// - /// # Examples - /// - /// Simple patterns: - /// - /// ``` - /// let v: Vec<&str> = "Mary had a little lamb".split(' ').collect(); - /// assert_eq!(v, ["Mary", "had", "a", "little", "lamb"]); - /// - /// let v: Vec<&str> = "".split('X').collect(); - /// assert_eq!(v, [""]); - /// - /// let v: Vec<&str> = "lionXXtigerXleopard".split('X').collect(); - /// assert_eq!(v, ["lion", "", "tiger", "leopard"]); - /// - /// let v: Vec<&str> = "lion::tiger::leopard".split("::").collect(); - /// assert_eq!(v, ["lion", "tiger", "leopard"]); - /// - /// let v: Vec<&str> = "abc1def2ghi".split(char::is_numeric).collect(); - /// assert_eq!(v, ["abc", "def", "ghi"]); - /// - /// let v: Vec<&str> = "lionXtigerXleopard".split(char::is_uppercase).collect(); - /// assert_eq!(v, ["lion", "tiger", "leopard"]); - /// ``` - /// - /// A more complex pattern, using a closure: - /// - /// ``` - /// let v: Vec<&str> = "abc1defXghi".split(|c| c == '1' || c == 'X').collect(); - /// assert_eq!(v, ["abc", "def", "ghi"]); - /// ``` - /// - /// If a string contains multiple contiguous separators, you will end up - /// with empty strings in the output: - /// - /// ``` - /// let x = "||||a||b|c".to_string(); - /// let d: Vec<_> = x.split('|').collect(); - /// - /// assert_eq!(d, &["", "", "", "", "a", "", "b", "c"]); - /// ``` - /// - /// Contiguous separators are separated by the empty string. - /// - /// ``` - /// let x = "(///)".to_string(); - /// let d: Vec<_> = x.split('/').collect(); - /// - /// assert_eq!(d, &["(", "", "", ")"]); - /// ``` - /// - /// Separators at the start or end of a string are neighbored - /// by empty strings. - /// - /// ``` - /// let d: Vec<_> = "010".split("0").collect(); - /// assert_eq!(d, &["", "1", ""]); - /// ``` - /// - /// When the empty string is used as a separator, it separates - /// every character in the string, along with the beginning - /// and end of the string. - /// - /// ``` - /// let f: Vec<_> = "rust".split("").collect(); - /// assert_eq!(f, &["", "r", "u", "s", "t", ""]); - /// ``` - /// - /// Contiguous separators can lead to possibly surprising behavior - /// when whitespace is used as the separator. This code is correct: - /// - /// ``` - /// let x = " a b c".to_string(); - /// let d: Vec<_> = x.split(' ').collect(); - /// - /// assert_eq!(d, &["", "", "", "", "a", "", "b", "c"]); - /// ``` - /// - /// It does _not_ give you: - /// - /// ```,ignore - /// assert_eq!(d, &["a", "b", "c"]); - /// ``` - /// - /// Use [`split_whitespace`] for this behavior. - /// - /// [`split_whitespace`]: #method.split_whitespace - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P> { - core_str::StrExt::split(self, pat) - } - - /// An iterator over substrings of the given string slice, separated by - /// characters matched by a pattern and yielded in reverse order. - /// - /// The pattern can be a `&str`, [`char`], or a closure that determines the - /// split. - /// - /// [`char`]: primitive.char.html - /// - /// # Iterator behavior - /// - /// The returned iterator requires that the pattern supports a reverse - /// search, and it will be a [`DoubleEndedIterator`] if a forward/reverse - /// search yields the same elements. - /// - /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html - /// - /// For iterating from the front, the [`split`] method can be used. - /// - /// [`split`]: #method.split - /// - /// # Examples - /// - /// Simple patterns: - /// - /// ``` - /// let v: Vec<&str> = "Mary had a little lamb".rsplit(' ').collect(); - /// assert_eq!(v, ["lamb", "little", "a", "had", "Mary"]); - /// - /// let v: Vec<&str> = "".rsplit('X').collect(); - /// assert_eq!(v, [""]); - /// - /// let v: Vec<&str> = "lionXXtigerXleopard".rsplit('X').collect(); - /// assert_eq!(v, ["leopard", "tiger", "", "lion"]); - /// - /// let v: Vec<&str> = "lion::tiger::leopard".rsplit("::").collect(); - /// assert_eq!(v, ["leopard", "tiger", "lion"]); - /// ``` - /// - /// A more complex pattern, using a closure: - /// - /// ``` - /// let v: Vec<&str> = "abc1defXghi".rsplit(|c| c == '1' || c == 'X').collect(); - /// assert_eq!(v, ["ghi", "def", "abc"]); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn rsplit<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplit<'a, P> - where P::Searcher: ReverseSearcher<'a> - { - core_str::StrExt::rsplit(self, pat) - } - - /// An iterator over substrings of the given string slice, separated by - /// characters matched by a pattern. - /// - /// The pattern can be a `&str`, [`char`], or a closure that determines the - /// split. - /// - /// Equivalent to [`split`], except that the trailing substring - /// is skipped if empty. - /// - /// [`split`]: #method.split - /// - /// This method can be used for string data that is _terminated_, - /// rather than _separated_ by a pattern. - /// - /// # Iterator behavior - /// - /// The returned iterator will be a [`DoubleEndedIterator`] if the pattern - /// allows a reverse search and forward/reverse search yields the same - /// elements. This is true for, eg, [`char`] but not for `&str`. - /// - /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html - /// [`char`]: primitive.char.html - /// - /// If the pattern allows a reverse search but its results might differ - /// from a forward search, the [`rsplit_terminator`] method can be used. - /// - /// [`rsplit_terminator`]: #method.rsplit_terminator - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let v: Vec<&str> = "A.B.".split_terminator('.').collect(); - /// assert_eq!(v, ["A", "B"]); - /// - /// let v: Vec<&str> = "A..B..".split_terminator(".").collect(); - /// assert_eq!(v, ["A", "", "B", ""]); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn split_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitTerminator<'a, P> { - core_str::StrExt::split_terminator(self, pat) - } - - /// An iterator over substrings of `self`, separated by characters - /// matched by a pattern and yielded in reverse order. - /// - /// The pattern can be a simple `&str`, [`char`], or a closure that - /// determines the split. - /// Additional libraries might provide more complex patterns like - /// regular expressions. - /// - /// [`char`]: primitive.char.html - /// - /// Equivalent to [`split`], except that the trailing substring is - /// skipped if empty. - /// - /// [`split`]: #method.split - /// - /// This method can be used for string data that is _terminated_, - /// rather than _separated_ by a pattern. - /// - /// # Iterator behavior - /// - /// The returned iterator requires that the pattern supports a - /// reverse search, and it will be double ended if a forward/reverse - /// search yields the same elements. - /// - /// For iterating from the front, the [`split_terminator`] method can be - /// used. - /// - /// [`split_terminator`]: #method.split_terminator - /// - /// # Examples - /// - /// ``` - /// let v: Vec<&str> = "A.B.".rsplit_terminator('.').collect(); - /// assert_eq!(v, ["B", "A"]); - /// - /// let v: Vec<&str> = "A..B..".rsplit_terminator(".").collect(); - /// assert_eq!(v, ["", "B", "", "A"]); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn rsplit_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplitTerminator<'a, P> - where P::Searcher: ReverseSearcher<'a> - { - core_str::StrExt::rsplit_terminator(self, pat) - } - - /// An iterator over substrings of the given string slice, separated by a - /// pattern, restricted to returning at most `n` items. - /// - /// If `n` substrings are returned, the last substring (the `n`th substring) - /// will contain the remainder of the string. - /// - /// The pattern can be a `&str`, [`char`], or a closure that determines the - /// split. - /// - /// [`char`]: primitive.char.html - /// - /// # Iterator behavior - /// - /// The returned iterator will not be double ended, because it is - /// not efficient to support. - /// - /// If the pattern allows a reverse search, the [`rsplitn`] method can be - /// used. - /// - /// [`rsplitn`]: #method.rsplitn - /// - /// # Examples - /// - /// Simple patterns: - /// - /// ``` - /// let v: Vec<&str> = "Mary had a little lambda".splitn(3, ' ').collect(); - /// assert_eq!(v, ["Mary", "had", "a little lambda"]); - /// - /// let v: Vec<&str> = "lionXXtigerXleopard".splitn(3, "X").collect(); - /// assert_eq!(v, ["lion", "", "tigerXleopard"]); - /// - /// let v: Vec<&str> = "abcXdef".splitn(1, 'X').collect(); - /// assert_eq!(v, ["abcXdef"]); - /// - /// let v: Vec<&str> = "".splitn(1, 'X').collect(); - /// assert_eq!(v, [""]); - /// ``` - /// - /// A more complex pattern, using a closure: - /// - /// ``` - /// let v: Vec<&str> = "abc1defXghi".splitn(2, |c| c == '1' || c == 'X').collect(); - /// assert_eq!(v, ["abc", "defXghi"]); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn splitn<'a, P: Pattern<'a>>(&'a self, n: usize, pat: P) -> SplitN<'a, P> { - core_str::StrExt::splitn(self, n, pat) - } - - /// An iterator over substrings of this string slice, separated by a - /// pattern, starting from the end of the string, restricted to returning - /// at most `n` items. - /// - /// If `n` substrings are returned, the last substring (the `n`th substring) - /// will contain the remainder of the string. - /// - /// The pattern can be a `&str`, [`char`], or a closure that - /// determines the split. - /// - /// [`char`]: primitive.char.html - /// - /// # Iterator behavior - /// - /// The returned iterator will not be double ended, because it is not - /// efficient to support. - /// - /// For splitting from the front, the [`splitn`] method can be used. - /// - /// [`splitn`]: #method.splitn - /// - /// # Examples - /// - /// Simple patterns: - /// - /// ``` - /// let v: Vec<&str> = "Mary had a little lamb".rsplitn(3, ' ').collect(); - /// assert_eq!(v, ["lamb", "little", "Mary had a"]); - /// - /// let v: Vec<&str> = "lionXXtigerXleopard".rsplitn(3, 'X').collect(); - /// assert_eq!(v, ["leopard", "tiger", "lionX"]); - /// - /// let v: Vec<&str> = "lion::tiger::leopard".rsplitn(2, "::").collect(); - /// assert_eq!(v, ["leopard", "lion::tiger"]); - /// ``` - /// - /// A more complex pattern, using a closure: - /// - /// ``` - /// let v: Vec<&str> = "abc1defXghi".rsplitn(2, |c| c == '1' || c == 'X').collect(); - /// assert_eq!(v, ["ghi", "abc1def"]); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn rsplitn<'a, P: Pattern<'a>>(&'a self, n: usize, pat: P) -> RSplitN<'a, P> - where P::Searcher: ReverseSearcher<'a> - { - core_str::StrExt::rsplitn(self, n, pat) - } - - /// An iterator over the disjoint matches of a pattern within the given string - /// slice. - /// - /// The pattern can be a `&str`, [`char`], or a closure that - /// determines if a character matches. - /// - /// [`char`]: primitive.char.html - /// - /// # Iterator behavior - /// - /// The returned iterator will be a [`DoubleEndedIterator`] if the pattern - /// allows a reverse search and forward/reverse search yields the same - /// elements. This is true for, eg, [`char`] but not for `&str`. - /// - /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html - /// [`char`]: primitive.char.html - /// - /// If the pattern allows a reverse search but its results might differ - /// from a forward search, the [`rmatches`] method can be used. - /// - /// [`rmatches`]: #method.rmatches - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let v: Vec<&str> = "abcXXXabcYYYabc".matches("abc").collect(); - /// assert_eq!(v, ["abc", "abc", "abc"]); - /// - /// let v: Vec<&str> = "1abc2abc3".matches(char::is_numeric).collect(); - /// assert_eq!(v, ["1", "2", "3"]); - /// ``` - #[stable(feature = "str_matches", since = "1.2.0")] - #[inline] - pub fn matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> Matches<'a, P> { - core_str::StrExt::matches(self, pat) - } - - /// An iterator over the disjoint matches of a pattern within this string slice, - /// yielded in reverse order. - /// - /// The pattern can be a `&str`, [`char`], or a closure that determines if - /// a character matches. - /// - /// [`char`]: primitive.char.html - /// - /// # Iterator behavior - /// - /// The returned iterator requires that the pattern supports a reverse - /// search, and it will be a [`DoubleEndedIterator`] if a forward/reverse - /// search yields the same elements. - /// - /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html - /// - /// For iterating from the front, the [`matches`] method can be used. - /// - /// [`matches`]: #method.matches - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let v: Vec<&str> = "abcXXXabcYYYabc".rmatches("abc").collect(); - /// assert_eq!(v, ["abc", "abc", "abc"]); - /// - /// let v: Vec<&str> = "1abc2abc3".rmatches(char::is_numeric).collect(); - /// assert_eq!(v, ["3", "2", "1"]); - /// ``` - #[stable(feature = "str_matches", since = "1.2.0")] - #[inline] - pub fn rmatches<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatches<'a, P> - where P::Searcher: ReverseSearcher<'a> - { - core_str::StrExt::rmatches(self, pat) - } - - /// An iterator over the disjoint matches of a pattern within this string - /// slice as well as the index that the match starts at. - /// - /// For matches of `pat` within `self` that overlap, only the indices - /// corresponding to the first match are returned. - /// - /// The pattern can be a `&str`, [`char`], or a closure that determines - /// if a character matches. - /// - /// [`char`]: primitive.char.html - /// - /// # Iterator behavior - /// - /// The returned iterator will be a [`DoubleEndedIterator`] if the pattern - /// allows a reverse search and forward/reverse search yields the same - /// elements. This is true for, eg, [`char`] but not for `&str`. - /// - /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html - /// - /// If the pattern allows a reverse search but its results might differ - /// from a forward search, the [`rmatch_indices`] method can be used. - /// - /// [`rmatch_indices`]: #method.rmatch_indices - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let v: Vec<_> = "abcXXXabcYYYabc".match_indices("abc").collect(); - /// assert_eq!(v, [(0, "abc"), (6, "abc"), (12, "abc")]); - /// - /// let v: Vec<_> = "1abcabc2".match_indices("abc").collect(); - /// assert_eq!(v, [(1, "abc"), (4, "abc")]); - /// - /// let v: Vec<_> = "ababa".match_indices("aba").collect(); - /// assert_eq!(v, [(0, "aba")]); // only the first `aba` - /// ``` - #[stable(feature = "str_match_indices", since = "1.5.0")] - #[inline] - pub fn match_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> MatchIndices<'a, P> { - core_str::StrExt::match_indices(self, pat) - } - - /// An iterator over the disjoint matches of a pattern within `self`, - /// yielded in reverse order along with the index of the match. - /// - /// For matches of `pat` within `self` that overlap, only the indices - /// corresponding to the last match are returned. - /// - /// The pattern can be a `&str`, [`char`], or a closure that determines if a - /// character matches. - /// - /// [`char`]: primitive.char.html - /// - /// # Iterator behavior - /// - /// The returned iterator requires that the pattern supports a reverse - /// search, and it will be a [`DoubleEndedIterator`] if a forward/reverse - /// search yields the same elements. - /// - /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html - /// - /// For iterating from the front, the [`match_indices`] method can be used. - /// - /// [`match_indices`]: #method.match_indices - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let v: Vec<_> = "abcXXXabcYYYabc".rmatch_indices("abc").collect(); - /// assert_eq!(v, [(12, "abc"), (6, "abc"), (0, "abc")]); - /// - /// let v: Vec<_> = "1abcabc2".rmatch_indices("abc").collect(); - /// assert_eq!(v, [(4, "abc"), (1, "abc")]); - /// - /// let v: Vec<_> = "ababa".rmatch_indices("aba").collect(); - /// assert_eq!(v, [(2, "aba")]); // only the last `aba` - /// ``` - #[stable(feature = "str_match_indices", since = "1.5.0")] - #[inline] - pub fn rmatch_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatchIndices<'a, P> - where P::Searcher: ReverseSearcher<'a> - { - core_str::StrExt::rmatch_indices(self, pat) - } - - /// Returns a string slice with leading and trailing whitespace removed. - /// - /// 'Whitespace' is defined according to the terms of the Unicode Derived - /// Core Property `White_Space`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let s = " Hello\tworld\t"; - /// - /// assert_eq!("Hello\tworld", s.trim()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn trim(&self) -> &str { - StrExt::trim(self) - } - - /// Returns a string slice with leading whitespace removed. - /// - /// 'Whitespace' is defined according to the terms of the Unicode Derived - /// Core Property `White_Space`. - /// - /// # Text directionality - /// - /// A string is a sequence of bytes. 'Left' in this context means the first - /// position of that byte string; for a language like Arabic or Hebrew - /// which are 'right to left' rather than 'left to right', this will be - /// the _right_ side, not the left. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let s = " Hello\tworld\t"; - /// - /// assert_eq!("Hello\tworld\t", s.trim_left()); - /// ``` - /// - /// Directionality: - /// - /// ``` - /// let s = " English"; - /// assert!(Some('E') == s.trim_left().chars().next()); - /// - /// let s = " עברית"; - /// assert!(Some('ע') == s.trim_left().chars().next()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn trim_left(&self) -> &str { - StrExt::trim_left(self) - } - - /// Returns a string slice with trailing whitespace removed. - /// - /// 'Whitespace' is defined according to the terms of the Unicode Derived - /// Core Property `White_Space`. - /// - /// # Text directionality - /// - /// A string is a sequence of bytes. 'Right' in this context means the last - /// position of that byte string; for a language like Arabic or Hebrew - /// which are 'right to left' rather than 'left to right', this will be - /// the _left_ side, not the right. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// let s = " Hello\tworld\t"; - /// - /// assert_eq!(" Hello\tworld", s.trim_right()); - /// ``` - /// - /// Directionality: - /// - /// ``` - /// let s = "English "; - /// assert!(Some('h') == s.trim_right().chars().rev().next()); - /// - /// let s = "עברית "; - /// assert!(Some('ת') == s.trim_right().chars().rev().next()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn trim_right(&self) -> &str { - StrExt::trim_right(self) - } - - /// Returns a string slice with all prefixes and suffixes that match a - /// pattern repeatedly removed. - /// - /// The pattern can be a [`char`] or a closure that determines if a - /// character matches. - /// - /// [`char`]: primitive.char.html - /// - /// # Examples - /// - /// Simple patterns: - /// - /// ``` - /// assert_eq!("11foo1bar11".trim_matches('1'), "foo1bar"); - /// assert_eq!("123foo1bar123".trim_matches(char::is_numeric), "foo1bar"); - /// - /// let x: &[_] = &['1', '2']; - /// assert_eq!("12foo1bar12".trim_matches(x), "foo1bar"); - /// ``` - /// - /// A more complex pattern, using a closure: - /// - /// ``` - /// assert_eq!("1foo1barXX".trim_matches(|c| c == '1' || c == 'X'), "foo1bar"); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn trim_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str - where P::Searcher: DoubleEndedSearcher<'a> - { - core_str::StrExt::trim_matches(self, pat) - } - - /// Returns a string slice with all prefixes that match a pattern - /// repeatedly removed. - /// - /// The pattern can be a `&str`, [`char`], or a closure that determines if - /// a character matches. - /// - /// [`char`]: primitive.char.html - /// - /// # Text directionality - /// - /// A string is a sequence of bytes. 'Left' in this context means the first - /// position of that byte string; for a language like Arabic or Hebrew - /// which are 'right to left' rather than 'left to right', this will be - /// the _right_ side, not the left. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert_eq!("11foo1bar11".trim_left_matches('1'), "foo1bar11"); - /// assert_eq!("123foo1bar123".trim_left_matches(char::is_numeric), "foo1bar123"); - /// - /// let x: &[_] = &['1', '2']; - /// assert_eq!("12foo1bar12".trim_left_matches(x), "foo1bar12"); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn trim_left_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str { - core_str::StrExt::trim_left_matches(self, pat) - } - - /// Returns a string slice with all suffixes that match a pattern - /// repeatedly removed. - /// - /// The pattern can be a `&str`, [`char`], or a closure that - /// determines if a character matches. - /// - /// [`char`]: primitive.char.html - /// - /// # Text directionality - /// - /// A string is a sequence of bytes. 'Right' in this context means the last - /// position of that byte string; for a language like Arabic or Hebrew - /// which are 'right to left' rather than 'left to right', this will be - /// the _left_ side, not the right. - /// - /// # Examples - /// - /// Simple patterns: - /// - /// ``` - /// assert_eq!("11foo1bar11".trim_right_matches('1'), "11foo1bar"); - /// assert_eq!("123foo1bar123".trim_right_matches(char::is_numeric), "123foo1bar"); - /// - /// let x: &[_] = &['1', '2']; - /// assert_eq!("12foo1bar12".trim_right_matches(x), "12foo1bar"); - /// ``` - /// - /// A more complex pattern, using a closure: - /// - /// ``` - /// assert_eq!("1fooX".trim_right_matches(|c| c == '1' || c == 'X'), "1foo"); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn trim_right_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str - where P::Searcher: ReverseSearcher<'a> - { - core_str::StrExt::trim_right_matches(self, pat) - } - - /// Parses this string slice into another type. - /// - /// Because `parse` is so general, it can cause problems with type - /// inference. As such, `parse` is one of the few times you'll see - /// the syntax affectionately known as the 'turbofish': `::<>`. This - /// helps the inference algorithm understand specifically which type - /// you're trying to parse into. - /// - /// `parse` can parse any type that implements the [`FromStr`] trait. - /// - /// [`FromStr`]: str/trait.FromStr.html - /// - /// # Errors - /// - /// Will return [`Err`] if it's not possible to parse this string slice into - /// the desired type. - /// - /// [`Err`]: str/trait.FromStr.html#associatedtype.Err - /// - /// # Examples - /// - /// Basic usage - /// - /// ``` - /// let four: u32 = "4".parse().unwrap(); - /// - /// assert_eq!(4, four); - /// ``` - /// - /// Using the 'turbofish' instead of annotating `four`: - /// - /// ``` - /// let four = "4".parse::<u32>(); - /// - /// assert_eq!(Ok(4), four); - /// ``` - /// - /// Failing to parse: - /// - /// ``` - /// let nope = "j".parse::<u32>(); - /// - /// assert!(nope.is_err()); - /// ``` - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn parse<F: FromStr>(&self) -> Result<F, F::Err> { - core_str::StrExt::parse(self) - } + #[cfg(stage0)] + str_core_methods!(); /// Converts a `Box<str>` into a `Box<[u8]>` without copying or allocating. /// @@ -1856,6 +207,7 @@ impl str { /// let s = "this is old"; /// assert_eq!(s, s.replace("cookie monster", "little lamb")); /// ``` + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn replace<'a, P: Pattern<'a>>(&'a self, from: P, to: &str) -> String { @@ -1895,6 +247,7 @@ impl str { /// let s = "this is old"; /// assert_eq!(s, s.replacen("cookie monster", "little lamb", 10)); /// ``` + #[must_use] #[stable(feature = "str_replacen", since = "1.16.0")] pub fn replacen<'a, P: Pattern<'a>>(&'a self, pat: P, to: &str, count: usize) -> String { // Hope to reduce the times of re-allocation @@ -2085,121 +438,7 @@ impl str { /// ``` #[stable(feature = "repeat_str", since = "1.16.0")] pub fn repeat(&self, n: usize) -> String { - if n == 0 { - return String::new(); - } - - // If `n` is larger than zero, it can be split as - // `n = 2^expn + rem (2^expn > rem, expn >= 0, rem >= 0)`. - // `2^expn` is the number represented by the leftmost '1' bit of `n`, - // and `rem` is the remaining part of `n`. - - // Using `Vec` to access `set_len()`. - let mut buf = Vec::with_capacity(self.len() * n); - - // `2^expn` repetition is done by doubling `buf` `expn`-times. - buf.extend(self.as_bytes()); - { - let mut m = n >> 1; - // If `m > 0`, there are remaining bits up to the leftmost '1'. - while m > 0 { - // `buf.extend(buf)`: - unsafe { - ptr::copy_nonoverlapping( - buf.as_ptr(), - (buf.as_mut_ptr() as *mut u8).add(buf.len()), - buf.len(), - ); - // `buf` has capacity of `self.len() * n`. - let buf_len = buf.len(); - buf.set_len(buf_len * 2); - } - - m >>= 1; - } - } - - // `rem` (`= n - 2^expn`) repetition is done by copying - // first `rem` repetitions from `buf` itself. - let rem_len = self.len() * n - buf.len(); // `self.len() * rem` - if rem_len > 0 { - // `buf.extend(buf[0 .. rem_len])`: - unsafe { - // This is non-overlapping since `2^expn > rem`. - ptr::copy_nonoverlapping( - buf.as_ptr(), - (buf.as_mut_ptr() as *mut u8).add(buf.len()), - rem_len, - ); - // `buf.len() + rem_len` equals to `buf.capacity()` (`= self.len() * n`). - let buf_cap = buf.capacity(); - buf.set_len(buf_cap); - } - } - - unsafe { String::from_utf8_unchecked(buf) } - } - - /// Returns true if this `str` is entirely whitespace, and false otherwise. - /// - /// 'Whitespace' is defined according to the terms of the Unicode Derived Core - /// Property `White_Space`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert!(" \t ".is_whitespace()); - /// - /// // a non-breaking space - /// assert!("\u{A0}".is_whitespace()); - /// - /// assert!(!" 越".is_whitespace()); - /// ``` - #[stable(feature = "unicode_methods_on_intrinsics", since = "1.27.0")] - #[inline] - pub fn is_whitespace(&self) -> bool { - StrExt::is_whitespace(self) - } - - /// Returns true if this `str` is entirely alphanumeric, and false otherwise. - /// - /// 'Alphanumeric'-ness is defined in terms of the Unicode General Categories - /// 'Nd', 'Nl', 'No' and the Derived Core Property 'Alphabetic'. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// assert!("٣7৬Kو藏".is_alphanumeric()); - /// assert!(!"¾①".is_alphanumeric()); - /// ``` - #[stable(feature = "unicode_methods_on_intrinsics", since = "1.27.0")] - #[inline] - pub fn is_alphanumeric(&self) -> bool { - StrExt::is_alphanumeric(self) - } - - /// Checks if all characters in this string are within the ASCII range. - /// - /// # Examples - /// - /// ``` - /// let ascii = "hello!\n"; - /// let non_ascii = "Grüße, Jürgen ❤"; - /// - /// assert!(ascii.is_ascii()); - /// assert!(!non_ascii.is_ascii()); - /// ``` - #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] - #[inline] - pub fn is_ascii(&self) -> bool { - // We can treat each byte as character here: all multibyte characters - // start with a byte that is not in the ascii range, so we will stop - // there already. - self.bytes().all(|b| b.is_ascii()) + unsafe { String::from_utf8_unchecked(self.as_bytes().repeat(n)) } } /// Returns a copy of this string where each character is mapped to its @@ -2261,54 +500,6 @@ impl str { // make_ascii_lowercase() preserves the UTF-8 invariant. unsafe { String::from_utf8_unchecked(bytes) } } - - /// Checks that two strings are an ASCII case-insensitive match. - /// - /// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`, - /// but without allocating and copying temporaries. - /// - /// # Examples - /// - /// ``` - /// assert!("Ferris".eq_ignore_ascii_case("FERRIS")); - /// assert!("Ferrös".eq_ignore_ascii_case("FERRöS")); - /// assert!(!"Ferrös".eq_ignore_ascii_case("FERRÖS")); - /// ``` - #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] - #[inline] - pub fn eq_ignore_ascii_case(&self, other: &str) -> bool { - self.as_bytes().eq_ignore_ascii_case(other.as_bytes()) - } - - /// Converts this string to its ASCII upper case equivalent in-place. - /// - /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', - /// but non-ASCII letters are unchanged. - /// - /// To return a new uppercased value without modifying the existing one, use - /// [`to_ascii_uppercase`]. - /// - /// [`to_ascii_uppercase`]: #method.to_ascii_uppercase - #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] - pub fn make_ascii_uppercase(&mut self) { - let me = unsafe { self.as_bytes_mut() }; - me.make_ascii_uppercase() - } - - /// Converts this string to its ASCII lower case equivalent in-place. - /// - /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', - /// but non-ASCII letters are unchanged. - /// - /// To return a new lowercased value without modifying the existing one, use - /// [`to_ascii_lowercase`]. - /// - /// [`to_ascii_lowercase`]: #method.to_ascii_lowercase - #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] - pub fn make_ascii_lowercase(&mut self) { - let me = unsafe { self.as_bytes_mut() }; - me.make_ascii_lowercase() - } } /// Converts a boxed slice of bytes to a boxed string slice without checking diff --git a/src/liballoc/tests/str.rs b/src/liballoc/tests/str.rs index a3f4c385fe2..a03b61ec97e 100644 --- a/src/liballoc/tests/str.rs +++ b/src/liballoc/tests/str.rs @@ -402,6 +402,36 @@ fn test_str_get_maxinclusive() { } #[test] +fn test_str_slice_rangetoinclusive_ok() { + let s = "abcαβγ"; + assert_eq!(&s[..=2], "abc"); + assert_eq!(&s[..=4], "abcα"); +} + +#[test] +#[should_panic] +fn test_str_slice_rangetoinclusive_notok() { + let s = "abcαβγ"; + &s[..=3]; +} + +#[test] +fn test_str_slicemut_rangetoinclusive_ok() { + let mut s = "abcαβγ".to_owned(); + let s: &mut str = &mut s; + assert_eq!(&mut s[..=2], "abc"); + assert_eq!(&mut s[..=4], "abcα"); +} + +#[test] +#[should_panic] +fn test_str_slicemut_rangetoinclusive_notok() { + let mut s = "abcαβγ".to_owned(); + let s: &mut str = &mut s; + &mut s[..=3]; +} + +#[test] fn test_is_char_boundary() { let s = "ศไทย中华Việt Nam β-release 🐱123"; assert!(s.is_char_boundary(0)); diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 7d1b2ed85c7..b184404c15b 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -74,6 +74,7 @@ use core::iter::{FromIterator, FusedIterator, TrustedLen}; use core::marker::PhantomData; use core::mem; #[cfg(not(test))] +#[cfg(stage0)] use core::num::Float; use core::ops::Bound::{Excluded, Included, Unbounded}; use core::ops::{Index, IndexMut, RangeBounds}; diff --git a/src/liballoc_jemalloc/Cargo.toml b/src/liballoc_jemalloc/Cargo.toml index 02435170374..7986d5dd2eb 100644 --- a/src/liballoc_jemalloc/Cargo.toml +++ b/src/liballoc_jemalloc/Cargo.toml @@ -12,7 +12,6 @@ test = false doc = false [dependencies] -alloc_system = { path = "../liballoc_system" } core = { path = "../libcore" } libc = { path = "../rustc/libc_shim" } compiler_builtins = { path = "../rustc/compiler_builtins_shim" } diff --git a/src/liballoc_jemalloc/lib.rs b/src/liballoc_jemalloc/lib.rs index 2b66c293f21..4b8755877de 100644 --- a/src/liballoc_jemalloc/lib.rs +++ b/src/liballoc_jemalloc/lib.rs @@ -14,7 +14,7 @@ reason = "this library is unlikely to be stabilized in its current \ form or name", issue = "27783")] -#![feature(alloc_system)] +#![feature(core_intrinsics)] #![feature(libc)] #![feature(linkage)] #![feature(staged_api)] @@ -23,15 +23,12 @@ #![cfg_attr(not(dummy_jemalloc), feature(allocator_api))] #![rustc_alloc_kind = "exe"] -extern crate alloc_system; extern crate libc; #[cfg(not(dummy_jemalloc))] pub use contents::*; #[cfg(not(dummy_jemalloc))] mod contents { - use core::alloc::GlobalAlloc; - use alloc_system::System; use libc::{c_int, c_void, size_t}; // Note that the symbols here are prefixed by default on macOS and Windows (we @@ -100,10 +97,11 @@ mod contents { ptr } + #[cfg(stage0)] #[no_mangle] #[rustc_std_internal_symbol] pub unsafe extern fn __rde_oom() -> ! { - System.oom() + ::core::intrinsics::abort(); } #[no_mangle] diff --git a/src/liballoc_system/lib.rs b/src/liballoc_system/lib.rs index fd8109e2a4a..7376ac0f15d 100644 --- a/src/liballoc_system/lib.rs +++ b/src/liballoc_system/lib.rs @@ -71,11 +71,6 @@ unsafe impl Alloc for System { new_size: usize) -> Result<NonNull<Opaque>, AllocErr> { NonNull::new(GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size)).ok_or(AllocErr) } - - #[inline] - fn oom(&mut self) -> ! { - ::oom() - } } #[cfg(stage0)] @@ -103,11 +98,6 @@ unsafe impl<'a> Alloc for &'a System { new_size: usize) -> Result<NonNull<Opaque>, AllocErr> { NonNull::new(GlobalAlloc::realloc(*self, ptr.as_ptr(), layout, new_size)).ok_or(AllocErr) } - - #[inline] - fn oom(&mut self) -> ! { - ::oom() - } } #[cfg(any(windows, unix, target_os = "cloudabi", target_os = "redox"))] @@ -366,63 +356,3 @@ mod platform { } } } - -#[inline] -fn oom() -> ! { - write_to_stderr("fatal runtime error: memory allocation failed"); - unsafe { - ::core::intrinsics::abort(); - } -} - -#[cfg(any(unix, target_os = "redox"))] -#[inline] -fn write_to_stderr(s: &str) { - extern crate libc; - - unsafe { - libc::write(libc::STDERR_FILENO, - s.as_ptr() as *const libc::c_void, - s.len()); - } -} - -#[cfg(windows)] -#[inline] -fn write_to_stderr(s: &str) { - use core::ptr; - - type LPVOID = *mut u8; - type HANDLE = LPVOID; - type DWORD = u32; - type BOOL = i32; - type LPDWORD = *mut DWORD; - type LPOVERLAPPED = *mut u8; - - const STD_ERROR_HANDLE: DWORD = -12i32 as DWORD; - - extern "system" { - fn WriteFile(hFile: HANDLE, - lpBuffer: LPVOID, - nNumberOfBytesToWrite: DWORD, - lpNumberOfBytesWritten: LPDWORD, - lpOverlapped: LPOVERLAPPED) - -> BOOL; - fn GetStdHandle(which: DWORD) -> HANDLE; - } - - unsafe { - // WriteFile silently fails if it is passed an invalid - // handle, so there is no need to check the result of - // GetStdHandle. - WriteFile(GetStdHandle(STD_ERROR_HANDLE), - s.as_ptr() as LPVOID, - s.len() as DWORD, - ptr::null_mut(), - ptr::null_mut()); - } -} - -#[cfg(not(any(windows, unix, target_os = "redox")))] -#[inline] -fn write_to_stderr(_: &str) {} diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index f08baa3dd71..674c4fb57c7 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -63,7 +63,7 @@ fn size_align<T>() -> (usize, usize) { /// requests have positive size. A caller to the `Alloc::alloc` /// method must either ensure that conditions like this are met, or /// use specific allocators with looser requirements.) -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct Layout { // size of the requested block of memory, measured in bytes. size: usize, @@ -451,17 +451,6 @@ pub unsafe trait GlobalAlloc { } new_ptr } - - /// Aborts the thread or process, optionally performing - /// cleanup or logging diagnostic information before panicking or - /// aborting. - /// - /// `oom` is meant to be used by clients unable to cope with an - /// unsatisfied allocation request, and wish to abandon - /// computation rather than attempt to recover locally. - fn oom(&self) -> ! { - unsafe { ::intrinsics::abort() } - } } /// An implementation of `Alloc` can allocate, reallocate, and @@ -614,32 +603,6 @@ pub unsafe trait Alloc { /// to allocate that block of memory. unsafe fn dealloc(&mut self, ptr: NonNull<Opaque>, layout: Layout); - /// Allocator-specific method for signaling an out-of-memory - /// condition. - /// - /// `oom` aborts the thread or process, optionally performing - /// cleanup or logging diagnostic information before panicking or - /// aborting. - /// - /// `oom` is meant to be used by clients unable to cope with an - /// unsatisfied allocation request, and wish to abandon - /// computation rather than attempt to recover locally. - /// - /// Implementations of the `oom` method are discouraged from - /// infinitely regressing in nested calls to `oom`. In - /// practice this means implementors should eschew allocating, - /// especially from `self` (directly or indirectly). - /// - /// Implementations of the allocation and reallocation methods - /// (e.g. `alloc`, `alloc_one`, `realloc`) are discouraged from - /// panicking (or aborting) in the event of memory exhaustion; - /// instead they should return an appropriate error from the - /// invoked method, and let the client decide whether to invoke - /// this `oom` method in response. - fn oom(&mut self) -> ! { - unsafe { ::intrinsics::abort() } - } - // == ALLOCATOR-SPECIFIC QUANTITIES AND LIMITS == // usable_size diff --git a/src/libcore/array.rs b/src/libcore/array.rs index 87144c27c9e..3d24f8902bd 100644 --- a/src/libcore/array.rs +++ b/src/libcore/array.rs @@ -59,7 +59,7 @@ unsafe impl<T, A: Unsize<[T]>> FixedSizeArray<T> for A { } /// The error type returned when a conversion from a slice to an array fails. -#[stable(feature = "try_from", since = "1.26.0")] +#[unstable(feature = "try_from", issue = "33417")] #[derive(Debug, Copy, Clone)] pub struct TryFromSliceError(()); @@ -148,7 +148,7 @@ macro_rules! array_impls { } } - #[stable(feature = "try_from", since = "1.26.0")] + #[unstable(feature = "try_from", issue = "33417")] impl<'a, T> TryFrom<&'a [T]> for &'a [T; $N] { type Error = TryFromSliceError; @@ -162,7 +162,7 @@ macro_rules! array_impls { } } - #[stable(feature = "try_from", since = "1.26.0")] + #[unstable(feature = "try_from", issue = "33417")] impl<'a, T> TryFrom<&'a mut [T]> for &'a mut [T; $N] { type Error = TryFromSliceError; diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index c8ee166fee3..1ff187ed3f1 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -256,6 +256,33 @@ impl<T:Copy> Cell<T> { pub fn get(&self) -> T { unsafe{ *self.value.get() } } + + /// Updates the contained value using a function and returns the new value. + /// + /// # Examples + /// + /// ``` + /// #![feature(cell_update)] + /// + /// use std::cell::Cell; + /// + /// let c = Cell::new(5); + /// let new = c.update(|x| x + 1); + /// + /// assert_eq!(new, 6); + /// assert_eq!(c.get(), 6); + /// ``` + #[inline] + #[unstable(feature = "cell_update", issue = "50186")] + pub fn update<F>(&self, f: F) -> T + where + F: FnOnce(T) -> T, + { + let old = self.get(); + let new = f(old); + self.set(new); + new + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/char/convert.rs b/src/libcore/char/convert.rs index 150562a4a9b..803a924eb3a 100644 --- a/src/libcore/char/convert.rs +++ b/src/libcore/char/convert.rs @@ -204,7 +204,7 @@ impl FromStr for char { } -#[stable(feature = "try_from", since = "1.26.0")] +#[unstable(feature = "try_from", issue = "33417")] impl TryFrom<u32> for char { type Error = CharTryFromError; @@ -219,11 +219,11 @@ impl TryFrom<u32> for char { } /// The error type returned when a conversion from u32 to char fails. -#[stable(feature = "try_from", since = "1.26.0")] +#[unstable(feature = "try_from", issue = "33417")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct CharTryFromError(()); -#[stable(feature = "try_from", since = "1.26.0")] +#[unstable(feature = "try_from", issue = "33417")] impl fmt::Display for CharTryFromError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { "converted integer out of range for `char`".fmt(f) diff --git a/src/libcore/char/decode.rs b/src/libcore/char/decode.rs index 48b531104f8..45a73191db2 100644 --- a/src/libcore/char/decode.rs +++ b/src/libcore/char/decode.rs @@ -17,11 +17,17 @@ use super::from_u32_unchecked; /// An iterator over an iterator of bytes of the characters the bytes represent /// as UTF-8 #[unstable(feature = "decode_utf8", issue = "33906")] +#[rustc_deprecated(since = "1.27.0", reason = "Use str::from_utf8 instead: + https://doc.rust-lang.org/nightly/std/str/struct.Utf8Error.html#examples")] #[derive(Clone, Debug)] +#[allow(deprecated)] pub struct DecodeUtf8<I: Iterator<Item = u8>>(::iter::Peekable<I>); /// Decodes an `Iterator` of bytes as UTF-8. #[unstable(feature = "decode_utf8", issue = "33906")] +#[rustc_deprecated(since = "1.27.0", reason = "Use str::from_utf8 instead: + https://doc.rust-lang.org/nightly/std/str/struct.Utf8Error.html#examples")] +#[allow(deprecated)] #[inline] pub fn decode_utf8<I: IntoIterator<Item = u8>>(i: I) -> DecodeUtf8<I::IntoIter> { DecodeUtf8(i.into_iter().peekable()) @@ -29,10 +35,14 @@ pub fn decode_utf8<I: IntoIterator<Item = u8>>(i: I) -> DecodeUtf8<I::IntoIter> /// `<DecodeUtf8 as Iterator>::next` returns this for an invalid input sequence. #[unstable(feature = "decode_utf8", issue = "33906")] +#[rustc_deprecated(since = "1.27.0", reason = "Use str::from_utf8 instead: + https://doc.rust-lang.org/nightly/std/str/struct.Utf8Error.html#examples")] #[derive(PartialEq, Eq, Debug)] +#[allow(deprecated)] pub struct InvalidSequence(()); #[unstable(feature = "decode_utf8", issue = "33906")] +#[allow(deprecated)] impl<I: Iterator<Item = u8>> Iterator for DecodeUtf8<I> { type Item = Result<char, InvalidSequence>; #[inline] @@ -127,6 +137,7 @@ impl<I: Iterator<Item = u8>> Iterator for DecodeUtf8<I> { } #[unstable(feature = "decode_utf8", issue = "33906")] +#[allow(deprecated)] impl<I: FusedIterator<Item = u8>> FusedIterator for DecodeUtf8<I> {} /// An iterator that decodes UTF-16 encoded code points from an iterator of `u16`s. diff --git a/src/libcore/char/mod.rs b/src/libcore/char/mod.rs index 9edc0c88756..4f6c302247d 100644 --- a/src/libcore/char/mod.rs +++ b/src/libcore/char/mod.rs @@ -40,7 +40,7 @@ pub use self::convert::{from_u32, from_digit}; pub use self::convert::from_u32_unchecked; #[stable(feature = "char_from_str", since = "1.20.0")] pub use self::convert::ParseCharError; -#[stable(feature = "try_from", since = "1.26.0")] +#[unstable(feature = "try_from", issue = "33417")] pub use self::convert::CharTryFromError; #[stable(feature = "decode_utf16", since = "1.9.0")] pub use self::decode::{decode_utf16, DecodeUtf16, DecodeUtf16Error}; @@ -51,6 +51,9 @@ pub use unicode::tables::UNICODE_VERSION; #[unstable(feature = "unicode_version", issue = "49726")] pub use unicode::version::UnicodeVersion; #[unstable(feature = "decode_utf8", issue = "33906")] +#[rustc_deprecated(since = "1.27.0", reason = "Use str::from_utf8 instead: + https://doc.rust-lang.org/nightly/std/str/struct.Utf8Error.html#examples")] +#[allow(deprecated)] pub use self::decode::{decode_utf8, DecodeUtf8, InvalidSequence}; use fmt::{self, Write}; diff --git a/src/libcore/clone.rs b/src/libcore/clone.rs index 58a8439162c..f79f7351698 100644 --- a/src/libcore/clone.rs +++ b/src/libcore/clone.rs @@ -179,7 +179,7 @@ mod impls { bool char } - #[stable(feature = "never_type", since = "1.26.0")] + #[unstable(feature = "never_type", issue = "35121")] impl Clone for ! { #[inline] fn clone(&self) -> Self { diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index 3ae9b05b865..13e838773a5 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -106,6 +106,8 @@ use self::Ordering::*; /// ``` #[lang = "eq"] #[stable(feature = "rust1", since = "1.0.0")] +#[doc(alias = "==")] +#[doc(alias = "!=")] #[rustc_on_unimplemented = "can't compare `{Self}` with `{Rhs}`"] pub trait PartialEq<Rhs: ?Sized = Self> { /// This method tests for `self` and `other` values to be equal, and is used @@ -160,6 +162,8 @@ pub trait PartialEq<Rhs: ?Sized = Self> { /// } /// impl Eq for Book {} /// ``` +#[doc(alias = "==")] +#[doc(alias = "!=")] #[stable(feature = "rust1", since = "1.0.0")] pub trait Eq: PartialEq<Self> { // this method is used solely by #[deriving] to assert @@ -428,6 +432,10 @@ impl<T: Ord> Ord for Reverse<T> { /// } /// ``` #[lang = "ord"] +#[doc(alias = "<")] +#[doc(alias = ">")] +#[doc(alias = "<=")] +#[doc(alias = ">=")] #[stable(feature = "rust1", since = "1.0.0")] pub trait Ord: Eq + PartialOrd<Self> { /// This method returns an `Ordering` between `self` and `other`. @@ -599,6 +607,10 @@ impl PartialOrd for Ordering { /// ``` #[lang = "partial_ord"] #[stable(feature = "rust1", since = "1.0.0")] +#[doc(alias = ">")] +#[doc(alias = "<")] +#[doc(alias = "<=")] +#[doc(alias = ">=")] #[rustc_on_unimplemented = "can't compare `{Self}` with `{Rhs}`"] pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> { /// This method returns an ordering between `self` and `other` values if one exists. @@ -881,24 +893,24 @@ mod impls { ord_impl! { char usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } - #[stable(feature = "never_type", since = "1.26.0")] + #[unstable(feature = "never_type", issue = "35121")] impl PartialEq for ! { fn eq(&self, _: &!) -> bool { *self } } - #[stable(feature = "never_type", since = "1.26.0")] + #[unstable(feature = "never_type", issue = "35121")] impl Eq for ! {} - #[stable(feature = "never_type", since = "1.26.0")] + #[unstable(feature = "never_type", issue = "35121")] impl PartialOrd for ! { fn partial_cmp(&self, _: &!) -> Option<Ordering> { *self } } - #[stable(feature = "never_type", since = "1.26.0")] + #[unstable(feature = "never_type", issue = "35121")] impl Ord for ! { fn cmp(&self, _: &!) -> Ordering { *self diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs index 63721395784..7324df95bc5 100644 --- a/src/libcore/convert.rs +++ b/src/libcore/convert.rs @@ -322,26 +322,22 @@ pub trait From<T>: Sized { /// /// [`TryFrom`]: trait.TryFrom.html /// [`Into`]: trait.Into.html -#[stable(feature = "try_from", since = "1.26.0")] +#[unstable(feature = "try_from", issue = "33417")] pub trait TryInto<T>: Sized { /// The type returned in the event of a conversion error. - #[stable(feature = "try_from", since = "1.26.0")] type Error; /// Performs the conversion. - #[stable(feature = "try_from", since = "1.26.0")] fn try_into(self) -> Result<T, Self::Error>; } /// Attempt to construct `Self` via a conversion. -#[stable(feature = "try_from", since = "1.26.0")] +#[unstable(feature = "try_from", issue = "33417")] pub trait TryFrom<T>: Sized { /// The type returned in the event of a conversion error. - #[stable(feature = "try_from", since = "1.26.0")] type Error; /// Performs the conversion. - #[stable(feature = "try_from", since = "1.26.0")] fn try_from(value: T) -> Result<Self, Self::Error>; } @@ -409,7 +405,7 @@ impl<T> From<T> for T { // TryFrom implies TryInto -#[stable(feature = "try_from", since = "1.26.0")] +#[unstable(feature = "try_from", issue = "33417")] impl<T, U> TryInto<U> for T where U: TryFrom<T> { type Error = U::Error; @@ -421,7 +417,7 @@ impl<T, U> TryInto<U> for T where U: TryFrom<T> // Infallible conversions are semantically equivalent to fallible conversions // with an uninhabited error type. -#[stable(feature = "try_from", since = "1.26.0")] +#[unstable(feature = "try_from", issue = "33417")] impl<T, U> TryFrom<U> for T where T: From<U> { type Error = !; diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 277bef2bf66..99e3012c9bf 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -547,6 +547,7 @@ impl<'a> Display for Arguments<'a> { message="`{Self}` doesn't implement `{Debug}`", label="`{Self}` cannot be formatted using `:?` because it doesn't implement `{Debug}`", )] +#[doc(alias = "{:?}")] #[lang = "debug_trait"] pub trait Debug { /// Formats the value using the given formatter. @@ -612,6 +613,7 @@ pub trait Debug { label="`{Self}` cannot be formatted with the default formatter; \ try using `:?` instead if you are using a format string", )] +#[doc(alias = "{}")] #[stable(feature = "rust1", since = "1.0.0")] pub trait Display { /// Formats the value using the given formatter. @@ -1780,14 +1782,14 @@ macro_rules! fmt_refs { fmt_refs! { Debug, Display, Octal, Binary, LowerHex, UpperHex, LowerExp, UpperExp } -#[stable(feature = "never_type", since = "1.26.0")] +#[unstable(feature = "never_type", issue = "35121")] impl Debug for ! { fn fmt(&self, _: &mut Formatter) -> Result { *self } } -#[stable(feature = "never_type", since = "1.26.0")] +#[unstable(feature = "never_type", issue = "35121")] impl Display for ! { fn fmt(&self, _: &mut Formatter) -> Result { *self diff --git a/src/libcore/hint.rs b/src/libcore/hint.rs new file mode 100644 index 00000000000..f4e96e67b2c --- /dev/null +++ b/src/libcore/hint.rs @@ -0,0 +1,61 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![stable(feature = "core_hint", since = "1.27.0")] + +//! Hints to compiler that affects how code should be emitted or optimized. + +use intrinsics; + +/// Informs the compiler that this point in the code is not reachable, enabling +/// further optimizations. +/// +/// # Safety +/// +/// Reaching this function is completely *undefined behavior* (UB). In +/// particular, the compiler assumes that all UB must never happen, and +/// therefore will eliminate all branches that reach to a call to +/// `unreachable_unchecked()`. +/// +/// Like all instances of UB, if this assumption turns out to be wrong, i.e. the +/// `unreachable_unchecked()` call is actually reachable among all possible +/// control flow, the compiler will apply the wrong optimization strategy, and +/// may sometimes even corrupt seemingly unrelated code, causing +/// difficult-to-debug problems. +/// +/// Use this function only when you can prove that the code will never call it. +/// +/// The [`unreachable!()`] macro is the safe counterpart of this function, which +/// will panic instead when executed. +/// +/// [`unreachable!()`]: ../macro.unreachable.html +/// +/// # Example +/// +/// ``` +/// fn div_1(a: u32, b: u32) -> u32 { +/// use std::hint::unreachable_unchecked; +/// +/// // `b.saturating_add(1)` is always positive (not zero), +/// // hence `checked_div` will never return None. +/// // Therefore, the else branch is unreachable. +/// a.checked_div(b.saturating_add(1)) +/// .unwrap_or_else(|| unsafe { unreachable_unchecked() }) +/// } +/// +/// assert_eq!(div_1(7, 0), 7); +/// assert_eq!(div_1(9, 1), 4); +/// assert_eq!(div_1(11, std::u32::MAX), 0); +/// ``` +#[inline] +#[stable(feature = "unreachable", since = "1.27.0")] +pub unsafe fn unreachable_unchecked() -> ! { + intrinsics::unreachable() +} diff --git a/src/libcore/internal_macros.rs b/src/libcore/internal_macros.rs index cb215a38e53..58eef649287 100644 --- a/src/libcore/internal_macros.rs +++ b/src/libcore/internal_macros.rs @@ -87,3 +87,16 @@ macro_rules! forward_ref_op_assign { } } +#[cfg(stage0)] +macro_rules! public_in_stage0 { + ( { $(#[$attr:meta])* } $($Item: tt)*) => { + $(#[$attr])* pub $($Item)* + } +} + +#[cfg(not(stage0))] +macro_rules! public_in_stage0 { + ( { $(#[$attr:meta])* } $($Item: tt)*) => { + $(#[$attr])* pub(crate) $($Item)* + } +} diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 83274682250..fb0d2d9c882 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -638,6 +638,9 @@ extern "rust-intrinsic" { /// NB: This is very different from the `unreachable!()` macro: Unlike the /// macro, which panics when it is executed, it is *undefined behavior* to /// reach code marked with this function. + /// + /// The stabilized version of this intrinsic is + /// [`std::hint::unreachable_unchecked`](../../std/hint/fn.unreachable_unchecked.html). pub fn unreachable() -> !; /// Informs the optimizer that a condition is always true. diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index ea7a46f44ae..0e21a3327fd 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -71,6 +71,7 @@ #![feature(cfg_target_has_atomic)] #![feature(concat_idents)] #![feature(const_fn)] +#![feature(core_float)] #![feature(custom_attribute)] #![feature(doc_cfg)] #![feature(doc_spotlight)] @@ -82,6 +83,7 @@ #![feature(iterator_repeat_with)] #![feature(lang_items)] #![feature(link_llvm_intrinsics)] +#![feature(never_type)] #![feature(exhaustive_patterns)] #![feature(macro_at_most_once_rep)] #![feature(no_core)] @@ -92,12 +94,15 @@ #![feature(rustc_attrs)] #![feature(rustc_const_unstable)] #![feature(simd_ffi)] +#![feature(core_slice_ext)] +#![feature(core_str_ext)] #![feature(specialization)] #![feature(staged_api)] #![feature(stmt_expr_attributes)] #![feature(unboxed_closures)] #![feature(untagged_unions)] #![feature(unwind_attributes)] +#![feature(doc_alias)] #![cfg_attr(not(stage0), feature(mmx_target_feature))] #![cfg_attr(not(stage0), feature(tbm_target_feature))] @@ -158,6 +163,7 @@ pub mod intrinsics; pub mod mem; pub mod nonzero; pub mod ptr; +pub mod hint; /* Core language traits */ @@ -228,7 +234,7 @@ macro_rules! test_v512 { ($item:item) => {}; } #[allow(unused_macros)] macro_rules! vector_impl { ($([$f:ident, $($args:tt)*]),*) => { $($f!($($args)*);)* } } #[path = "../stdsimd/coresimd/mod.rs"] -#[allow(missing_docs, missing_debug_implementations, dead_code)] +#[allow(missing_docs, missing_debug_implementations, dead_code, unused_imports)] #[unstable(feature = "stdsimd", issue = "48556")] #[cfg(not(stage0))] // allow changes to how stdsimd works in stage0 mod coresimd; diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index 90a9cb3379b..f9371ed0575 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -295,6 +295,7 @@ macro_rules! debug_assert_ne { /// ``` #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] +#[doc(alias = "?")] macro_rules! try { ($expr:expr) => (match $expr { $crate::result::Result::Ok(val) => val, @@ -420,13 +421,13 @@ macro_rules! writeln { /// * Iterators that dynamically terminate. /// /// If the determination that the code is unreachable proves incorrect, the -/// program immediately terminates with a [`panic!`]. The function [`unreachable`], -/// which belongs to the [`std::intrinsics`] module, informs the compilier to +/// program immediately terminates with a [`panic!`]. The function [`unreachable_unchecked`], +/// which belongs to the [`std::hint`] module, informs the compilier to /// optimize the code out of the release version entirely. /// /// [`panic!`]: ../std/macro.panic.html -/// [`unreachable`]: ../std/intrinsics/fn.unreachable.html -/// [`std::intrinsics`]: ../std/intrinsics/index.html +/// [`unreachable_unchecked`]: ../std/hint/fn.unreachable_unchecked.html +/// [`std::hint`]: ../std/hint/index.html /// /// # Panics /// diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 885aabe0806..feb689dbc1f 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -630,7 +630,7 @@ mod copy_impls { bool char } - #[stable(feature = "never_type", since = "1.26.0")] + #[unstable(feature = "never_type", issue = "35121")] impl Copy for ! {} #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index e3f08926610..10efab82ddf 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -1094,18 +1094,6 @@ impl<T: ::hash::Hash> ::hash::Hash for ManuallyDrop<T> { } } -/// Tells LLVM that this point in the code is not reachable, enabling further -/// optimizations. -/// -/// NB: This is very different from the `unreachable!()` macro: Unlike the -/// macro, which panics when it is executed, it is *undefined behavior* to -/// reach code marked with this function. -#[inline] -#[unstable(feature = "unreachable", issue = "43751")] -pub unsafe fn unreachable() -> ! { - intrinsics::unreachable() -} - /// A pinned reference. /// /// A pinned reference is a lot like a mutable reference, except that it is not diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 3586fa5442f..8d5f6f601da 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -17,9 +17,9 @@ #![stable(feature = "rust1", since = "1.0.0")] -use intrinsics; use mem; use num::Float; +#[cfg(not(stage0))] use num::FpCategory; use num::FpCategory as Fp; /// The radix or base of the internal representation of `f32`. @@ -188,27 +188,6 @@ impl Float for f32 { } } - /// Computes the absolute value of `self`. Returns `Float::nan()` if the - /// number is `Float::nan()`. - #[inline] - fn abs(self) -> f32 { - unsafe { intrinsics::fabsf32(self) } - } - - /// Returns a number that represents the sign of `self`. - /// - /// - `1.0` if the number is positive, `+0.0` or `Float::infinity()` - /// - `-1.0` if the number is negative, `-0.0` or `Float::neg_infinity()` - /// - `Float::nan()` if the number is `Float::nan()` - #[inline] - fn signum(self) -> f32 { - if self.is_nan() { - NAN - } else { - unsafe { intrinsics::copysignf32(1.0, self) } - } - } - /// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with /// positive sign bit and positive infinity. #[inline] @@ -231,11 +210,6 @@ impl Float for f32 { 1.0 / self } - #[inline] - fn powi(self, n: i32) -> f32 { - unsafe { intrinsics::powif32(self, n) } - } - /// Converts to degrees, assuming the number is in radians. #[inline] fn to_degrees(self) -> f32 { @@ -292,3 +266,286 @@ impl Float for f32 { unsafe { mem::transmute(v) } } } + +// FIXME: remove (inline) this macro and the Float trait +// when updating to a bootstrap compiler that has the new lang items. +#[cfg_attr(stage0, macro_export)] +#[unstable(feature = "core_float", issue = "32110")] +macro_rules! f32_core_methods { () => { + /// Returns `true` if this value is `NaN` and false otherwise. + /// + /// ``` + /// use std::f32; + /// + /// let nan = f32::NAN; + /// let f = 7.0_f32; + /// + /// assert!(nan.is_nan()); + /// assert!(!f.is_nan()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_nan(self) -> bool { Float::is_nan(self) } + + /// Returns `true` if this value is positive infinity or negative infinity and + /// false otherwise. + /// + /// ``` + /// use std::f32; + /// + /// let f = 7.0f32; + /// let inf = f32::INFINITY; + /// let neg_inf = f32::NEG_INFINITY; + /// let nan = f32::NAN; + /// + /// assert!(!f.is_infinite()); + /// assert!(!nan.is_infinite()); + /// + /// assert!(inf.is_infinite()); + /// assert!(neg_inf.is_infinite()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_infinite(self) -> bool { Float::is_infinite(self) } + + /// Returns `true` if this number is neither infinite nor `NaN`. + /// + /// ``` + /// use std::f32; + /// + /// let f = 7.0f32; + /// let inf = f32::INFINITY; + /// let neg_inf = f32::NEG_INFINITY; + /// let nan = f32::NAN; + /// + /// assert!(f.is_finite()); + /// + /// assert!(!nan.is_finite()); + /// assert!(!inf.is_finite()); + /// assert!(!neg_inf.is_finite()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_finite(self) -> bool { Float::is_finite(self) } + + /// Returns `true` if the number is neither zero, infinite, + /// [subnormal][subnormal], or `NaN`. + /// + /// ``` + /// use std::f32; + /// + /// let min = f32::MIN_POSITIVE; // 1.17549435e-38f32 + /// let max = f32::MAX; + /// let lower_than_min = 1.0e-40_f32; + /// let zero = 0.0_f32; + /// + /// assert!(min.is_normal()); + /// assert!(max.is_normal()); + /// + /// assert!(!zero.is_normal()); + /// assert!(!f32::NAN.is_normal()); + /// assert!(!f32::INFINITY.is_normal()); + /// // Values between `0` and `min` are Subnormal. + /// assert!(!lower_than_min.is_normal()); + /// ``` + /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_normal(self) -> bool { Float::is_normal(self) } + + /// Returns the floating point category of the number. If only one property + /// is going to be tested, it is generally faster to use the specific + /// predicate instead. + /// + /// ``` + /// use std::num::FpCategory; + /// use std::f32; + /// + /// let num = 12.4_f32; + /// let inf = f32::INFINITY; + /// + /// assert_eq!(num.classify(), FpCategory::Normal); + /// assert_eq!(inf.classify(), FpCategory::Infinite); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn classify(self) -> FpCategory { Float::classify(self) } + + /// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with + /// positive sign bit and positive infinity. + /// + /// ``` + /// let f = 7.0_f32; + /// let g = -7.0_f32; + /// + /// assert!(f.is_sign_positive()); + /// assert!(!g.is_sign_positive()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_sign_positive(self) -> bool { Float::is_sign_positive(self) } + + /// Returns `true` if and only if `self` has a negative sign, including `-0.0`, `NaN`s with + /// negative sign bit and negative infinity. + /// + /// ``` + /// let f = 7.0f32; + /// let g = -7.0f32; + /// + /// assert!(!f.is_sign_negative()); + /// assert!(g.is_sign_negative()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_sign_negative(self) -> bool { Float::is_sign_negative(self) } + + /// Takes the reciprocal (inverse) of a number, `1/x`. + /// + /// ``` + /// use std::f32; + /// + /// let x = 2.0_f32; + /// let abs_difference = (x.recip() - (1.0/x)).abs(); + /// + /// assert!(abs_difference <= f32::EPSILON); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn recip(self) -> f32 { Float::recip(self) } + + /// Converts radians to degrees. + /// + /// ``` + /// use std::f32::{self, consts}; + /// + /// let angle = consts::PI; + /// + /// let abs_difference = (angle.to_degrees() - 180.0).abs(); + /// + /// assert!(abs_difference <= f32::EPSILON); + /// ``` + #[stable(feature = "f32_deg_rad_conversions", since="1.7.0")] + #[inline] + pub fn to_degrees(self) -> f32 { Float::to_degrees(self) } + + /// Converts degrees to radians. + /// + /// ``` + /// use std::f32::{self, consts}; + /// + /// let angle = 180.0f32; + /// + /// let abs_difference = (angle.to_radians() - consts::PI).abs(); + /// + /// assert!(abs_difference <= f32::EPSILON); + /// ``` + #[stable(feature = "f32_deg_rad_conversions", since="1.7.0")] + #[inline] + pub fn to_radians(self) -> f32 { Float::to_radians(self) } + + /// Returns the maximum of the two numbers. + /// + /// ``` + /// let x = 1.0f32; + /// let y = 2.0f32; + /// + /// assert_eq!(x.max(y), y); + /// ``` + /// + /// If one of the arguments is NaN, then the other argument is returned. + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn max(self, other: f32) -> f32 { + Float::max(self, other) + } + + /// Returns the minimum of the two numbers. + /// + /// ``` + /// let x = 1.0f32; + /// let y = 2.0f32; + /// + /// assert_eq!(x.min(y), x); + /// ``` + /// + /// If one of the arguments is NaN, then the other argument is returned. + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn min(self, other: f32) -> f32 { + Float::min(self, other) + } + + /// Raw transmutation to `u32`. + /// + /// This is currently identical to `transmute::<f32, u32>(self)` on all platforms. + /// + /// See `from_bits` for some discussion of the portability of this operation + /// (there are almost no issues). + /// + /// Note that this function is distinct from `as` casting, which attempts to + /// preserve the *numeric* value, and not the bitwise value. + /// + /// # Examples + /// + /// ``` + /// assert_ne!((1f32).to_bits(), 1f32 as u32); // to_bits() is not casting! + /// assert_eq!((12.5f32).to_bits(), 0x41480000); + /// + /// ``` + #[stable(feature = "float_bits_conv", since = "1.20.0")] + #[inline] + pub fn to_bits(self) -> u32 { + Float::to_bits(self) + } + + /// Raw transmutation from `u32`. + /// + /// This is currently identical to `transmute::<u32, f32>(v)` on all platforms. + /// It turns out this is incredibly portable, for two reasons: + /// + /// * Floats and Ints have the same endianness on all supported platforms. + /// * IEEE-754 very precisely specifies the bit layout of floats. + /// + /// However there is one caveat: prior to the 2008 version of IEEE-754, how + /// to interpret the NaN signaling bit wasn't actually specified. Most platforms + /// (notably x86 and ARM) picked the interpretation that was ultimately + /// standardized in 2008, but some didn't (notably MIPS). As a result, all + /// signaling NaNs on MIPS are quiet NaNs on x86, and vice-versa. + /// + /// Rather than trying to preserve signaling-ness cross-platform, this + /// implementation favours preserving the exact bits. This means that + /// any payloads encoded in NaNs will be preserved even if the result of + /// this method is sent over the network from an x86 machine to a MIPS one. + /// + /// If the results of this method are only manipulated by the same + /// architecture that produced them, then there is no portability concern. + /// + /// If the input isn't NaN, then there is no portability concern. + /// + /// If you don't care about signalingness (very likely), then there is no + /// portability concern. + /// + /// Note that this function is distinct from `as` casting, which attempts to + /// preserve the *numeric* value, and not the bitwise value. + /// + /// # Examples + /// + /// ``` + /// use std::f32; + /// let v = f32::from_bits(0x41480000); + /// let difference = (v - 12.5).abs(); + /// assert!(difference <= 1e-5); + /// ``` + #[stable(feature = "float_bits_conv", since = "1.20.0")] + #[inline] + pub fn from_bits(v: u32) -> Self { + Float::from_bits(v) + } +}} + +#[lang = "f32"] +#[cfg(not(test))] +#[cfg(not(stage0))] +impl f32 { + f32_core_methods!(); +} diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index 64c0d508b38..08b869734d4 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -17,10 +17,10 @@ #![stable(feature = "rust1", since = "1.0.0")] -use intrinsics; use mem; -use num::FpCategory as Fp; use num::Float; +#[cfg(not(stage0))] use num::FpCategory; +use num::FpCategory as Fp; /// The radix or base of the internal representation of `f64`. #[stable(feature = "rust1", since = "1.0.0")] @@ -188,27 +188,6 @@ impl Float for f64 { } } - /// Computes the absolute value of `self`. Returns `Float::nan()` if the - /// number is `Float::nan()`. - #[inline] - fn abs(self) -> f64 { - unsafe { intrinsics::fabsf64(self) } - } - - /// Returns a number that represents the sign of `self`. - /// - /// - `1.0` if the number is positive, `+0.0` or `Float::infinity()` - /// - `-1.0` if the number is negative, `-0.0` or `Float::neg_infinity()` - /// - `Float::nan()` if the number is `Float::nan()` - #[inline] - fn signum(self) -> f64 { - if self.is_nan() { - NAN - } else { - unsafe { intrinsics::copysignf64(1.0, self) } - } - } - /// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with /// positive sign bit and positive infinity. #[inline] @@ -229,11 +208,6 @@ impl Float for f64 { 1.0 / self } - #[inline] - fn powi(self, n: i32) -> f64 { - unsafe { intrinsics::powif64(self, n) } - } - /// Converts to degrees, assuming the number is in radians. #[inline] fn to_degrees(self) -> f64 { @@ -291,3 +265,296 @@ impl Float for f64 { unsafe { mem::transmute(v) } } } + +// FIXME: remove (inline) this macro and the Float trait +// when updating to a bootstrap compiler that has the new lang items. +#[cfg_attr(stage0, macro_export)] +#[unstable(feature = "core_float", issue = "32110")] +macro_rules! f64_core_methods { () => { + /// Returns `true` if this value is `NaN` and false otherwise. + /// + /// ``` + /// use std::f64; + /// + /// let nan = f64::NAN; + /// let f = 7.0_f64; + /// + /// assert!(nan.is_nan()); + /// assert!(!f.is_nan()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_nan(self) -> bool { Float::is_nan(self) } + + /// Returns `true` if this value is positive infinity or negative infinity and + /// false otherwise. + /// + /// ``` + /// use std::f64; + /// + /// let f = 7.0f64; + /// let inf = f64::INFINITY; + /// let neg_inf = f64::NEG_INFINITY; + /// let nan = f64::NAN; + /// + /// assert!(!f.is_infinite()); + /// assert!(!nan.is_infinite()); + /// + /// assert!(inf.is_infinite()); + /// assert!(neg_inf.is_infinite()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_infinite(self) -> bool { Float::is_infinite(self) } + + /// Returns `true` if this number is neither infinite nor `NaN`. + /// + /// ``` + /// use std::f64; + /// + /// let f = 7.0f64; + /// let inf: f64 = f64::INFINITY; + /// let neg_inf: f64 = f64::NEG_INFINITY; + /// let nan: f64 = f64::NAN; + /// + /// assert!(f.is_finite()); + /// + /// assert!(!nan.is_finite()); + /// assert!(!inf.is_finite()); + /// assert!(!neg_inf.is_finite()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_finite(self) -> bool { Float::is_finite(self) } + + /// Returns `true` if the number is neither zero, infinite, + /// [subnormal][subnormal], or `NaN`. + /// + /// ``` + /// use std::f64; + /// + /// let min = f64::MIN_POSITIVE; // 2.2250738585072014e-308f64 + /// let max = f64::MAX; + /// let lower_than_min = 1.0e-308_f64; + /// let zero = 0.0f64; + /// + /// assert!(min.is_normal()); + /// assert!(max.is_normal()); + /// + /// assert!(!zero.is_normal()); + /// assert!(!f64::NAN.is_normal()); + /// assert!(!f64::INFINITY.is_normal()); + /// // Values between `0` and `min` are Subnormal. + /// assert!(!lower_than_min.is_normal()); + /// ``` + /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_normal(self) -> bool { Float::is_normal(self) } + + /// Returns the floating point category of the number. If only one property + /// is going to be tested, it is generally faster to use the specific + /// predicate instead. + /// + /// ``` + /// use std::num::FpCategory; + /// use std::f64; + /// + /// let num = 12.4_f64; + /// let inf = f64::INFINITY; + /// + /// assert_eq!(num.classify(), FpCategory::Normal); + /// assert_eq!(inf.classify(), FpCategory::Infinite); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn classify(self) -> FpCategory { Float::classify(self) } + + /// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with + /// positive sign bit and positive infinity. + /// + /// ``` + /// let f = 7.0_f64; + /// let g = -7.0_f64; + /// + /// assert!(f.is_sign_positive()); + /// assert!(!g.is_sign_positive()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_sign_positive(self) -> bool { Float::is_sign_positive(self) } + + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_deprecated(since = "1.0.0", reason = "renamed to is_sign_positive")] + #[inline] + #[doc(hidden)] + pub fn is_positive(self) -> bool { Float::is_sign_positive(self) } + + /// Returns `true` if and only if `self` has a negative sign, including `-0.0`, `NaN`s with + /// negative sign bit and negative infinity. + /// + /// ``` + /// let f = 7.0_f64; + /// let g = -7.0_f64; + /// + /// assert!(!f.is_sign_negative()); + /// assert!(g.is_sign_negative()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_sign_negative(self) -> bool { Float::is_sign_negative(self) } + + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_deprecated(since = "1.0.0", reason = "renamed to is_sign_negative")] + #[inline] + #[doc(hidden)] + pub fn is_negative(self) -> bool { Float::is_sign_negative(self) } + + /// Takes the reciprocal (inverse) of a number, `1/x`. + /// + /// ``` + /// let x = 2.0_f64; + /// let abs_difference = (x.recip() - (1.0/x)).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn recip(self) -> f64 { Float::recip(self) } + + /// Converts radians to degrees. + /// + /// ``` + /// use std::f64::consts; + /// + /// let angle = consts::PI; + /// + /// let abs_difference = (angle.to_degrees() - 180.0).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn to_degrees(self) -> f64 { Float::to_degrees(self) } + + /// Converts degrees to radians. + /// + /// ``` + /// use std::f64::consts; + /// + /// let angle = 180.0_f64; + /// + /// let abs_difference = (angle.to_radians() - consts::PI).abs(); + /// + /// assert!(abs_difference < 1e-10); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn to_radians(self) -> f64 { Float::to_radians(self) } + + /// Returns the maximum of the two numbers. + /// + /// ``` + /// let x = 1.0_f64; + /// let y = 2.0_f64; + /// + /// assert_eq!(x.max(y), y); + /// ``` + /// + /// If one of the arguments is NaN, then the other argument is returned. + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn max(self, other: f64) -> f64 { + Float::max(self, other) + } + + /// Returns the minimum of the two numbers. + /// + /// ``` + /// let x = 1.0_f64; + /// let y = 2.0_f64; + /// + /// assert_eq!(x.min(y), x); + /// ``` + /// + /// If one of the arguments is NaN, then the other argument is returned. + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn min(self, other: f64) -> f64 { + Float::min(self, other) + } + + /// Raw transmutation to `u64`. + /// + /// This is currently identical to `transmute::<f64, u64>(self)` on all platforms. + /// + /// See `from_bits` for some discussion of the portability of this operation + /// (there are almost no issues). + /// + /// Note that this function is distinct from `as` casting, which attempts to + /// preserve the *numeric* value, and not the bitwise value. + /// + /// # Examples + /// + /// ``` + /// assert!((1f64).to_bits() != 1f64 as u64); // to_bits() is not casting! + /// assert_eq!((12.5f64).to_bits(), 0x4029000000000000); + /// + /// ``` + #[stable(feature = "float_bits_conv", since = "1.20.0")] + #[inline] + pub fn to_bits(self) -> u64 { + Float::to_bits(self) + } + + /// Raw transmutation from `u64`. + /// + /// This is currently identical to `transmute::<u64, f64>(v)` on all platforms. + /// It turns out this is incredibly portable, for two reasons: + /// + /// * Floats and Ints have the same endianness on all supported platforms. + /// * IEEE-754 very precisely specifies the bit layout of floats. + /// + /// However there is one caveat: prior to the 2008 version of IEEE-754, how + /// to interpret the NaN signaling bit wasn't actually specified. Most platforms + /// (notably x86 and ARM) picked the interpretation that was ultimately + /// standardized in 2008, but some didn't (notably MIPS). As a result, all + /// signaling NaNs on MIPS are quiet NaNs on x86, and vice-versa. + /// + /// Rather than trying to preserve signaling-ness cross-platform, this + /// implementation favours preserving the exact bits. This means that + /// any payloads encoded in NaNs will be preserved even if the result of + /// this method is sent over the network from an x86 machine to a MIPS one. + /// + /// If the results of this method are only manipulated by the same + /// architecture that produced them, then there is no portability concern. + /// + /// If the input isn't NaN, then there is no portability concern. + /// + /// If you don't care about signalingness (very likely), then there is no + /// portability concern. + /// + /// Note that this function is distinct from `as` casting, which attempts to + /// preserve the *numeric* value, and not the bitwise value. + /// + /// # Examples + /// + /// ``` + /// use std::f64; + /// let v = f64::from_bits(0x4029000000000000); + /// let difference = (v - 12.5).abs(); + /// assert!(difference <= 1e-5); + /// ``` + #[stable(feature = "float_bits_conv", since = "1.20.0")] + #[inline] + pub fn from_bits(v: u64) -> Self { + Float::from_bits(v) + } +}} + +#[lang = "f64"] +#[cfg(not(test))] +#[cfg(not(stage0))] +impl f64 { + f64_core_methods!(); +} diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index f2e8caaad14..a062fbda5ba 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -1765,7 +1765,11 @@ assert_eq!((-a).mod_euc(-b), 1); pub fn mod_euc(self, rhs: Self) -> Self { let r = self % rhs; if r < 0 { - r + rhs.abs() + if rhs < 0 { + r - rhs + } else { + r + rhs + } } else { r } @@ -4098,83 +4102,58 @@ pub enum FpCategory { Normal, } -/// A built-in floating point number. +// Technically private and only exposed for coretests: #[doc(hidden)] -#[unstable(feature = "core_float", - reason = "stable interface is via `impl f{32,64}` in later crates", - issue = "32110")] +#[unstable(feature = "float_internals", + reason = "internal routines only exposed for testing", + issue = "0")] pub trait Float: Sized { /// Type used by `to_bits` and `from_bits`. - #[stable(feature = "core_float_bits", since = "1.25.0")] type Bits; /// Returns `true` if this value is NaN and false otherwise. - #[stable(feature = "core", since = "1.6.0")] fn is_nan(self) -> bool; + /// Returns `true` if this value is positive infinity or negative infinity and /// false otherwise. - #[stable(feature = "core", since = "1.6.0")] fn is_infinite(self) -> bool; + /// Returns `true` if this number is neither infinite nor NaN. - #[stable(feature = "core", since = "1.6.0")] fn is_finite(self) -> bool; + /// Returns `true` if this number is neither zero, infinite, denormal, or NaN. - #[stable(feature = "core", since = "1.6.0")] fn is_normal(self) -> bool; + /// Returns the category that this number falls into. - #[stable(feature = "core", since = "1.6.0")] fn classify(self) -> FpCategory; - /// Computes the absolute value of `self`. Returns `Float::nan()` if the - /// number is `Float::nan()`. - #[stable(feature = "core", since = "1.6.0")] - fn abs(self) -> Self; - /// Returns a number that represents the sign of `self`. - /// - /// - `1.0` if the number is positive, `+0.0` or `Float::infinity()` - /// - `-1.0` if the number is negative, `-0.0` or `Float::neg_infinity()` - /// - `Float::nan()` if the number is `Float::nan()` - #[stable(feature = "core", since = "1.6.0")] - fn signum(self) -> Self; - /// Returns `true` if `self` is positive, including `+0.0` and /// `Float::infinity()`. - #[stable(feature = "core", since = "1.6.0")] fn is_sign_positive(self) -> bool; + /// Returns `true` if `self` is negative, including `-0.0` and /// `Float::neg_infinity()`. - #[stable(feature = "core", since = "1.6.0")] fn is_sign_negative(self) -> bool; /// Take the reciprocal (inverse) of a number, `1/x`. - #[stable(feature = "core", since = "1.6.0")] fn recip(self) -> Self; - /// Raise a number to an integer power. - /// - /// Using this function is generally faster than using `powf` - #[stable(feature = "core", since = "1.6.0")] - fn powi(self, n: i32) -> Self; - /// Convert radians to degrees. - #[stable(feature = "deg_rad_conversions", since="1.7.0")] fn to_degrees(self) -> Self; + /// Convert degrees to radians. - #[stable(feature = "deg_rad_conversions", since="1.7.0")] fn to_radians(self) -> Self; /// Returns the maximum of the two numbers. - #[stable(feature = "core_float_min_max", since="1.20.0")] fn max(self, other: Self) -> Self; + /// Returns the minimum of the two numbers. - #[stable(feature = "core_float_min_max", since="1.20.0")] fn min(self, other: Self) -> Self; /// Raw transmutation to integer. - #[stable(feature = "core_float_bits", since="1.25.0")] fn to_bits(self) -> Self::Bits; + /// Raw transmutation from integer. - #[stable(feature = "core_float_bits", since="1.25.0")] fn from_bits(v: Self::Bits) -> Self; } @@ -4192,7 +4171,7 @@ macro_rules! from_str_radix_int_impl { from_str_radix_int_impl! { isize i8 i16 i32 i64 i128 usize u8 u16 u32 u64 u128 } /// The error type returned when a checked integral type conversion fails. -#[stable(feature = "try_from", since = "1.26.0")] +#[unstable(feature = "try_from", issue = "33417")] #[derive(Debug, Copy, Clone)] pub struct TryFromIntError(()); @@ -4207,14 +4186,14 @@ impl TryFromIntError { } } -#[stable(feature = "try_from", since = "1.26.0")] +#[unstable(feature = "try_from", issue = "33417")] impl fmt::Display for TryFromIntError { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { self.__description().fmt(fmt) } } -#[stable(feature = "try_from", since = "1.26.0")] +#[unstable(feature = "try_from", issue = "33417")] impl From<!> for TryFromIntError { fn from(never: !) -> TryFromIntError { never @@ -4224,7 +4203,7 @@ impl From<!> for TryFromIntError { // only negative bounds macro_rules! try_from_lower_bounded { ($source:ty, $($target:ty),*) => {$( - #[stable(feature = "try_from", since = "1.26.0")] + #[unstable(feature = "try_from", issue = "33417")] impl TryFrom<$source> for $target { type Error = TryFromIntError; @@ -4243,7 +4222,7 @@ macro_rules! try_from_lower_bounded { // unsigned to signed (only positive bound) macro_rules! try_from_upper_bounded { ($source:ty, $($target:ty),*) => {$( - #[stable(feature = "try_from", since = "1.26.0")] + #[unstable(feature = "try_from", issue = "33417")] impl TryFrom<$source> for $target { type Error = TryFromIntError; @@ -4262,7 +4241,7 @@ macro_rules! try_from_upper_bounded { // all other cases macro_rules! try_from_both_bounded { ($source:ty, $($target:ty),*) => {$( - #[stable(feature = "try_from", since = "1.26.0")] + #[unstable(feature = "try_from", issue = "33417")] impl TryFrom<$source> for $target { type Error = TryFromIntError; diff --git a/src/libcore/ops/arith.rs b/src/libcore/ops/arith.rs index 88db019b02f..a1bc5463f73 100644 --- a/src/libcore/ops/arith.rs +++ b/src/libcore/ops/arith.rs @@ -87,12 +87,14 @@ message="cannot add `{RHS}` to `{Self}`", label="no implementation for `{Self} + {RHS}`", )] +#[doc(alias = "+")] pub trait Add<RHS=Self> { /// The resulting type after applying the `+` operator. #[stable(feature = "rust1", since = "1.0.0")] type Output; /// Performs the `+` operation. + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn add(self, rhs: RHS) -> Self::Output; } @@ -183,12 +185,14 @@ add_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented(message="cannot subtract `{RHS}` from `{Self}`", label="no implementation for `{Self} - {RHS}`")] +#[doc(alias = "-")] pub trait Sub<RHS=Self> { /// The resulting type after applying the `-` operator. #[stable(feature = "rust1", since = "1.0.0")] type Output; /// Performs the `-` operation. + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn sub(self, rhs: RHS) -> Self::Output; } @@ -301,12 +305,14 @@ sub_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented(message="cannot multiply `{RHS}` to `{Self}`", label="no implementation for `{Self} * {RHS}`")] +#[doc(alias = "*")] pub trait Mul<RHS=Self> { /// The resulting type after applying the `*` operator. #[stable(feature = "rust1", since = "1.0.0")] type Output; /// Performs the `*` operation. + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn mul(self, rhs: RHS) -> Self::Output; } @@ -423,12 +429,14 @@ mul_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented(message="cannot divide `{Self}` by `{RHS}`", label="no implementation for `{Self} / {RHS}`")] +#[doc(alias = "/")] pub trait Div<RHS=Self> { /// The resulting type after applying the `/` operator. #[stable(feature = "rust1", since = "1.0.0")] type Output; /// Performs the `/` operation. + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn div(self, rhs: RHS) -> Self::Output; } @@ -506,12 +514,14 @@ div_impl_float! { f32 f64 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented(message="cannot mod `{Self}` by `{RHS}`", label="no implementation for `{Self} % {RHS}`")] +#[doc(alias = "%")] pub trait Rem<RHS=Self> { /// The resulting type after applying the `%` operator. #[stable(feature = "rust1", since = "1.0.0")] type Output = Self; /// Performs the `%` operation. + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn rem(self, rhs: RHS) -> Self::Output; } @@ -589,12 +599,14 @@ rem_impl_float! { f32 f64 } /// ``` #[lang = "neg"] #[stable(feature = "rust1", since = "1.0.0")] +#[doc(alias = "-")] pub trait Neg { /// The resulting type after applying the `-` operator. #[stable(feature = "rust1", since = "1.0.0")] type Output; /// Performs the unary `-` operation. + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn neg(self) -> Self::Output; } @@ -664,6 +676,8 @@ neg_impl_numeric! { isize i8 i16 i32 i64 i128 f32 f64 } #[stable(feature = "op_assign_traits", since = "1.8.0")] #[rustc_on_unimplemented(message="cannot add-assign `{Rhs}` to `{Self}`", label="no implementation for `{Self} += {Rhs}`")] +#[doc(alias = "+")] +#[doc(alias = "+=")] pub trait AddAssign<Rhs=Self> { /// Performs the `+=` operation. #[stable(feature = "op_assign_traits", since = "1.8.0")] @@ -718,6 +732,8 @@ add_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } #[stable(feature = "op_assign_traits", since = "1.8.0")] #[rustc_on_unimplemented(message="cannot subtract-assign `{Rhs}` from `{Self}`", label="no implementation for `{Self} -= {Rhs}`")] +#[doc(alias = "-")] +#[doc(alias = "-=")] pub trait SubAssign<Rhs=Self> { /// Performs the `-=` operation. #[stable(feature = "op_assign_traits", since = "1.8.0")] @@ -763,6 +779,8 @@ sub_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } #[stable(feature = "op_assign_traits", since = "1.8.0")] #[rustc_on_unimplemented(message="cannot multiply-assign `{Rhs}` to `{Self}`", label="no implementation for `{Self} *= {Rhs}`")] +#[doc(alias = "*")] +#[doc(alias = "*=")] pub trait MulAssign<Rhs=Self> { /// Performs the `*=` operation. #[stable(feature = "op_assign_traits", since = "1.8.0")] @@ -808,6 +826,8 @@ mul_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } #[stable(feature = "op_assign_traits", since = "1.8.0")] #[rustc_on_unimplemented(message="cannot divide-assign `{Self}` by `{Rhs}`", label="no implementation for `{Self} /= {Rhs}`")] +#[doc(alias = "/")] +#[doc(alias = "/=")] pub trait DivAssign<Rhs=Self> { /// Performs the `/=` operation. #[stable(feature = "op_assign_traits", since = "1.8.0")] @@ -856,6 +876,8 @@ div_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } #[stable(feature = "op_assign_traits", since = "1.8.0")] #[rustc_on_unimplemented(message="cannot mod-assign `{Self}` by `{Rhs}``", label="no implementation for `{Self} %= {Rhs}`")] +#[doc(alias = "%")] +#[doc(alias = "%=")] pub trait RemAssign<Rhs=Self> { /// Performs the `%=` operation. #[stable(feature = "op_assign_traits", since = "1.8.0")] diff --git a/src/libcore/ops/bit.rs b/src/libcore/ops/bit.rs index ec1e65be774..3900f365b0a 100644 --- a/src/libcore/ops/bit.rs +++ b/src/libcore/ops/bit.rs @@ -46,6 +46,7 @@ pub trait Not { type Output; /// Performs the unary `!` operation. + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn not(self) -> Self::Output; } @@ -119,6 +120,7 @@ not_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// assert_eq!(bv1 & bv2, expected); /// ``` #[lang = "bitand"] +#[doc(alias = "&")] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented(message="no implementation for `{Self} & {RHS}`", label="no implementation for `{Self} & {RHS}`")] @@ -128,6 +130,7 @@ pub trait BitAnd<RHS=Self> { type Output; /// Performs the `&` operation. + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn bitand(self, rhs: RHS) -> Self::Output; } @@ -201,6 +204,7 @@ bitand_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// assert_eq!(bv1 | bv2, expected); /// ``` #[lang = "bitor"] +#[doc(alias = "|")] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented(message="no implementation for `{Self} | {RHS}`", label="no implementation for `{Self} | {RHS}`")] @@ -210,6 +214,7 @@ pub trait BitOr<RHS=Self> { type Output; /// Performs the `|` operation. + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn bitor(self, rhs: RHS) -> Self::Output; } @@ -286,6 +291,7 @@ bitor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// assert_eq!(bv1 ^ bv2, expected); /// ``` #[lang = "bitxor"] +#[doc(alias = "^")] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented(message="no implementation for `{Self} ^ {RHS}`", label="no implementation for `{Self} ^ {RHS}`")] @@ -295,6 +301,7 @@ pub trait BitXor<RHS=Self> { type Output; /// Performs the `^` operation. + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn bitxor(self, rhs: RHS) -> Self::Output; } @@ -372,15 +379,17 @@ bitxor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// SpinVector { vec: vec![2, 3, 4, 0, 1] }); /// ``` #[lang = "shl"] +#[doc(alias = "<<")] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented(message="no implementation for `{Self} << {RHS}`", label="no implementation for `{Self} << {RHS}`")] -pub trait Shl<RHS> { +pub trait Shl<RHS=Self> { /// The resulting type after applying the `<<` operator. #[stable(feature = "rust1", since = "1.0.0")] type Output; /// Performs the `<<` operation. + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn shl(self, rhs: RHS) -> Self::Output; } @@ -479,15 +488,17 @@ shl_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 isize i128 } /// SpinVector { vec: vec![3, 4, 0, 1, 2] }); /// ``` #[lang = "shr"] +#[doc(alias = ">>")] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented(message="no implementation for `{Self} >> {RHS}`", label="no implementation for `{Self} >> {RHS}`")] -pub trait Shr<RHS> { +pub trait Shr<RHS=Self> { /// The resulting type after applying the `>>` operator. #[stable(feature = "rust1", since = "1.0.0")] type Output; /// Performs the `>>` operation. + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn shr(self, rhs: RHS) -> Self::Output; } @@ -593,6 +604,7 @@ shr_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize } /// assert_eq!(bv, expected); /// ``` #[lang = "bitand_assign"] +#[doc(alias = "&=")] #[stable(feature = "op_assign_traits", since = "1.8.0")] #[rustc_on_unimplemented(message="no implementation for `{Self} &= {Rhs}`", label="no implementation for `{Self} &= {Rhs}`")] @@ -641,6 +653,7 @@ bitand_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// assert_eq!(prefs, PersonalPreferences { likes_cats: true, likes_dogs: true }); /// ``` #[lang = "bitor_assign"] +#[doc(alias = "|=")] #[stable(feature = "op_assign_traits", since = "1.8.0")] #[rustc_on_unimplemented(message="no implementation for `{Self} |= {Rhs}`", label="no implementation for `{Self} |= {Rhs}`")] @@ -689,6 +702,7 @@ bitor_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// assert_eq!(personality, Personality { has_soul: true, likes_knitting: false}); /// ``` #[lang = "bitxor_assign"] +#[doc(alias = "^=")] #[stable(feature = "op_assign_traits", since = "1.8.0")] #[rustc_on_unimplemented(message="no implementation for `{Self} ^= {Rhs}`", label="no implementation for `{Self} ^= {Rhs}`")] @@ -735,10 +749,11 @@ bitxor_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// assert_eq!(scalar, Scalar(16)); /// ``` #[lang = "shl_assign"] +#[doc(alias = "<<=")] #[stable(feature = "op_assign_traits", since = "1.8.0")] #[rustc_on_unimplemented(message="no implementation for `{Self} <<= {Rhs}`", label="no implementation for `{Self} <<= {Rhs}`")] -pub trait ShlAssign<Rhs> { +pub trait ShlAssign<Rhs=Self> { /// Performs the `<<=` operation. #[stable(feature = "op_assign_traits", since = "1.8.0")] fn shl_assign(&mut self, rhs: Rhs); @@ -802,6 +817,7 @@ shl_assign_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize } /// assert_eq!(scalar, Scalar(4)); /// ``` #[lang = "shr_assign"] +#[doc(alias = ">>=")] #[stable(feature = "op_assign_traits", since = "1.8.0")] #[rustc_on_unimplemented(message="no implementation for `{Self} >>= {Rhs}`", label="no implementation for `{Self} >>= {Rhs}`")] diff --git a/src/libcore/ops/deref.rs b/src/libcore/ops/deref.rs index 4ce0740130b..54eecc82e19 100644 --- a/src/libcore/ops/deref.rs +++ b/src/libcore/ops/deref.rs @@ -68,6 +68,8 @@ /// assert_eq!('a', *x); /// ``` #[lang = "deref"] +#[doc(alias = "*")] +#[doc(alias = "&*")] #[stable(feature = "rust1", since = "1.0.0")] pub trait Deref { /// The resulting type after dereferencing. @@ -75,6 +77,7 @@ pub trait Deref { type Target: ?Sized; /// Dereferences the value. + #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn deref(&self) -> &Self::Target; } @@ -162,6 +165,7 @@ impl<'a, T: ?Sized> Deref for &'a mut T { /// assert_eq!('b', *x); /// ``` #[lang = "deref_mut"] +#[doc(alias = "*")] #[stable(feature = "rust1", since = "1.0.0")] pub trait DerefMut: Deref { /// Mutably dereferences the value. diff --git a/src/libcore/ops/index.rs b/src/libcore/ops/index.rs index d65c0aba504..0a0e92a9180 100644 --- a/src/libcore/ops/index.rs +++ b/src/libcore/ops/index.rs @@ -62,6 +62,9 @@ #[lang = "index"] #[rustc_on_unimplemented = "the type `{Self}` cannot be indexed by `{Idx}`"] #[stable(feature = "rust1", since = "1.0.0")] +#[doc(alias = "]")] +#[doc(alias = "[")] +#[doc(alias = "[]")] pub trait Index<Idx: ?Sized> { /// The returned type after indexing. #[stable(feature = "rust1", since = "1.0.0")] @@ -146,6 +149,9 @@ pub trait Index<Idx: ?Sized> { #[lang = "index_mut"] #[rustc_on_unimplemented = "the type `{Self}` cannot be mutably indexed by `{Idx}`"] #[stable(feature = "rust1", since = "1.0.0")] +#[doc(alias = "[")] +#[doc(alias = "]")] +#[doc(alias = "[]")] pub trait IndexMut<Idx: ?Sized>: Index<Idx> { /// Performs the mutable indexing (`container[index]`) operation. #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index 6f3e3b50885..d70f7ae66f9 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -45,6 +45,7 @@ use fmt; /// [`IntoIterator`]: ../iter/trait.Iterator.html /// [`Iterator`]: ../iter/trait.IntoIterator.html /// [slicing index]: ../slice/trait.SliceIndex.html +#[doc(alias = "..")] #[derive(Copy, Clone, PartialEq, Eq, Hash)] #[stable(feature = "rust1", since = "1.0.0")] pub struct RangeFull; @@ -74,6 +75,7 @@ impl fmt::Debug for RangeFull { /// assert_eq!(arr[1.. ], [ 'b', 'c', 'd']); /// assert_eq!(arr[1..3], [ 'b', 'c' ]); // Range /// ``` +#[doc(alias = "..")] #[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186 #[stable(feature = "rust1", since = "1.0.0")] pub struct Range<Idx> { @@ -175,6 +177,7 @@ impl<Idx: PartialOrd<Idx>> Range<Idx> { /// ``` /// /// [`Iterator`]: ../iter/trait.IntoIterator.html +#[doc(alias = "..")] #[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186 #[stable(feature = "rust1", since = "1.0.0")] pub struct RangeFrom<Idx> { @@ -256,6 +259,7 @@ impl<Idx: PartialOrd<Idx>> RangeFrom<Idx> { /// [`IntoIterator`]: ../iter/trait.Iterator.html /// [`Iterator`]: ../iter/trait.IntoIterator.html /// [slicing index]: ../slice/trait.SliceIndex.html +#[doc(alias = "..")] #[derive(Copy, Clone, PartialEq, Eq, Hash)] #[stable(feature = "rust1", since = "1.0.0")] pub struct RangeTo<Idx> { @@ -323,6 +327,7 @@ impl<Idx: PartialOrd<Idx>> RangeTo<Idx> { /// assert_eq!(arr[ ..=2], [0,1,2 ]); /// assert_eq!(arr[1..=2], [ 1,2 ]); // RangeInclusive /// ``` +#[doc(alias = "..=")] #[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186 #[stable(feature = "inclusive_range", since = "1.26.0")] pub struct RangeInclusive<Idx> { @@ -449,6 +454,7 @@ impl<Idx: PartialOrd<Idx>> RangeInclusive<Idx> { /// [`IntoIterator`]: ../iter/trait.Iterator.html /// [`Iterator`]: ../iter/trait.IntoIterator.html /// [slicing index]: ../slice/trait.SliceIndex.html +#[doc(alias = "..=")] #[derive(Copy, Clone, PartialEq, Eq, Hash)] #[stable(feature = "inclusive_range", since = "1.26.0")] pub struct RangeToInclusive<Idx> { diff --git a/src/libcore/ops/try.rs b/src/libcore/ops/try.rs index ef6a8fb6a61..4f2d30aa6a8 100644 --- a/src/libcore/ops/try.rs +++ b/src/libcore/ops/try.rs @@ -28,6 +28,7 @@ that implement `{Try}`", label="the `?` operator cannot be applied to type `{Self}`") )] +#[doc(alias = "?")] pub trait Try { /// The type of this value when viewed as successful. #[unstable(feature = "try_trait", issue = "42327")] diff --git a/src/libcore/prelude/v1.rs b/src/libcore/prelude/v1.rs index cc3ad71117a..8212648f2d8 100644 --- a/src/libcore/prelude/v1.rs +++ b/src/libcore/prelude/v1.rs @@ -58,7 +58,9 @@ pub use result::Result::{self, Ok, Err}; // Re-exported extension traits for primitive types #[stable(feature = "core_prelude", since = "1.4.0")] #[doc(no_inline)] +#[cfg(stage0)] pub use slice::SliceExt; #[stable(feature = "core_prelude", since = "1.4.0")] #[doc(no_inline)] +#[cfg(stage0)] pub use str::StrExt; diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 4a7d7c410eb..c61bdfc9c4f 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -166,8 +166,6 @@ pub unsafe fn swap<T>(x: *mut T, y: *mut T) { /// Basic usage: /// /// ``` -/// #![feature(swap_nonoverlapping)] -/// /// use std::ptr; /// /// let mut x = [1, 2, 3, 4]; @@ -181,7 +179,7 @@ pub unsafe fn swap<T>(x: *mut T, y: *mut T) { /// assert_eq!(y, [1, 2, 9]); /// ``` #[inline] -#[unstable(feature = "swap_nonoverlapping", issue = "42818")] +#[stable(feature = "swap_nonoverlapping", since = "1.27.0")] pub unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) { let x = x as *mut u8; let y = y as *mut u8; @@ -2515,6 +2513,7 @@ impl<T: ?Sized> PartialOrd for *mut T { reason = "use NonNull instead and consider PhantomData<T> \ (if you also use #[may_dangle]), Send, and/or Sync")] #[allow(deprecated)] +#[doc(hidden)] pub struct Unique<T: ?Sized> { pointer: NonZero<*const T>, // NOTE: this marker has no consequences for variance, but is necessary @@ -2744,7 +2743,7 @@ impl<T: ?Sized> NonNull<T> { } /// Cast to a pointer of another type - #[unstable(feature = "nonnull_cast", issue = "47653")] + #[stable(feature = "nonnull_cast", since = "1.27.0")] pub fn cast<U>(self) -> NonNull<U> { unsafe { NonNull::new_unchecked(self.as_ptr() as *mut U) diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 0a22028da81..83e8a6e4b68 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -68,12 +68,15 @@ struct Repr<T> { // Extension traits // +public_in_stage0! { +{ /// Extension methods for slices. #[unstable(feature = "core_slice_ext", reason = "stable interface provided by `impl [T]` in later crates", issue = "32110")] #[allow(missing_docs)] // documented elsewhere -pub trait SliceExt { +} +trait SliceExt { type Item; #[stable(feature = "core", since = "1.6.0")] @@ -86,7 +89,7 @@ pub trait SliceExt { fn split<P>(&self, pred: P) -> Split<Self::Item, P> where P: FnMut(&Self::Item) -> bool; - #[unstable(feature = "slice_rsplit", issue = "41020")] + #[stable(feature = "slice_rsplit", since = "1.27.0")] fn rsplit<P>(&self, pred: P) -> RSplit<Self::Item, P> where P: FnMut(&Self::Item) -> bool; @@ -169,7 +172,7 @@ pub trait SliceExt { fn split_mut<P>(&mut self, pred: P) -> SplitMut<Self::Item, P> where P: FnMut(&Self::Item) -> bool; - #[unstable(feature = "slice_rsplit", issue = "41020")] + #[stable(feature = "slice_rsplit", since = "1.27.0")] fn rsplit_mut<P>(&mut self, pred: P) -> RSplitMut<Self::Item, P> where P: FnMut(&Self::Item) -> bool; @@ -223,7 +226,7 @@ pub trait SliceExt { #[stable(feature = "copy_from_slice", since = "1.9.0")] fn copy_from_slice(&mut self, src: &[Self::Item]) where Self::Item: Copy; - #[unstable(feature = "swap_with_slice", issue = "44030")] + #[stable(feature = "swap_with_slice", since = "1.27.0")] fn swap_with_slice(&mut self, src: &mut [Self::Item]); #[stable(feature = "sort_unstable", since = "1.20.0")] @@ -238,7 +241,7 @@ pub trait SliceExt { fn sort_unstable_by_key<B, F>(&mut self, f: F) where F: FnMut(&Self::Item) -> B, B: Ord; -} +}} // Use macros to be generic over const/mut macro_rules! slice_offset { @@ -755,6 +758,1474 @@ impl<T> SliceExt for [T] { } } +// FIXME: remove (inline) this macro and the SliceExt trait +// when updating to a bootstrap compiler that has the new lang items. +#[cfg_attr(stage0, macro_export)] +#[unstable(feature = "core_slice_ext", issue = "32110")] +macro_rules! slice_core_methods { () => { + /// Returns the number of elements in the slice. + /// + /// # Examples + /// + /// ``` + /// let a = [1, 2, 3]; + /// assert_eq!(a.len(), 3); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn len(&self) -> usize { + SliceExt::len(self) + } + + /// Returns `true` if the slice has a length of 0. + /// + /// # Examples + /// + /// ``` + /// let a = [1, 2, 3]; + /// assert!(!a.is_empty()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn is_empty(&self) -> bool { + SliceExt::is_empty(self) + } + + /// Returns the first element of the slice, or `None` if it is empty. + /// + /// # Examples + /// + /// ``` + /// let v = [10, 40, 30]; + /// assert_eq!(Some(&10), v.first()); + /// + /// let w: &[i32] = &[]; + /// assert_eq!(None, w.first()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn first(&self) -> Option<&T> { + SliceExt::first(self) + } + + /// Returns a mutable pointer to the first element of the slice, or `None` if it is empty. + /// + /// # Examples + /// + /// ``` + /// let x = &mut [0, 1, 2]; + /// + /// if let Some(first) = x.first_mut() { + /// *first = 5; + /// } + /// assert_eq!(x, &[5, 1, 2]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn first_mut(&mut self) -> Option<&mut T> { + SliceExt::first_mut(self) + } + + /// Returns the first and all the rest of the elements of the slice, or `None` if it is empty. + /// + /// # Examples + /// + /// ``` + /// let x = &[0, 1, 2]; + /// + /// if let Some((first, elements)) = x.split_first() { + /// assert_eq!(first, &0); + /// assert_eq!(elements, &[1, 2]); + /// } + /// ``` + #[stable(feature = "slice_splits", since = "1.5.0")] + #[inline] + pub fn split_first(&self) -> Option<(&T, &[T])> { + SliceExt::split_first(self) + } + + /// Returns the first and all the rest of the elements of the slice, or `None` if it is empty. + /// + /// # Examples + /// + /// ``` + /// let x = &mut [0, 1, 2]; + /// + /// if let Some((first, elements)) = x.split_first_mut() { + /// *first = 3; + /// elements[0] = 4; + /// elements[1] = 5; + /// } + /// assert_eq!(x, &[3, 4, 5]); + /// ``` + #[stable(feature = "slice_splits", since = "1.5.0")] + #[inline] + pub fn split_first_mut(&mut self) -> Option<(&mut T, &mut [T])> { + SliceExt::split_first_mut(self) + } + + /// Returns the last and all the rest of the elements of the slice, or `None` if it is empty. + /// + /// # Examples + /// + /// ``` + /// let x = &[0, 1, 2]; + /// + /// if let Some((last, elements)) = x.split_last() { + /// assert_eq!(last, &2); + /// assert_eq!(elements, &[0, 1]); + /// } + /// ``` + #[stable(feature = "slice_splits", since = "1.5.0")] + #[inline] + pub fn split_last(&self) -> Option<(&T, &[T])> { + SliceExt::split_last(self) + } + + /// Returns the last and all the rest of the elements of the slice, or `None` if it is empty. + /// + /// # Examples + /// + /// ``` + /// let x = &mut [0, 1, 2]; + /// + /// if let Some((last, elements)) = x.split_last_mut() { + /// *last = 3; + /// elements[0] = 4; + /// elements[1] = 5; + /// } + /// assert_eq!(x, &[4, 5, 3]); + /// ``` + #[stable(feature = "slice_splits", since = "1.5.0")] + #[inline] + pub fn split_last_mut(&mut self) -> Option<(&mut T, &mut [T])> { + SliceExt::split_last_mut(self) + } + + /// Returns the last element of the slice, or `None` if it is empty. + /// + /// # Examples + /// + /// ``` + /// let v = [10, 40, 30]; + /// assert_eq!(Some(&30), v.last()); + /// + /// let w: &[i32] = &[]; + /// assert_eq!(None, w.last()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn last(&self) -> Option<&T> { + SliceExt::last(self) + } + + /// Returns a mutable pointer to the last item in the slice. + /// + /// # Examples + /// + /// ``` + /// let x = &mut [0, 1, 2]; + /// + /// if let Some(last) = x.last_mut() { + /// *last = 10; + /// } + /// assert_eq!(x, &[0, 1, 10]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn last_mut(&mut self) -> Option<&mut T> { + SliceExt::last_mut(self) + } + + /// Returns a reference to an element or subslice depending on the type of + /// index. + /// + /// - If given a position, returns a reference to the element at that + /// position or `None` if out of bounds. + /// - If given a range, returns the subslice corresponding to that range, + /// or `None` if out of bounds. + /// + /// # Examples + /// + /// ``` + /// let v = [10, 40, 30]; + /// assert_eq!(Some(&40), v.get(1)); + /// assert_eq!(Some(&[10, 40][..]), v.get(0..2)); + /// assert_eq!(None, v.get(3)); + /// assert_eq!(None, v.get(0..4)); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn get<I>(&self, index: I) -> Option<&I::Output> + where I: SliceIndex<Self> + { + SliceExt::get(self, index) + } + + /// Returns a mutable reference to an element or subslice depending on the + /// type of index (see [`get`]) or `None` if the index is out of bounds. + /// + /// [`get`]: #method.get + /// + /// # Examples + /// + /// ``` + /// let x = &mut [0, 1, 2]; + /// + /// if let Some(elem) = x.get_mut(1) { + /// *elem = 42; + /// } + /// assert_eq!(x, &[0, 42, 2]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn get_mut<I>(&mut self, index: I) -> Option<&mut I::Output> + where I: SliceIndex<Self> + { + SliceExt::get_mut(self, index) + } + + /// Returns a reference to an element or subslice, without doing bounds + /// checking. + /// + /// This is generally not recommended, use with caution! For a safe + /// alternative see [`get`]. + /// + /// [`get`]: #method.get + /// + /// # Examples + /// + /// ``` + /// let x = &[1, 2, 4]; + /// + /// unsafe { + /// assert_eq!(x.get_unchecked(1), &2); + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub unsafe fn get_unchecked<I>(&self, index: I) -> &I::Output + where I: SliceIndex<Self> + { + SliceExt::get_unchecked(self, index) + } + + /// Returns a mutable reference to an element or subslice, without doing + /// bounds checking. + /// + /// This is generally not recommended, use with caution! For a safe + /// alternative see [`get_mut`]. + /// + /// [`get_mut`]: #method.get_mut + /// + /// # Examples + /// + /// ``` + /// let x = &mut [1, 2, 4]; + /// + /// unsafe { + /// let elem = x.get_unchecked_mut(1); + /// *elem = 13; + /// } + /// assert_eq!(x, &[1, 13, 4]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub unsafe fn get_unchecked_mut<I>(&mut self, index: I) -> &mut I::Output + where I: SliceIndex<Self> + { + SliceExt::get_unchecked_mut(self, index) + } + + /// Returns a raw pointer to the slice's buffer. + /// + /// The caller must ensure that the slice outlives the pointer this + /// function returns, or else it will end up pointing to garbage. + /// + /// Modifying the container referenced by this slice may cause its buffer + /// to be reallocated, which would also make any pointers to it invalid. + /// + /// # Examples + /// + /// ``` + /// let x = &[1, 2, 4]; + /// let x_ptr = x.as_ptr(); + /// + /// unsafe { + /// for i in 0..x.len() { + /// assert_eq!(x.get_unchecked(i), &*x_ptr.offset(i as isize)); + /// } + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn as_ptr(&self) -> *const T { + SliceExt::as_ptr(self) + } + + /// Returns an unsafe mutable pointer to the slice's buffer. + /// + /// The caller must ensure that the slice outlives the pointer this + /// function returns, or else it will end up pointing to garbage. + /// + /// Modifying the container referenced by this slice may cause its buffer + /// to be reallocated, which would also make any pointers to it invalid. + /// + /// # Examples + /// + /// ``` + /// let x = &mut [1, 2, 4]; + /// let x_ptr = x.as_mut_ptr(); + /// + /// unsafe { + /// for i in 0..x.len() { + /// *x_ptr.offset(i as isize) += 2; + /// } + /// } + /// assert_eq!(x, &[3, 4, 6]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn as_mut_ptr(&mut self) -> *mut T { + SliceExt::as_mut_ptr(self) + } + + /// Swaps two elements in the slice. + /// + /// # Arguments + /// + /// * a - The index of the first element + /// * b - The index of the second element + /// + /// # Panics + /// + /// Panics if `a` or `b` are out of bounds. + /// + /// # Examples + /// + /// ``` + /// let mut v = ["a", "b", "c", "d"]; + /// v.swap(1, 3); + /// assert!(v == ["a", "d", "c", "b"]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn swap(&mut self, a: usize, b: usize) { + SliceExt::swap(self, a, b) + } + + /// Reverses the order of elements in the slice, in place. + /// + /// # Examples + /// + /// ``` + /// let mut v = [1, 2, 3]; + /// v.reverse(); + /// assert!(v == [3, 2, 1]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn reverse(&mut self) { + SliceExt::reverse(self) + } + + /// Returns an iterator over the slice. + /// + /// # Examples + /// + /// ``` + /// let x = &[1, 2, 4]; + /// let mut iterator = x.iter(); + /// + /// assert_eq!(iterator.next(), Some(&1)); + /// assert_eq!(iterator.next(), Some(&2)); + /// assert_eq!(iterator.next(), Some(&4)); + /// assert_eq!(iterator.next(), None); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn iter(&self) -> Iter<T> { + SliceExt::iter(self) + } + + /// Returns an iterator that allows modifying each value. + /// + /// # Examples + /// + /// ``` + /// let x = &mut [1, 2, 4]; + /// for elem in x.iter_mut() { + /// *elem += 2; + /// } + /// assert_eq!(x, &[3, 4, 6]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn iter_mut(&mut self) -> IterMut<T> { + SliceExt::iter_mut(self) + } + + /// Returns an iterator over all contiguous windows of length + /// `size`. The windows overlap. If the slice is shorter than + /// `size`, the iterator returns no values. + /// + /// # Panics + /// + /// Panics if `size` is 0. + /// + /// # Examples + /// + /// ``` + /// let slice = ['r', 'u', 's', 't']; + /// let mut iter = slice.windows(2); + /// assert_eq!(iter.next().unwrap(), &['r', 'u']); + /// assert_eq!(iter.next().unwrap(), &['u', 's']); + /// assert_eq!(iter.next().unwrap(), &['s', 't']); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// If the slice is shorter than `size`: + /// + /// ``` + /// let slice = ['f', 'o', 'o']; + /// let mut iter = slice.windows(4); + /// assert!(iter.next().is_none()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn windows(&self, size: usize) -> Windows<T> { + SliceExt::windows(self, size) + } + + /// Returns an iterator over `chunk_size` elements of the slice at a + /// time. The chunks are slices and do not overlap. If `chunk_size` does + /// not divide the length of the slice, then the last chunk will + /// not have length `chunk_size`. + /// + /// See [`exact_chunks`] for a variant of this iterator that returns chunks + /// of always exactly `chunk_size` elements. + /// + /// # Panics + /// + /// Panics if `chunk_size` is 0. + /// + /// # Examples + /// + /// ``` + /// let slice = ['l', 'o', 'r', 'e', 'm']; + /// let mut iter = slice.chunks(2); + /// assert_eq!(iter.next().unwrap(), &['l', 'o']); + /// assert_eq!(iter.next().unwrap(), &['r', 'e']); + /// assert_eq!(iter.next().unwrap(), &['m']); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// [`exact_chunks`]: #method.exact_chunks + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn chunks(&self, chunk_size: usize) -> Chunks<T> { + SliceExt::chunks(self, chunk_size) + } + + /// Returns an iterator over `chunk_size` elements of the slice at a + /// time. The chunks are slices and do not overlap. If `chunk_size` does + /// not divide the length of the slice, then the last up to `chunk_size-1` + /// elements will be omitted. + /// + /// Due to each chunk having exactly `chunk_size` elements, the compiler + /// can often optimize the resulting code better than in the case of + /// [`chunks`]. + /// + /// # Panics + /// + /// Panics if `chunk_size` is 0. + /// + /// # Examples + /// + /// ``` + /// #![feature(exact_chunks)] + /// + /// let slice = ['l', 'o', 'r', 'e', 'm']; + /// let mut iter = slice.exact_chunks(2); + /// assert_eq!(iter.next().unwrap(), &['l', 'o']); + /// assert_eq!(iter.next().unwrap(), &['r', 'e']); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// [`chunks`]: #method.chunks + #[unstable(feature = "exact_chunks", issue = "47115")] + #[inline] + pub fn exact_chunks(&self, chunk_size: usize) -> ExactChunks<T> { + SliceExt::exact_chunks(self, chunk_size) + } + + /// Returns an iterator over `chunk_size` elements of the slice at a time. + /// The chunks are mutable slices, and do not overlap. If `chunk_size` does + /// not divide the length of the slice, then the last chunk will not + /// have length `chunk_size`. + /// + /// See [`exact_chunks_mut`] for a variant of this iterator that returns chunks + /// of always exactly `chunk_size` elements. + /// + /// # Panics + /// + /// Panics if `chunk_size` is 0. + /// + /// # Examples + /// + /// ``` + /// let v = &mut [0, 0, 0, 0, 0]; + /// let mut count = 1; + /// + /// for chunk in v.chunks_mut(2) { + /// for elem in chunk.iter_mut() { + /// *elem += count; + /// } + /// count += 1; + /// } + /// assert_eq!(v, &[1, 1, 2, 2, 3]); + /// ``` + /// + /// [`exact_chunks_mut`]: #method.exact_chunks_mut + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn chunks_mut(&mut self, chunk_size: usize) -> ChunksMut<T> { + SliceExt::chunks_mut(self, chunk_size) + } + + /// Returns an iterator over `chunk_size` elements of the slice at a time. + /// The chunks are mutable slices, and do not overlap. If `chunk_size` does + /// not divide the length of the slice, then the last up to `chunk_size-1` + /// elements will be omitted. + /// + /// + /// Due to each chunk having exactly `chunk_size` elements, the compiler + /// can often optimize the resulting code better than in the case of + /// [`chunks_mut`]. + /// + /// # Panics + /// + /// Panics if `chunk_size` is 0. + /// + /// # Examples + /// + /// ``` + /// #![feature(exact_chunks)] + /// + /// let v = &mut [0, 0, 0, 0, 0]; + /// let mut count = 1; + /// + /// for chunk in v.exact_chunks_mut(2) { + /// for elem in chunk.iter_mut() { + /// *elem += count; + /// } + /// count += 1; + /// } + /// assert_eq!(v, &[1, 1, 2, 2, 0]); + /// ``` + /// + /// [`chunks_mut`]: #method.chunks_mut + #[unstable(feature = "exact_chunks", issue = "47115")] + #[inline] + pub fn exact_chunks_mut(&mut self, chunk_size: usize) -> ExactChunksMut<T> { + SliceExt::exact_chunks_mut(self, chunk_size) + } + + /// Divides one slice into two at an index. + /// + /// The first will contain all indices from `[0, mid)` (excluding + /// the index `mid` itself) and the second will contain all + /// indices from `[mid, len)` (excluding the index `len` itself). + /// + /// # Panics + /// + /// Panics if `mid > len`. + /// + /// # Examples + /// + /// ``` + /// let v = [1, 2, 3, 4, 5, 6]; + /// + /// { + /// let (left, right) = v.split_at(0); + /// assert!(left == []); + /// assert!(right == [1, 2, 3, 4, 5, 6]); + /// } + /// + /// { + /// let (left, right) = v.split_at(2); + /// assert!(left == [1, 2]); + /// assert!(right == [3, 4, 5, 6]); + /// } + /// + /// { + /// let (left, right) = v.split_at(6); + /// assert!(left == [1, 2, 3, 4, 5, 6]); + /// assert!(right == []); + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn split_at(&self, mid: usize) -> (&[T], &[T]) { + SliceExt::split_at(self, mid) + } + + /// Divides one mutable slice into two at an index. + /// + /// The first will contain all indices from `[0, mid)` (excluding + /// the index `mid` itself) and the second will contain all + /// indices from `[mid, len)` (excluding the index `len` itself). + /// + /// # Panics + /// + /// Panics if `mid > len`. + /// + /// # Examples + /// + /// ``` + /// let mut v = [1, 0, 3, 0, 5, 6]; + /// // scoped to restrict the lifetime of the borrows + /// { + /// let (left, right) = v.split_at_mut(2); + /// assert!(left == [1, 0]); + /// assert!(right == [3, 0, 5, 6]); + /// left[1] = 2; + /// right[1] = 4; + /// } + /// assert!(v == [1, 2, 3, 4, 5, 6]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) { + SliceExt::split_at_mut(self, mid) + } + + /// Returns an iterator over subslices separated by elements that match + /// `pred`. The matched element is not contained in the subslices. + /// + /// # Examples + /// + /// ``` + /// let slice = [10, 40, 33, 20]; + /// let mut iter = slice.split(|num| num % 3 == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[10, 40]); + /// assert_eq!(iter.next().unwrap(), &[20]); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// If the first element is matched, an empty slice will be the first item + /// returned by the iterator. Similarly, if the last element in the slice + /// is matched, an empty slice will be the last item returned by the + /// iterator: + /// + /// ``` + /// let slice = [10, 40, 33]; + /// let mut iter = slice.split(|num| num % 3 == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[10, 40]); + /// assert_eq!(iter.next().unwrap(), &[]); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// If two matched elements are directly adjacent, an empty slice will be + /// present between them: + /// + /// ``` + /// let slice = [10, 6, 33, 20]; + /// let mut iter = slice.split(|num| num % 3 == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[10]); + /// assert_eq!(iter.next().unwrap(), &[]); + /// assert_eq!(iter.next().unwrap(), &[20]); + /// assert!(iter.next().is_none()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn split<F>(&self, pred: F) -> Split<T, F> + where F: FnMut(&T) -> bool + { + SliceExt::split(self, pred) + } + + /// Returns an iterator over mutable subslices separated by elements that + /// match `pred`. The matched element is not contained in the subslices. + /// + /// # Examples + /// + /// ``` + /// let mut v = [10, 40, 30, 20, 60, 50]; + /// + /// for group in v.split_mut(|num| *num % 3 == 0) { + /// group[0] = 1; + /// } + /// assert_eq!(v, [1, 40, 30, 1, 60, 1]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn split_mut<F>(&mut self, pred: F) -> SplitMut<T, F> + where F: FnMut(&T) -> bool + { + SliceExt::split_mut(self, pred) + } + + /// Returns an iterator over subslices separated by elements that match + /// `pred`, starting at the end of the slice and working backwards. + /// The matched element is not contained in the subslices. + /// + /// # Examples + /// + /// ``` + /// let slice = [11, 22, 33, 0, 44, 55]; + /// let mut iter = slice.rsplit(|num| *num == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[44, 55]); + /// assert_eq!(iter.next().unwrap(), &[11, 22, 33]); + /// assert_eq!(iter.next(), None); + /// ``` + /// + /// As with `split()`, if the first or last element is matched, an empty + /// slice will be the first (or last) item returned by the iterator. + /// + /// ``` + /// let v = &[0, 1, 1, 2, 3, 5, 8]; + /// let mut it = v.rsplit(|n| *n % 2 == 0); + /// assert_eq!(it.next().unwrap(), &[]); + /// assert_eq!(it.next().unwrap(), &[3, 5]); + /// assert_eq!(it.next().unwrap(), &[1, 1]); + /// assert_eq!(it.next().unwrap(), &[]); + /// assert_eq!(it.next(), None); + /// ``` + #[stable(feature = "slice_rsplit", since = "1.27.0")] + #[inline] + pub fn rsplit<F>(&self, pred: F) -> RSplit<T, F> + where F: FnMut(&T) -> bool + { + SliceExt::rsplit(self, pred) + } + + /// Returns an iterator over mutable subslices separated by elements that + /// match `pred`, starting at the end of the slice and working + /// backwards. The matched element is not contained in the subslices. + /// + /// # Examples + /// + /// ``` + /// let mut v = [100, 400, 300, 200, 600, 500]; + /// + /// let mut count = 0; + /// for group in v.rsplit_mut(|num| *num % 3 == 0) { + /// count += 1; + /// group[0] = count; + /// } + /// assert_eq!(v, [3, 400, 300, 2, 600, 1]); + /// ``` + /// + #[stable(feature = "slice_rsplit", since = "1.27.0")] + #[inline] + pub fn rsplit_mut<F>(&mut self, pred: F) -> RSplitMut<T, F> + where F: FnMut(&T) -> bool + { + SliceExt::rsplit_mut(self, pred) + } + + /// Returns an iterator over subslices separated by elements that match + /// `pred`, limited to returning at most `n` items. The matched element is + /// not contained in the subslices. + /// + /// The last element returned, if any, will contain the remainder of the + /// slice. + /// + /// # Examples + /// + /// Print the slice split once by numbers divisible by 3 (i.e. `[10, 40]`, + /// `[20, 60, 50]`): + /// + /// ``` + /// let v = [10, 40, 30, 20, 60, 50]; + /// + /// for group in v.splitn(2, |num| *num % 3 == 0) { + /// println!("{:?}", group); + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn splitn<F>(&self, n: usize, pred: F) -> SplitN<T, F> + where F: FnMut(&T) -> bool + { + SliceExt::splitn(self, n, pred) + } + + /// Returns an iterator over subslices separated by elements that match + /// `pred`, limited to returning at most `n` items. The matched element is + /// not contained in the subslices. + /// + /// The last element returned, if any, will contain the remainder of the + /// slice. + /// + /// # Examples + /// + /// ``` + /// let mut v = [10, 40, 30, 20, 60, 50]; + /// + /// for group in v.splitn_mut(2, |num| *num % 3 == 0) { + /// group[0] = 1; + /// } + /// assert_eq!(v, [1, 40, 30, 1, 60, 50]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn splitn_mut<F>(&mut self, n: usize, pred: F) -> SplitNMut<T, F> + where F: FnMut(&T) -> bool + { + SliceExt::splitn_mut(self, n, pred) + } + + /// Returns an iterator over subslices separated by elements that match + /// `pred` limited to returning at most `n` items. This starts at the end of + /// the slice and works backwards. The matched element is not contained in + /// the subslices. + /// + /// The last element returned, if any, will contain the remainder of the + /// slice. + /// + /// # Examples + /// + /// Print the slice split once, starting from the end, by numbers divisible + /// by 3 (i.e. `[50]`, `[10, 40, 30, 20]`): + /// + /// ``` + /// let v = [10, 40, 30, 20, 60, 50]; + /// + /// for group in v.rsplitn(2, |num| *num % 3 == 0) { + /// println!("{:?}", group); + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn rsplitn<F>(&self, n: usize, pred: F) -> RSplitN<T, F> + where F: FnMut(&T) -> bool + { + SliceExt::rsplitn(self, n, pred) + } + + /// Returns an iterator over subslices separated by elements that match + /// `pred` limited to returning at most `n` items. This starts at the end of + /// the slice and works backwards. The matched element is not contained in + /// the subslices. + /// + /// The last element returned, if any, will contain the remainder of the + /// slice. + /// + /// # Examples + /// + /// ``` + /// let mut s = [10, 40, 30, 20, 60, 50]; + /// + /// for group in s.rsplitn_mut(2, |num| *num % 3 == 0) { + /// group[0] = 1; + /// } + /// assert_eq!(s, [1, 40, 30, 20, 60, 1]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn rsplitn_mut<F>(&mut self, n: usize, pred: F) -> RSplitNMut<T, F> + where F: FnMut(&T) -> bool + { + SliceExt::rsplitn_mut(self, n, pred) + } + + /// Returns `true` if the slice contains an element with the given value. + /// + /// # Examples + /// + /// ``` + /// let v = [10, 40, 30]; + /// assert!(v.contains(&30)); + /// assert!(!v.contains(&50)); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn contains(&self, x: &T) -> bool + where T: PartialEq + { + SliceExt::contains(self, x) + } + + /// Returns `true` if `needle` is a prefix of the slice. + /// + /// # Examples + /// + /// ``` + /// let v = [10, 40, 30]; + /// assert!(v.starts_with(&[10])); + /// assert!(v.starts_with(&[10, 40])); + /// assert!(!v.starts_with(&[50])); + /// assert!(!v.starts_with(&[10, 50])); + /// ``` + /// + /// Always returns `true` if `needle` is an empty slice: + /// + /// ``` + /// let v = &[10, 40, 30]; + /// assert!(v.starts_with(&[])); + /// let v: &[u8] = &[]; + /// assert!(v.starts_with(&[])); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn starts_with(&self, needle: &[T]) -> bool + where T: PartialEq + { + SliceExt::starts_with(self, needle) + } + + /// Returns `true` if `needle` is a suffix of the slice. + /// + /// # Examples + /// + /// ``` + /// let v = [10, 40, 30]; + /// assert!(v.ends_with(&[30])); + /// assert!(v.ends_with(&[40, 30])); + /// assert!(!v.ends_with(&[50])); + /// assert!(!v.ends_with(&[50, 30])); + /// ``` + /// + /// Always returns `true` if `needle` is an empty slice: + /// + /// ``` + /// let v = &[10, 40, 30]; + /// assert!(v.ends_with(&[])); + /// let v: &[u8] = &[]; + /// assert!(v.ends_with(&[])); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn ends_with(&self, needle: &[T]) -> bool + where T: PartialEq + { + SliceExt::ends_with(self, needle) + } + + /// Binary searches this sorted slice for a given element. + /// + /// If the value is found then `Ok` is returned, containing the + /// index of the matching element; if the value is not found then + /// `Err` is returned, containing the index where a matching + /// element could be inserted while maintaining sorted order. + /// + /// # Examples + /// + /// Looks up a series of four elements. The first is found, with a + /// uniquely determined position; the second and third are not + /// found; the fourth could match any position in `[1, 4]`. + /// + /// ``` + /// let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]; + /// + /// assert_eq!(s.binary_search(&13), Ok(9)); + /// assert_eq!(s.binary_search(&4), Err(7)); + /// assert_eq!(s.binary_search(&100), Err(13)); + /// let r = s.binary_search(&1); + /// assert!(match r { Ok(1...4) => true, _ => false, }); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn binary_search(&self, x: &T) -> Result<usize, usize> + where T: Ord + { + SliceExt::binary_search(self, x) + } + + /// Binary searches this sorted slice with a comparator function. + /// + /// The comparator function should implement an order consistent + /// with the sort order of the underlying slice, returning an + /// order code that indicates whether its argument is `Less`, + /// `Equal` or `Greater` the desired target. + /// + /// If a matching value is found then returns `Ok`, containing + /// the index for the matched element; if no match is found then + /// `Err` is returned, containing the index where a matching + /// element could be inserted while maintaining sorted order. + /// + /// # Examples + /// + /// Looks up a series of four elements. The first is found, with a + /// uniquely determined position; the second and third are not + /// found; the fourth could match any position in `[1, 4]`. + /// + /// ``` + /// let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]; + /// + /// let seek = 13; + /// assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Ok(9)); + /// let seek = 4; + /// assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Err(7)); + /// let seek = 100; + /// assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Err(13)); + /// let seek = 1; + /// let r = s.binary_search_by(|probe| probe.cmp(&seek)); + /// assert!(match r { Ok(1...4) => true, _ => false, }); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn binary_search_by<'a, F>(&'a self, f: F) -> Result<usize, usize> + where F: FnMut(&'a T) -> Ordering + { + SliceExt::binary_search_by(self, f) + } + + /// Binary searches this sorted slice with a key extraction function. + /// + /// Assumes that the slice is sorted by the key, for instance with + /// [`sort_by_key`] using the same key extraction function. + /// + /// If a matching value is found then returns `Ok`, containing the + /// index for the matched element; if no match is found then `Err` + /// is returned, containing the index where a matching element could + /// be inserted while maintaining sorted order. + /// + /// [`sort_by_key`]: #method.sort_by_key + /// + /// # Examples + /// + /// Looks up a series of four elements in a slice of pairs sorted by + /// their second elements. The first is found, with a uniquely + /// determined position; the second and third are not found; the + /// fourth could match any position in `[1, 4]`. + /// + /// ``` + /// let s = [(0, 0), (2, 1), (4, 1), (5, 1), (3, 1), + /// (1, 2), (2, 3), (4, 5), (5, 8), (3, 13), + /// (1, 21), (2, 34), (4, 55)]; + /// + /// assert_eq!(s.binary_search_by_key(&13, |&(a,b)| b), Ok(9)); + /// assert_eq!(s.binary_search_by_key(&4, |&(a,b)| b), Err(7)); + /// assert_eq!(s.binary_search_by_key(&100, |&(a,b)| b), Err(13)); + /// let r = s.binary_search_by_key(&1, |&(a,b)| b); + /// assert!(match r { Ok(1...4) => true, _ => false, }); + /// ``` + #[stable(feature = "slice_binary_search_by_key", since = "1.10.0")] + #[inline] + pub fn binary_search_by_key<'a, B, F>(&'a self, b: &B, f: F) -> Result<usize, usize> + where F: FnMut(&'a T) -> B, + B: Ord + { + SliceExt::binary_search_by_key(self, b, f) + } + + /// Sorts the slice, but may not preserve the order of equal elements. + /// + /// This sort is unstable (i.e. may reorder equal elements), in-place (i.e. does not allocate), + /// and `O(n log n)` worst-case. + /// + /// # Current implementation + /// + /// The current algorithm is based on [pattern-defeating quicksort][pdqsort] by Orson Peters, + /// which combines the fast average case of randomized quicksort with the fast worst case of + /// heapsort, while achieving linear time on slices with certain patterns. It uses some + /// randomization to avoid degenerate cases, but with a fixed seed to always provide + /// deterministic behavior. + /// + /// It is typically faster than stable sorting, except in a few special cases, e.g. when the + /// slice consists of several concatenated sorted sequences. + /// + /// # Examples + /// + /// ``` + /// let mut v = [-5, 4, 1, -3, 2]; + /// + /// v.sort_unstable(); + /// assert!(v == [-5, -3, 1, 2, 4]); + /// ``` + /// + /// [pdqsort]: https://github.com/orlp/pdqsort + #[stable(feature = "sort_unstable", since = "1.20.0")] + #[inline] + pub fn sort_unstable(&mut self) + where T: Ord + { + SliceExt::sort_unstable(self); + } + + /// Sorts the slice with a comparator function, but may not preserve the order of equal + /// elements. + /// + /// This sort is unstable (i.e. may reorder equal elements), in-place (i.e. does not allocate), + /// and `O(n log n)` worst-case. + /// + /// # Current implementation + /// + /// The current algorithm is based on [pattern-defeating quicksort][pdqsort] by Orson Peters, + /// which combines the fast average case of randomized quicksort with the fast worst case of + /// heapsort, while achieving linear time on slices with certain patterns. It uses some + /// randomization to avoid degenerate cases, but with a fixed seed to always provide + /// deterministic behavior. + /// + /// It is typically faster than stable sorting, except in a few special cases, e.g. when the + /// slice consists of several concatenated sorted sequences. + /// + /// # Examples + /// + /// ``` + /// let mut v = [5, 4, 1, 3, 2]; + /// v.sort_unstable_by(|a, b| a.cmp(b)); + /// assert!(v == [1, 2, 3, 4, 5]); + /// + /// // reverse sorting + /// v.sort_unstable_by(|a, b| b.cmp(a)); + /// assert!(v == [5, 4, 3, 2, 1]); + /// ``` + /// + /// [pdqsort]: https://github.com/orlp/pdqsort + #[stable(feature = "sort_unstable", since = "1.20.0")] + #[inline] + pub fn sort_unstable_by<F>(&mut self, compare: F) + where F: FnMut(&T, &T) -> Ordering + { + SliceExt::sort_unstable_by(self, compare); + } + + /// Sorts the slice with a key extraction function, but may not preserve the order of equal + /// elements. + /// + /// This sort is unstable (i.e. may reorder equal elements), in-place (i.e. does not allocate), + /// and `O(m n log(m n))` worst-case, where the key function is `O(m)`. + /// + /// # Current implementation + /// + /// The current algorithm is based on [pattern-defeating quicksort][pdqsort] by Orson Peters, + /// which combines the fast average case of randomized quicksort with the fast worst case of + /// heapsort, while achieving linear time on slices with certain patterns. It uses some + /// randomization to avoid degenerate cases, but with a fixed seed to always provide + /// deterministic behavior. + /// + /// # Examples + /// + /// ``` + /// let mut v = [-5i32, 4, 1, -3, 2]; + /// + /// v.sort_unstable_by_key(|k| k.abs()); + /// assert!(v == [1, 2, -3, 4, -5]); + /// ``` + /// + /// [pdqsort]: https://github.com/orlp/pdqsort + #[stable(feature = "sort_unstable", since = "1.20.0")] + #[inline] + pub fn sort_unstable_by_key<K, F>(&mut self, f: F) + where F: FnMut(&T) -> K, K: Ord + { + SliceExt::sort_unstable_by_key(self, f); + } + + /// Rotates the slice in-place such that the first `mid` elements of the + /// slice move to the end while the last `self.len() - mid` elements move to + /// the front. After calling `rotate_left`, the element previously at index + /// `mid` will become the first element in the slice. + /// + /// # Panics + /// + /// This function will panic if `mid` is greater than the length of the + /// slice. Note that `mid == self.len()` does _not_ panic and is a no-op + /// rotation. + /// + /// # Complexity + /// + /// Takes linear (in `self.len()`) time. + /// + /// # Examples + /// + /// ``` + /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f']; + /// a.rotate_left(2); + /// assert_eq!(a, ['c', 'd', 'e', 'f', 'a', 'b']); + /// ``` + /// + /// Rotating a subslice: + /// + /// ``` + /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f']; + /// a[1..5].rotate_left(1); + /// assert_eq!(a, ['a', 'c', 'd', 'e', 'b', 'f']); + /// ``` + #[stable(feature = "slice_rotate", since = "1.26.0")] + pub fn rotate_left(&mut self, mid: usize) { + SliceExt::rotate_left(self, mid); + } + + /// Rotates the slice in-place such that the first `self.len() - k` + /// elements of the slice move to the end while the last `k` elements move + /// to the front. After calling `rotate_right`, the element previously at + /// index `self.len() - k` will become the first element in the slice. + /// + /// # Panics + /// + /// This function will panic if `k` is greater than the length of the + /// slice. Note that `k == self.len()` does _not_ panic and is a no-op + /// rotation. + /// + /// # Complexity + /// + /// Takes linear (in `self.len()`) time. + /// + /// # Examples + /// + /// ``` + /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f']; + /// a.rotate_right(2); + /// assert_eq!(a, ['e', 'f', 'a', 'b', 'c', 'd']); + /// ``` + /// + /// Rotate a subslice: + /// + /// ``` + /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f']; + /// a[1..5].rotate_right(1); + /// assert_eq!(a, ['a', 'e', 'b', 'c', 'd', 'f']); + /// ``` + #[stable(feature = "slice_rotate", since = "1.26.0")] + pub fn rotate_right(&mut self, k: usize) { + SliceExt::rotate_right(self, k); + } + + /// Copies the elements from `src` into `self`. + /// + /// The length of `src` must be the same as `self`. + /// + /// If `src` implements `Copy`, it can be more performant to use + /// [`copy_from_slice`]. + /// + /// # Panics + /// + /// This function will panic if the two slices have different lengths. + /// + /// # Examples + /// + /// Cloning two elements from a slice into another: + /// + /// ``` + /// let src = [1, 2, 3, 4]; + /// let mut dst = [0, 0]; + /// + /// dst.clone_from_slice(&src[2..]); + /// + /// assert_eq!(src, [1, 2, 3, 4]); + /// assert_eq!(dst, [3, 4]); + /// ``` + /// + /// Rust enforces that there can only be one mutable reference with no + /// immutable references to a particular piece of data in a particular + /// scope. Because of this, attempting to use `clone_from_slice` on a + /// single slice will result in a compile failure: + /// + /// ```compile_fail + /// let mut slice = [1, 2, 3, 4, 5]; + /// + /// slice[..2].clone_from_slice(&slice[3..]); // compile fail! + /// ``` + /// + /// To work around this, we can use [`split_at_mut`] to create two distinct + /// sub-slices from a slice: + /// + /// ``` + /// let mut slice = [1, 2, 3, 4, 5]; + /// + /// { + /// let (left, right) = slice.split_at_mut(2); + /// left.clone_from_slice(&right[1..]); + /// } + /// + /// assert_eq!(slice, [4, 5, 3, 4, 5]); + /// ``` + /// + /// [`copy_from_slice`]: #method.copy_from_slice + /// [`split_at_mut`]: #method.split_at_mut + #[stable(feature = "clone_from_slice", since = "1.7.0")] + pub fn clone_from_slice(&mut self, src: &[T]) where T: Clone { + SliceExt::clone_from_slice(self, src) + } + + /// Copies all elements from `src` into `self`, using a memcpy. + /// + /// The length of `src` must be the same as `self`. + /// + /// If `src` does not implement `Copy`, use [`clone_from_slice`]. + /// + /// # Panics + /// + /// This function will panic if the two slices have different lengths. + /// + /// # Examples + /// + /// Copying two elements from a slice into another: + /// + /// ``` + /// let src = [1, 2, 3, 4]; + /// let mut dst = [0, 0]; + /// + /// dst.copy_from_slice(&src[2..]); + /// + /// assert_eq!(src, [1, 2, 3, 4]); + /// assert_eq!(dst, [3, 4]); + /// ``` + /// + /// Rust enforces that there can only be one mutable reference with no + /// immutable references to a particular piece of data in a particular + /// scope. Because of this, attempting to use `copy_from_slice` on a + /// single slice will result in a compile failure: + /// + /// ```compile_fail + /// let mut slice = [1, 2, 3, 4, 5]; + /// + /// slice[..2].copy_from_slice(&slice[3..]); // compile fail! + /// ``` + /// + /// To work around this, we can use [`split_at_mut`] to create two distinct + /// sub-slices from a slice: + /// + /// ``` + /// let mut slice = [1, 2, 3, 4, 5]; + /// + /// { + /// let (left, right) = slice.split_at_mut(2); + /// left.copy_from_slice(&right[1..]); + /// } + /// + /// assert_eq!(slice, [4, 5, 3, 4, 5]); + /// ``` + /// + /// [`clone_from_slice`]: #method.clone_from_slice + /// [`split_at_mut`]: #method.split_at_mut + #[stable(feature = "copy_from_slice", since = "1.9.0")] + pub fn copy_from_slice(&mut self, src: &[T]) where T: Copy { + SliceExt::copy_from_slice(self, src) + } + + /// Swaps all elements in `self` with those in `other`. + /// + /// The length of `other` must be the same as `self`. + /// + /// # Panics + /// + /// This function will panic if the two slices have different lengths. + /// + /// # Example + /// + /// Swapping two elements across slices: + /// + /// ``` + /// let mut slice1 = [0, 0]; + /// let mut slice2 = [1, 2, 3, 4]; + /// + /// slice1.swap_with_slice(&mut slice2[2..]); + /// + /// assert_eq!(slice1, [3, 4]); + /// assert_eq!(slice2, [1, 2, 0, 0]); + /// ``` + /// + /// Rust enforces that there can only be one mutable reference to a + /// particular piece of data in a particular scope. Because of this, + /// attempting to use `swap_with_slice` on a single slice will result in + /// a compile failure: + /// + /// ```compile_fail + /// let mut slice = [1, 2, 3, 4, 5]; + /// slice[..2].swap_with_slice(&mut slice[3..]); // compile fail! + /// ``` + /// + /// To work around this, we can use [`split_at_mut`] to create two distinct + /// mutable sub-slices from a slice: + /// + /// ``` + /// let mut slice = [1, 2, 3, 4, 5]; + /// + /// { + /// let (left, right) = slice.split_at_mut(2); + /// left.swap_with_slice(&mut right[1..]); + /// } + /// + /// assert_eq!(slice, [4, 5, 3, 1, 2]); + /// ``` + /// + /// [`split_at_mut`]: #method.split_at_mut + #[stable(feature = "swap_with_slice", since = "1.27.0")] + pub fn swap_with_slice(&mut self, other: &mut [T]) { + SliceExt::swap_with_slice(self, other) + } +}} + +#[lang = "slice"] +#[cfg(not(test))] +#[cfg(not(stage0))] +impl<T> [T] { + slice_core_methods!(); +} + +// FIXME: remove (inline) this macro +// when updating to a bootstrap compiler that has the new lang items. +#[cfg_attr(stage0, macro_export)] +#[unstable(feature = "core_slice_ext", issue = "32110")] +macro_rules! slice_u8_core_methods { () => { + /// Checks if all bytes in this slice are within the ASCII range. + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] + #[inline] + pub fn is_ascii(&self) -> bool { + self.iter().all(|b| b.is_ascii()) + } + + /// Checks that two slices are an ASCII case-insensitive match. + /// + /// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`, + /// but without allocating and copying temporaries. + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] + #[inline] + pub fn eq_ignore_ascii_case(&self, other: &[u8]) -> bool { + self.len() == other.len() && + self.iter().zip(other).all(|(a, b)| { + a.eq_ignore_ascii_case(b) + }) + } + + /// Converts this slice to its ASCII upper case equivalent in-place. + /// + /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', + /// but non-ASCII letters are unchanged. + /// + /// To return a new uppercased value without modifying the existing one, use + /// [`to_ascii_uppercase`]. + /// + /// [`to_ascii_uppercase`]: #method.to_ascii_uppercase + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] + #[inline] + pub fn make_ascii_uppercase(&mut self) { + for byte in self { + byte.make_ascii_uppercase(); + } + } + + /// Converts this slice to its ASCII lower case equivalent in-place. + /// + /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', + /// but non-ASCII letters are unchanged. + /// + /// To return a new lowercased value without modifying the existing one, use + /// [`to_ascii_lowercase`]. + /// + /// [`to_ascii_lowercase`]: #method.to_ascii_lowercase + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] + #[inline] + pub fn make_ascii_lowercase(&mut self) { + for byte in self { + byte.make_ascii_lowercase(); + } + } +}} + +#[lang = "slice_u8"] +#[cfg(not(test))] +#[cfg(not(stage0))] +impl [u8] { + slice_u8_core_methods!(); +} + #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented = "slice indices are of type `usize` or ranges of `usize`"] impl<T, I> ops::Index<I> for [T] @@ -1840,13 +3311,13 @@ impl<'a, T, P> FusedIterator for SplitMut<'a, T, P> where P: FnMut(&T) -> bool { /// /// [`rsplit`]: ../../std/primitive.slice.html#method.rsplit /// [slices]: ../../std/primitive.slice.html -#[unstable(feature = "slice_rsplit", issue = "41020")] +#[stable(feature = "slice_rsplit", since = "1.27.0")] #[derive(Clone)] // Is this correct, or does it incorrectly require `T: Clone`? pub struct RSplit<'a, T:'a, P> where P: FnMut(&T) -> bool { inner: Split<'a, T, P> } -#[unstable(feature = "slice_rsplit", issue = "41020")] +#[stable(feature = "slice_rsplit", since = "1.27.0")] impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for RSplit<'a, T, P> where P: FnMut(&T) -> bool { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("RSplit") @@ -1856,7 +3327,7 @@ impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for RSplit<'a, T, P> where P: FnMut(& } } -#[unstable(feature = "slice_rsplit", issue = "41020")] +#[stable(feature = "slice_rsplit", since = "1.27.0")] impl<'a, T, P> Iterator for RSplit<'a, T, P> where P: FnMut(&T) -> bool { type Item = &'a [T]; @@ -1871,7 +3342,7 @@ impl<'a, T, P> Iterator for RSplit<'a, T, P> where P: FnMut(&T) -> bool { } } -#[unstable(feature = "slice_rsplit", issue = "41020")] +#[stable(feature = "slice_rsplit", since = "1.27.0")] impl<'a, T, P> DoubleEndedIterator for RSplit<'a, T, P> where P: FnMut(&T) -> bool { #[inline] fn next_back(&mut self) -> Option<&'a [T]> { @@ -1879,7 +3350,7 @@ impl<'a, T, P> DoubleEndedIterator for RSplit<'a, T, P> where P: FnMut(&T) -> bo } } -#[unstable(feature = "slice_rsplit", issue = "41020")] +#[stable(feature = "slice_rsplit", since = "1.27.0")] impl<'a, T, P> SplitIter for RSplit<'a, T, P> where P: FnMut(&T) -> bool { #[inline] fn finish(&mut self) -> Option<&'a [T]> { @@ -1887,7 +3358,7 @@ impl<'a, T, P> SplitIter for RSplit<'a, T, P> where P: FnMut(&T) -> bool { } } -#[unstable(feature = "slice_rsplit", issue = "41020")] +#[stable(feature = "slice_rsplit", since = "1.27.0")] impl<'a, T, P> FusedIterator for RSplit<'a, T, P> where P: FnMut(&T) -> bool {} /// An iterator over the subslices of the vector which are separated @@ -1897,12 +3368,12 @@ impl<'a, T, P> FusedIterator for RSplit<'a, T, P> where P: FnMut(&T) -> bool {} /// /// [`rsplit_mut`]: ../../std/primitive.slice.html#method.rsplit_mut /// [slices]: ../../std/primitive.slice.html -#[unstable(feature = "slice_rsplit", issue = "41020")] +#[stable(feature = "slice_rsplit", since = "1.27.0")] pub struct RSplitMut<'a, T:'a, P> where P: FnMut(&T) -> bool { inner: SplitMut<'a, T, P> } -#[unstable(feature = "slice_rsplit", issue = "41020")] +#[stable(feature = "slice_rsplit", since = "1.27.0")] impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for RSplitMut<'a, T, P> where P: FnMut(&T) -> bool { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("RSplitMut") @@ -1912,7 +3383,7 @@ impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for RSplitMut<'a, T, P> where P: FnMu } } -#[unstable(feature = "slice_rsplit", issue = "41020")] +#[stable(feature = "slice_rsplit", since = "1.27.0")] impl<'a, T, P> SplitIter for RSplitMut<'a, T, P> where P: FnMut(&T) -> bool { #[inline] fn finish(&mut self) -> Option<&'a mut [T]> { @@ -1920,7 +3391,7 @@ impl<'a, T, P> SplitIter for RSplitMut<'a, T, P> where P: FnMut(&T) -> bool { } } -#[unstable(feature = "slice_rsplit", issue = "41020")] +#[stable(feature = "slice_rsplit", since = "1.27.0")] impl<'a, T, P> Iterator for RSplitMut<'a, T, P> where P: FnMut(&T) -> bool { type Item = &'a mut [T]; @@ -1935,7 +3406,7 @@ impl<'a, T, P> Iterator for RSplitMut<'a, T, P> where P: FnMut(&T) -> bool { } } -#[unstable(feature = "slice_rsplit", issue = "41020")] +#[stable(feature = "slice_rsplit", since = "1.27.0")] impl<'a, T, P> DoubleEndedIterator for RSplitMut<'a, T, P> where P: FnMut(&T) -> bool, { @@ -1945,7 +3416,7 @@ impl<'a, T, P> DoubleEndedIterator for RSplitMut<'a, T, P> where } } -#[unstable(feature = "slice_rsplit", issue = "41020")] +#[stable(feature = "slice_rsplit", since = "1.27.0")] impl<'a, T, P> FusedIterator for RSplitMut<'a, T, P> where P: FnMut(&T) -> bool {} /// An private iterator over subslices separated by elements that diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index f1fe23092de..b39d9feb35b 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -2100,31 +2100,28 @@ mod traits { fn index(self, slice: &str) -> &Self::Output { assert!(self.end != usize::max_value(), "attempted to index str up to maximum usize"); - let end = self.end + 1; - self.get(slice).unwrap_or_else(|| super::slice_error_fail(slice, 0, end)) + (..self.end+1).index(slice) } #[inline] fn index_mut(self, slice: &mut str) -> &mut Self::Output { assert!(self.end != usize::max_value(), "attempted to index str up to maximum usize"); - if slice.is_char_boundary(self.end) { - unsafe { self.get_unchecked_mut(slice) } - } else { - super::slice_error_fail(slice, 0, self.end + 1) - } + (..self.end+1).index_mut(slice) } } } - +public_in_stage0! { +{ /// Methods for string slices #[allow(missing_docs)] #[doc(hidden)] #[unstable(feature = "core_str_ext", reason = "stable interface provided by `impl str` in later crates", issue = "32110")] -pub trait StrExt { +} +trait StrExt { // NB there are no docs here are they're all located on the StrExt trait in // liballoc, not here. @@ -2218,17 +2215,13 @@ pub trait StrExt { fn parse<T: FromStr>(&self) -> Result<T, T::Err>; #[stable(feature = "split_whitespace", since = "1.1.0")] fn split_whitespace<'a>(&'a self) -> SplitWhitespace<'a>; - #[stable(feature = "unicode_methods_on_intrinsics", since = "1.27.0")] - fn is_whitespace(&self) -> bool; - #[stable(feature = "unicode_methods_on_intrinsics", since = "1.27.0")] - fn is_alphanumeric(&self) -> bool; #[stable(feature = "rust1", since = "1.0.0")] fn trim(&self) -> &str; #[stable(feature = "rust1", since = "1.0.0")] fn trim_left(&self) -> &str; #[stable(feature = "rust1", since = "1.0.0")] fn trim_right(&self) -> &str; -} +}} // truncate `&str` to length at most equal to `max` // return `true` if it were truncated, and the new str. @@ -2555,16 +2548,6 @@ impl StrExt for str { } #[inline] - fn is_whitespace(&self) -> bool { - self.chars().all(|c| c.is_whitespace()) - } - - #[inline] - fn is_alphanumeric(&self) -> bool { - self.chars().all(|c| c.is_alphanumeric()) - } - - #[inline] fn trim(&self) -> &str { self.trim_matches(|c: char| c.is_whitespace()) } @@ -2580,6 +2563,1685 @@ impl StrExt for str { } } +// FIXME: remove (inline) this macro and the SliceExt trait +// when updating to a bootstrap compiler that has the new lang items. +#[cfg_attr(stage0, macro_export)] +#[unstable(feature = "core_str_ext", issue = "32110")] +macro_rules! str_core_methods { () => { + /// Returns the length of `self`. + /// + /// This length is in bytes, not [`char`]s or graphemes. In other words, + /// it may not be what a human considers the length of the string. + /// + /// [`char`]: primitive.char.html + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let len = "foo".len(); + /// assert_eq!(3, len); + /// + /// let len = "ƒoo".len(); // fancy f! + /// assert_eq!(4, len); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn len(&self) -> usize { + StrExt::len(self) + } + + /// Returns `true` if `self` has a length of zero bytes. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let s = ""; + /// assert!(s.is_empty()); + /// + /// let s = "not empty"; + /// assert!(!s.is_empty()); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn is_empty(&self) -> bool { + StrExt::is_empty(self) + } + + /// Checks that `index`-th byte lies at the start and/or end of a + /// UTF-8 code point sequence. + /// + /// The start and end of the string (when `index == self.len()`) are + /// considered to be + /// boundaries. + /// + /// Returns `false` if `index` is greater than `self.len()`. + /// + /// # Examples + /// + /// ``` + /// let s = "Löwe 老虎 Léopard"; + /// assert!(s.is_char_boundary(0)); + /// // start of `老` + /// assert!(s.is_char_boundary(6)); + /// assert!(s.is_char_boundary(s.len())); + /// + /// // second byte of `ö` + /// assert!(!s.is_char_boundary(2)); + /// + /// // third byte of `老` + /// assert!(!s.is_char_boundary(8)); + /// ``` + #[stable(feature = "is_char_boundary", since = "1.9.0")] + #[inline] + pub fn is_char_boundary(&self, index: usize) -> bool { + StrExt::is_char_boundary(self, index) + } + + /// Converts a string slice to a byte slice. To convert the byte slice back + /// into a string slice, use the [`str::from_utf8`] function. + /// + /// [`str::from_utf8`]: ./str/fn.from_utf8.html + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let bytes = "bors".as_bytes(); + /// assert_eq!(b"bors", bytes); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline(always)] + pub fn as_bytes(&self) -> &[u8] { + StrExt::as_bytes(self) + } + + /// Converts a mutable string slice to a mutable byte slice. To convert the + /// mutable byte slice back into a mutable string slice, use the + /// [`str::from_utf8_mut`] function. + /// + /// [`str::from_utf8_mut`]: ./str/fn.from_utf8_mut.html + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let mut s = String::from("Hello"); + /// let bytes = unsafe { s.as_bytes_mut() }; + /// + /// assert_eq!(b"Hello", bytes); + /// ``` + /// + /// Mutability: + /// + /// ``` + /// let mut s = String::from("🗻∈🌏"); + /// + /// unsafe { + /// let bytes = s.as_bytes_mut(); + /// + /// bytes[0] = 0xF0; + /// bytes[1] = 0x9F; + /// bytes[2] = 0x8D; + /// bytes[3] = 0x94; + /// } + /// + /// assert_eq!("🍔∈🌏", s); + /// ``` + #[stable(feature = "str_mut_extras", since = "1.20.0")] + #[inline(always)] + pub unsafe fn as_bytes_mut(&mut self) -> &mut [u8] { + StrExt::as_bytes_mut(self) + } + + /// Converts a string slice to a raw pointer. + /// + /// As string slices are a slice of bytes, the raw pointer points to a + /// [`u8`]. This pointer will be pointing to the first byte of the string + /// slice. + /// + /// [`u8`]: primitive.u8.html + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let s = "Hello"; + /// let ptr = s.as_ptr(); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn as_ptr(&self) -> *const u8 { + StrExt::as_ptr(self) + } + + /// Returns a subslice of `str`. + /// + /// This is the non-panicking alternative to indexing the `str`. Returns + /// [`None`] whenever equivalent indexing operation would panic. + /// + /// [`None`]: option/enum.Option.html#variant.None + /// + /// # Examples + /// + /// ``` + /// let v = String::from("🗻∈🌏"); + /// + /// assert_eq!(Some("🗻"), v.get(0..4)); + /// + /// // indices not on UTF-8 sequence boundaries + /// assert!(v.get(1..).is_none()); + /// assert!(v.get(..8).is_none()); + /// + /// // out of bounds + /// assert!(v.get(..42).is_none()); + /// ``` + #[stable(feature = "str_checked_slicing", since = "1.20.0")] + #[inline] + pub fn get<I: SliceIndex<str>>(&self, i: I) -> Option<&I::Output> { + StrExt::get(self, i) + } + + /// Returns a mutable subslice of `str`. + /// + /// This is the non-panicking alternative to indexing the `str`. Returns + /// [`None`] whenever equivalent indexing operation would panic. + /// + /// [`None`]: option/enum.Option.html#variant.None + /// + /// # Examples + /// + /// ``` + /// let mut v = String::from("hello"); + /// // correct length + /// assert!(v.get_mut(0..5).is_some()); + /// // out of bounds + /// assert!(v.get_mut(..42).is_none()); + /// assert_eq!(Some("he"), v.get_mut(0..2).map(|v| &*v)); + /// + /// assert_eq!("hello", v); + /// { + /// let s = v.get_mut(0..2); + /// let s = s.map(|s| { + /// s.make_ascii_uppercase(); + /// &*s + /// }); + /// assert_eq!(Some("HE"), s); + /// } + /// assert_eq!("HEllo", v); + /// ``` + #[stable(feature = "str_checked_slicing", since = "1.20.0")] + #[inline] + pub fn get_mut<I: SliceIndex<str>>(&mut self, i: I) -> Option<&mut I::Output> { + StrExt::get_mut(self, i) + } + + /// Returns a unchecked subslice of `str`. + /// + /// This is the unchecked alternative to indexing the `str`. + /// + /// # Safety + /// + /// Callers of this function are responsible that these preconditions are + /// satisfied: + /// + /// * The starting index must come before the ending index; + /// * Indexes must be within bounds of the original slice; + /// * Indexes must lie on UTF-8 sequence boundaries. + /// + /// Failing that, the returned string slice may reference invalid memory or + /// violate the invariants communicated by the `str` type. + /// + /// # Examples + /// + /// ``` + /// let v = "🗻∈🌏"; + /// unsafe { + /// assert_eq!("🗻", v.get_unchecked(0..4)); + /// assert_eq!("∈", v.get_unchecked(4..7)); + /// assert_eq!("🌏", v.get_unchecked(7..11)); + /// } + /// ``` + #[stable(feature = "str_checked_slicing", since = "1.20.0")] + #[inline] + pub unsafe fn get_unchecked<I: SliceIndex<str>>(&self, i: I) -> &I::Output { + StrExt::get_unchecked(self, i) + } + + /// Returns a mutable, unchecked subslice of `str`. + /// + /// This is the unchecked alternative to indexing the `str`. + /// + /// # Safety + /// + /// Callers of this function are responsible that these preconditions are + /// satisfied: + /// + /// * The starting index must come before the ending index; + /// * Indexes must be within bounds of the original slice; + /// * Indexes must lie on UTF-8 sequence boundaries. + /// + /// Failing that, the returned string slice may reference invalid memory or + /// violate the invariants communicated by the `str` type. + /// + /// # Examples + /// + /// ``` + /// let mut v = String::from("🗻∈🌏"); + /// unsafe { + /// assert_eq!("🗻", v.get_unchecked_mut(0..4)); + /// assert_eq!("∈", v.get_unchecked_mut(4..7)); + /// assert_eq!("🌏", v.get_unchecked_mut(7..11)); + /// } + /// ``` + #[stable(feature = "str_checked_slicing", since = "1.20.0")] + #[inline] + pub unsafe fn get_unchecked_mut<I: SliceIndex<str>>(&mut self, i: I) -> &mut I::Output { + StrExt::get_unchecked_mut(self, i) + } + + /// Creates a string slice from another string slice, bypassing safety + /// checks. + /// + /// This is generally not recommended, use with caution! For a safe + /// alternative see [`str`] and [`Index`]. + /// + /// [`str`]: primitive.str.html + /// [`Index`]: ops/trait.Index.html + /// + /// This new slice goes from `begin` to `end`, including `begin` but + /// excluding `end`. + /// + /// To get a mutable string slice instead, see the + /// [`slice_mut_unchecked`] method. + /// + /// [`slice_mut_unchecked`]: #method.slice_mut_unchecked + /// + /// # Safety + /// + /// Callers of this function are responsible that three preconditions are + /// satisfied: + /// + /// * `begin` must come before `end`. + /// * `begin` and `end` must be byte positions within the string slice. + /// * `begin` and `end` must lie on UTF-8 sequence boundaries. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let s = "Löwe 老虎 Léopard"; + /// + /// unsafe { + /// assert_eq!("Löwe 老虎 Léopard", s.slice_unchecked(0, 21)); + /// } + /// + /// let s = "Hello, world!"; + /// + /// unsafe { + /// assert_eq!("world", s.slice_unchecked(7, 12)); + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str { + StrExt::slice_unchecked(self, begin, end) + } + + /// Creates a string slice from another string slice, bypassing safety + /// checks. + /// This is generally not recommended, use with caution! For a safe + /// alternative see [`str`] and [`IndexMut`]. + /// + /// [`str`]: primitive.str.html + /// [`IndexMut`]: ops/trait.IndexMut.html + /// + /// This new slice goes from `begin` to `end`, including `begin` but + /// excluding `end`. + /// + /// To get an immutable string slice instead, see the + /// [`slice_unchecked`] method. + /// + /// [`slice_unchecked`]: #method.slice_unchecked + /// + /// # Safety + /// + /// Callers of this function are responsible that three preconditions are + /// satisfied: + /// + /// * `begin` must come before `end`. + /// * `begin` and `end` must be byte positions within the string slice. + /// * `begin` and `end` must lie on UTF-8 sequence boundaries. + #[stable(feature = "str_slice_mut", since = "1.5.0")] + #[inline] + pub unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut str { + StrExt::slice_mut_unchecked(self, begin, end) + } + + /// Divide one string slice into two at an index. + /// + /// The argument, `mid`, should be a byte offset from the start of the + /// string. It must also be on the boundary of a UTF-8 code point. + /// + /// The two slices returned go from the start of the string slice to `mid`, + /// and from `mid` to the end of the string slice. + /// + /// To get mutable string slices instead, see the [`split_at_mut`] + /// method. + /// + /// [`split_at_mut`]: #method.split_at_mut + /// + /// # Panics + /// + /// Panics if `mid` is not on a UTF-8 code point boundary, or if it is + /// beyond the last code point of the string slice. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let s = "Per Martin-Löf"; + /// + /// let (first, last) = s.split_at(3); + /// + /// assert_eq!("Per", first); + /// assert_eq!(" Martin-Löf", last); + /// ``` + #[inline] + #[stable(feature = "str_split_at", since = "1.4.0")] + pub fn split_at(&self, mid: usize) -> (&str, &str) { + StrExt::split_at(self, mid) + } + + /// Divide one mutable string slice into two at an index. + /// + /// The argument, `mid`, should be a byte offset from the start of the + /// string. It must also be on the boundary of a UTF-8 code point. + /// + /// The two slices returned go from the start of the string slice to `mid`, + /// and from `mid` to the end of the string slice. + /// + /// To get immutable string slices instead, see the [`split_at`] method. + /// + /// [`split_at`]: #method.split_at + /// + /// # Panics + /// + /// Panics if `mid` is not on a UTF-8 code point boundary, or if it is + /// beyond the last code point of the string slice. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let mut s = "Per Martin-Löf".to_string(); + /// { + /// let (first, last) = s.split_at_mut(3); + /// first.make_ascii_uppercase(); + /// assert_eq!("PER", first); + /// assert_eq!(" Martin-Löf", last); + /// } + /// assert_eq!("PER Martin-Löf", s); + /// ``` + #[inline] + #[stable(feature = "str_split_at", since = "1.4.0")] + pub fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str) { + StrExt::split_at_mut(self, mid) + } + + /// Returns an iterator over the [`char`]s of a string slice. + /// + /// As a string slice consists of valid UTF-8, we can iterate through a + /// string slice by [`char`]. This method returns such an iterator. + /// + /// It's important to remember that [`char`] represents a Unicode Scalar + /// Value, and may not match your idea of what a 'character' is. Iteration + /// over grapheme clusters may be what you actually want. + /// + /// [`char`]: primitive.char.html + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let word = "goodbye"; + /// + /// let count = word.chars().count(); + /// assert_eq!(7, count); + /// + /// let mut chars = word.chars(); + /// + /// assert_eq!(Some('g'), chars.next()); + /// assert_eq!(Some('o'), chars.next()); + /// assert_eq!(Some('o'), chars.next()); + /// assert_eq!(Some('d'), chars.next()); + /// assert_eq!(Some('b'), chars.next()); + /// assert_eq!(Some('y'), chars.next()); + /// assert_eq!(Some('e'), chars.next()); + /// + /// assert_eq!(None, chars.next()); + /// ``` + /// + /// Remember, [`char`]s may not match your human intuition about characters: + /// + /// ``` + /// let y = "y̆"; + /// + /// let mut chars = y.chars(); + /// + /// assert_eq!(Some('y'), chars.next()); // not 'y̆' + /// assert_eq!(Some('\u{0306}'), chars.next()); + /// + /// assert_eq!(None, chars.next()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn chars(&self) -> Chars { + StrExt::chars(self) + } + /// Returns an iterator over the [`char`]s of a string slice, and their + /// positions. + /// + /// As a string slice consists of valid UTF-8, we can iterate through a + /// string slice by [`char`]. This method returns an iterator of both + /// these [`char`]s, as well as their byte positions. + /// + /// The iterator yields tuples. The position is first, the [`char`] is + /// second. + /// + /// [`char`]: primitive.char.html + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let word = "goodbye"; + /// + /// let count = word.char_indices().count(); + /// assert_eq!(7, count); + /// + /// let mut char_indices = word.char_indices(); + /// + /// assert_eq!(Some((0, 'g')), char_indices.next()); + /// assert_eq!(Some((1, 'o')), char_indices.next()); + /// assert_eq!(Some((2, 'o')), char_indices.next()); + /// assert_eq!(Some((3, 'd')), char_indices.next()); + /// assert_eq!(Some((4, 'b')), char_indices.next()); + /// assert_eq!(Some((5, 'y')), char_indices.next()); + /// assert_eq!(Some((6, 'e')), char_indices.next()); + /// + /// assert_eq!(None, char_indices.next()); + /// ``` + /// + /// Remember, [`char`]s may not match your human intuition about characters: + /// + /// ``` + /// let yes = "y̆es"; + /// + /// let mut char_indices = yes.char_indices(); + /// + /// assert_eq!(Some((0, 'y')), char_indices.next()); // not (0, 'y̆') + /// assert_eq!(Some((1, '\u{0306}')), char_indices.next()); + /// + /// // note the 3 here - the last character took up two bytes + /// assert_eq!(Some((3, 'e')), char_indices.next()); + /// assert_eq!(Some((4, 's')), char_indices.next()); + /// + /// assert_eq!(None, char_indices.next()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn char_indices(&self) -> CharIndices { + StrExt::char_indices(self) + } + + /// An iterator over the bytes of a string slice. + /// + /// As a string slice consists of a sequence of bytes, we can iterate + /// through a string slice by byte. This method returns such an iterator. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let mut bytes = "bors".bytes(); + /// + /// assert_eq!(Some(b'b'), bytes.next()); + /// assert_eq!(Some(b'o'), bytes.next()); + /// assert_eq!(Some(b'r'), bytes.next()); + /// assert_eq!(Some(b's'), bytes.next()); + /// + /// assert_eq!(None, bytes.next()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn bytes(&self) -> Bytes { + StrExt::bytes(self) + } + + /// Split a string slice by whitespace. + /// + /// The iterator returned will return string slices that are sub-slices of + /// the original string slice, separated by any amount of whitespace. + /// + /// 'Whitespace' is defined according to the terms of the Unicode Derived + /// Core Property `White_Space`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let mut iter = "A few words".split_whitespace(); + /// + /// assert_eq!(Some("A"), iter.next()); + /// assert_eq!(Some("few"), iter.next()); + /// assert_eq!(Some("words"), iter.next()); + /// + /// assert_eq!(None, iter.next()); + /// ``` + /// + /// All kinds of whitespace are considered: + /// + /// ``` + /// let mut iter = " Mary had\ta\u{2009}little \n\t lamb".split_whitespace(); + /// assert_eq!(Some("Mary"), iter.next()); + /// assert_eq!(Some("had"), iter.next()); + /// assert_eq!(Some("a"), iter.next()); + /// assert_eq!(Some("little"), iter.next()); + /// assert_eq!(Some("lamb"), iter.next()); + /// + /// assert_eq!(None, iter.next()); + /// ``` + #[stable(feature = "split_whitespace", since = "1.1.0")] + #[inline] + pub fn split_whitespace(&self) -> SplitWhitespace { + StrExt::split_whitespace(self) + } + + /// An iterator over the lines of a string, as string slices. + /// + /// Lines are ended with either a newline (`\n`) or a carriage return with + /// a line feed (`\r\n`). + /// + /// The final line ending is optional. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let text = "foo\r\nbar\n\nbaz\n"; + /// let mut lines = text.lines(); + /// + /// assert_eq!(Some("foo"), lines.next()); + /// assert_eq!(Some("bar"), lines.next()); + /// assert_eq!(Some(""), lines.next()); + /// assert_eq!(Some("baz"), lines.next()); + /// + /// assert_eq!(None, lines.next()); + /// ``` + /// + /// The final line ending isn't required: + /// + /// ``` + /// let text = "foo\nbar\n\r\nbaz"; + /// let mut lines = text.lines(); + /// + /// assert_eq!(Some("foo"), lines.next()); + /// assert_eq!(Some("bar"), lines.next()); + /// assert_eq!(Some(""), lines.next()); + /// assert_eq!(Some("baz"), lines.next()); + /// + /// assert_eq!(None, lines.next()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn lines(&self) -> Lines { + StrExt::lines(self) + } + + /// An iterator over the lines of a string. + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_deprecated(since = "1.4.0", reason = "use lines() instead now")] + #[inline] + #[allow(deprecated)] + pub fn lines_any(&self) -> LinesAny { + StrExt::lines_any(self) + } + + /// Returns an iterator of `u16` over the string encoded as UTF-16. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let text = "Zażółć gęślą jaźń"; + /// + /// let utf8_len = text.len(); + /// let utf16_len = text.encode_utf16().count(); + /// + /// assert!(utf16_len <= utf8_len); + /// ``` + #[stable(feature = "encode_utf16", since = "1.8.0")] + pub fn encode_utf16(&self) -> EncodeUtf16 { + EncodeUtf16::new(self) + } + + /// Returns `true` if the given pattern matches a sub-slice of + /// this string slice. + /// + /// Returns `false` if it does not. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let bananas = "bananas"; + /// + /// assert!(bananas.contains("nana")); + /// assert!(!bananas.contains("apples")); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn contains<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool { + StrExt::contains(self, pat) + } + + /// Returns `true` if the given pattern matches a prefix of this + /// string slice. + /// + /// Returns `false` if it does not. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let bananas = "bananas"; + /// + /// assert!(bananas.starts_with("bana")); + /// assert!(!bananas.starts_with("nana")); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn starts_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool { + StrExt::starts_with(self, pat) + } + + /// Returns `true` if the given pattern matches a suffix of this + /// string slice. + /// + /// Returns `false` if it does not. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let bananas = "bananas"; + /// + /// assert!(bananas.ends_with("anas")); + /// assert!(!bananas.ends_with("nana")); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn ends_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool + where P::Searcher: ReverseSearcher<'a> + { + StrExt::ends_with(self, pat) + } + + /// Returns the byte index of the first character of this string slice that + /// matches the pattern. + /// + /// Returns [`None`] if the pattern doesn't match. + /// + /// The pattern can be a `&str`, [`char`], or a closure that determines if + /// a character matches. + /// + /// [`char`]: primitive.char.html + /// [`None`]: option/enum.Option.html#variant.None + /// + /// # Examples + /// + /// Simple patterns: + /// + /// ``` + /// let s = "Löwe 老虎 Léopard"; + /// + /// assert_eq!(s.find('L'), Some(0)); + /// assert_eq!(s.find('é'), Some(14)); + /// assert_eq!(s.find("Léopard"), Some(13)); + /// ``` + /// + /// More complex patterns using point-free style and closures: + /// + /// ``` + /// let s = "Löwe 老虎 Léopard"; + /// + /// assert_eq!(s.find(char::is_whitespace), Some(5)); + /// assert_eq!(s.find(char::is_lowercase), Some(1)); + /// assert_eq!(s.find(|c: char| c.is_whitespace() || c.is_lowercase()), Some(1)); + /// assert_eq!(s.find(|c: char| (c < 'o') && (c > 'a')), Some(4)); + /// ``` + /// + /// Not finding the pattern: + /// + /// ``` + /// let s = "Löwe 老虎 Léopard"; + /// let x: &[_] = &['1', '2']; + /// + /// assert_eq!(s.find(x), None); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize> { + StrExt::find(self, pat) + } + + /// Returns the byte index of the last character of this string slice that + /// matches the pattern. + /// + /// Returns [`None`] if the pattern doesn't match. + /// + /// The pattern can be a `&str`, [`char`], or a closure that determines if + /// a character matches. + /// + /// [`char`]: primitive.char.html + /// [`None`]: option/enum.Option.html#variant.None + /// + /// # Examples + /// + /// Simple patterns: + /// + /// ``` + /// let s = "Löwe 老虎 Léopard"; + /// + /// assert_eq!(s.rfind('L'), Some(13)); + /// assert_eq!(s.rfind('é'), Some(14)); + /// ``` + /// + /// More complex patterns with closures: + /// + /// ``` + /// let s = "Löwe 老虎 Léopard"; + /// + /// assert_eq!(s.rfind(char::is_whitespace), Some(12)); + /// assert_eq!(s.rfind(char::is_lowercase), Some(20)); + /// ``` + /// + /// Not finding the pattern: + /// + /// ``` + /// let s = "Löwe 老虎 Léopard"; + /// let x: &[_] = &['1', '2']; + /// + /// assert_eq!(s.rfind(x), None); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn rfind<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize> + where P::Searcher: ReverseSearcher<'a> + { + StrExt::rfind(self, pat) + } + + /// An iterator over substrings of this string slice, separated by + /// characters matched by a pattern. + /// + /// The pattern can be a `&str`, [`char`], or a closure that determines the + /// split. + /// + /// # Iterator behavior + /// + /// The returned iterator will be a [`DoubleEndedIterator`] if the pattern + /// allows a reverse search and forward/reverse search yields the same + /// elements. This is true for, eg, [`char`] but not for `&str`. + /// + /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html + /// + /// If the pattern allows a reverse search but its results might differ + /// from a forward search, the [`rsplit`] method can be used. + /// + /// [`char`]: primitive.char.html + /// [`rsplit`]: #method.rsplit + /// + /// # Examples + /// + /// Simple patterns: + /// + /// ``` + /// let v: Vec<&str> = "Mary had a little lamb".split(' ').collect(); + /// assert_eq!(v, ["Mary", "had", "a", "little", "lamb"]); + /// + /// let v: Vec<&str> = "".split('X').collect(); + /// assert_eq!(v, [""]); + /// + /// let v: Vec<&str> = "lionXXtigerXleopard".split('X').collect(); + /// assert_eq!(v, ["lion", "", "tiger", "leopard"]); + /// + /// let v: Vec<&str> = "lion::tiger::leopard".split("::").collect(); + /// assert_eq!(v, ["lion", "tiger", "leopard"]); + /// + /// let v: Vec<&str> = "abc1def2ghi".split(char::is_numeric).collect(); + /// assert_eq!(v, ["abc", "def", "ghi"]); + /// + /// let v: Vec<&str> = "lionXtigerXleopard".split(char::is_uppercase).collect(); + /// assert_eq!(v, ["lion", "tiger", "leopard"]); + /// ``` + /// + /// A more complex pattern, using a closure: + /// + /// ``` + /// let v: Vec<&str> = "abc1defXghi".split(|c| c == '1' || c == 'X').collect(); + /// assert_eq!(v, ["abc", "def", "ghi"]); + /// ``` + /// + /// If a string contains multiple contiguous separators, you will end up + /// with empty strings in the output: + /// + /// ``` + /// let x = "||||a||b|c".to_string(); + /// let d: Vec<_> = x.split('|').collect(); + /// + /// assert_eq!(d, &["", "", "", "", "a", "", "b", "c"]); + /// ``` + /// + /// Contiguous separators are separated by the empty string. + /// + /// ``` + /// let x = "(///)".to_string(); + /// let d: Vec<_> = x.split('/').collect(); + /// + /// assert_eq!(d, &["(", "", "", ")"]); + /// ``` + /// + /// Separators at the start or end of a string are neighbored + /// by empty strings. + /// + /// ``` + /// let d: Vec<_> = "010".split("0").collect(); + /// assert_eq!(d, &["", "1", ""]); + /// ``` + /// + /// When the empty string is used as a separator, it separates + /// every character in the string, along with the beginning + /// and end of the string. + /// + /// ``` + /// let f: Vec<_> = "rust".split("").collect(); + /// assert_eq!(f, &["", "r", "u", "s", "t", ""]); + /// ``` + /// + /// Contiguous separators can lead to possibly surprising behavior + /// when whitespace is used as the separator. This code is correct: + /// + /// ``` + /// let x = " a b c".to_string(); + /// let d: Vec<_> = x.split(' ').collect(); + /// + /// assert_eq!(d, &["", "", "", "", "a", "", "b", "c"]); + /// ``` + /// + /// It does _not_ give you: + /// + /// ```,ignore + /// assert_eq!(d, &["a", "b", "c"]); + /// ``` + /// + /// Use [`split_whitespace`] for this behavior. + /// + /// [`split_whitespace`]: #method.split_whitespace + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P> { + StrExt::split(self, pat) + } + + /// An iterator over substrings of the given string slice, separated by + /// characters matched by a pattern and yielded in reverse order. + /// + /// The pattern can be a `&str`, [`char`], or a closure that determines the + /// split. + /// + /// [`char`]: primitive.char.html + /// + /// # Iterator behavior + /// + /// The returned iterator requires that the pattern supports a reverse + /// search, and it will be a [`DoubleEndedIterator`] if a forward/reverse + /// search yields the same elements. + /// + /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html + /// + /// For iterating from the front, the [`split`] method can be used. + /// + /// [`split`]: #method.split + /// + /// # Examples + /// + /// Simple patterns: + /// + /// ``` + /// let v: Vec<&str> = "Mary had a little lamb".rsplit(' ').collect(); + /// assert_eq!(v, ["lamb", "little", "a", "had", "Mary"]); + /// + /// let v: Vec<&str> = "".rsplit('X').collect(); + /// assert_eq!(v, [""]); + /// + /// let v: Vec<&str> = "lionXXtigerXleopard".rsplit('X').collect(); + /// assert_eq!(v, ["leopard", "tiger", "", "lion"]); + /// + /// let v: Vec<&str> = "lion::tiger::leopard".rsplit("::").collect(); + /// assert_eq!(v, ["leopard", "tiger", "lion"]); + /// ``` + /// + /// A more complex pattern, using a closure: + /// + /// ``` + /// let v: Vec<&str> = "abc1defXghi".rsplit(|c| c == '1' || c == 'X').collect(); + /// assert_eq!(v, ["ghi", "def", "abc"]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn rsplit<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplit<'a, P> + where P::Searcher: ReverseSearcher<'a> + { + StrExt::rsplit(self, pat) + } + + /// An iterator over substrings of the given string slice, separated by + /// characters matched by a pattern. + /// + /// The pattern can be a `&str`, [`char`], or a closure that determines the + /// split. + /// + /// Equivalent to [`split`], except that the trailing substring + /// is skipped if empty. + /// + /// [`split`]: #method.split + /// + /// This method can be used for string data that is _terminated_, + /// rather than _separated_ by a pattern. + /// + /// # Iterator behavior + /// + /// The returned iterator will be a [`DoubleEndedIterator`] if the pattern + /// allows a reverse search and forward/reverse search yields the same + /// elements. This is true for, eg, [`char`] but not for `&str`. + /// + /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html + /// [`char`]: primitive.char.html + /// + /// If the pattern allows a reverse search but its results might differ + /// from a forward search, the [`rsplit_terminator`] method can be used. + /// + /// [`rsplit_terminator`]: #method.rsplit_terminator + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let v: Vec<&str> = "A.B.".split_terminator('.').collect(); + /// assert_eq!(v, ["A", "B"]); + /// + /// let v: Vec<&str> = "A..B..".split_terminator(".").collect(); + /// assert_eq!(v, ["A", "", "B", ""]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn split_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitTerminator<'a, P> { + StrExt::split_terminator(self, pat) + } + + /// An iterator over substrings of `self`, separated by characters + /// matched by a pattern and yielded in reverse order. + /// + /// The pattern can be a simple `&str`, [`char`], or a closure that + /// determines the split. + /// Additional libraries might provide more complex patterns like + /// regular expressions. + /// + /// [`char`]: primitive.char.html + /// + /// Equivalent to [`split`], except that the trailing substring is + /// skipped if empty. + /// + /// [`split`]: #method.split + /// + /// This method can be used for string data that is _terminated_, + /// rather than _separated_ by a pattern. + /// + /// # Iterator behavior + /// + /// The returned iterator requires that the pattern supports a + /// reverse search, and it will be double ended if a forward/reverse + /// search yields the same elements. + /// + /// For iterating from the front, the [`split_terminator`] method can be + /// used. + /// + /// [`split_terminator`]: #method.split_terminator + /// + /// # Examples + /// + /// ``` + /// let v: Vec<&str> = "A.B.".rsplit_terminator('.').collect(); + /// assert_eq!(v, ["B", "A"]); + /// + /// let v: Vec<&str> = "A..B..".rsplit_terminator(".").collect(); + /// assert_eq!(v, ["", "B", "", "A"]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn rsplit_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplitTerminator<'a, P> + where P::Searcher: ReverseSearcher<'a> + { + StrExt::rsplit_terminator(self, pat) + } + + /// An iterator over substrings of the given string slice, separated by a + /// pattern, restricted to returning at most `n` items. + /// + /// If `n` substrings are returned, the last substring (the `n`th substring) + /// will contain the remainder of the string. + /// + /// The pattern can be a `&str`, [`char`], or a closure that determines the + /// split. + /// + /// [`char`]: primitive.char.html + /// + /// # Iterator behavior + /// + /// The returned iterator will not be double ended, because it is + /// not efficient to support. + /// + /// If the pattern allows a reverse search, the [`rsplitn`] method can be + /// used. + /// + /// [`rsplitn`]: #method.rsplitn + /// + /// # Examples + /// + /// Simple patterns: + /// + /// ``` + /// let v: Vec<&str> = "Mary had a little lambda".splitn(3, ' ').collect(); + /// assert_eq!(v, ["Mary", "had", "a little lambda"]); + /// + /// let v: Vec<&str> = "lionXXtigerXleopard".splitn(3, "X").collect(); + /// assert_eq!(v, ["lion", "", "tigerXleopard"]); + /// + /// let v: Vec<&str> = "abcXdef".splitn(1, 'X').collect(); + /// assert_eq!(v, ["abcXdef"]); + /// + /// let v: Vec<&str> = "".splitn(1, 'X').collect(); + /// assert_eq!(v, [""]); + /// ``` + /// + /// A more complex pattern, using a closure: + /// + /// ``` + /// let v: Vec<&str> = "abc1defXghi".splitn(2, |c| c == '1' || c == 'X').collect(); + /// assert_eq!(v, ["abc", "defXghi"]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn splitn<'a, P: Pattern<'a>>(&'a self, n: usize, pat: P) -> SplitN<'a, P> { + StrExt::splitn(self, n, pat) + } + + /// An iterator over substrings of this string slice, separated by a + /// pattern, starting from the end of the string, restricted to returning + /// at most `n` items. + /// + /// If `n` substrings are returned, the last substring (the `n`th substring) + /// will contain the remainder of the string. + /// + /// The pattern can be a `&str`, [`char`], or a closure that + /// determines the split. + /// + /// [`char`]: primitive.char.html + /// + /// # Iterator behavior + /// + /// The returned iterator will not be double ended, because it is not + /// efficient to support. + /// + /// For splitting from the front, the [`splitn`] method can be used. + /// + /// [`splitn`]: #method.splitn + /// + /// # Examples + /// + /// Simple patterns: + /// + /// ``` + /// let v: Vec<&str> = "Mary had a little lamb".rsplitn(3, ' ').collect(); + /// assert_eq!(v, ["lamb", "little", "Mary had a"]); + /// + /// let v: Vec<&str> = "lionXXtigerXleopard".rsplitn(3, 'X').collect(); + /// assert_eq!(v, ["leopard", "tiger", "lionX"]); + /// + /// let v: Vec<&str> = "lion::tiger::leopard".rsplitn(2, "::").collect(); + /// assert_eq!(v, ["leopard", "lion::tiger"]); + /// ``` + /// + /// A more complex pattern, using a closure: + /// + /// ``` + /// let v: Vec<&str> = "abc1defXghi".rsplitn(2, |c| c == '1' || c == 'X').collect(); + /// assert_eq!(v, ["ghi", "abc1def"]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn rsplitn<'a, P: Pattern<'a>>(&'a self, n: usize, pat: P) -> RSplitN<'a, P> + where P::Searcher: ReverseSearcher<'a> + { + StrExt::rsplitn(self, n, pat) + } + + /// An iterator over the disjoint matches of a pattern within the given string + /// slice. + /// + /// The pattern can be a `&str`, [`char`], or a closure that + /// determines if a character matches. + /// + /// [`char`]: primitive.char.html + /// + /// # Iterator behavior + /// + /// The returned iterator will be a [`DoubleEndedIterator`] if the pattern + /// allows a reverse search and forward/reverse search yields the same + /// elements. This is true for, eg, [`char`] but not for `&str`. + /// + /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html + /// [`char`]: primitive.char.html + /// + /// If the pattern allows a reverse search but its results might differ + /// from a forward search, the [`rmatches`] method can be used. + /// + /// [`rmatches`]: #method.rmatches + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let v: Vec<&str> = "abcXXXabcYYYabc".matches("abc").collect(); + /// assert_eq!(v, ["abc", "abc", "abc"]); + /// + /// let v: Vec<&str> = "1abc2abc3".matches(char::is_numeric).collect(); + /// assert_eq!(v, ["1", "2", "3"]); + /// ``` + #[stable(feature = "str_matches", since = "1.2.0")] + #[inline] + pub fn matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> Matches<'a, P> { + StrExt::matches(self, pat) + } + + /// An iterator over the disjoint matches of a pattern within this string slice, + /// yielded in reverse order. + /// + /// The pattern can be a `&str`, [`char`], or a closure that determines if + /// a character matches. + /// + /// [`char`]: primitive.char.html + /// + /// # Iterator behavior + /// + /// The returned iterator requires that the pattern supports a reverse + /// search, and it will be a [`DoubleEndedIterator`] if a forward/reverse + /// search yields the same elements. + /// + /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html + /// + /// For iterating from the front, the [`matches`] method can be used. + /// + /// [`matches`]: #method.matches + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let v: Vec<&str> = "abcXXXabcYYYabc".rmatches("abc").collect(); + /// assert_eq!(v, ["abc", "abc", "abc"]); + /// + /// let v: Vec<&str> = "1abc2abc3".rmatches(char::is_numeric).collect(); + /// assert_eq!(v, ["3", "2", "1"]); + /// ``` + #[stable(feature = "str_matches", since = "1.2.0")] + #[inline] + pub fn rmatches<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatches<'a, P> + where P::Searcher: ReverseSearcher<'a> + { + StrExt::rmatches(self, pat) + } + + /// An iterator over the disjoint matches of a pattern within this string + /// slice as well as the index that the match starts at. + /// + /// For matches of `pat` within `self` that overlap, only the indices + /// corresponding to the first match are returned. + /// + /// The pattern can be a `&str`, [`char`], or a closure that determines + /// if a character matches. + /// + /// [`char`]: primitive.char.html + /// + /// # Iterator behavior + /// + /// The returned iterator will be a [`DoubleEndedIterator`] if the pattern + /// allows a reverse search and forward/reverse search yields the same + /// elements. This is true for, eg, [`char`] but not for `&str`. + /// + /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html + /// + /// If the pattern allows a reverse search but its results might differ + /// from a forward search, the [`rmatch_indices`] method can be used. + /// + /// [`rmatch_indices`]: #method.rmatch_indices + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let v: Vec<_> = "abcXXXabcYYYabc".match_indices("abc").collect(); + /// assert_eq!(v, [(0, "abc"), (6, "abc"), (12, "abc")]); + /// + /// let v: Vec<_> = "1abcabc2".match_indices("abc").collect(); + /// assert_eq!(v, [(1, "abc"), (4, "abc")]); + /// + /// let v: Vec<_> = "ababa".match_indices("aba").collect(); + /// assert_eq!(v, [(0, "aba")]); // only the first `aba` + /// ``` + #[stable(feature = "str_match_indices", since = "1.5.0")] + #[inline] + pub fn match_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> MatchIndices<'a, P> { + StrExt::match_indices(self, pat) + } + + /// An iterator over the disjoint matches of a pattern within `self`, + /// yielded in reverse order along with the index of the match. + /// + /// For matches of `pat` within `self` that overlap, only the indices + /// corresponding to the last match are returned. + /// + /// The pattern can be a `&str`, [`char`], or a closure that determines if a + /// character matches. + /// + /// [`char`]: primitive.char.html + /// + /// # Iterator behavior + /// + /// The returned iterator requires that the pattern supports a reverse + /// search, and it will be a [`DoubleEndedIterator`] if a forward/reverse + /// search yields the same elements. + /// + /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html + /// + /// For iterating from the front, the [`match_indices`] method can be used. + /// + /// [`match_indices`]: #method.match_indices + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let v: Vec<_> = "abcXXXabcYYYabc".rmatch_indices("abc").collect(); + /// assert_eq!(v, [(12, "abc"), (6, "abc"), (0, "abc")]); + /// + /// let v: Vec<_> = "1abcabc2".rmatch_indices("abc").collect(); + /// assert_eq!(v, [(4, "abc"), (1, "abc")]); + /// + /// let v: Vec<_> = "ababa".rmatch_indices("aba").collect(); + /// assert_eq!(v, [(2, "aba")]); // only the last `aba` + /// ``` + #[stable(feature = "str_match_indices", since = "1.5.0")] + #[inline] + pub fn rmatch_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatchIndices<'a, P> + where P::Searcher: ReverseSearcher<'a> + { + StrExt::rmatch_indices(self, pat) + } + + /// Returns a string slice with leading and trailing whitespace removed. + /// + /// 'Whitespace' is defined according to the terms of the Unicode Derived + /// Core Property `White_Space`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let s = " Hello\tworld\t"; + /// + /// assert_eq!("Hello\tworld", s.trim()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn trim(&self) -> &str { + StrExt::trim(self) + } + + /// Returns a string slice with leading whitespace removed. + /// + /// 'Whitespace' is defined according to the terms of the Unicode Derived + /// Core Property `White_Space`. + /// + /// # Text directionality + /// + /// A string is a sequence of bytes. 'Left' in this context means the first + /// position of that byte string; for a language like Arabic or Hebrew + /// which are 'right to left' rather than 'left to right', this will be + /// the _right_ side, not the left. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let s = " Hello\tworld\t"; + /// + /// assert_eq!("Hello\tworld\t", s.trim_left()); + /// ``` + /// + /// Directionality: + /// + /// ``` + /// let s = " English"; + /// assert!(Some('E') == s.trim_left().chars().next()); + /// + /// let s = " עברית"; + /// assert!(Some('ע') == s.trim_left().chars().next()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn trim_left(&self) -> &str { + StrExt::trim_left(self) + } + + /// Returns a string slice with trailing whitespace removed. + /// + /// 'Whitespace' is defined according to the terms of the Unicode Derived + /// Core Property `White_Space`. + /// + /// # Text directionality + /// + /// A string is a sequence of bytes. 'Right' in this context means the last + /// position of that byte string; for a language like Arabic or Hebrew + /// which are 'right to left' rather than 'left to right', this will be + /// the _left_ side, not the right. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let s = " Hello\tworld\t"; + /// + /// assert_eq!(" Hello\tworld", s.trim_right()); + /// ``` + /// + /// Directionality: + /// + /// ``` + /// let s = "English "; + /// assert!(Some('h') == s.trim_right().chars().rev().next()); + /// + /// let s = "עברית "; + /// assert!(Some('ת') == s.trim_right().chars().rev().next()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn trim_right(&self) -> &str { + StrExt::trim_right(self) + } + + /// Returns a string slice with all prefixes and suffixes that match a + /// pattern repeatedly removed. + /// + /// The pattern can be a [`char`] or a closure that determines if a + /// character matches. + /// + /// [`char`]: primitive.char.html + /// + /// # Examples + /// + /// Simple patterns: + /// + /// ``` + /// assert_eq!("11foo1bar11".trim_matches('1'), "foo1bar"); + /// assert_eq!("123foo1bar123".trim_matches(char::is_numeric), "foo1bar"); + /// + /// let x: &[_] = &['1', '2']; + /// assert_eq!("12foo1bar12".trim_matches(x), "foo1bar"); + /// ``` + /// + /// A more complex pattern, using a closure: + /// + /// ``` + /// assert_eq!("1foo1barXX".trim_matches(|c| c == '1' || c == 'X'), "foo1bar"); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn trim_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str + where P::Searcher: DoubleEndedSearcher<'a> + { + StrExt::trim_matches(self, pat) + } + + /// Returns a string slice with all prefixes that match a pattern + /// repeatedly removed. + /// + /// The pattern can be a `&str`, [`char`], or a closure that determines if + /// a character matches. + /// + /// [`char`]: primitive.char.html + /// + /// # Text directionality + /// + /// A string is a sequence of bytes. 'Left' in this context means the first + /// position of that byte string; for a language like Arabic or Hebrew + /// which are 'right to left' rather than 'left to right', this will be + /// the _right_ side, not the left. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// assert_eq!("11foo1bar11".trim_left_matches('1'), "foo1bar11"); + /// assert_eq!("123foo1bar123".trim_left_matches(char::is_numeric), "foo1bar123"); + /// + /// let x: &[_] = &['1', '2']; + /// assert_eq!("12foo1bar12".trim_left_matches(x), "foo1bar12"); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn trim_left_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str { + StrExt::trim_left_matches(self, pat) + } + + /// Returns a string slice with all suffixes that match a pattern + /// repeatedly removed. + /// + /// The pattern can be a `&str`, [`char`], or a closure that + /// determines if a character matches. + /// + /// [`char`]: primitive.char.html + /// + /// # Text directionality + /// + /// A string is a sequence of bytes. 'Right' in this context means the last + /// position of that byte string; for a language like Arabic or Hebrew + /// which are 'right to left' rather than 'left to right', this will be + /// the _left_ side, not the right. + /// + /// # Examples + /// + /// Simple patterns: + /// + /// ``` + /// assert_eq!("11foo1bar11".trim_right_matches('1'), "11foo1bar"); + /// assert_eq!("123foo1bar123".trim_right_matches(char::is_numeric), "123foo1bar"); + /// + /// let x: &[_] = &['1', '2']; + /// assert_eq!("12foo1bar12".trim_right_matches(x), "12foo1bar"); + /// ``` + /// + /// A more complex pattern, using a closure: + /// + /// ``` + /// assert_eq!("1fooX".trim_right_matches(|c| c == '1' || c == 'X'), "1foo"); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn trim_right_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str + where P::Searcher: ReverseSearcher<'a> + { + StrExt::trim_right_matches(self, pat) + } + + /// Parses this string slice into another type. + /// + /// Because `parse` is so general, it can cause problems with type + /// inference. As such, `parse` is one of the few times you'll see + /// the syntax affectionately known as the 'turbofish': `::<>`. This + /// helps the inference algorithm understand specifically which type + /// you're trying to parse into. + /// + /// `parse` can parse any type that implements the [`FromStr`] trait. + /// + /// [`FromStr`]: str/trait.FromStr.html + /// + /// # Errors + /// + /// Will return [`Err`] if it's not possible to parse this string slice into + /// the desired type. + /// + /// [`Err`]: str/trait.FromStr.html#associatedtype.Err + /// + /// # Examples + /// + /// Basic usage + /// + /// ``` + /// let four: u32 = "4".parse().unwrap(); + /// + /// assert_eq!(4, four); + /// ``` + /// + /// Using the 'turbofish' instead of annotating `four`: + /// + /// ``` + /// let four = "4".parse::<u32>(); + /// + /// assert_eq!(Ok(4), four); + /// ``` + /// + /// Failing to parse: + /// + /// ``` + /// let nope = "j".parse::<u32>(); + /// + /// assert!(nope.is_err()); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn parse<F: FromStr>(&self) -> Result<F, F::Err> { + StrExt::parse(self) + } + + /// Checks if all characters in this string are within the ASCII range. + /// + /// # Examples + /// + /// ``` + /// let ascii = "hello!\n"; + /// let non_ascii = "Grüße, Jürgen ❤"; + /// + /// assert!(ascii.is_ascii()); + /// assert!(!non_ascii.is_ascii()); + /// ``` + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] + #[inline] + pub fn is_ascii(&self) -> bool { + // We can treat each byte as character here: all multibyte characters + // start with a byte that is not in the ascii range, so we will stop + // there already. + self.bytes().all(|b| b.is_ascii()) + } + + /// Checks that two strings are an ASCII case-insensitive match. + /// + /// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`, + /// but without allocating and copying temporaries. + /// + /// # Examples + /// + /// ``` + /// assert!("Ferris".eq_ignore_ascii_case("FERRIS")); + /// assert!("Ferrös".eq_ignore_ascii_case("FERRöS")); + /// assert!(!"Ferrös".eq_ignore_ascii_case("FERRÖS")); + /// ``` + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] + #[inline] + pub fn eq_ignore_ascii_case(&self, other: &str) -> bool { + self.as_bytes().eq_ignore_ascii_case(other.as_bytes()) + } + + /// Converts this string to its ASCII upper case equivalent in-place. + /// + /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', + /// but non-ASCII letters are unchanged. + /// + /// To return a new uppercased value without modifying the existing one, use + /// [`to_ascii_uppercase`]. + /// + /// [`to_ascii_uppercase`]: #method.to_ascii_uppercase + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] + pub fn make_ascii_uppercase(&mut self) { + let me = unsafe { self.as_bytes_mut() }; + me.make_ascii_uppercase() + } + + /// Converts this string to its ASCII lower case equivalent in-place. + /// + /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', + /// but non-ASCII letters are unchanged. + /// + /// To return a new lowercased value without modifying the existing one, use + /// [`to_ascii_lowercase`]. + /// + /// [`to_ascii_lowercase`]: #method.to_ascii_lowercase + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] + pub fn make_ascii_lowercase(&mut self) { + let me = unsafe { self.as_bytes_mut() }; + me.make_ascii_lowercase() + } +}} + +#[lang = "str"] +#[cfg(not(test))] +#[cfg(not(stage0))] +impl str { + str_core_methods!(); +} + + #[stable(feature = "rust1", since = "1.0.0")] impl AsRef<[u8]> for str { #[inline] @@ -2665,3 +4327,72 @@ impl<'a> DoubleEndedIterator for SplitWhitespace<'a> { #[stable(feature = "fused", since = "1.26.0")] impl<'a> FusedIterator for SplitWhitespace<'a> {} + +/// An iterator of [`u16`] over the string encoded as UTF-16. +/// +/// [`u16`]: ../../std/primitive.u16.html +/// +/// This struct is created by the [`encode_utf16`] method on [`str`]. +/// See its documentation for more. +/// +/// [`encode_utf16`]: ../../std/primitive.str.html#method.encode_utf16 +/// [`str`]: ../../std/primitive.str.html +#[derive(Clone)] +#[stable(feature = "encode_utf16", since = "1.8.0")] +pub struct EncodeUtf16<'a> { + chars: Chars<'a>, + extra: u16, +} + +// FIXME: remove (inline) this method +// when updating to a bootstrap compiler that has the new lang items. +// For grepping purpose: #[cfg(stage0)] +impl<'a> EncodeUtf16<'a> { + #[unstable(feature = "core_str_ext", issue = "32110")] + #[doc(hidden)] + pub fn new(s: &'a str) -> Self { + EncodeUtf16 { chars: s.chars(), extra: 0 } + } +} + +#[stable(feature = "collection_debug", since = "1.17.0")] +impl<'a> fmt::Debug for EncodeUtf16<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("EncodeUtf16 { .. }") + } +} + +#[stable(feature = "encode_utf16", since = "1.8.0")] +impl<'a> Iterator for EncodeUtf16<'a> { + type Item = u16; + + #[inline] + fn next(&mut self) -> Option<u16> { + if self.extra != 0 { + let tmp = self.extra; + self.extra = 0; + return Some(tmp); + } + + let mut buf = [0; 2]; + self.chars.next().map(|ch| { + let n = ch.encode_utf16(&mut buf).len(); + if n == 2 { + self.extra = buf[1]; + } + buf[0] + }) + } + + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + let (low, high) = self.chars.size_hint(); + // every char gets either one u16 or two u16, + // so this iterator is between 1 or 2 times as + // long as the underlying iterator. + (low, high.and_then(|n| n.checked_mul(2))) + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl<'a> FusedIterator for EncodeUtf16<'a> {} diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index cf3842dbe27..7aba8b51cff 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -990,9 +990,7 @@ macro_rules! atomic_int { #[$stable_debug] impl fmt::Debug for $atomic_type { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_tuple(stringify!($atomic_type)) - .field(&self.load(Ordering::SeqCst)) - .finish() + fmt::Debug::fmt(&self.load(Ordering::SeqCst), f) } } @@ -2090,7 +2088,7 @@ pub fn compiler_fence(order: Ordering) { #[stable(feature = "atomic_debug", since = "1.3.0")] impl fmt::Debug for AtomicBool { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_tuple("AtomicBool").field(&self.load(Ordering::SeqCst)).finish() + fmt::Debug::fmt(&self.load(Ordering::SeqCst), f) } } @@ -2098,7 +2096,7 @@ impl fmt::Debug for AtomicBool { #[stable(feature = "atomic_debug", since = "1.3.0")] impl<T> fmt::Debug for AtomicPtr<T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_tuple("AtomicPtr").field(&self.load(Ordering::SeqCst)).finish() + fmt::Debug::fmt(&self.load(Ordering::SeqCst), f) } } diff --git a/src/libcore/tests/cell.rs b/src/libcore/tests/cell.rs index cc0ef6a6f17..962fb2f0e02 100644 --- a/src/libcore/tests/cell.rs +++ b/src/libcore/tests/cell.rs @@ -27,6 +27,17 @@ fn smoketest_cell() { } #[test] +fn cell_update() { + let x = Cell::new(10); + + assert_eq!(x.update(|x| x + 5), 15); + assert_eq!(x.get(), 15); + + assert_eq!(x.update(|x| x / 3), 5); + assert_eq!(x.get(), 5); +} + +#[test] fn cell_has_sensible_show() { let x = Cell::new("foo bar"); assert!(format!("{:?}", x).contains(x.get())); diff --git a/src/libcore/tests/char.rs b/src/libcore/tests/char.rs index 4e10ceac878..ab90763abf8 100644 --- a/src/libcore/tests/char.rs +++ b/src/libcore/tests/char.rs @@ -364,6 +364,7 @@ fn eu_iterator_specializations() { } #[test] +#[allow(deprecated)] fn test_decode_utf8() { macro_rules! assert_decode_utf8 { ($input_bytes: expr, $expected_str: expr) => { diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index bb875c7219a..e4d27717938 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -10,13 +10,16 @@ #![feature(ascii_ctype)] #![feature(box_syntax)] +#![feature(cell_update)] #![feature(core_float)] #![feature(core_private_bignum)] #![feature(core_private_diy_float)] #![feature(dec2flt)] #![feature(decode_utf8)] +#![feature(euclidean_division)] #![feature(exact_size_is_empty)] #![feature(fixed_size_array)] +#![feature(float_internals)] #![feature(flt2dec)] #![feature(fmt_internals)] #![feature(hashmap_internals)] @@ -36,6 +39,7 @@ #![feature(str_internals)] #![feature(test)] #![feature(trusted_len)] +#![feature(try_from)] #![feature(try_trait)] #![feature(exact_chunks)] #![cfg_attr(stage0, feature(atomic_nand))] diff --git a/src/libcore/tests/num/int_macros.rs b/src/libcore/tests/num/int_macros.rs index 8d791283ab8..71d2e794538 100644 --- a/src/libcore/tests/num/int_macros.rs +++ b/src/libcore/tests/num/int_macros.rs @@ -31,6 +31,11 @@ mod tests { } #[test] + fn test_mod_euc() { + assert!((-1 as $T).mod_euc(MIN) == MAX); + } + + #[test] pub fn test_abs() { assert!((1 as $T).abs() == 1 as $T); assert!((0 as $T).abs() == 0 as $T); diff --git a/src/libcore/time.rs b/src/libcore/time.rs index b8d0719b9b9..e22fe450bb1 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -137,7 +137,6 @@ impl Duration { /// # Examples /// /// ``` - /// #![feature(duration_from_micros)] /// use std::time::Duration; /// /// let duration = Duration::from_micros(1_000_002); @@ -145,7 +144,7 @@ impl Duration { /// assert_eq!(1, duration.as_secs()); /// assert_eq!(2000, duration.subsec_nanos()); /// ``` - #[unstable(feature = "duration_from_micros", issue = "44400")] + #[stable(feature = "duration_from_micros", since = "1.27.0")] #[inline] pub const fn from_micros(micros: u64) -> Duration { Duration { @@ -159,7 +158,6 @@ impl Duration { /// # Examples /// /// ``` - /// #![feature(duration_extras)] /// use std::time::Duration; /// /// let duration = Duration::from_nanos(1_000_000_123); @@ -167,7 +165,7 @@ impl Duration { /// assert_eq!(1, duration.as_secs()); /// assert_eq!(123, duration.subsec_nanos()); /// ``` - #[unstable(feature = "duration_extras", issue = "46507")] + #[stable(feature = "duration_extras", since = "1.27.0")] #[inline] pub const fn from_nanos(nanos: u64) -> Duration { Duration { @@ -217,14 +215,13 @@ impl Duration { /// # Examples /// /// ``` - /// #![feature(duration_extras)] /// use std::time::Duration; /// /// let duration = Duration::from_millis(5432); /// assert_eq!(duration.as_secs(), 5); /// assert_eq!(duration.subsec_millis(), 432); /// ``` - #[unstable(feature = "duration_extras", issue = "46507")] + #[stable(feature = "duration_extras", since = "1.27.0")] #[inline] pub fn subsec_millis(&self) -> u32 { self.nanos / NANOS_PER_MILLI } @@ -237,14 +234,13 @@ impl Duration { /// # Examples /// /// ``` - /// #![feature(duration_extras, duration_from_micros)] /// use std::time::Duration; /// /// let duration = Duration::from_micros(1_234_567); /// assert_eq!(duration.as_secs(), 1); /// assert_eq!(duration.subsec_micros(), 234_567); /// ``` - #[unstable(feature = "duration_extras", issue = "46507")] + #[stable(feature = "duration_extras", since = "1.27.0")] #[inline] pub fn subsec_micros(&self) -> u32 { self.nanos / NANOS_PER_MICRO } diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs index e171216523a..f51dbc3772f 100644 --- a/src/libproc_macro/lib.rs +++ b/src/libproc_macro/lib.rs @@ -270,7 +270,7 @@ impl Span { /// `self` was generated from, if any. #[unstable(feature = "proc_macro", issue = "38356")] pub fn parent(&self) -> Option<Span> { - self.0.ctxt().outer().expn_info().map(|i| Span(i.call_site)) + self.0.parent().map(Span) } /// The span for the origin source code that `self` was generated from. If diff --git a/src/libproc_macro/quote.rs b/src/libproc_macro/quote.rs index a0ec6928094..d1f8e75192a 100644 --- a/src/libproc_macro/quote.rs +++ b/src/libproc_macro/quote.rs @@ -163,9 +163,9 @@ impl<'a> Quote for &'a str { } } -impl Quote for usize { +impl Quote for u16 { fn quote(self) -> TokenStream { - TokenTree::from(Literal::usize_unsuffixed(self)).into() + TokenTree::from(Literal::u16_unsuffixed(self)).into() } } @@ -197,7 +197,7 @@ macro_rules! literals { ($($i:ident),*; $($raw:ident),*) => { pub enum LiteralKind { $($i,)* - $($raw(usize),)* + $($raw(u16),)* } impl LiteralKind { diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml index 2aae0f24d48..357ebb89fb6 100644 --- a/src/librustc/Cargo.toml +++ b/src/librustc/Cargo.toml @@ -18,7 +18,7 @@ lazy_static = "1.0.0" log = { version = "0.4", features = ["release_max_level_info", "std"] } proc_macro = { path = "../libproc_macro" } rustc_apfloat = { path = "../librustc_apfloat" } -rustc_back = { path = "../librustc_back" } +rustc_target = { path = "../librustc_target" } rustc_const_math = { path = "../librustc_const_math" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_errors = { path = "../librustc_errors" } diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 1b907073238..e4f432e7caf 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -70,7 +70,8 @@ use rustc_data_structures::stable_hasher::{StableHasher, HashStable}; use std::fmt; use std::hash::Hash; use syntax_pos::symbol::InternedString; -use traits::query::{CanonicalProjectionGoal, CanonicalTyGoal}; +use traits::query::{CanonicalProjectionGoal, + CanonicalTyGoal, CanonicalPredicateGoal}; use ty::{TyCtxt, Instance, InstanceDef, ParamEnv, ParamEnvAnd, PolyTraitRef, Ty}; use ty::subst::Substs; @@ -556,7 +557,6 @@ define_dep_nodes!( <'tcx> [input] DefSpan(DefId), [] LookupStability(DefId), [] LookupDeprecationEntry(DefId), - [] ItemBodyNestedBodies(DefId), [] ConstIsRvaluePromotableToStatic(DefId), [] RvaluePromotableMap(DefId), [] ImplParent(DefId), @@ -567,6 +567,7 @@ define_dep_nodes!( <'tcx> [] ItemAttrs(DefId), [] TransFnAttrs(DefId), [] FnArgNames(DefId), + [] RenderedConst(DefId), [] DylibDepFormats(CrateNum), [] IsPanicRuntime(CrateNum), [] IsCompilerBuiltins(CrateNum), @@ -615,7 +616,6 @@ define_dep_nodes!( <'tcx> [input] GetLangItems, [] DefinedLangItems(CrateNum), [] MissingLangItems(CrateNum), - [] ExternConstBody(DefId), [] VisibleParentMap, [input] MissingExternCrateItem(CrateNum), [input] UsedCrateSource(CrateNum), @@ -644,6 +644,7 @@ define_dep_nodes!( <'tcx> [] NormalizeProjectionTy(CanonicalProjectionGoal<'tcx>), [] NormalizeTyAfterErasingRegions(ParamEnvAnd<'tcx, Ty<'tcx>>), [] DropckOutlives(CanonicalTyGoal<'tcx>), + [] EvaluateObligation(CanonicalPredicateGoal<'tcx>), [] SubstituteNormalizeAndTestPredicates { key: (DefId, &'tcx Substs<'tcx>) }, @@ -656,6 +657,7 @@ define_dep_nodes!( <'tcx> [input] Features, [] ProgramClausesFor(DefId), + [] ProgramClausesForEnv(ParamEnv<'tcx>), [] WasmImportModuleMap(CrateNum), [] ForeignModules(CrateNum), diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs index d60c22064d3..22ab1b15c8b 100644 --- a/src/librustc/dep_graph/graph.rs +++ b/src/librustc/dep_graph/graph.rs @@ -12,11 +12,10 @@ use errors::DiagnosticBuilder; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; -use rustc_data_structures::sync::Lrc; -use std::cell::{Ref, RefCell}; +use rustc_data_structures::sync::{Lrc, RwLock, ReadGuard, Lock}; use std::env; use std::hash::Hash; -use ty::TyCtxt; +use ty::{self, TyCtxt}; use util::common::{ProfileQueriesMsg, profq_msg}; use ich::{StableHashingContext, StableHashingContextProvider, Fingerprint}; @@ -24,7 +23,6 @@ use ich::{StableHashingContext, StableHashingContextProvider, Fingerprint}; use super::debug::EdgeFilter; use super::dep_node::{DepNode, DepKind, WorkProductId}; use super::query::DepGraphQuery; -use super::raii; use super::safe::DepGraphSafe; use super::serialized::{SerializedDepGraph, SerializedDepNodeIndex}; use super::prev::PreviousDepGraph; @@ -37,7 +35,7 @@ pub struct DepGraph { // result value fingerprints. Do not rely on the length of this vector // being the same as the number of nodes in the graph. The vector can // contain an arbitrary number of zero-entries at the end. - fingerprints: Lrc<RefCell<IndexVec<DepNodeIndex, Fingerprint>>> + fingerprints: Lrc<Lock<IndexVec<DepNodeIndex, Fingerprint>>> } @@ -67,27 +65,27 @@ struct DepGraphData { /// tracking. The `current` field is the dependency graph of only the /// current compilation session: We don't merge the previous dep-graph into /// current one anymore. - current: RefCell<CurrentDepGraph>, + current: Lock<CurrentDepGraph>, /// The dep-graph from the previous compilation session. It contains all /// nodes and edges as well as all fingerprints of nodes that have them. previous: PreviousDepGraph, - colors: RefCell<DepNodeColorMap>, + colors: Lock<DepNodeColorMap>, /// When we load, there may be `.o` files, cached mir, or other such /// things available to us. If we find that they are not dirty, we /// load the path to the file storing those work-products here into /// this map. We can later look for and extract that data. - previous_work_products: RefCell<FxHashMap<WorkProductId, WorkProduct>>, + previous_work_products: RwLock<FxHashMap<WorkProductId, WorkProduct>>, /// Work-products that we generate in this run. - work_products: RefCell<FxHashMap<WorkProductId, WorkProduct>>, + work_products: RwLock<FxHashMap<WorkProductId, WorkProduct>>, - dep_node_debug: RefCell<FxHashMap<DepNode, String>>, + dep_node_debug: Lock<FxHashMap<DepNode, String>>, // Used for testing, only populated when -Zquery-dep-graph is specified. - loaded_from_cache: RefCell<FxHashMap<DepNodeIndex, bool>>, + loaded_from_cache: Lock<FxHashMap<DepNodeIndex, bool>>, } impl DepGraph { @@ -102,22 +100,22 @@ impl DepGraph { (prev_graph_node_count * 115) / 100); DepGraph { data: Some(Lrc::new(DepGraphData { - previous_work_products: RefCell::new(FxHashMap()), - work_products: RefCell::new(FxHashMap()), - dep_node_debug: RefCell::new(FxHashMap()), - current: RefCell::new(CurrentDepGraph::new()), + previous_work_products: RwLock::new(FxHashMap()), + work_products: RwLock::new(FxHashMap()), + dep_node_debug: Lock::new(FxHashMap()), + current: Lock::new(CurrentDepGraph::new()), previous: prev_graph, - colors: RefCell::new(DepNodeColorMap::new(prev_graph_node_count)), - loaded_from_cache: RefCell::new(FxHashMap()), + colors: Lock::new(DepNodeColorMap::new(prev_graph_node_count)), + loaded_from_cache: Lock::new(FxHashMap()), })), - fingerprints: Lrc::new(RefCell::new(fingerprints)), + fingerprints: Lrc::new(Lock::new(fingerprints)), } } pub fn new_disabled() -> DepGraph { DepGraph { data: None, - fingerprints: Lrc::new(RefCell::new(IndexVec::new())), + fingerprints: Lrc::new(Lock::new(IndexVec::new())), } } @@ -144,21 +142,32 @@ impl DepGraph { pub fn assert_ignored(&self) { - if let Some(ref data) = self.data { - match data.current.borrow().task_stack.last() { - Some(&OpenTask::Ignore) | None => { - // ignored + if let Some(..) = self.data { + ty::tls::with_context_opt(|icx| { + let icx = if let Some(icx) = icx { icx } else { return }; + match *icx.task { + OpenTask::Ignore => { + // ignored + } + _ => panic!("expected an ignore context") } - _ => panic!("expected an ignore context") - } + }) } } pub fn with_ignore<OP,R>(&self, op: OP) -> R where OP: FnOnce() -> R { - let _task = self.data.as_ref().map(|data| raii::IgnoreTask::new(&data.current)); - op() + ty::tls::with_context(|icx| { + let icx = ty::tls::ImplicitCtxt { + task: &OpenTask::Ignore, + ..icx.clone() + }; + + ty::tls::enter_context(&icx, |_| { + op() + }) + }) } /// Starts a new dep-graph task. Dep-graph tasks are specified @@ -197,24 +206,51 @@ impl DepGraph { where C: DepGraphSafe + StableHashingContextProvider<'gcx>, R: HashStable<StableHashingContext<'gcx>>, { - self.with_task_impl(key, cx, arg, task, - |data, key| data.borrow_mut().push_task(key), - |data, key| data.borrow_mut().pop_task(key)) + self.with_task_impl(key, cx, arg, false, task, + |key| OpenTask::Regular(Lock::new(RegularOpenTask { + node: key, + reads: Vec::new(), + read_set: FxHashSet(), + })), + |data, key, task| data.borrow_mut().complete_task(key, task)) } - fn with_task_impl<'gcx, C, A, R>(&self, - key: DepNode, - cx: C, - arg: A, - task: fn(C, A) -> R, - push: fn(&RefCell<CurrentDepGraph>, DepNode), - pop: fn(&RefCell<CurrentDepGraph>, DepNode) -> DepNodeIndex) - -> (R, DepNodeIndex) + /// Creates a new dep-graph input with value `input` + pub fn input_task<'gcx, C, R>(&self, + key: DepNode, + cx: C, + input: R) + -> (R, DepNodeIndex) where C: DepGraphSafe + StableHashingContextProvider<'gcx>, R: HashStable<StableHashingContext<'gcx>>, { + fn identity_fn<C, A>(_: C, arg: A) -> A { + arg + } + + self.with_task_impl(key, cx, input, true, identity_fn, + |_| OpenTask::Ignore, + |data, key, _| data.borrow_mut().alloc_node(key, Vec::new())) + } + + fn with_task_impl<'gcx, C, A, R>( + &self, + key: DepNode, + cx: C, + arg: A, + no_tcx: bool, + task: fn(C, A) -> R, + create_task: fn(DepNode) -> OpenTask, + finish_task_and_alloc_depnode: fn(&Lock<CurrentDepGraph>, + DepNode, + OpenTask) -> DepNodeIndex + ) -> (R, DepNodeIndex) + where + C: DepGraphSafe + StableHashingContextProvider<'gcx>, + R: HashStable<StableHashingContext<'gcx>>, + { if let Some(ref data) = self.data { - push(&data.current, key); + let open_task = create_task(key); // In incremental mode, hash the result of the task. We don't // do anything with the hash yet, but we are computing it @@ -227,13 +263,26 @@ impl DepGraph { profq_msg(hcx.sess(), ProfileQueriesMsg::TaskBegin(key.clone())) }; - let result = task(cx, arg); + let result = if no_tcx { + task(cx, arg) + } else { + ty::tls::with_context(|icx| { + let icx = ty::tls::ImplicitCtxt { + task: &open_task, + ..icx.clone() + }; + + ty::tls::enter_context(&icx, |_| { + task(cx, arg) + }) + }) + }; if cfg!(debug_assertions) { profq_msg(hcx.sess(), ProfileQueriesMsg::TaskEnd) }; - let dep_node_index = pop(&data.current, key); + let dep_node_index = finish_task_and_alloc_depnode(&data.current, key, open_task); let mut stable_hasher = StableHasher::new(); result.hash_stable(&mut hcx, &mut stable_hasher); @@ -302,11 +351,28 @@ impl DepGraph { where OP: FnOnce() -> R { if let Some(ref data) = self.data { - data.current.borrow_mut().push_anon_task(); - let result = op(); + let (result, open_task) = ty::tls::with_context(|icx| { + let task = OpenTask::Anon(Lock::new(AnonOpenTask { + reads: Vec::new(), + read_set: FxHashSet(), + })); + + let r = { + let icx = ty::tls::ImplicitCtxt { + task: &task, + ..icx.clone() + }; + + ty::tls::enter_context(&icx, |_| { + op() + }) + }; + + (r, task) + }); let dep_node_index = data.current .borrow_mut() - .pop_anon_task(dep_kind); + .pop_anon_task(dep_kind, open_task); (result, dep_node_index) } else { (op(), DepNodeIndex::INVALID) @@ -324,9 +390,9 @@ impl DepGraph { where C: DepGraphSafe + StableHashingContextProvider<'gcx>, R: HashStable<StableHashingContext<'gcx>>, { - self.with_task_impl(key, cx, arg, task, - |data, key| data.borrow_mut().push_eval_always_task(key), - |data, key| data.borrow_mut().pop_eval_always_task(key)) + self.with_task_impl(key, cx, arg, false, task, + |key| OpenTask::EvalAlways { node: key }, + |data, key, task| data.borrow_mut().complete_eval_always_task(key, task)) } #[inline] @@ -432,13 +498,13 @@ impl DepGraph { /// Access the map of work-products created during this run. Only /// used during saving of the dep-graph. - pub fn work_products(&self) -> Ref<FxHashMap<WorkProductId, WorkProduct>> { + pub fn work_products(&self) -> ReadGuard<FxHashMap<WorkProductId, WorkProduct>> { self.data.as_ref().unwrap().work_products.borrow() } /// Access the map of work-products created during the cached run. Only /// used during saving of the dep-graph. - pub fn previous_work_products(&self) -> Ref<FxHashMap<WorkProductId, WorkProduct>> { + pub fn previous_work_products(&self) -> ReadGuard<FxHashMap<WorkProductId, WorkProduct>> { self.data.as_ref().unwrap().previous_work_products.borrow() } @@ -528,6 +594,7 @@ impl DepGraph { debug!("try_mark_green({:?}) - BEGIN", dep_node); let data = self.data.as_ref().unwrap(); + #[cfg(not(parallel_queries))] debug_assert!(!data.current.borrow().node_to_node_index.contains_key(dep_node)); if dep_node.kind.is_input() { @@ -668,16 +735,24 @@ impl DepGraph { } } - // If we got here without hitting a `return` that means that all // dependencies of this DepNode could be marked as green. Therefore we - // can also mark this DepNode as green. We do so by... + // can also mark this DepNode as green. - // ... allocating an entry for it in the current dependency graph and - // adding all the appropriate edges imported from the previous graph ... - let dep_node_index = data.current - .borrow_mut() - .alloc_node(*dep_node, current_deps); + // There may be multiple threads trying to mark the same dep node green concurrently + + let (dep_node_index, did_allocation) = { + let mut current = data.current.borrow_mut(); + + if let Some(&dep_node_index) = current.node_to_node_index.get(&dep_node) { + // Someone else allocated it before us + (dep_node_index, false) + } else { + // We allocating an entry for the node in the current dependency graph and + // adding all the appropriate edges imported from the previous graph + (current.alloc_node(*dep_node, current_deps), true) + } + }; // ... copying the fingerprint from the previous graph too, so we don't // have to recompute it ... @@ -689,6 +764,8 @@ impl DepGraph { fingerprints.resize(dep_node_index.index() + 1, Fingerprint::ZERO); } + // Multiple threads can all write the same fingerprint here + #[cfg(not(parallel_queries))] debug_assert!(fingerprints[dep_node_index] == Fingerprint::ZERO, "DepGraph::try_mark_green() - Duplicate fingerprint \ insertion for {:?}", dep_node); @@ -697,7 +774,14 @@ impl DepGraph { } // ... emitting any stored diagnostic ... - { + if did_allocation { + // Only the thread which did the allocation emits the error messages + + // FIXME: Ensure that these are printed before returning for all threads. + // Currently threads where did_allocation = false can continue on + // and emit other diagnostics before these diagnostics are emitted. + // Such diagnostics should be emitted after these. + // See https://github.com/rust-lang/rust/issues/48685 let diagnostics = tcx.on_disk_query_result_cache .load_diagnostics(tcx, prev_dep_node_index); @@ -716,6 +800,8 @@ impl DepGraph { // ... and finally storing a "Green" entry in the color map. let mut colors = data.colors.borrow_mut(); + // Multiple threads can all write the same color here + #[cfg(not(parallel_queries))] debug_assert!(colors.get(prev_dep_node_index).is_none(), "DepGraph::try_mark_green() - Duplicate DepNodeColor \ insertion for {:?}", dep_node); @@ -839,7 +925,6 @@ pub(super) struct CurrentDepGraph { nodes: IndexVec<DepNodeIndex, DepNode>, edges: IndexVec<DepNodeIndex, Vec<DepNodeIndex>>, node_to_node_index: FxHashMap<DepNode, DepNodeIndex>, - task_stack: Vec<OpenTask>, forbidden_edge: Option<EdgeFilter>, // Anonymous DepNodes are nodes the ID of which we compute from the list of @@ -888,38 +973,19 @@ impl CurrentDepGraph { edges: IndexVec::new(), node_to_node_index: FxHashMap(), anon_id_seed: stable_hasher.finish(), - task_stack: Vec::new(), forbidden_edge, total_read_count: 0, total_duplicate_read_count: 0, } } - pub(super) fn push_ignore(&mut self) { - self.task_stack.push(OpenTask::Ignore); - } - - pub(super) fn pop_ignore(&mut self) { - let popped_node = self.task_stack.pop().unwrap(); - debug_assert_eq!(popped_node, OpenTask::Ignore); - } - - pub(super) fn push_task(&mut self, key: DepNode) { - self.task_stack.push(OpenTask::Regular { - node: key, - reads: Vec::new(), - read_set: FxHashSet(), - }); - } - - pub(super) fn pop_task(&mut self, key: DepNode) -> DepNodeIndex { - let popped_node = self.task_stack.pop().unwrap(); - - if let OpenTask::Regular { - node, - read_set: _, - reads - } = popped_node { + fn complete_task(&mut self, key: DepNode, task: OpenTask) -> DepNodeIndex { + if let OpenTask::Regular(task) = task { + let RegularOpenTask { + node, + read_set: _, + reads + } = task.into_inner(); assert_eq!(node, key); // If this is an input node, we expect that it either has no @@ -946,24 +1012,16 @@ impl CurrentDepGraph { self.alloc_node(node, reads) } else { - bug!("pop_task() - Expected regular task to be popped") + bug!("complete_task() - Expected regular task to be popped") } } - fn push_anon_task(&mut self) { - self.task_stack.push(OpenTask::Anon { - reads: Vec::new(), - read_set: FxHashSet(), - }); - } - - fn pop_anon_task(&mut self, kind: DepKind) -> DepNodeIndex { - let popped_node = self.task_stack.pop().unwrap(); - - if let OpenTask::Anon { - read_set: _, - reads - } = popped_node { + fn pop_anon_task(&mut self, kind: DepKind, task: OpenTask) -> DepNodeIndex { + if let OpenTask::Anon(task) = task { + let AnonOpenTask { + read_set: _, + reads + } = task.into_inner(); debug_assert!(!kind.is_input()); let mut fingerprint = self.anon_id_seed; @@ -997,62 +1055,54 @@ impl CurrentDepGraph { } } - fn push_eval_always_task(&mut self, key: DepNode) { - self.task_stack.push(OpenTask::EvalAlways { node: key }); - } - - fn pop_eval_always_task(&mut self, key: DepNode) -> DepNodeIndex { - let popped_node = self.task_stack.pop().unwrap(); - + fn complete_eval_always_task(&mut self, key: DepNode, task: OpenTask) -> DepNodeIndex { if let OpenTask::EvalAlways { node, - } = popped_node { + } = task { debug_assert_eq!(node, key); let krate_idx = self.node_to_node_index[&DepNode::new_no_params(DepKind::Krate)]; self.alloc_node(node, vec![krate_idx]) } else { - bug!("pop_eval_always_task() - Expected eval always task to be popped"); + bug!("complete_eval_always_task() - Expected eval always task to be popped"); } } fn read_index(&mut self, source: DepNodeIndex) { - match self.task_stack.last_mut() { - Some(&mut OpenTask::Regular { - ref mut reads, - ref mut read_set, - node: ref target, - }) => { - self.total_read_count += 1; - if read_set.insert(source) { - reads.push(source); - - if cfg!(debug_assertions) { - if let Some(ref forbidden_edge) = self.forbidden_edge { - let source = self.nodes[source]; - if forbidden_edge.test(&source, &target) { - bug!("forbidden edge {:?} -> {:?} created", - source, - target) + ty::tls::with_context_opt(|icx| { + let icx = if let Some(icx) = icx { icx } else { return }; + match *icx.task { + OpenTask::Regular(ref task) => { + let mut task = task.lock(); + self.total_read_count += 1; + if task.read_set.insert(source) { + task.reads.push(source); + + if cfg!(debug_assertions) { + if let Some(ref forbidden_edge) = self.forbidden_edge { + let target = &task.node; + let source = self.nodes[source]; + if forbidden_edge.test(&source, &target) { + bug!("forbidden edge {:?} -> {:?} created", + source, + target) + } } } + } else { + self.total_duplicate_read_count += 1; } - } else { - self.total_duplicate_read_count += 1; } - } - Some(&mut OpenTask::Anon { - ref mut reads, - ref mut read_set, - }) => { - if read_set.insert(source) { - reads.push(source); + OpenTask::Anon(ref task) => { + let mut task = task.lock(); + if task.read_set.insert(source) { + task.reads.push(source); + } + } + OpenTask::Ignore | OpenTask::EvalAlways { .. } => { + // ignore } } - Some(&mut OpenTask::Ignore) | - Some(&mut OpenTask::EvalAlways { .. }) | None => { - // ignore - } - } + }) } fn alloc_node(&mut self, @@ -1070,17 +1120,20 @@ impl CurrentDepGraph { } } -#[derive(Clone, Debug, PartialEq)] -enum OpenTask { - Regular { - node: DepNode, - reads: Vec<DepNodeIndex>, - read_set: FxHashSet<DepNodeIndex>, - }, - Anon { - reads: Vec<DepNodeIndex>, - read_set: FxHashSet<DepNodeIndex>, - }, +pub struct RegularOpenTask { + node: DepNode, + reads: Vec<DepNodeIndex>, + read_set: FxHashSet<DepNodeIndex>, +} + +pub struct AnonOpenTask { + reads: Vec<DepNodeIndex>, + read_set: FxHashSet<DepNodeIndex>, +} + +pub enum OpenTask { + Regular(Lock<RegularOpenTask>), + Anon(Lock<AnonOpenTask>), Ignore, EvalAlways { node: DepNode, diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs index a472183698a..8a6f66911ec 100644 --- a/src/librustc/dep_graph/mod.rs +++ b/src/librustc/dep_graph/mod.rs @@ -14,13 +14,12 @@ mod dep_tracking_map; mod graph; mod prev; mod query; -mod raii; mod safe; mod serialized; pub use self::dep_tracking_map::{DepTrackingMap, DepTrackingMapConfig}; pub use self::dep_node::{DepNode, DepKind, DepConstructor, WorkProductId, label_strs}; -pub use self::graph::{DepGraph, WorkProduct, DepNodeIndex, DepNodeColor}; +pub use self::graph::{DepGraph, WorkProduct, DepNodeIndex, DepNodeColor, OpenTask}; pub use self::graph::WorkProductFileKind; pub use self::prev::PreviousDepGraph; pub use self::query::DepGraphQuery; diff --git a/src/librustc/dep_graph/raii.rs b/src/librustc/dep_graph/raii.rs deleted file mode 100644 index 5728bcc7d27..00000000000 --- a/src/librustc/dep_graph/raii.rs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use super::graph::CurrentDepGraph; - -use std::cell::RefCell; - -pub struct IgnoreTask<'graph> { - graph: &'graph RefCell<CurrentDepGraph>, -} - -impl<'graph> IgnoreTask<'graph> { - pub(super) fn new(graph: &'graph RefCell<CurrentDepGraph>) -> IgnoreTask<'graph> { - graph.borrow_mut().push_ignore(); - IgnoreTask { - graph, - } - } -} - -impl<'graph> Drop for IgnoreTask<'graph> { - fn drop(&mut self) { - self.graph.borrow_mut().pop_ignore(); - } -} - diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs index 956cd17f38f..19f8d15662d 100644 --- a/src/librustc/hir/check_attr.rs +++ b/src/librustc/hir/check_attr.rs @@ -30,6 +30,7 @@ enum Target { ForeignMod, Expression, Statement, + Closure, Other, } @@ -103,14 +104,14 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> { self.check_repr(item, target); } - /// Check if an `#[inline]` is applied to a function. + /// Check if an `#[inline]` is applied to a function or a closure. fn check_inline(&self, attr: &hir::Attribute, span: &Span, target: Target) { - if target != Target::Fn { + if target != Target::Fn && target != Target::Closure { struct_span_err!(self.tcx.sess, attr.span, E0518, - "attribute should be applied to function") - .span_label(*span, "not a function") + "attribute should be applied to function or closure") + .span_label(*span, "not a function or closure") .emit(); } } @@ -286,9 +287,13 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> { } fn check_expr_attributes(&self, expr: &hir::Expr) { + let target = match expr.node { + hir::ExprClosure(..) => Target::Closure, + _ => Target::Expression, + }; for attr in expr.attrs.iter() { if attr.check_name("inline") { - self.check_inline(attr, &expr.span, Target::Expression); + self.check_inline(attr, &expr.span, target); } if attr.check_name("repr") { self.emit_repr_error( diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 3823376df73..3e5dcee113a 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -41,7 +41,7 @@ //! This order consistency is required in a few places in rustc, for //! example generator inference, and possibly also HIR borrowck. -use syntax::abi::Abi; +use rustc_target::spec::abi::Abi; use syntax::ast::{NodeId, CRATE_NODE_ID, Name, Attribute}; use syntax_pos::Span; use hir::*; diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 4023521147e..e4b9fc1385d 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -655,7 +655,7 @@ impl<'a> LoweringContext<'a> { self.resolver.definitions().create_def_with_parent( parent_id.index, def_node_id, - DefPathData::LifetimeDef(str_name), + DefPathData::LifetimeDef(str_name.as_interned_str()), DefIndexAddressSpace::High, Mark::root(), span, @@ -1302,7 +1302,7 @@ impl<'a> LoweringContext<'a> { self.context.resolver.definitions().create_def_with_parent( self.parent, def_node_id, - DefPathData::LifetimeDef(name.name().as_str()), + DefPathData::LifetimeDef(name.name().as_interned_str()), DefIndexAddressSpace::High, Mark::root(), lifetime.span, @@ -4107,15 +4107,13 @@ impl<'a> LoweringContext<'a> { } fn maybe_lint_bare_trait(&self, span: Span, id: NodeId, is_global: bool) { - if self.sess.features_untracked().dyn_trait { - self.sess.buffer_lint_with_diagnostic( - builtin::BARE_TRAIT_OBJECT, - id, - span, - "trait objects without an explicit `dyn` are deprecated", - builtin::BuiltinLintDiagnostics::BareTraitObject(span, is_global), - ) - } + self.sess.buffer_lint_with_diagnostic( + builtin::BARE_TRAIT_OBJECT, + id, + span, + "trait objects without an explicit `dyn` are deprecated", + builtin::BuiltinLintDiagnostics::BareTraitObject(span, is_global), + ) } fn wrap_in_try_constructor( diff --git a/src/librustc/hir/map/blocks.rs b/src/librustc/hir/map/blocks.rs index 1eaacdb1d7f..362c0bf07f7 100644 --- a/src/librustc/hir/map/blocks.rs +++ b/src/librustc/hir/map/blocks.rs @@ -25,7 +25,7 @@ use hir as ast; use hir::map::{self, Node}; use hir::{Expr, FnDecl}; use hir::intravisit::FnKind; -use syntax::abi; +use rustc_target::spec::abi; use syntax::ast::{Attribute, Name, NodeId}; use syntax_pos::Span; diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs index f77275926eb..38de8548f30 100644 --- a/src/librustc/hir/map/collector.rs +++ b/src/librustc/hir/map/collector.rs @@ -79,26 +79,23 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { body_ids: _, } = *krate; - root_mod_sig_dep_index = dep_graph.with_task( + root_mod_sig_dep_index = dep_graph.input_task( root_mod_def_path_hash.to_dep_node(DepKind::Hir), &hcx, HirItemLike { item_like: (module, attrs, span), hash_bodies: false }, - identity_fn ).1; - root_mod_full_dep_index = dep_graph.with_task( + root_mod_full_dep_index = dep_graph.input_task( root_mod_def_path_hash.to_dep_node(DepKind::HirBody), &hcx, HirItemLike { item_like: (module, attrs, span), hash_bodies: true }, - identity_fn ).1; } { - dep_graph.with_task( + dep_graph.input_task( DepNode::new_no_params(DepKind::AllLocalTraitImpls), &hcx, &krate.trait_impls, - identity_fn ); } @@ -169,12 +166,11 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { let (_, crate_dep_node_index) = self .dep_graph - .with_task(DepNode::new_no_params(DepKind::Krate), + .input_task(DepNode::new_no_params(DepKind::Krate), &self.hcx, (((node_hashes, upstream_crates), source_file_names), (commandline_args_hash, - crate_disambiguator.to_fingerprint())), - identity_fn); + crate_disambiguator.to_fingerprint()))); let svh = Svh::new(self.dep_graph .fingerprint_of(crate_dep_node_index) @@ -267,18 +263,16 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { let def_path_hash = self.definitions.def_path_hash(dep_node_owner); - self.current_signature_dep_index = self.dep_graph.with_task( + self.current_signature_dep_index = self.dep_graph.input_task( def_path_hash.to_dep_node(DepKind::Hir), &self.hcx, HirItemLike { item_like, hash_bodies: false }, - identity_fn ).1; - self.current_full_dep_index = self.dep_graph.with_task( + self.current_full_dep_index = self.dep_graph.input_task( def_path_hash.to_dep_node(DepKind::HirBody), &self.hcx, HirItemLike { item_like, hash_bodies: true }, - identity_fn ).1; self.hir_body_nodes.push((def_path_hash, self.current_full_dep_index)); @@ -520,12 +514,6 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { } } -// We use this with DepGraph::with_task(). Since we are handling only input -// values here, the "task" computing them just passes them through. -fn identity_fn<T>(_: &StableHashingContext, item_like: T) -> T { - item_like -} - // This is a wrapper structure that allows determining if span values within // the wrapped item should be hashed or not. struct HirItemLike<T> { diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index 4bd857c73e6..ebd8e623582 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -107,17 +107,18 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { // information we encapsulate into let def_data = match i.node { ItemKind::Impl(..) => DefPathData::Impl, + ItemKind::Trait(..) => DefPathData::Trait(i.ident.name.as_interned_str()), ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) | - ItemKind::Trait(..) | ItemKind::TraitAlias(..) | + ItemKind::TraitAlias(..) | ItemKind::ExternCrate(..) | ItemKind::ForeignMod(..) | ItemKind::Ty(..) => - DefPathData::TypeNs(i.ident.name.as_str()), + DefPathData::TypeNs(i.ident.name.as_interned_str()), ItemKind::Mod(..) if i.ident == keywords::Invalid.ident() => { return visit::walk_item(self, i); } - ItemKind::Mod(..) => DefPathData::Module(i.ident.name.as_str()), + ItemKind::Mod(..) => DefPathData::Module(i.ident.name.as_interned_str()), ItemKind::Static(..) | ItemKind::Const(..) | ItemKind::Fn(..) => - DefPathData::ValueNs(i.ident.name.as_str()), - ItemKind::MacroDef(..) => DefPathData::MacroDef(i.ident.name.as_str()), + DefPathData::ValueNs(i.ident.name.as_interned_str()), + ItemKind::MacroDef(..) => DefPathData::MacroDef(i.ident.name.as_interned_str()), ItemKind::Mac(..) => return self.visit_macro_invoc(i.id, false), ItemKind::GlobalAsm(..) => DefPathData::Misc, ItemKind::Use(..) => { @@ -132,7 +133,8 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { for v in &enum_definition.variants { let variant_def_index = this.create_def(v.node.data.id(), - DefPathData::EnumVariant(v.node.ident.name.as_str()), + DefPathData::EnumVariant(v.node.ident + .name.as_interned_str()), REGULAR_SPACE, v.span); this.with_parent(variant_def_index, |this| { @@ -140,7 +142,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { let name = field.ident.map(|ident| ident.name) .unwrap_or_else(|| Symbol::intern(&index.to_string())); this.create_def(field.id, - DefPathData::Field(name.as_str()), + DefPathData::Field(name.as_interned_str()), REGULAR_SPACE, field.span); } @@ -164,7 +166,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { let name = field.ident.map(|ident| ident.name) .unwrap_or_else(|| Symbol::intern(&index.to_string())); this.create_def(field.id, - DefPathData::Field(name.as_str()), + DefPathData::Field(name.as_interned_str()), REGULAR_SPACE, field.span); } @@ -186,7 +188,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { } let def = self.create_def(foreign_item.id, - DefPathData::ValueNs(foreign_item.ident.name.as_str()), + DefPathData::ValueNs(foreign_item.ident.name.as_interned_str()), REGULAR_SPACE, foreign_item.span); @@ -200,7 +202,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { GenericParam::Lifetime(ref lifetime_def) => { self.create_def( lifetime_def.lifetime.id, - DefPathData::LifetimeDef(lifetime_def.lifetime.ident.name.as_str()), + DefPathData::LifetimeDef(lifetime_def.lifetime.ident.name.as_interned_str()), REGULAR_SPACE, lifetime_def.lifetime.ident.span ); @@ -208,7 +210,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { GenericParam::Type(ref ty_param) => { self.create_def( ty_param.id, - DefPathData::TypeParam(ty_param.ident.name.as_str()), + DefPathData::TypeParam(ty_param.ident.name.as_interned_str()), REGULAR_SPACE, ty_param.ident.span ); @@ -221,8 +223,10 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { fn visit_trait_item(&mut self, ti: &'a TraitItem) { let def_data = match ti.node { TraitItemKind::Method(..) | TraitItemKind::Const(..) => - DefPathData::ValueNs(ti.ident.name.as_str()), - TraitItemKind::Type(..) => DefPathData::TypeNs(ti.ident.name.as_str()), + DefPathData::ValueNs(ti.ident.name.as_interned_str()), + TraitItemKind::Type(..) => { + DefPathData::AssocTypeInTrait(ti.ident.name.as_interned_str()) + }, TraitItemKind::Macro(..) => return self.visit_macro_invoc(ti.id, false), }; @@ -239,8 +243,8 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { fn visit_impl_item(&mut self, ii: &'a ImplItem) { let def_data = match ii.node { ImplItemKind::Method(..) | ImplItemKind::Const(..) => - DefPathData::ValueNs(ii.ident.name.as_str()), - ImplItemKind::Type(..) => DefPathData::TypeNs(ii.ident.name.as_str()), + DefPathData::ValueNs(ii.ident.name.as_interned_str()), + ImplItemKind::Type(..) => DefPathData::AssocTypeInImpl(ii.ident.name.as_interned_str()), ImplItemKind::Macro(..) => return self.visit_macro_invoc(ii.id, false), }; diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs index 1a2840de447..616dc22486d 100644 --- a/src/librustc/hir/map/definitions.rs +++ b/src/librustc/hir/map/definitions.rs @@ -212,6 +212,9 @@ impl DefKey { ::std::mem::discriminant(data).hash(&mut hasher); match *data { DefPathData::TypeNs(name) | + DefPathData::Trait(name) | + DefPathData::AssocTypeInTrait(name) | + DefPathData::AssocTypeInImpl(name) | DefPathData::ValueNs(name) | DefPathData::Module(name) | DefPathData::MacroDef(name) | @@ -358,6 +361,12 @@ pub enum DefPathData { // Different kinds of items and item-like things: /// An impl Impl, + /// A trait + Trait(InternedString), + /// An associated type **declaration** (i.e., in a trait) + AssocTypeInTrait(InternedString), + /// An associated type **value** (i.e., in an impl) + AssocTypeInImpl(InternedString), /// Something in the type NS TypeNs(InternedString), /// Something in the value NS @@ -639,6 +648,9 @@ impl DefPathData { use self::DefPathData::*; match *self { TypeNs(name) | + Trait(name) | + AssocTypeInTrait(name) | + AssocTypeInImpl(name) | ValueNs(name) | Module(name) | MacroDef(name) | @@ -663,6 +675,9 @@ impl DefPathData { use self::DefPathData::*; let s = match *self { TypeNs(name) | + Trait(name) | + AssocTypeInTrait(name) | + AssocTypeInImpl(name) | ValueNs(name) | Module(name) | MacroDef(name) | @@ -686,7 +701,7 @@ impl DefPathData { Typeof => "{{typeof}}", }; - Symbol::intern(s).as_str() + Symbol::intern(s).as_interned_str() } pub fn to_string(&self) -> String { @@ -716,7 +731,7 @@ macro_rules! define_global_metadata_kind { definitions.create_def_with_parent( CRATE_DEF_INDEX, ast::DUMMY_NODE_ID, - DefPathData::GlobalMetaData(instance.name().as_str()), + DefPathData::GlobalMetaData(instance.name().as_interned_str()), GLOBAL_MD_ADDRESS_SPACE, Mark::root(), DUMMY_SP @@ -731,7 +746,7 @@ macro_rules! define_global_metadata_kind { let def_key = DefKey { parent: Some(CRATE_DEF_INDEX), disambiguated_data: DisambiguatedDefPathData { - data: DefPathData::GlobalMetaData(self.name().as_str()), + data: DefPathData::GlobalMetaData(self.name().as_interned_str()), disambiguator: 0, } }; diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index b88185c3154..a9613a60a57 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -21,7 +21,7 @@ use hir::def_id::{CRATE_DEF_INDEX, DefId, LocalDefId, DefIndexAddressSpace}; use middle::cstore::CrateStore; -use syntax::abi::Abi; +use rustc_target::spec::abi::Abi; use syntax::ast::{self, Name, NodeId, CRATE_NODE_ID}; use syntax::codemap::Spanned; use syntax::ext::base::MacroKind; @@ -30,14 +30,11 @@ use syntax_pos::Span; use hir::*; use hir::print::Nested; use hir::svh::Svh; -use util::nodemap::{DefIdMap, FxHashMap}; +use util::nodemap::FxHashMap; -use arena::SyncTypedArena; use std::io; use ty::TyCtxt; -use rustc_data_structures::sync::Lock; - pub mod blocks; mod collector; mod def_collector; @@ -219,7 +216,6 @@ impl<'hir> MapEntry<'hir> { pub struct Forest { krate: Crate, pub dep_graph: DepGraph, - inlined_bodies: SyncTypedArena<Body> } impl Forest { @@ -227,7 +223,6 @@ impl Forest { Forest { krate, dep_graph: dep_graph.clone(), - inlined_bodies: SyncTypedArena::new() } } @@ -264,9 +259,6 @@ pub struct Map<'hir> { definitions: &'hir Definitions, - /// Bodies inlined from other crates are cached here. - inlined_bodies: Lock<DefIdMap<&'hir Body>>, - /// The reverse mapping of `node_to_hir_id`. hir_to_node_id: FxHashMap<HirId, NodeId>, } @@ -923,21 +915,6 @@ impl<'hir> Map<'hir> { } } - pub fn get_inlined_body_untracked(&self, def_id: DefId) -> Option<&'hir Body> { - self.inlined_bodies.borrow().get(&def_id).cloned() - } - - pub fn intern_inlined_body(&self, def_id: DefId, body: Body) -> &'hir Body { - let mut inlined_bodies = self.inlined_bodies.borrow_mut(); - if let Some(&b) = inlined_bodies.get(&def_id) { - debug_assert_eq!(&body, b); - return b; - } - let body = self.forest.inlined_bodies.alloc(body); - inlined_bodies.insert(def_id, body); - body - } - /// Returns the name associated with the given NodeId's AST. pub fn name(&self, id: NodeId) -> Name { match self.get(id) { @@ -1195,7 +1172,6 @@ pub fn map_crate<'hir>(sess: &::session::Session, map, hir_to_node_id, definitions, - inlined_bodies: Lock::new(DefIdMap()), }; hir_id_validator::check_crate(&map); diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index f471ffb072d..0dc89d64bd5 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -34,7 +34,7 @@ use mir::mono::Linkage; use syntax_pos::{Span, DUMMY_SP}; use syntax::codemap::{self, Spanned}; -use syntax::abi::Abi; +use rustc_target::spec::abi::Abi; use syntax::ast::{self, Name, NodeId, DUMMY_NODE_ID, AsmDialect}; use syntax::ast::{Attribute, Lit, StrStyle, FloatTy, IntTy, UintTy, MetaItem}; use syntax::attr::InlineAttr; diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index d3f2458ef87..3943c30127d 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -10,7 +10,7 @@ pub use self::AnnNode::*; -use syntax::abi::Abi; +use rustc_target::spec::abi::Abi; use syntax::ast; use syntax::codemap::{CodeMap, Spanned}; use syntax::parse::{token, ParseSess}; diff --git a/src/librustc/ich/impls_cstore.rs b/src/librustc/ich/impls_cstore.rs index d885bd43bc8..96d7cb6b041 100644 --- a/src/librustc/ich/impls_cstore.rs +++ b/src/librustc/ich/impls_cstore.rs @@ -11,8 +11,6 @@ //! This module contains `HashStable` implementations for various data types //! from rustc::middle::cstore in no particular order. -use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult}; - use middle; impl_stable_hash_for!(enum middle::cstore::DepKind { @@ -64,29 +62,3 @@ impl_stable_hash_for!(struct middle::cstore::CrateSource { rlib, rmeta }); - -impl<HCX> HashStable<HCX> for middle::cstore::ExternBodyNestedBodies { - fn hash_stable<W: StableHasherResult>(&self, - hcx: &mut HCX, - hasher: &mut StableHasher<W>) { - let middle::cstore::ExternBodyNestedBodies { - nested_bodies: _, - fingerprint, - } = *self; - - fingerprint.hash_stable(hcx, hasher); - } -} - -impl<'a, HCX> HashStable<HCX> for middle::cstore::ExternConstBody<'a> { - fn hash_stable<W: StableHasherResult>(&self, - hcx: &mut HCX, - hasher: &mut StableHasher<W>) { - let middle::cstore::ExternConstBody { - body: _, - fingerprint, - } = *self; - - fingerprint.hash_stable(hcx, hasher); - } -} diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs index c73f171806e..437626ff536 100644 --- a/src/librustc/ich/impls_mir.rs +++ b/src/librustc/ich/impls_mir.rs @@ -563,6 +563,11 @@ impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for mir::Literal<'gcx> { impl_stable_hash_for!(struct mir::Location { block, statement_index }); +impl_stable_hash_for!(struct mir::BorrowCheckResult<'tcx> { + closure_requirements, + used_mut_upvars +}); + impl_stable_hash_for!(struct mir::ClosureRegionRequirements<'tcx> { num_external_vids, outlives_requirements diff --git a/src/librustc/ich/impls_misc.rs b/src/librustc/ich/impls_misc.rs index 951315fb4a8..db404179175 100644 --- a/src/librustc/ich/impls_misc.rs +++ b/src/librustc/ich/impls_misc.rs @@ -20,7 +20,7 @@ impl_stable_hash_for!(enum ::session::search_paths::PathKind { All }); -impl_stable_hash_for!(enum ::rustc_back::PanicStrategy { +impl_stable_hash_for!(enum ::rustc_target::spec::PanicStrategy { Abort, Unwind }); diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index 4ac678aaa05..c1e86473996 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -19,7 +19,7 @@ use std::mem; use syntax::ast; use syntax::feature_gate; use syntax::parse::token; -use syntax::symbol::InternedString; +use syntax::symbol::{InternedString, LocalInternedString}; use syntax::tokenstream; use syntax_pos::FileMap; @@ -34,8 +34,7 @@ impl<'a> HashStable<StableHashingContext<'a>> for InternedString { fn hash_stable<W: StableHasherResult>(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher<W>) { - let s: &str = &**self; - s.hash_stable(hcx, hasher); + self.with(|s| s.hash_stable(hcx, hasher)) } } @@ -50,6 +49,27 @@ impl<'a> ToStableHashKey<StableHashingContext<'a>> for InternedString { } } +impl<'a> HashStable<StableHashingContext<'a>> for LocalInternedString { + #[inline] + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a>, + hasher: &mut StableHasher<W>) { + let s: &str = &**self; + s.hash_stable(hcx, hasher); + } +} + +impl<'a> ToStableHashKey<StableHashingContext<'a>> for LocalInternedString { + type KeyType = LocalInternedString; + + #[inline] + fn to_stable_hash_key(&self, + _: &StableHashingContext<'a>) + -> LocalInternedString { + self.clone() + } +} + impl<'a> HashStable<StableHashingContext<'a>> for ast::Name { #[inline] fn hash_stable<W: StableHasherResult>(&self, @@ -66,7 +86,7 @@ impl<'a> ToStableHashKey<StableHashingContext<'a>> for ast::Name { fn to_stable_hash_key(&self, _: &StableHashingContext<'a>) -> InternedString { - self.as_str() + self.as_interned_str() } } @@ -82,7 +102,7 @@ impl_stable_hash_for!(enum ::syntax::ext::base::MacroKind { }); -impl_stable_hash_for!(enum ::syntax::abi::Abi { +impl_stable_hash_for!(enum ::rustc_target::spec::abi::Abi { Cdecl, Stdcall, Fastcall, diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 70c152b40c0..5ab8d6eb7b3 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -262,8 +262,7 @@ impl<'a, 'gcx, T> HashStable<StableHashingContext<'a>> for ty::Binder<T> fn hash_stable<W: StableHasherResult>(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher<W>) { - let ty::Binder(ref inner) = *self; - inner.hash_stable(hcx, hasher); + self.skip_binder().hash_stable(hcx, hasher); } } @@ -1352,10 +1351,6 @@ impl_stable_hash_for!( } ); -impl_stable_hash_for!(struct infer::canonical::QueryRegionConstraints<'tcx> { - region_outlives, ty_outlives -}); - impl_stable_hash_for!(enum infer::canonical::Certainty { Proven, Ambiguous }); @@ -1417,6 +1412,7 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for traits::Goal<'tcx> { quantifier.hash_stable(hcx, hasher); goal.hash_stable(hcx, hasher); }, + CannotProve => { }, } } } diff --git a/src/librustc/infer/canonical.rs b/src/librustc/infer/canonical.rs index 8ea6eb005a1..4bb191a878f 100644 --- a/src/librustc/infer/canonical.rs +++ b/src/librustc/infer/canonical.rs @@ -42,7 +42,6 @@ use traits::{Obligation, ObligationCause, PredicateObligation}; use ty::{self, CanonicalVar, Lift, Region, Slice, Ty, TyCtxt, TypeFlags}; use ty::subst::{Kind, UnpackedKind}; use ty::fold::{TypeFoldable, TypeFolder}; -use util::captures::Captures; use rustc_data_structures::indexed_vec::IndexVec; use rustc_data_structures::fx::FxHashMap; @@ -121,7 +120,7 @@ pub enum CanonicalTyVarKind { #[derive(Clone, Debug)] pub struct QueryResult<'tcx, R> { pub var_values: CanonicalVarValues<'tcx>, - pub region_constraints: QueryRegionConstraints<'tcx>, + pub region_constraints: Vec<QueryRegionConstraint<'tcx>>, pub certainty: Certainty, pub value: R, } @@ -181,12 +180,7 @@ impl<'tcx, R> Canonical<'tcx, QueryResult<'tcx, R>> { } } -/// Subset of `RegionConstraintData` produced by trait query. -#[derive(Clone, Debug, Default)] -pub struct QueryRegionConstraints<'tcx> { - pub region_outlives: Vec<(Region<'tcx>, Region<'tcx>)>, - pub ty_outlives: Vec<(Ty<'tcx>, Region<'tcx>)>, -} +pub type QueryRegionConstraint<'tcx> = ty::Binder<ty::OutlivesPredicate<Kind<'tcx>, Region<'tcx>>>; /// Trait implemented by values that can be canonicalized. It mainly /// serves to identify the interning table we will use. @@ -382,35 +376,31 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { &'a self, cause: &'a ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, - unsubstituted_region_constraints: &'a QueryRegionConstraints<'tcx>, + unsubstituted_region_constraints: &'a [QueryRegionConstraint<'tcx>], result_subst: &'a CanonicalVarValues<'tcx>, - ) -> impl Iterator<Item = PredicateObligation<'tcx>> + Captures<'gcx> + 'a { - let QueryRegionConstraints { - region_outlives, - ty_outlives, - } = unsubstituted_region_constraints; - - let region_obligations = region_outlives.iter().map(move |(r1, r2)| { - let r1 = substitute_value(self.tcx, result_subst, r1); - let r2 = substitute_value(self.tcx, result_subst, r2); - Obligation::new( - cause.clone(), - param_env, - ty::Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(r1, r2))), - ) - }); - - let ty_obligations = ty_outlives.iter().map(move |(t1, r2)| { - let t1 = substitute_value(self.tcx, result_subst, t1); + ) -> impl Iterator<Item = PredicateObligation<'tcx>> + 'a { + Box::new(unsubstituted_region_constraints.iter().map(move |constraint| { + let ty::OutlivesPredicate(k1, r2) = constraint.skip_binder(); // restored below + let k1 = substitute_value(self.tcx, result_subst, k1); let r2 = substitute_value(self.tcx, result_subst, r2); - Obligation::new( - cause.clone(), - param_env, - ty::Predicate::TypeOutlives(ty::Binder(ty::OutlivesPredicate(t1, r2))), - ) - }); - - region_obligations.chain(ty_obligations) + match k1.unpack() { + UnpackedKind::Lifetime(r1) => + Obligation::new( + cause.clone(), + param_env, + ty::Predicate::RegionOutlives( + ty::Binder::dummy(ty::OutlivesPredicate(r1, r2))), + ), + + UnpackedKind::Type(t1) => + Obligation::new( + cause.clone(), + param_env, + ty::Predicate::TypeOutlives( + ty::Binder::dummy(ty::OutlivesPredicate(t1, r2))), + ), + } + })) as Box<dyn Iterator<Item = _>> } /// Given two sets of values for the same set of canonical variables, unify them. @@ -914,19 +904,6 @@ BraceStructTypeFoldableImpl! { } BraceStructTypeFoldableImpl! { - impl<'tcx> TypeFoldable<'tcx> for QueryRegionConstraints<'tcx> { - region_outlives, ty_outlives - } -} - -BraceStructLiftImpl! { - impl<'a, 'tcx> Lift<'tcx> for QueryRegionConstraints<'a> { - type Lifted = QueryRegionConstraints<'tcx>; - region_outlives, ty_outlives - } -} - -BraceStructTypeFoldableImpl! { impl<'tcx, R> TypeFoldable<'tcx> for QueryResult<'tcx, R> { var_values, region_constraints, certainty, value } where R: TypeFoldable<'tcx>, diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs index c2167751a27..096aed85f55 100644 --- a/src/librustc/infer/combine.rs +++ b/src/librustc/infer/combine.rs @@ -302,7 +302,7 @@ struct Generalizer<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> { /// Result from a generalization operation. This includes /// not only the generalized type, but also a bool flag -/// indicating whether further WF checks are needed.q +/// indicating whether further WF checks are needed. struct Generalization<'tcx> { ty: Ty<'tcx>, @@ -351,7 +351,7 @@ impl<'cx, 'gcx, 'tcx> TypeRelation<'cx, 'gcx, 'tcx> for Generalizer<'cx, 'gcx, ' -> RelateResult<'tcx, ty::Binder<T>> where T: Relate<'tcx> { - Ok(ty::Binder(self.relate(a.skip_binder(), b.skip_binder())?)) + Ok(ty::Binder::bind(self.relate(a.skip_binder(), b.skip_binder())?)) } fn relate_item_substs(&mut self, diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index d8a2c95ab59..588f75f809c 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -916,7 +916,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { }; if let (Some(def_id), Some(ret_ty)) = (def_id, ret_ty) { - if exp_is_struct && exp_found.expected == ret_ty.0 { + if exp_is_struct && &exp_found.expected == ret_ty.skip_binder() { let message = format!( "did you mean `{}(/* fields */)`?", self.tcx.item_path_str(def_id) diff --git a/src/librustc/infer/higher_ranked/mod.rs b/src/librustc/infer/higher_ranked/mod.rs index d44f2ec9549..c35cdf91fe7 100644 --- a/src/librustc/infer/higher_ranked/mod.rs +++ b/src/librustc/infer/higher_ranked/mod.rs @@ -19,7 +19,7 @@ use super::{CombinedSnapshot, use super::combine::CombineFields; use super::region_constraints::{TaintDirections}; -use std::collections::BTreeMap; +use rustc_data_structures::lazy_btree_map::LazyBTreeMap; use ty::{self, TyCtxt, Binder, TypeFoldable}; use ty::error::TypeError; use ty::relate::{Relate, RelateResult, TypeRelation}; @@ -80,7 +80,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { debug!("higher_ranked_sub: OK result={:?}", result); - Ok(ty::Binder(result)) + Ok(ty::Binder::bind(result)) }); } @@ -239,7 +239,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { b, result1); - Ok(ty::Binder(result1)) + Ok(ty::Binder::bind(result1)) }); fn generalize_region<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, @@ -247,7 +247,8 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { snapshot: &CombinedSnapshot<'a, 'tcx>, debruijn: ty::DebruijnIndex, new_vars: &[ty::RegionVid], - a_map: &BTreeMap<ty::BoundRegion, ty::Region<'tcx>>, + a_map: &LazyBTreeMap<ty::BoundRegion, + ty::Region<'tcx>>, r0: ty::Region<'tcx>) -> ty::Region<'tcx> { // Regions that pre-dated the LUB computation stay as they are. @@ -335,7 +336,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { b, result1); - Ok(ty::Binder(result1)) + Ok(ty::Binder::bind(result1)) }); fn generalize_region<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, @@ -343,7 +344,8 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { snapshot: &CombinedSnapshot<'a, 'tcx>, debruijn: ty::DebruijnIndex, new_vars: &[ty::RegionVid], - a_map: &BTreeMap<ty::BoundRegion, ty::Region<'tcx>>, + a_map: &LazyBTreeMap<ty::BoundRegion, + ty::Region<'tcx>>, a_vars: &[ty::RegionVid], b_vars: &[ty::RegionVid], r0: ty::Region<'tcx>) @@ -412,7 +414,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { fn rev_lookup<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, span: Span, - a_map: &BTreeMap<ty::BoundRegion, ty::Region<'tcx>>, + a_map: &LazyBTreeMap<ty::BoundRegion, ty::Region<'tcx>>, r: ty::Region<'tcx>) -> ty::Region<'tcx> { for (a_br, a_r) in a_map { @@ -435,7 +437,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { } fn var_ids<'a, 'gcx, 'tcx>(fields: &CombineFields<'a, 'gcx, 'tcx>, - map: &BTreeMap<ty::BoundRegion, ty::Region<'tcx>>) + map: &LazyBTreeMap<ty::BoundRegion, ty::Region<'tcx>>) -> Vec<ty::RegionVid> { map.iter() .map(|(_, &r)| match *r { diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 40cc43c3ca6..553926dba8f 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -28,9 +28,9 @@ use ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric}; use ty::fold::TypeFoldable; use ty::relate::RelateResult; use traits::{self, ObligationCause, PredicateObligations}; +use rustc_data_structures::lazy_btree_map::LazyBTreeMap; use rustc_data_structures::unify as ut; use std::cell::{Cell, RefCell, Ref, RefMut}; -use std::collections::BTreeMap; use std::fmt; use syntax::ast; use errors::DiagnosticBuilder; @@ -187,7 +187,7 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { /// A map returned by `skolemize_late_bound_regions()` indicating the skolemized /// region that each late-bound region was replaced with. -pub type SkolemizationMap<'tcx> = BTreeMap<ty::BoundRegion, ty::Region<'tcx>>; +pub type SkolemizationMap<'tcx> = LazyBTreeMap<ty::BoundRegion, ty::Region<'tcx>>; /// See `error_reporting` module for more details #[derive(Clone, Debug)] @@ -1216,7 +1216,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { span: Span, lbrct: LateBoundRegionConversionTime, value: &ty::Binder<T>) - -> (T, BTreeMap<ty::BoundRegion, ty::Region<'tcx>>) + -> (T, LazyBTreeMap<ty::BoundRegion, ty::Region<'tcx>>) where T : TypeFoldable<'tcx> { self.tcx.replace_late_bound_regions( diff --git a/src/librustc/infer/sub.rs b/src/librustc/infer/sub.rs index f891f692c7d..58eae5e6a5b 100644 --- a/src/librustc/infer/sub.rs +++ b/src/librustc/infer/sub.rs @@ -98,7 +98,7 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> self.fields.trace.cause.clone(), self.fields.param_env, ty::Predicate::Subtype( - ty::Binder(ty::SubtypePredicate { + ty::Binder::dummy(ty::SubtypePredicate { a_is_expected: self.a_is_expected, a, b, diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index a2cefe488c6..24892dfcc8f 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -45,18 +45,20 @@ #![feature(const_fn)] #![feature(core_intrinsics)] #![feature(drain_filter)] -#![feature(dyn_trait)] #![feature(entry_or_default)] +#![cfg_attr(stage0, feature(dyn_trait))] #![feature(from_ref)] #![feature(fs_read_write)] #![cfg_attr(windows, feature(libc))] #![feature(macro_lifetime_matcher)] #![feature(macro_vis_matcher)] +#![feature(never_type)] #![feature(exhaustive_patterns)] #![feature(non_exhaustive)] #![feature(nonzero)] #![feature(proc_macro_internals)] #![feature(quote)] +#![feature(optin_builtin_traits)] #![feature(refcell_replace_swap)] #![feature(rustc_diagnostic_macros)] #![feature(slice_patterns)] @@ -80,7 +82,7 @@ extern crate graphviz; #[macro_use] extern crate lazy_static; #[cfg(windows)] extern crate libc; -extern crate rustc_back; +extern crate rustc_target; #[macro_use] extern crate rustc_data_structures; extern crate serialize; extern crate rustc_const_math; diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 97cfcf0f607..109edffcde3 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -255,6 +255,13 @@ declare_lint! { } declare_lint! { + pub ABSOLUTE_PATH_STARTING_WITH_MODULE, + Allow, + "fully qualified paths that start with a module name \ + instead of `crate`, `self`, or an extern crate name" +} + +declare_lint! { pub ILLEGAL_FLOATING_POINT_LITERAL_PATTERN, Warn, "floating-point literals cannot be used in patterns" @@ -314,6 +321,7 @@ impl LintPass for HardwiredLints { TYVAR_BEHIND_RAW_POINTER, ELIDED_LIFETIME_IN_PATH, BARE_TRAIT_OBJECT, + ABSOLUTE_PATH_STARTING_WITH_MODULE, UNSTABLE_NAME_COLLISION, ) } @@ -324,7 +332,8 @@ impl LintPass for HardwiredLints { #[derive(PartialEq, RustcEncodable, RustcDecodable, Debug)] pub enum BuiltinLintDiagnostics { Normal, - BareTraitObject(Span, /* is_global */ bool) + BareTraitObject(Span, /* is_global */ bool), + AbsPathWithModule(Span), } impl BuiltinLintDiagnostics { @@ -339,6 +348,23 @@ impl BuiltinLintDiagnostics { }; db.span_suggestion(span, "use `dyn`", sugg); } + BuiltinLintDiagnostics::AbsPathWithModule(span) => { + let sugg = match sess.codemap().span_to_snippet(span) { + Ok(ref s) => { + // FIXME(Manishearth) ideally the emitting code + // can tell us whether or not this is global + let opt_colon = if s.trim_left().starts_with("::") { + "" + } else { + "::" + }; + + format!("crate{}{}", opt_colon, s) + } + Err(_) => format!("crate::<path>") + }; + db.span_suggestion(span, "use `crate`", sugg); + } } } } diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index d5849ea22b1..f90baa2ccd9 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -657,7 +657,8 @@ impl<'a, 'tcx> LateContext<'a, 'tcx> { } } -impl<'a, 'tcx> LayoutOf<Ty<'tcx>> for &'a LateContext<'a, 'tcx> { +impl<'a, 'tcx> LayoutOf for &'a LateContext<'a, 'tcx> { + type Ty = Ty<'tcx>; type TyLayout = Result<TyLayout<'tcx>, LayoutError<'tcx>>; fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout { diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 292ec184dfa..4400ebc294f 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -22,25 +22,22 @@ //! are *mostly* used as a part of that interface, but these should //! probably get a better home if someone can find one. -use hir; use hir::def; use hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use hir::map as hir_map; use hir::map::definitions::{Definitions, DefKey, DefPathTable}; use hir::svh::Svh; -use ich; use ty::{self, TyCtxt}; use session::{Session, CrateDisambiguator}; use session::search_paths::PathKind; use std::any::Any; -use std::collections::BTreeMap; use std::path::{Path, PathBuf}; use syntax::ast; use syntax::ext::base::SyntaxExtension; use syntax::symbol::Symbol; use syntax_pos::Span; -use rustc_back::target::Target; +use rustc_target::spec::Target; use rustc_data_structures::sync::{MetadataRef, Lrc}; pub use self::NativeLibraryKind::*; @@ -209,26 +206,6 @@ pub trait MetadataLoader { -> Result<MetadataRef, String>; } -#[derive(Clone)] -pub struct ExternConstBody<'tcx> { - pub body: &'tcx hir::Body, - - // It would require a lot of infrastructure to enable stable-hashing Bodies - // from other crates, so we hash on export and just store the fingerprint - // with them. - pub fingerprint: ich::Fingerprint, -} - -#[derive(Clone)] -pub struct ExternBodyNestedBodies { - pub nested_bodies: Lrc<BTreeMap<hir::BodyId, hir::Body>>, - - // It would require a lot of infrastructure to enable stable-hashing Bodies - // from other crates, so we hash on export and just store the fingerprint - // with them. - pub fingerprint: ich::Fingerprint, -} - /// A store of Rust crates, through with their metadata /// can be accessed. /// diff --git a/src/librustc/middle/dependency_format.rs b/src/librustc/middle/dependency_format.rs index e7fc8d633c8..4996a6acff8 100644 --- a/src/librustc/middle/dependency_format.rs +++ b/src/librustc/middle/dependency_format.rs @@ -69,7 +69,7 @@ use ty::TyCtxt; use middle::cstore::{self, DepKind}; use middle::cstore::LinkagePreference::{self, RequireStatic, RequireDynamic}; use util::nodemap::FxHashMap; -use rustc_back::PanicStrategy; +use rustc_target::spec::PanicStrategy; /// A list of dependencies for a certain crate type. /// diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs index 0a4e5094cde..27f7dbf508d 100644 --- a/src/librustc/middle/intrinsicck.rs +++ b/src/librustc/middle/intrinsicck.rs @@ -13,7 +13,7 @@ use hir::def_id::DefId; use ty::{self, Ty, TyCtxt}; use ty::layout::{LayoutError, Pointer, SizeSkeleton}; -use syntax::abi::Abi::RustIntrinsic; +use rustc_target::spec::abi::Abi::RustIntrinsic; use syntax_pos::Span; use hir::intravisit::{self, Visitor, NestedVisitorMap}; use hir; diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 3b37031cf46..95e92e21b09 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -214,6 +214,9 @@ language_item_table! { StrImplItem, "str", str_impl; SliceImplItem, "slice", slice_impl; SliceU8ImplItem, "slice_u8", slice_u8_impl; + StrAllocImplItem, "str_alloc", str_alloc_impl; + SliceAllocImplItem, "slice_alloc", slice_alloc_impl; + SliceU8AllocImplItem, "slice_u8_alloc", slice_u8_alloc_impl; ConstPtrImplItem, "const_ptr", const_ptr_impl; MutPtrImplItem, "mut_ptr", mut_ptr_impl; I8ImplItem, "i8", i8_impl; @@ -230,6 +233,8 @@ language_item_table! { UsizeImplItem, "usize", usize_impl; F32ImplItem, "f32", f32_impl; F64ImplItem, "f64", f64_impl; + F32RuntimeImplItem, "f32_runtime", f32_runtime_impl; + F64RuntimeImplItem, "f64_runtime", f64_runtime_impl; SizedTraitLangItem, "sized", sized_trait; UnsizeTraitLangItem, "unsize", unsize_trait; @@ -298,7 +303,8 @@ language_item_table! { ExchangeMallocFnLangItem, "exchange_malloc", exchange_malloc_fn; BoxFreeFnLangItem, "box_free", box_free_fn; - DropInPlaceFnLangItem, "drop_in_place", drop_in_place_fn; + DropInPlaceFnLangItem, "drop_in_place", drop_in_place_fn; + OomLangItem, "oom", oom; StartFnLangItem, "start", start_fn; diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 11dc2a81885..17c114bc3b3 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -184,6 +184,7 @@ impl<'a, 'tcx> Visitor<'tcx> for IrMaps<'a, 'tcx> { b: hir::BodyId, s: Span, id: NodeId) { visit_fn(self, fk, fd, b, s, id); } + fn visit_local(&mut self, l: &'tcx hir::Local) { visit_local(self, l); } fn visit_expr(&mut self, ex: &'tcx Expr) { visit_expr(self, ex); } fn visit_arm(&mut self, a: &'tcx hir::Arm) { visit_arm(self, a); } @@ -361,6 +362,16 @@ fn visit_fn<'a, 'tcx: 'a>(ir: &mut IrMaps<'a, 'tcx>, // swap in a new set of IR maps for this function body: let mut fn_maps = IrMaps::new(ir.tcx); + // Don't run unused pass for #[derive()] + if let FnKind::Method(..) = fk { + let parent = ir.tcx.hir.get_parent(id); + if let Some(hir::map::Node::NodeItem(i)) = ir.tcx.hir.find(parent) { + if i.attrs.iter().any(|a| a.check_name("automatically_derived")) { + return; + } + } + } + debug!("creating fn_maps: {:?}", &fn_maps as *const IrMaps); let body = ir.tcx.hir.body(body_id); diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 48a62c8c14d..0aeb15b49fb 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -26,7 +26,7 @@ use middle::privacy; use session::config; use util::nodemap::{NodeSet, FxHashSet}; -use syntax::abi::Abi; +use rustc_target::spec::abi::Abi; use syntax::ast; use syntax::attr; use hir; diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 42483c83f4b..5f4efbeeaa8 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -22,6 +22,7 @@ use ty; use std::fmt; use std::mem; +use rustc_data_structures::small_vec::SmallVec; use rustc_data_structures::sync::Lrc; use syntax::codemap; use syntax::ast; @@ -677,96 +678,75 @@ impl<'tcx> ScopeTree { -> Scope { if scope_a == scope_b { return scope_a; } - // [1] The initial values for `a_buf` and `b_buf` are not used. - // The `ancestors_of` function will return some prefix that - // is re-initialized with new values (or else fallback to a - // heap-allocated vector). - let mut a_buf: [Scope; 32] = [scope_a /* [1] */; 32]; - let mut a_vec: Vec<Scope> = vec![]; - let mut b_buf: [Scope; 32] = [scope_b /* [1] */; 32]; - let mut b_vec: Vec<Scope> = vec![]; - let parent_map = &self.parent_map; - let a_ancestors = ancestors_of(parent_map, scope_a, &mut a_buf, &mut a_vec); - let b_ancestors = ancestors_of(parent_map, scope_b, &mut b_buf, &mut b_vec); - let mut a_index = a_ancestors.len() - 1; - let mut b_index = b_ancestors.len() - 1; - - // Here, [ab]_ancestors is a vector going from narrow to broad. - // The end of each vector will be the item where the scope is - // defined; if there are any common ancestors, then the tails of - // the vector will be the same. So basically we want to walk - // backwards from the tail of each vector and find the first point - // where they diverge. If one vector is a suffix of the other, - // then the corresponding scope is a superscope of the other. - - if a_ancestors[a_index] != b_ancestors[b_index] { - // In this case, the two regions belong to completely - // different functions. Compare those fn for lexical - // nesting. The reasoning behind this is subtle. See the - // "Modeling closures" section of the README in - // infer::region_constraints for more details. - let a_root_scope = a_ancestors[a_index]; - let b_root_scope = a_ancestors[a_index]; - return match (a_root_scope.data(), b_root_scope.data()) { - (ScopeData::Destruction(a_root_id), - ScopeData::Destruction(b_root_id)) => { - if self.closure_is_enclosed_by(a_root_id, b_root_id) { - // `a` is enclosed by `b`, hence `b` is the ancestor of everything in `a` - scope_b - } else if self.closure_is_enclosed_by(b_root_id, a_root_id) { - // `b` is enclosed by `a`, hence `a` is the ancestor of everything in `b` - scope_a - } else { - // neither fn encloses the other - bug!() - } + // Process the lists in tandem from the innermost scope, recording the + // scopes seen so far. The first scope that comes up for a second time + // is the nearest common ancestor. + // + // Note: another way to compute the nearest common ancestor is to get + // the full scope chain for both scopes and then compare the chains to + // find the first scope in a common tail. But getting a parent scope + // requires a hash table lookup, and we often have very long scope + // chains (10s or 100s of scopes) that only differ by a few elements at + // the start. So this algorithm is faster. + let mut ma = Some(scope_a); + let mut mb = Some(scope_b); + let mut seen: SmallVec<[Scope; 32]> = SmallVec::new(); + loop { + if let Some(a) = ma { + if seen.iter().position(|s| *s == a).is_some() { + return a; } - _ => { - // root ids are always Node right now - bug!() + seen.push(a); + ma = self.parent_map.get(&a).map(|s| *s); + } + + if let Some(b) = mb { + if seen.iter().position(|s| *s == b).is_some() { + return b; } - }; - } + seen.push(b); + mb = self.parent_map.get(&b).map(|s| *s); + } - loop { - // Loop invariant: a_ancestors[a_index] == b_ancestors[b_index] - // for all indices between a_index and the end of the array - if a_index == 0 { return scope_a; } - if b_index == 0 { return scope_b; } - a_index -= 1; - b_index -= 1; - if a_ancestors[a_index] != b_ancestors[b_index] { - return a_ancestors[a_index + 1]; + if ma.is_none() && mb.is_none() { + break; } - } + }; - fn ancestors_of<'a, 'tcx>(parent_map: &FxHashMap<Scope, Scope>, - scope: Scope, - buf: &'a mut [Scope; 32], - vec: &'a mut Vec<Scope>) - -> &'a [Scope] { - // debug!("ancestors_of(scope={:?})", scope); + fn outermost_scope(parent_map: &FxHashMap<Scope, Scope>, scope: Scope) -> Scope { let mut scope = scope; - - let mut i = 0; - while i < 32 { - buf[i] = scope; - match parent_map.get(&scope) { - Some(&superscope) => scope = superscope, - _ => return &buf[..i+1] - } - i += 1; + loop { + match parent_map.get(&scope) { + Some(&superscope) => scope = superscope, + None => break scope, + } } + } - *vec = Vec::with_capacity(64); - vec.extend_from_slice(buf); - loop { - vec.push(scope); - match parent_map.get(&scope) { - Some(&superscope) => scope = superscope, - _ => return &*vec + // In this (rare) case, the two regions belong to completely different + // functions. Compare those fn for lexical nesting. The reasoning + // behind this is subtle. See the "Modeling closures" section of the + // README in infer::region_constraints for more details. + let a_root_scope = outermost_scope(&self.parent_map, scope_a); + let b_root_scope = outermost_scope(&self.parent_map, scope_b); + match (a_root_scope.data(), b_root_scope.data()) { + (ScopeData::Destruction(a_root_id), + ScopeData::Destruction(b_root_id)) => { + if self.closure_is_enclosed_by(a_root_id, b_root_id) { + // `a` is enclosed by `b`, hence `b` is the ancestor of everything in `a` + scope_b + } else if self.closure_is_enclosed_by(b_root_id, a_root_id) { + // `b` is enclosed by `a`, hence `a` is the ancestor of everything in `b` + scope_a + } else { + // neither fn encloses the other + bug!() } } + _ => { + // root ids are always Node right now + bug!() + } } } diff --git a/src/librustc/middle/weak_lang_items.rs b/src/librustc/middle/weak_lang_items.rs index e19f4483f65..42e4d3861ba 100644 --- a/src/librustc/middle/weak_lang_items.rs +++ b/src/librustc/middle/weak_lang_items.rs @@ -13,7 +13,7 @@ use session::config; use middle::lang_items; -use rustc_back::PanicStrategy; +use rustc_target::spec::PanicStrategy; use syntax::ast; use syntax::symbol::Symbol; use syntax_pos::Span; @@ -151,4 +151,5 @@ weak_lang_items! { panic_fmt, PanicFmtLangItem, rust_begin_unwind; eh_personality, EhPersonalityLangItem, rust_eh_personality; eh_unwind_resume, EhUnwindResumeLangItem, rust_eh_unwind_resume; + oom, OomLangItem, rust_oom; } diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index c525c4ed651..c26b3014e53 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -21,6 +21,7 @@ use rustc_data_structures::indexed_vec::{IndexVec, Idx}; use rustc_data_structures::control_flow_graph::dominators::{Dominators, dominators}; use rustc_data_structures::control_flow_graph::{GraphPredecessors, GraphSuccessors}; use rustc_data_structures::control_flow_graph::ControlFlowGraph; +use rustc_data_structures::small_vec::SmallVec; use rustc_serialize as serialize; use hir::def::CtorKind; use hir::def_id::DefId; @@ -247,6 +248,22 @@ impl<'tcx> Mir<'tcx> { }) } + /// Returns an iterator over all user-declared mutable arguments and locals. + #[inline] + pub fn mut_vars_and_args_iter<'a>(&'a self) -> impl Iterator<Item=Local> + 'a { + (1..self.local_decls.len()).filter_map(move |index| { + let local = Local::new(index); + let decl = &self.local_decls[local]; + if (decl.is_user_variable || index < self.arg_count + 1) + && decl.mutability == Mutability::Mut + { + Some(local) + } else { + None + } + }) + } + /// Returns an iterator over all function arguments. #[inline] pub fn args_iter(&self) -> impl Iterator<Item=Local> { @@ -2029,6 +2046,12 @@ pub struct GeneratorLayout<'tcx> { pub fields: Vec<LocalDecl<'tcx>>, } +#[derive(Clone, Debug, RustcEncodable, RustcDecodable)] +pub struct BorrowCheckResult<'gcx> { + pub closure_requirements: Option<ClosureRegionRequirements<'gcx>>, + pub used_mut_upvars: SmallVec<[Field; 8]>, +} + /// After we borrow check a closure, we are left with various /// requirements that we have inferred between the free regions that /// appear in the closure's signature or on its field types. These diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 59823390a0a..ab703d423c6 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -16,19 +16,21 @@ pub use self::CrateType::*; pub use self::Passes::*; pub use self::DebugInfoLevel::*; +use std::str::FromStr; + use session::{early_error, early_warn, Session}; use session::search_paths::SearchPaths; use ich::StableHashingContext; -use rustc_back::{LinkerFlavor, PanicStrategy, RelroLevel}; -use rustc_back::target::{Target, TargetTriple}; +use rustc_target::spec::{LinkerFlavor, PanicStrategy, RelroLevel}; +use rustc_target::spec::{Target, TargetTriple}; use rustc_data_structures::stable_hasher::ToStableHashKey; use lint; use middle::cstore; use syntax::ast::{self, IntTy, UintTy}; use syntax::codemap::{FileName, FilePathMapping}; -use syntax::edition::Edition; +use syntax::edition::{Edition, EDITION_NAME_LIST, DEFAULT_EDITION}; use syntax::parse::token; use syntax::parse; use syntax::symbol::Symbol; @@ -410,6 +412,7 @@ top_level_options!( // Remap source path prefixes in all output (messages, object files, debug, etc) remap_path_prefix: Vec<(PathBuf, PathBuf)> [UNTRACKED], + edition: Edition [TRACKED], } ); @@ -589,6 +592,7 @@ pub fn basic_options() -> Options { cli_forced_codegen_units: None, cli_forced_thinlto_off: false, remap_path_prefix: Vec::new(), + edition: DEFAULT_EDITION, } } @@ -766,23 +770,20 @@ macro_rules! options { pub const parse_sanitizer: Option<&'static str> = Some("one of: `address`, `leak`, `memory` or `thread`"); pub const parse_linker_flavor: Option<&'static str> = - Some(::rustc_back::LinkerFlavor::one_of()); + Some(::rustc_target::spec::LinkerFlavor::one_of()); pub const parse_optimization_fuel: Option<&'static str> = Some("crate=integer"); pub const parse_unpretty: Option<&'static str> = Some("`string` or `string=string`"); pub const parse_lto: Option<&'static str> = Some("one of `thin`, `fat`, or omitted"); - pub const parse_edition: Option<&'static str> = - Some("one of: `2015`, `2018`"); } #[allow(dead_code)] mod $mod_set { use super::{$struct_name, Passes, SomePasses, AllPasses, Sanitizer, Lto}; - use rustc_back::{LinkerFlavor, PanicStrategy, RelroLevel}; + use rustc_target::spec::{LinkerFlavor, PanicStrategy, RelroLevel}; use std::path::PathBuf; - use syntax::edition::Edition; $( pub fn $opt(cg: &mut $struct_name, v: Option<&str>) -> bool { @@ -985,20 +986,6 @@ macro_rules! options { true } - fn parse_edition(slot: &mut Edition, v: Option<&str>) -> bool { - match v { - Some(s) => { - let edition = s.parse(); - if let Ok(parsed) = edition { - *slot = parsed; - true - } else { - false - } - } - _ => false, - } - } } ) } @@ -1259,6 +1246,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, useful for profiling / PGO."), relro_level: Option<RelroLevel> = (None, parse_relro_level, [TRACKED], "choose which RELRO level to use"), + nll_subminimal_causes: bool = (false, parse_bool, [UNTRACKED], + "when tracking region error causes, accept subminimal results for faster execution."), disable_nll_user_type_assert: bool = (false, parse_bool, [UNTRACKED], "disable user provided type assertion in NLL"), trans_time_graph: bool = (false, parse_bool, [UNTRACKED], @@ -1290,10 +1279,6 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, `everybody_loops` (all function bodies replaced with `loop {}`), `hir` (the HIR), `hir,identified`, or `hir,typed` (HIR with types for each node)."), - edition: Edition = (Edition::Edition2015, parse_edition, [TRACKED], - "The edition to build Rust with. Newer editions may include features - that require breaking changes. The default edition is 2015 (the first - edition). Crates compiled with different editions can be linked together."), run_dsymutil: Option<bool> = (None, parse_opt_bool, [TRACKED], "run `dsymutil` and delete intermediate object files"), ui_testing: bool = (false, parse_bool, [UNTRACKED], @@ -1304,6 +1289,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "tell the linker to strip debuginfo when building without debuginfo enabled."), share_generics: Option<bool> = (None, parse_opt_bool, [TRACKED], "make the current crate share its generic instantiations"), + chalk: bool = (false, parse_bool, [TRACKED], + "enable the experimental Chalk-based trait solving engine"), } pub fn default_lib_output() -> CrateType { @@ -1654,6 +1641,12 @@ pub fn rustc_optgroups() -> Vec<RustcOptGroup> { `expanded,identified` (fully parenthesized, AST nodes with IDs).", "TYPE", ), + opt::opt_s( + "", + "edition", + "Specify which edition of the compiler to use when compiling code.", + EDITION_NAME_LIST, + ), opt::multi_s( "", "remap-path-prefix", @@ -1713,6 +1706,34 @@ pub fn build_session_options_and_crate_config( ), }; + let edition = match matches.opt_str("edition") { + Some(arg) => match Edition::from_str(&arg){ + Ok(edition) => edition, + Err(_) => early_error( + ErrorOutputType::default(), + &format!( + "argument for --edition must be one of: \ + {}. (instead was `{}`)", + EDITION_NAME_LIST, + arg + ), + ), + } + None => DEFAULT_EDITION, + }; + + if !edition.is_stable() && !nightly_options::is_nightly_build() { + early_error( + ErrorOutputType::default(), + &format!( + "Edition {} is unstable an only\ + available for nightly builds of rustc.", + edition, + ) + ) + } + + // We need the opts_present check because the driver will send us Matches // with only stable options if no unstable options are used. Since error-format // is unstable, it will not be present. We have to use opts_present not @@ -2169,6 +2190,7 @@ pub fn build_session_options_and_crate_config( cli_forced_codegen_units: codegen_units, cli_forced_thinlto_off: disable_thinlto, remap_path_prefix, + edition, }, cfg, ) @@ -2298,11 +2320,11 @@ mod dep_tracking { use std::hash::Hash; use std::path::PathBuf; use std::collections::hash_map::DefaultHasher; - use super::{CrateType, DebugInfoLevel, Edition, ErrorOutputType, Lto, OptLevel, OutputTypes, + use super::{CrateType, DebugInfoLevel, ErrorOutputType, Lto, OptLevel, OutputTypes, Passes, Sanitizer}; use syntax::feature_gate::UnstableFeatures; - use rustc_back::{PanicStrategy, RelroLevel}; - use rustc_back::target::TargetTriple; + use rustc_target::spec::{PanicStrategy, RelroLevel, TargetTriple}; + use syntax::edition::Edition; pub trait DepTrackingHash { fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType); @@ -2361,8 +2383,8 @@ mod dep_tracking { impl_dep_tracking_hash_via_hash!(cstore::NativeLibraryKind); impl_dep_tracking_hash_via_hash!(Sanitizer); impl_dep_tracking_hash_via_hash!(Option<Sanitizer>); - impl_dep_tracking_hash_via_hash!(Edition); impl_dep_tracking_hash_via_hash!(TargetTriple); + impl_dep_tracking_hash_via_hash!(Edition); impl_dep_tracking_hash_for_sortable_vec_of!(String); impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf); @@ -2433,8 +2455,9 @@ mod tests { use std::iter::FromIterator; use std::path::PathBuf; use super::{Externs, OutputType, OutputTypes}; - use rustc_back::{PanicStrategy, RelroLevel}; + use rustc_target::spec::{PanicStrategy, RelroLevel}; use syntax::symbol::Symbol; + use syntax::edition::{Edition, DEFAULT_EDITION}; use syntax; fn optgroups() -> getopts::Options { @@ -3079,4 +3102,17 @@ mod tests { opts.debugging_opts.relro_level = Some(RelroLevel::Full); assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash()); } + + #[test] + fn test_edition_parsing() { + // test default edition + let options = super::basic_options(); + assert!(options.edition == DEFAULT_EDITION); + + let matches = optgroups() + .parse(&["--edition=2018".to_string()]) + .unwrap(); + let (sessopts, _) = build_session_options_and_crate_config(&matches); + assert!(sessopts.edition == Edition::Edition2018) + } } diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 696bd736594..a0f11443425 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -26,7 +26,7 @@ use util::nodemap::{FxHashSet}; use util::common::{duration_to_secs_str, ErrorReported}; use util::common::ProfileQueriesMsg; -use rustc_data_structures::sync::{Lrc, Lock, LockCell, OneThread, Once, RwLock}; +use rustc_data_structures::sync::{self, Lrc, Lock, LockCell, OneThread, Once, RwLock}; use syntax::ast::NodeId; use errors::{self, DiagnosticBuilder, DiagnosticId}; @@ -41,8 +41,8 @@ use syntax::{ast, codemap}; use syntax::feature_gate::AttributeType; use syntax_pos::{MultiSpan, Span}; -use rustc_back::{LinkerFlavor, PanicStrategy}; -use rustc_back::target::{Target, TargetTriple}; +use rustc_target::spec::{LinkerFlavor, PanicStrategy}; +use rustc_target::spec::{Target, TargetTriple}; use rustc_data_structures::flock; use jobserver::Client; @@ -89,7 +89,7 @@ pub struct Session { /// Set of (DiagnosticId, Option<Span>, message) tuples tracking /// (sub)diagnostics that have been set once, but should not be set again, /// in order to avoid redundantly verbose output (Issue #24690, #44953). - pub one_time_diagnostics: RefCell<FxHashSet<(DiagnosticMessageId, Option<Span>, String)>>, + pub one_time_diagnostics: Lock<FxHashSet<(DiagnosticMessageId, Option<Span>, String)>>, pub plugin_llvm_passes: OneThread<RefCell<Vec<String>>>, pub plugin_attributes: OneThread<RefCell<Vec<(String, AttributeType)>>>, pub crate_types: Once<Vec<config::CrateType>>, @@ -156,7 +156,7 @@ pub struct Session { /// Loaded up early on in the initialization of this `Session` to avoid /// false positives about a job server in our environment. - pub jobserver_from_env: Option<Client>, + pub jobserver: Client, /// Metadata about the allocators for the current crate being compiled pub has_global_allocator: Once<bool>, @@ -929,16 +929,16 @@ impl Session { } pub fn teach(&self, code: &DiagnosticId) -> bool { - self.opts.debugging_opts.teach && !self.parse_sess.span_diagnostic.code_emitted(code) + self.opts.debugging_opts.teach && self.parse_sess.span_diagnostic.must_teach(code) } /// Are we allowed to use features from the Rust 2018 edition? pub fn rust_2018(&self) -> bool { - self.opts.debugging_opts.edition >= Edition::Edition2018 + self.opts.edition >= Edition::Edition2018 } pub fn edition(&self) -> Edition { - self.opts.debugging_opts.edition + self.opts.edition } } @@ -983,7 +983,7 @@ pub fn build_session_with_codemap( let external_macro_backtrace = sopts.debugging_opts.external_macro_backtrace; - let emitter: Box<dyn Emitter> = + let emitter: Box<dyn Emitter + sync::Send> = match (sopts.error_format, emitter_dest) { (config::ErrorOutputType::HumanReadable(color_config), None) => Box::new( EmitterWriter::stderr( @@ -1091,7 +1091,7 @@ pub fn build_session_( working_dir, lint_store: RwLock::new(lint::LintStore::new()), buffered_lints: Lock::new(Some(lint::LintBuffer::new())), - one_time_diagnostics: RefCell::new(FxHashSet()), + one_time_diagnostics: Lock::new(FxHashSet()), plugin_llvm_passes: OneThread::new(RefCell::new(Vec::new())), plugin_attributes: OneThread::new(RefCell::new(Vec::new())), crate_types: Once::new(), @@ -1128,14 +1128,23 @@ pub fn build_session_( // positives, or in other words we try to execute this before we open // any file descriptors ourselves. // + // Pick a "reasonable maximum" if we don't otherwise have + // a jobserver in our environment, capping out at 32 so we + // don't take everything down by hogging the process run queue. + // The fixed number is used to have deterministic compilation + // across machines. + // // Also note that we stick this in a global because there could be // multiple `Session` instances in this process, and the jobserver is // per-process. - jobserver_from_env: unsafe { - static mut GLOBAL_JOBSERVER: *mut Option<Client> = 0 as *mut _; + jobserver: unsafe { + static mut GLOBAL_JOBSERVER: *mut Client = 0 as *mut _; static INIT: std::sync::Once = std::sync::ONCE_INIT; INIT.call_once(|| { - GLOBAL_JOBSERVER = Box::into_raw(Box::new(Client::from_env())); + let client = Client::from_env().unwrap_or_else(|| { + Client::new(32).expect("failed to create jobserver") + }); + GLOBAL_JOBSERVER = Box::into_raw(Box::new(client)); }); (*GLOBAL_JOBSERVER).clone() }, @@ -1188,7 +1197,7 @@ pub enum IncrCompSession { } pub fn early_error(output: config::ErrorOutputType, msg: &str) -> ! { - let emitter: Box<dyn Emitter> = match output { + let emitter: Box<dyn Emitter + sync::Send> = match output { config::ErrorOutputType::HumanReadable(color_config) => { Box::new(EmitterWriter::stderr(color_config, None, false, false)) } @@ -1203,7 +1212,7 @@ pub fn early_error(output: config::ErrorOutputType, msg: &str) -> ! { } pub fn early_warn(output: config::ErrorOutputType, msg: &str) { - let emitter: Box<dyn Emitter> = match output { + let emitter: Box<dyn Emitter + sync::Send> = match output { config::ErrorOutputType::HumanReadable(color_config) => { Box::new(EmitterWriter::stderr(color_config, None, false, false)) } diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs index 31f8af1f968..5a626e7b82c 100644 --- a/src/librustc/traits/coherence.rs +++ b/src/librustc/traits/coherence.rs @@ -154,7 +154,10 @@ fn overlap<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>, recursion_depth: 0, predicate: p }) .chain(obligations) - .find(|o| !selcx.evaluate_obligation(o)); + .find(|o| !selcx.predicate_may_hold_fatal(o)); + // FIXME: the call to `selcx.predicate_may_hold_fatal` above should be ported + // to the canonical trait query form, `infcx.predicate_may_hold`, once + // the new system supports intercrate mode (which coherence needs). if let Some(failing_obligation) = opt_failing_obligation { debug!("overlap: obligation unsatisfiable {:?}", failing_obligation); diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 2af4c3f9fd4..047d4bb8930 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -24,6 +24,7 @@ use super::{ SelectionContext, SelectionError, ObjectSafetyViolation, + Overflow, }; use errors::DiagnosticBuilder; @@ -537,7 +538,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { &data.parent_trait_ref); match self.get_parent_trait_ref(&data.parent_code) { Some(t) => Some(t), - None => Some(format!("{}", parent_trait_ref.0.self_ty())), + None => Some(format!("{}", parent_trait_ref.skip_binder().self_ty())), } } _ => None, @@ -659,8 +660,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { predicate: ty::Predicate::Trait(predicate), .. obligation.clone() }; - let mut selcx = SelectionContext::new(self); - if selcx.evaluate_obligation(&unit_obligation) { + if self.predicate_may_hold(&unit_obligation) { err.note("the trait is implemented for `()`. \ Possibly this error has been caused by changes to \ Rust's type-inference algorithm \ @@ -830,6 +830,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } err.struct_error(self.tcx, span, "constant expression") } + + Overflow => { + bug!("overflow should be handled before the `report_selection_error` path"); + } }; self.note_obligation_cause(&mut err, obligation); err.emit(); @@ -862,7 +866,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { obligation: &PredicateObligation<'tcx>, err: &mut DiagnosticBuilder<'tcx>, trait_ref: &ty::Binder<ty::TraitRef<'tcx>>) { - let ty::Binder(trait_ref) = trait_ref; + let trait_ref = trait_ref.skip_binder(); let span = obligation.cause.span; if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(span) { @@ -872,7 +876,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { .count(); let mut trait_type = trait_ref.self_ty(); - let mut selcx = SelectionContext::new(self); for refs_remaining in 0..refs_number { if let ty::TypeVariants::TyRef(_, ty::TypeAndMut{ ty: t_type, mutbl: _ }) = @@ -886,7 +889,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { obligation.param_env, new_trait_ref.to_predicate()); - if selcx.evaluate_obligation(&new_obligation) { + if self.predicate_may_hold(&new_obligation) { let sp = self.tcx.sess.codemap() .span_take_while(span, |c| c.is_whitespace() || *c == '&'); @@ -976,6 +979,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ArgKind::Arg(format!("{}", field.name), "_".to_string()) }).collect::<Vec<_>>()) } + hir::map::NodeStructCtor(ref variant_data) => { + (self.tcx.sess.codemap().def_span(self.tcx.hir.span(variant_data.id())), + variant_data.fields() + .iter().map(|_| ArgKind::Arg("_".to_owned(), "_".to_owned())) + .collect()) + } _ => panic!("non-FnLike node found: {:?}", node), } } @@ -1091,7 +1100,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { tcx.mk_infer(ty::TyVar(ty::TyVid { index: 0 })), false, hir::Unsafety::Normal, - ::syntax::abi::Abi::Rust + ::rustc_target::spec::abi::Abi::Rust ) } else { tcx.mk_fn_sig( @@ -1099,10 +1108,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { tcx.mk_infer(ty::TyVar(ty::TyVid { index: 0 })), false, hir::Unsafety::Normal, - ::syntax::abi::Abi::Rust + ::rustc_target::spec::abi::Abi::Rust ) }; - format!("{}", ty::Binder(sig)) + format!("{}", ty::Binder::bind(sig)) } let argument_is_closure = expected_ref.skip_binder().substs.type_at(0).is_closure(); @@ -1322,7 +1331,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { cleaned_pred.to_predicate() ); - selcx.evaluate_obligation(&obligation) + self.predicate_may_hold(&obligation) }) } @@ -1436,7 +1445,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } ObligationCauseCode::BuiltinDerivedObligation(ref data) => { let parent_trait_ref = self.resolve_type_vars_if_possible(&data.parent_trait_ref); - let ty = parent_trait_ref.0.self_ty(); + let ty = parent_trait_ref.skip_binder().self_ty(); err.note(&format!("required because it appears within the type `{}`", ty)); obligated_types.push(ty); @@ -1453,7 +1462,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { err.note( &format!("required because of the requirements on the impl of `{}` for `{}`", parent_trait_ref, - parent_trait_ref.0.self_ty())); + parent_trait_ref.skip_binder().self_ty())); let parent_predicate = parent_trait_ref.to_predicate(); self.note_obligation_cause_code(err, &parent_predicate, @@ -1484,7 +1493,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { if let ObligationCauseCode::BuiltinDerivedObligation(ref data) = cause_code { let parent_trait_ref = self.resolve_type_vars_if_possible(&data.parent_trait_ref); for obligated_type in obligated_types { - if obligated_type == &parent_trait_ref.0.self_ty() { + if obligated_type == &parent_trait_ref.skip_binder().self_ty() { return true; } } diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 1c091d68a2e..6e201507181 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -112,7 +112,7 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> { selcx, register_region_obligations: self.register_region_obligations }); - debug!("select: outcome={:?}", outcome); + debug!("select: outcome={:#?}", outcome); // FIXME: if we kept the original cache key, we could mark projection // obligations as complete for the projection cache here. @@ -333,7 +333,7 @@ fn process_predicate<'a, 'gcx, 'tcx>( if data.is_global() { // no type variables present, can use evaluation for better caching. // FIXME: consider caching errors too. - if selcx.evaluate_obligation_conservatively(&obligation) { + if selcx.infcx().predicate_must_hold(&obligation) { debug!("selecting trait `{:?}` at depth {} evaluated to holds", data, obligation.recursion_depth); return Ok(Some(vec![])) diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 8d2398d3409..dd5208e908e 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -41,7 +41,7 @@ pub use self::object_safety::ObjectSafetyViolation; pub use self::object_safety::MethodViolationCode; pub use self::on_unimplemented::{OnUnimplementedDirective, OnUnimplementedNote}; pub use self::select::{EvaluationCache, SelectionContext, SelectionCache}; -pub use self::select::IntercrateAmbiguityCause; +pub use self::select::{EvaluationResult, IntercrateAmbiguityCause, OverflowError}; pub use self::specialize::{OverlapError, specialization_graph, translate_substs}; pub use self::specialize::{SpecializesCache, find_associated_item}; pub use self::engine::TraitEngine; @@ -74,6 +74,19 @@ pub enum IntercrateMode { Fixed } +// The mode that trait queries run in +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub enum TraitQueryMode { + // Standard/un-canonicalized queries get accurate + // spans etc. passed in and hence can do reasonable + // error reporting on their own. + Standard, + // Canonicalized queries get dummy spans and hence + // must generally propagate errors to + // pre-canonicalization callsites. + Canonical, +} + /// An `Obligation` represents some trait reference (e.g. `int:Eq`) for /// which the vtable must be found. The process of finding a vtable is /// called "resolving" the `Obligation`. This process consists of @@ -282,13 +295,16 @@ pub enum QuantifierKind { #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub enum Goal<'tcx> { - Implies(&'tcx Slice<Clause<'tcx>>, &'tcx Goal<'tcx>), + Implies(Clauses<'tcx>, &'tcx Goal<'tcx>), And(&'tcx Goal<'tcx>, &'tcx Goal<'tcx>), Not(&'tcx Goal<'tcx>), DomainGoal(DomainGoal<'tcx>), - Quantified(QuantifierKind, ty::Binder<&'tcx Goal<'tcx>>) + Quantified(QuantifierKind, ty::Binder<&'tcx Goal<'tcx>>), + CannotProve, } +pub type Goals<'tcx> = &'tcx Slice<Goal<'tcx>>; + impl<'tcx> Goal<'tcx> { pub fn from_poly_domain_goal<'a>( domain_goal: PolyDomainGoal<'tcx>, @@ -318,6 +334,9 @@ pub enum Clause<'tcx> { ForAll(ty::Binder<ProgramClause<'tcx>>), } +/// Multiple clauses. +pub type Clauses<'tcx> = &'tcx Slice<Clause<'tcx>>; + /// A "program clause" has the form `D :- G1, ..., Gn`. It is saying /// that the domain goal `D` is true if `G1...Gn` are provable. This /// is equivalent to the implication `G1..Gn => D`; we usually write @@ -330,7 +349,7 @@ pub struct ProgramClause<'tcx> { pub goal: DomainGoal<'tcx>, /// ...if we can prove these hypotheses (there may be no hypotheses at all): - pub hypotheses: &'tcx Slice<Goal<'tcx>>, + pub hypotheses: Goals<'tcx>, } pub type Selection<'tcx> = Vtable<'tcx, PredicateObligation<'tcx>>; @@ -343,6 +362,7 @@ pub enum SelectionError<'tcx> { ty::error::TypeError<'tcx>), TraitNotObjectSafe(DefId), ConstEvalFailure(ConstEvalErr<'tcx>), + Overflow, } pub struct FulfillmentError<'tcx> { @@ -544,8 +564,7 @@ pub fn type_known_to_meet_bound<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx predicate: trait_ref.to_predicate(), }; - let result = SelectionContext::new(infcx) - .evaluate_obligation_conservatively(&obligation); + let result = infcx.predicate_must_hold(&obligation); debug!("type_known_to_meet_ty={:?} bound={} => {:?}", ty, infcx.tcx.item_path_str(def_id), result); @@ -849,16 +868,19 @@ fn vtable_methods<'a, 'tcx>( // the method may have some early-bound lifetimes, add // regions for those - let substs = Substs::for_item(tcx, def_id, - |_, _| tcx.types.re_erased, - |def, _| trait_ref.substs().type_for_def(def)); + let substs = trait_ref.map_bound(|trait_ref| { + Substs::for_item( + tcx, def_id, + |_, _| tcx.types.re_erased, + |def, _| trait_ref.substs.type_for_def(def)) + }); // the trait type may have higher-ranked lifetimes in it; // so erase them if they appear, so that we get the type // at some particular call site let substs = tcx.normalize_erasing_late_bound_regions( ty::ParamEnv::reveal_all(), - &ty::Binder(substs), + &substs ); // It's possible that the method relies on where clauses that @@ -991,7 +1013,7 @@ impl<'tcx> FulfillmentError<'tcx> { impl<'tcx> TraitObligation<'tcx> { fn self_ty(&self) -> ty::Binder<Ty<'tcx>> { - ty::Binder(self.predicate.skip_binder().self_ty()) + self.predicate.map_bound(|p| p.self_ty()) } } diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index 52a0a897595..c0d5a337cee 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -149,7 +149,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { trait_def_id: DefId, supertraits_only: bool) -> bool { - let trait_ref = ty::Binder(ty::TraitRef { + let trait_ref = ty::Binder::dummy(ty::TraitRef { def_id: trait_def_id, substs: Substs::identity_for_item(self, trait_def_id) }); @@ -199,7 +199,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { .any(|predicate| { match predicate { ty::Predicate::Trait(ref trait_pred) if trait_pred.def_id() == sized_def_id => { - trait_pred.0.self_ty().is_self() + trait_pred.skip_binder().self_ty().is_self() } ty::Predicate::Projection(..) | ty::Predicate::Trait(..) | @@ -352,7 +352,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // Compute supertraits of current trait lazily. if supertraits.is_none() { - let trait_ref = ty::Binder(ty::TraitRef { + let trait_ref = ty::Binder::bind(ty::TraitRef { def_id: trait_def_id, substs: Substs::identity_for_item(self, trait_def_id) }); @@ -367,7 +367,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // direct equality here because all of these types // are part of the formal parameter listing, and // hence there should be no inference variables. - let projection_trait_ref = ty::Binder(data.trait_ref(self)); + let projection_trait_ref = ty::Binder::bind(data.trait_ref(self)); let is_supertrait_of_current_trait = supertraits.as_ref().unwrap().contains(&projection_trait_ref); diff --git a/src/librustc/traits/on_unimplemented.rs b/src/librustc/traits/on_unimplemented.rs index 405dafdff2b..d1fd70ae02d 100644 --- a/src/librustc/traits/on_unimplemented.rs +++ b/src/librustc/traits/on_unimplemented.rs @@ -18,10 +18,10 @@ use util::nodemap::FxHashMap; use syntax::ast::{MetaItem, NestedMetaItem}; use syntax::attr; use syntax_pos::Span; -use syntax_pos::symbol::InternedString; +use syntax_pos::symbol::LocalInternedString; #[derive(Clone, Debug)] -pub struct OnUnimplementedFormatString(InternedString); +pub struct OnUnimplementedFormatString(LocalInternedString); #[derive(Debug)] pub struct OnUnimplementedDirective { @@ -225,7 +225,7 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedDirective { impl<'a, 'gcx, 'tcx> OnUnimplementedFormatString { pub fn try_parse(tcx: TyCtxt<'a, 'gcx, 'tcx>, trait_def_id: DefId, - from: InternedString, + from: LocalInternedString, err_sp: Span) -> Result<Self, ErrorReported> { diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index 9f21ea14d0f..0c35e20324c 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -196,7 +196,10 @@ pub fn poly_project_and_unify_type<'cx, 'gcx, 'tcx>( let span = obligation.cause.span; match infcx.leak_check(false, span, &skol_map, snapshot) { Ok(()) => Ok(infcx.plug_leaks(skol_map, snapshot, result)), - Err(e) => Err(MismatchedProjectionTypes { err: e }), + Err(e) => { + debug!("poly_project_and_unify_type: leak check encountered error {:?}", e); + Err(MismatchedProjectionTypes { err: e }) + } } } Err(e) => { @@ -243,7 +246,10 @@ fn project_and_unify_type<'cx, 'gcx, 'tcx>( obligations.extend(inferred_obligations); Ok(Some(obligations)) }, - Err(err) => Err(MismatchedProjectionTypes { err: err }), + Err(err) => { + debug!("project_and_unify_type: equating types encountered error {:?}", err); + Err(MismatchedProjectionTypes { err: err }) + } } } @@ -478,7 +484,7 @@ pub fn normalize_projection_type<'a, 'b, 'gcx, 'tcx>( let def_id = projection_ty.item_def_id; let ty_var = selcx.infcx().next_ty_var( TypeVariableOrigin::NormalizeProjectionType(tcx.def_span(def_id))); - let projection = ty::Binder(ty::ProjectionPredicate { + let projection = ty::Binder::dummy(ty::ProjectionPredicate { projection_ty, ty: ty_var }); @@ -982,8 +988,7 @@ fn assemble_candidates_from_predicates<'cx, 'gcx, 'tcx, I>( predicate); match predicate { ty::Predicate::Projection(data) => { - let same_def_id = - data.0.projection_ty.item_def_id == obligation.predicate.item_def_id; + let same_def_id = data.projection_def_id() == obligation.predicate.item_def_id; let is_match = same_def_id && infcx.probe(|_| { let data_poly_trait_ref = @@ -1241,7 +1246,7 @@ fn confirm_object_candidate<'cx, 'gcx, 'tcx>( // item with the correct name let env_predicates = env_predicates.filter_map(|p| match p { ty::Predicate::Projection(data) => - if data.0.projection_ty.item_def_id == obligation.predicate.item_def_id { + if data.projection_def_id() == obligation.predicate.item_def_id { Some(data) } else { None @@ -1302,28 +1307,28 @@ fn confirm_generator_candidate<'cx, 'gcx, 'tcx>( let gen_def_id = tcx.lang_items().gen_trait().unwrap(); - // Note: we unwrap the binder here but re-create it below (1) - let ty::Binder((trait_ref, yield_ty, return_ty)) = + let predicate = tcx.generator_trait_ref_and_outputs(gen_def_id, obligation.predicate.self_ty(), - gen_sig); - - let name = tcx.associated_item(obligation.predicate.item_def_id).name; - let ty = if name == Symbol::intern("Return") { - return_ty - } else if name == Symbol::intern("Yield") { - yield_ty - } else { - bug!() - }; + gen_sig) + .map_bound(|(trait_ref, yield_ty, return_ty)| { + let name = tcx.associated_item(obligation.predicate.item_def_id).name; + let ty = if name == Symbol::intern("Return") { + return_ty + } else if name == Symbol::intern("Yield") { + yield_ty + } else { + bug!() + }; - let predicate = ty::Binder(ty::ProjectionPredicate { // (1) recreate binder here - projection_ty: ty::ProjectionTy { - substs: trait_ref.substs, - item_def_id: obligation.predicate.item_def_id, - }, - ty: ty - }); + ty::ProjectionPredicate { + projection_ty: ty::ProjectionTy { + substs: trait_ref.substs, + item_def_id: obligation.predicate.item_def_id, + }, + ty: ty + } + }); confirm_param_env_candidate(selcx, obligation, predicate) .with_addl_obligations(vtable.nested) @@ -1400,21 +1405,21 @@ fn confirm_callable_candidate<'cx, 'gcx, 'tcx>( // the `Output` associated type is declared on `FnOnce` let fn_once_def_id = tcx.lang_items().fn_once_trait().unwrap(); - // Note: we unwrap the binder here but re-create it below (1) - let ty::Binder((trait_ref, ret_type)) = + let predicate = tcx.closure_trait_ref_and_return_type(fn_once_def_id, obligation.predicate.self_ty(), fn_sig, - flag); - - let predicate = ty::Binder(ty::ProjectionPredicate { // (1) recreate binder here - projection_ty: ty::ProjectionTy::from_ref_and_name( - tcx, - trait_ref, - Symbol::intern(FN_OUTPUT_NAME), - ), - ty: ret_type - }); + flag) + .map_bound(|(trait_ref, ret_type)| { + ty::ProjectionPredicate { + projection_ty: ty::ProjectionTy::from_ref_and_name( + tcx, + trait_ref, + Symbol::intern(FN_OUTPUT_NAME), + ), + ty: ret_type + } + }); confirm_param_env_candidate(selcx, obligation, predicate) } diff --git a/src/librustc/traits/query/evaluate_obligation.rs b/src/librustc/traits/query/evaluate_obligation.rs new file mode 100644 index 00000000000..4e028cac49a --- /dev/null +++ b/src/librustc/traits/query/evaluate_obligation.rs @@ -0,0 +1,70 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use infer::InferCtxt; +use infer::canonical::{Canonical, Canonicalize}; +use traits::{EvaluationResult, PredicateObligation, SelectionContext, + TraitQueryMode, OverflowError}; +use traits::query::CanonicalPredicateGoal; +use ty::{ParamEnvAnd, Predicate, TyCtxt}; + +impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { + /// Evaluates whether the predicate can be satisfied (by any means) + /// in the given `ParamEnv`. + pub fn predicate_may_hold( + &self, + obligation: &PredicateObligation<'tcx>, + ) -> bool { + self.evaluate_obligation(obligation).may_apply() + } + + /// Evaluates whether the predicate can be satisfied in the given + /// `ParamEnv`, and returns `false` if not certain. However, this is + /// not entirely accurate if inference variables are involved. + pub fn predicate_must_hold( + &self, + obligation: &PredicateObligation<'tcx>, + ) -> bool { + self.evaluate_obligation(obligation) == EvaluationResult::EvaluatedToOk + } + + // Helper function that canonicalizes and runs the query, as well as handles + // overflow. + fn evaluate_obligation( + &self, + obligation: &PredicateObligation<'tcx>, + ) -> EvaluationResult { + let (c_pred, _) = + self.canonicalize_query(&obligation.param_env.and(obligation.predicate)); + // Run canonical query. If overflow occurs, rerun from scratch but this time + // in standard trait query mode so that overflow is handled appropriately + // within `SelectionContext`. + match self.tcx.global_tcx().evaluate_obligation(c_pred) { + Ok(result) => result, + Err(OverflowError) => { + let mut selcx = + SelectionContext::with_query_mode(&self, TraitQueryMode::Standard); + selcx.evaluate_obligation_recursively(obligation) + .expect("Overflow should be caught earlier in standard query mode") + } + } + } +} + +impl<'gcx: 'tcx, 'tcx> Canonicalize<'gcx, 'tcx> for ParamEnvAnd<'tcx, Predicate<'tcx>> { + type Canonicalized = CanonicalPredicateGoal<'gcx>; + + fn intern( + _gcx: TyCtxt<'_, 'gcx, 'gcx>, + value: Canonical<'gcx, Self::Lifted>, + ) -> Self::Canonicalized { + value + } +} diff --git a/src/librustc/traits/query/mod.rs b/src/librustc/traits/query/mod.rs index f1f9256f825..096633ddab2 100644 --- a/src/librustc/traits/query/mod.rs +++ b/src/librustc/traits/query/mod.rs @@ -19,6 +19,7 @@ use infer::canonical::Canonical; use ty::{self, Ty}; pub mod dropck_outlives; +pub mod evaluate_obligation; pub mod normalize; pub mod normalize_erasing_regions; @@ -27,6 +28,9 @@ pub type CanonicalProjectionGoal<'tcx> = pub type CanonicalTyGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, Ty<'tcx>>>; +pub type CanonicalPredicateGoal<'tcx> = + Canonical<'tcx, ty::ParamEnvAnd<'tcx, ty::Predicate<'tcx>>>; + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub struct NoSolution; diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 51493f26194..4ba3655bb64 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -17,12 +17,12 @@ use self::EvaluationResult::*; use super::coherence::{self, Conflict}; use super::DerivedObligationCause; -use super::IntercrateMode; +use super::{IntercrateMode, TraitQueryMode}; use super::project; use super::project::{normalize_with_depth, Normalized, ProjectionCacheKey}; use super::{PredicateObligation, TraitObligation, ObligationCause}; use super::{ObligationCauseCode, BuiltinDerivedObligation, ImplDerivedObligation}; -use super::{SelectionError, Unimplemented, OutputTypeParameterMismatch}; +use super::{SelectionError, Unimplemented, OutputTypeParameterMismatch, Overflow}; use super::{ObjectCastObligation, Obligation}; use super::TraitNotObjectSafe; use super::Selection; @@ -51,7 +51,7 @@ use std::cmp; use std::fmt; use std::mem; use std::rc::Rc; -use syntax::abi::Abi; +use rustc_target::spec::abi::Abi; use hir; use util::nodemap::{FxHashMap, FxHashSet}; @@ -87,7 +87,12 @@ pub struct SelectionContext<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> { /// Controls whether or not to filter out negative impls when selecting. /// This is used in librustdoc to distinguish between the lack of an impl /// and a negative impl - allow_negative_impls: bool + allow_negative_impls: bool, + + /// The mode that trait queries run in, which informs our error handling + /// policy. In essence, canonicalized queries need their errors propagated + /// rather than immediately reported because we do not have accurate spans. + query_mode: TraitQueryMode, } #[derive(Clone, Debug)] @@ -319,7 +324,7 @@ enum BuiltinImplConditions<'tcx> { /// all the "potential success" candidates can potentially succeed, /// so they are no-ops when unioned with a definite error, and within /// the categories it's easy to see that the unions are correct. -enum EvaluationResult { +pub enum EvaluationResult { /// Evaluation successful EvaluatedToOk, /// Evaluation is known to be ambiguous - it *might* hold for some @@ -385,7 +390,7 @@ enum EvaluationResult { } impl EvaluationResult { - fn may_apply(self) -> bool { + pub fn may_apply(self) -> bool { match self { EvaluatedToOk | EvaluatedToAmbig | @@ -408,6 +413,26 @@ impl EvaluationResult { } } +impl_stable_hash_for!(enum self::EvaluationResult { + EvaluatedToOk, + EvaluatedToAmbig, + EvaluatedToUnknown, + EvaluatedToRecur, + EvaluatedToErr +}); + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +/// Indicates that trait evaluation caused overflow. +pub struct OverflowError; + +impl_stable_hash_for!(struct OverflowError { }); + +impl<'tcx> From<OverflowError> for SelectionError<'tcx> { + fn from(OverflowError: OverflowError) -> SelectionError<'tcx> { + SelectionError::Overflow + } +} + #[derive(Clone)] pub struct EvaluationCache<'tcx> { hashmap: RefCell<FxHashMap<ty::PolyTraitRef<'tcx>, WithDepNode<EvaluationResult>>> @@ -421,6 +446,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { intercrate: None, intercrate_ambiguity_causes: None, allow_negative_impls: false, + query_mode: TraitQueryMode::Standard, } } @@ -433,6 +459,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { intercrate: Some(mode), intercrate_ambiguity_causes: None, allow_negative_impls: false, + query_mode: TraitQueryMode::Standard, } } @@ -445,6 +472,20 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { intercrate: None, intercrate_ambiguity_causes: None, allow_negative_impls, + query_mode: TraitQueryMode::Standard, + } + } + + pub fn with_query_mode(infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>, + query_mode: TraitQueryMode) -> SelectionContext<'cx, 'gcx, 'tcx> { + debug!("with_query_mode({:?})", query_mode); + SelectionContext { + infcx, + freshener: infcx.freshener(), + intercrate: None, + intercrate_ambiguity_causes: None, + allow_negative_impls: false, + query_mode, } } @@ -528,12 +569,27 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { assert!(!obligation.predicate.has_escaping_regions()); let stack = self.push_stack(TraitObligationStackList::empty(), obligation); - let ret = match self.candidate_from_obligation(&stack)? { - None => None, - Some(candidate) => Some(self.confirm_candidate(obligation, candidate)?) + + let candidate = match self.candidate_from_obligation(&stack) { + Err(SelectionError::Overflow) => { + // In standard mode, overflow must have been caught and reported + // earlier. + assert!(self.query_mode == TraitQueryMode::Canonical); + return Err(SelectionError::Overflow); + }, + Err(e) => { return Err(e); }, + Ok(None) => { return Ok(None); }, + Ok(Some(candidate)) => candidate }; - Ok(ret) + match self.confirm_candidate(obligation, candidate) { + Err(SelectionError::Overflow) => { + assert!(self.query_mode == TraitQueryMode::Canonical); + return Err(SelectionError::Overflow); + }, + Err(e) => Err(e), + Ok(candidate) => Ok(Some(candidate)) + } } /////////////////////////////////////////////////////////////////////////// @@ -547,32 +603,30 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // we can be sure it does not. /// Evaluates whether the obligation `obligation` can be satisfied (by any means). - pub fn evaluate_obligation(&mut self, - obligation: &PredicateObligation<'tcx>) - -> bool + pub fn predicate_may_hold_fatal(&mut self, + obligation: &PredicateObligation<'tcx>) + -> bool { - debug!("evaluate_obligation({:?})", + debug!("predicate_may_hold_fatal({:?})", obligation); - self.probe(|this, _| { - this.evaluate_predicate_recursively(TraitObligationStackList::empty(), obligation) - .may_apply() - }) + // This fatal query is a stopgap that should only be used in standard mode, + // where we do not expect overflow to be propagated. + assert!(self.query_mode == TraitQueryMode::Standard); + + self.evaluate_obligation_recursively(obligation) + .expect("Overflow should be caught earlier in standard query mode") + .may_apply() } - /// Evaluates whether the obligation `obligation` can be satisfied, - /// and returns `false` if not certain. However, this is not entirely - /// accurate if inference variables are involved. - pub fn evaluate_obligation_conservatively(&mut self, - obligation: &PredicateObligation<'tcx>) - -> bool + /// Evaluates whether the obligation `obligation` can be satisfied and returns + /// an `EvaluationResult`. + pub fn evaluate_obligation_recursively(&mut self, + obligation: &PredicateObligation<'tcx>) + -> Result<EvaluationResult, OverflowError> { - debug!("evaluate_obligation_conservatively({:?})", - obligation); - self.probe(|this, _| { this.evaluate_predicate_recursively(TraitObligationStackList::empty(), obligation) - == EvaluatedToOk }) } @@ -582,29 +636,29 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { fn evaluate_predicates_recursively<'a,'o,I>(&mut self, stack: TraitObligationStackList<'o, 'tcx>, predicates: I) - -> EvaluationResult + -> Result<EvaluationResult, OverflowError> where I : IntoIterator<Item=&'a PredicateObligation<'tcx>>, 'tcx:'a { let mut result = EvaluatedToOk; for obligation in predicates { - let eval = self.evaluate_predicate_recursively(stack, obligation); + let eval = self.evaluate_predicate_recursively(stack, obligation)?; debug!("evaluate_predicate_recursively({:?}) = {:?}", obligation, eval); if let EvaluatedToErr = eval { // fast-path - EvaluatedToErr is the top of the lattice, // so we don't need to look on the other predicates. - return EvaluatedToErr; + return Ok(EvaluatedToErr); } else { result = cmp::max(result, eval); } } - result + Ok(result) } fn evaluate_predicate_recursively<'o>(&mut self, previous_stack: TraitObligationStackList<'o, 'tcx>, obligation: &PredicateObligation<'tcx>) - -> EvaluationResult + -> Result<EvaluationResult, OverflowError> { debug!("evaluate_predicate_recursively({:?})", obligation); @@ -620,11 +674,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // does this code ever run? match self.infcx.subtype_predicate(&obligation.cause, obligation.param_env, p) { Some(Ok(InferOk { obligations, .. })) => { - self.evaluate_predicates_recursively(previous_stack, &obligations); - EvaluatedToOk + self.evaluate_predicates_recursively(previous_stack, &obligations) }, - Some(Err(_)) => EvaluatedToErr, - None => EvaluatedToAmbig, + Some(Err(_)) => Ok(EvaluatedToErr), + None => Ok(EvaluatedToAmbig), } } @@ -636,21 +689,21 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { Some(obligations) => self.evaluate_predicates_recursively(previous_stack, obligations.iter()), None => - EvaluatedToAmbig, + Ok(EvaluatedToAmbig), } } ty::Predicate::TypeOutlives(..) | ty::Predicate::RegionOutlives(..) => { // we do not consider region relationships when // evaluating trait matches - EvaluatedToOk + Ok(EvaluatedToOk) } ty::Predicate::ObjectSafe(trait_def_id) => { if self.tcx().is_object_safe(trait_def_id) { - EvaluatedToOk + Ok(EvaluatedToOk) } else { - EvaluatedToErr + Ok(EvaluatedToErr) } } @@ -668,10 +721,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { result } Ok(None) => { - EvaluatedToAmbig + Ok(EvaluatedToAmbig) } Err(_) => { - EvaluatedToErr + Ok(EvaluatedToErr) } } } @@ -680,13 +733,13 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { match self.infcx.closure_kind(closure_def_id, closure_substs) { Some(closure_kind) => { if closure_kind.extends(kind) { - EvaluatedToOk + Ok(EvaluatedToOk) } else { - EvaluatedToErr + Ok(EvaluatedToErr) } } None => { - EvaluatedToAmbig + Ok(EvaluatedToAmbig) } } } @@ -707,16 +760,16 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { promoted: None }; match self.tcx().const_eval(param_env.and(cid)) { - Ok(_) => EvaluatedToOk, - Err(_) => EvaluatedToErr + Ok(_) => Ok(EvaluatedToOk), + Err(_) => Ok(EvaluatedToErr) } } else { - EvaluatedToErr + Ok(EvaluatedToErr) } } None => { // Inference variables still left in param_env or substs. - EvaluatedToAmbig + Ok(EvaluatedToAmbig) } } } @@ -726,7 +779,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { fn evaluate_trait_predicate_recursively<'o>(&mut self, previous_stack: TraitObligationStackList<'o, 'tcx>, mut obligation: TraitObligation<'tcx>) - -> EvaluationResult + -> Result<EvaluationResult, OverflowError> { debug!("evaluate_trait_predicate_recursively({:?})", obligation); @@ -745,22 +798,23 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { debug!("CACHE HIT: EVAL({:?})={:?}", fresh_trait_ref, result); - return result; + return Ok(result); } let (result, dep_node) = self.in_task(|this| this.evaluate_stack(&stack)); + let result = result?; debug!("CACHE MISS: EVAL({:?})={:?}", fresh_trait_ref, result); self.insert_evaluation_cache(obligation.param_env, fresh_trait_ref, dep_node, result); - result + Ok(result) } fn evaluate_stack<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) - -> EvaluationResult + -> Result<EvaluationResult, OverflowError> { // In intercrate mode, whenever any of the types are unbound, // there can always be an impl. Even if there are no impls in @@ -786,7 +840,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // This suffices to allow chains like `FnMut` implemented in // terms of `Fn` etc, but we could probably make this more // precise still. - let unbound_input_types = stack.fresh_trait_ref.input_types().any(|ty| ty.is_fresh()); + let unbound_input_types = + stack.fresh_trait_ref.skip_binder().input_types().any(|ty| ty.is_fresh()); // this check was an imperfect workaround for a bug n the old // intercrate mode, it should be removed when that goes away. if unbound_input_types && @@ -814,7 +869,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } } } - return EvaluatedToAmbig; + return Ok(EvaluatedToAmbig); } if unbound_input_types && stack.iter().skip(1).any( @@ -824,7 +879,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { { debug!("evaluate_stack({:?}) --> unbound argument, recursive --> giving up", stack.fresh_trait_ref); - return EvaluatedToUnknown; + return Ok(EvaluatedToUnknown); } // If there is any previous entry on the stack that precisely @@ -859,18 +914,19 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { if self.coinductive_match(cycle) { debug!("evaluate_stack({:?}) --> recursive, coinductive", stack.fresh_trait_ref); - return EvaluatedToOk; + return Ok(EvaluatedToOk); } else { debug!("evaluate_stack({:?}) --> recursive, inductive", stack.fresh_trait_ref); - return EvaluatedToRecur; + return Ok(EvaluatedToRecur); } } match self.candidate_from_obligation(stack) { Ok(Some(c)) => self.evaluate_candidate(stack, &c), - Ok(None) => EvaluatedToAmbig, - Err(..) => EvaluatedToErr + Ok(None) => Ok(EvaluatedToAmbig), + Err(Overflow) => Err(OverflowError), + Err(..) => Ok(EvaluatedToErr) } } @@ -908,7 +964,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { fn evaluate_candidate<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>, candidate: &SelectionCandidate<'tcx>) - -> EvaluationResult + -> Result<EvaluationResult, OverflowError> { debug!("evaluate_candidate: depth={} candidate={:?}", stack.obligation.recursion_depth, candidate); @@ -920,12 +976,12 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { stack.list(), selection.nested_obligations().iter()) } - Err(..) => EvaluatedToErr + Err(..) => Ok(EvaluatedToErr) } - }); + })?; debug!("evaluate_candidate: depth={} result={:?}", stack.obligation.recursion_depth, result); - result + Ok(result) } fn check_evaluation_cache(&self, @@ -999,7 +1055,14 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // not update) the cache. let recursion_limit = *self.infcx.tcx.sess.recursion_limit.get(); if stack.obligation.recursion_depth >= recursion_limit { - self.infcx().report_overflow_error(&stack.obligation, true); + match self.query_mode { + TraitQueryMode::Standard => { + self.infcx().report_overflow_error(&stack.obligation, true); + }, + TraitQueryMode::Canonical => { + return Err(Overflow); + }, + } } // Check the cache. Note that we skolemize the trait-ref @@ -1080,9 +1143,15 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { debug!("evaluate_stack: intercrate_ambiguity_causes is some"); // Heuristics: show the diagnostics when there are no candidates in crate. if let Ok(candidate_set) = self.assemble_candidates(stack) { - if !candidate_set.ambiguous && candidate_set.vec.iter().all(|c| { - !self.evaluate_candidate(stack, &c).may_apply() - }) { + let no_candidates_apply = + candidate_set + .vec + .iter() + .map(|c| self.evaluate_candidate(stack, &c)) + .collect::<Result<Vec<_>, OverflowError>>()? + .iter() + .all(|r| !r.may_apply()); + if !candidate_set.ambiguous && no_candidates_apply { let trait_ref = stack.obligation.predicate.skip_binder().trait_ref; let self_ty = trait_ref.self_ty(); let trait_desc = trait_ref.to_string(); @@ -1150,18 +1219,21 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } // Winnow, but record the exact outcome of evaluation, which - // is needed for specialization. - let mut candidates: Vec<_> = candidates.into_iter().filter_map(|c| { - let eval = self.evaluate_candidate(stack, &c); - if eval.may_apply() { - Some(EvaluatedCandidate { + // is needed for specialization. Propagate overflow if it occurs. + let candidates: Result<Vec<Option<EvaluatedCandidate>>, _> = candidates + .into_iter() + .map(|c| match self.evaluate_candidate(stack, &c) { + Ok(eval) if eval.may_apply() => Ok(Some(EvaluatedCandidate { candidate: c, evaluation: eval, - }) - } else { - None - } - }).collect(); + })), + Ok(_) => Ok(None), + Err(OverflowError) => Err(Overflow), + }) + .collect(); + + let mut candidates: Vec<EvaluatedCandidate> = + candidates?.into_iter().filter_map(|c| c).collect(); // If there are STILL multiple candidate, we can further // reduce the list by dropping duplicates -- including @@ -1274,7 +1346,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { -> Option<SelectionResult<'tcx, SelectionCandidate<'tcx>>> { let tcx = self.tcx(); - let trait_ref = &cache_fresh_trait_pred.0.trait_ref; + let trait_ref = &cache_fresh_trait_pred.skip_binder().trait_ref; if self.can_use_global_caches(param_env) { let cache = tcx.selection_cache.hashmap.borrow(); if let Some(cached) = cache.get(&trait_ref) { @@ -1294,7 +1366,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { candidate: SelectionResult<'tcx, SelectionCandidate<'tcx>>) { let tcx = self.tcx(); - let trait_ref = cache_fresh_trait_pred.0.trait_ref; + let trait_ref = cache_fresh_trait_pred.skip_binder().trait_ref; if self.can_use_global_caches(param_env) { let mut cache = tcx.selection_cache.hashmap.borrow_mut(); if let Some(trait_ref) = tcx.lift_to_global(&trait_ref) { @@ -1357,7 +1429,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let lang_items = self.tcx().lang_items(); if lang_items.copy_trait() == Some(def_id) { debug!("obligation self ty is {:?}", - obligation.predicate.0.self_ty()); + obligation.predicate.skip_binder().self_ty()); // User-defined copy impls are permitted, but only for // structs and enums. @@ -1409,7 +1481,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // before we go into the whole skolemization thing, just // quickly check if the self-type is a projection at all. - match obligation.predicate.0.trait_ref.self_ty().sty { + match obligation.predicate.skip_binder().trait_ref.self_ty().sty { ty::TyProjection(_) | ty::TyAnon(..) => {} ty::TyInfer(ty::TyVar(_)) => { span_bug!(obligation.cause.span, @@ -1507,7 +1579,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { { assert!(!skol_trait_ref.has_escaping_regions()); if let Err(_) = self.infcx.at(&obligation.cause, obligation.param_env) - .sup(ty::Binder(skol_trait_ref), trait_bound) { + .sup(ty::Binder::dummy(skol_trait_ref), trait_bound) { return false; } @@ -1536,12 +1608,14 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let matching_bounds = all_bounds.filter(|p| p.def_id() == stack.obligation.predicate.def_id()); - let matching_bounds = - matching_bounds.filter( - |bound| self.evaluate_where_clause(stack, bound.clone()).may_apply()); - - let param_candidates = - matching_bounds.map(|bound| ParamCandidate(bound)); + // keep only those bounds which may apply, and propagate overflow if it occurs + let mut param_candidates = vec![]; + for bound in matching_bounds { + let wc = self.evaluate_where_clause(stack, bound.clone())?; + if wc.may_apply() { + param_candidates.push(ParamCandidate(bound)); + } + } candidates.vec.extend(param_candidates); @@ -1551,14 +1625,14 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { fn evaluate_where_clause<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>, where_clause_trait_ref: ty::PolyTraitRef<'tcx>) - -> EvaluationResult + -> Result<EvaluationResult, OverflowError> { self.probe(move |this, _| { match this.match_where_clause_trait_ref(stack.obligation, where_clause_trait_ref) { Ok(obligations) => { this.evaluate_predicates_recursively(stack.list(), obligations.iter()) } - Err(()) => EvaluatedToErr + Err(()) => Ok(EvaluatedToErr) } }) } @@ -1605,7 +1679,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { candidates: &mut SelectionCandidateSet<'tcx>) -> Result<(),SelectionError<'tcx>> { - let kind = match self.tcx().lang_items().fn_trait_kind(obligation.predicate.0.def_id()) { + let kind = match self.tcx().lang_items().fn_trait_kind(obligation.predicate.def_id()) { Some(k) => k, None => { return Ok(()); } }; @@ -1661,12 +1735,12 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // provide an impl, but only for suitable `fn` pointers ty::TyFnDef(..) | ty::TyFnPtr(_) => { - if let ty::Binder(ty::FnSig { + if let ty::FnSig { unsafety: hir::Unsafety::Normal, abi: Abi::Rust, variadic: false, .. - }) = self_ty.fn_sig(self.tcx()) { + } = self_ty.fn_sig(self.tcx()).skip_binder() { candidates.vec.push(FnPointerCandidate); } } @@ -1687,7 +1761,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { self.tcx().for_each_relevant_impl( obligation.predicate.def_id(), - obligation.predicate.0.trait_ref.self_ty(), + obligation.predicate.skip_binder().trait_ref.self_ty(), |impl_def_id| { self.probe(|this, snapshot| { /* [1] */ match this.match_impl(impl_def_id, obligation, snapshot) { @@ -2046,19 +2120,19 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ty::TyGeneratorWitness(..) | ty::TyArray(..) | ty::TyClosure(..) | ty::TyNever | ty::TyError => { // safe for everything - Where(ty::Binder(Vec::new())) + Where(ty::Binder::dummy(Vec::new())) } ty::TyStr | ty::TySlice(_) | ty::TyDynamic(..) | ty::TyForeign(..) => Never, ty::TyTuple(tys) => { - Where(ty::Binder(tys.last().into_iter().cloned().collect())) + Where(ty::Binder::bind(tys.last().into_iter().cloned().collect())) } ty::TyAdt(def, substs) => { let sized_crit = def.sized_constraint(self.tcx()); // (*) binder moved here - Where(ty::Binder( + Where(ty::Binder::bind( sized_crit.iter().map(|ty| ty.subst(self.tcx(), substs)).collect() )) } @@ -2088,7 +2162,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { match self_ty.sty { ty::TyInfer(ty::IntVar(_)) | ty::TyInfer(ty::FloatVar(_)) | ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyError => { - Where(ty::Binder(Vec::new())) + Where(ty::Binder::dummy(Vec::new())) } ty::TyUint(_) | ty::TyInt(_) | ty::TyBool | ty::TyFloat(_) | @@ -2106,12 +2180,12 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ty::TyArray(element_ty, _) => { // (*) binder moved here - Where(ty::Binder(vec![element_ty])) + Where(ty::Binder::bind(vec![element_ty])) } ty::TyTuple(tys) => { // (*) binder moved here - Where(ty::Binder(tys.to_vec())) + Where(ty::Binder::bind(tys.to_vec())) } ty::TyClosure(def_id, substs) => { @@ -2119,7 +2193,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let is_copy_trait = Some(trait_id) == self.tcx().lang_items().copy_trait(); let is_clone_trait = Some(trait_id) == self.tcx().lang_items().clone_trait(); if is_copy_trait || is_clone_trait { - Where(ty::Binder(substs.upvar_tys(def_id, self.tcx()).collect())) + Where(ty::Binder::bind(substs.upvar_tys(def_id, self.tcx()).collect())) } else { Never } @@ -2260,7 +2334,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // 3. Re-bind the regions back to `for<'a> &'a int : Copy` types.skip_binder().into_iter().flat_map(|ty| { // binder moved -\ - let ty: ty::Binder<Ty<'tcx>> = ty::Binder(ty); // <----------/ + let ty: ty::Binder<Ty<'tcx>> = ty::Binder::bind(ty); // <----/ self.in_snapshot(|this, snapshot| { let (skol_ty, skol_map) = @@ -2450,18 +2524,19 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { /// 1. For each constituent type `Y` in `X`, `Y : Foo` holds /// 2. For each where-clause `C` declared on `Foo`, `[Self => X] C` holds. fn confirm_auto_impl_candidate(&mut self, - obligation: &TraitObligation<'tcx>, - trait_def_id: DefId) - -> VtableAutoImplData<PredicateObligation<'tcx>> + obligation: &TraitObligation<'tcx>, + trait_def_id: DefId) + -> VtableAutoImplData<PredicateObligation<'tcx>> { debug!("confirm_auto_impl_candidate({:?}, {:?})", obligation, trait_def_id); - // binder is moved below - let self_ty = self.infcx.shallow_resolve(obligation.predicate.skip_binder().self_ty()); - let types = self.constituent_types_for_ty(self_ty); - self.vtable_auto_impl(obligation, trait_def_id, ty::Binder(types)) + let types = obligation.predicate.map_bound(|inner| { + let self_ty = self.infcx.shallow_resolve(inner.self_ty()); + self.constituent_types_for_ty(self_ty) + }); + self.vtable_auto_impl(obligation, trait_def_id, types) } /// See `confirm_auto_impl_candidate` @@ -2726,7 +2801,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { { debug!("confirm_closure_candidate({:?})", obligation); - let kind = match self.tcx().lang_items().fn_trait_kind(obligation.predicate.0.def_id()) { + let kind = match self.tcx().lang_items().fn_trait_kind(obligation.predicate.def_id()) { Some(k) => k, None => bug!("closure candidate for non-fn trait {:?}", obligation) }; @@ -2835,14 +2910,15 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // Trait+Kx+'a -> Trait+Ky+'b (upcasts). (&ty::TyDynamic(ref data_a, r_a), &ty::TyDynamic(ref data_b, r_b)) => { // See assemble_candidates_for_unsizing for more info. - // Binders reintroduced below in call to mk_existential_predicates. - let principal = data_a.skip_binder().principal(); - let iter = principal.into_iter().map(ty::ExistentialPredicate::Trait) - .chain(data_a.skip_binder().projection_bounds() - .map(|x| ty::ExistentialPredicate::Projection(x))) - .chain(data_b.auto_traits().map(ty::ExistentialPredicate::AutoTrait)); - let new_trait = tcx.mk_dynamic( - ty::Binder(tcx.mk_existential_predicates(iter)), r_b); + let existential_predicates = data_a.map_bound(|data_a| { + let principal = data_a.principal(); + let iter = principal.into_iter().map(ty::ExistentialPredicate::Trait) + .chain(data_a.projection_bounds() + .map(|x| ty::ExistentialPredicate::Projection(x))) + .chain(data_b.auto_traits().map(ty::ExistentialPredicate::AutoTrait)); + tcx.mk_existential_predicates(iter) + }); + let new_trait = tcx.mk_dynamic(existential_predicates, r_b); let InferOk { obligations, .. } = self.infcx.at(&obligation.cause, obligation.param_env) .eq(target, new_trait) @@ -2857,7 +2933,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { nested.push(Obligation::with_depth(cause, obligation.recursion_depth + 1, obligation.param_env, - ty::Binder(outlives).to_predicate())); + ty::Binder::bind(outlives).to_predicate())); } // T -> Trait. @@ -2900,7 +2976,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // If the type is `Foo+'a`, ensures that the type // being cast to `Foo+'a` outlives `'a`: let outlives = ty::OutlivesPredicate(source, r); - push(ty::Binder(outlives).to_predicate()); + push(ty::Binder::dummy(outlives).to_predicate()); } // [T; n] -> [T]. @@ -3201,18 +3277,19 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { -> ty::PolyTraitRef<'tcx> { let closure_type = self.infcx.closure_sig(closure_def_id, substs); - let ty::Binder((trait_ref, _)) = - self.tcx().closure_trait_ref_and_return_type(obligation.predicate.def_id(), - obligation.predicate.0.self_ty(), // (1) - closure_type, - util::TupleArgumentsFlag::No); + // (1) Feels icky to skip the binder here, but OTOH we know // that the self-type is an unboxed closure type and hence is // in fact unparameterized (or at least does not reference any // regions bound in the obligation). Still probably some // refactoring could make this nicer. - ty::Binder(trait_ref) + self.tcx().closure_trait_ref_and_return_type(obligation.predicate.def_id(), + obligation.predicate + .skip_binder().self_ty(), // (1) + closure_type, + util::TupleArgumentsFlag::No) + .map_bound(|(trait_ref, _)| trait_ref) } fn generator_trait_ref_unnormalized(&mut self, @@ -3222,17 +3299,18 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { -> ty::PolyTraitRef<'tcx> { let gen_sig = substs.generator_poly_sig(closure_def_id, self.tcx()); - let ty::Binder((trait_ref, ..)) = - self.tcx().generator_trait_ref_and_outputs(obligation.predicate.def_id(), - obligation.predicate.0.self_ty(), // (1) - gen_sig); + // (1) Feels icky to skip the binder here, but OTOH we know // that the self-type is an generator type and hence is // in fact unparameterized (or at least does not reference any // regions bound in the obligation). Still probably some // refactoring could make this nicer. - ty::Binder(trait_ref) + self.tcx().generator_trait_ref_and_outputs(obligation.predicate.def_id(), + obligation.predicate + .skip_binder().self_ty(), // (1) + gen_sig) + .map_bound(|(trait_ref, ..)| trait_ref) } /// Returns the obligations that are implied by instantiating an diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index 31c5bf1bbad..d7e42655bbb 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -177,6 +177,7 @@ impl<'a, 'tcx> Lift<'tcx> for traits::SelectionError<'a> { super::ConstEvalFailure(ref err) => { tcx.lift(err).map(super::ConstEvalFailure) } + super::Overflow => bug!() // FIXME: ape ConstEvalFailure? } } } @@ -491,6 +492,7 @@ impl<'tcx> fmt::Display for traits::Goal<'tcx> { // FIXME: appropriate binder names write!(fmt, "{}<> {{ {} }}", qkind, goal.skip_binder()) } + CannotProve => write!(fmt, "CannotProve"), } } } @@ -557,6 +559,7 @@ EnumTypeFoldableImpl! { (traits::Goal::Not)(goal), (traits::Goal::DomainGoal)(domain_goal), (traits::Goal::Quantified)(qkind, goal), + (traits::Goal::CannotProve), } } diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index 9e38911f53c..3c62f04afc5 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -209,13 +209,13 @@ impl<'cx, 'gcx, 'tcx> Elaborator<'cx, 'gcx, 'tcx> { None } else { Some(ty::Predicate::RegionOutlives( - ty::Binder(ty::OutlivesPredicate(r, r_min)))) + ty::Binder::dummy(ty::OutlivesPredicate(r, r_min)))) }, Component::Param(p) => { let ty = tcx.mk_param(p.idx, p.name); Some(ty::Predicate::TypeOutlives( - ty::Binder(ty::OutlivesPredicate(ty, r_min)))) + ty::Binder::dummy(ty::OutlivesPredicate(ty, r_min)))) }, Component::UnresolvedInferenceVariable(_) => { @@ -514,7 +514,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { def_id: fn_trait_def_id, substs: self.mk_substs_trait(self_ty, &[arguments_tuple]), }; - ty::Binder((trait_ref, sig.skip_binder().output())) + ty::Binder::bind((trait_ref, sig.skip_binder().output())) } pub fn generator_trait_ref_and_outputs(self, @@ -527,7 +527,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { def_id: fn_trait_def_id, substs: self.mk_substs_trait(self_ty, &[]), }; - ty::Binder((trait_ref, sig.skip_binder().yield_ty, sig.skip_binder().return_ty)) + ty::Binder::bind((trait_ref, sig.skip_binder().yield_ty, sig.skip_binder().return_ty)) } pub fn impl_is_default(self, node_item_def_id: DefId) -> bool { diff --git a/src/librustc/ty/_match.rs b/src/librustc/ty/_match.rs index f86c1cf0dd6..047bfcc8c6f 100644 --- a/src/librustc/ty/_match.rs +++ b/src/librustc/ty/_match.rs @@ -92,6 +92,6 @@ impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Match<'a, 'gcx, 'tcx> { -> RelateResult<'tcx, ty::Binder<T>> where T: Relate<'tcx> { - Ok(ty::Binder(self.relate(a.skip_binder(), b.skip_binder())?)) + Ok(ty::Binder::bind(self.relate(a.skip_binder(), b.skip_binder())?)) } } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 28ad5edbd2d..c28fcfe8805 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -34,11 +34,11 @@ use middle::resolve_lifetime::{self, ObjectLifetimeDefault}; use middle::stability; use mir::{self, Mir, interpret}; use mir::interpret::{Value, PrimVal}; -use ty::subst::{Kind, Substs}; +use ty::subst::{Kind, Substs, Subst}; use ty::ReprOptions; use ty::Instance; use traits; -use traits::{Clause, Goal}; +use traits::{Clause, Clauses, Goal, Goals}; use ty::{self, Ty, TypeAndMut}; use ty::{TyS, TypeVariants, Slice}; use ty::{AdtKind, AdtDef, ClosureSubsts, GeneratorInterior, Region, Const}; @@ -70,7 +70,7 @@ use std::ops::Deref; use std::iter; use std::sync::mpsc; use std::sync::Arc; -use syntax::abi; +use rustc_target::spec::abi; use syntax::ast::{self, NodeId}; use syntax::attr; use syntax::codemap::MultiSpan; @@ -1204,7 +1204,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { f: F) -> R where F: for<'b> FnOnce(TyCtxt<'b, 'tcx, 'tcx>) -> R { - let data_layout = TargetDataLayout::parse(s); + let data_layout = TargetDataLayout::parse(&s.target.target).unwrap_or_else(|err| { + s.fatal(&err); + }); let interners = CtxtInterners::new(&arenas.interner); let common_types = CommonTypes::new(&interners); let dep_graph = hir.dep_graph.clone(); @@ -1562,6 +1564,7 @@ impl<'gcx: 'tcx, 'tcx> GlobalCtxt<'gcx> { tcx, query: icx.query.clone(), layout_depth: icx.layout_depth, + task: icx.task, }; ty::tls::enter_context(&new_icx, |new_icx| { f(new_icx.tcx) @@ -1741,6 +1744,7 @@ pub mod tls { use errors::{Diagnostic, TRACK_DIAGNOSTICS}; use rustc_data_structures::OnDrop; use rustc_data_structures::sync::Lrc; + use dep_graph::OpenTask; /// This is the implicit state of rustc. It contains the current /// TyCtxt and query. It is updated when creating a local interner or @@ -1759,6 +1763,10 @@ pub mod tls { /// Used to prevent layout from recursing too deeply. pub layout_depth: usize, + + /// The current dep graph task. This is used to add dependencies to queries + /// when executing them + pub task: &'a OpenTask, } // A thread local value which stores a pointer to the current ImplicitCtxt @@ -1845,6 +1853,7 @@ pub mod tls { tcx, query: None, layout_depth: 0, + task: &OpenTask::Ignore, }; enter_context(&icx, |_| { f(tcx) @@ -2319,7 +2328,15 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn mk_box(self, ty: Ty<'tcx>) -> Ty<'tcx> { let def_id = self.require_lang_item(lang_items::OwnedBoxLangItem); let adt_def = self.adt_def(def_id); - let substs = self.mk_substs(iter::once(Kind::from(ty))); + let generics = self.generics_of(def_id); + let mut substs = vec![Kind::from(ty)]; + // Add defaults for other generic params if there are some. + for def in generics.types.iter().skip(1) { + assert!(def.has_default); + let ty = self.type_of(def.def_id).subst(self, &substs); + substs.push(ty.into()); + } + let substs = self.mk_substs(substs.into_iter()); self.mk_ty(TyAdt(adt_def, substs)) } @@ -2374,6 +2391,14 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.intern_tup(&[]) } + pub fn mk_diverging_default(self) -> Ty<'tcx> { + if self.features().never_type { + self.types.never + } else { + self.intern_tup(&[]) + } + } + pub fn mk_bool(self) -> Ty<'tcx> { self.mk_ty(TyBool) } @@ -2454,7 +2479,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } pub fn mk_self_type(self) -> Ty<'tcx> { - self.mk_param(0, keywords::SelfType.name().as_str()) + self.mk_param(0, keywords::SelfType.name().as_interned_str()) } pub fn mk_param_from_def(self, def: &ty::TypeParameterDef) -> Ty<'tcx> { @@ -2509,7 +2534,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } - pub fn intern_clauses(self, ts: &[Clause<'tcx>]) -> &'tcx Slice<Clause<'tcx>> { + pub fn intern_clauses(self, ts: &[Clause<'tcx>]) -> Clauses<'tcx> { if ts.len() == 0 { Slice::empty() } else { @@ -2517,7 +2542,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } - pub fn intern_goals(self, ts: &[Goal<'tcx>]) -> &'tcx Slice<Goal<'tcx>> { + pub fn intern_goals(self, ts: &[Goal<'tcx>]) -> Goals<'tcx> { if ts.len() == 0 { Slice::empty() } else { @@ -2571,13 +2596,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.mk_substs(iter::once(s).chain(t.into_iter().cloned()).map(Kind::from)) } - pub fn mk_clauses<I: InternAs<[Clause<'tcx>], - &'tcx Slice<Clause<'tcx>>>>(self, iter: I) -> I::Output { + pub fn mk_clauses<I: InternAs<[Clause<'tcx>], Clauses<'tcx>>>(self, iter: I) -> I::Output { iter.intern_with(|xs| self.intern_clauses(xs)) } - pub fn mk_goals<I: InternAs<[Goal<'tcx>], - &'tcx Slice<Goal<'tcx>>>>(self, iter: I) -> I::Output { + pub fn mk_goals<I: InternAs<[Goal<'tcx>], Goals<'tcx>>>(self, iter: I) -> I::Output { iter.intern_with(|xs| self.intern_goals(xs)) } diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index eb392418647..cf2004a681e 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -11,7 +11,7 @@ use hir::def_id::DefId; use ty::{self, BoundRegion, Region, Ty, TyCtxt}; use std::fmt; -use syntax::abi; +use rustc_target::spec::abi; use syntax::ast; use errors::DiagnosticBuilder; use syntax_pos::Span; diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index 8071cd0c639..650ac4e6f6d 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -43,8 +43,8 @@ use middle::const_val::ConstVal; use hir::def_id::DefId; use ty::{self, Binder, Ty, TyCtxt, TypeFlags}; +use rustc_data_structures::lazy_btree_map::LazyBTreeMap; use std::fmt; -use std::collections::BTreeMap; use util::nodemap::FxHashSet; /// The TypeFoldable trait is implemented for every type that can be folded. @@ -334,7 +334,7 @@ struct RegionReplacer<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { tcx: TyCtxt<'a, 'gcx, 'tcx>, current_depth: u32, fld_r: &'a mut (dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx> + 'a), - map: BTreeMap<ty::BoundRegion, ty::Region<'tcx>> + map: LazyBTreeMap<ty::BoundRegion, ty::Region<'tcx>> } impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { @@ -349,7 +349,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn replace_late_bound_regions<T,F>(self, value: &Binder<T>, mut f: F) - -> (T, BTreeMap<ty::BoundRegion, ty::Region<'tcx>>) + -> (T, LazyBTreeMap<ty::BoundRegion, ty::Region<'tcx>>) where F : FnMut(ty::BoundRegion) -> ty::Region<'tcx>, T : TypeFoldable<'tcx>, { @@ -394,7 +394,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } }); - Binder(value) + Binder::bind(value) } /// Returns a set of all late-bound regions that are constrained @@ -446,7 +446,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { where T : TypeFoldable<'tcx>, { let mut counter = 0; - Binder(self.replace_late_bound_regions(sig, |_| { + Binder::bind(self.replace_late_bound_regions(sig, |_| { counter += 1; self.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1), ty::BrAnon(counter))) }).0) @@ -462,7 +462,7 @@ impl<'a, 'gcx, 'tcx> RegionReplacer<'a, 'gcx, 'tcx> { tcx, current_depth: 1, fld_r, - map: BTreeMap::default() + map: LazyBTreeMap::default() } } } diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index 76f7a0b59a2..ecd415c4bc4 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -12,7 +12,7 @@ use hir::def_id::DefId; use ty::{self, Ty, TypeFoldable, Substs, TyCtxt}; use ty::subst::Kind; use traits; -use syntax::abi::Abi; +use rustc_target::spec::abi::Abi; use util::ppaux; use std::fmt; @@ -259,7 +259,7 @@ fn resolve_associated_item<'a, 'tcx>( def_id, trait_id, rcvr_substs); let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs); - let vtbl = tcx.trans_fulfill_obligation((param_env, ty::Binder(trait_ref))); + let vtbl = tcx.trans_fulfill_obligation((param_env, ty::Binder::bind(trait_ref))); // Now that we know which impl is being used, we can dispatch to // the actual function: diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs index 8189064db69..752b7f69a6a 100644 --- a/src/librustc/ty/item_path.rs +++ b/src/librustc/ty/item_path.rs @@ -14,7 +14,7 @@ use ty::{self, Ty, TyCtxt}; use middle::cstore::{ExternCrate, ExternCrateSource}; use syntax::ast; use syntax::symbol::Symbol; -use syntax::symbol::InternedString; +use syntax::symbol::LocalInternedString; use std::cell::Cell; @@ -131,7 +131,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { { let visible_parent_map = self.visible_parent_map(LOCAL_CRATE); - let (mut cur_def, mut cur_path) = (external_def_id, Vec::<InternedString>::new()); + let (mut cur_def, mut cur_path) = (external_def_id, Vec::<LocalInternedString>::new()); loop { // If `cur_def` is a direct or injected extern crate, push the path to the crate // followed by the path to the item within the crate and return. @@ -168,8 +168,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } let data = cur_def_key.disambiguated_data.data; - let symbol = - data.get_opt_name().unwrap_or_else(|| Symbol::intern("<unnamed>").as_str()); + let symbol = data.get_opt_name().map(|n| n.as_str()).unwrap_or_else(|| { + Symbol::intern("<unnamed>").as_str() + }); cur_path.push(symbol); match visible_parent_map.get(&cur_def) { @@ -204,6 +205,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // finer-grained distinctions, e.g. between enum/struct). data @ DefPathData::Misc | data @ DefPathData::TypeNs(..) | + data @ DefPathData::Trait(..) | + data @ DefPathData::AssocTypeInTrait(..) | + data @ DefPathData::AssocTypeInImpl(..) | data @ DefPathData::ValueNs(..) | data @ DefPathData::Module(..) | data @ DefPathData::TypeParam(..) | @@ -218,7 +222,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { data @ DefPathData::GlobalMetaData(..) => { let parent_def_id = self.parent_def_id(def_id).unwrap(); self.push_item_path(buffer, parent_def_id); - buffer.push(&data.as_interned_str()); + buffer.push(&data.as_interned_str().as_symbol().as_str()); } DefPathData::StructCtor => { // present `X` instead of `X::{{constructor}}` let parent_def_id = self.parent_def_id(def_id).unwrap(); diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 6bd833568d4..55137e28911 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -8,10 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -pub use self::Integer::*; -pub use self::Primitive::*; - -use session::{self, DataTypeKind, Session}; +use session::{self, DataTypeKind}; use ty::{self, Ty, TyCtxt, TypeFoldable, ReprOptions}; use syntax::ast::{self, FloatTy, IntTy, UintTy}; @@ -21,432 +18,28 @@ use syntax_pos::DUMMY_SP; use std::cmp; use std::fmt; use std::i128; -use std::iter; use std::mem; -use std::ops::{Add, Sub, Mul, AddAssign, Deref, RangeInclusive}; +use std::ops::RangeInclusive; use ich::StableHashingContext; use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult}; -/// Parsed [Data layout](http://llvm.org/docs/LangRef.html#data-layout) -/// for a target, which contains everything needed to compute layouts. -pub struct TargetDataLayout { - pub endian: Endian, - pub i1_align: Align, - pub i8_align: Align, - pub i16_align: Align, - pub i32_align: Align, - pub i64_align: Align, - pub i128_align: Align, - pub f32_align: Align, - pub f64_align: Align, - pub pointer_size: Size, - pub pointer_align: Align, - pub aggregate_align: Align, - - /// Alignments for vector types. - pub vector_align: Vec<(Size, Align)> -} - -impl Default for TargetDataLayout { - /// Creates an instance of `TargetDataLayout`. - fn default() -> TargetDataLayout { - TargetDataLayout { - endian: Endian::Big, - i1_align: Align::from_bits(8, 8).unwrap(), - i8_align: Align::from_bits(8, 8).unwrap(), - i16_align: Align::from_bits(16, 16).unwrap(), - i32_align: Align::from_bits(32, 32).unwrap(), - i64_align: Align::from_bits(32, 64).unwrap(), - i128_align: Align::from_bits(32, 64).unwrap(), - f32_align: Align::from_bits(32, 32).unwrap(), - f64_align: Align::from_bits(64, 64).unwrap(), - pointer_size: Size::from_bits(64), - pointer_align: Align::from_bits(64, 64).unwrap(), - aggregate_align: Align::from_bits(0, 64).unwrap(), - vector_align: vec![ - (Size::from_bits(64), Align::from_bits(64, 64).unwrap()), - (Size::from_bits(128), Align::from_bits(128, 128).unwrap()) - ] - } - } -} - -impl TargetDataLayout { - pub fn parse(sess: &Session) -> TargetDataLayout { - // Parse a bit count from a string. - let parse_bits = |s: &str, kind: &str, cause: &str| { - s.parse::<u64>().unwrap_or_else(|err| { - sess.err(&format!("invalid {} `{}` for `{}` in \"data-layout\": {}", - kind, s, cause, err)); - 0 - }) - }; - - // Parse a size string. - let size = |s: &str, cause: &str| { - Size::from_bits(parse_bits(s, "size", cause)) - }; - - // Parse an alignment string. - let align = |s: &[&str], cause: &str| { - if s.is_empty() { - sess.err(&format!("missing alignment for `{}` in \"data-layout\"", cause)); - } - let abi = parse_bits(s[0], "alignment", cause); - let pref = s.get(1).map_or(abi, |pref| parse_bits(pref, "alignment", cause)); - Align::from_bits(abi, pref).unwrap_or_else(|err| { - sess.err(&format!("invalid alignment for `{}` in \"data-layout\": {}", - cause, err)); - Align::from_bits(8, 8).unwrap() - }) - }; - - let mut dl = TargetDataLayout::default(); - let mut i128_align_src = 64; - for spec in sess.target.target.data_layout.split("-") { - match &spec.split(":").collect::<Vec<_>>()[..] { - &["e"] => dl.endian = Endian::Little, - &["E"] => dl.endian = Endian::Big, - &["a", ref a..] => dl.aggregate_align = align(a, "a"), - &["f32", ref a..] => dl.f32_align = align(a, "f32"), - &["f64", ref a..] => dl.f64_align = align(a, "f64"), - &[p @ "p", s, ref a..] | &[p @ "p0", s, ref a..] => { - dl.pointer_size = size(s, p); - dl.pointer_align = align(a, p); - } - &[s, ref a..] if s.starts_with("i") => { - let bits = match s[1..].parse::<u64>() { - Ok(bits) => bits, - Err(_) => { - size(&s[1..], "i"); // For the user error. - continue; - } - }; - let a = align(a, s); - match bits { - 1 => dl.i1_align = a, - 8 => dl.i8_align = a, - 16 => dl.i16_align = a, - 32 => dl.i32_align = a, - 64 => dl.i64_align = a, - _ => {} - } - if bits >= i128_align_src && bits <= 128 { - // Default alignment for i128 is decided by taking the alignment of - // largest-sized i{64...128}. - i128_align_src = bits; - dl.i128_align = a; - } - } - &[s, ref a..] if s.starts_with("v") => { - let v_size = size(&s[1..], "v"); - let a = align(a, s); - if let Some(v) = dl.vector_align.iter_mut().find(|v| v.0 == v_size) { - v.1 = a; - continue; - } - // No existing entry, add a new one. - dl.vector_align.push((v_size, a)); - } - _ => {} // Ignore everything else. - } - } - - // Perform consistency checks against the Target information. - let endian_str = match dl.endian { - Endian::Little => "little", - Endian::Big => "big" - }; - if endian_str != sess.target.target.target_endian { - sess.err(&format!("inconsistent target specification: \"data-layout\" claims \ - architecture is {}-endian, while \"target-endian\" is `{}`", - endian_str, sess.target.target.target_endian)); - } - - if dl.pointer_size.bits().to_string() != sess.target.target.target_pointer_width { - sess.err(&format!("inconsistent target specification: \"data-layout\" claims \ - pointers are {}-bit, while \"target-pointer-width\" is `{}`", - dl.pointer_size.bits(), sess.target.target.target_pointer_width)); - } - - dl - } - - /// Return exclusive upper bound on object size. - /// - /// The theoretical maximum object size is defined as the maximum positive `isize` value. - /// This ensures that the `offset` semantics remain well-defined by allowing it to correctly - /// index every address within an object along with one byte past the end, along with allowing - /// `isize` to store the difference between any two pointers into an object. - /// - /// The upper bound on 64-bit currently needs to be lower because LLVM uses a 64-bit integer - /// to represent object size in bits. It would need to be 1 << 61 to account for this, but is - /// currently conservatively bounded to 1 << 47 as that is enough to cover the current usable - /// address space on 64-bit ARMv8 and x86_64. - pub fn obj_size_bound(&self) -> u64 { - match self.pointer_size.bits() { - 16 => 1 << 15, - 32 => 1 << 31, - 64 => 1 << 47, - bits => bug!("obj_size_bound: unknown pointer bit size {}", bits) - } - } - - pub fn ptr_sized_integer(&self) -> Integer { - match self.pointer_size.bits() { - 16 => I16, - 32 => I32, - 64 => I64, - bits => bug!("ptr_sized_integer: unknown pointer bit size {}", bits) - } - } - - pub fn vector_align(&self, vec_size: Size) -> Align { - for &(size, align) in &self.vector_align { - if size == vec_size { - return align; - } - } - // Default to natural alignment, which is what LLVM does. - // That is, use the size, rounded up to a power of 2. - let align = vec_size.bytes().next_power_of_two(); - Align::from_bytes(align, align).unwrap() - } -} - -pub trait HasDataLayout: Copy { - fn data_layout(&self) -> &TargetDataLayout; -} - -impl<'a> HasDataLayout for &'a TargetDataLayout { - fn data_layout(&self) -> &TargetDataLayout { - self - } -} - -/// Endianness of the target, which must match cfg(target-endian). -#[derive(Copy, Clone)] -pub enum Endian { - Little, - Big -} - -/// Size of a type in bytes. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -pub struct Size { - raw: u64 -} - -impl Size { - pub fn from_bits(bits: u64) -> Size { - // Avoid potential overflow from `bits + 7`. - Size::from_bytes(bits / 8 + ((bits % 8) + 7) / 8) - } - - pub fn from_bytes(bytes: u64) -> Size { - if bytes >= (1 << 61) { - bug!("Size::from_bytes: {} bytes in bits doesn't fit in u64", bytes) - } - Size { - raw: bytes - } - } - - pub fn bytes(self) -> u64 { - self.raw - } - - pub fn bits(self) -> u64 { - self.bytes() * 8 - } - - pub fn abi_align(self, align: Align) -> Size { - let mask = align.abi() - 1; - Size::from_bytes((self.bytes() + mask) & !mask) - } - - pub fn is_abi_aligned(self, align: Align) -> bool { - let mask = align.abi() - 1; - self.bytes() & mask == 0 - } - - pub fn checked_add<C: HasDataLayout>(self, offset: Size, cx: C) -> Option<Size> { - let dl = cx.data_layout(); - - // Each Size is less than dl.obj_size_bound(), so the sum is - // also less than 1 << 62 (and therefore can't overflow). - let bytes = self.bytes() + offset.bytes(); - - if bytes < dl.obj_size_bound() { - Some(Size::from_bytes(bytes)) - } else { - None - } - } - - pub fn checked_mul<C: HasDataLayout>(self, count: u64, cx: C) -> Option<Size> { - let dl = cx.data_layout(); - - match self.bytes().checked_mul(count) { - Some(bytes) if bytes < dl.obj_size_bound() => { - Some(Size::from_bytes(bytes)) - } - _ => None - } - } -} - -// Panicking addition, subtraction and multiplication for convenience. -// Avoid during layout computation, return `LayoutError` instead. - -impl Add for Size { - type Output = Size; - fn add(self, other: Size) -> Size { - // Each Size is less than 1 << 61, so the sum is - // less than 1 << 62 (and therefore can't overflow). - Size::from_bytes(self.bytes() + other.bytes()) - } -} - -impl Sub for Size { - type Output = Size; - fn sub(self, other: Size) -> Size { - // Each Size is less than 1 << 61, so an underflow - // would result in a value larger than 1 << 61, - // which Size::from_bytes will catch for us. - Size::from_bytes(self.bytes() - other.bytes()) - } -} - -impl Mul<u64> for Size { - type Output = Size; - fn mul(self, count: u64) -> Size { - match self.bytes().checked_mul(count) { - Some(bytes) => Size::from_bytes(bytes), - None => { - bug!("Size::mul: {} * {} doesn't fit in u64", self.bytes(), count) - } - } - } -} - -impl AddAssign for Size { - fn add_assign(&mut self, other: Size) { - *self = *self + other; - } -} +pub use rustc_target::abi::*; -/// Alignment of a type in bytes, both ABI-mandated and preferred. -/// Each field is a power of two, giving the alignment a maximum -/// value of 2<sup>(2<sup>8</sup> - 1)</sup>, which is limited by LLVM to a i32, with -/// a maximum capacity of 2<sup>31</sup> - 1 or 2147483647. -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] -pub struct Align { - abi_pow2: u8, - pref_pow2: u8, -} - -impl Align { - pub fn from_bits(abi: u64, pref: u64) -> Result<Align, String> { - Align::from_bytes(Size::from_bits(abi).bytes(), - Size::from_bits(pref).bytes()) - } - - pub fn from_bytes(abi: u64, pref: u64) -> Result<Align, String> { - let log2 = |align: u64| { - // Treat an alignment of 0 bytes like 1-byte alignment. - if align == 0 { - return Ok(0); - } - - let mut bytes = align; - let mut pow: u8 = 0; - while (bytes & 1) == 0 { - pow += 1; - bytes >>= 1; - } - if bytes != 1 { - Err(format!("`{}` is not a power of 2", align)) - } else if pow > 30 { - Err(format!("`{}` is too large", align)) - } else { - Ok(pow) - } - }; - - Ok(Align { - abi_pow2: log2(abi)?, - pref_pow2: log2(pref)?, - }) - } - - pub fn abi(self) -> u64 { - 1 << self.abi_pow2 - } - - pub fn pref(self) -> u64 { - 1 << self.pref_pow2 - } - - pub fn abi_bits(self) -> u64 { - self.abi() * 8 - } - - pub fn pref_bits(self) -> u64 { - self.pref() * 8 - } - - pub fn min(self, other: Align) -> Align { - Align { - abi_pow2: cmp::min(self.abi_pow2, other.abi_pow2), - pref_pow2: cmp::min(self.pref_pow2, other.pref_pow2), - } - } - - pub fn max(self, other: Align) -> Align { - Align { - abi_pow2: cmp::max(self.abi_pow2, other.abi_pow2), - pref_pow2: cmp::max(self.pref_pow2, other.pref_pow2), - } - } -} - -/// Integers, also used for enum discriminants. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -pub enum Integer { - I8, - I16, - I32, - I64, - I128, +pub trait IntegerExt { + fn to_ty<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, signed: bool) -> Ty<'tcx>; + fn from_attr<C: HasDataLayout>(cx: C, ity: attr::IntType) -> Integer; + fn repr_discr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + ty: Ty<'tcx>, + repr: &ReprOptions, + min: i128, + max: i128) + -> (Integer, bool); } -impl<'a, 'tcx> Integer { - pub fn size(&self) -> Size { - match *self { - I8 => Size::from_bytes(1), - I16 => Size::from_bytes(2), - I32 => Size::from_bytes(4), - I64 => Size::from_bytes(8), - I128 => Size::from_bytes(16), - } - } - - pub fn align<C: HasDataLayout>(&self, cx: C) -> Align { - let dl = cx.data_layout(); - - match *self { - I8 => dl.i8_align, - I16 => dl.i16_align, - I32 => dl.i32_align, - I64 => dl.i64_align, - I128 => dl.i128_align, - } - } - - pub fn to_ty(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, signed: bool) -> Ty<'tcx> { +impl IntegerExt for Integer { + fn to_ty<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, signed: bool) -> Ty<'tcx> { match (*self, signed) { (I8, false) => tcx.types.u8, (I16, false) => tcx.types.u16, @@ -461,57 +54,8 @@ impl<'a, 'tcx> Integer { } } - /// Find the smallest Integer type which can represent the signed value. - pub fn fit_signed(x: i128) -> Integer { - match x { - -0x0000_0000_0000_0080...0x0000_0000_0000_007f => I8, - -0x0000_0000_0000_8000...0x0000_0000_0000_7fff => I16, - -0x0000_0000_8000_0000...0x0000_0000_7fff_ffff => I32, - -0x8000_0000_0000_0000...0x7fff_ffff_ffff_ffff => I64, - _ => I128 - } - } - - /// Find the smallest Integer type which can represent the unsigned value. - pub fn fit_unsigned(x: u128) -> Integer { - match x { - 0...0x0000_0000_0000_00ff => I8, - 0...0x0000_0000_0000_ffff => I16, - 0...0x0000_0000_ffff_ffff => I32, - 0...0xffff_ffff_ffff_ffff => I64, - _ => I128, - } - } - - /// Find the smallest integer with the given alignment. - pub fn for_abi_align<C: HasDataLayout>(cx: C, align: Align) -> Option<Integer> { - let dl = cx.data_layout(); - - let wanted = align.abi(); - for &candidate in &[I8, I16, I32, I64, I128] { - if wanted == candidate.align(dl).abi() && wanted == candidate.size().bytes() { - return Some(candidate); - } - } - None - } - - /// Find the largest integer with the given alignment or less. - pub fn approximate_abi_align<C: HasDataLayout>(cx: C, align: Align) -> Integer { - let dl = cx.data_layout(); - - let wanted = align.abi(); - // FIXME(eddyb) maybe include I128 in the future, when it works everywhere. - for &candidate in &[I64, I32, I16] { - if wanted >= candidate.align(dl).abi() && wanted >= candidate.size().bytes() { - return candidate; - } - } - I8 - } - /// Get the Integer type from an attr::IntType. - pub fn from_attr<C: HasDataLayout>(cx: C, ity: attr::IntType) -> Integer { + fn from_attr<C: HasDataLayout>(cx: C, ity: attr::IntType) -> Integer { let dl = cx.data_layout(); match ity { @@ -530,7 +74,7 @@ impl<'a, 'tcx> Integer { /// signed discriminant range and #[repr] attribute. /// N.B.: u128 values above i128::MAX will be treated as signed, but /// that shouldn't affect anything, other than maybe debuginfo. - fn repr_discr(tcx: TyCtxt<'a, 'tcx, 'tcx>, + fn repr_discr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>, repr: &ReprOptions, min: i128, @@ -578,46 +122,12 @@ impl<'a, 'tcx> Integer { } } -/// Fundamental unit of memory access and layout. -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub enum Primitive { - /// The `bool` is the signedness of the `Integer` type. - /// - /// One would think we would not care about such details this low down, - /// but some ABIs are described in terms of C types and ISAs where the - /// integer arithmetic is done on {sign,zero}-extended registers, e.g. - /// a negative integer passed by zero-extension will appear positive in - /// the callee, and most operations on it will produce the wrong values. - Int(Integer, bool), - F32, - F64, - Pointer +pub trait PrimitiveExt { + fn to_ty<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx>; } -impl<'a, 'tcx> Primitive { - pub fn size<C: HasDataLayout>(self, cx: C) -> Size { - let dl = cx.data_layout(); - - match self { - Int(i, _) => i.size(), - F32 => Size::from_bits(32), - F64 => Size::from_bits(64), - Pointer => dl.pointer_size - } - } - - pub fn align<C: HasDataLayout>(self, cx: C) -> Align { - let dl = cx.data_layout(); - - match self { - Int(i, _) => i.align(dl), - F32 => dl.f32_align, - F64 => dl.f64_align, - Pointer => dl.pointer_align - } - } - - pub fn to_ty(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx> { +impl PrimitiveExt for Primitive { + fn to_ty<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx> { match *self { Int(i, signed) => i.to_ty(tcx, signed), F32 => tcx.types.f32, @@ -627,29 +137,6 @@ impl<'a, 'tcx> Primitive { } } -/// Information about one scalar component of a Rust type. -#[derive(Clone, PartialEq, Eq, Hash, Debug)] -pub struct Scalar { - pub value: Primitive, - - /// Inclusive wrap-around range of valid values, that is, if - /// min > max, it represents min..=u128::MAX followed by 0..=max. - // FIXME(eddyb) always use the shortest range, e.g. by finding - // the largest space between two consecutive valid values and - // taking everything else as the (shortest) valid range. - pub valid_range: RangeInclusive<u128>, -} - -impl Scalar { - pub fn is_bool(&self) -> bool { - if let Int(I8, _) = self.value { - self.valid_range == (0..=1) - } else { - false - } - } -} - /// The first half of a fat pointer. /// /// - For a trait object, this is the address of the box. @@ -662,183 +149,6 @@ pub const FAT_PTR_ADDR: usize = 0; /// - For a slice, this is the length. pub const FAT_PTR_EXTRA: usize = 1; -/// Describes how the fields of a type are located in memory. -#[derive(PartialEq, Eq, Hash, Debug)] -pub enum FieldPlacement { - /// All fields start at no offset. The `usize` is the field count. - Union(usize), - - /// Array/vector-like placement, with all fields of identical types. - Array { - stride: Size, - count: u64 - }, - - /// Struct-like placement, with precomputed offsets. - /// - /// Fields are guaranteed to not overlap, but note that gaps - /// before, between and after all the fields are NOT always - /// padding, and as such their contents may not be discarded. - /// For example, enum variants leave a gap at the start, - /// where the discriminant field in the enum layout goes. - Arbitrary { - /// Offsets for the first byte of each field, - /// ordered to match the source definition order. - /// This vector does not go in increasing order. - // FIXME(eddyb) use small vector optimization for the common case. - offsets: Vec<Size>, - - /// Maps source order field indices to memory order indices, - /// depending how fields were permuted. - // FIXME(camlorn) also consider small vector optimization here. - memory_index: Vec<u32> - } -} - -impl FieldPlacement { - pub fn count(&self) -> usize { - match *self { - FieldPlacement::Union(count) => count, - FieldPlacement::Array { count, .. } => { - let usize_count = count as usize; - assert_eq!(usize_count as u64, count); - usize_count - } - FieldPlacement::Arbitrary { ref offsets, .. } => offsets.len() - } - } - - pub fn offset(&self, i: usize) -> Size { - match *self { - FieldPlacement::Union(_) => Size::from_bytes(0), - FieldPlacement::Array { stride, count } => { - let i = i as u64; - assert!(i < count); - stride * i - } - FieldPlacement::Arbitrary { ref offsets, .. } => offsets[i] - } - } - - pub fn memory_index(&self, i: usize) -> usize { - match *self { - FieldPlacement::Union(_) | - FieldPlacement::Array { .. } => i, - FieldPlacement::Arbitrary { ref memory_index, .. } => { - let r = memory_index[i]; - assert_eq!(r as usize as u32, r); - r as usize - } - } - } - - /// Get source indices of the fields by increasing offsets. - #[inline] - pub fn index_by_increasing_offset<'a>(&'a self) -> impl iter::Iterator<Item=usize>+'a { - let mut inverse_small = [0u8; 64]; - let mut inverse_big = vec![]; - let use_small = self.count() <= inverse_small.len(); - - // We have to write this logic twice in order to keep the array small. - if let FieldPlacement::Arbitrary { ref memory_index, .. } = *self { - if use_small { - for i in 0..self.count() { - inverse_small[memory_index[i] as usize] = i as u8; - } - } else { - inverse_big = vec![0; self.count()]; - for i in 0..self.count() { - inverse_big[memory_index[i] as usize] = i as u32; - } - } - } - - (0..self.count()).map(move |i| { - match *self { - FieldPlacement::Union(_) | - FieldPlacement::Array { .. } => i, - FieldPlacement::Arbitrary { .. } => { - if use_small { inverse_small[i] as usize } - else { inverse_big[i] as usize } - } - } - }) - } -} - -/// Describes how values of the type are passed by target ABIs, -/// in terms of categories of C types there are ABI rules for. -#[derive(Clone, PartialEq, Eq, Hash, Debug)] -pub enum Abi { - Uninhabited, - Scalar(Scalar), - ScalarPair(Scalar, Scalar), - Vector { - element: Scalar, - count: u64 - }, - Aggregate { - /// If true, the size is exact, otherwise it's only a lower bound. - sized: bool, - } -} - -impl Abi { - /// Returns true if the layout corresponds to an unsized type. - pub fn is_unsized(&self) -> bool { - match *self { - Abi::Uninhabited | - Abi::Scalar(_) | - Abi::ScalarPair(..) | - Abi::Vector { .. } => false, - Abi::Aggregate { sized } => !sized - } - } - - /// Returns true if this is a single signed integer scalar - pub fn is_signed(&self) -> bool { - match *self { - Abi::Scalar(ref scal) => match scal.value { - Primitive::Int(_, signed) => signed, - _ => false, - }, - _ => false, - } - } -} - -#[derive(PartialEq, Eq, Hash, Debug)] -pub enum Variants { - /// Single enum variants, structs/tuples, unions, and all non-ADTs. - Single { - index: usize - }, - - /// General-case enums: for each case there is a struct, and they all have - /// all space reserved for the discriminant, and their first field starts - /// at a non-0 offset, after where the discriminant would go. - Tagged { - discr: Scalar, - variants: Vec<LayoutDetails>, - }, - - /// Multiple cases distinguished by a niche (values invalid for a type): - /// 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)`. - /// - /// For example, `Option<(usize, &T)>` is represented such that - /// `None` has a null pointer for the second tuple field, and - /// `Some` is the identity function (with a non-null reference). - NicheFilling { - dataful_variant: usize, - niche_variants: RangeInclusive<usize>, - niche: Scalar, - niche_start: u128, - variants: Vec<LayoutDetails>, - } -} - #[derive(Copy, Clone, Debug)] pub enum LayoutError<'tcx> { Unknown(Ty<'tcx>), @@ -858,40 +168,6 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> { } } -#[derive(PartialEq, Eq, Hash, Debug)] -pub struct LayoutDetails { - pub variants: Variants, - pub fields: FieldPlacement, - pub abi: Abi, - pub align: Align, - pub size: Size -} - -impl LayoutDetails { - fn scalar<C: HasDataLayout>(cx: C, scalar: Scalar) -> Self { - let size = scalar.value.size(cx); - let align = scalar.value.align(cx); - LayoutDetails { - variants: Variants::Single { index: 0 }, - fields: FieldPlacement::Union(0), - abi: Abi::Scalar(scalar), - size, - align, - } - } - - fn uninhabited(field_count: usize) -> Self { - let align = Align::from_bytes(1, 1).unwrap(); - LayoutDetails { - variants: Variants::Single { index: 0 }, - fields: FieldPlacement::Union(field_count), - abi: Abi::Uninhabited, - align, - size: Size::from_bytes(0) - } - } -} - fn layout_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> Result<&'tcx LayoutDetails, LayoutError<'tcx>> @@ -1451,11 +727,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { // Only one variant is inhabited. (inh_second.is_none() && // Representation optimizations are allowed. - !def.repr.inhibit_enum_layout_opt() && - // Inhabited variant either has data ... - (!variants[inh_first.unwrap()].is_empty() || - // ... or there other, uninhabited, variants. - variants.len() > 1)); + !def.repr.inhibit_enum_layout_opt()); if is_struct { // Struct, or univariant enum equivalent to a struct. // (Typechecking will reject discriminant-sizing attrs.) @@ -1489,6 +761,9 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { return Ok(tcx.intern_layout(st)); } + // The current code for niche-filling relies on variant indices + // instead of actual discriminants, so dataful enums with + // explicit discriminants (RFC #2363) would misbehave. let no_explicit_discriminants = def.variants.iter().enumerate() .all(|(i, v)| v.discr == ty::VariantDiscr::Relative(i)); @@ -1525,9 +800,9 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { if let Some(i) = dataful_variant { let count = (niche_variants.end - niche_variants.start + 1) as u128; - for (field_index, field) in variants[i].iter().enumerate() { + for (field_index, &field) in variants[i].iter().enumerate() { let (offset, niche, niche_start) = - match field.find_niche(self, count)? { + match self.find_niche(field, count)? { Some(niche) => niche, None => continue }; @@ -1622,7 +897,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { } // Create the set of structs that represent each variant. - let mut variants = variants.into_iter().enumerate().map(|(i, field_layouts)| { + let mut layout_variants = variants.iter().enumerate().map(|(i, field_layouts)| { let mut st = univariant_uninterned(&field_layouts, &def.repr, StructKind::Prefixed(min_ity.size(), prefix_align))?; st.variants = Variants::Single { index: i }; @@ -1683,7 +958,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { // Patch up the variants' first few fields. let old_ity_size = min_ity.size(); let new_ity_size = ity.size(); - for variant in &mut variants { + for variant in &mut layout_variants { if variant.abi == Abi::Uninhabited { continue; } @@ -1705,19 +980,85 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { } } - let discr = Scalar { + let tag_mask = !0u128 >> (128 - ity.size().bits()); + let tag = Scalar { value: Int(ity, signed), - valid_range: (min as u128)..=(max as u128) - }; - let abi = if discr.value.size(dl) == size { - Abi::Scalar(discr.clone()) - } else { - Abi::Aggregate { sized: true } + valid_range: (min as u128 & tag_mask)..=(max as u128 & tag_mask), }; + let mut abi = Abi::Aggregate { sized: true }; + if tag.value.size(dl) == size { + abi = Abi::Scalar(tag.clone()); + } else if !tag.is_bool() { + // HACK(nox): Blindly using ScalarPair for all tagged enums + // where applicable leads to Option<u8> being handled as {i1, i8}, + // which later confuses SROA and some loop optimisations, + // ultimately leading to the repeat-trusted-len test + // failing. We make the trade-off of using ScalarPair only + // for types where the tag isn't a boolean. + let mut common_prim = None; + for (field_layouts, layout_variant) in variants.iter().zip(&layout_variants) { + let offsets = match layout_variant.fields { + FieldPlacement::Arbitrary { ref offsets, .. } => offsets, + _ => bug!(), + }; + let mut fields = field_layouts + .iter() + .zip(offsets) + .filter(|p| !p.0.is_zst()); + let (field, offset) = match (fields.next(), fields.next()) { + (None, None) => continue, + (Some(pair), None) => pair, + _ => { + common_prim = None; + break; + } + }; + let prim = match field.details.abi { + Abi::Scalar(ref scalar) => scalar.value, + _ => { + common_prim = None; + break; + } + }; + if let Some(pair) = common_prim { + // This is pretty conservative. We could go fancier + // by conflating things like i32 and u32, or even + // realising that (u8, u8) could just cohabit with + // u16 or even u32. + if pair != (prim, offset) { + common_prim = None; + break; + } + } else { + common_prim = Some((prim, offset)); + } + } + if let Some((prim, offset)) = common_prim { + let pair = scalar_pair(tag.clone(), scalar_unit(prim)); + let pair_offsets = match pair.fields { + FieldPlacement::Arbitrary { + ref offsets, + ref memory_index + } => { + assert_eq!(memory_index, &[0, 1]); + offsets + } + _ => bug!() + }; + if pair_offsets[0] == Size::from_bytes(0) && + pair_offsets[1] == *offset && + align == pair.align && + size == pair.size { + // We can use `ScalarPair` only when it matches our + // already computed layout (including `#[repr(C)]`). + abi = pair.abi; + } + } + } tcx.intern_layout(LayoutDetails { variants: Variants::Tagged { - discr, - variants + discr: tag, + variants: layout_variants, }, fields: FieldPlacement::Arbitrary { offsets: vec![Size::from_bytes(0)], @@ -2023,26 +1364,6 @@ impl<'a, 'tcx> SizeSkeleton<'tcx> { } } -/// The details of the layout of a type, alongside the type itself. -/// Provides various type traversal APIs (e.g. recursing into fields). -/// -/// Note that the details are NOT guaranteed to always be identical -/// to those obtained from `layout_of(ty)`, as we need to produce -/// layouts for which Rust types do not exist, such as enum variants -/// or synthetic fields of enums (i.e. discriminants) and fat pointers. -#[derive(Copy, Clone, Debug)] -pub struct TyLayout<'tcx> { - pub ty: Ty<'tcx>, - details: &'tcx LayoutDetails -} - -impl<'tcx> Deref for TyLayout<'tcx> { - type Target = &'tcx LayoutDetails; - fn deref(&self) -> &&'tcx LayoutDetails { - &self.details - } -} - pub trait HasTyCtxt<'tcx>: HasDataLayout { fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx>; } @@ -2094,13 +1415,10 @@ impl<T, E> MaybeResult<T> for Result<T, E> { } } -pub trait LayoutOf<T> { - type TyLayout; +pub type TyLayout<'tcx> = ::rustc_target::abi::TyLayout<'tcx, Ty<'tcx>>; - fn layout_of(self, ty: T) -> Self::TyLayout; -} - -impl<'a, 'tcx> LayoutOf<Ty<'tcx>> for LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { +impl<'a, 'tcx> LayoutOf for LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { + type Ty = Ty<'tcx>; type TyLayout = Result<TyLayout<'tcx>, LayoutError<'tcx>>; /// Computes the layout of a type. Note that this implicitly @@ -2126,7 +1444,8 @@ impl<'a, 'tcx> LayoutOf<Ty<'tcx>> for LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { } } -impl<'a, 'tcx> LayoutOf<Ty<'tcx>> for LayoutCx<'tcx, ty::maps::TyCtxtAt<'a, 'tcx, 'tcx>> { +impl<'a, 'tcx> LayoutOf for LayoutCx<'tcx, ty::maps::TyCtxtAt<'a, 'tcx, 'tcx>> { + type Ty = Ty<'tcx>; type TyLayout = Result<TyLayout<'tcx>, LayoutError<'tcx>>; /// Computes the layout of a type. Note that this implicitly @@ -2185,22 +1504,22 @@ impl<'a, 'tcx> ty::maps::TyCtxtAt<'a, 'tcx, 'tcx> { } } -impl<'a, 'tcx> TyLayout<'tcx> { - pub fn for_variant<C>(&self, cx: C, variant_index: usize) -> Self - where C: LayoutOf<Ty<'tcx>> + HasTyCtxt<'tcx>, - C::TyLayout: MaybeResult<TyLayout<'tcx>> - { - let details = match self.variants { - Variants::Single { index } if index == variant_index => self.details, +impl<'a, 'tcx, C> TyLayoutMethods<'tcx, C> for Ty<'tcx> + where C: LayoutOf<Ty = Ty<'tcx>> + HasTyCtxt<'tcx>, + C::TyLayout: MaybeResult<TyLayout<'tcx>> +{ + fn for_variant(this: TyLayout<'tcx>, cx: C, variant_index: usize) -> TyLayout<'tcx> { + let details = match this.variants { + Variants::Single { index } if index == variant_index => this.details, Variants::Single { index } => { // Deny calling for_variant more than once for non-Single enums. - cx.layout_of(self.ty).map_same(|layout| { + cx.layout_of(this.ty).map_same(|layout| { assert_eq!(layout.variants, Variants::Single { index }); layout }); - let fields = match self.ty.sty { + let fields = match this.ty.sty { ty::TyAdt(def, _) => def.variants[variant_index].fields.len(), _ => bug!() }; @@ -2218,17 +1537,14 @@ impl<'a, 'tcx> TyLayout<'tcx> { assert_eq!(details.variants, Variants::Single { index: variant_index }); TyLayout { - ty: self.ty, + ty: this.ty, details } } - pub fn field<C>(&self, cx: C, i: usize) -> C::TyLayout - where C: LayoutOf<Ty<'tcx>> + HasTyCtxt<'tcx>, - C::TyLayout: MaybeResult<TyLayout<'tcx>> - { + fn field(this: TyLayout<'tcx>, cx: C, i: usize) -> C::TyLayout { let tcx = cx.tcx(); - cx.layout_of(match self.ty.sty { + cx.layout_of(match this.ty.sty { ty::TyBool | ty::TyChar | ty::TyInt(_) | @@ -2240,7 +1556,7 @@ impl<'a, 'tcx> TyLayout<'tcx> { ty::TyGeneratorWitness(..) | ty::TyForeign(..) | ty::TyDynamic(..) => { - bug!("TyLayout::field_type({:?}): not applicable", self) + bug!("TyLayout::field_type({:?}): not applicable", this) } // Potentially-fat pointers. @@ -2254,13 +1570,13 @@ impl<'a, 'tcx> TyLayout<'tcx> { // as the `Abi` or `FieldPlacement` is checked by users. if i == 0 { let nil = tcx.mk_nil(); - let ptr_ty = if self.ty.is_unsafe_ptr() { + let ptr_ty = if this.ty.is_unsafe_ptr() { tcx.mk_mut_ptr(nil) } else { tcx.mk_mut_ref(tcx.types.re_static, nil) }; return cx.layout_of(ptr_ty).map_same(|mut ptr_layout| { - ptr_layout.ty = self.ty; + ptr_layout.ty = this.ty; ptr_layout }); } @@ -2273,7 +1589,7 @@ impl<'a, 'tcx> TyLayout<'tcx> { // the correct number of vtables slots. tcx.mk_imm_ref(tcx.types.re_static, tcx.mk_nil()) } - _ => bug!("TyLayout::field_type({:?}): not applicable", self) + _ => bug!("TyLayout::field_type({:?}): not applicable", this) } } @@ -2295,12 +1611,12 @@ impl<'a, 'tcx> TyLayout<'tcx> { // SIMD vector types. ty::TyAdt(def, ..) if def.repr.simd() => { - self.ty.simd_type(tcx) + this.ty.simd_type(tcx) } // ADTs. ty::TyAdt(def, substs) => { - match self.variants { + match this.variants { Variants::Single { index } => { def.variants[index].fields[i].ty(tcx, substs) } @@ -2320,45 +1636,25 @@ impl<'a, 'tcx> TyLayout<'tcx> { ty::TyProjection(_) | ty::TyAnon(..) | ty::TyParam(_) | ty::TyInfer(_) | ty::TyError => { - bug!("TyLayout::field_type: unexpected type `{}`", self.ty) + bug!("TyLayout::field_type: unexpected type `{}`", this.ty) } }) } +} - /// Returns true if the layout corresponds to an unsized type. - pub fn is_unsized(&self) -> bool { - self.abi.is_unsized() - } - - /// Returns true if the type is a ZST and not unsized. - pub fn is_zst(&self) -> bool { - match self.abi { - Abi::Uninhabited => true, - Abi::Scalar(_) | - Abi::ScalarPair(..) | - Abi::Vector { .. } => false, - Abi::Aggregate { sized } => sized && self.size.bytes() == 0 - } - } - - pub fn size_and_align(&self) -> (Size, Align) { - (self.size, self.align) - } - +impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { /// Find the offset of a niche leaf field, starting from /// the given type and recursing through aggregates, which /// has at least `count` consecutive invalid values. /// The tuple is `(offset, scalar, niche_value)`. // FIXME(eddyb) traverse already optimized enums. - fn find_niche<C>(&self, cx: C, count: u128) + fn find_niche(self, layout: TyLayout<'tcx>, count: u128) -> Result<Option<(Size, Scalar, u128)>, LayoutError<'tcx>> - where C: LayoutOf<Ty<'tcx>, TyLayout = Result<Self, LayoutError<'tcx>>> + - HasTyCtxt<'tcx> { let scalar_component = |scalar: &Scalar, offset| { let Scalar { value, valid_range: ref v } = *scalar; - let bits = value.size(cx).bits(); + let bits = value.size(self).bits(); assert!(bits <= 128); let max_value = !0u128 >> (128 - bits); @@ -2385,17 +1681,17 @@ impl<'a, 'tcx> TyLayout<'tcx> { // Locals variables which live across yields are stored // in the generator type as fields. These may be uninitialized // so we don't look for niches there. - if let ty::TyGenerator(..) = self.ty.sty { + if let ty::TyGenerator(..) = layout.ty.sty { return Ok(None); } - match self.abi { + match layout.abi { Abi::Scalar(ref scalar) => { return Ok(scalar_component(scalar, Size::from_bytes(0))); } Abi::ScalarPair(ref a, ref b) => { return Ok(scalar_component(a, Size::from_bytes(0)).or_else(|| { - scalar_component(b, a.value.size(cx).abi_align(b.value.align(cx))) + scalar_component(b, a.value.size(self).abi_align(b.value.align(self))) })); } Abi::Vector { ref element, .. } => { @@ -2405,22 +1701,22 @@ impl<'a, 'tcx> TyLayout<'tcx> { } // Perhaps one of the fields is non-zero, let's recurse and find out. - if let FieldPlacement::Union(_) = self.fields { + if let FieldPlacement::Union(_) = layout.fields { // Only Rust enums have safe-to-inspect fields // (a discriminant), other unions are unsafe. - if let Variants::Single { .. } = self.variants { + if let Variants::Single { .. } = layout.variants { return Ok(None); } } - if let FieldPlacement::Array { .. } = self.fields { - if self.fields.count() > 0 { - return self.field(cx, 0)?.find_niche(cx, count); + if let FieldPlacement::Array { .. } = layout.fields { + if layout.fields.count() > 0 { + return self.find_niche(layout.field(self, 0)?, count); } } - for i in 0..self.fields.count() { - let r = self.field(cx, i)?.find_niche(cx, count)?; + for i in 0..layout.fields.count() { + let r = self.find_niche(layout.field(self, i)?, count)?; if let Some((offset, scalar, niche_value)) = r { - let offset = self.fields.offset(i) + offset; + let offset = layout.fields.offset(i) + offset; return Ok(Some((offset, scalar, niche_value))); } } @@ -2548,14 +1844,22 @@ impl_stable_hash_for!(enum ::ty::layout::Primitive { Pointer }); -impl_stable_hash_for!(struct ::ty::layout::Align { - abi_pow2, - pref_pow2 -}); +impl<'gcx> HashStable<StableHashingContext<'gcx>> for Align { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'gcx>, + hasher: &mut StableHasher<W>) { + self.abi().hash_stable(hcx, hasher); + self.pref().hash_stable(hcx, hasher); + } +} -impl_stable_hash_for!(struct ::ty::layout::Size { - raw -}); +impl<'gcx> HashStable<StableHashingContext<'gcx>> for Size { + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'gcx>, + hasher: &mut StableHasher<W>) { + self.bytes().hash_stable(hcx, hasher); + } +} impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for LayoutError<'gcx> { diff --git a/src/librustc/ty/maps/config.rs b/src/librustc/ty/maps/config.rs index 664c84f5986..57c8c4f34e7 100644 --- a/src/librustc/ty/maps/config.rs +++ b/src/librustc/ty/maps/config.rs @@ -9,24 +9,45 @@ // except according to those terms. use dep_graph::SerializedDepNodeIndex; +use dep_graph::DepNode; use hir::def_id::{CrateNum, DefId, DefIndex}; use mir::interpret::{GlobalId}; -use traits::query::{CanonicalProjectionGoal, CanonicalTyGoal}; +use traits::query::{CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal}; use ty::{self, ParamEnvAnd, Ty, TyCtxt}; use ty::subst::Substs; use ty::maps::queries; +use ty::maps::Query; +use ty::maps::QueryMap; use std::hash::Hash; +use std::fmt::Debug; use syntax_pos::symbol::InternedString; +use rustc_data_structures::sync::Lock; +use rustc_data_structures::stable_hasher::HashStable; +use ich::StableHashingContext; /// Query configuration and description traits. -pub trait QueryConfig { - type Key: Eq + Hash + Clone; - type Value; +pub trait QueryConfig<'tcx> { + const NAME: &'static str; + + type Key: Eq + Hash + Clone + Debug; + type Value: Clone + for<'a> HashStable<StableHashingContext<'a>>; + + fn query(key: Self::Key) -> Query<'tcx>; + + // Don't use this method to access query results, instead use the methods on TyCtxt + fn query_map<'a>(tcx: TyCtxt<'a, 'tcx, '_>) -> &'a Lock<QueryMap<'tcx, Self>>; + + fn to_dep_node(tcx: TyCtxt<'_, 'tcx, '_>, key: &Self::Key) -> DepNode; + + // Don't use this method to compute query results, instead use the methods on TyCtxt + fn compute(tcx: TyCtxt<'_, 'tcx, '_>, key: Self::Key) -> Self::Value; + + fn handle_cycle_error(tcx: TyCtxt<'_, 'tcx, '_>) -> Self::Value; } -pub(super) trait QueryDescription<'tcx>: QueryConfig { +pub trait QueryDescription<'tcx>: QueryConfig<'tcx> { fn describe(tcx: TyCtxt, key: Self::Key) -> String; #[inline] @@ -41,7 +62,7 @@ pub(super) trait QueryDescription<'tcx>: QueryConfig { } } -impl<'tcx, M: QueryConfig<Key=DefId>> QueryDescription<'tcx> for M { +impl<'tcx, M: QueryConfig<'tcx, Key=DefId>> QueryDescription<'tcx> for M { default fn describe(tcx: TyCtxt, def_id: DefId) -> String { if !tcx.sess.verbose() { format!("processing `{}`", tcx.item_path_str(def_id)) @@ -73,6 +94,12 @@ impl<'tcx> QueryDescription<'tcx> for queries::normalize_ty_after_erasing_region } } +impl<'tcx> QueryDescription<'tcx> for queries::evaluate_obligation<'tcx> { + fn describe(_tcx: TyCtxt, goal: CanonicalPredicateGoal<'tcx>) -> String { + format!("evaluating trait selection obligation `{}`", goal.value.value) + } +} + impl<'tcx> QueryDescription<'tcx> for queries::is_copy_raw<'tcx> { fn describe(_tcx: TyCtxt, env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> String { format!("computing whether `{}` is `Copy`", env.value) @@ -283,12 +310,6 @@ impl<'tcx> QueryDescription<'tcx> for queries::trait_of_item<'tcx> { } } -impl<'tcx> QueryDescription<'tcx> for queries::item_body_nested_bodies<'tcx> { - fn describe(tcx: TyCtxt, def_id: DefId) -> String { - format!("nested item bodies of `{}`", tcx.item_path_str(def_id)) - } -} - impl<'tcx> QueryDescription<'tcx> for queries::const_is_rvalue_promotable_to_static<'tcx> { fn describe(tcx: TyCtxt, def_id: DefId) -> String { format!("const checking if rvalue is promotable to static `{}`", @@ -723,6 +744,12 @@ impl<'tcx> QueryDescription<'tcx> for queries::program_clauses_for<'tcx> { } } +impl<'tcx> QueryDescription<'tcx> for queries::program_clauses_for_env<'tcx> { + fn describe(_tcx: TyCtxt, _: ty::ParamEnv<'tcx>) -> String { + format!("generating chalk-style clauses for param env") + } +} + impl<'tcx> QueryDescription<'tcx> for queries::wasm_import_module_map<'tcx> { fn describe(_tcx: TyCtxt, _: CrateNum) -> String { format!("wasm import module map") diff --git a/src/librustc/ty/maps/job.rs b/src/librustc/ty/maps/job.rs index 374406158c1..3b6af018d6b 100644 --- a/src/librustc/ty/maps/job.rs +++ b/src/librustc/ty/maps/job.rs @@ -17,13 +17,10 @@ use ty::context::TyCtxt; use errors::Diagnostic; /// Indicates the state of a query for a given key in a query map -pub(super) enum QueryResult<'tcx, T> { +pub(super) enum QueryResult<'tcx> { /// An already executing query. The query job can be used to await for its completion Started(Lrc<QueryJob<'tcx>>), - /// The query is complete and produced `T` - Complete(T), - /// The query panicked. Queries trying to wait on this will raise a fatal error / silently panic Poisoned, } diff --git a/src/librustc/ty/maps/keys.rs b/src/librustc/ty/maps/keys.rs index b8167ec9186..da29f23589e 100644 --- a/src/librustc/ty/maps/keys.rs +++ b/src/librustc/ty/maps/keys.rs @@ -11,7 +11,7 @@ //! Defines the set of legal keys that can be used in queries. use hir::def_id::{CrateNum, DefId, LOCAL_CRATE, DefIndex}; -use traits::query::{CanonicalProjectionGoal, CanonicalTyGoal}; +use traits::query::{CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal}; use ty::{self, Ty, TyCtxt}; use ty::subst::Substs; use ty::fast_reject::SimplifiedType; @@ -154,6 +154,15 @@ impl<'tcx> Key for Ty<'tcx> { } } +impl<'tcx> Key for ty::ParamEnv<'tcx> { + fn map_crate(&self) -> CrateNum { + LOCAL_CRATE + } + fn default_span(&self, _: TyCtxt) -> Span { + DUMMY_SP + } +} + impl<'tcx, T: Key> Key for ty::ParamEnvAnd<'tcx, T> { fn map_crate(&self) -> CrateNum { self.value.map_crate() @@ -191,3 +200,13 @@ impl<'tcx> Key for CanonicalTyGoal<'tcx> { DUMMY_SP } } + +impl<'tcx> Key for CanonicalPredicateGoal<'tcx> { + fn map_crate(&self) -> CrateNum { + LOCAL_CRATE + } + + fn default_span(&self, _tcx: TyCtxt) -> Span { + DUMMY_SP + } +} diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs index 2325b1893d9..d89846a75ef 100644 --- a/src/librustc/ty/maps/mod.rs +++ b/src/librustc/ty/maps/mod.rs @@ -9,7 +9,6 @@ // except according to those terms. use dep_graph::{DepConstructor, DepNode}; -use errors::DiagnosticBuilder; use hir::def_id::{CrateNum, DefId, DefIndex}; use hir::def::{Def, Export}; use hir::{self, TraitCandidate, ItemLocalId, TransFnAttrs}; @@ -17,9 +16,8 @@ use hir::svh::Svh; use infer::canonical::{self, Canonical}; use lint; use middle::borrowck::BorrowCheckResult; -use middle::cstore::{ExternCrate, LinkagePreference, NativeLibrary, - ExternBodyNestedBodies, ForeignModule}; -use middle::cstore::{NativeLibraryKind, DepKind, CrateSource, ExternConstBody}; +use middle::cstore::{ExternCrate, LinkagePreference, NativeLibrary, ForeignModule}; +use middle::cstore::{NativeLibraryKind, DepKind, CrateSource}; use middle::privacy::AccessLevels; use middle::reachable::ReachableSet; use middle::region; @@ -33,20 +31,21 @@ use mir; use mir::interpret::{GlobalId}; use session::{CompileResult, CrateDisambiguator}; use session::config::OutputFilenames; -use traits::Vtable; -use traits::query::{CanonicalProjectionGoal, CanonicalTyGoal, NoSolution}; +use traits::{self, Vtable}; +use traits::query::{CanonicalPredicateGoal, CanonicalProjectionGoal, + CanonicalTyGoal, NoSolution}; use traits::query::dropck_outlives::{DtorckConstraint, DropckOutlivesResult}; use traits::query::normalize::NormalizationResult; use traits::specialization_graph; -use traits::Clause; -use ty::{self, CrateInherentImpls, ParamEnvAnd, Slice, Ty, TyCtxt}; +use traits::Clauses; +use ty::{self, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt}; use ty::steal::Steal; use ty::subst::Substs; use util::nodemap::{DefIdSet, DefIdMap, ItemLocalSet}; -use util::common::{profq_msg, ErrorReported, ProfileQueriesMsg}; +use util::common::{ErrorReported}; use rustc_data_structures::indexed_set::IdxSetBuf; -use rustc_back::PanicStrategy; +use rustc_target::spec::PanicStrategy; use rustc_data_structures::indexed_vec::IndexVec; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stable_hasher::StableVec; @@ -68,7 +67,6 @@ pub use self::plumbing::force_from_dep_node; mod job; pub use self::job::{QueryJob, QueryInfo}; -use self::job::QueryResult; mod keys; pub use self::keys::Key; @@ -213,7 +211,7 @@ define_maps! { <'tcx> /// 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) -> Option<mir::ClosureRegionRequirements<'tcx>>, + [] fn mir_borrowck: MirBorrowCheck(DefId) -> mir::BorrowCheckResult<'tcx>, /// Gets a complete map from all types to their inherent impls. /// Not meant to be used directly outside of coherence. @@ -254,9 +252,11 @@ define_maps! { <'tcx> [] fn item_attrs: ItemAttrs(DefId) -> Lrc<[ast::Attribute]>, [] fn trans_fn_attrs: trans_fn_attrs(DefId) -> TransFnAttrs, [] 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>, [] fn trait_of_item: TraitOfItem(DefId) -> Option<DefId>, - [] fn item_body_nested_bodies: ItemBodyNestedBodies(DefId) -> ExternBodyNestedBodies, [] fn const_is_rvalue_promotable_to_static: ConstIsRvaluePromotableToStatic(DefId) -> bool, [] fn rvalue_promotable_map: RvaluePromotableMap(DefId) -> Lrc<ItemLocalSet>, [] fn is_mir_available: IsMirAvailable(DefId) -> bool, @@ -376,7 +376,6 @@ define_maps! { <'tcx> [] 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 extern_const_body: ExternConstBody(DefId) -> ExternConstBody<'tcx>, [] fn visible_parent_map: visible_parent_map_node(CrateNum) -> Lrc<DefIdMap<DefId>>, [] fn missing_extern_crate_item: MissingExternCrateItem(CrateNum) -> bool, @@ -433,6 +432,12 @@ define_maps! { <'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 substitute_normalize_and_test_predicates: substitute_normalize_and_test_predicates_node((DefId, &'tcx Substs<'tcx>)) -> bool, @@ -445,7 +450,11 @@ define_maps! { <'tcx> [] fn features_query: features_node(CrateNum) -> Lrc<feature_gate::Features>, - [] fn program_clauses_for: ProgramClausesFor(DefId) -> Lrc<&'tcx Slice<Clause<'tcx>>>, + [] fn program_clauses_for: ProgramClausesFor(DefId) -> Clauses<'tcx>, + + [] fn program_clauses_for_env: ProgramClausesForEnv( + ty::ParamEnv<'tcx> + ) -> Clauses<'tcx>, [] fn wasm_custom_sections: WasmCustomSections(CrateNum) -> Lrc<Vec<DefId>>, [] fn wasm_import_module_map: WasmImportModuleMap(CrateNum) diff --git a/src/librustc/ty/maps/on_disk_cache.rs b/src/librustc/ty/maps/on_disk_cache.rs index f88e33c708e..cea2a03fd53 100644 --- a/src/librustc/ty/maps/on_disk_cache.rs +++ b/src/librustc/ty/maps/on_disk_cache.rs @@ -30,7 +30,6 @@ use syntax::codemap::{CodeMap, StableFilemapId}; use syntax_pos::{BytePos, Span, DUMMY_SP, FileMap}; use syntax_pos::hygiene::{Mark, SyntaxContext, ExpnInfo}; use ty; -use ty::maps::job::QueryResult; use ty::codec::{self as ty_codec, TyDecoder, TyEncoder}; use ty::context::TyCtxt; use util::common::time; @@ -239,14 +238,12 @@ impl<'sess> OnDiskCache<'sess> { encode_query_results::<specialization_graph_of, _>(tcx, enc, qri)?; // const eval is special, it only encodes successfully evaluated constants - use ty::maps::plumbing::GetCacheInternal; - for (key, entry) in const_eval::get_cache_internal(tcx).map.iter() { + use ty::maps::QueryConfig; + let map = const_eval::query_map(tcx).borrow(); + assert!(map.active.is_empty()); + for (key, entry) in map.results.iter() { use ty::maps::config::QueryDescription; if const_eval::cache_on_disk(key.clone()) { - let entry = match *entry { - QueryResult::Complete(ref v) => v, - _ => panic!("incomplete query"), - }; if let Ok(ref value) = entry.value { let dep_node = SerializedDepNodeIndex::new(entry.index.index()); @@ -1124,7 +1121,7 @@ fn encode_query_results<'enc, 'a, 'tcx, Q, E>(tcx: TyCtxt<'a, 'tcx, 'tcx>, encoder: &mut CacheEncoder<'enc, 'a, 'tcx, E>, query_result_index: &mut EncodedQueryResultIndex) -> Result<(), E::Error> - where Q: super::plumbing::GetCacheInternal<'tcx>, + where Q: super::config::QueryDescription<'tcx>, E: 'enc + TyEncoder, Q::Value: Encodable, { @@ -1133,12 +1130,10 @@ fn encode_query_results<'enc, 'a, 'tcx, Q, E>(tcx: TyCtxt<'a, 'tcx, 'tcx>, time(tcx.sess, desc, || { - for (key, entry) in Q::get_cache_internal(tcx).map.iter() { + let map = Q::query_map(tcx).borrow(); + assert!(map.active.is_empty()); + for (key, entry) in map.results.iter() { if Q::cache_on_disk(key.clone()) { - let entry = match *entry { - QueryResult::Complete(ref v) => v, - _ => panic!("incomplete query"), - }; let dep_node = SerializedDepNodeIndex::new(entry.index.index()); // Record position of the cache entry diff --git a/src/librustc/ty/maps/plumbing.rs b/src/librustc/ty/maps/plumbing.rs index 4f6925938c8..37950463f74 100644 --- a/src/librustc/ty/maps/plumbing.rs +++ b/src/librustc/ty/maps/plumbing.rs @@ -15,21 +15,29 @@ use dep_graph::{DepNodeIndex, DepNode, DepKind, DepNodeColor}; use errors::DiagnosticBuilder; use errors::Level; +use errors::Diagnostic; +use errors::FatalError; use ty::tls; use ty::{TyCtxt}; use ty::maps::Query; +use ty::maps::config::QueryConfig; use ty::maps::config::QueryDescription; -use ty::maps::job::{QueryResult, QueryInfo}; +use ty::maps::job::{QueryJob, QueryResult, QueryInfo}; use ty::item_path; +use util::common::{profq_msg, ProfileQueriesMsg, QueryMsg}; + use rustc_data_structures::fx::{FxHashMap}; -use rustc_data_structures::sync::LockGuard; -use std::marker::PhantomData; +use rustc_data_structures::sync::{Lrc, Lock}; +use std::mem; +use std::ptr; +use std::collections::hash_map::Entry; use syntax_pos::Span; +use syntax::codemap::DUMMY_SP; -pub(super) struct QueryMap<'tcx, D: QueryDescription<'tcx>> { - phantom: PhantomData<(D, &'tcx ())>, - pub(super) map: FxHashMap<D::Key, QueryResult<'tcx, QueryValue<D::Value>>>, +pub struct QueryMap<'tcx, D: QueryConfig<'tcx> + ?Sized> { + pub(super) results: FxHashMap<D::Key, QueryValue<D::Value>>, + pub(super) active: FxHashMap<D::Key, QueryResult<'tcx>>, } pub(super) struct QueryValue<T> { @@ -48,18 +56,166 @@ impl<T> QueryValue<T> { } } -impl<'tcx, M: QueryDescription<'tcx>> QueryMap<'tcx, M> { +impl<'tcx, M: QueryConfig<'tcx>> QueryMap<'tcx, M> { pub(super) fn new() -> QueryMap<'tcx, M> { QueryMap { - phantom: PhantomData, - map: FxHashMap(), + results: FxHashMap(), + active: FxHashMap(), + } + } +} + +// If enabled, send a message to the profile-queries thread +macro_rules! profq_msg { + ($tcx:expr, $msg:expr) => { + if cfg!(debug_assertions) { + if $tcx.sess.profile_queries() { + profq_msg($tcx.sess, $msg) + } + } + } +} + +// If enabled, format a key using its debug string, which can be +// expensive to compute (in terms of time). +macro_rules! profq_query_msg { + ($query:expr, $tcx:expr, $key:expr) => {{ + let msg = if cfg!(debug_assertions) { + if $tcx.sess.profile_queries_and_keys() { + Some(format!("{:?}", $key)) + } else { None } + } else { None }; + QueryMsg { + query: $query, + msg, + } + }} +} + +/// A type representing the responsibility to execute the job in the `job` field. +/// This will poison the relevant query if dropped. +pub(super) struct JobOwner<'a, 'tcx: 'a, Q: QueryDescription<'tcx> + 'a> { + map: &'a Lock<QueryMap<'tcx, Q>>, + key: Q::Key, + job: Lrc<QueryJob<'tcx>>, +} + +impl<'a, 'tcx, Q: QueryDescription<'tcx>> JobOwner<'a, 'tcx, Q> { + /// Either gets a JobOwner corresponding the the query, allowing us to + /// start executing the query, or it returns with the result of the query. + /// If the query is executing elsewhere, this will wait for it. + /// If the query panicked, this will silently panic. + pub(super) fn try_get( + tcx: TyCtxt<'a, 'tcx, '_>, + span: Span, + key: &Q::Key, + ) -> TryGetJob<'a, 'tcx, Q> { + let map = Q::query_map(tcx); + loop { + let mut lock = map.borrow_mut(); + if let Some(value) = lock.results.get(key) { + profq_msg!(tcx, ProfileQueriesMsg::CacheHit); + let result = Ok((value.value.clone(), value.index)); + return TryGetJob::JobCompleted(result); + } + let job = match lock.active.entry((*key).clone()) { + Entry::Occupied(entry) => { + match *entry.get() { + QueryResult::Started(ref job) => job.clone(), + QueryResult::Poisoned => FatalError.raise(), + } + } + Entry::Vacant(entry) => { + // No job entry for this query. Return a new one to be started later + return tls::with_related_context(tcx, |icx| { + let info = QueryInfo { + span, + query: Q::query(key.clone()), + }; + let job = Lrc::new(QueryJob::new(info, icx.query.clone())); + let owner = JobOwner { + map, + job: job.clone(), + key: (*key).clone(), + }; + entry.insert(QueryResult::Started(job)); + TryGetJob::NotYetStarted(owner) + }) + } + }; + mem::drop(lock); + + if let Err(cycle) = job.await(tcx, span) { + return TryGetJob::JobCompleted(Err(cycle)); + } + } + } + + /// Completes the query by updating the query map with the `result`, + /// signals the waiter and forgets the JobOwner, so it won't poison the query + pub(super) fn complete(self, result: &Q::Value, dep_node_index: DepNodeIndex) { + // We can move out of `self` here because we `mem::forget` it below + let key = unsafe { ptr::read(&self.key) }; + let job = unsafe { ptr::read(&self.job) }; + let map = self.map; + + // Forget ourself so our destructor won't poison the query + mem::forget(self); + + let value = QueryValue::new(result.clone(), dep_node_index); + { + let mut lock = map.borrow_mut(); + lock.active.remove(&key); + lock.results.insert(key, value); } + + job.signal_complete(); + } + + /// Executes a job by changing the ImplicitCtxt to point to the + /// new query job while it executes. It returns the diagnostics + /// captured during execution and the actual result. + pub(super) fn start<'lcx, F, R>( + &self, + tcx: TyCtxt<'_, 'tcx, 'lcx>, + compute: F) + -> (R, Vec<Diagnostic>) + where + F: for<'b> FnOnce(TyCtxt<'b, 'tcx, 'lcx>) -> R + { + // The TyCtxt stored in TLS has the same global interner lifetime + // as `tcx`, so we use `with_related_context` to relate the 'gcx lifetimes + // when accessing the ImplicitCtxt + let r = tls::with_related_context(tcx, move |current_icx| { + // Update the ImplicitCtxt to point to our new query job + let new_icx = tls::ImplicitCtxt { + tcx, + query: Some(self.job.clone()), + layout_depth: current_icx.layout_depth, + task: current_icx.task, + }; + + // Use the ImplicitCtxt while we execute the query + tls::enter_context(&new_icx, |_| { + compute(tcx) + }) + }); + + // Extract the diagnostic from the job + let diagnostics = mem::replace(&mut *self.job.diagnostics.lock(), Vec::new()); + + (r, diagnostics) } } -pub(super) trait GetCacheInternal<'tcx>: QueryDescription<'tcx> + Sized { - fn get_cache_internal<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> LockGuard<'a, QueryMap<'tcx, Self>>; +impl<'a, 'tcx, Q: QueryDescription<'tcx>> Drop for JobOwner<'a, 'tcx, Q> { + fn drop(&mut self) { + // Poison the query so jobs waiting on it panic + self.map.borrow_mut().active.insert(self.key.clone(), QueryResult::Poisoned); + // Also signal the completion of the job, so waiters + // will continue execution + self.job.signal_complete(); + } } #[derive(Clone)] @@ -70,14 +226,14 @@ pub(super) struct CycleError<'tcx> { } /// The result of `try_get_lock` -pub(super) enum TryGetLock<'a, 'tcx: 'a, T, D: QueryDescription<'tcx> + 'a> { +pub(super) enum TryGetJob<'a, 'tcx: 'a, D: QueryDescription<'tcx> + 'a> { /// The query is not yet started. Contains a guard to the map eventually used to start it. - NotYetStarted(LockGuard<'a, QueryMap<'tcx, D>>), + NotYetStarted(JobOwner<'a, 'tcx, D>), /// The query was already completed. /// Returns the result of the query and its dep node index /// if it succeeded or a cycle error if it failed - JobCompleted(Result<(T, DepNodeIndex), CycleError<'tcx>>), + JobCompleted(Result<(D::Value, DepNodeIndex), CycleError<'tcx>>), } impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { @@ -180,28 +336,277 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } } -} -// If enabled, send a message to the profile-queries thread -macro_rules! profq_msg { - ($tcx:expr, $msg:expr) => { - if cfg!(debug_assertions) { - if $tcx.sess.profile_queries() { - profq_msg($tcx.sess, $msg) + fn try_get_with<Q: QueryDescription<'gcx>>( + self, + span: Span, + key: Q::Key) + -> Result<Q::Value, CycleError<'gcx>> + { + debug!("ty::queries::{}::try_get_with(key={:?}, span={:?})", + Q::NAME, + key, + span); + + profq_msg!(self, + ProfileQueriesMsg::QueryBegin( + span.data(), + profq_query_msg!(Q::NAME, self, key), + ) + ); + + let job = match JobOwner::try_get(self, span, &key) { + TryGetJob::NotYetStarted(job) => job, + TryGetJob::JobCompleted(result) => { + return result.map(|(v, index)| { + self.dep_graph.read_index(index); + v + }) } + }; + + // Fast path for when incr. comp. is off. `to_dep_node` is + // expensive for some DepKinds. + if !self.dep_graph.is_fully_enabled() { + let null_dep_node = DepNode::new_no_params(::dep_graph::DepKind::Null); + return self.force_query_with_job::<Q>(key, job, null_dep_node).map(|(v, _)| v); + } + + let dep_node = Q::to_dep_node(self, &key); + + if dep_node.kind.is_anon() { + profq_msg!(self, ProfileQueriesMsg::ProviderBegin); + + let res = job.start(self, |tcx| { + tcx.dep_graph.with_anon_task(dep_node.kind, || { + Q::compute(tcx.global_tcx(), key) + }) + }); + + profq_msg!(self, ProfileQueriesMsg::ProviderEnd); + let ((result, dep_node_index), diagnostics) = res; + + self.dep_graph.read_index(dep_node_index); + + self.on_disk_query_result_cache + .store_diagnostics_for_anon_node(dep_node_index, diagnostics); + + job.complete(&result, dep_node_index); + + return Ok(result); + } + + if !dep_node.kind.is_input() { + if let Some(dep_node_index) = self.try_mark_green_and_read(&dep_node) { + profq_msg!(self, ProfileQueriesMsg::CacheHit); + return self.load_from_disk_and_cache_in_memory::<Q>(key, + job, + dep_node_index, + &dep_node) + } + } + + match self.force_query_with_job::<Q>(key, job, dep_node) { + Ok((result, dep_node_index)) => { + self.dep_graph.read_index(dep_node_index); + Ok(result) + } + Err(e) => Err(e) } } -} -// If enabled, format a key using its debug string, which can be -// expensive to compute (in terms of time). -macro_rules! profq_key { - ($tcx:expr, $key:expr) => { - if cfg!(debug_assertions) { - if $tcx.sess.profile_queries_and_keys() { - Some(format!("{:?}", $key)) - } else { None } - } else { None } + fn load_from_disk_and_cache_in_memory<Q: QueryDescription<'gcx>>( + self, + key: Q::Key, + job: JobOwner<'a, 'gcx, Q>, + dep_node_index: DepNodeIndex, + dep_node: &DepNode + ) -> Result<Q::Value, CycleError<'gcx>> + { + // Note this function can be called concurrently from the same query + // We must ensure that this is handled correctly + + debug_assert!(self.dep_graph.is_green(dep_node)); + + // First we try to load the result from the on-disk cache + let result = if Q::cache_on_disk(key.clone()) && + self.sess.opts.debugging_opts.incremental_queries { + let prev_dep_node_index = + self.dep_graph.prev_dep_node_index_of(dep_node); + let result = Q::try_load_from_disk(self.global_tcx(), + prev_dep_node_index); + + // We always expect to find a cached result for things that + // can be forced from DepNode. + debug_assert!(!dep_node.kind.can_reconstruct_query_key() || + result.is_some(), + "Missing on-disk cache entry for {:?}", + dep_node); + result + } else { + // Some things are never cached on disk. + None + }; + + let result = if let Some(result) = result { + result + } else { + // We could not load a result from the on-disk cache, so + // recompute. + + // The diagnostics for this query have already been + // promoted to the current session during + // try_mark_green(), so we can ignore them here. + let (result, _) = job.start(self, |tcx| { + // The dep-graph for this computation is already in + // place + tcx.dep_graph.with_ignore(|| { + Q::compute(tcx, key) + }) + }); + result + }; + + // If -Zincremental-verify-ich is specified, re-hash results from + // the cache and make sure that they have the expected fingerprint. + if self.sess.opts.debugging_opts.incremental_verify_ich { + use rustc_data_structures::stable_hasher::{StableHasher, HashStable}; + use ich::Fingerprint; + + assert!(Some(self.dep_graph.fingerprint_of(dep_node_index)) == + self.dep_graph.prev_fingerprint_of(dep_node), + "Fingerprint for green query instance not loaded \ + from cache: {:?}", dep_node); + + debug!("BEGIN verify_ich({:?})", dep_node); + let mut hcx = self.create_stable_hashing_context(); + let mut hasher = StableHasher::new(); + + result.hash_stable(&mut hcx, &mut hasher); + + let new_hash: Fingerprint = hasher.finish(); + debug!("END verify_ich({:?})", dep_node); + + let old_hash = self.dep_graph.fingerprint_of(dep_node_index); + + assert!(new_hash == old_hash, "Found unstable fingerprints \ + for {:?}", dep_node); + } + + if self.sess.opts.debugging_opts.query_dep_graph { + self.dep_graph.mark_loaded_from_cache(dep_node_index, true); + } + + job.complete(&result, dep_node_index); + + Ok(result) + } + + fn force_query_with_job<Q: QueryDescription<'gcx>>( + self, + key: Q::Key, + job: JobOwner<'_, 'gcx, Q>, + dep_node: DepNode) + -> Result<(Q::Value, DepNodeIndex), CycleError<'gcx>> { + // If the following assertion triggers, it can have two reasons: + // 1. Something is wrong with DepNode creation, either here or + // in DepGraph::try_mark_green() + // 2. Two distinct query keys get mapped to the same DepNode + // (see for example #48923) + assert!(!self.dep_graph.dep_node_exists(&dep_node), + "Forcing query with already existing DepNode.\n\ + - query-key: {:?}\n\ + - dep-node: {:?}", + key, dep_node); + + profq_msg!(self, ProfileQueriesMsg::ProviderBegin); + let res = job.start(self, |tcx| { + if dep_node.kind.is_eval_always() { + tcx.dep_graph.with_eval_always_task(dep_node, + tcx, + key, + Q::compute) + } else { + tcx.dep_graph.with_task(dep_node, + tcx, + key, + Q::compute) + } + }); + profq_msg!(self, ProfileQueriesMsg::ProviderEnd); + + let ((result, dep_node_index), diagnostics) = res; + + if self.sess.opts.debugging_opts.query_dep_graph { + self.dep_graph.mark_loaded_from_cache(dep_node_index, false); + } + + if dep_node.kind != ::dep_graph::DepKind::Null { + self.on_disk_query_result_cache + .store_diagnostics(dep_node_index, diagnostics); + } + + job.complete(&result, dep_node_index); + + Ok((result, dep_node_index)) + } + + /// Ensure that either this query has all green inputs or been executed. + /// Executing query::ensure(D) is considered a read of the dep-node D. + /// + /// This function is particularly useful when executing passes for their + /// side-effects -- e.g., in order to report errors for erroneous programs. + /// + /// Note: The optimization is only available during incr. comp. + pub fn ensure_query<Q: QueryDescription<'gcx>>(self, key: Q::Key) -> () { + let dep_node = Q::to_dep_node(self, &key); + + // Ensuring an "input" or anonymous query makes no sense + assert!(!dep_node.kind.is_anon()); + assert!(!dep_node.kind.is_input()); + if self.try_mark_green_and_read(&dep_node).is_none() { + // A None return from `try_mark_green_and_read` means that this is either + // a new dep node or that the dep node has already been marked red. + // Either way, we can't call `dep_graph.read()` as we don't have the + // DepNodeIndex. We must invoke the query itself. The performance cost + // this introduces should be negligible as we'll immediately hit the + // in-memory cache, or another query down the line will. + let _ = self.get_query::<Q>(DUMMY_SP, key); + } + } + + #[allow(dead_code)] + fn force_query<Q: QueryDescription<'gcx>>( + self, + key: Q::Key, + span: Span, + dep_node: DepNode + ) -> Result<(Q::Value, DepNodeIndex), CycleError<'gcx>> { + // We may be concurrently trying both execute and force a query + // Ensure that only one of them runs the query + let job = match JobOwner::try_get(self, span, &key) { + TryGetJob::NotYetStarted(job) => job, + TryGetJob::JobCompleted(result) => return result, + }; + self.force_query_with_job::<Q>(key, job, dep_node) + } + + pub fn try_get_query<Q: QueryDescription<'gcx>>( + self, + span: Span, + key: Q::Key + ) -> Result<Q::Value, DiagnosticBuilder<'a>> { + match self.try_get_with::<Q>(span, key) { + Ok(e) => Ok(e), + Err(e) => Err(self.report_cycle(e)), + } + } + + pub fn get_query<Q: QueryDescription<'gcx>>(self, span: Span, key: Q::Key) -> Q::Value { + self.try_get_query::<Q>(span, key).unwrap_or_else(|mut e| { + e.emit(); + Q::handle_cycle_error(self) + }) } } @@ -210,7 +615,7 @@ macro_rules! handle_cycle_error { Value::from_cycle_error($this.global_tcx()) }}; ([fatal_cycle$(, $modifiers:ident)*][$this:expr]) => {{ - $this.tcx.sess.abort_if_errors(); + $this.sess.abort_if_errors(); unreachable!(); }}; ([$other:ident$(, $modifiers:ident)*][$($args:tt)*]) => { @@ -223,12 +628,7 @@ macro_rules! define_maps { $($(#[$attr:meta])* [$($modifiers:tt)*] fn $name:ident: $node:ident($K:ty) -> $V:ty,)*) => { - use dep_graph::DepNodeIndex; - use std::mem; - use errors::Diagnostic; - use errors::FatalError; - use rustc_data_structures::sync::{Lock, LockGuard}; - use rustc_data_structures::OnDrop; + use rustc_data_structures::sync::Lock; define_map_struct! { tcx: $tcx, @@ -251,12 +651,6 @@ macro_rules! define_maps { $($(#[$attr])* $name($K)),* } - #[allow(bad_style)] - #[derive(Clone, Debug, PartialEq, Eq)] - pub enum QueryMsg { - $($name(Option<String>)),* - } - impl<$tcx> Query<$tcx> { pub fn name(&self) -> &'static str { match *self { @@ -303,162 +697,38 @@ macro_rules! define_maps { })* } - $(impl<$tcx> QueryConfig for queries::$name<$tcx> { + $(impl<$tcx> QueryConfig<$tcx> for queries::$name<$tcx> { type Key = $K; type Value = $V; - } - impl<$tcx> GetCacheInternal<$tcx> for queries::$name<$tcx> { - fn get_cache_internal<'a>(tcx: TyCtxt<'a, $tcx, $tcx>) - -> LockGuard<'a, QueryMap<$tcx, Self>> { - tcx.maps.$name.borrow() + const NAME: &'static str = stringify!($name); + + fn query(key: Self::Key) -> Query<'tcx> { + Query::$name(key) } - } - impl<'a, $tcx, 'lcx> queries::$name<$tcx> { + fn query_map<'a>(tcx: TyCtxt<'a, $tcx, '_>) -> &'a Lock<QueryMap<$tcx, Self>> { + &tcx.maps.$name + } #[allow(unused)] - fn to_dep_node(tcx: TyCtxt<'a, $tcx, 'lcx>, key: &$K) -> DepNode { + fn to_dep_node(tcx: TyCtxt<'_, $tcx, '_>, key: &Self::Key) -> DepNode { use dep_graph::DepConstructor::*; DepNode::new(tcx, $node(*key)) } - /// Either get the lock of the query map, allowing us to - /// start executing the query, or it returns with the result of the query. - /// If the query already executed and panicked, this will fatal error / silently panic - fn try_get_lock( - tcx: TyCtxt<'a, $tcx, 'lcx>, - span: Span, - key: &$K - ) -> TryGetLock<'a, $tcx, $V, Self> - { - loop { - let lock = tcx.maps.$name.borrow_mut(); - let job = if let Some(value) = lock.map.get(key) { - match *value { - QueryResult::Started(ref job) => Some(job.clone()), - QueryResult::Complete(ref value) => { - profq_msg!(tcx, ProfileQueriesMsg::CacheHit); - let result = Ok(((&value.value).clone(), value.index)); - return TryGetLock::JobCompleted(result); - }, - QueryResult::Poisoned => FatalError.raise(), - } - } else { - None - }; - let job = if let Some(job) = job { - job - } else { - return TryGetLock::NotYetStarted(lock); - }; - mem::drop(lock); - - if let Err(cycle) = job.await(tcx, span) { - return TryGetLock::JobCompleted(Err(cycle)); - } - } + fn compute(tcx: TyCtxt<'_, 'tcx, '_>, key: Self::Key) -> Self::Value { + let provider = tcx.maps.providers[key.map_crate()].$name; + provider(tcx.global_tcx(), key) } - fn try_get_with(tcx: TyCtxt<'a, $tcx, 'lcx>, - span: Span, - key: $K) - -> Result<$V, CycleError<$tcx>> - { - debug!("ty::queries::{}::try_get_with(key={:?}, span={:?})", - stringify!($name), - key, - span); - - profq_msg!(tcx, - ProfileQueriesMsg::QueryBegin( - span.data(), - QueryMsg::$name(profq_key!(tcx, key)) - ) - ); - - /// Get the lock used to start the query or - /// return the result of the completed query - macro_rules! get_lock_or_return { - () => {{ - match Self::try_get_lock(tcx, span, &key) { - TryGetLock::NotYetStarted(lock) => lock, - TryGetLock::JobCompleted(result) => { - return result.map(|(v, index)| { - tcx.dep_graph.read_index(index); - v - }) - } - } - }} - } - - let mut lock = get_lock_or_return!(); - - // Fast path for when incr. comp. is off. `to_dep_node` is - // expensive for some DepKinds. - if !tcx.dep_graph.is_fully_enabled() { - let null_dep_node = DepNode::new_no_params(::dep_graph::DepKind::Null); - return Self::force_with_lock(tcx, key, span, lock, null_dep_node) - .map(|(v, _)| v); - } - - let dep_node = Self::to_dep_node(tcx, &key); - - if dep_node.kind.is_anon() { - profq_msg!(tcx, ProfileQueriesMsg::ProviderBegin); - - let res = Self::start_job(tcx, span, key, lock, |tcx| { - tcx.dep_graph.with_anon_task(dep_node.kind, || { - Self::compute_result(tcx.global_tcx(), key) - }) - })?; - - profq_msg!(tcx, ProfileQueriesMsg::ProviderEnd); - let (((result, dep_node_index), diagnostics), job) = res; - - tcx.dep_graph.read_index(dep_node_index); - - tcx.on_disk_query_result_cache - .store_diagnostics_for_anon_node(dep_node_index, diagnostics); - - let value = QueryValue::new(Clone::clone(&result), dep_node_index); - - tcx.maps - .$name - .borrow_mut() - .map - .insert(key, QueryResult::Complete(value)); - - job.signal_complete(); - - return Ok(result); - } - - if !dep_node.kind.is_input() { - // try_mark_green_and_read may force queries. So we must drop our lock here - mem::drop(lock); - if let Some(dep_node_index) = tcx.try_mark_green_and_read(&dep_node) { - profq_msg!(tcx, ProfileQueriesMsg::CacheHit); - return Self::load_from_disk_and_cache_in_memory(tcx, - key, - span, - dep_node_index, - &dep_node) - } - lock = get_lock_or_return!(); - } - - match Self::force_with_lock(tcx, key, span, lock, dep_node) { - Ok((result, dep_node_index)) => { - tcx.dep_graph.read_index(dep_node_index); - Ok(result) - } - Err(e) => Err(e) - } + fn handle_cycle_error(tcx: TyCtxt<'_, 'tcx, '_>) -> Self::Value { + handle_cycle_error!([$($modifiers)*][tcx]) } + } + impl<'a, $tcx, 'lcx> queries::$name<$tcx> { /// Ensure that either this query has all green inputs or been executed. /// Executing query::ensure(D) is considered a read of the dep-node D. /// @@ -467,281 +737,7 @@ macro_rules! define_maps { /// /// Note: The optimization is only available during incr. comp. pub fn ensure(tcx: TyCtxt<'a, $tcx, 'lcx>, key: $K) -> () { - let dep_node = Self::to_dep_node(tcx, &key); - - // Ensuring an "input" or anonymous query makes no sense - assert!(!dep_node.kind.is_anon()); - assert!(!dep_node.kind.is_input()); - if tcx.try_mark_green_and_read(&dep_node).is_none() { - // A None return from `try_mark_green_and_read` means that this is either - // a new dep node or that the dep node has already been marked red. - // Either way, we can't call `dep_graph.read()` as we don't have the - // DepNodeIndex. We must invoke the query itself. The performance cost - // this introduces should be negligible as we'll immediately hit the - // in-memory cache, or another query down the line will. - let _ = tcx.$name(key); - } - } - - /// Creates a job for the query and updates the query map indicating that it started. - /// Then it changes ImplicitCtxt to point to the new query job while it executes. - /// If the query panics, this updates the query map to indicate so. - fn start_job<F, R>(tcx: TyCtxt<'_, $tcx, 'lcx>, - span: Span, - key: $K, - mut map: LockGuard<'_, QueryMap<$tcx, Self>>, - compute: F) - -> Result<((R, Vec<Diagnostic>), Lrc<QueryJob<$tcx>>), CycleError<$tcx>> - where F: for<'b> FnOnce(TyCtxt<'b, $tcx, 'lcx>) -> R - { - let query = Query::$name(Clone::clone(&key)); - - let entry = QueryInfo { - span, - query, - }; - - // The TyCtxt stored in TLS has the same global interner lifetime - // as `tcx`, so we use `with_related_context` to relate the 'gcx lifetimes - // when accessing the ImplicitCtxt - let (r, job) = ty::tls::with_related_context(tcx, move |icx| { - let job = Lrc::new(QueryJob::new(entry, icx.query.clone())); - - // Store the job in the query map and drop the lock to allow - // others to wait it - map.map.entry(key).or_insert(QueryResult::Started(job.clone())); - mem::drop(map); - - let r = { - let on_drop = OnDrop(|| { - // Poison the query so jobs waiting on it panic - tcx.maps - .$name - .borrow_mut() - .map - .insert(key, QueryResult::Poisoned); - // Also signal the completion of the job, so waiters - // will continue execution - job.signal_complete(); - }); - - // Update the ImplicitCtxt to point to our new query job - let icx = ty::tls::ImplicitCtxt { - tcx, - query: Some(job.clone()), - layout_depth: icx.layout_depth, - }; - - // Use the ImplicitCtxt while we execute the query - let r = ty::tls::enter_context(&icx, |icx| { - compute(icx.tcx) - }); - - mem::forget(on_drop); - - r - }; - - (r, job) - }); - - // Extract the diagnostic from the job - let diagnostics: Vec<_> = mem::replace(&mut *job.diagnostics.lock(), Vec::new()); - - Ok(((r, diagnostics), job)) - } - - fn compute_result(tcx: TyCtxt<'a, $tcx, 'lcx>, key: $K) -> $V { - let provider = tcx.maps.providers[key.map_crate()].$name; - provider(tcx.global_tcx(), key) - } - - fn load_from_disk_and_cache_in_memory(tcx: TyCtxt<'a, $tcx, 'lcx>, - key: $K, - span: Span, - dep_node_index: DepNodeIndex, - dep_node: &DepNode) - -> Result<$V, CycleError<$tcx>> - { - // Note this function can be called concurrently from the same query - // We must ensure that this is handled correctly - - debug_assert!(tcx.dep_graph.is_green(dep_node)); - - // First we try to load the result from the on-disk cache - let result = if Self::cache_on_disk(key) && - tcx.sess.opts.debugging_opts.incremental_queries { - let prev_dep_node_index = - tcx.dep_graph.prev_dep_node_index_of(dep_node); - let result = Self::try_load_from_disk(tcx.global_tcx(), - prev_dep_node_index); - - // We always expect to find a cached result for things that - // can be forced from DepNode. - debug_assert!(!dep_node.kind.can_reconstruct_query_key() || - result.is_some(), - "Missing on-disk cache entry for {:?}", - dep_node); - result - } else { - // Some things are never cached on disk. - None - }; - - let (result, job) = if let Some(result) = result { - (result, None) - } else { - // We could not load a result from the on-disk cache, so - // recompute. - - // The diagnostics for this query have already been - // promoted to the current session during - // try_mark_green(), so we can ignore them here. - let ((result, _), job) = Self::start_job(tcx, - span, - key, - tcx.maps.$name.borrow_mut(), - |tcx| { - // The dep-graph for this computation is already in - // place - tcx.dep_graph.with_ignore(|| { - Self::compute_result(tcx, key) - }) - })?; - (result, Some(job)) - }; - - // If -Zincremental-verify-ich is specified, re-hash results from - // the cache and make sure that they have the expected fingerprint. - if tcx.sess.opts.debugging_opts.incremental_verify_ich { - use rustc_data_structures::stable_hasher::{StableHasher, HashStable}; - use ich::Fingerprint; - - assert!(Some(tcx.dep_graph.fingerprint_of(dep_node_index)) == - tcx.dep_graph.prev_fingerprint_of(dep_node), - "Fingerprint for green query instance not loaded \ - from cache: {:?}", dep_node); - - debug!("BEGIN verify_ich({:?})", dep_node); - let mut hcx = tcx.create_stable_hashing_context(); - let mut hasher = StableHasher::new(); - - result.hash_stable(&mut hcx, &mut hasher); - - let new_hash: Fingerprint = hasher.finish(); - debug!("END verify_ich({:?})", dep_node); - - let old_hash = tcx.dep_graph.fingerprint_of(dep_node_index); - - assert!(new_hash == old_hash, "Found unstable fingerprints \ - for {:?}", dep_node); - } - - if tcx.sess.opts.debugging_opts.query_dep_graph { - tcx.dep_graph.mark_loaded_from_cache(dep_node_index, true); - } - - let value = QueryValue::new(Clone::clone(&result), dep_node_index); - - tcx.maps - .$name - .borrow_mut() - .map - .insert(key, QueryResult::Complete(value)); - - job.map(|j| j.signal_complete()); - - Ok(result) - } - - #[allow(dead_code)] - fn force(tcx: TyCtxt<'a, $tcx, 'lcx>, - key: $K, - span: Span, - dep_node: DepNode) - -> Result<($V, DepNodeIndex), CycleError<$tcx>> { - // We may be concurrently trying both execute and force a query - // Ensure that only one of them runs the query - let lock = match Self::try_get_lock(tcx, span, &key) { - TryGetLock::NotYetStarted(lock) => lock, - TryGetLock::JobCompleted(result) => return result, - }; - Self::force_with_lock(tcx, - key, - span, - lock, - dep_node) - } - - fn force_with_lock(tcx: TyCtxt<'a, $tcx, 'lcx>, - key: $K, - span: Span, - map: LockGuard<'_, QueryMap<$tcx, Self>>, - dep_node: DepNode) - -> Result<($V, DepNodeIndex), CycleError<$tcx>> { - // If the following assertion triggers, it can have two reasons: - // 1. Something is wrong with DepNode creation, either here or - // in DepGraph::try_mark_green() - // 2. Two distinct query keys get mapped to the same DepNode - // (see for example #48923) - assert!(!tcx.dep_graph.dep_node_exists(&dep_node), - "Forcing query with already existing DepNode.\n\ - - query-key: {:?}\n\ - - dep-node: {:?}", - key, dep_node); - - profq_msg!(tcx, ProfileQueriesMsg::ProviderBegin); - let res = Self::start_job(tcx, - span, - key, - map, - |tcx| { - if dep_node.kind.is_eval_always() { - tcx.dep_graph.with_eval_always_task(dep_node, - tcx, - key, - Self::compute_result) - } else { - tcx.dep_graph.with_task(dep_node, - tcx, - key, - Self::compute_result) - } - })?; - profq_msg!(tcx, ProfileQueriesMsg::ProviderEnd); - - let (((result, dep_node_index), diagnostics), job) = res; - - if tcx.sess.opts.debugging_opts.query_dep_graph { - tcx.dep_graph.mark_loaded_from_cache(dep_node_index, false); - } - - if dep_node.kind != ::dep_graph::DepKind::Null { - tcx.on_disk_query_result_cache - .store_diagnostics(dep_node_index, diagnostics); - } - - let value = QueryValue::new(Clone::clone(&result), dep_node_index); - - tcx.maps - .$name - .borrow_mut() - .map - .insert(key, QueryResult::Complete(value)); - - let job: Lrc<QueryJob> = job; - - job.signal_complete(); - - Ok((result, dep_node_index)) - } - - pub fn try_get(tcx: TyCtxt<'a, $tcx, 'lcx>, span: Span, key: $K) - -> Result<$V, DiagnosticBuilder<'a>> { - match Self::try_get_with(tcx, span, key) { - Ok(e) => Ok(e), - Err(e) => Err(tcx.report_cycle(e)), - } + tcx.ensure_query::<queries::$name>(key); } })* @@ -777,10 +773,7 @@ macro_rules! define_maps { impl<'a, $tcx, 'lcx> TyCtxtAt<'a, $tcx, 'lcx> { $($(#[$attr])* pub fn $name(self, key: $K) -> $V { - queries::$name::try_get(self.tcx, self.span, key).unwrap_or_else(|mut e| { - e.emit(); - handle_cycle_error!([$($modifiers)*][self]) - }) + self.tcx.get_query::<queries::$name>(self.span, key) })* } @@ -871,7 +864,6 @@ macro_rules! define_provider_struct { pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, dep_node: &DepNode) -> bool { - use ty::maps::keys::Key; use hir::def_id::LOCAL_CRATE; // We must avoid ever having to call force_from_dep_node() for a @@ -914,23 +906,14 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, { use $crate::util::common::{ProfileQueriesMsg, profq_msg}; - // FIXME(eddyb) Get more valid Span's on queries. - // def_span guard is necessary to prevent a recursive loop, - // default_span calls def_span query internally. - let span = if stringify!($query) != "def_span" { - $key.default_span(tcx) - } else { - ::syntax_pos::DUMMY_SP - }; - profq_msg!(tcx, ProfileQueriesMsg::QueryBegin( - span.data(), - ::ty::maps::QueryMsg::$query(profq_key!(tcx, $key)) + DUMMY_SP.data(), + profq_query_msg!(::ty::maps::queries::$query::NAME, tcx, $key), ) ); - match ::ty::maps::queries::$query::force(tcx, $key, span, *dep_node) { + match tcx.force_query::<::ty::maps::queries::$query>($key, DUMMY_SP, *dep_node) { Ok(_) => {}, Err(e) => { tcx.report_cycle(e).emit(); @@ -976,8 +959,10 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, DepKind::NormalizeProjectionTy | DepKind::NormalizeTyAfterErasingRegions | DepKind::DropckOutlives | + DepKind::EvaluateObligation | DepKind::SubstituteNormalizeAndTestPredicates | DepKind::InstanceDefSizeEstimate | + DepKind::ProgramClausesForEnv | // This one should never occur in this context DepKind::Null => { @@ -1048,7 +1033,6 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, DepKind::LookupDeprecationEntry => { force!(lookup_deprecation_entry, def_id!()); } - DepKind::ItemBodyNestedBodies => { force!(item_body_nested_bodies, def_id!()); } DepKind::ConstIsRvaluePromotableToStatic => { force!(const_is_rvalue_promotable_to_static, def_id!()); } @@ -1063,6 +1047,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, DepKind::ItemAttrs => { force!(item_attrs, def_id!()); } DepKind::TransFnAttrs => { force!(trans_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::IsPanicRuntime => { force!(is_panic_runtime, krate!()); } DepKind::IsCompilerBuiltins => { force!(is_compiler_builtins, krate!()); } @@ -1119,7 +1104,6 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, DepKind::GetLangItems => { force!(get_lang_items, LOCAL_CRATE); } DepKind::DefinedLangItems => { force!(defined_lang_items, krate!()); } DepKind::MissingLangItems => { force!(missing_lang_items, krate!()); } - DepKind::ExternConstBody => { force!(extern_const_body, def_id!()); } DepKind::VisibleParentMap => { force!(visible_parent_map, LOCAL_CRATE); } DepKind::MissingExternCrateItem => { force!(missing_extern_crate_item, krate!()); diff --git a/src/librustc/ty/maps/values.rs b/src/librustc/ty/maps/values.rs index 8d38d7dbbbb..d3d06248792 100644 --- a/src/librustc/ty/maps/values.rs +++ b/src/librustc/ty/maps/values.rs @@ -37,7 +37,7 @@ impl<'tcx> Value<'tcx> for Ty<'tcx> { impl<'tcx> Value<'tcx> for ty::SymbolName { fn from_cycle_error<'a>(_: TyCtxt<'a, 'tcx, 'tcx>) -> Self { - ty::SymbolName { name: Symbol::intern("<error>").as_str() } + ty::SymbolName { name: Symbol::intern("<error>").as_interned_str() } } } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index c3d2d5675de..5a121d3edbe 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -51,7 +51,7 @@ use std::mem; use syntax::ast::{self, DUMMY_NODE_ID, Name, Ident, NodeId}; use syntax::attr; use syntax::ext::hygiene::Mark; -use syntax::symbol::{Symbol, InternedString}; +use syntax::symbol::{Symbol, LocalInternedString, InternedString}; use syntax_pos::{DUMMY_SP, Span}; use rustc_data_structures::accumulate_vec::IntoIter as AccIntoIter; @@ -1048,18 +1048,18 @@ impl<'a, 'gcx, 'tcx> Predicate<'tcx> { // from the substitution and the value being substituted into, and // this trick achieves that). - let substs = &trait_ref.0.substs; + let substs = &trait_ref.skip_binder().substs; match *self { - Predicate::Trait(ty::Binder(ref data)) => - Predicate::Trait(ty::Binder(data.subst(tcx, substs))), - Predicate::Subtype(ty::Binder(ref data)) => - Predicate::Subtype(ty::Binder(data.subst(tcx, substs))), - Predicate::RegionOutlives(ty::Binder(ref data)) => - Predicate::RegionOutlives(ty::Binder(data.subst(tcx, substs))), - Predicate::TypeOutlives(ty::Binder(ref data)) => - Predicate::TypeOutlives(ty::Binder(data.subst(tcx, substs))), - Predicate::Projection(ty::Binder(ref data)) => - Predicate::Projection(ty::Binder(data.subst(tcx, substs))), + Predicate::Trait(ref binder) => + Predicate::Trait(binder.map_bound(|data| data.subst(tcx, substs))), + Predicate::Subtype(ref binder) => + Predicate::Subtype(binder.map_bound(|data| data.subst(tcx, substs))), + Predicate::RegionOutlives(ref binder) => + Predicate::RegionOutlives(binder.map_bound(|data| data.subst(tcx, substs))), + Predicate::TypeOutlives(ref binder) => + Predicate::TypeOutlives(binder.map_bound(|data| data.subst(tcx, substs))), + Predicate::Projection(ref binder) => + Predicate::Projection(binder.map_bound(|data| data.subst(tcx, substs))), Predicate::WellFormed(data) => Predicate::WellFormed(data.subst(tcx, substs)), Predicate::ObjectSafe(trait_def_id) => @@ -1095,7 +1095,7 @@ impl<'tcx> TraitPredicate<'tcx> { impl<'tcx> PolyTraitPredicate<'tcx> { pub fn def_id(&self) -> DefId { // ok to skip binder since trait def-id does not care about regions - self.0.def_id() + self.skip_binder().def_id() } } @@ -1138,17 +1138,31 @@ pub struct ProjectionPredicate<'tcx> { pub type PolyProjectionPredicate<'tcx> = Binder<ProjectionPredicate<'tcx>>; impl<'tcx> PolyProjectionPredicate<'tcx> { + /// Returns the def-id of the associated item being projected. + pub fn item_def_id(&self) -> DefId { + self.skip_binder().projection_ty.item_def_id + } + pub fn to_poly_trait_ref(&self, tcx: TyCtxt) -> PolyTraitRef<'tcx> { // Note: unlike with TraitRef::to_poly_trait_ref(), // self.0.trait_ref is permitted to have escaping regions. // This is because here `self` has a `Binder` and so does our // return value, so we are preserving the number of binding // levels. - ty::Binder(self.0.projection_ty.trait_ref(tcx)) + self.map_bound(|predicate| predicate.projection_ty.trait_ref(tcx)) } pub fn ty(&self) -> Binder<Ty<'tcx>> { - Binder(self.skip_binder().ty) // preserves binding levels + self.map_bound(|predicate| predicate.ty) + } + + /// The DefId of the TraitItem for the associated type. + /// + /// Note that this is not the DefId of the TraitRef containing this + /// associated type, which is in tcx.associated_item(projection_def_id()).container. + pub fn projection_def_id(&self) -> DefId { + // ok to skip binder since trait def-id does not care about regions + self.skip_binder().projection_ty.item_def_id } } @@ -1158,8 +1172,7 @@ pub trait ToPolyTraitRef<'tcx> { impl<'tcx> ToPolyTraitRef<'tcx> for TraitRef<'tcx> { fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx> { - assert!(!self.has_escaping_regions()); - ty::Binder(self.clone()) + ty::Binder::dummy(self.clone()) } } @@ -1175,12 +1188,7 @@ pub trait ToPredicate<'tcx> { impl<'tcx> ToPredicate<'tcx> for TraitRef<'tcx> { fn to_predicate(&self) -> Predicate<'tcx> { - // we're about to add a binder, so let's check that we don't - // accidentally capture anything, or else that might be some - // weird debruijn accounting. - assert!(!self.has_escaping_regions()); - - ty::Predicate::Trait(ty::Binder(ty::TraitPredicate { + ty::Predicate::Trait(ty::Binder::dummy(ty::TraitPredicate { trait_ref: self.clone() })) } @@ -1219,17 +1227,19 @@ impl<'tcx> Predicate<'tcx> { ty::Predicate::Trait(ref data) => { data.skip_binder().input_types().collect() } - ty::Predicate::Subtype(ty::Binder(SubtypePredicate { a, b, a_is_expected: _ })) => { + ty::Predicate::Subtype(binder) => { + let SubtypePredicate { a, b, a_is_expected: _ } = binder.skip_binder(); vec![a, b] } - ty::Predicate::TypeOutlives(ty::Binder(ref data)) => { - vec![data.0] + ty::Predicate::TypeOutlives(binder) => { + vec![binder.skip_binder().0] } ty::Predicate::RegionOutlives(..) => { vec![] } ty::Predicate::Projection(ref data) => { - data.0.projection_ty.substs.types().chain(Some(data.0.ty)).collect() + let inner = data.skip_binder(); + inner.projection_ty.substs.types().chain(Some(inner.ty)).collect() } ty::Predicate::WellFormed(data) => { vec![data] @@ -1972,32 +1982,38 @@ impl<'a, 'gcx, 'tcx> AdtDef { tcx: TyCtxt<'a, 'gcx, 'tcx>, variant_index: usize) -> Discr<'tcx> { - let repr_type = self.repr.discr_type(); - let mut explicit_value = repr_type.initial_discriminant(tcx.global_tcx()); + let (val, offset) = self.discriminant_def_for_variant(variant_index); + let explicit_value = val + .and_then(|expr_did| self.eval_explicit_discr(tcx, expr_did)) + .unwrap_or_else(|| self.repr.discr_type().initial_discriminant(tcx.global_tcx())); + explicit_value.checked_add(tcx, offset as u128).0 + } + + /// Yields a DefId for the discriminant and an offset to add to it + /// Alternatively, if there is no explicit discriminant, returns the + /// inferred discriminant directly + pub fn discriminant_def_for_variant( + &self, + variant_index: usize, + ) -> (Option<DefId>, usize) { let mut explicit_index = variant_index; + let expr_did; loop { match self.variants[explicit_index].discr { - ty::VariantDiscr::Relative(0) => break, + ty::VariantDiscr::Relative(0) => { + expr_did = None; + break; + }, ty::VariantDiscr::Relative(distance) => { explicit_index -= distance; } - ty::VariantDiscr::Explicit(expr_did) => { - match self.eval_explicit_discr(tcx, expr_did) { - Some(discr) => { - explicit_value = discr; - break; - }, - None => { - if explicit_index == 0 { - break; - } - explicit_index -= 1; - } - } + ty::VariantDiscr::Explicit(did) => { + expr_did = Some(did); + break; } } } - explicit_value.checked_add(tcx, (variant_index - explicit_index) as u128).0 + (expr_did, variant_index - explicit_index) } pub fn destructor(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<Destructor> { @@ -2015,7 +2031,7 @@ impl<'a, 'gcx, 'tcx> AdtDef { /// Due to normalization being eager, this applies even if /// the associated type is behind a pointer, e.g. issue #31299. pub fn sized_constraint(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> &'tcx [Ty<'tcx>] { - match queries::adt_sized_constraint::try_get(tcx, DUMMY_SP, self.did) { + match tcx.try_get_query::<queries::adt_sized_constraint>(DUMMY_SP, self.did) { Ok(tys) => tys, Err(mut bug) => { debug!("adt_sized_constraint: {:?} is recursive", self); @@ -2085,7 +2101,7 @@ impl<'a, 'gcx, 'tcx> AdtDef { Some(x) => x, _ => return vec![ty] }; - let sized_predicate = Binder(TraitRef { + let sized_predicate = Binder::dummy(TraitRef { def_id: sized_trait, substs: tcx.mk_substs_trait(ty, &[]) }).to_predicate(); @@ -2447,7 +2463,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn item_name(self, id: DefId) -> InternedString { if id.index == CRATE_DEF_INDEX { - self.original_crate_name(id.krate).as_str() + self.original_crate_name(id.krate).as_interned_str() } else { let def_key = self.def_key(id); // The name of a StructCtor is that of its struct parent. @@ -2804,15 +2820,13 @@ impl_stable_hash_for!(struct self::SymbolName { impl SymbolName { pub fn new(name: &str) -> SymbolName { SymbolName { - name: Symbol::intern(name).as_str() + name: Symbol::intern(name).as_interned_str() } } -} - -impl Deref for SymbolName { - type Target = str; - fn deref(&self) -> &str { &self.name } + pub fn as_str(&self) -> LocalInternedString { + self.name.as_str() + } } impl fmt::Display for SymbolName { diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 36eb3e3f94c..03ed6e7ac90 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -22,7 +22,7 @@ use mir::interpret::{GlobalId, Value, PrimVal}; use util::common::ErrorReported; use std::rc::Rc; use std::iter; -use syntax::abi; +use rustc_target::spec::abi; use hir as ast; use rustc_data_structures::accumulate_vec::AccumulateVec; @@ -431,10 +431,10 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, { // Wrap our types with a temporary GeneratorWitness struct // inside the binder so we can related them - let a_types = ty::Binder(GeneratorWitness(*a_types.skip_binder())); - let b_types = ty::Binder(GeneratorWitness(*b_types.skip_binder())); + let a_types = a_types.map_bound(GeneratorWitness); + let b_types = b_types.map_bound(GeneratorWitness); // Then remove the GeneratorWitness for the result - let types = ty::Binder(relation.relate(&a_types, &b_types)?.skip_binder().0); + let types = relation.relate(&a_types, &b_types)?.map_bound(|witness| witness.0); Ok(tcx.mk_generator_witness(types)) } diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 7b4b7082bb6..9b20fce6673 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -44,7 +44,7 @@ CloneTypeFoldableAndLiftImpls! { ::hir::MatchSource, ::hir::Mutability, ::hir::Unsafety, - ::syntax::abi::Abi, + ::rustc_target::spec::abi::Abi, ::mir::Local, ::mir::Promoted, ::traits::Reveal, @@ -270,7 +270,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::Predicate<'a> { impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for ty::Binder<T> { type Lifted = ty::Binder<T::Lifted>; fn lift_to_tcx<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<Self::Lifted> { - tcx.lift(&self.0).map(|x| ty::Binder(x)) + tcx.lift(self.skip_binder()).map(ty::Binder::bind) } } @@ -720,7 +720,7 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Vec<T> { impl<'tcx, T:TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder<T> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - ty::Binder(self.0.fold_with(folder)) + self.map_bound_ref(|ty| ty.fold_with(folder)) } fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { @@ -728,7 +728,7 @@ impl<'tcx, T:TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder<T> { } fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { - self.0.visit_with(visitor) + self.skip_binder().visit_with(visitor) } fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool { diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 310fcbcfcb3..e9c1e87676b 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -22,7 +22,7 @@ use util::captures::Captures; use std::iter; use std::cmp::Ordering; -use syntax::abi; +use rustc_target::spec::abi; use syntax::ast::{self, Name}; use syntax::symbol::{keywords, InternedString}; @@ -345,7 +345,7 @@ impl<'tcx> ClosureSubsts<'tcx> { /// binder, but it never contains bound regions. Probably this /// function should be removed. pub fn generator_poly_sig(self, def_id: DefId, tcx: TyCtxt<'_, '_, '_>) -> PolyGenSig<'tcx> { - ty::Binder(self.generator_sig(def_id, tcx)) + ty::Binder::dummy(self.generator_sig(def_id, tcx)) } /// Return the "generator signature", which consists of its yield @@ -504,13 +504,13 @@ impl<'tcx> Slice<ExistentialPredicate<'tcx>> { impl<'tcx> Binder<&'tcx Slice<ExistentialPredicate<'tcx>>> { pub fn principal(&self) -> Option<PolyExistentialTraitRef<'tcx>> { - self.skip_binder().principal().map(Binder) + self.skip_binder().principal().map(Binder::bind) } #[inline] pub fn projection_bounds<'a>(&'a self) -> impl Iterator<Item=PolyExistentialProjection<'tcx>> + 'a { - self.skip_binder().projection_bounds().map(Binder) + self.skip_binder().projection_bounds().map(Binder::bind) } #[inline] @@ -520,7 +520,7 @@ impl<'tcx> Binder<&'tcx Slice<ExistentialPredicate<'tcx>>> { pub fn iter<'a>(&'a self) -> impl DoubleEndedIterator<Item=Binder<ExistentialPredicate<'tcx>>> + 'tcx { - self.skip_binder().iter().cloned().map(Binder) + self.skip_binder().iter().cloned().map(Binder::bind) } } @@ -567,26 +567,16 @@ pub type PolyTraitRef<'tcx> = Binder<TraitRef<'tcx>>; impl<'tcx> PolyTraitRef<'tcx> { pub fn self_ty(&self) -> Ty<'tcx> { - self.0.self_ty() + self.skip_binder().self_ty() } pub fn def_id(&self) -> DefId { - self.0.def_id - } - - pub fn substs(&self) -> &'tcx Substs<'tcx> { - // FIXME(#20664) every use of this fn is probably a bug, it should yield Binder<> - self.0.substs - } - - pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator<Item=Ty<'tcx>> + 'a { - // FIXME(#20664) every use of this fn is probably a bug, it should yield Binder<> - self.0.input_types() + self.skip_binder().def_id } pub fn to_poly_trait_predicate(&self) -> ty::PolyTraitPredicate<'tcx> { // Note that we preserve binding levels - Binder(ty::TraitPredicate { trait_ref: self.0.clone() }) + Binder(ty::TraitPredicate { trait_ref: self.skip_binder().clone() }) } } @@ -633,12 +623,7 @@ pub type PolyExistentialTraitRef<'tcx> = Binder<ExistentialTraitRef<'tcx>>; impl<'tcx> PolyExistentialTraitRef<'tcx> { pub fn def_id(&self) -> DefId { - self.0.def_id - } - - pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator<Item=Ty<'tcx>> + 'a { - // FIXME(#20664) every use of this fn is probably a bug, it should yield Binder<> - self.0.input_types() + self.skip_binder().def_id } } @@ -650,7 +635,7 @@ impl<'tcx> PolyExistentialTraitRef<'tcx> { /// type from `Binder<T>` to just `T` (see /// e.g. `liberate_late_bound_regions`). #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] -pub struct Binder<T>(pub T); +pub struct Binder<T>(T); impl<T> Binder<T> { /// Wraps `value` in a binder, asserting that `value` does not @@ -664,6 +649,12 @@ impl<T> Binder<T> { Binder(value) } + /// Wraps `value` in a binder, binding late-bound regions (if any). + pub fn bind<'tcx>(value: T) -> Binder<T> + { + Binder(value) + } + /// Skips the binder and returns the "bound" value. This is a /// risky thing to do because it's easy to get confused about /// debruijn indices and the like. It is usually better to @@ -685,7 +676,7 @@ impl<T> Binder<T> { } pub fn as_ref(&self) -> Binder<&T> { - ty::Binder(&self.0) + Binder(&self.0) } pub fn map_bound_ref<F, U>(&self, f: F) -> Binder<U> @@ -697,7 +688,7 @@ impl<T> Binder<T> { pub fn map_bound<F, U>(self, f: F) -> Binder<U> where F: FnOnce(T) -> U { - ty::Binder(f(self.0)) + Binder(f(self.0)) } /// Unwraps and returns the value within, but only if it contains @@ -730,7 +721,7 @@ impl<T> Binder<T> { pub fn fuse<U,F,R>(self, u: Binder<U>, f: F) -> Binder<R> where F: FnOnce(T, U) -> R { - ty::Binder(f(self.0, u.0)) + Binder(f(self.0, u.0)) } /// Split the contents into two things that share the same binder @@ -743,7 +734,7 @@ impl<T> Binder<T> { where F: FnOnce(T) -> (U, V) { let (u, v) = f(self.0); - (ty::Binder(u), ty::Binder(v)) + (Binder(u), Binder(v)) } } @@ -839,7 +830,7 @@ pub type PolyFnSig<'tcx> = Binder<FnSig<'tcx>>; impl<'tcx> PolyFnSig<'tcx> { pub fn inputs(&self) -> Binder<&'tcx [Ty<'tcx>]> { - Binder(self.skip_binder().inputs()) + self.map_bound_ref(|fn_sig| fn_sig.inputs()) } pub fn input(&self, index: usize) -> ty::Binder<Ty<'tcx>> { self.map_bound_ref(|fn_sig| fn_sig.inputs()[index]) @@ -873,7 +864,7 @@ impl<'a, 'gcx, 'tcx> ParamTy { } pub fn for_self() -> ParamTy { - ParamTy::new(0, keywords::SelfType.name().as_str()) + ParamTy::new(0, keywords::SelfType.name().as_interned_str()) } pub fn for_def(def: &ty::TypeParameterDef) -> ParamTy { @@ -885,8 +876,10 @@ impl<'a, 'gcx, 'tcx> ParamTy { } pub fn is_self(&self) -> bool { - if self.name == keywords::SelfType.name().as_str() { - assert_eq!(self.idx, 0); + // FIXME(#50125): Ignoring `Self` with `idx != 0` might lead to weird behavior elsewhere, + // but this should only be possible when using `-Z continue-parse-after-error` like + // `compile-fail/issue-36638.rs`. + if self.name == keywords::SelfType.name().as_str() && self.idx == 0 { true } else { false @@ -1152,6 +1145,10 @@ impl<'a, 'tcx, 'gcx> PolyExistentialProjection<'tcx> { -> ty::PolyProjectionPredicate<'tcx> { self.map_bound(|p| p.with_self_ty(tcx, self_ty)) } + + pub fn item_def_id(&self) -> DefId { + return self.skip_binder().item_def_id; + } } impl DebruijnIndex { diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 77eff49d19f..4aa70e1f7e0 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -22,7 +22,7 @@ use ty::fold::TypeVisitor; use ty::subst::UnpackedKind; use ty::maps::TyCtxtAt; use ty::TypeVariants::*; -use ty::layout::Integer; +use ty::layout::{Integer, IntegerExt}; use util::common::ErrorReported; use middle::lang_items; use mir::interpret::{Value, PrimVal}; @@ -380,7 +380,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { ty::Predicate::ConstEvaluatable(..) => { None } - ty::Predicate::TypeOutlives(ty::Binder(ty::OutlivesPredicate(t, r))) => { + ty::Predicate::TypeOutlives(predicate) => { // Search for a bound of the form `erased_self_ty // : 'a`, but be wary of something like `for<'a> // erased_self_ty : 'a` (we interpret a @@ -390,8 +390,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // it's kind of a moot point since you could never // construct such an object, but this seems // correct even if that code changes). - if t == erased_self_ty && !r.has_escaping_regions() { - Some(r) + let ty::OutlivesPredicate(ref t, ref r) = predicate.skip_binder(); + if t == &erased_self_ty && !r.has_escaping_regions() { + Some(*r) } else { None } @@ -561,7 +562,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { ty::ClosureKind::FnMut => self.mk_mut_ref(self.mk_region(env_region), closure_ty), ty::ClosureKind::FnOnce => closure_ty, }; - Some(ty::Binder(env_ty)) + Some(ty::Binder::bind(env_ty)) } /// Given the def-id of some item that has no type parameters, make @@ -1023,7 +1024,7 @@ fn needs_drop_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let (param_env, ty) = query.into_parts(); let needs_drop = |ty: Ty<'tcx>| -> bool { - match ty::queries::needs_drop_raw::try_get(tcx, DUMMY_SP, param_env.and(ty)) { + match tcx.try_get_query::<ty::queries::needs_drop_raw>(DUMMY_SP, param_env.and(ty)) { Ok(v) => v, Err(mut bug) => { // Cycles should be reported as an error by `check_representable`. diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index f05d56c9d83..aea84791fe8 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -307,7 +307,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { cause, param_env, ty::Predicate::TypeOutlives( - ty::Binder( + ty::Binder::dummy( ty::OutlivesPredicate(mt.ty, r))))); } } @@ -492,7 +492,8 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { for implicit_bound in implicit_bounds { let cause = self.cause(traits::ObjectTypeBound(ty, explicit_bound)); - let outlives = ty::Binder(ty::OutlivesPredicate(explicit_bound, implicit_bound)); + let outlives = ty::Binder::dummy( + ty::OutlivesPredicate(explicit_bound, implicit_bound)); self.out.push(traits::Obligation::new(cause, self.param_env, outlives.to_predicate())); diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs index bb6aa654c29..c74e42263ef 100644 --- a/src/librustc/util/common.rs +++ b/src/librustc/util/common.rs @@ -25,7 +25,6 @@ use std::time::{Duration, Instant}; use std::sync::mpsc::{Sender}; use syntax_pos::{SpanData}; -use ty::maps::{QueryMsg}; use ty::TyCtxt; use dep_graph::{DepNode}; use proc_macro; @@ -77,6 +76,13 @@ pub struct ProfQDumpParams { pub dump_profq_msg_log:bool, } +#[allow(bad_style)] +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct QueryMsg { + pub query: &'static str, + pub msg: Option<String>, +} + /// A sequence of these messages induce a trace of query-based incremental compilation. /// FIXME(matthewhammer): Determine whether we should include cycle detection here or not. #[derive(Clone,Debug)] diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index dd478967b18..b777f513e6d 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -28,7 +28,7 @@ use std::fmt; use std::usize; use rustc_data_structures::indexed_vec::Idx; -use syntax::abi::Abi; +use rustc_target::spec::abi::Abi; use syntax::ast::CRATE_NODE_ID; use syntax::symbol::{Symbol, InternedString}; use hir; @@ -268,14 +268,31 @@ impl PrintContext { loop { let key = tcx.def_key(item_def_id); match key.disambiguated_data.data { + DefPathData::AssocTypeInTrait(_) | + DefPathData::AssocTypeInImpl(_) | + DefPathData::Trait(_) | DefPathData::TypeNs(_) => { break; } - DefPathData::ValueNs(_) | DefPathData::EnumVariant(_) => { + DefPathData::ValueNs(_) | + DefPathData::EnumVariant(_) => { is_value_path = true; break; } - _ => { + DefPathData::CrateRoot | + DefPathData::Misc | + DefPathData::Impl | + DefPathData::Module(_) | + DefPathData::MacroDef(_) | + DefPathData::ClosureExpr | + DefPathData::TypeParam(_) | + DefPathData::LifetimeDef(_) | + DefPathData::Field(_) | + DefPathData::StructCtor | + DefPathData::Initializer | + DefPathData::ImplTrait | + DefPathData::Typeof | + DefPathData::GlobalMetaData(_) => { // if we're making a symbol for something, there ought // to be a value or type-def or something in there // *somewhere* @@ -445,7 +462,7 @@ impl PrintContext { 0 => Symbol::intern("'r"), 1 => Symbol::intern("'s"), i => Symbol::intern(&format!("'t{}", i-2)), - }.as_str() + }.as_interned_str() } // Replace any anonymous late-bound regions with named @@ -456,7 +473,7 @@ impl PrintContext { let value = if let Some(v) = lifted { v } else { - return original.0.print_display(f, self); + return original.skip_binder().print_display(f, self); }; if self.binder_depth == 0 { @@ -662,9 +679,9 @@ define_print! { ty::tls::with(|tcx| { let dummy_self = tcx.mk_infer(ty::FreshTy(0)); - let trait_ref = tcx.lift(&ty::Binder(*self)) + let trait_ref = *tcx.lift(&ty::Binder::bind(*self)) .expect("could not lift TraitRef for printing") - .with_self_ty(tcx, dummy_self).0; + .with_self_ty(tcx, dummy_self).skip_binder(); cx.parameterized(f, trait_ref.substs, trait_ref.def_id, &[]) }) } diff --git a/src/librustc_allocator/Cargo.toml b/src/librustc_allocator/Cargo.toml index e3d1d8e32c4..765cb80f357 100644 --- a/src/librustc_allocator/Cargo.toml +++ b/src/librustc_allocator/Cargo.toml @@ -11,5 +11,6 @@ test = false [dependencies] rustc = { path = "../librustc" } rustc_errors = { path = "../librustc_errors" } +rustc_target = { path = "../librustc_target" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/librustc_allocator/expand.rs b/src/librustc_allocator/expand.rs index 305502e7f06..de8814d3d6a 100644 --- a/src/librustc_allocator/expand.rs +++ b/src/librustc_allocator/expand.rs @@ -10,13 +10,13 @@ use rustc::middle::allocator::AllocatorKind; use rustc_errors; -use syntax::abi::Abi; -use syntax::ast::{Crate, Attribute, LitKind, StrStyle}; -use syntax::ast::{Unsafety, Constness, Generics, Mutability, Ty, Mac, Arg}; -use syntax::ast::{self, Ident, Item, ItemKind, TyKind, VisibilityKind, Expr}; +use rustc_target::spec::abi::Abi; +use syntax::ast::{Attribute, Crate, LitKind, StrStyle}; +use syntax::ast::{Arg, Constness, Generics, Mac, Mutability, Ty, Unsafety}; +use syntax::ast::{self, Expr, Ident, Item, ItemKind, TyKind, VisibilityKind}; use syntax::attr; use syntax::codemap::{dummy_spanned, respan}; -use syntax::codemap::{ExpnInfo, NameAndSpan, MacroAttribute}; +use syntax::codemap::{ExpnInfo, MacroAttribute, NameAndSpan}; use syntax::ext::base::ExtCtxt; use syntax::ext::base::Resolver; use syntax::ext::build::AstBuilder; @@ -31,10 +31,12 @@ use syntax_pos::{Span, DUMMY_SP}; use {AllocatorMethod, AllocatorTy, ALLOCATOR_METHODS}; -pub fn modify(sess: &ParseSess, - resolver: &mut Resolver, - krate: Crate, - handler: &rustc_errors::Handler) -> ast::Crate { +pub fn modify( + sess: &ParseSess, + resolver: &mut Resolver, + krate: Crate, + handler: &rustc_errors::Handler, +) -> ast::Crate { ExpandAllocatorDirectives { handler, sess, @@ -55,20 +57,24 @@ impl<'a> Folder for ExpandAllocatorDirectives<'a> { let name = if attr::contains_name(&item.attrs, "global_allocator") { "global_allocator" } else { - return fold::noop_fold_item(item, self) + return fold::noop_fold_item(item, self); }; match item.node { ItemKind::Static(..) => {} _ => { - self.handler.span_err(item.span, "allocators must be statics"); - return SmallVector::one(item) + self.handler + .span_err(item.span, "allocators must be statics"); + return SmallVector::one(item); } } if self.found { - self.handler.span_err(item.span, "cannot define more than one \ - #[global_allocator]"); - return SmallVector::one(item) + self.handler.span_err( + item.span, + "cannot define more than one \ + #[global_allocator]", + ); + return SmallVector::one(item); } self.found = true; @@ -80,7 +86,7 @@ impl<'a> Folder for ExpandAllocatorDirectives<'a> { span: None, allow_internal_unstable: true, allow_internal_unsafe: false, - } + }, }); let span = item.span.with_ctxt(SyntaxContext::empty().apply_mark(mark)); let ecfg = ExpansionConfig::default(name.to_string()); @@ -91,10 +97,7 @@ impl<'a> Folder for ExpandAllocatorDirectives<'a> { core: Ident::from_str("core"), cx: ExtCtxt::new(self.sess, ecfg, self.resolver), }; - let super_path = f.cx.path(f.span, vec![ - Ident::from_str("super"), - f.global, - ]); + let super_path = f.cx.path(f.span, vec![Ident::from_str("super"), f.global]); let mut items = vec![ f.cx.item_extern_crate(f.span, f.core), f.cx.item_use_simple( @@ -114,7 +117,7 @@ impl<'a> Folder for ExpandAllocatorDirectives<'a> { let mut ret = SmallVector::new(); ret.push(item); ret.push(module); - return ret + return ret; } fn fold_mac(&mut self, mac: Mac) -> Mac { @@ -139,30 +142,39 @@ impl<'a> AllocFnFactory<'a> { i += 1; name }; - let args = method.inputs.iter().map(|ty| { - self.arg_ty(ty, &mut abi_args, mk) - }).collect(); + let args = method + .inputs + .iter() + .map(|ty| self.arg_ty(ty, &mut abi_args, mk)) + .collect(); let result = self.call_allocator(method.name, args); let (output_ty, output_expr) = self.ret_ty(&method.output, result); - let kind = ItemKind::Fn(self.cx.fn_decl(abi_args, ast::FunctionRetTy::Ty(output_ty)), - Unsafety::Unsafe, - dummy_spanned(Constness::NotConst), - Abi::Rust, - Generics::default(), - self.cx.block_expr(output_expr)); - self.cx.item(self.span, - Ident::from_str(&self.kind.fn_name(method.name)), - self.attrs(), - kind) + let kind = ItemKind::Fn( + self.cx.fn_decl(abi_args, ast::FunctionRetTy::Ty(output_ty)), + Unsafety::Unsafe, + dummy_spanned(Constness::NotConst), + Abi::Rust, + Generics::default(), + self.cx.block_expr(output_expr), + ); + self.cx.item( + self.span, + Ident::from_str(&self.kind.fn_name(method.name)), + self.attrs(), + kind, + ) } fn call_allocator(&self, method: &str, mut args: Vec<P<Expr>>) -> P<Expr> { - let method = self.cx.path(self.span, vec![ - self.core, - Ident::from_str("alloc"), - Ident::from_str("GlobalAlloc"), - Ident::from_str(method), - ]); + let method = self.cx.path( + self.span, + vec![ + self.core, + Ident::from_str("alloc"), + Ident::from_str("GlobalAlloc"), + Ident::from_str(method), + ], + ); let method = self.cx.expr_path(method); let allocator = self.cx.path_ident(self.span, self.global); let allocator = self.cx.expr_path(allocator); @@ -189,10 +201,12 @@ impl<'a> AllocFnFactory<'a> { ] } - fn arg_ty(&self, - ty: &AllocatorTy, - args: &mut Vec<Arg>, - ident: &mut FnMut() -> Ident) -> P<Expr> { + fn arg_ty( + &self, + ty: &AllocatorTy, + args: &mut Vec<Arg>, + ident: &mut FnMut() -> Ident, + ) -> P<Expr> { match *ty { AllocatorTy::Layout => { let usize = self.cx.path_ident(self.span, Ident::from_str("usize")); @@ -202,18 +216,19 @@ impl<'a> AllocFnFactory<'a> { args.push(self.cx.arg(self.span, size, ty_usize.clone())); args.push(self.cx.arg(self.span, align, ty_usize)); - let layout_new = self.cx.path(self.span, vec![ - self.core, - Ident::from_str("alloc"), - Ident::from_str("Layout"), - Ident::from_str("from_size_align_unchecked"), - ]); + let layout_new = self.cx.path( + self.span, + vec![ + self.core, + Ident::from_str("alloc"), + Ident::from_str("Layout"), + Ident::from_str("from_size_align_unchecked"), + ], + ); let layout_new = self.cx.expr_path(layout_new); let size = self.cx.expr_ident(self.span, size); let align = self.cx.expr_ident(self.span, align); - let layout = self.cx.expr_call(self.span, - layout_new, - vec![size, align]); + let layout = self.cx.expr_call(self.span, layout_new, vec![size, align]); layout } @@ -230,9 +245,7 @@ impl<'a> AllocFnFactory<'a> { self.cx.expr_ident(self.span, ident) } - AllocatorTy::ResultPtr | - AllocatorTy::Bang | - AllocatorTy::Unit => { + AllocatorTy::ResultPtr | AllocatorTy::Unit => { panic!("can't convert AllocatorTy to an argument") } } @@ -249,17 +262,9 @@ impl<'a> AllocFnFactory<'a> { (self.ptr_u8(), expr) } - AllocatorTy::Bang => { - (self.cx.ty(self.span, TyKind::Never), expr) - } + AllocatorTy::Unit => (self.cx.ty(self.span, TyKind::Tup(Vec::new())), expr), - AllocatorTy::Unit => { - (self.cx.ty(self.span, TyKind::Tup(Vec::new())), expr) - } - - AllocatorTy::Layout | - AllocatorTy::Usize | - AllocatorTy::Ptr => { + AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => { panic!("can't convert AllocatorTy to an output") } } @@ -277,11 +282,14 @@ impl<'a> AllocFnFactory<'a> { } fn ptr_opaque(&self) -> P<Ty> { - let opaque = self.cx.path(self.span, vec![ - self.core, - Ident::from_str("alloc"), - Ident::from_str("Opaque"), - ]); + let opaque = self.cx.path( + self.span, + vec![ + self.core, + Ident::from_str("alloc"), + Ident::from_str("Opaque"), + ], + ); let ty_opaque = self.cx.ty_path(opaque); self.cx.ty_ptr(self.span, ty_opaque, Mutability::Mutable) } diff --git a/src/librustc_allocator/lib.rs b/src/librustc_allocator/lib.rs index 706eab72d44..6595564fb30 100644 --- a/src/librustc_allocator/lib.rs +++ b/src/librustc_allocator/lib.rs @@ -12,6 +12,7 @@ extern crate rustc; extern crate rustc_errors; +extern crate rustc_target; extern crate syntax; extern crate syntax_pos; @@ -24,11 +25,6 @@ pub static ALLOCATOR_METHODS: &[AllocatorMethod] = &[ output: AllocatorTy::ResultPtr, }, AllocatorMethod { - name: "oom", - inputs: &[], - output: AllocatorTy::Bang, - }, - AllocatorMethod { name: "dealloc", inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout], output: AllocatorTy::Unit, @@ -52,7 +48,6 @@ pub struct AllocatorMethod { } pub enum AllocatorTy { - Bang, Layout, Ptr, ResultPtr, diff --git a/src/librustc_apfloat/lib.rs b/src/librustc_apfloat/lib.rs index 0f051ea5981..08438805a70 100644 --- a/src/librustc_apfloat/lib.rs +++ b/src/librustc_apfloat/lib.rs @@ -45,6 +45,7 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![forbid(unsafe_code)] +#![feature(try_from)] // See librustc_cratesio_shim/Cargo.toml for a comment explaining this. #[allow(unused_extern_crates)] extern crate rustc_cratesio_shim; diff --git a/src/librustc_back/README.md b/src/librustc_back/README.md deleted file mode 100644 index 3c01692c12b..00000000000 --- a/src/librustc_back/README.md +++ /dev/null @@ -1,6 +0,0 @@ -`librustc_back` contains some very low-level details that are -specific to different LLVM targets and so forth. - -For more information about how trans works, see the [rustc guide]. - -[rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/trans.html diff --git a/src/librustc_back/lib.rs b/src/librustc_back/lib.rs deleted file mode 100644 index 027a9c45555..00000000000 --- a/src/librustc_back/lib.rs +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Some stuff used by rustc that doesn't have many dependencies -//! -//! Originally extracted from rustc::back, which was nominally the -//! compiler 'backend', though LLVM is rustc's backend, so rustc_back -//! is really just odds-and-ends relating to code gen and linking. -//! This crate mostly exists to make rustc smaller, so we might put -//! more 'stuff' here in the future. It does not have a dependency on -//! rustc_llvm. -//! -//! FIXME: Split this into two crates: one that has deps on syntax, and -//! one that doesn't; the one that doesn't might get decent parallel -//! build speedups. - -#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", - html_favicon_url = "https://doc.rust-lang.org/favicon.ico", - html_root_url = "https://doc.rust-lang.org/nightly/")] - -#![feature(box_syntax)] -#![feature(const_fn)] -#![feature(fs_read_write)] - -extern crate syntax; -extern crate rand; -extern crate serialize; -#[macro_use] extern crate log; - -extern crate serialize as rustc_serialize; // used by deriving - -pub mod target; - -use std::str::FromStr; - -use serialize::json::{Json, ToJson}; - -#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, Hash, - RustcEncodable, RustcDecodable)] -pub enum LinkerFlavor { - Em, - Gcc, - Ld, - Msvc, - Lld(LldFlavor), -} - -#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, Hash, - RustcEncodable, RustcDecodable)] -pub enum LldFlavor { - Wasm, - Ld64, - Ld, - Link, -} - -impl ToJson for LinkerFlavor { - fn to_json(&self) -> Json { - self.desc().to_json() - } -} -macro_rules! flavor_mappings { - ($((($($flavor:tt)*), $string:expr),)*) => ( - impl LinkerFlavor { - pub const fn one_of() -> &'static str { - concat!("one of: ", $($string, " ",)+) - } - - pub fn from_str(s: &str) -> Option<Self> { - Some(match s { - $($string => $($flavor)*,)+ - _ => return None, - }) - } - - pub fn desc(&self) -> &str { - match *self { - $($($flavor)* => $string,)+ - } - } - } - ) -} - - -flavor_mappings! { - ((LinkerFlavor::Em), "em"), - ((LinkerFlavor::Gcc), "gcc"), - ((LinkerFlavor::Ld), "ld"), - ((LinkerFlavor::Msvc), "msvc"), - ((LinkerFlavor::Lld(LldFlavor::Wasm)), "wasm-ld"), - ((LinkerFlavor::Lld(LldFlavor::Ld64)), "ld64.lld"), - ((LinkerFlavor::Lld(LldFlavor::Ld)), "ld.lld"), - ((LinkerFlavor::Lld(LldFlavor::Link)), "lld-link"), -} - -#[derive(Clone, Copy, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)] -pub enum PanicStrategy { - Unwind, - Abort, -} - -impl PanicStrategy { - pub fn desc(&self) -> &str { - match *self { - PanicStrategy::Unwind => "unwind", - PanicStrategy::Abort => "abort", - } - } -} - -impl ToJson for PanicStrategy { - fn to_json(&self) -> Json { - match *self { - PanicStrategy::Abort => "abort".to_json(), - PanicStrategy::Unwind => "unwind".to_json(), - } - } -} - -#[derive(Clone, Copy, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)] -pub enum RelroLevel { - Full, - Partial, - Off, - None, -} - -impl RelroLevel { - pub fn desc(&self) -> &str { - match *self { - RelroLevel::Full => "full", - RelroLevel::Partial => "partial", - RelroLevel::Off => "off", - RelroLevel::None => "none", - } - } -} - -impl FromStr for RelroLevel { - type Err = (); - - fn from_str(s: &str) -> Result<RelroLevel, ()> { - match s { - "full" => Ok(RelroLevel::Full), - "partial" => Ok(RelroLevel::Partial), - "off" => Ok(RelroLevel::Off), - "none" => Ok(RelroLevel::None), - _ => Err(()), - } - } -} - -impl ToJson for RelroLevel { - fn to_json(&self) -> Json { - match *self { - RelroLevel::Full => "full".to_json(), - RelroLevel::Partial => "partial".to_json(), - RelroLevel::Off => "off".to_json(), - RelroLevel::None => "None".to_json(), - } - } -} diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 6d832d4060a..519dd574e5a 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -144,7 +144,10 @@ fn borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, owner_def_id: DefId) { check_loans::check_loans(&mut bccx, &loan_dfcx, &flowed_moves, &all_loans, body); } - unused::check(&mut bccx, body); + + if !tcx.use_mir_borrowck() { + unused::check(&mut bccx, body); + } Lrc::new(BorrowCheckResult { used_mut_nodes: bccx.used_mut_nodes.into_inner(), diff --git a/src/librustc_cratesio_shim/Cargo.toml b/src/librustc_cratesio_shim/Cargo.toml index 143f88e8f4b..342c7d1b678 100644 --- a/src/librustc_cratesio_shim/Cargo.toml +++ b/src/librustc_cratesio_shim/Cargo.toml @@ -21,3 +21,4 @@ crate-type = ["dylib"] [dependencies] bitflags = "1.0" +log = "0.4" diff --git a/src/librustc_cratesio_shim/src/lib.rs b/src/librustc_cratesio_shim/src/lib.rs index 769b4f57206..85a5b331d8c 100644 --- a/src/librustc_cratesio_shim/src/lib.rs +++ b/src/librustc_cratesio_shim/src/lib.rs @@ -12,3 +12,4 @@ #![allow(unused_extern_crates)] extern crate bitflags; +extern crate log; diff --git a/src/librustc_data_structures/Cargo.toml b/src/librustc_data_structures/Cargo.toml index e1f0a74fc68..9178d0d00fa 100644 --- a/src/librustc_data_structures/Cargo.toml +++ b/src/librustc_data_structures/Cargo.toml @@ -11,6 +11,7 @@ crate-type = ["dylib"] [dependencies] ena = "0.9.1" log = "0.4" +rustc_cratesio_shim = { path = "../librustc_cratesio_shim" } serialize = { path = "../libserialize" } cfg-if = "0.1.2" stable_deref_trait = "1.0.0" diff --git a/src/librustc_data_structures/lazy_btree_map.rs b/src/librustc_data_structures/lazy_btree_map.rs new file mode 100644 index 00000000000..74f91af10fe --- /dev/null +++ b/src/librustc_data_structures/lazy_btree_map.rs @@ -0,0 +1,108 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::collections::btree_map; +use std::collections::BTreeMap; + +/// A thin wrapper around BTreeMap that avoids allocating upon creation. +/// +/// Vec, HashSet and HashMap all have the nice feature that they don't do any +/// heap allocation when creating a new structure of the default size. In +/// contrast, BTreeMap *does* allocate in that situation. The compiler uses +/// B-Tree maps in some places such that many maps are created but few are +/// inserted into, so having a BTreeMap alternative that avoids allocating on +/// creation is a performance win. +/// +/// Only a fraction of BTreeMap's functionality is currently supported. +/// Additional functionality should be added on demand. +#[derive(Debug)] +pub struct LazyBTreeMap<K, V>(Option<BTreeMap<K, V>>); + +impl<K, V> LazyBTreeMap<K, V> { + pub fn new() -> LazyBTreeMap<K, V> { + LazyBTreeMap(None) + } + + pub fn iter(&self) -> Iter<K, V> { + Iter(self.0.as_ref().map(|btm| btm.iter())) + } + + pub fn is_empty(&self) -> bool { + self.0.as_ref().map_or(true, |btm| btm.is_empty()) + } +} + +impl<K: Ord, V> LazyBTreeMap<K, V> { + fn instantiate(&mut self) -> &mut BTreeMap<K, V> { + if let Some(ref mut btm) = self.0 { + btm + } else { + let btm = BTreeMap::new(); + self.0 = Some(btm); + self.0.as_mut().unwrap() + } + } + + pub fn insert(&mut self, key: K, value: V) -> Option<V> { + self.instantiate().insert(key, value) + } + + pub fn entry(&mut self, key: K) -> btree_map::Entry<K, V> { + self.instantiate().entry(key) + } + + pub fn values<'a>(&'a self) -> Values<'a, K, V> { + Values(self.0.as_ref().map(|btm| btm.values())) + } +} + +impl<K: Ord, V> Default for LazyBTreeMap<K, V> { + fn default() -> LazyBTreeMap<K, V> { + LazyBTreeMap::new() + } +} + +impl<'a, K: 'a, V: 'a> IntoIterator for &'a LazyBTreeMap<K, V> { + type Item = (&'a K, &'a V); + type IntoIter = Iter<'a, K, V>; + + fn into_iter(self) -> Iter<'a, K, V> { + self.iter() + } +} + +pub struct Iter<'a, K: 'a, V: 'a>(Option<btree_map::Iter<'a, K, V>>); + +impl<'a, K: 'a, V: 'a> Iterator for Iter<'a, K, V> { + type Item = (&'a K, &'a V); + + fn next(&mut self) -> Option<(&'a K, &'a V)> { + self.0.as_mut().and_then(|iter| iter.next()) + } + + fn size_hint(&self) -> (usize, Option<usize>) { + self.0.as_ref().map_or_else(|| (0, Some(0)), |iter| iter.size_hint()) + } +} + +pub struct Values<'a, K: 'a, V: 'a>(Option<btree_map::Values<'a, K, V>>); + +impl<'a, K, V> Iterator for Values<'a, K, V> { + type Item = &'a V; + + fn next(&mut self) -> Option<&'a V> { + self.0.as_mut().and_then(|values| values.next()) + } + + fn size_hint(&self) -> (usize, Option<usize>) { + self.0.as_ref().map_or_else(|| (0, Some(0)), |values| values.size_hint()) + } +} + diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index ba1d73dc268..597d1627ada 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -45,6 +45,10 @@ extern crate parking_lot; extern crate cfg_if; extern crate stable_deref_trait; +// See librustc_cratesio_shim/Cargo.toml for a comment explaining this. +#[allow(unused_extern_crates)] +extern crate rustc_cratesio_shim; + pub use rustc_serialize::hex::ToHex; pub mod array_vec; @@ -56,6 +60,7 @@ pub mod bitvec; pub mod graph; pub mod indexed_set; pub mod indexed_vec; +pub mod lazy_btree_map; pub mod obligation_forest; pub mod sip128; pub mod snapshot_map; diff --git a/src/librustc_driver/Cargo.toml b/src/librustc_driver/Cargo.toml index 3bff79ed3a6..5aae1bcad89 100644 --- a/src/librustc_driver/Cargo.toml +++ b/src/librustc_driver/Cargo.toml @@ -15,7 +15,7 @@ log = "0.4" env_logger = { version = "0.5", default-features = false } rustc = { path = "../librustc" } rustc_allocator = { path = "../librustc_allocator" } -rustc_back = { path = "../librustc_back" } +rustc_target = { path = "../librustc_target" } rustc_borrowck = { path = "../librustc_borrowck" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_errors = { path = "../librustc_errors" } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index a0eed9e2f8c..2fb811eba1e 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -14,17 +14,17 @@ use rustc::hir::lowering::lower_crate; use rustc::ich::Fingerprint; use rustc_data_structures::stable_hasher::StableHasher; use rustc_mir as mir; -use rustc::session::{Session, CompileResult, CrateDisambiguator}; +use rustc::session::{CompileResult, CrateDisambiguator, Session}; use rustc::session::CompileIncomplete; use rustc::session::config::{self, Input, OutputFilenames, OutputType}; use rustc::session::search_paths::PathKind; use rustc::lint; -use rustc::middle::{self, stability, reachable, resolve_lifetime}; +use rustc::middle::{self, reachable, resolve_lifetime, stability}; use rustc::middle::cstore::CrateStore; use rustc::middle::privacy::AccessLevels; -use rustc::ty::{self, TyCtxt, Resolutions, AllArenas}; +use rustc::ty::{self, AllArenas, Resolutions, TyCtxt}; use rustc::traits; -use rustc::util::common::{ErrorReported, time, install_panic_hook}; +use rustc::util::common::{install_panic_hook, time, ErrorReported}; use rustc_allocator as allocator; use rustc_borrowck as borrowck; use rustc_incremental; @@ -37,14 +37,14 @@ use rustc_typeck as typeck; use rustc_privacy; use rustc_plugin::registry::Registry; use rustc_plugin as plugin; -use rustc_passes::{self, ast_validation, loops, rvalue_promotion, hir_stats}; +use rustc_passes::{self, ast_validation, hir_stats, loops, rvalue_promotion}; use super::Compilation; use serialize::json; use std::any::Any; use std::env; -use std::ffi::{OsString, OsStr}; +use std::ffi::{OsStr, OsString}; use std::fs; use std::io::{self, Write}; use std::iter; @@ -64,15 +64,17 @@ use pretty::ReplaceBodyWithLoop; use profile; -pub fn compile_input(trans: Box<TransCrate>, - sess: &Session, - cstore: &CStore, - input_path: &Option<PathBuf>, - input: &Input, - outdir: &Option<PathBuf>, - output: &Option<PathBuf>, - addl_plugins: Option<Vec<String>>, - control: &CompileController) -> CompileResult { +pub fn compile_input( + trans: Box<TransCrate>, + sess: &Session, + cstore: &CStore, + input_path: &Option<PathBuf>, + input: &Input, + outdir: &Option<PathBuf>, + output: &Option<PathBuf>, + addl_plugins: Option<Vec<String>>, + control: &CompileController, +) -> CompileResult { macro_rules! controller_entry_point { ($point: ident, $tsess: expr, $make_state: expr, $phase_result: expr) => {{ let state = &mut $make_state; @@ -106,16 +108,9 @@ pub fn compile_input(trans: Box<TransCrate>, }; let (krate, registry) = { - let mut compile_state = CompileState::state_after_parse(input, - sess, - outdir, - output, - krate, - &cstore); - controller_entry_point!(after_parse, - sess, - compile_state, - Ok(())); + let mut compile_state = + CompileState::state_after_parse(input, sess, outdir, output, krate, &cstore); + controller_entry_point!(after_parse, sess, compile_state, Ok(())); (compile_state.krate.unwrap(), compile_state.registry) }; @@ -125,7 +120,13 @@ pub fn compile_input(trans: Box<TransCrate>, ::rustc_trans_utils::link::find_crate_name(Some(sess), &krate.attrs, input); install_panic_hook(); - let ExpansionResult { expanded_crate, defs, analysis, resolutions, mut hir_forest } = { + let ExpansionResult { + expanded_crate, + defs, + analysis, + resolutions, + mut hir_forest, + } = { phase_2_configure_and_expand( sess, &cstore, @@ -136,11 +137,17 @@ pub fn compile_input(trans: Box<TransCrate>, control.make_glob_map, |expanded_crate| { let mut state = CompileState::state_after_expand( - input, sess, outdir, output, &cstore, expanded_crate, &crate_name, + input, + sess, + outdir, + output, + &cstore, + expanded_crate, + &crate_name, ); controller_entry_point!(after_expand, sess, state, Ok(())); Ok(()) - } + }, )? }; @@ -152,24 +159,28 @@ pub fn compile_input(trans: Box<TransCrate>, if output_contains_path(&output_paths, input_path) { sess.err(&format!( "the input file \"{}\" would be overwritten by the generated \ - executable", - input_path.display())); + executable", + input_path.display() + )); return Err(CompileIncomplete::Stopped); } if let Some(dir_path) = output_conflicts_with_dir(&output_paths) { sess.err(&format!( "the generated executable for the input file \"{}\" conflicts with the \ - existing directory \"{}\"", - input_path.display(), dir_path.display())); + existing directory \"{}\"", + input_path.display(), + dir_path.display() + )); return Err(CompileIncomplete::Stopped); } } } write_out_deps(sess, &outputs, &output_paths); - if sess.opts.output_types.contains_key(&OutputType::DepInfo) && - sess.opts.output_types.len() == 1 { - return Ok(()) + if sess.opts.output_types.contains_key(&OutputType::DepInfo) + && sess.opts.output_types.len() == 1 + { + return Ok(()); } if let &Some(ref dir) = outdir { @@ -182,28 +193,32 @@ pub fn compile_input(trans: Box<TransCrate>, let arenas = AllArenas::new(); // Construct the HIR map - let hir_map = time(sess, - "indexing hir", - || hir_map::map_crate(sess, cstore, &mut hir_forest, &defs)); + let hir_map = time(sess, "indexing hir", || { + hir_map::map_crate(sess, cstore, &mut hir_forest, &defs) + }); { hir_map.dep_graph.assert_ignored(); - controller_entry_point!(after_hir_lowering, - sess, - CompileState::state_after_hir_lowering(input, - sess, - outdir, - output, - &arenas, - &cstore, - &hir_map, - &analysis, - &resolutions, - &expanded_crate, - &hir_map.krate(), - &outputs, - &crate_name), - Ok(())); + controller_entry_point!( + after_hir_lowering, + sess, + CompileState::state_after_hir_lowering( + input, + sess, + outdir, + output, + &arenas, + &cstore, + &hir_map, + &analysis, + &resolutions, + &expanded_crate, + &hir_map.krate(), + &outputs, + &crate_name + ), + Ok(()) + ); } let opt_crate = if control.keep_ast { @@ -213,60 +228,64 @@ pub fn compile_input(trans: Box<TransCrate>, None }; - phase_3_run_analysis_passes(&*trans, - control, - sess, - cstore, - hir_map, - analysis, - resolutions, - &arenas, - &crate_name, - &outputs, - |tcx, analysis, rx, result| { - { - // Eventually, we will want to track plugins. - tcx.dep_graph.with_ignore(|| { - let mut state = CompileState::state_after_analysis(input, - sess, - outdir, - output, - opt_crate, - tcx.hir.krate(), - &analysis, - tcx, - &crate_name); - (control.after_analysis.callback)(&mut state); - }); - - if control.after_analysis.stop == Compilation::Stop { - return result.and_then(|_| Err(CompileIncomplete::Stopped)); + phase_3_run_analysis_passes( + &*trans, + control, + sess, + cstore, + hir_map, + analysis, + resolutions, + &arenas, + &crate_name, + &outputs, + |tcx, analysis, rx, result| { + { + // Eventually, we will want to track plugins. + tcx.dep_graph.with_ignore(|| { + let mut state = CompileState::state_after_analysis( + input, + sess, + outdir, + output, + opt_crate, + tcx.hir.krate(), + &analysis, + tcx, + &crate_name, + ); + (control.after_analysis.callback)(&mut state); + }); + + if control.after_analysis.stop == Compilation::Stop { + return result.and_then(|_| Err(CompileIncomplete::Stopped)); + } } - } - result?; + result?; - if log_enabled!(::log::Level::Info) { - println!("Pre-trans"); - tcx.print_debug_stats(); - } + if log_enabled!(::log::Level::Info) { + println!("Pre-trans"); + tcx.print_debug_stats(); + } - let ongoing_trans = phase_4_translate_to_llvm(&*trans, tcx, rx); + let ongoing_trans = phase_4_translate_to_llvm(&*trans, tcx, rx); - if log_enabled!(::log::Level::Info) { - println!("Post-trans"); - tcx.print_debug_stats(); - } + if log_enabled!(::log::Level::Info) { + println!("Post-trans"); + tcx.print_debug_stats(); + } - if tcx.sess.opts.output_types.contains_key(&OutputType::Mir) { - if let Err(e) = mir::transform::dump_mir::emit_mir(tcx, &outputs) { - sess.err(&format!("could not emit MIR: {}", e)); - sess.abort_if_errors(); + if tcx.sess.opts.output_types.contains_key(&OutputType::Mir) { + if let Err(e) = mir::transform::dump_mir::emit_mir(tcx, &outputs) { + sess.err(&format!("could not emit MIR: {}", e)); + sess.abort_if_errors(); + } } - } - Ok((outputs.clone(), ongoing_trans, tcx.dep_graph.clone())) - })?? + Ok((outputs.clone(), ongoing_trans, tcx.dep_graph.clone())) + }, + )?? }; if sess.opts.debugging_opts.print_type_sizes { @@ -391,10 +410,7 @@ pub struct CompileState<'a, 'tcx: 'a> { } impl<'a, 'tcx> CompileState<'a, 'tcx> { - fn empty(input: &'a Input, - session: &'tcx Session, - out_dir: &'a Option<PathBuf>) - -> Self { + fn empty(input: &'a Input, session: &'tcx Session, out_dir: &'a Option<PathBuf>) -> Self { CompileState { input, session, @@ -415,13 +431,14 @@ impl<'a, 'tcx> CompileState<'a, 'tcx> { } } - fn state_after_parse(input: &'a Input, - session: &'tcx Session, - out_dir: &'a Option<PathBuf>, - out_file: &'a Option<PathBuf>, - krate: ast::Crate, - cstore: &'tcx CStore) - -> Self { + fn state_after_parse( + input: &'a Input, + session: &'tcx Session, + out_dir: &'a Option<PathBuf>, + out_file: &'a Option<PathBuf>, + krate: ast::Crate, + cstore: &'tcx CStore, + ) -> Self { CompileState { // Initialize the registry before moving `krate` registry: Some(Registry::new(&session, krate.span)), @@ -432,14 +449,15 @@ impl<'a, 'tcx> CompileState<'a, 'tcx> { } } - fn state_after_expand(input: &'a Input, - session: &'tcx Session, - out_dir: &'a Option<PathBuf>, - out_file: &'a Option<PathBuf>, - cstore: &'tcx CStore, - expanded_crate: &'a ast::Crate, - crate_name: &'a str) - -> Self { + fn state_after_expand( + input: &'a Input, + session: &'tcx Session, + out_dir: &'a Option<PathBuf>, + out_file: &'a Option<PathBuf>, + cstore: &'tcx CStore, + expanded_crate: &'a ast::Crate, + crate_name: &'a str, + ) -> Self { CompileState { crate_name: Some(crate_name), cstore: Some(cstore), @@ -449,20 +467,21 @@ impl<'a, 'tcx> CompileState<'a, 'tcx> { } } - fn state_after_hir_lowering(input: &'a Input, - session: &'tcx Session, - out_dir: &'a Option<PathBuf>, - out_file: &'a Option<PathBuf>, - arenas: &'tcx AllArenas<'tcx>, - cstore: &'tcx CStore, - hir_map: &'a hir_map::Map<'tcx>, - analysis: &'a ty::CrateAnalysis, - resolutions: &'a Resolutions, - krate: &'a ast::Crate, - hir_crate: &'a hir::Crate, - output_filenames: &'a OutputFilenames, - crate_name: &'a str) - -> Self { + fn state_after_hir_lowering( + input: &'a Input, + session: &'tcx Session, + out_dir: &'a Option<PathBuf>, + out_file: &'a Option<PathBuf>, + arenas: &'tcx AllArenas<'tcx>, + cstore: &'tcx CStore, + hir_map: &'a hir_map::Map<'tcx>, + analysis: &'a ty::CrateAnalysis, + resolutions: &'a Resolutions, + krate: &'a ast::Crate, + hir_crate: &'a hir::Crate, + output_filenames: &'a OutputFilenames, + crate_name: &'a str, + ) -> Self { CompileState { crate_name: Some(crate_name), arenas: Some(arenas), @@ -478,16 +497,17 @@ impl<'a, 'tcx> CompileState<'a, 'tcx> { } } - fn state_after_analysis(input: &'a Input, - session: &'tcx Session, - out_dir: &'a Option<PathBuf>, - out_file: &'a Option<PathBuf>, - krate: Option<&'a ast::Crate>, - hir_crate: &'a hir::Crate, - analysis: &'a ty::CrateAnalysis, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - crate_name: &'a str) - -> Self { + fn state_after_analysis( + input: &'a Input, + session: &'tcx Session, + out_dir: &'a Option<PathBuf>, + out_file: &'a Option<PathBuf>, + krate: Option<&'a ast::Crate>, + hir_crate: &'a hir::Crate, + analysis: &'a ty::CrateAnalysis, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + crate_name: &'a str, + ) -> Self { CompileState { analysis: Some(analysis), tcx: Some(tcx), @@ -499,11 +519,12 @@ impl<'a, 'tcx> CompileState<'a, 'tcx> { } } - fn state_when_compilation_done(input: &'a Input, - session: &'tcx Session, - out_dir: &'a Option<PathBuf>, - out_file: &'a Option<PathBuf>) - -> Self { + fn state_when_compilation_done( + input: &'a Input, + session: &'tcx Session, + out_dir: &'a Option<PathBuf>, + out_file: &'a Option<PathBuf>, + ) -> Self { CompileState { out_file: out_file.as_ref().map(|s| &**s), ..CompileState::empty(input, session, out_dir) @@ -511,27 +532,24 @@ impl<'a, 'tcx> CompileState<'a, 'tcx> { } } -pub fn phase_1_parse_input<'a>(control: &CompileController, - sess: &'a Session, - input: &Input) - -> PResult<'a, ast::Crate> { - sess.diagnostic().set_continue_after_error(control.continue_parse_after_error); +pub fn phase_1_parse_input<'a>( + control: &CompileController, + sess: &'a Session, + input: &Input, +) -> PResult<'a, ast::Crate> { + sess.diagnostic() + .set_continue_after_error(control.continue_parse_after_error); if sess.profile_queries() { profile::begin(sess); } - let krate = time(sess, "parsing", || { - match *input { - Input::File(ref file) => { - parse::parse_crate_from_file(file, &sess.parse_sess) - } - Input::Str { ref input, ref name } => { - parse::parse_crate_from_source_str(name.clone(), - input.clone(), - &sess.parse_sess) - } - } + let krate = time(sess, "parsing", || match *input { + Input::File(ref file) => parse::parse_crate_from_file(file, &sess.parse_sess), + Input::Str { + ref input, + ref name, + } => parse::parse_crate_from_source_str(name.clone(), input.clone(), &sess.parse_sess), })?; sess.diagnostic().set_continue_after_error(true); @@ -541,7 +559,10 @@ pub fn phase_1_parse_input<'a>(control: &CompileController, } if sess.opts.debugging_opts.input_stats { - println!("Lines of code: {}", sess.codemap().count_lines()); + println!( + "Lines of code: {}", + sess.codemap().count_lines() + ); println!("Pre-expansion node count: {}", count_nodes(&krate)); } @@ -586,16 +607,19 @@ pub struct InnerExpansionResult<'a> { /// standard library and prelude, and name resolution. /// /// Returns `None` if we're aborting after handling -W help. -pub fn phase_2_configure_and_expand<F>(sess: &Session, - cstore: &CStore, - krate: ast::Crate, - registry: Option<Registry>, - crate_name: &str, - addl_plugins: Option<Vec<String>>, - make_glob_map: MakeGlobMap, - after_expand: F) - -> Result<ExpansionResult, CompileIncomplete> - where F: FnOnce(&ast::Crate) -> CompileResult { +pub fn phase_2_configure_and_expand<F>( + sess: &Session, + cstore: &CStore, + krate: ast::Crate, + registry: Option<Registry>, + crate_name: &str, + addl_plugins: Option<Vec<String>>, + make_glob_map: MakeGlobMap, + after_expand: F, +) -> Result<ExpansionResult, CompileIncomplete> +where + F: FnOnce(&ast::Crate) -> CompileResult, +{ // Currently, we ignore the name resolution data structures for the purposes of dependency // tracking. Instead we will run name resolution and include its output in the hash of each // item, much like we do for macro expansion. In other words, the hash reflects not just @@ -603,52 +627,72 @@ pub fn phase_2_configure_and_expand<F>(sess: &Session, // this back at some point. let mut crate_loader = CrateLoader::new(sess, &cstore, &crate_name); let resolver_arenas = Resolver::arenas(); - let result = phase_2_configure_and_expand_inner(sess, cstore, krate, registry, crate_name, - addl_plugins, make_glob_map, &resolver_arenas, - &mut crate_loader, after_expand); + let result = phase_2_configure_and_expand_inner( + sess, + cstore, + krate, + registry, + crate_name, + addl_plugins, + make_glob_map, + &resolver_arenas, + &mut crate_loader, + after_expand, + ); match result { - Ok(InnerExpansionResult {expanded_crate, resolver, hir_forest}) => { - Ok(ExpansionResult { - expanded_crate, - defs: resolver.definitions, - hir_forest, - resolutions: Resolutions { - freevars: resolver.freevars, - export_map: resolver.export_map, - trait_map: resolver.trait_map, - maybe_unused_trait_imports: resolver.maybe_unused_trait_imports, - maybe_unused_extern_crates: resolver.maybe_unused_extern_crates, - }, - - analysis: ty::CrateAnalysis { - access_levels: Lrc::new(AccessLevels::default()), - name: crate_name.to_string(), - glob_map: if resolver.make_glob_map { Some(resolver.glob_map) } else { None }, + Ok(InnerExpansionResult { + expanded_crate, + resolver, + hir_forest, + }) => Ok(ExpansionResult { + expanded_crate, + defs: resolver.definitions, + hir_forest, + resolutions: Resolutions { + freevars: resolver.freevars, + export_map: resolver.export_map, + trait_map: resolver.trait_map, + maybe_unused_trait_imports: resolver.maybe_unused_trait_imports, + maybe_unused_extern_crates: resolver.maybe_unused_extern_crates, + }, + + analysis: ty::CrateAnalysis { + access_levels: Lrc::new(AccessLevels::default()), + name: crate_name.to_string(), + glob_map: if resolver.make_glob_map { + Some(resolver.glob_map) + } else { + None }, - }) - } - Err(x) => Err(x) + }, + }), + Err(x) => Err(x), } } /// Same as phase_2_configure_and_expand, but doesn't let you keep the resolver /// around -pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, - cstore: &'a CStore, - krate: ast::Crate, - registry: Option<Registry>, - crate_name: &str, - addl_plugins: Option<Vec<String>>, - make_glob_map: MakeGlobMap, - resolver_arenas: &'a ResolverArenas<'a>, - crate_loader: &'a mut CrateLoader, - after_expand: F) - -> Result<InnerExpansionResult<'a>, CompileIncomplete> - where F: FnOnce(&ast::Crate) -> CompileResult, +pub fn phase_2_configure_and_expand_inner<'a, F>( + sess: &'a Session, + cstore: &'a CStore, + krate: ast::Crate, + registry: Option<Registry>, + crate_name: &str, + addl_plugins: Option<Vec<String>>, + make_glob_map: MakeGlobMap, + resolver_arenas: &'a ResolverArenas<'a>, + crate_loader: &'a mut CrateLoader, + after_expand: F, +) -> Result<InnerExpansionResult<'a>, CompileIncomplete> +where + F: FnOnce(&ast::Crate) -> CompileResult, { - let (mut krate, features) = syntax::config::features(krate, &sess.parse_sess, - sess.opts.test, - sess.opts.debugging_opts.edition); + let (mut krate, features) = syntax::config::features( + krate, + &sess.parse_sess, + sess.opts.test, + sess.edition(), + ); // these need to be set "early" so that expansion sees `quote` if enabled. sess.init_features(features); @@ -657,17 +701,16 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, let disambiguator = compute_crate_disambiguator(sess); sess.crate_disambiguator.set(disambiguator); - rustc_incremental::prepare_session_directory( - sess, - &crate_name, - disambiguator, - ); + rustc_incremental::prepare_session_directory(sess, &crate_name, disambiguator); if sess.opts.incremental.is_some() { time(sess, "garbage collect incremental cache directory", || { if let Err(e) = rustc_incremental::garbage_collect_session_directories(sess) { - warn!("Error while trying to garbage collect incremental \ - compilation cache directory: {}", e); + warn!( + "Error while trying to garbage collect incremental \ + compilation cache directory: {}", + e + ); } }); } @@ -690,23 +733,31 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, let mut addl_plugins = Some(addl_plugins); let registrars = time(sess, "plugin loading", || { - plugin::load::load_plugins(sess, - &cstore, - &krate, - crate_name, - addl_plugins.take().unwrap()) + plugin::load::load_plugins( + sess, + &cstore, + &krate, + crate_name, + addl_plugins.take().unwrap(), + ) }); let mut registry = registry.unwrap_or(Registry::new(sess, krate.span)); time(sess, "plugin registration", || { if sess.features_untracked().rustc_diagnostic_macros { - registry.register_macro("__diagnostic_used", - diagnostics::plugin::expand_diagnostic_used); - registry.register_macro("__register_diagnostic", - diagnostics::plugin::expand_register_diagnostic); - registry.register_macro("__build_diagnostic_array", - diagnostics::plugin::expand_build_diagnostic_array); + registry.register_macro( + "__diagnostic_used", + diagnostics::plugin::expand_diagnostic_used, + ); + registry.register_macro( + "__register_diagnostic", + diagnostics::plugin::expand_register_diagnostic, + ); + registry.register_macro( + "__build_diagnostic_array", + diagnostics::plugin::expand_build_diagnostic_array, + ); } for registrar in registrars { @@ -716,8 +767,15 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, }); let whitelisted_legacy_custom_derives = registry.take_whitelisted_custom_derives(); - let Registry { syntax_exts, early_lint_passes, late_lint_passes, lint_groups, - llvm_passes, attributes, .. } = registry; + let Registry { + syntax_exts, + early_lint_passes, + late_lint_passes, + lint_groups, + llvm_passes, + attributes, + .. + } = registry; sess.track_errors(|| { let mut ls = sess.lint_store.borrow_mut(); @@ -742,16 +800,19 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, return Err(CompileIncomplete::Stopped); } - let mut resolver = Resolver::new(sess, - cstore, - &krate, - crate_name, - make_glob_map, - crate_loader, - &resolver_arenas); + let mut resolver = Resolver::new( + sess, + cstore, + &krate, + crate_name, + make_glob_map, + crate_loader, + &resolver_arenas, + ); resolver.whitelisted_legacy_custom_derives = whitelisted_legacy_custom_derives; syntax_ext::register_builtins(&mut resolver, syntax_exts, sess.features_untracked().quote); + // Expand all macros 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 @@ -769,18 +830,23 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, let mut old_path = OsString::new(); if cfg!(windows) { old_path = env::var_os("PATH").unwrap_or(old_path); - let mut new_path = sess.host_filesearch(PathKind::All) - .get_dylib_search_paths(); + let mut new_path = sess.host_filesearch(PathKind::All).get_dylib_search_paths(); for path in env::split_paths(&old_path) { if !new_path.contains(&path) { new_path.push(path); } } - env::set_var("PATH", - &env::join_paths(new_path.iter() - .filter(|p| env::join_paths(iter::once(p)).is_ok())) - .unwrap()); + env::set_var( + "PATH", + &env::join_paths( + new_path + .iter() + .filter(|p| env::join_paths(iter::once(p)).is_ok()), + ).unwrap(), + ); } + + // Create the config for macro expansion let features = sess.features_untracked(); let cfg = syntax::ext::expand::ExpansionConfig { features: Some(&features), @@ -793,16 +859,23 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, let mut ecx = ExtCtxt::new(&sess.parse_sess, cfg, &mut resolver); let err_count = ecx.parse_sess.span_diagnostic.err_count(); + // Expand macros now! let krate = time(sess, "expand crate", || { ecx.monotonic_expander().expand_crate(krate) }); + // The rest is error reporting + time(sess, "check unused macros", || { ecx.check_unused_macros(); }); - let mut missing_fragment_specifiers: Vec<_> = - ecx.parse_sess.missing_fragment_specifiers.borrow().iter().cloned().collect(); + let mut missing_fragment_specifiers: Vec<_> = ecx.parse_sess + .missing_fragment_specifiers + .borrow() + .iter() + .cloned() + .collect(); missing_fragment_specifiers.sort(); for span in missing_fragment_specifiers { let lint = lint::builtin::MISSING_FRAGMENT_SPECIFIER; @@ -819,12 +892,14 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, }); krate = time(sess, "maybe building test harness", || { - syntax::test::modify_for_testing(&sess.parse_sess, - &mut resolver, - sess.opts.test, - krate, - sess.diagnostic(), - &sess.features_untracked()) + syntax::test::modify_for_testing( + &sess.parse_sess, + &mut resolver, + sess.opts.test, + krate, + sess.diagnostic(), + &sess.features_untracked(), + ) }); // If we're actually rustdoc then there's no need to actually compile @@ -842,21 +917,20 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, let num_crate_types = crate_types.len(); let is_proc_macro_crate = crate_types.contains(&config::CrateTypeProcMacro); let is_test_crate = sess.opts.test; - syntax_ext::proc_macro_registrar::modify(&sess.parse_sess, - &mut resolver, - krate, - is_proc_macro_crate, - is_test_crate, - num_crate_types, - sess.diagnostic()) + syntax_ext::proc_macro_registrar::modify( + &sess.parse_sess, + &mut resolver, + krate, + is_proc_macro_crate, + is_test_crate, + num_crate_types, + sess.diagnostic(), + ) }); } krate = time(sess, "creating allocators", || { - allocator::expand::modify(&sess.parse_sess, - &mut resolver, - krate, - sess.diagnostic()) + allocator::expand::modify(&sess.parse_sess, &mut resolver, krate, sess.diagnostic()) }); after_expand(&krate)?; @@ -873,9 +947,9 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, println!("{}", json::as_json(&krate)); } - time(sess, - "AST validation", - || ast_validation::check_crate(sess, &krate)); + time(sess, "AST validation", || { + ast_validation::check_crate(sess, &krate) + }); time(sess, "name resolution", || -> CompileResult { resolver.resolve_crate(&krate); @@ -885,11 +959,13 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, // Needs to go *after* expansion to be able to check the results of macro expansion. time(sess, "complete gated feature checking", || { sess.track_errors(|| { - syntax::feature_gate::check_crate(&krate, - &sess.parse_sess, - &sess.features_untracked(), - &attributes, - sess.opts.unstable_features); + syntax::feature_gate::check_crate( + &krate, + &sess.parse_sess, + &sess.features_untracked(), + &attributes, + sess.opts.unstable_features, + ); }) })?; @@ -905,11 +981,12 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, None => DepGraph::new_disabled(), Some(future) => { let prev_graph = time(sess, "blocked while dep-graph loading finishes", || { - future.open() - .unwrap_or_else(|e| rustc_incremental::LoadResult::Error { - message: format!("could not decode incremental cache: {:?}", e) - }) - .open(sess) + future + .open() + .unwrap_or_else(|e| rustc_incremental::LoadResult::Error { + message: format!("could not decode incremental cache: {:?}", e), + }) + .open(sess) }); DepGraph::new(prev_graph) } @@ -924,9 +1001,9 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session, hir_map::Forest::new(hir_crate, &dep_graph) }); - time(sess, - "early lint checks", - || lint::check_ast_crate(sess, &krate)); + time(sess, "early lint checks", || { + lint::check_ast_crate(sess, &krate) + }); // Discard hygiene data, which isn't required after lowering to HIR. if !sess.opts.debugging_opts.keep_hygiene_data { @@ -965,39 +1042,43 @@ pub fn default_provide_extern(providers: &mut ty::maps::Providers) { /// Run the resolution, typechecking, region checking and other /// miscellaneous analysis passes on the crate. Return various /// structures carrying the results of the analysis. -pub fn phase_3_run_analysis_passes<'tcx, F, R>(trans: &TransCrate, - control: &CompileController, - sess: &'tcx Session, - cstore: &'tcx CrateStore, - hir_map: hir_map::Map<'tcx>, - mut analysis: ty::CrateAnalysis, - resolutions: Resolutions, - arenas: &'tcx AllArenas<'tcx>, - name: &str, - output_filenames: &OutputFilenames, - f: F) - -> Result<R, CompileIncomplete> - where F: for<'a> FnOnce(TyCtxt<'a, 'tcx, 'tcx>, - ty::CrateAnalysis, - mpsc::Receiver<Box<Any + Send>>, - CompileResult) -> R +pub fn phase_3_run_analysis_passes<'tcx, F, R>( + trans: &TransCrate, + control: &CompileController, + sess: &'tcx Session, + cstore: &'tcx CrateStore, + hir_map: hir_map::Map<'tcx>, + mut analysis: ty::CrateAnalysis, + resolutions: Resolutions, + arenas: &'tcx AllArenas<'tcx>, + name: &str, + output_filenames: &OutputFilenames, + f: F, +) -> Result<R, CompileIncomplete> +where + F: for<'a> FnOnce( + TyCtxt<'a, 'tcx, 'tcx>, + ty::CrateAnalysis, + mpsc::Receiver<Box<Any + Send>>, + CompileResult, + ) -> R, { - let query_result_on_disk_cache = time(sess, - "load query result cache", - || rustc_incremental::load_query_result_cache(sess)); + let query_result_on_disk_cache = time(sess, "load query result cache", || { + rustc_incremental::load_query_result_cache(sess) + }); - time(sess, - "looking for entry point", - || middle::entry::find_entry_point(sess, &hir_map, name)); + time(sess, "looking for entry point", || { + middle::entry::find_entry_point(sess, &hir_map, name) + }); - sess.plugin_registrar_fn.set(time(sess, "looking for plugin registrar", || { - plugin::build::find_plugin_registrar(sess.diagnostic(), &hir_map) - })); - sess.derive_registrar_fn.set(derive_registrar::find(&hir_map)); + sess.plugin_registrar_fn + .set(time(sess, "looking for plugin registrar", || { + plugin::build::find_plugin_registrar(sess.diagnostic(), &hir_map) + })); + sess.derive_registrar_fn + .set(derive_registrar::find(&hir_map)); - time(sess, - "loop checking", - || loops::check_crate(sess, &hir_map)); + time(sess, "loop checking", || loops::check_crate(sess, &hir_map)); let mut local_providers = ty::maps::Providers::default(); default_provide(&mut local_providers); @@ -1011,115 +1092,113 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(trans: &TransCrate, let (tx, rx) = mpsc::channel(); - TyCtxt::create_and_enter(sess, - cstore, - local_providers, - extern_providers, - arenas, - resolutions, - hir_map, - query_result_on_disk_cache, - name, - tx, - output_filenames, - |tcx| { - // Do some initialization of the DepGraph that can only be done with the - // tcx available. - rustc_incremental::dep_graph_tcx_init(tcx); - - time(sess, "attribute checking", || { - hir::check_attr::check_crate(tcx) - }); + TyCtxt::create_and_enter( + sess, + cstore, + local_providers, + extern_providers, + arenas, + resolutions, + hir_map, + query_result_on_disk_cache, + name, + tx, + output_filenames, + |tcx| { + // Do some initialization of the DepGraph that can only be done with the + // tcx available. + rustc_incremental::dep_graph_tcx_init(tcx); + + time(sess, "attribute checking", || { + hir::check_attr::check_crate(tcx) + }); - time(sess, - "stability checking", - || stability::check_unstable_api_usage(tcx)); + time(sess, "stability checking", || { + stability::check_unstable_api_usage(tcx) + }); - // passes are timed inside typeck - match typeck::check_crate(tcx) { - Ok(x) => x, - Err(x) => { - f(tcx, analysis, rx, Err(x)); - return Err(x); + // passes are timed inside typeck + match typeck::check_crate(tcx) { + Ok(x) => x, + Err(x) => { + f(tcx, analysis, rx, Err(x)); + return Err(x); + } } - } - time(sess, - "rvalue promotion", - || rvalue_promotion::check_crate(tcx)); + time(sess, "rvalue promotion", || { + rvalue_promotion::check_crate(tcx) + }); - analysis.access_levels = - time(sess, "privacy checking", || rustc_privacy::check_crate(tcx)); + analysis.access_levels = + time(sess, "privacy checking", || rustc_privacy::check_crate(tcx)); - time(sess, - "intrinsic checking", - || middle::intrinsicck::check_crate(tcx)); + time(sess, "intrinsic checking", || { + middle::intrinsicck::check_crate(tcx) + }); - time(sess, - "match checking", - || mir::matchck_crate(tcx)); + time(sess, "match checking", || mir::matchck_crate(tcx)); - // this must run before MIR dump, because - // "not all control paths return a value" is reported here. - // - // maybe move the check to a MIR pass? - time(sess, - "liveness checking", - || middle::liveness::check_crate(tcx)); - - time(sess, - "borrow checking", - || borrowck::check_crate(tcx)); - - time(sess, - "MIR borrow checking", - || for def_id in tcx.body_owners() { tcx.mir_borrowck(def_id); }); - - time(sess, - "MIR effect checking", - || for def_id in tcx.body_owners() { - mir::transform::check_unsafety::check_unsafety(tcx, def_id) - }); - // Avoid overwhelming user with errors if type checking failed. - // I'm not sure how helpful this is, to be honest, but it avoids - // a - // lot of annoying errors in the compile-fail tests (basically, - // lint warnings and so on -- kindck used to do this abort, but - // kindck is gone now). -nmatsakis - if sess.err_count() > 0 { - return Ok(f(tcx, analysis, rx, sess.compile_status())); - } + // this must run before MIR dump, because + // "not all control paths return a value" is reported here. + // + // maybe move the check to a MIR pass? + time(sess, "liveness checking", || { + middle::liveness::check_crate(tcx) + }); - time(sess, "death checking", || middle::dead::check_crate(tcx)); + time(sess, "borrow checking", || borrowck::check_crate(tcx)); - time(sess, "unused lib feature checking", || { - stability::check_unused_or_stable_features(tcx) - }); + time(sess, "MIR borrow checking", || { + for def_id in tcx.body_owners() { + tcx.mir_borrowck(def_id); + } + }); - time(sess, "lint checking", || lint::check_crate(tcx)); + time(sess, "dumping chalk-like clauses", || { + rustc_traits::lowering::dump_program_clauses(tcx); + }); - time(sess, - "dumping chalk-like clauses", - || rustc_traits::lowering::dump_program_clauses(tcx)); + time(sess, "MIR effect checking", || { + for def_id in tcx.body_owners() { + mir::transform::check_unsafety::check_unsafety(tcx, def_id) + } + }); + // Avoid overwhelming user with errors if type checking failed. + // I'm not sure how helpful this is, to be honest, but it avoids + // a + // lot of annoying errors in the compile-fail tests (basically, + // lint warnings and so on -- kindck used to do this abort, but + // kindck is gone now). -nmatsakis + if sess.err_count() > 0 { + return Ok(f(tcx, analysis, rx, sess.compile_status())); + } - return Ok(f(tcx, analysis, rx, tcx.sess.compile_status())); - }) + time(sess, "death checking", || middle::dead::check_crate(tcx)); + + time(sess, "unused lib feature checking", || { + stability::check_unused_or_stable_features(tcx) + }); + + time(sess, "lint checking", || lint::check_crate(tcx)); + + return Ok(f(tcx, analysis, rx, tcx.sess.compile_status())); + }, + ) } /// Run the translation phase to LLVM, after which the AST and analysis can /// be discarded. -pub fn phase_4_translate_to_llvm<'a, 'tcx>(trans: &TransCrate, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - rx: mpsc::Receiver<Box<Any + Send>>) - -> Box<Any> { - time(tcx.sess, - "resolving dependency formats", - || ::rustc::middle::dependency_format::calculate(tcx)); - - let translation = - time(tcx.sess, "translation", move || { - trans.trans_crate(tcx, rx) - }); +pub fn phase_4_translate_to_llvm<'a, 'tcx>( + trans: &TransCrate, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + rx: mpsc::Receiver<Box<Any + Send>>, +) -> Box<Any> { + time(tcx.sess, "resolving dependency formats", || { + ::rustc::middle::dependency_format::calculate(tcx) + }); + + let translation = time(tcx.sess, "translation", move || trans.trans_crate(tcx, rx)); if tcx.sess.profile_queries() { profile::dump(&tcx.sess, "profile_queries".to_string()) } @@ -1134,27 +1213,27 @@ fn escape_dep_filename(filename: &FileName) -> String { } // Returns all the paths that correspond to generated files. -fn generated_output_paths(sess: &Session, - outputs: &OutputFilenames, - exact_name: bool, - crate_name: &str) -> Vec<PathBuf> { +fn generated_output_paths( + sess: &Session, + outputs: &OutputFilenames, + exact_name: bool, + crate_name: &str, +) -> Vec<PathBuf> { let mut out_filenames = Vec::new(); for output_type in sess.opts.output_types.keys() { let file = outputs.path(*output_type); match *output_type { // If the filename has been overridden using `-o`, it will not be modified // by appending `.rlib`, `.exe`, etc., so we can skip this transformation. - OutputType::Exe if !exact_name => { - for crate_type in sess.crate_types.borrow().iter() { - let p = ::rustc_trans_utils::link::filename_for_input( - sess, - *crate_type, - crate_name, - outputs - ); - out_filenames.push(p); - } - } + OutputType::Exe if !exact_name => for crate_type in sess.crate_types.borrow().iter() { + let p = ::rustc_trans_utils::link::filename_for_input( + sess, + *crate_type, + crate_name, + outputs, + ); + out_filenames.push(p); + }, OutputType::DepInfo if sess.opts.debugging_opts.dep_info_omit_d_target => { // Don't add the dep-info output when omitting it from dep-info targets } @@ -1169,24 +1248,28 @@ fn generated_output_paths(sess: &Session, // Runs `f` on every output file path and returns the first non-None result, or None if `f` // returns None for every file path. fn check_output<F, T>(output_paths: &Vec<PathBuf>, f: F) -> Option<T> - where F: Fn(&PathBuf) -> Option<T> { - for output_path in output_paths { - if let Some(result) = f(output_path) { - return Some(result); - } - } - None +where + F: Fn(&PathBuf) -> Option<T>, +{ + for output_path in output_paths { + if let Some(result) = f(output_path) { + return Some(result); + } + } + None } pub fn output_contains_path(output_paths: &Vec<PathBuf>, input_path: &PathBuf) -> bool { let input_path = input_path.canonicalize().ok(); if input_path.is_none() { - return false + return false; } let check = |output_path: &PathBuf| { if output_path.canonicalize().ok() == input_path { Some(()) - } else { None } + } else { + None + } }; check_output(output_paths, check).is_some() } @@ -1195,100 +1278,92 @@ pub fn output_conflicts_with_dir(output_paths: &Vec<PathBuf>) -> Option<PathBuf> let check = |output_path: &PathBuf| { if output_path.is_dir() { Some(output_path.clone()) - } else { None } + } else { + None + } }; check_output(output_paths, check) } -fn write_out_deps(sess: &Session, - outputs: &OutputFilenames, - out_filenames: &Vec<PathBuf>) { +fn write_out_deps(sess: &Session, outputs: &OutputFilenames, out_filenames: &Vec<PathBuf>) { // Write out dependency rules to the dep-info file if requested if !sess.opts.output_types.contains_key(&OutputType::DepInfo) { return; } let deps_filename = outputs.path(OutputType::DepInfo); - let result = - (|| -> io::Result<()> { - // Build a list of files used to compile the output and - // write Makefile-compatible dependency rules - let files: Vec<String> = sess.codemap() - .files() - .iter() - .filter(|fmap| fmap.is_real_file()) - .filter(|fmap| !fmap.is_imported()) - .map(|fmap| escape_dep_filename(&fmap.name)) - .collect(); - let mut file = fs::File::create(&deps_filename)?; - for path in out_filenames { - write!(file, "{}: {}\n\n", path.display(), files.join(" "))?; - } + let result = (|| -> io::Result<()> { + // Build a list of files used to compile the output and + // write Makefile-compatible dependency rules + let files: Vec<String> = sess.codemap() + .files() + .iter() + .filter(|fmap| fmap.is_real_file()) + .filter(|fmap| !fmap.is_imported()) + .map(|fmap| escape_dep_filename(&fmap.name)) + .collect(); + let mut file = fs::File::create(&deps_filename)?; + for path in out_filenames { + write!(file, "{}: {}\n\n", path.display(), files.join(" "))?; + } - // Emit a fake target for each input file to the compilation. This - // prevents `make` from spitting out an error if a file is later - // deleted. For more info see #28735 - for path in files { - writeln!(file, "{}:", path)?; - } - Ok(()) - })(); + // Emit a fake target for each input file to the compilation. This + // prevents `make` from spitting out an error if a file is later + // deleted. For more info see #28735 + for path in files { + writeln!(file, "{}:", path)?; + } + Ok(()) + })(); match result { Ok(()) => {} Err(e) => { - sess.fatal(&format!("error writing dependencies to `{}`: {}", - deps_filename.display(), - e)); + sess.fatal(&format!( + "error writing dependencies to `{}`: {}", + deps_filename.display(), + e + )); } } } pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec<config::CrateType> { // Unconditionally collect crate types from attributes to make them used - let attr_types: Vec<config::CrateType> = - attrs.iter() - .filter_map(|a| { - if a.check_name("crate_type") { - match a.value_str() { - Some(ref n) if *n == "rlib" => { - Some(config::CrateTypeRlib) - } - Some(ref n) if *n == "dylib" => { - Some(config::CrateTypeDylib) - } - Some(ref n) if *n == "cdylib" => { - Some(config::CrateTypeCdylib) - } - Some(ref n) if *n == "lib" => { - Some(config::default_lib_output()) - } - Some(ref n) if *n == "staticlib" => { - Some(config::CrateTypeStaticlib) - } - Some(ref n) if *n == "proc-macro" => { - Some(config::CrateTypeProcMacro) - } - Some(ref n) if *n == "bin" => Some(config::CrateTypeExecutable), - Some(_) => { - session.buffer_lint(lint::builtin::UNKNOWN_CRATE_TYPES, - ast::CRATE_NODE_ID, - a.span, - "invalid `crate_type` value"); - None - } - _ => { - session.struct_span_err(a.span, "`crate_type` requires a value") - .note("for example: `#![crate_type=\"lib\"]`") - .emit(); - None - } - } - } else { - None - } - }) - .collect(); + let attr_types: Vec<config::CrateType> = attrs + .iter() + .filter_map(|a| { + if a.check_name("crate_type") { + match a.value_str() { + Some(ref n) if *n == "rlib" => Some(config::CrateTypeRlib), + Some(ref n) if *n == "dylib" => Some(config::CrateTypeDylib), + Some(ref n) if *n == "cdylib" => Some(config::CrateTypeCdylib), + Some(ref n) if *n == "lib" => Some(config::default_lib_output()), + Some(ref n) if *n == "staticlib" => Some(config::CrateTypeStaticlib), + Some(ref n) if *n == "proc-macro" => Some(config::CrateTypeProcMacro), + Some(ref n) if *n == "bin" => Some(config::CrateTypeExecutable), + Some(_) => { + session.buffer_lint( + lint::builtin::UNKNOWN_CRATE_TYPES, + ast::CRATE_NODE_ID, + a.span, + "invalid `crate_type` value", + ); + None + } + _ => { + session + .struct_span_err(a.span, "`crate_type` requires a value") + .note("for example: `#![crate_type=\"lib\"]`") + .emit(); + None + } + } + } else { + None + } + }) + .collect(); // If we're generating a test executable, then ignore all other output // styles at all other locations @@ -1303,7 +1378,9 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec<c if base.is_empty() { base.extend(attr_types); if base.is_empty() { - base.push(::rustc_trans_utils::link::default_output_for_target(session)); + base.push(::rustc_trans_utils::link::default_output_for_target( + session, + )); } base.sort(); base.dedup(); @@ -1314,9 +1391,10 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec<c let res = !::rustc_trans_utils::link::invalid_output_for_target(session, *crate_type); if !res { - session.warn(&format!("dropping unsupported crate type `{}` for target `{}`", - *crate_type, - session.opts.target_triple)); + session.warn(&format!( + "dropping unsupported crate type `{}` for target `{}`", + *crate_type, session.opts.target_triple + )); } res @@ -1351,19 +1429,22 @@ pub fn compute_crate_disambiguator(session: &Session) -> CrateDisambiguator { // Also incorporate crate type, so that we don't get symbol conflicts when // linking against a library of the same name, if this is an executable. - let is_exe = session.crate_types.borrow().contains(&config::CrateTypeExecutable); + let is_exe = session + .crate_types + .borrow() + .contains(&config::CrateTypeExecutable); hasher.write(if is_exe { b"exe" } else { b"lib" }); CrateDisambiguator::from(hasher.finish()) - } -pub fn build_output_filenames(input: &Input, - odir: &Option<PathBuf>, - ofile: &Option<PathBuf>, - attrs: &[ast::Attribute], - sess: &Session) - -> OutputFilenames { +pub fn build_output_filenames( + input: &Input, + odir: &Option<PathBuf>, + ofile: &Option<PathBuf>, + attrs: &[ast::Attribute], + sess: &Session, +) -> OutputFilenames { match *ofile { None => { // "-" as input file will cause the parser to read from stdin so we @@ -1376,10 +1457,10 @@ pub fn build_output_filenames(input: &Input, // If a crate name is present, we use it as the link name let stem = sess.opts - .crate_name - .clone() - .or_else(|| attr::find_crate_name(attrs).map(|n| n.to_string())) - .unwrap_or(input.filestem()); + .crate_name + .clone() + .or_else(|| attr::find_crate_name(attrs).map(|n| n.to_string())) + .unwrap_or(input.filestem()); OutputFilenames { out_directory: dirpath, @@ -1392,13 +1473,15 @@ pub fn build_output_filenames(input: &Input, Some(ref out_file) => { let unnamed_output_types = sess.opts - .output_types - .values() - .filter(|a| a.is_none()) - .count(); + .output_types + .values() + .filter(|a| a.is_none()) + .count(); let ofile = if unnamed_output_types > 1 { - sess.warn("due to multiple output types requested, the explicitly specified \ - output file name will be adapted for each output type"); + sess.warn( + "due to multiple output types requested, the explicitly specified \ + output file name will be adapted for each output type", + ); None } else { Some(out_file.clone()) @@ -1414,11 +1497,12 @@ pub fn build_output_filenames(input: &Input, OutputFilenames { out_directory: out_file.parent().unwrap_or(cur_dir).to_path_buf(), - out_filestem: out_file.file_stem() - .unwrap_or(OsStr::new("")) - .to_str() - .unwrap() - .to_string(), + out_filestem: out_file + .file_stem() + .unwrap_or(OsStr::new("")) + .to_str() + .unwrap() + .to_string(), single_output_file: ofile, extra: sess.opts.cg.extra_filename.clone(), outputs: sess.opts.output_types.clone(), diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index fb333ec38fb..3f166daac71 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -35,7 +35,7 @@ extern crate env_logger; extern crate libc; extern crate rustc; extern crate rustc_allocator; -extern crate rustc_back; +extern crate rustc_target; extern crate rustc_borrowck; extern crate rustc_data_structures; extern crate rustc_errors as errors; @@ -1021,7 +1021,7 @@ impl RustcDefaultCalls { for req in &sess.opts.prints { match *req { TargetList => { - let mut targets = rustc_back::target::get_targets().collect::<Vec<String>>(); + let mut targets = rustc_target::spec::get_targets().collect::<Vec<String>>(); targets.sort(); println!("{}", targets.join("\n")); }, @@ -1526,7 +1526,8 @@ pub fn in_rustc_thread<F, R>(f: F) -> Result<R, Box<Any + Send>> let thread = cfg.spawn(f); thread.unwrap().join() } else { - Ok(f()) + let f = panic::AssertUnwindSafe(f); + panic::catch_unwind(f) } } diff --git a/src/librustc_driver/profile/trace.rs b/src/librustc_driver/profile/trace.rs index 280f3c8c796..6426286ccbc 100644 --- a/src/librustc_driver/profile/trace.rs +++ b/src/librustc_driver/profile/trace.rs @@ -10,7 +10,7 @@ use super::*; use syntax_pos::SpanData; -use rustc::ty::maps::QueryMsg; +use rustc::util::common::QueryMsg; use std::fs::File; use std::time::{Duration, Instant}; use std::collections::hash_map::HashMap; diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 5aae895ccc4..d2ee3d8743c 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -28,10 +28,10 @@ use rustc_metadata::cstore::CStore; use rustc::hir::map as hir_map; use rustc::session::{self, config}; use rustc::session::config::{OutputFilenames, OutputTypes}; -use rustc_data_structures::sync::Lrc; +use rustc_data_structures::sync::{self, Lrc}; use syntax; use syntax::ast; -use syntax::abi::Abi; +use rustc_target::spec::abi::Abi; use syntax::codemap::{CodeMap, FilePathMapping, FileName}; use errors; use errors::emitter::Emitter; @@ -88,13 +88,13 @@ impl Emitter for ExpectErrorEmitter { } } -fn errors(msgs: &[&str]) -> (Box<Emitter + Send>, usize) { +fn errors(msgs: &[&str]) -> (Box<Emitter + sync::Send>, usize) { let v = msgs.iter().map(|m| m.to_string()).collect(); - (box ExpectErrorEmitter { messages: v } as Box<Emitter + Send>, msgs.len()) + (box ExpectErrorEmitter { messages: v } as Box<Emitter + sync::Send>, msgs.len()) } fn test_env<F>(source_string: &str, - args: (Box<Emitter + Send>, usize), + args: (Box<Emitter + sync::Send>, usize), body: F) where F: FnOnce(Env) { @@ -104,7 +104,7 @@ fn test_env<F>(source_string: &str, } fn test_env_impl<F>(source_string: &str, - (emitter, expected_err_count): (Box<Emitter + Send>, usize), + (emitter, expected_err_count): (Box<Emitter + sync::Send>, usize), body: F) where F: FnOnce(Env) { @@ -284,7 +284,7 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { } pub fn t_fn(&self, input_tys: &[Ty<'tcx>], output_ty: Ty<'tcx>) -> Ty<'tcx> { - self.infcx.tcx.mk_fn_ptr(ty::Binder(self.infcx.tcx.mk_fn_sig( + self.infcx.tcx.mk_fn_ptr(ty::Binder::bind(self.infcx.tcx.mk_fn_sig( input_tys.iter().cloned(), output_ty, false, @@ -303,11 +303,11 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { pub fn t_param(&self, index: u32) -> Ty<'tcx> { let name = format!("T{}", index); - self.infcx.tcx.mk_param(index, Symbol::intern(&name).as_str()) + self.infcx.tcx.mk_param(index, Symbol::intern(&name).as_interned_str()) } pub fn re_early_bound(&self, index: u32, name: &'static str) -> ty::Region<'tcx> { - let name = Symbol::intern(name).as_str(); + let name = Symbol::intern(name).as_interned_str(); self.infcx.tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion { def_id: self.infcx.tcx.hir.local_def_id(ast::CRATE_NODE_ID), index, diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index 8d5f9ac93f0..ce3efef08cc 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -33,12 +33,12 @@ use self::Level::*; use emitter::{Emitter, EmitterWriter}; -use rustc_data_structures::sync::{self, Lrc}; +use rustc_data_structures::sync::{self, Lrc, Lock, LockCell}; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::stable_hasher::StableHasher; use std::borrow::Cow; -use std::cell::{RefCell, Cell}; +use std::cell::Cell; use std::{error, fmt}; use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering::SeqCst; @@ -262,19 +262,22 @@ pub struct Handler { pub flags: HandlerFlags, err_count: AtomicUsize, - emitter: RefCell<Box<Emitter>>, - continue_after_error: Cell<bool>, - delayed_span_bug: RefCell<Option<Diagnostic>>, + emitter: Lock<Box<Emitter + sync::Send>>, + continue_after_error: LockCell<bool>, + delayed_span_bug: Lock<Option<Diagnostic>>, // This set contains the `DiagnosticId` of all emitted diagnostics to avoid // emitting the same diagnostic with extended help (`--teach`) twice, which // would be uneccessary repetition. - tracked_diagnostic_codes: RefCell<FxHashSet<DiagnosticId>>, + taught_diagnostics: Lock<FxHashSet<DiagnosticId>>, + + /// Used to suggest rustc --explain <error code> + emitted_diagnostic_codes: Lock<FxHashSet<DiagnosticId>>, // This set contains a hash of every diagnostic that has been emitted by // this handler. These hashes is used to avoid emitting the same error // twice. - emitted_diagnostics: RefCell<FxHashSet<u128>>, + emitted_diagnostics: Lock<FxHashSet<u128>>, } fn default_track_diagnostic(_: &Diagnostic) {} @@ -315,7 +318,7 @@ impl Handler { pub fn with_emitter(can_emit_warnings: bool, treat_err_as_bug: bool, - e: Box<Emitter>) + e: Box<Emitter + sync::Send>) -> Handler { Handler::with_emitter_and_flags( e, @@ -326,15 +329,16 @@ impl Handler { }) } - pub fn with_emitter_and_flags(e: Box<Emitter>, flags: HandlerFlags) -> Handler { + pub fn with_emitter_and_flags(e: Box<Emitter + sync::Send>, flags: HandlerFlags) -> Handler { Handler { flags, err_count: AtomicUsize::new(0), - emitter: RefCell::new(e), - continue_after_error: Cell::new(true), - delayed_span_bug: RefCell::new(None), - tracked_diagnostic_codes: RefCell::new(FxHashSet()), - emitted_diagnostics: RefCell::new(FxHashSet()), + emitter: Lock::new(e), + continue_after_error: LockCell::new(true), + delayed_span_bug: Lock::new(None), + taught_diagnostics: Lock::new(FxHashSet()), + emitted_diagnostic_codes: Lock::new(FxHashSet()), + emitted_diagnostics: Lock::new(FxHashSet()), } } @@ -348,7 +352,7 @@ impl Handler { /// tools that want to reuse a `Parser` cleaning the previously emitted diagnostics as well as /// the overall count of emitted error diagnostics. pub fn reset_err_count(&self) { - self.emitted_diagnostics.replace(FxHashSet()); + *self.emitted_diagnostics.borrow_mut() = FxHashSet(); self.err_count.store(0, SeqCst); } @@ -568,10 +572,10 @@ impl Handler { let _ = self.fatal(&s); let can_show_explain = self.emitter.borrow().should_show_explain(); - let are_there_diagnostics = !self.tracked_diagnostic_codes.borrow().is_empty(); + let are_there_diagnostics = !self.emitted_diagnostic_codes.borrow().is_empty(); if can_show_explain && are_there_diagnostics { let mut error_codes = - self.tracked_diagnostic_codes.borrow() + self.emitted_diagnostic_codes.borrow() .clone() .into_iter() .filter_map(|x| match x { @@ -630,12 +634,13 @@ impl Handler { } } - /// `true` if a diagnostic with this code has already been emitted in this handler. + /// `true` if we haven't taught a diagnostic with this code already. + /// The caller must then teach the user about such a diagnostic. /// /// Used to suppress emitting the same error multiple times with extended explanation when /// calling `-Zteach`. - pub fn code_emitted(&self, code: &DiagnosticId) -> bool { - self.tracked_diagnostic_codes.borrow().contains(code) + pub fn must_teach(&self, code: &DiagnosticId) -> bool { + self.taught_diagnostics.borrow_mut().insert(code.clone()) } pub fn force_print_db(&self, mut db: DiagnosticBuilder) { @@ -651,7 +656,7 @@ impl Handler { }); if let Some(ref code) = diagnostic.code { - self.tracked_diagnostic_codes.borrow_mut().insert(code.clone()); + self.emitted_diagnostic_codes.borrow_mut().insert(code.clone()); } let diagnostic_hash = { diff --git a/src/librustc_incremental/assert_module_sources.rs b/src/librustc_incremental/assert_module_sources.rs index 46ba94f2061..6906dacfc5e 100644 --- a/src/librustc_incremental/assert_module_sources.rs +++ b/src/librustc_incremental/assert_module_sources.rs @@ -74,7 +74,7 @@ impl<'a, 'tcx> AssertModuleSource<'a, 'tcx> { let mname = self.field(attr, MODULE); let mangled_cgu_name = CodegenUnit::mangle_name(&mname.as_str()); - let mangled_cgu_name = Symbol::intern(&mangled_cgu_name).as_str(); + let mangled_cgu_name = Symbol::intern(&mangled_cgu_name).as_interned_str(); let dep_node = DepNode::new(self.tcx, DepConstructor::CompileCodegenUnit(mangled_cgu_name)); diff --git a/src/librustc_lint/Cargo.toml b/src/librustc_lint/Cargo.toml index 5ff891202db..f097095abe4 100644 --- a/src/librustc_lint/Cargo.toml +++ b/src/librustc_lint/Cargo.toml @@ -13,5 +13,6 @@ test = false log = "0.4" rustc = { path = "../librustc" } rustc_mir = { path = "../librustc_mir"} +rustc_target = { path = "../librustc_target" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/librustc_lint/bad_style.rs b/src/librustc_lint/bad_style.rs index 463ec4796e8..651a2e187f6 100644 --- a/src/librustc_lint/bad_style.rs +++ b/src/librustc_lint/bad_style.rs @@ -13,7 +13,7 @@ use rustc::ty; use lint::{LateContext, LintContext, LintArray}; use lint::{LintPass, LateLintPass}; -use syntax::abi::Abi; +use rustc_target::spec::abi::Abi; use syntax::ast; use syntax::attr; use syntax_pos::Span; diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 6f2c51b0f18..91ce6f3854a 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -960,7 +960,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion { // Attempt to select a concrete impl before checking. ty::TraitContainer(trait_def_id) => { let trait_ref = ty::TraitRef::from_method(tcx, trait_def_id, callee_substs); - let trait_ref = ty::Binder(trait_ref); + let trait_ref = ty::Binder::bind(trait_ref); let span = tcx.hir.span(expr_id); let obligation = traits::Obligation::new(traits::ObligationCause::misc(span, expr_id), @@ -1169,7 +1169,7 @@ impl LintPass for MutableTransmutes { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MutableTransmutes { fn check_expr(&mut self, cx: &LateContext, expr: &hir::Expr) { - use syntax::abi::Abi::RustIntrinsic; + use rustc_target::spec::abi::Abi::RustIntrinsic; let msg = "mutating transmuted &mut T from &T may cause undefined behavior, \ consider instead using an UnsafeCell"; @@ -1441,3 +1441,71 @@ 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 get_lints(&self) -> LintArray { + lint_array!() + } +} + +fn check_const(cx: &LateContext, body_id: hir::BodyId, what: &str) { + let def_id = cx.tcx.hir.body_owner_def_id(body_id); + let param_env = cx.tcx.param_env(def_id); + let cid = ::rustc::mir::interpret::GlobalId { + instance: ty::Instance::mono(cx.tcx, def_id), + promoted: None + }; + if let Err(err) = cx.tcx.const_eval(param_env.and(cid)) { + let span = cx.tcx.def_span(def_id); + let mut diag = cx.struct_span_lint( + CONST_ERR, + span, + &format!("this {} cannot be used", what), + ); + use rustc::middle::const_val::ConstEvalErrDescription; + match err.description() { + ConstEvalErrDescription::Simple(message) => { + diag.span_label(span, message); + } + ConstEvalErrDescription::Backtrace(miri, frames) => { + diag.span_label(span, format!("{}", miri)); + for frame in frames { + diag.span_label(frame.span, format!("inside call to `{}`", frame.location)); + } + } + } + diag.emit() + } +} + +struct UnusedBrokenConstVisitor<'a, 'tcx: 'a>(&'a LateContext<'a, 'tcx>); + +impl<'a, 'tcx, 'v> hir::intravisit::Visitor<'v> for UnusedBrokenConstVisitor<'a, 'tcx> { + fn visit_nested_body(&mut self, id: hir::BodyId) { + check_const(self.0, id, "array length"); + } + fn nested_visit_map<'this>(&'this mut self) -> hir::intravisit::NestedVisitorMap<'this, 'v> { + hir::intravisit::NestedVisitorMap::None + } +} + +impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedBrokenConst { + fn check_item(&mut self, cx: &LateContext, it: &hir::Item) { + match it.node { + hir::ItemConst(_, body_id) => { + check_const(cx, body_id, "constant"); + }, + hir::ItemTy(ref ty, _) => hir::intravisit::walk_ty( + &mut UnusedBrokenConstVisitor(cx), + ty + ), + _ => {}, + } + } +} diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 16e8600f2d8..65b340d6568 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -37,10 +37,11 @@ extern crate rustc; #[macro_use] extern crate log; extern crate rustc_mir; +extern crate rustc_target; extern crate syntax_pos; use rustc::lint; -use rustc::lint::builtin::BARE_TRAIT_OBJECT; +use rustc::lint::builtin::{BARE_TRAIT_OBJECT, ABSOLUTE_PATH_STARTING_WITH_MODULE}; use rustc::session; use rustc::util; @@ -136,6 +137,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { UnionsWithDropFields, UnreachablePub, TypeAliasBounds, + UnusedBrokenConst, ); add_builtin_with_new!(sess, @@ -278,6 +280,11 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { // Note: this item represents future incompatibility of all unstable functions in the // standard library, and thus should never be removed or changed to an error. }, + FutureIncompatibleInfo { + id: LintId::of(ABSOLUTE_PATH_STARTING_WITH_MODULE), + reference: "issue TBD", + edition: Some(Edition::Edition2018), + }, ]); // Register renamed and removed lints diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 445fe0cc401..904a3e4c427 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -13,7 +13,7 @@ use rustc::hir::map as hir_map; use rustc::ty::subst::Substs; use rustc::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt}; -use rustc::ty::layout::{self, LayoutOf}; +use rustc::ty::layout::{self, IntegerExt, LayoutOf}; use util::nodemap::FxHashSet; use lint::{LateContext, LintContext, LintArray}; use lint::{LintPass, LateLintPass}; @@ -22,7 +22,7 @@ use std::cmp; use std::{i8, i16, i32, i64, u8, u16, u32, u64, f32, f64}; use syntax::{ast, attr}; -use syntax::abi::Abi; +use rustc_target::spec::abi::Abi; use syntax_pos::Span; use syntax::codemap; diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index bf86f6a6952..5ec8305de78 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -91,23 +91,35 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { let def_id = def.def_id(); fn_warned = check_must_use(cx, def_id, s.span, "return value of "); } - - if let hir::ExprBinary(bin_op, ..) = expr.node { - match bin_op.node { - // Hardcoding the comparison operators here seemed more - // expedient than the refactoring that would be needed to - // look up the `#[must_use]` attribute which does exist on - // the comparison trait methods - hir::BiEq | hir::BiLt | hir::BiLe | hir::BiNe | hir::BiGe | hir::BiGt => { - let msg = "unused comparison which must be used"; - cx.span_lint(UNUSED_MUST_USE, expr.span, msg); - op_warned = true; - }, - _ => {}, - } + let must_use_op = match expr.node { + // Hardcoding operators here seemed more expedient than the + // refactoring that would be needed to look up the `#[must_use]` + // attribute which does exist on the comparison trait methods + hir::ExprBinary(bin_op, ..) => { + match bin_op.node { + hir::BiEq | hir::BiLt | hir::BiLe | hir::BiNe | hir::BiGe | hir::BiGt => { + Some("comparison") + }, + hir::BiAdd | hir::BiSub | hir::BiDiv | hir::BiMul | hir::BiRem => { + Some("arithmetic operation") + }, + hir::BiAnd | hir::BiOr => { + Some("logical operation") + }, + hir::BiBitXor | hir::BiBitAnd | hir::BiBitOr | hir::BiShl | hir::BiShr => { + Some("bitwise operation") + }, + } + }, + hir::ExprUnary(..) => Some("unary operation"), + _ => None + }; + if let Some(must_use_op) = must_use_op { + cx.span_lint(UNUSED_MUST_USE, expr.span, + &format!("unused {} which must be used", must_use_op)); + op_warned = true; } } - if !(ty_warned || fn_warned || op_warned) { cx.span_lint(UNUSED_RESULTS, s.span, "unused result"); } diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs index 54e3f544acb..1619637b827 100644 --- a/src/librustc_llvm/build.rs +++ b/src/librustc_llvm/build.rs @@ -28,6 +28,12 @@ fn detect_llvm_link() -> (&'static str, &'static str) { } fn main() { + if env::var_os("RUST_CHECK").is_some() { + // If we're just running `check`, there's no need for LLVM to be built. + println!("cargo:rerun-if-env-changed=RUST_CHECK"); + return; + } + let target = env::var("TARGET").expect("TARGET was not set"); let llvm_config = env::var_os("LLVM_CONFIG") .map(PathBuf::from) diff --git a/src/librustc_metadata/Cargo.toml b/src/librustc_metadata/Cargo.toml index a2dcf7f3f83..338824d5efe 100644 --- a/src/librustc_metadata/Cargo.toml +++ b/src/librustc_metadata/Cargo.toml @@ -13,7 +13,7 @@ flate2 = "1.0" log = "0.4" proc_macro = { path = "../libproc_macro" } rustc = { path = "../librustc" } -rustc_back = { path = "../librustc_back" } +rustc_target = { path = "../librustc_target" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_errors = { path = "../librustc_errors" } serialize = { path = "../libserialize" } diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs deleted file mode 100644 index 71b15643cbc..00000000000 --- a/src/librustc_metadata/astencode.rs +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use rustc::hir::intravisit::{Visitor, NestedVisitorMap}; - -use isolated_encoder::IsolatedEncoder; -use schema::*; - -use rustc::hir; -use rustc::ty::{self, TyCtxt}; - -use rustc::ich::Fingerprint; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; - -#[derive(RustcEncodable, RustcDecodable)] -pub struct Ast<'tcx> { - pub body: Lazy<hir::Body>, - pub tables: Lazy<ty::TypeckTables<'tcx>>, - pub nested_bodies: LazySeq<hir::Body>, - pub rvalue_promotable_to_static: bool, - pub stable_bodies_hash: Fingerprint, -} - -impl_stable_hash_for!(struct Ast<'tcx> { - body, - tables, - nested_bodies, - rvalue_promotable_to_static, - stable_bodies_hash -}); - -impl<'a, 'b, 'tcx> IsolatedEncoder<'a, 'b, 'tcx> { - pub fn encode_body(&mut self, body_id: hir::BodyId) -> Lazy<Ast<'tcx>> { - let body = self.tcx.hir.body(body_id); - - // In order to avoid having to hash hir::Bodies from extern crates, we - // hash them here, during export, and store the hash with metadata. - let stable_bodies_hash = { - let mut hcx = self.tcx.create_stable_hashing_context(); - let mut hasher = StableHasher::new(); - - hcx.while_hashing_hir_bodies(true, |hcx| { - body.hash_stable(hcx, &mut hasher); - }); - - hasher.finish() - }; - - let lazy_body = self.lazy(body); - let body_owner_def_id = self.tcx.hir.body_owner_def_id(body_id); - let tables = self.tcx.typeck_tables_of(body_owner_def_id); - let lazy_tables = self.lazy(tables); - - let mut visitor = NestedBodyCollector { - tcx: self.tcx, - bodies_found: Vec::new(), - }; - visitor.visit_body(body); - let lazy_nested_bodies = self.lazy_seq_ref_from_slice(&visitor.bodies_found); - - let rvalue_promotable_to_static = - self.tcx.const_is_rvalue_promotable_to_static(body_owner_def_id); - - self.lazy(&Ast { - body: lazy_body, - tables: lazy_tables, - nested_bodies: lazy_nested_bodies, - rvalue_promotable_to_static, - stable_bodies_hash, - }) - } -} - -struct NestedBodyCollector<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, - bodies_found: Vec<&'tcx hir::Body>, -} - -impl<'a, 'tcx: 'a> Visitor<'tcx> for NestedBodyCollector<'a, 'tcx> { - fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { - NestedVisitorMap::None - } - - fn visit_nested_body(&mut self, body: hir::BodyId) { - let body = self.tcx.hir.body(body); - self.bodies_found.push(body); - self.visit_body(body); - } -} diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 8a18a4b5290..d0237071a60 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -21,8 +21,7 @@ use rustc::middle::allocator::AllocatorKind; use rustc::middle::cstore::DepKind; use rustc::session::{Session, CrateDisambiguator}; use rustc::session::config::{Sanitizer, self}; -use rustc_back::PanicStrategy; -use rustc_back::target::TargetTriple; +use rustc_target::spec::{PanicStrategy, TargetTriple}; use rustc::session::search_paths::PathKind; use rustc::middle; use rustc::middle::cstore::{validate_crate_name, ExternCrate, ExternCrateSource}; diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index 8765d9d8c2b..64bbcf436cb 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -18,7 +18,7 @@ use rustc::hir::map::definitions::DefPathTable; use rustc::hir::svh::Svh; use rustc::middle::cstore::{DepKind, ExternCrate, MetadataLoader}; use rustc::session::{Session, CrateDisambiguator}; -use rustc_back::PanicStrategy; +use rustc_target::spec::PanicStrategy; use rustc_data_structures::indexed_vec::IndexVec; use rustc::util::nodemap::{FxHashMap, NodeMap}; diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 2c995d2f5cd..fdfe2a98bf9 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -51,7 +51,7 @@ macro_rules! provide { pub fn provide_extern<$lt>(providers: &mut Providers<$lt>) { $(fn $name<'a, $lt:$lt, T>($tcx: TyCtxt<'a, $lt, $lt>, def_id_arg: T) -> <ty::queries::$name<$lt> as - QueryConfig>::Value + QueryConfig<$lt>>::Value where T: IntoArgs, { #[allow(unused_variables)] @@ -142,7 +142,6 @@ provide! { <'tcx> tcx, def_id, other, cdata, mir_const_qualif => { (cdata.mir_const_qualif(def_id.index), Lrc::new(IdxSetBuf::new_empty(0))) } - typeck_tables_of => { cdata.item_body_tables(def_id.index, tcx) } fn_sig => { cdata.fn_sig(def_id.index, tcx) } inherent_impls => { Lrc::new(cdata.get_inherent_implementations_for_type(def_id.index)) } is_const_fn => { cdata.is_const_fn(def_id.index) } @@ -161,9 +160,9 @@ provide! { <'tcx> tcx, def_id, other, cdata, // This is only used by rustdoc anyway, which shouldn't have // incremental recompilation ever enabled. fn_arg_names => { cdata.get_fn_arg_names(def_id.index) } + rendered_const => { cdata.get_rendered_const(def_id.index) } impl_parent => { cdata.get_parent_impl(def_id.index) } trait_of_item => { cdata.get_trait_of_item(def_id.index) } - item_body_nested_bodies => { cdata.item_body_nested_bodies(tcx, def_id.index) } const_is_rvalue_promotable_to_static => { cdata.const_is_rvalue_promotable_to_static(def_id.index) } @@ -243,11 +242,6 @@ provide! { <'tcx> tcx, def_id, other, cdata, defined_lang_items => { Lrc::new(cdata.get_lang_items()) } missing_lang_items => { Lrc::new(cdata.get_missing_lang_items()) } - extern_const_body => { - debug!("item_body({:?}): inlining item", def_id); - cdata.extern_const_body(tcx, def_id.index) - } - missing_extern_crate_item => { let r = match *cdata.extern_crate.borrow() { Some(extern_crate) if !extern_crate.direct => true, @@ -541,7 +535,7 @@ impl CrateStore for cstore::CStore { .insert(local_span, (name.to_string(), data.get_span(id.index, sess))); LoadedMacro::MacroDef(ast::Item { - ident: ast::Ident::from_str(&name), + ident: ast::Ident::from_str(&name.as_str()), id: ast::DUMMY_NODE_ID, span: local_span, attrs: attrs.iter().cloned().collect(), diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 936d680380c..57f92707ccf 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -17,8 +17,7 @@ use rustc_data_structures::sync::{Lrc, ReadGuard}; use rustc::hir::map::{DefKey, DefPath, DefPathData, DefPathHash, DisambiguatedDefPathData}; use rustc::hir; -use rustc::middle::cstore::{LinkagePreference, ExternConstBody, - ExternBodyNestedBodies}; +use rustc::middle::cstore::LinkagePreference; use rustc::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel}; use rustc::hir::def::{self, Def, CtorKind}; use rustc::hir::def_id::{CrateNum, DefId, DefIndex, @@ -33,7 +32,6 @@ use rustc::mir::Mir; use rustc::util::captures::Captures; use rustc::util::nodemap::FxHashMap; -use std::collections::BTreeMap; use std::io; use std::mem; use std::u32; @@ -42,7 +40,7 @@ use rustc_serialize::{Decodable, Decoder, SpecializedDecoder, opaque}; use syntax::attr; use syntax::ast::{self, Ident}; use syntax::codemap; -use syntax::symbol::{InternedString, Symbol}; +use syntax::symbol::InternedString; use syntax::ext::base::MacroKind; use syntax_pos::{self, Span, BytePos, Pos, DUMMY_SP, NO_EXPANSION}; @@ -433,7 +431,7 @@ impl<'a, 'tcx> MetadataBlob { impl<'tcx> EntryKind<'tcx> { fn to_def(&self, did: DefId) -> Option<Def> { Some(match *self { - EntryKind::Const(_) => Def::Const(did), + EntryKind::Const(..) => Def::Const(did), EntryKind::AssociatedConst(..) => Def::AssociatedConst(did), EntryKind::ImmStatic | EntryKind::ForeignImmStatic => Def::Static(did, false), @@ -539,12 +537,12 @@ impl<'a, 'tcx> CrateMetadata { ty::VariantDef { did: self.local_def_id(data.struct_ctor.unwrap_or(index)), - name: Symbol::intern(&self.item_name(index)), + name: self.item_name(index).as_symbol(), fields: item.children.decode(self).map(|index| { let f = self.entry(index); ty::FieldDef { did: self.local_def_id(index), - name: Symbol::intern(&self.item_name(index)), + name: self.item_name(index).as_symbol(), vis: f.visibility.decode(self) } }).collect(), @@ -732,7 +730,7 @@ impl<'a, 'tcx> CrateMetadata { if let Some(def) = self.get_def(child_index) { callback(def::Export { def, - ident: Ident::from_str(&self.item_name(child_index)), + ident: Ident::from_interned_str(self.item_name(child_index)), vis: self.get_visibility(child_index), span: self.entry(child_index).span.decode((self, sess)), is_import: false, @@ -750,7 +748,7 @@ impl<'a, 'tcx> CrateMetadata { let span = child.span.decode((self, sess)); if let (Some(def), Some(name)) = (self.get_def(child_index), def_key.disambiguated_data.data.get_opt_name()) { - let ident = Ident::from_str(&name); + let ident = Ident::from_interned_str(name); let vis = self.get_visibility(child_index); let is_import = false; callback(def::Export { def, ident, vis, span, is_import }); @@ -794,54 +792,12 @@ impl<'a, 'tcx> CrateMetadata { } } - pub fn extern_const_body(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - id: DefIndex) - -> ExternConstBody<'tcx> { - assert!(!self.is_proc_macro(id)); - let ast = self.entry(id).ast.unwrap(); - let def_id = self.local_def_id(id); - let ast = ast.decode((self, tcx)); - let body = ast.body.decode((self, tcx)); - ExternConstBody { - body: tcx.hir.intern_inlined_body(def_id, body), - fingerprint: ast.stable_bodies_hash, - } - } - - pub fn item_body_tables(&self, - id: DefIndex, - tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> &'tcx ty::TypeckTables<'tcx> { - let ast = self.entry(id).ast.unwrap().decode(self); - tcx.alloc_tables(ast.tables.decode((self, tcx))) - } - - pub fn item_body_nested_bodies(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - id: DefIndex) - -> ExternBodyNestedBodies { - if let Some(ref ast) = self.entry(id).ast { - let mut ast = ast.decode(self); - let nested_bodies: BTreeMap<_, _> = ast.nested_bodies - .decode((self, tcx.sess)) - .map(|body| (body.id(), body)) - .collect(); - ExternBodyNestedBodies { - nested_bodies: Lrc::new(nested_bodies), - fingerprint: ast.stable_bodies_hash, - } - } else { - ExternBodyNestedBodies { - nested_bodies: Lrc::new(BTreeMap::new()), - fingerprint: Fingerprint::ZERO, - } - } - } - pub fn const_is_rvalue_promotable_to_static(&self, id: DefIndex) -> bool { - self.entry(id).ast.expect("const item missing `ast`") - .decode(self).rvalue_promotable_to_static + match self.entry(id).kind { + EntryKind::AssociatedConst(_, data, _) | + EntryKind::Const(data, _) => data.ast_promotable, + _ => bug!(), + } } pub fn is_item_mir_available(&self, id: DefIndex) -> bool { @@ -861,10 +817,10 @@ impl<'a, 'tcx> CrateMetadata { pub fn mir_const_qualif(&self, id: DefIndex) -> u8 { match self.entry(id).kind { - EntryKind::Const(qualif) | - EntryKind::AssociatedConst(AssociatedContainer::ImplDefault, qualif) | - EntryKind::AssociatedConst(AssociatedContainer::ImplFinal, qualif) => { - qualif + EntryKind::Const(qualif, _) | + EntryKind::AssociatedConst(AssociatedContainer::ImplDefault, qualif, _) | + EntryKind::AssociatedConst(AssociatedContainer::ImplFinal, qualif, _) => { + qualif.mir } _ => bug!(), } @@ -877,7 +833,7 @@ impl<'a, 'tcx> CrateMetadata { let name = def_key.disambiguated_data.data.get_opt_name().unwrap(); let (kind, container, has_self) = match item.kind { - EntryKind::AssociatedConst(container, _) => { + EntryKind::AssociatedConst(container, _, _) => { (ty::AssociatedKind::Const, container, false) } EntryKind::Method(data) => { @@ -891,7 +847,7 @@ impl<'a, 'tcx> CrateMetadata { }; ty::AssociatedItem { - name: Symbol::intern(&name), + name: name.as_symbol(), kind, vis: item.visibility.decode(self), defaultness: container.defaultness(), @@ -958,7 +914,7 @@ impl<'a, 'tcx> CrateMetadata { self.entry(id) .children .decode(self) - .map(|index| Symbol::intern(&self.item_name(index))) + .map(|index| self.item_name(index).as_symbol()) .collect() } @@ -1021,7 +977,13 @@ impl<'a, 'tcx> CrateMetadata { } pub fn get_trait_of_item(&self, id: DefIndex) -> Option<DefId> { - self.def_key(id).parent.and_then(|parent_index| { + let def_key = self.def_key(id); + match def_key.disambiguated_data.data { + DefPathData::TypeNs(..) | DefPathData::ValueNs(..) => (), + // Not an associated item + _ => return None, + } + def_key.parent.and_then(|parent_index| { match self.entry(parent_index).kind { EntryKind::Trait(_) => Some(self.local_def_id(parent_index)), _ => None, @@ -1076,6 +1038,14 @@ impl<'a, 'tcx> CrateMetadata { lazy_seq.decode((self, tcx)).collect() } + pub fn get_rendered_const(&self, id: DefIndex) -> String { + match self.entry(id).kind { + EntryKind::Const(_, data) | + EntryKind::AssociatedConst(_, _, data) => data.decode(self).0, + _ => bug!(), + } + } + pub fn wasm_custom_sections(&self) -> Vec<DefId> { let sections = self.root .wasm_custom_sections @@ -1142,7 +1112,7 @@ impl<'a, 'tcx> CrateMetadata { DefKey { parent: Some(CRATE_DEF_INDEX), disambiguated_data: DisambiguatedDefPathData { - data: DefPathData::MacroDef(name.as_str()), + data: DefPathData::MacroDef(name.as_interned_str()), disambiguator: 0, } } diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 67c180e94ca..d7a06f7932f 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -622,7 +622,6 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { generics: Some(self.encode_generics(def_id)), predicates: Some(self.encode_predicates(def_id)), - ast: None, mir: self.encode_optimized_mir(def_id), } } @@ -660,7 +659,6 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { generics: None, predicates: None, - ast: None, mir: None } } @@ -701,7 +699,6 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { generics: Some(self.encode_generics(def_id)), predicates: Some(self.encode_predicates(def_id)), - ast: None, mir: None, } } @@ -759,7 +756,6 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { generics: Some(self.encode_generics(def_id)), predicates: Some(self.encode_predicates(def_id)), - ast: None, mir: self.encode_optimized_mir(def_id), } } @@ -795,7 +791,18 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { let kind = match trait_item.kind { ty::AssociatedKind::Const => { - EntryKind::AssociatedConst(container, 0) + let const_qualif = + if let hir::TraitItemKind::Const(_, Some(body)) = ast_item.node { + self.const_qualif(0, body) + } else { + ConstQualif { mir: 0, ast_promotable: false } + }; + + let rendered = + hir::print::to_string(&self.tcx.hir, |s| s.print_trait_item(ast_item)); + let rendered_const = self.lazy(&RenderedConst(rendered)); + + EntryKind::AssociatedConst(container, const_qualif, rendered_const) } ty::AssociatedKind::Method => { let fn_data = if let hir::TraitItemKind::Method(_, ref m) = ast_item.node { @@ -855,11 +862,6 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { generics: Some(self.encode_generics(def_id)), predicates: Some(self.encode_predicates(def_id)), - ast: if let hir::TraitItemKind::Const(_, Some(body)) = ast_item.node { - Some(self.encode_body(body)) - } else { - None - }, mir: self.encode_optimized_mir(def_id), } } @@ -869,6 +871,13 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { !self.tcx.sess.opts.output_types.should_trans() } + fn const_qualif(&self, mir: u8, body_id: hir::BodyId) -> ConstQualif { + let body_owner_def_id = self.tcx.hir.body_owner_def_id(body_id); + let ast_promotable = self.tcx.const_is_rvalue_promotable_to_static(body_owner_def_id); + + ConstQualif { mir, ast_promotable } + } + fn encode_info_for_impl_item(&mut self, def_id: DefId) -> Entry<'tcx> { debug!("IsolatedEncoder::encode_info_for_impl_item({:?})", def_id); let tcx = self.tcx; @@ -886,8 +895,15 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { let kind = match impl_item.kind { ty::AssociatedKind::Const => { - EntryKind::AssociatedConst(container, - self.tcx.at(ast_item.span).mir_const_qualif(def_id).0) + if let hir::ImplItemKind::Const(_, body_id) = ast_item.node { + let mir = self.tcx.at(ast_item.span).mir_const_qualif(def_id).0; + + EntryKind::AssociatedConst(container, + self.const_qualif(mir, body_id), + self.encode_rendered_const_for_body(body_id)) + } else { + bug!() + } } ty::AssociatedKind::Method => { let fn_data = if let hir::ImplItemKind::Method(ref sig, body) = ast_item.node { @@ -908,20 +924,21 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { ty::AssociatedKind::Type => EntryKind::AssociatedType(container) }; - let (ast, mir) = if let hir::ImplItemKind::Const(_, body) = ast_item.node { - (Some(body), true) - } else if let hir::ImplItemKind::Method(ref sig, body) = ast_item.node { - let generics = self.tcx.generics_of(def_id); - let types = generics.parent_types as usize + generics.types.len(); - let needs_inline = (types > 0 || tcx.trans_fn_attrs(def_id).requests_inline()) && - !self.metadata_output_only(); - let is_const_fn = sig.constness == hir::Constness::Const; - let ast = if is_const_fn { Some(body) } else { None }; - let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir; - (ast, needs_inline || is_const_fn || always_encode_mir) - } else { - (None, false) - }; + let mir = + match ast_item.node { + hir::ImplItemKind::Const(..) => true, + hir::ImplItemKind::Method(ref sig, _) => { + let generics = self.tcx.generics_of(def_id); + let types = generics.parent_types as usize + generics.types.len(); + let needs_inline = + (types > 0 || tcx.trans_fn_attrs(def_id).requests_inline()) + && !self.metadata_output_only(); + let is_const_fn = sig.constness == hir::Constness::Const; + let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir; + needs_inline || is_const_fn || always_encode_mir + }, + hir::ImplItemKind::Type(..) => false, + }; Entry { kind, @@ -942,7 +959,6 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { generics: Some(self.encode_generics(def_id)), predicates: Some(self.encode_predicates(def_id)), - ast: ast.map(|body| self.encode_body(body)), mir: if mir { self.encode_optimized_mir(def_id) } else { None }, } } @@ -999,6 +1015,13 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { self.tcx.lookup_deprecation(def_id).map(|depr| self.lazy(&depr)) } + fn encode_rendered_const_for_body(&mut self, body_id: hir::BodyId) -> Lazy<RenderedConst> { + let body = self.tcx.hir.body(body_id); + let rendered = hir::print::to_string(&self.tcx.hir, |s| s.print_expr(&body.value)); + let rendered_const = &RenderedConst(rendered); + self.lazy(rendered_const) + } + fn encode_info_for_item(&mut self, (def_id, item): (DefId, &'tcx hir::Item)) -> Entry<'tcx> { let tcx = self.tcx; @@ -1007,8 +1030,12 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { let kind = match item.node { hir::ItemStatic(_, hir::MutMutable, _) => EntryKind::MutStatic, hir::ItemStatic(_, hir::MutImmutable, _) => EntryKind::ImmStatic, - hir::ItemConst(..) => { - EntryKind::Const(tcx.at(item.span).mir_const_qualif(def_id).0) + hir::ItemConst(_, body_id) => { + let mir = tcx.at(item.span).mir_const_qualif(def_id).0; + EntryKind::Const( + self.const_qualif(mir, body_id), + self.encode_rendered_const_for_body(body_id) + ) } hir::ItemFn(_, _, constness, .., body) => { let data = FnData { @@ -1191,13 +1218,6 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { _ => None, }, - ast: match item.node { - hir::ItemConst(_, body) | - hir::ItemFn(_, _, hir::Constness::Const, _, _, body) => { - Some(self.encode_body(body)) - } - _ => None, - }, mir: match item.node { hir::ItemStatic(..) => { self.encode_optimized_mir(def_id) @@ -1240,7 +1260,6 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { variances: LazySeq::empty(), generics: None, predicates: None, - ast: None, mir: None, } } @@ -1269,7 +1288,6 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { generics: None, predicates: None, - ast: None, mir: None, } } @@ -1292,7 +1310,6 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { generics: Some(self.encode_generics(def_id)), predicates: Some(self.encode_predicates(def_id)), - ast: None, mir: None, } } @@ -1337,7 +1354,6 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { generics: Some(self.encode_generics(def_id)), predicates: None, - ast: None, mir: self.encode_optimized_mir(def_id), } } @@ -1346,10 +1362,12 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { debug!("IsolatedEncoder::encode_info_for_embedded_const({:?})", def_id); let tcx = self.tcx; let id = tcx.hir.as_local_node_id(def_id).unwrap(); - let body = tcx.hir.body_owned_by(id); + let body_id = tcx.hir.body_owned_by(id); + let const_data = self.encode_rendered_const_for_body(body_id); + let mir = tcx.mir_const_qualif(def_id).0; Entry { - kind: EntryKind::Const(tcx.mir_const_qualif(def_id).0), + kind: EntryKind::Const(self.const_qualif(mir, body_id), const_data), visibility: self.lazy(&ty::Visibility::Public), span: self.lazy(&tcx.def_span(def_id)), attributes: LazySeq::empty(), @@ -1363,7 +1381,6 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { generics: Some(self.encode_generics(def_id)), predicates: Some(self.encode_predicates(def_id)), - ast: Some(self.encode_body(body)), mir: self.encode_optimized_mir(def_id), } } @@ -1565,7 +1582,6 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { generics: Some(self.encode_generics(def_id)), predicates: Some(self.encode_predicates(def_id)), - ast: None, mir: None, } } diff --git a/src/librustc_metadata/isolated_encoder.rs b/src/librustc_metadata/isolated_encoder.rs index 689c190966e..88594afa320 100644 --- a/src/librustc_metadata/isolated_encoder.rs +++ b/src/librustc_metadata/isolated_encoder.rs @@ -55,10 +55,4 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { { self.ecx.lazy_seq_ref(slice.iter()) } - - pub fn lazy_seq_ref_from_slice<T>(&mut self, slice: &[&T]) -> LazySeq<T> - where T: Encodable - { - self.ecx.lazy_seq_ref(slice.iter().map(|x| *x)) - } } diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index cbbc9d74228..a99e0a32e66 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -38,13 +38,12 @@ extern crate proc_macro; #[macro_use] extern crate rustc; -extern crate rustc_back; +extern crate rustc_target; #[macro_use] extern crate rustc_data_structures; mod diagnostics; -mod astencode; mod index_builder; mod index; mod encoder; diff --git a/src/librustc_metadata/link_args.rs b/src/librustc_metadata/link_args.rs index 6fafde0d09c..b699885b0eb 100644 --- a/src/librustc_metadata/link_args.rs +++ b/src/librustc_metadata/link_args.rs @@ -11,7 +11,7 @@ use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir; use rustc::ty::TyCtxt; -use syntax::abi::Abi; +use rustc_target::spec::abi::Abi; pub fn collect<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Vec<String> { let mut collector = Collector { diff --git a/src/librustc_metadata/locator.rs b/src/librustc_metadata/locator.rs index f553c55ae56..9b1b48efca5 100644 --- a/src/librustc_metadata/locator.rs +++ b/src/librustc_metadata/locator.rs @@ -236,7 +236,7 @@ use rustc::util::nodemap::FxHashMap; use errors::DiagnosticBuilder; use syntax::symbol::Symbol; use syntax_pos::Span; -use rustc_back::target::{Target, TargetTriple}; +use rustc_target::spec::{Target, TargetTriple}; use std::cmp; use std::collections::HashSet; diff --git a/src/librustc_metadata/native_libs.rs b/src/librustc_metadata/native_libs.rs index 4bb6d8fb87c..70b8c7b11fd 100644 --- a/src/librustc_metadata/native_libs.rs +++ b/src/librustc_metadata/native_libs.rs @@ -14,7 +14,7 @@ use rustc::middle::cstore::{self, NativeLibrary}; use rustc::session::Session; use rustc::ty::TyCtxt; use rustc::util::nodemap::FxHashSet; -use syntax::abi::Abi; +use rustc_target::spec::abi::Abi; use syntax::attr; use syntax::codemap::Span; use syntax::feature_gate::{self, GateIssue}; diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index 23ea5e4cc55..c9949389ace 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use astencode; use index; use rustc::hir; @@ -20,8 +19,7 @@ use rustc::middle::lang_items; use rustc::mir; use rustc::session::CrateDisambiguator; use rustc::ty::{self, Ty, ReprOptions}; -use rustc_back::PanicStrategy; -use rustc_back::target::TargetTriple; +use rustc_target::spec::{PanicStrategy, TargetTriple}; use rustc_serialize as serialize; use syntax::{ast, attr}; @@ -266,7 +264,6 @@ pub struct Entry<'tcx> { pub generics: Option<Lazy<ty::Generics>>, pub predicates: Option<Lazy<ty::GenericPredicates<'tcx>>>, - pub ast: Option<Lazy<astencode::Ast<'tcx>>>, pub mir: Option<Lazy<mir::Mir<'tcx>>>, } @@ -283,13 +280,12 @@ impl_stable_hash_for!(struct Entry<'tcx> { variances, generics, predicates, - ast, mir }); #[derive(Copy, Clone, RustcEncodable, RustcDecodable)] pub enum EntryKind<'tcx> { - Const(u8), + Const(ConstQualif, Lazy<RenderedConst>), ImmStatic, MutStatic, ForeignImmStatic, @@ -313,7 +309,7 @@ pub enum EntryKind<'tcx> { Impl(Lazy<ImplData<'tcx>>), Method(Lazy<MethodData<'tcx>>), AssociatedType(AssociatedContainer), - AssociatedConst(AssociatedContainer, u8), + AssociatedConst(AssociatedContainer, ConstQualif, Lazy<RenderedConst>), } impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for EntryKind<'gcx> { @@ -333,8 +329,9 @@ impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for EntryKind<'gcx> { EntryKind::Type => { // Nothing else to hash here. } - EntryKind::Const(qualif) => { + EntryKind::Const(qualif, ref const_data) => { qualif.hash_stable(hcx, hasher); + const_data.hash_stable(hcx, hasher); } EntryKind::Enum(ref repr_options) => { repr_options.hash_stable(hcx, hasher); @@ -375,14 +372,38 @@ impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for EntryKind<'gcx> { EntryKind::AssociatedType(associated_container) => { associated_container.hash_stable(hcx, hasher); } - EntryKind::AssociatedConst(associated_container, qualif) => { + EntryKind::AssociatedConst(associated_container, qualif, ref const_data) => { associated_container.hash_stable(hcx, hasher); qualif.hash_stable(hcx, hasher); + const_data.hash_stable(hcx, hasher); } } } } +/// Additional data for EntryKind::Const and EntryKind::AssociatedConst +#[derive(Clone, Copy, RustcEncodable, RustcDecodable)] +pub struct ConstQualif { + pub mir: u8, + pub ast_promotable: bool, +} + +impl_stable_hash_for!(struct ConstQualif { mir, ast_promotable }); + +/// Contains a constant which has been rendered to a String. +/// Used by rustdoc. +#[derive(RustcEncodable, RustcDecodable)] +pub struct RenderedConst(pub String); + +impl<'a> HashStable<StableHashingContext<'a>> for RenderedConst { + #[inline] + fn hash_stable<W: StableHasherResult>(&self, + hcx: &mut StableHashingContext<'a>, + hasher: &mut StableHasher<W>) { + self.0.hash_stable(hcx, hasher); + } +} + #[derive(RustcEncodable, RustcDecodable)] pub struct ModData { pub reexports: LazySeq<def::Export>, diff --git a/src/librustc_mir/Cargo.toml b/src/librustc_mir/Cargo.toml index 90a0f18aba3..a1b348774b1 100644 --- a/src/librustc_mir/Cargo.toml +++ b/src/librustc_mir/Cargo.toml @@ -15,7 +15,7 @@ graphviz = { path = "../libgraphviz" } log = "0.4" log_settings = "0.1.1" rustc = { path = "../librustc" } -rustc_back = { path = "../librustc_back" } +rustc_target = { path = "../librustc_target" } rustc_const_math = { path = "../librustc_const_math" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_errors = { path = "../librustc_errors" } diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 4dd8d245d3b..3145be7df85 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -17,15 +17,17 @@ use rustc::hir::map::definitions::DefPathData; use rustc::infer::InferCtxt; use rustc::ty::{self, ParamEnv, TyCtxt}; use rustc::ty::maps::Providers; -use rustc::mir::{AssertMessage, BasicBlock, BorrowKind, Location, Place}; -use rustc::mir::{Mir, Mutability, Operand, Projection, ProjectionElem, Rvalue}; -use rustc::mir::{Field, Statement, StatementKind, Terminator, TerminatorKind}; -use rustc::mir::ClosureRegionRequirements; +use rustc::lint::builtin::UNUSED_MUT; +use rustc::mir::{AssertMessage, AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind}; +use rustc::mir::{ClearCrossCrate, Local, Location, Place, Mir, Mutability, Operand}; +use rustc::mir::{Projection, ProjectionElem, Rvalue, Field, Statement, StatementKind}; +use rustc::mir::{Terminator, TerminatorKind}; use rustc_data_structures::control_flow_graph::dominators::Dominators; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::indexed_set::IdxSetBuf; use rustc_data_structures::indexed_vec::Idx; +use rustc_data_structures::small_vec::SmallVec; use std::rc::Rc; @@ -69,12 +71,15 @@ pub fn provide(providers: &mut Providers) { fn mir_borrowck<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId, -) -> Option<ClosureRegionRequirements<'tcx>> { +) -> BorrowCheckResult<'tcx> { let input_mir = tcx.mir_validated(def_id); debug!("run query mir_borrowck: {}", tcx.item_path_str(def_id)); if !tcx.has_attr(def_id, "rustc_mir_borrowck") && !tcx.use_mir_borrowck() { - return None; + return BorrowCheckResult { + closure_requirements: None, + used_mut_upvars: SmallVec::new(), + }; } let opt_closure_req = tcx.infer_ctxt().enter(|infcx| { @@ -90,7 +95,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>( infcx: &InferCtxt<'a, 'gcx, 'tcx>, input_mir: &Mir<'gcx>, def_id: DefId, -) -> Option<ClosureRegionRequirements<'gcx>> { +) -> BorrowCheckResult<'gcx> { let tcx = infcx.tcx; let attributes = tcx.get_attrs(def_id); let param_env = tcx.param_env(def_id); @@ -237,6 +242,8 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>( reservation_error_reported: FxHashSet(), moved_error_reported: FxHashSet(), nonlexical_regioncx: regioncx, + used_mut: FxHashSet(), + used_mut_upvars: SmallVec::new(), nonlexical_cause_info: None, borrow_set, dominators, @@ -252,7 +259,66 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>( mbcx.analyze_results(&mut state); // entry point for DataflowResultsConsumer - opt_closure_req + // 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 + // would have a chance of erroneously adding non-user-defined mutable vars + // to the set. + let temporary_used_locals: FxHashSet<Local> = + mbcx.used_mut.iter() + .filter(|&local| !mbcx.mir.local_decls[*local].is_user_variable) + .cloned() + .collect(); + + for local in temporary_used_locals { + for location in mbcx.mir.find_assignments(local) { + for moi in &mbcx.move_data.loc_map[location] { + let mpi = &mbcx.move_data.moves[*moi].path; + let path = &mbcx.move_data.move_paths[*mpi]; + debug!("assignment of {:?} to {:?}, adding {:?} to used mutable set", + path.place, local, path.place); + if let Place::Local(user_local) = path.place { + mbcx.used_mut.insert(user_local); + } + } + } + } + + debug!("mbcx.used_mut: {:?}", mbcx.used_mut); + + for local in mbcx.mir.mut_vars_and_args_iter().filter(|local| !mbcx.used_mut.contains(local)) { + if let ClearCrossCrate::Set(ref vsi) = mbcx.mir.visibility_scope_info { + let local_decl = &mbcx.mir.local_decls[local]; + + // Skip implicit `self` argument for closures + if local.index() == 1 && tcx.is_closure(mbcx.mir_def_id) { + continue; + } + + // Skip over locals that begin with an underscore + match local_decl.name { + Some(name) if name.as_str().starts_with("_") => continue, + _ => {}, + } + + let source_info = local_decl.source_info; + let mut_span = tcx.sess.codemap().span_until_non_whitespace(source_info.span); + + tcx.struct_span_lint_node( + UNUSED_MUT, + vsi[local_decl.syntactic_scope].lint_root, + source_info.span, + "variable does not need to be mutable" + ) + .span_suggestion_short(mut_span, "remove this `mut`", "".to_owned()) + .emit(); + } + } + + BorrowCheckResult { + closure_requirements: opt_closure_req, + used_mut_upvars: mbcx.used_mut_upvars, + } } #[allow(dead_code)] @@ -287,6 +353,12 @@ pub struct MirBorrowckCtxt<'cx, 'gcx: 'tcx, 'tcx: 'cx> { /// This field keeps track of errors reported in the checking of moved variables, /// so that we don't report report seemingly duplicate errors. moved_error_reported: FxHashSet<Place<'tcx>>, + /// This field keeps track of all the local variables that are declared mut and are mutated. + /// Used for the warning issued by an unused mutable local variable. + used_mut: FxHashSet<Local>, + /// If the function we're checking is a closure, then we'll need to report back the list of + /// mutable upvars that have been used. This field keeps track of them. + used_mut_upvars: SmallVec<[Field; 8]>, /// Non-lexical region inference context, if NLL is enabled. This /// contains the results from region inference and lets us e.g. /// find out which CFG points are contained in each borrow region. @@ -684,6 +756,11 @@ enum InitializationRequiringAction { Assignment, } +struct RootPlace<'d, 'tcx: 'd> { + place: &'d Place<'tcx>, + is_local_mutation_allowed: LocalMutationIsAllowed, +} + impl InitializationRequiringAction { fn as_noun(self) -> &'static str { match self { @@ -729,6 +806,17 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { erased_drop_place_ty: ty::Ty<'gcx>, span: Span, ) { + let gcx = self.tcx.global_tcx(); + let drop_field = | + mir: &mut MirBorrowckCtxt<'cx, 'gcx, 'tcx>, + (index, field): (usize, ty::Ty<'gcx>), + | { + let field_ty = gcx.normalize_erasing_regions(mir.param_env, field); + let place = drop_place.clone().field(Field::new(index), field_ty); + + mir.visit_terminator_drop(loc, term, flow_state, &place, field_ty, span); + }; + match erased_drop_place_ty.sty { // When a struct is being dropped, we need to check // whether it has a destructor, if it does, then we can @@ -737,14 +825,24 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // destructor but `bar` does not, we will only check for // borrows of `x.foo` and not `x.bar`. See #47703. ty::TyAdt(def, substs) if def.is_struct() && !def.has_dtor(self.tcx) => { - for (index, field) in def.all_fields().enumerate() { - let gcx = self.tcx.global_tcx(); - let field_ty = field.ty(gcx, substs); - let field_ty = gcx.normalize_erasing_regions(self.param_env, field_ty); - let place = drop_place.clone().field(Field::new(index), field_ty); - - self.visit_terminator_drop(loc, term, flow_state, &place, field_ty, span); - } + def.all_fields() + .map(|field| field.ty(gcx, substs)) + .enumerate() + .for_each(|field| drop_field(self, field)); + } + // Same as above, but for tuples. + ty::TyTuple(tys) => { + tys.iter().cloned().enumerate() + .for_each(|field| drop_field(self, field)); + } + // Closures and generators also have disjoint fields, but they are only + // directly accessed in the body of the closure/generator. + ty::TyClosure(def, substs) + | ty::TyGenerator(def, substs, ..) + if *drop_place == Place::Local(Local::new(1)) && !self.mir.upvar_decls.is_empty() + => { + substs.upvar_tys(def, self.tcx).enumerate() + .for_each(|field| drop_field(self, field)); } _ => { // We have now refined the type of the value being @@ -752,7 +850,6 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // subfield; so check whether that field's type still // "needs drop". If so, we assume that the destructor // may access any data it likes (i.e., a Deep Write). - let gcx = self.tcx.global_tcx(); if erased_drop_place_ty.needs_drop(gcx, self.param_env) { self.access_place( ContextKind::Drop.new(loc), @@ -810,7 +907,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } let mutability_error = - self.check_access_permissions(place_span, rw, is_local_mutation_allowed); + self.check_access_permissions(place_span, rw, is_local_mutation_allowed, flow_state); let conflict_error = self.check_access_for_conflict(context, place_span, sd, rw, flow_state); @@ -1077,9 +1174,34 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // `NullOp::Box`? } - Rvalue::Aggregate(ref _aggregate_kind, ref operands) => for operand in operands { - self.consume_operand(context, (operand, span), flow_state); - }, + Rvalue::Aggregate(ref aggregate_kind, ref operands) => { + // We need to report back the list of mutable upvars that were + // moved into the closure and subsequently used by the closure, + // in order to populate our used_mut set. + if let AggregateKind::Closure(def_id, _) = &**aggregate_kind { + let BorrowCheckResult { used_mut_upvars, .. } = self.tcx.mir_borrowck(*def_id); + debug!("{:?} used_mut_upvars={:?}", def_id, used_mut_upvars); + for field in used_mut_upvars { + match operands[field.index()] { + Operand::Move(Place::Local(local)) => { + self.used_mut.insert(local); + } + Operand::Move(ref place @ Place::Projection(_)) => { + if let Some(field) = self.is_upvar_field_projection(place) { + self.used_mut_upvars.push(field); + } + } + Operand::Move(Place::Static(..)) | + Operand::Copy(..) | + Operand::Constant(..) => {} + } + } + } + + for operand in operands { + self.consume_operand(context, (operand, span), flow_state); + } + } } } @@ -1280,7 +1402,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { ) { debug!("check_if_reassignment_to_immutable_state({:?})", place); // determine if this path has a non-mut owner (and thus needs checking). - if let Ok(()) = self.is_mutable(place, LocalMutationIsAllowed::No) { + if let Ok(..) = self.is_mutable(place, LocalMutationIsAllowed::No) { return; } debug!( @@ -1574,10 +1696,11 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { /// /// Returns true if an error is reported, false otherwise. fn check_access_permissions( - &self, + &mut self, (place, span): (&Place<'tcx>, Span), kind: ReadOrWrite, is_local_mutation_allowed: LocalMutationIsAllowed, + flow_state: &Flows<'cx, 'gcx, 'tcx>, ) -> bool { debug!( "check_access_permissions({:?}, {:?}, {:?})", @@ -1592,90 +1715,93 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } } Reservation(WriteKind::MutableBorrow(BorrowKind::Mut { .. })) - | Write(WriteKind::MutableBorrow(BorrowKind::Mut { .. })) => if let Err(place_err) = - self.is_mutable(place, is_local_mutation_allowed) - { - error_reported = true; - let item_msg = self.get_default_err_msg(place); - let mut err = self.tcx - .cannot_borrow_path_as_mutable(span, &item_msg, Origin::Mir); - err.span_label(span, "cannot borrow as mutable"); - - if place != place_err { - if let Some(name) = self.describe_place(place_err) { - err.note(&format!("the value which is causing this path not to be mutable \ - is...: `{}`", name)); - } - } - - err.emit(); - }, - Reservation(WriteKind::Mutate) | Write(WriteKind::Mutate) => { + | Write(WriteKind::MutableBorrow(BorrowKind::Mut { .. })) => { + match self.is_mutable(place, is_local_mutation_allowed) { + Ok(root_place) => self.add_used_mut(root_place, flow_state), + Err(place_err) => { + error_reported = true; + let item_msg = self.get_default_err_msg(place); + let mut err = self.tcx + .cannot_borrow_path_as_mutable(span, &item_msg, Origin::Mir); + err.span_label(span, "cannot borrow as mutable"); - if let Err(place_err) = self.is_mutable(place, is_local_mutation_allowed) { - error_reported = true; - let mut err_info = None; - match *place_err { - - Place::Projection(box Projection { - ref base, elem:ProjectionElem::Deref}) => { - match *base { - Place::Local(local) => { - let locations = self.mir.find_assignments(local); - if locations.len() > 0 { - let item_msg = if error_reported { - self.get_secondary_err_msg(base) - } else { - self.get_default_err_msg(place) - }; - let sp = self.mir.source_info(locations[0]).span; - let mut to_suggest_span = String::new(); - if let Ok(src) = - self.tcx.sess.codemap().span_to_snippet(sp) { - to_suggest_span = src[1..].to_string(); - }; - err_info = Some(( - sp, - "consider changing this to be a \ - mutable reference", - to_suggest_span, - item_msg, - self.get_primary_err_msg(base))); - } - }, - _ => {}, - } - }, - _ => {}, - } - - if let Some((err_help_span, - err_help_stmt, - to_suggest_span, - item_msg, - sec_span)) = err_info { - let mut err = self.tcx.cannot_assign(span, &item_msg, Origin::Mir); - err.span_suggestion(err_help_span, - err_help_stmt, - format!("&mut {}", to_suggest_span)); - if place != place_err { - err.span_label(span, sec_span); - } - err.emit() - } else { - let item_msg_ = self.get_default_err_msg(place); - let mut err = self.tcx.cannot_assign(span, &item_msg_, Origin::Mir); - err.span_label(span, "cannot mutate"); if place != place_err { if let Some(name) = self.describe_place(place_err) { err.note(&format!("the value which is causing this path not to be \ - mutable is...: `{}`", name)); + mutable is...: `{}`", name)); } } + err.emit(); } } } + Reservation(WriteKind::Mutate) | Write(WriteKind::Mutate) => { + match self.is_mutable(place, is_local_mutation_allowed) { + Ok(root_place) => self.add_used_mut(root_place, flow_state), + Err(place_err) => { + error_reported = true; + + let err_info = if let Place::Projection( + box Projection { + base: Place::Local(local), + elem: ProjectionElem::Deref + } + ) = *place_err { + let locations = self.mir.find_assignments(local); + if locations.len() > 0 { + let item_msg = if error_reported { + self.get_secondary_err_msg(&Place::Local(local)) + } else { + self.get_default_err_msg(place) + }; + let sp = self.mir.source_info(locations[0]).span; + let mut to_suggest_span = String::new(); + if let Ok(src) = + self.tcx.sess.codemap().span_to_snippet(sp) { + to_suggest_span = src[1..].to_string(); + }; + Some((sp, + "consider changing this to be a \ + mutable reference", + to_suggest_span, + item_msg, + self.get_primary_err_msg(&Place::Local(local)))) + } else { + None + } + } else { + None + }; + + if let Some((err_help_span, + err_help_stmt, + to_suggest_span, + item_msg, + sec_span)) = err_info { + let mut err = self.tcx.cannot_assign(span, &item_msg, Origin::Mir); + err.span_suggestion(err_help_span, + err_help_stmt, + format!("&mut {}", to_suggest_span)); + if place != place_err { + err.span_label(span, sec_span); + } + err.emit() + } else { + let item_msg = self.get_default_err_msg(place); + let mut err = self.tcx.cannot_assign(span, &item_msg, Origin::Mir); + err.span_label(span, "cannot mutate"); + if place != place_err { + if let Some(name) = self.describe_place(place_err) { + err.note(&format!("the value which is causing this path not \ + to be mutable is...: `{}`", name)); + } + } + err.emit(); + } + } + } + } Reservation(WriteKind::Move) | Reservation(WriteKind::StorageDeadOrDrop) | Reservation(WriteKind::MutableBorrow(BorrowKind::Shared)) @@ -1702,30 +1828,76 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { error_reported } - /// Can this value be written or borrowed mutably + /// Adds the place into the used mutable variables set + fn add_used_mut<'d>( + &mut self, + root_place: RootPlace<'d, 'tcx>, + flow_state: &Flows<'cx, 'gcx, 'tcx> + ) { + match root_place { + RootPlace { + place: Place::Local(local), + is_local_mutation_allowed, + } => { + if is_local_mutation_allowed != LocalMutationIsAllowed::Yes { + // If the local may be initialized, and it is now currently being + // mutated, then it is justified to be annotated with the `mut` + // keyword, since the mutation may be a possible reassignment. + let mpi = self.move_data.rev_lookup.find_local(*local); + if flow_state.inits.contains(&mpi) { + self.used_mut.insert(*local); + } + } + } + RootPlace { + place: place @ Place::Projection(_), + is_local_mutation_allowed: _, + } => { + if let Some(field) = self.is_upvar_field_projection(&place) { + self.used_mut_upvars.push(field); + } + } + RootPlace { + place: Place::Static(..), + is_local_mutation_allowed: _, + } => {} + } + } + + /// Whether this value be written or borrowed mutably. + /// Returns the root place if the place passed in is a projection. fn is_mutable<'d>( &self, place: &'d Place<'tcx>, is_local_mutation_allowed: LocalMutationIsAllowed, - ) -> Result<(), &'d Place<'tcx>> { + ) -> Result<RootPlace<'d, 'tcx>, &'d Place<'tcx>> { match *place { Place::Local(local) => { let local = &self.mir.local_decls[local]; match local.mutability { Mutability::Not => match is_local_mutation_allowed { - LocalMutationIsAllowed::Yes | LocalMutationIsAllowed::ExceptUpvars => { - Ok(()) + LocalMutationIsAllowed::Yes => { + Ok(RootPlace { + place, + is_local_mutation_allowed: LocalMutationIsAllowed::Yes + }) + } + LocalMutationIsAllowed::ExceptUpvars => { + Ok(RootPlace { + place, + is_local_mutation_allowed: LocalMutationIsAllowed::ExceptUpvars + }) } LocalMutationIsAllowed::No => Err(place), }, - Mutability::Mut => Ok(()), + Mutability::Mut => Ok(RootPlace { place, is_local_mutation_allowed }), } } Place::Static(ref static_) => if self.tcx.is_static(static_.def_id) != Some(hir::Mutability::MutMutable) { Err(place) } else { - Ok(()) + Ok(RootPlace { place, is_local_mutation_allowed }) }, Place::Projection(ref proj) => { match proj.elem { @@ -1761,9 +1933,11 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { match tnm.mutbl { // `*const` raw pointers are not mutable hir::MutImmutable => return Err(place), - // `*mut` raw pointers are always mutable, regardless of context - // The users have to check by themselve. - hir::MutMutable => return Ok(()), + // `*mut` raw pointers are always mutable, regardless of + // context. The users have to check by themselves. + hir::MutMutable => { + return Ok(RootPlace { place, is_local_mutation_allowed }); + } } } // `Box<T>` owns its content, so mutable if its location is mutable @@ -1794,7 +1968,34 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } (Mutability::Not, LocalMutationIsAllowed::Yes) | (Mutability::Mut, _) => { - self.is_mutable(&proj.base, is_local_mutation_allowed) + // Subtle: this is an upvar + // reference, so it looks like + // `self.foo` -- we want to double + // check that the context `*self` + // is mutable (i.e., this is not a + // `Fn` closure). But if that + // check succeeds, we want to + // *blame* the mutability on + // `place` (that is, + // `self.foo`). This is used to + // propagate the info about + // whether mutability declarations + // are used outwards, so that we register + // the outer variable as mutable. Otherwise a + // test like this fails to record the `mut` + // as needed: + // + // ``` + // fn foo<F: FnOnce()>(_f: F) { } + // fn main() { + // let var = Vec::new(); + // foo(move || { + // var.push(1); + // }); + // } + // ``` + let _ = self.is_mutable(&proj.base, is_local_mutation_allowed)?; + Ok(RootPlace { place, is_local_mutation_allowed }) } } } else { diff --git a/src/librustc_mir/borrow_check/nll/region_infer/values.rs b/src/librustc_mir/borrow_check/nll/region_infer/values.rs index 2f0b4c24bd6..d15d85792d9 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/values.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/values.rs @@ -14,7 +14,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::indexed_vec::Idx; use rustc_data_structures::indexed_vec::IndexVec; use rustc::mir::{BasicBlock, Location, Mir}; -use rustc::ty::RegionVid; +use rustc::ty::{self, RegionVid}; use syntax::codemap::Span; use super::{Cause, CauseExt, TrackCauses}; @@ -263,7 +263,17 @@ impl RegionValues { if let Some(causes) = &mut self.causes { let cause = make_cause(causes); let old_cause = causes.get_mut(&(r, i)).unwrap(); - if cause < **old_cause { + // #49998: compare using root cause alone to avoid + // useless traffic from similar outlives chains. + + let overwrite = if ty::tls::with(|tcx| { + tcx.sess.opts.debugging_opts.nll_subminimal_causes + }) { + cause.root_cause() < old_cause.root_cause() + } else { + cause < **old_cause + }; + if overwrite { *old_cause = Rc::new(cause); return true; } 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 acd246b7031..a811b2c147e 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -275,7 +275,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { tcx.predicates_of(def_id).instantiate(tcx, substs); let predicates = type_checker.normalize(&instantiated_predicates.predicates, location); - type_checker.prove_predicates(predicates.iter().cloned(), location); + type_checker.prove_predicates(predicates, location); } value.ty @@ -918,11 +918,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { )); } - if self.is_box_free(func) { - self.check_box_free_inputs(mir, term, &sig, args, term_location); - } else { - self.check_call_inputs(mir, term, &sig, args, term_location); - } + self.check_call_inputs(mir, term, &sig, args, term_location); } TerminatorKind::Assert { ref cond, ref msg, .. @@ -1026,70 +1022,6 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } } - fn is_box_free(&self, operand: &Operand<'tcx>) -> bool { - match *operand { - Operand::Constant(ref c) => match c.ty.sty { - ty::TyFnDef(ty_def_id, _) => { - Some(ty_def_id) == self.tcx().lang_items().box_free_fn() - } - _ => false, - }, - _ => false, - } - } - - fn check_box_free_inputs( - &mut self, - mir: &Mir<'tcx>, - term: &Terminator<'tcx>, - sig: &ty::FnSig<'tcx>, - args: &[Operand<'tcx>], - term_location: Location, - ) { - debug!("check_box_free_inputs"); - - // box_free takes a Box as a pointer. Allow for that. - - if sig.inputs().len() != 1 { - span_mirbug!(self, term, "box_free should take 1 argument"); - return; - } - - let pointee_ty = match sig.inputs()[0].sty { - ty::TyRawPtr(mt) => mt.ty, - _ => { - span_mirbug!(self, term, "box_free should take a raw ptr"); - return; - } - }; - - if args.len() != 1 { - span_mirbug!(self, term, "box_free called with wrong # of args"); - return; - } - - let ty = args[0].ty(mir, self.tcx()); - let arg_ty = match ty.sty { - ty::TyRawPtr(mt) => mt.ty, - ty::TyAdt(def, _) if def.is_box() => ty.boxed_ty(), - _ => { - span_mirbug!(self, term, "box_free called with bad arg ty"); - return; - } - }; - - if let Err(terr) = self.sub_types(arg_ty, pointee_ty, term_location.at_self()) { - span_mirbug!( - self, - term, - "bad box_free arg ({:?} <- {:?}): {:?}", - pointee_ty, - arg_ty, - terr - ); - } - } - fn check_iscleanup(&mut self, mir: &Mir<'tcx>, block_data: &BasicBlockData<'tcx>) { let is_cleanup = block_data.is_cleanup; self.last_span = block_data.terminator().source_info.span; @@ -1494,7 +1426,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { // these extra requirements are basically like where // clauses on the struct. AggregateKind::Closure(def_id, substs) => { - if let Some(closure_region_requirements) = tcx.mir_borrowck(*def_id) { + if let Some(closure_region_requirements) = + tcx.mir_borrowck(*def_id).closure_requirements + { closure_region_requirements.apply_requirements( self.infcx, self.body_id, @@ -1516,34 +1450,34 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { let predicates = self.normalize(&instantiated_predicates.predicates, location); debug!("prove_aggregate_predicates: predicates={:?}", predicates); - self.prove_predicates(predicates.iter().cloned(), location); + self.prove_predicates(predicates, location); } fn prove_trait_ref(&mut self, trait_ref: ty::TraitRef<'tcx>, location: Location) { self.prove_predicates( - [ty::Predicate::Trait( + Some(ty::Predicate::Trait( trait_ref.to_poly_trait_ref().to_poly_trait_predicate(), - )].iter() - .cloned(), + )), location, ); } - fn prove_predicates( - &mut self, - predicates: impl IntoIterator<Item = ty::Predicate<'tcx>>, - location: Location, - ) { - let mut predicates_iter = predicates.into_iter(); + fn prove_predicates<T>(&mut self, predicates: T, location: Location) + where + T: IntoIterator<Item = ty::Predicate<'tcx>>, + T::IntoIter: Clone, + { + let predicates = predicates.into_iter(); debug!( "prove_predicates(predicates={:?}, location={:?})", - predicates_iter.by_ref().collect::<Vec<_>>(), - location + predicates.clone().collect::<Vec<_>>(), + location, ); self.fully_perform_op(location.at_self(), |this| { let cause = this.misc(this.last_span); - let obligations = predicates_iter + let obligations = predicates + .into_iter() .map(|p| traits::Obligation::new(cause.clone(), this.param_env, p)) .collect(); Ok(InferOk { diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index 28dc329e4fe..562f890b4c0 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -16,7 +16,7 @@ use hair::*; use rustc::ty; use rustc::mir::*; -use syntax::abi::Abi; +use rustc_target::spec::abi::Abi; impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { /// Compile `expr`, storing the result into `destination`, which @@ -220,7 +220,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let f = ty.fn_sig(this.hir.tcx()); if f.abi() == Abi::RustIntrinsic || f.abi() == Abi::PlatformIntrinsic { - Some(this.hir.tcx().item_name(def_id)) + Some(this.hir.tcx().item_name(def_id).as_str()) } else { None } diff --git a/src/librustc_mir/build/matches/simplify.rs b/src/librustc_mir/build/matches/simplify.rs index 4e95ee6444d..147b8cc2175 100644 --- a/src/librustc_mir/build/matches/simplify.rs +++ b/src/librustc_mir/build/matches/simplify.rs @@ -113,6 +113,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { PatternKind::Variant { adt_def, substs, variant_index, ref subpatterns } => { let irrefutable = adt_def.variants.iter().enumerate().all(|(i, v)| { i == variant_index || { + self.hir.tcx().features().never_type && self.hir.tcx().features().exhaustive_patterns && self.hir.tcx().is_variant_uninhabited_from_all_modules(v, substs) } diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 9b0e4c64171..0d836f5cb97 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -20,12 +20,12 @@ use rustc::mir::visit::{MutVisitor, TyContext}; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::subst::Substs; use rustc::util::nodemap::NodeMap; -use rustc_back::PanicStrategy; +use rustc_target::spec::PanicStrategy; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; use shim; use std::mem; use std::u32; -use syntax::abi::Abi; +use rustc_target::spec::abi::Abi; use syntax::ast; use syntax::attr::{self, UnwindAttr}; use syntax::symbol::keywords; diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index c0d28280946..d0c352319c8 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -589,12 +589,84 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, // Check to see if this cast is a "coercion cast", where the cast is actually done // using a coercion (or is a no-op). if let Some(&TyCastKind::CoercionCast) = cx.tables() - .cast_kinds() - .get(source.hir_id) { + .cast_kinds() + .get(source.hir_id) { // Convert the lexpr to a vexpr. ExprKind::Use { source: source.to_ref() } } else { - ExprKind::Cast { source: source.to_ref() } + // check whether this is casting an enum variant discriminant + // to prevent cycles, we refer to the discriminant initializer + // which is always an integer and thus doesn't need to know the + // enum's layout (or its tag type) to compute it during const eval + // Example: + // enum Foo { + // A, + // B = A as isize + 4, + // } + // The correct solution would be to add symbolic computations to miri, + // so we wouldn't have to compute and store the actual value + let var = if let hir::ExprPath(ref qpath) = source.node { + let def = cx.tables().qpath_def(qpath, source.hir_id); + cx + .tables() + .node_id_to_type(source.hir_id) + .ty_adt_def() + .and_then(|adt_def| { + match def { + Def::VariantCtor(variant_id, CtorKind::Const) => { + let idx = adt_def.variant_index_with_id(variant_id); + let (d, o) = adt_def.discriminant_def_for_variant(idx); + use rustc::ty::util::IntTypeExt; + let ty = adt_def.repr.discr_type().to_ty(cx.tcx()); + Some((d, o, ty)) + } + _ => None, + } + }) + } else { + None + }; + let source = if let Some((did, offset, ty)) = var { + let mk_const = |val| Expr { + temp_lifetime, + ty, + span: expr.span, + kind: ExprKind::Literal { + literal: Literal::Value { + value: cx.tcx().mk_const(ty::Const { + val, + ty, + }), + }, + }, + }.to_ref(); + let offset = mk_const( + ConstVal::Value(Value::ByVal(PrimVal::Bytes(offset as u128))), + ); + match did { + Some(did) => { + // in case we are offsetting from a computed discriminant + // and not the beginning of discriminants (which is always `0`) + let substs = Substs::identity_for_item(cx.tcx(), did); + let lhs = mk_const(ConstVal::Unevaluated(did, substs)); + let bin = ExprKind::Binary { + op: BinOp::Add, + lhs, + rhs: offset, + }; + Expr { + temp_lifetime, + ty, + span: expr.span, + kind: bin, + }.to_ref() + }, + None => offset, + } + } else { + source.to_ref() + }; + ExprKind::Cast { source } } } hir::ExprType(ref source, _) => return source.make_mirror(cx), diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index d8d5f5073ab..e6aa2d3abb7 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -22,6 +22,7 @@ use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use rustc::hir::map::blocks::FnLikeNode; use rustc::middle::region; use rustc::infer::InferCtxt; +use rustc::ty::layout::IntegerExt; use rustc::ty::subst::Subst; use rustc::ty::{self, Ty, TyCtxt, layout}; use rustc::ty::subst::Substs; diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index 6f8b1f8e799..ff7b4f9e0fd 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -985,15 +985,17 @@ fn slice_pat_covered_by_constructor(tcx: TyCtxt, _span: Span, Ok(true) } -fn constructor_covered_by_range(ctor: &Constructor, - from: &ConstVal, to: &ConstVal, - end: RangeEnd, - ty: Ty) - -> Result<bool, ErrorReported> { +fn constructor_covered_by_range<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + ctor: &Constructor, + from: &ConstVal, to: &ConstVal, + end: RangeEnd, + ty: Ty<'tcx>, +) -> Result<bool, ErrorReported> { trace!("constructor_covered_by_range {:#?}, {:#?}, {:#?}, {}", ctor, from, to, ty); - let cmp_from = |c_from| compare_const_vals(c_from, from, ty) + let cmp_from = |c_from| compare_const_vals(tcx, c_from, from, ty) .map(|res| res != Ordering::Less); - let cmp_to = |c_to| compare_const_vals(c_to, to, ty); + let cmp_to = |c_to| compare_const_vals(tcx, c_to, to, ty); macro_rules! some_or_ok { ($e:expr) => { match $e { @@ -1105,6 +1107,7 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>( }, _ => { match constructor_covered_by_range( + cx.tcx, constructor, &value.val, &value.val, RangeEnd::Included, value.ty, ) { @@ -1118,6 +1121,7 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>( PatternKind::Range { lo, hi, ref end } => { match constructor_covered_by_range( + cx.tcx, constructor, &lo.val, &hi.val, end.clone(), lo.ty, ) { Ok(true) => Some(vec![]), diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index 8d2b73d6ba0..c2da8c11d87 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -16,7 +16,7 @@ mod check_match; pub use self::check_match::check_crate; pub(crate) use self::check_match::check_match; -use interpret::{const_val_field, const_discr}; +use interpret::{const_val_field, const_variant_index, self}; use rustc::middle::const_val::ConstVal; use rustc::mir::{Field, BorrowKind, Mutability}; @@ -372,7 +372,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { (PatternKind::Constant { value: lo }, PatternKind::Constant { value: hi }) => { use std::cmp::Ordering; - match (end, compare_const_vals(&lo.val, &hi.val, ty).unwrap()) { + match (end, compare_const_vals(self.tcx, &lo.val, &hi.val, ty).unwrap()) { (RangeEnd::Excluded, Ordering::Less) => PatternKind::Range { lo, hi, end }, (RangeEnd::Excluded, _) => { @@ -835,38 +835,9 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { ty::TyAdt(adt_def, substs) if adt_def.is_enum() => { match cv.val { ConstVal::Value(val) => { - let discr_val = const_discr( + let variant_index = const_variant_index( self.tcx, self.param_env, instance, val, cv.ty - ).expect("const_discr failed"); - let layout = self - .tcx - .layout_of(self.param_env.and(cv.ty)) - .expect("layout of enum not available"); - let variant_index = match layout.variants { - ty::layout::Variants::Single { index } => index, - ty::layout::Variants::Tagged { ref discr, .. } => { - // raw discriminants for enums are isize or bigger during - // their computation, but later shrunk to the smallest possible - // representation - let size = discr.value.size(self.tcx).bits(); - let amt = 128 - size; - adt_def - .discriminants(self.tcx) - .position(|var| ((var.val << amt) >> amt) == discr_val) - .unwrap_or_else(|| { - bug!("discriminant {} not found in {:#?}", - discr_val, - adt_def - .discriminants(self.tcx) - .collect::<Vec<_>>(), - ); - }) - } - ty::layout::Variants::NicheFilling { .. } => { - assert_eq!(discr_val as usize as u128, discr_val); - discr_val as usize - }, - }; + ).expect("const_variant_index failed"); let subpatterns = adt_subpatterns( adt_def.variants[variant_index].fields.len(), Some(variant_index), @@ -1076,7 +1047,12 @@ impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> { } } -pub fn compare_const_vals(a: &ConstVal, b: &ConstVal, ty: Ty) -> Option<Ordering> { +pub fn compare_const_vals<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + a: &ConstVal, + b: &ConstVal, + ty: Ty<'tcx>, +) -> Option<Ordering> { use rustc_const_math::ConstFloat; trace!("compare_const_vals: {:?}, {:?}", a, b); use rustc::mir::interpret::{Value, PrimVal}; @@ -1096,7 +1072,11 @@ pub fn compare_const_vals(a: &ConstVal, b: &ConstVal, ty: Ty) -> Option<Ordering // FIXME(oli-obk): report cmp errors? l.try_cmp(r).ok() }, - ty::TyInt(_) => Some((a as i128).cmp(&(b as i128))), + ty::TyInt(_) => { + let a = interpret::sign_extend(tcx, a, ty).expect("layout error for TyInt"); + let b = interpret::sign_extend(tcx, b, ty).expect("layout error for TyInt"); + Some((a as i128).cmp(&(b as i128))) + }, _ => Some(a.cmp(&b)), } }, diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs index 954a3dbe5b9..dff9fa271ab 100644 --- a/src/librustc_mir/interpret/const_eval.rs +++ b/src/librustc_mir/interpret/const_eval.rs @@ -56,7 +56,7 @@ pub fn mk_eval_cx<'a, 'tcx>( Ok(ecx) } -pub fn eval_body_with_mir<'a, 'mir, 'tcx>( +pub fn eval_promoted<'a, 'mir, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, cid: GlobalId<'tcx>, mir: &'mir mir::Mir<'tcx>, @@ -66,7 +66,7 @@ pub fn eval_body_with_mir<'a, 'mir, 'tcx>( match res { Ok(val) => Some(val), Err(mut err) => { - ecx.report(&mut err, true, None); + ecx.report(&mut err, false, None); None } } @@ -263,7 +263,7 @@ impl<'mir, 'tcx> super::Machine<'mir, 'tcx> for CompileTimeEvaluator { ) -> EvalResult<'tcx> { let substs = instance.substs; - let intrinsic_name = &ecx.tcx.item_name(instance.def_id())[..]; + let intrinsic_name = &ecx.tcx.item_name(instance.def_id()).as_str()[..]; match intrinsic_name { "min_align_of" => { let elem_ty = substs.type_at(0); @@ -400,14 +400,14 @@ pub fn const_val_field<'a, 'tcx>( } } -pub fn const_discr<'a, 'tcx>( +pub fn const_variant_index<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, instance: ty::Instance<'tcx>, value: Value, ty: Ty<'tcx>, -) -> EvalResult<'tcx, u128> { - trace!("const_discr: {:?}, {:?}, {:?}", instance, value, ty); +) -> EvalResult<'tcx, usize> { + trace!("const_variant_index: {:?}, {:?}, {:?}", instance, value, ty); let mut ecx = mk_eval_cx(tcx, instance, param_env).unwrap(); let (ptr, align) = match value { Value::ByValPair(..) | Value::ByVal(_) => { @@ -421,7 +421,7 @@ pub fn const_discr<'a, 'tcx>( Value::ByRef(ptr, align) => (ptr, align), }; let place = Place::from_primval_ptr(ptr, align); - ecx.read_discriminant_value(place, ty) + ecx.read_discriminant_as_variant_index(place, ty) } pub fn const_eval_provider<'a, 'tcx>( diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 03785f9623b..f6e9994b5da 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -5,7 +5,7 @@ use rustc::hir::def::Def; use rustc::hir::map::definitions::DefPathData; use rustc::middle::const_val::{ConstVal, ErrKind}; use rustc::mir; -use rustc::ty::layout::{self, Size, Align, HasDataLayout, LayoutOf, TyLayout}; +use rustc::ty::layout::{self, Size, Align, HasDataLayout, IntegerExt, LayoutOf, TyLayout}; use rustc::ty::subst::{Subst, Substs}; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::maps::TyCtxtAt; @@ -162,7 +162,8 @@ impl<'c, 'b, 'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> layout::HasTyCtxt<'tcx> } } -impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> LayoutOf<Ty<'tcx>> for &'a EvalContext<'a, 'mir, 'tcx, M> { +impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> LayoutOf for &'a EvalContext<'a, 'mir, 'tcx, M> { + type Ty = Ty<'tcx>; type TyLayout = EvalResult<'tcx, TyLayout<'tcx>>; fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout { @@ -171,8 +172,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> LayoutOf<Ty<'tcx>> for &'a EvalCont } } -impl<'c, 'b, 'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> LayoutOf<Ty<'tcx>> +impl<'c, 'b, 'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> LayoutOf for &'c &'b mut EvalContext<'a, 'mir, 'tcx, M> { + type Ty = Ty<'tcx>; type TyLayout = EvalResult<'tcx, TyLayout<'tcx>>; #[inline] @@ -260,7 +262,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M self.param_env, def_id, substs, - ).ok_or(EvalErrorKind::TypeckError.into()) // turn error prop into a panic to expose associated type in const issue + ).ok_or_else(|| EvalErrorKind::TypeckError.into()) // turn error prop into a panic to expose associated type in const issue } pub(super) fn type_is_sized(&self, ty: Ty<'tcx>) -> bool { @@ -279,9 +281,9 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M trace!("load mir {:?}", instance); match instance { ty::InstanceDef::Item(def_id) => { - self.tcx.maybe_optimized_mir(def_id).ok_or_else(|| { + self.tcx.maybe_optimized_mir(def_id).ok_or_else(|| EvalErrorKind::NoMirFor(self.tcx.item_path_str(def_id)).into() - }) + ) } _ => Ok(self.tcx.instance_mir(instance)), } @@ -669,6 +671,23 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M (Value::ByVal(_), _) => bug!("expected fat ptr"), } } else { + let src_layout = self.layout_of(src.ty)?; + match src_layout.variants { + layout::Variants::Single { index } => { + if let Some(def) = src.ty.ty_adt_def() { + let discr_val = def + .discriminant_for_variant(*self.tcx, index) + .val; + return self.write_primval( + dest, + PrimVal::Bytes(discr_val), + dest_ty); + } + } + layout::Variants::Tagged { .. } | + layout::Variants::NicheFilling { .. } => {}, + } + let src_val = self.value_to_primval(src)?; let dest_val = self.cast_primval(src_val, src.ty, dest_ty)?; let valty = ValTy { @@ -691,7 +710,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M self.param_env, def_id, substs, - ).ok_or(EvalErrorKind::TypeckError.into()); + ).ok_or_else(|| EvalErrorKind::TypeckError.into()); let fn_ptr = self.memory.create_fn_alloc(instance?); let valty = ValTy { value: Value::ByVal(PrimVal::Ptr(fn_ptr)), @@ -743,35 +762,13 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M Discriminant(ref place) => { let ty = self.place_ty(place); - let layout = self.layout_of(ty)?; let place = self.eval_place(place)?; let discr_val = self.read_discriminant_value(place, ty)?; - match layout.variants { - layout::Variants::Single { index } => { - assert_eq!(discr_val, index as u128); - } - layout::Variants::Tagged { .. } | - layout::Variants::NicheFilling { .. } => { - if let ty::TyAdt(adt_def, _) = ty.sty { - trace!("Read discriminant {}, valid discriminants {:?}", discr_val, adt_def.discriminants(*self.tcx).collect::<Vec<_>>()); - if adt_def.discriminants(*self.tcx).all(|v| { - discr_val != v.val - }) - { - return err!(InvalidDiscriminant); - } - } else { - bug!("rustc only generates Rvalue::Discriminant for enums"); - } - } - } self.write_primval(dest, PrimVal::Bytes(discr_val), dest_ty)?; } } - if log_enabled!(::log::Level::Trace) { - self.dump_local(dest); - } + self.dump_local(dest); Ok(()) } @@ -837,30 +834,83 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M } } + /// reads a tag and produces the corresponding variant index + pub fn read_discriminant_as_variant_index( + &mut self, + place: Place, + ty: Ty<'tcx>, + ) -> EvalResult<'tcx, usize> { + let layout = self.layout_of(ty)?; + match layout.variants { + ty::layout::Variants::Single { index } => Ok(index), + ty::layout::Variants::Tagged { .. } => { + let discr_val = self.read_discriminant_value(place, ty)?; + ty + .ty_adt_def() + .expect("tagged layout for non adt") + .discriminants(self.tcx.tcx) + .position(|var| var.val == discr_val) + .ok_or_else(|| EvalErrorKind::InvalidDiscriminant.into()) + } + ty::layout::Variants::NicheFilling { .. } => { + let discr_val = self.read_discriminant_value(place, ty)?; + assert_eq!(discr_val as usize as u128, discr_val); + Ok(discr_val as usize) + }, + } + } + pub fn read_discriminant_value( &mut self, place: Place, ty: Ty<'tcx>, ) -> EvalResult<'tcx, u128> { let layout = self.layout_of(ty)?; - //trace!("read_discriminant_value {:#?}", layout); + trace!("read_discriminant_value {:#?}", layout); + if layout.abi == layout::Abi::Uninhabited { + return Ok(0); + } match layout.variants { layout::Variants::Single { index } => { - return Ok(index as u128); + let discr_val = ty.ty_adt_def().map_or( + index as u128, + |def| def.discriminant_for_variant(*self.tcx, index).val); + return Ok(discr_val); } layout::Variants::Tagged { .. } | layout::Variants::NicheFilling { .. } => {}, } let (discr_place, discr) = self.place_field(place, mir::Field::new(0), layout)?; + trace!("discr place: {:?}, {:?}", discr_place, discr); let raw_discr = self.value_to_primval(ValTy { value: self.read_place(discr_place)?, ty: discr.ty })?; let discr_val = match layout.variants { layout::Variants::Single { .. } => bug!(), - layout::Variants::Tagged { .. } => raw_discr.to_bytes()?, + // FIXME: should we catch invalid discriminants here? + layout::Variants::Tagged { .. } => { + if discr.ty.is_signed() { + let i = raw_discr.to_bytes()? as i128; + // going from layout tag type to typeck discriminant type + // requires first sign extending with the layout discriminant + let amt = 128 - discr.size.bits(); + let sexted = (i << amt) >> amt; + // and then zeroing with the typeck discriminant type + let discr_ty = ty + .ty_adt_def().expect("tagged layout corresponds to adt") + .repr + .discr_type(); + let discr_ty = layout::Integer::from_attr(self.tcx.tcx, discr_ty); + let amt = 128 - discr_ty.size().bits(); + let truncatee = sexted as u128; + (truncatee << amt) >> amt + } else { + raw_discr.to_bytes()? + } + }, layout::Variants::NicheFilling { dataful_variant, ref niche_variants, @@ -910,11 +960,18 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M layout::Abi::Uninhabited); } } - layout::Variants::Tagged { .. } => { + layout::Variants::Tagged { ref discr, .. } => { let discr_val = dest_ty.ty_adt_def().unwrap() .discriminant_for_variant(*self.tcx, variant_index) .val; + // raw discriminants for enums are isize or bigger during + // their computation, but the in-memory tag is the smallest possible + // representation + let size = discr.value.size(self.tcx.tcx).bits(); + let amt = 128 - size; + let discr_val = (discr_val << amt) >> amt; + let (discr_dest, discr) = self.place_field(dest, mir::Field::new(0), layout)?; self.write_primval(discr_dest, PrimVal::Bytes(discr_val), discr.ty)?; } @@ -1145,19 +1202,18 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M _ if primval.is_undef() => false, _ => bug!("write_value_to_ptr: invalid ByVal layout: {:#?}", layout) }; - self.memory.write_primval(dest.to_ptr()?, dest_align, primval, layout.size.bytes(), signed) + self.memory.write_primval(dest, dest_align, primval, layout.size.bytes(), signed) } Value::ByValPair(a_val, b_val) => { - let ptr = dest.to_ptr()?; trace!("write_value_to_ptr valpair: {:#?}", layout); let (a, b) = match layout.abi { layout::Abi::ScalarPair(ref a, ref b) => (&a.value, &b.value), _ => bug!("write_value_to_ptr: invalid ByValPair layout: {:#?}", layout) }; let (a_size, b_size) = (a.size(&self), b.size(&self)); - let a_ptr = ptr; + let a_ptr = dest; let b_offset = a_size.abi_align(b.align(&self)); - let b_ptr = ptr.offset(b_offset.bytes(), &self)?.into(); + let b_ptr = dest.offset(b_offset.bytes(), &self)?.into(); // TODO: What about signedess? self.memory.write_primval(a_ptr, dest_align, a_val, a_size.bytes(), false)?; self.memory.write_primval(b_ptr, dest_align, b_val, b_size.bytes(), false) @@ -1283,6 +1339,15 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M pub fn try_read_value(&self, ptr: Pointer, ptr_align: Align, ty: Ty<'tcx>) -> EvalResult<'tcx, Option<Value>> { use syntax::ast::FloatTy; + let layout = self.layout_of(ty)?; + // do the strongest layout check of the two + let align = layout.align.max(ptr_align); + self.memory.check_align(ptr, align)?; + + if layout.size.bytes() == 0 { + return Ok(Some(Value::ByVal(PrimVal::Undef))); + } + let ptr = ptr.to_ptr()?; let val = match ty.sty { ty::TyBool => { @@ -1505,6 +1570,9 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M pub fn dump_local(&self, place: Place) { // Debug output + if !log_enabled!(::log::Level::Trace) { + return; + } match place { Place::Local { frame, local } => { let mut allocs = Vec::new(); @@ -1679,27 +1747,17 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M } pub fn sign_extend(&self, value: u128, ty: Ty<'tcx>) -> EvalResult<'tcx, u128> { - let layout = self.layout_of(ty)?; - let size = layout.size.bits(); - assert!(layout.abi.is_signed()); - // sign extend - let amt = 128 - size; - // shift the unsigned value to the left - // and back to the right as signed (essentially fills with FF on the left) - Ok((((value << amt) as i128) >> amt) as u128) + super::sign_extend(self.tcx.tcx, value, ty) } pub fn truncate(&self, value: u128, ty: Ty<'tcx>) -> EvalResult<'tcx, u128> { - let size = self.layout_of(ty)?.size.bits(); - let amt = 128 - size; - // truncate (shift left to drop out leftover values, shift right to fill with zeroes) - Ok((value << amt) >> amt) + super::truncate(self.tcx.tcx, value, ty) } } impl<'mir, 'tcx> Frame<'mir, 'tcx> { pub fn get_local(&self, local: mir::Local) -> EvalResult<'tcx, Value> { - self.locals[local].ok_or(EvalErrorKind::DeadLocal.into()) + self.locals[local].ok_or_else(|| EvalErrorKind::DeadLocal.into()) } fn set_local(&mut self, local: mir::Local, value: Value) -> EvalResult<'tcx> { diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index dcf97f61545..7f8205b8327 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -334,11 +334,17 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { /// For debugging, print an allocation and all allocations it points to, recursively. pub fn dump_alloc(&self, id: AllocId) { + if !log_enabled!(::log::Level::Trace) { + return; + } self.dump_allocs(vec![id]); } /// For debugging, print a list of allocations and all allocations they point to, recursively. pub fn dump_allocs(&self, mut allocs: Vec<AllocId>) { + if !log_enabled!(::log::Level::Trace) { + return; + } use std::fmt::Write; allocs.sort(); allocs.dedup(); @@ -691,7 +697,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { self.read_primval(ptr, ptr_align, self.pointer_size()) } - pub fn write_primval(&mut self, ptr: MemoryPointer, ptr_align: Align, val: PrimVal, size: u64, signed: bool) -> EvalResult<'tcx> { + pub fn write_primval(&mut self, ptr: Pointer, ptr_align: Align, val: PrimVal, size: u64, signed: bool) -> EvalResult<'tcx> { let endianness = self.endianness(); let bytes = match val { @@ -703,11 +709,14 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { PrimVal::Bytes(bytes) => bytes, PrimVal::Undef => { - self.mark_definedness(PrimVal::Ptr(ptr).into(), size, false)?; + self.check_align(ptr.into(), ptr_align)?; + self.mark_definedness(ptr, size, false)?; return Ok(()); } }; + let ptr = ptr.to_ptr()?; + { let align = self.int_align(size); let dst = self.get_bytes_mut(ptr, size, ptr_align.min(align))?; @@ -734,7 +743,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { pub fn write_ptr_sized_unsigned(&mut self, ptr: MemoryPointer, ptr_align: Align, val: PrimVal) -> EvalResult<'tcx> { let ptr_size = self.pointer_size(); - self.write_primval(ptr, ptr_align, val, ptr_size, false) + self.write_primval(ptr.into(), ptr_align, val, ptr_size, false) } fn int_align(&self, size: u64) -> Align { diff --git a/src/librustc_mir/interpret/mod.rs b/src/librustc_mir/interpret/mod.rs index ae6337d82c3..1eb131810bd 100644 --- a/src/librustc_mir/interpret/mod.rs +++ b/src/librustc_mir/interpret/mod.rs @@ -19,15 +19,39 @@ pub use self::place::{Place, PlaceExtra}; pub use self::memory::{Memory, MemoryKind, HasMemory}; pub use self::const_eval::{ - eval_body_with_mir, + eval_promoted, mk_borrowck_eval_cx, eval_body, CompileTimeEvaluator, const_eval_provider, const_val_field, - const_discr, + const_variant_index, }; pub use self::machine::Machine; pub use self::memory::{write_target_uint, write_target_int, read_target_uint}; + +use rustc::mir::interpret::{EvalResult, EvalErrorKind}; +use rustc::ty::{Ty, TyCtxt, ParamEnv}; + +pub fn sign_extend<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, value: u128, ty: Ty<'tcx>) -> EvalResult<'tcx, u128> { + let param_env = ParamEnv::empty(); + let layout = tcx.layout_of(param_env.and(ty)).map_err(|layout| EvalErrorKind::Layout(layout))?; + let size = layout.size.bits(); + assert!(layout.abi.is_signed()); + // sign extend + let amt = 128 - size; + // shift the unsigned value to the left + // and back to the right as signed (essentially fills with FF on the left) + Ok((((value << amt) as i128) >> amt) as u128) +} + +pub fn truncate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, value: u128, ty: Ty<'tcx>) -> EvalResult<'tcx, u128> { + let param_env = ParamEnv::empty(); + let layout = tcx.layout_of(param_env.and(ty)).map_err(|layout| EvalErrorKind::Layout(layout))?; + let size = layout.size.bits(); + let amt = 128 - size; + // truncate (shift left to drop out leftover values, shift right to fill with zeroes) + Ok((value << amt) >> amt) +} diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 456f5fd75db..d03204bfab1 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -136,6 +136,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { let val = [a, b][field_index]; Ok(Some((Value::ByVal(val), field.ty))) }, + // FIXME(oli-obk): figure out whether we should be calling `try_read_value` here _ => Ok(None), } } @@ -218,9 +219,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { } }; - if log_enabled!(::log::Level::Trace) { - self.dump_local(place); - } + self.dump_local(place); Ok(place) } diff --git a/src/librustc_mir/interpret/terminator/mod.rs b/src/librustc_mir/interpret/terminator/mod.rs index 851fac532e3..aa80ee7af18 100644 --- a/src/librustc_mir/interpret/terminator/mod.rs +++ b/src/librustc_mir/interpret/terminator/mod.rs @@ -2,7 +2,7 @@ use rustc::mir; use rustc::ty::{self, Ty}; use rustc::ty::layout::LayoutOf; use syntax::codemap::Span; -use syntax::abi::Abi; +use rustc_target::spec::abi::Abi; use rustc::mir::interpret::{EvalResult, PrimVal, Value}; use super::{EvalContext, Place, Machine, ValTy}; @@ -37,7 +37,6 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { ref targets, .. } => { - // FIXME(CTFE): forbid branching let discr_val = self.eval_operand(discr)?; let discr_prim = self.value_to_primval(discr_val)?; @@ -45,8 +44,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { let mut target_block = targets[targets.len() - 1]; for (index, &const_int) in values.iter().enumerate() { - let prim = PrimVal::Bytes(const_int); - if discr_prim.to_bytes()? == prim.to_bytes()? { + if discr_prim.to_bytes()? == const_int { target_block = targets[index]; break; } diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index de3063a5756..75b7a10097d 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -24,7 +24,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(const_fn)] #![feature(core_intrinsics)] #![feature(decl_macro)] -#![feature(dyn_trait)] +#![cfg_attr(stage0, feature(dyn_trait))] #![feature(fs_read_write)] #![feature(macro_vis_matcher)] #![feature(exhaustive_patterns)] @@ -33,6 +33,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![feature(nonzero)] #![feature(inclusive_range_fields)] #![feature(crate_visibility_modifier)] +#![feature(never_type)] #![cfg_attr(stage0, feature(try_trait))] extern crate arena; @@ -48,7 +49,7 @@ extern crate rustc_errors; #[macro_use] extern crate syntax; extern crate syntax_pos; -extern crate rustc_back; +extern crate rustc_target; extern crate rustc_const_math; extern crate core; // for NonZero extern crate log_settings; diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index 008165f33b2..610e70b39cc 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -1177,7 +1177,7 @@ fn collect_neighbours<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, param_substs: instance.substs, }.visit_mir(&mir); let param_env = ty::ParamEnv::reveal_all(); - for (i, promoted) in mir.promoted.iter().enumerate() { + for i in 0..mir.promoted.len() { use rustc_data_structures::indexed_vec::Idx; let cid = GlobalId { instance, @@ -1185,9 +1185,7 @@ fn collect_neighbours<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }; match tcx.const_eval(param_env.and(cid)) { Ok(val) => collect_const(tcx, val, instance.substs, output), - Err(err) => { - err.report(tcx, promoted.span, "promoted"); - } + Err(_) => {}, } } } diff --git a/src/librustc_mir/monomorphize/item.rs b/src/librustc_mir/monomorphize/item.rs index 181751f1777..9e43bed1b63 100644 --- a/src/librustc_mir/monomorphize/item.rs +++ b/src/librustc_mir/monomorphize/item.rs @@ -76,7 +76,7 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug { MonoItem::GlobalAsm(node_id) => { let def_id = tcx.hir.local_def_id(node_id); ty::SymbolName { - name: Symbol::intern(&format!("global_asm_{:?}", def_id)).as_str() + name: Symbol::intern(&format!("global_asm_{:?}", def_id)).as_interned_str() } } } @@ -339,7 +339,7 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> { } let abi = sig.abi(); - if abi != ::syntax::abi::Abi::Rust { + if abi != ::rustc_target::spec::abi::Abi::Rust { output.push_str("extern \""); output.push_str(abi.name()); output.push_str("\" "); diff --git a/src/librustc_mir/monomorphize/mod.rs b/src/librustc_mir/monomorphize/mod.rs index 5c38735d920..020dce62c38 100644 --- a/src/librustc_mir/monomorphize/mod.rs +++ b/src/librustc_mir/monomorphize/mod.rs @@ -163,7 +163,7 @@ pub fn custom_coerce_unsize_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, -> CustomCoerceUnsized { let def_id = tcx.lang_items().coerce_unsized_trait().unwrap(); - let trait_ref = ty::Binder(ty::TraitRef { + let trait_ref = ty::Binder::bind(ty::TraitRef { def_id: def_id, substs: tcx.mk_substs_trait(source_ty, &[target_ty]) }); diff --git a/src/librustc_mir/monomorphize/partitioning.rs b/src/librustc_mir/monomorphize/partitioning.rs index f29f86af4ab..3a65cd4ea77 100644 --- a/src/librustc_mir/monomorphize/partitioning.rs +++ b/src/librustc_mir/monomorphize/partitioning.rs @@ -146,7 +146,7 @@ pub trait CodegenUnitExt<'tcx> { } fn work_product_id(&self) -> WorkProductId { - WorkProductId::from_cgu_name(self.name()) + WorkProductId::from_cgu_name(&self.name().as_str()) } fn items_in_deterministic_order<'a>(&self, @@ -206,9 +206,9 @@ fn fallback_cgu_name(tcx: TyCtxt) -> InternedString { const FALLBACK_CODEGEN_UNIT: &'static str = "__rustc_fallback_codegen_unit"; if tcx.sess.opts.debugging_opts.human_readable_cgu_names { - Symbol::intern(FALLBACK_CODEGEN_UNIT).as_str() + Symbol::intern(FALLBACK_CODEGEN_UNIT).as_interned_str() } else { - Symbol::intern(&CodegenUnit::mangle_name(FALLBACK_CODEGEN_UNIT)).as_str() + Symbol::intern(&CodegenUnit::mangle_name(FALLBACK_CODEGEN_UNIT)).as_interned_str() } } @@ -740,7 +740,7 @@ fn compute_codegen_unit_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } }) { cgu_name.push_str("-"); - cgu_name.push_str(&part.data.as_interned_str()); + cgu_name.push_str(&part.data.as_interned_str().as_str()); } if volatile { @@ -753,11 +753,11 @@ fn compute_codegen_unit_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, CodegenUnit::mangle_name(&cgu_name) }; - Symbol::intern(&cgu_name[..]).as_str() + Symbol::intern(&cgu_name[..]).as_interned_str() } fn numbered_codegen_unit_name(crate_name: &str, index: usize) -> InternedString { - Symbol::intern(&format!("{}{}", crate_name, index)).as_str() + Symbol::intern(&format!("{}{}", crate_name, index)).as_interned_str() } fn debug_dump<'a, 'b, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -772,7 +772,7 @@ fn debug_dump<'a, 'b, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, debug!("CodegenUnit {}:", cgu.name()); for (trans_item, linkage) in cgu.items() { - let symbol_name = trans_item.symbol_name(tcx); + let symbol_name = trans_item.symbol_name(tcx).name.as_str(); let symbol_hash_start = symbol_name.rfind('h'); let symbol_hash = symbol_hash_start.map(|i| &symbol_name[i ..]) .unwrap_or("<no hash>"); diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 6a0f42c6dbb..699a5b17435 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -20,7 +20,7 @@ use rustc::mir::interpret::{Value, PrimVal}; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; -use syntax::abi::Abi; +use rustc_target::spec::abi::Abi; use syntax::ast; use syntax_pos::Span; @@ -210,7 +210,7 @@ fn build_drop_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if let Some(..) = ty { let patch = { - let param_env = tcx.param_env(def_id); + let param_env = tcx.param_env(def_id).with_reveal_all(); let mut elaborator = DropShimElaborator { mir: &mir, patch: MirPatch::new(&mir), diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index 31af7c21857..2bf5a49c97e 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -149,7 +149,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { self.visibility_scope_info[source_info.scope].lint_root; self.register_violations(&[UnsafetyViolation { source_info, - description: Symbol::intern("borrow of packed field").as_str(), + description: Symbol::intern("borrow of packed field").as_interned_str(), kind: UnsafetyViolationKind::BorrowPacked(lint_root) }], &[]); } @@ -214,7 +214,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { self.visibility_scope_info[source_info.scope].lint_root; self.register_violations(&[UnsafetyViolation { source_info, - description: Symbol::intern("use of extern static").as_str(), + description: Symbol::intern("use of extern static").as_interned_str(), kind: UnsafetyViolationKind::ExternStatic(lint_root) }], &[]); } @@ -231,7 +231,7 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { let source_info = self.source_info; self.register_violations(&[UnsafetyViolation { source_info, - description: Symbol::intern(description).as_str(), + description: Symbol::intern(description).as_interned_str(), kind: UnsafetyViolationKind::General, }], &[]); } @@ -444,7 +444,7 @@ pub fn check_unsafety<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) { struct_span_err!( tcx.sess, source_info.span, E0133, "{} requires unsafe function or block", description) - .span_label(source_info.span, &description[..]) + .span_label(source_info.span, &description.as_str()[..]) .emit(); } UnsafetyViolationKind::ExternStatic(lint_node_id) => { @@ -452,7 +452,7 @@ pub fn check_unsafety<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) { lint_node_id, source_info.span, &format!("{} requires unsafe function or \ - block (error E0133)", &description[..])); + block (error E0133)", &description.as_str()[..])); } UnsafetyViolationKind::BorrowPacked(lint_node_id) => { if let Some(impl_def_id) = builtin_derive_def_id(tcx, def_id) { @@ -462,7 +462,7 @@ pub fn check_unsafety<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) { lint_node_id, source_info.span, &format!("{} requires unsafe function or \ - block (error E0133)", &description[..])); + block (error E0133)", &description.as_str()[..])); } } } diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index f133d6e9c6d..47b2f430bc7 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -20,7 +20,7 @@ use rustc::mir::visit::{Visitor, PlaceContext}; use rustc::middle::const_val::ConstVal; use rustc::ty::{TyCtxt, self, Instance}; use rustc::mir::interpret::{Value, PrimVal, GlobalId}; -use interpret::{eval_body_with_mir, mk_borrowck_eval_cx, ValTy}; +use interpret::{eval_promoted, mk_borrowck_eval_cx, ValTy}; use transform::{MirPass, MirSource}; use syntax::codemap::Span; use rustc::ty::subst::Substs; @@ -72,7 +72,8 @@ struct ConstPropagator<'b, 'a, 'tcx:'a+'b> { param_env: ParamEnv<'tcx>, } -impl<'a, 'b, 'tcx> LayoutOf<ty::Ty<'tcx>> for &'a ConstPropagator<'a, 'b, 'tcx> { +impl<'a, 'b, 'tcx> LayoutOf for &'a ConstPropagator<'a, 'b, 'tcx> { + type Ty = ty::Ty<'tcx>; type TyLayout = Result<TyLayout<'tcx>, LayoutError<'tcx>>; fn layout_of(self, ty: ty::Ty<'tcx>) -> Self::TyLayout { @@ -161,7 +162,7 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> { }; // cannot use `const_eval` here, because that would require having the MIR // for the current function available, but we're producing said MIR right now - let (value, _, ty) = eval_body_with_mir(self.tcx, cid, self.mir, self.param_env)?; + let (value, _, ty) = eval_promoted(self.tcx, cid, self.mir, self.param_env)?; let val = (value, ty, c.span); trace!("evaluated {:?} to {:?}", c, val); Some(val) diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/src/librustc_mir/transform/elaborate_drops.rs index 2e8dd623d74..f63a5ef301a 100644 --- a/src/librustc_mir/transform/elaborate_drops.rs +++ b/src/librustc_mir/transform/elaborate_drops.rs @@ -50,7 +50,7 @@ impl MirPass for ElaborateDrops { (hir::BodyOwnerKind::Fn, None) => {}, _ => return } - let param_env = tcx.param_env(src.def_id); + let param_env = tcx.param_env(src.def_id).with_reveal_all(); let move_data = MoveData::gather_moves(mir, tcx).unwrap(); let elaborate_patch = { let mir = &*mir; diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 2dd805ccf9b..2e2f8494146 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -28,7 +28,7 @@ use transform::{MirPass, MirSource}; use super::simplify::{remove_dead_blocks, CfgSimplifier}; use syntax::{attr}; -use syntax::abi::Abi; +use rustc_target::spec::abi::Abi; const DEFAULT_THRESHOLD: usize = 50; const HINT_THRESHOLD: usize = 100; @@ -126,7 +126,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { continue; } - let callee_mir = match ty::queries::optimized_mir::try_get(self.tcx, + let callee_mir = match self.tcx.try_get_query::<ty::queries::optimized_mir>( callsite.location.span, callsite.callee) { Ok(callee_mir) if self.should_inline(callsite, callee_mir) => { @@ -379,8 +379,6 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { TerminatorKind::Call { args, destination: Some(destination), cleanup, .. } => { debug!("Inlined {:?} into {:?}", callsite.callee, self.source); - let is_box_free = Some(callsite.callee) == self.tcx.lang_items().box_free_fn(); - let mut local_map = IndexVec::with_capacity(callee_mir.local_decls.len()); let mut scope_map = IndexVec::with_capacity(callee_mir.visibility_scopes.len()); let mut promoted_map = IndexVec::with_capacity(callee_mir.promoted.len()); @@ -460,24 +458,8 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { let return_block = destination.1; - let args : Vec<_> = if is_box_free { - assert!(args.len() == 1); - // box_free takes a Box, but is defined with a *mut T, inlining - // needs to generate the cast. - // FIXME: we should probably just generate correct MIR in the first place... - - let arg = if let Operand::Move(ref place) = args[0] { - place.clone() - } else { - bug!("Constant arg to \"box_free\""); - }; - - let ptr_ty = args[0].ty(caller_mir, self.tcx); - vec![self.cast_box_free_arg(arg, ptr_ty, &callsite, caller_mir)] - } else { - // Copy the arguments if needed. - self.make_call_args(args, &callsite, caller_mir) - }; + // Copy the arguments if needed. + let args: Vec<_> = self.make_call_args(args, &callsite, caller_mir); let bb_len = caller_mir.basic_blocks().len(); let mut integrator = Integrator { @@ -518,49 +500,6 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { } } - fn cast_box_free_arg(&self, arg: Place<'tcx>, ptr_ty: Ty<'tcx>, - callsite: &CallSite<'tcx>, caller_mir: &mut Mir<'tcx>) -> Local { - let arg = Rvalue::Ref( - self.tcx.types.re_erased, - BorrowKind::Mut { allow_two_phase_borrow: false }, - arg.deref()); - - let ty = arg.ty(caller_mir, self.tcx); - let ref_tmp = LocalDecl::new_temp(ty, callsite.location.span); - let ref_tmp = caller_mir.local_decls.push(ref_tmp); - let ref_tmp = Place::Local(ref_tmp); - - let ref_stmt = Statement { - source_info: callsite.location, - kind: StatementKind::Assign(ref_tmp.clone(), arg) - }; - - caller_mir[callsite.bb] - .statements.push(ref_stmt); - - let pointee_ty = match ptr_ty.sty { - ty::TyRawPtr(tm) | ty::TyRef(_, tm) => tm.ty, - _ if ptr_ty.is_box() => ptr_ty.boxed_ty(), - _ => bug!("Invalid type `{:?}` for call to box_free", ptr_ty) - }; - let ptr_ty = self.tcx.mk_mut_ptr(pointee_ty); - - let raw_ptr = Rvalue::Cast(CastKind::Misc, Operand::Move(ref_tmp), ptr_ty); - - let cast_tmp = LocalDecl::new_temp(ptr_ty, callsite.location.span); - let cast_tmp = caller_mir.local_decls.push(cast_tmp); - - let cast_stmt = Statement { - source_info: callsite.location, - kind: StatementKind::Assign(Place::Local(cast_tmp), raw_ptr) - }; - - caller_mir[callsite.bb] - .statements.push(cast_stmt); - - cast_tmp - } - fn make_call_args( &self, args: Vec<Operand<'tcx>>, diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index aeefd5ab1d5..4762c6aaa27 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -29,7 +29,7 @@ use rustc::mir::*; use rustc::mir::traversal::ReversePostorder; use rustc::mir::visit::{PlaceContext, Visitor}; use rustc::middle::lang_items; -use syntax::abi::Abi; +use rustc_target::spec::abi::Abi; use syntax::attr; use syntax::ast::LitKind; use syntax::feature_gate::UnstableFeatures; @@ -868,7 +868,7 @@ This does not pose a problem by itself because they can't be accessed directly." Abi::RustIntrinsic | Abi::PlatformIntrinsic => { assert!(!self.tcx.is_const_fn(def_id)); - match &self.tcx.item_name(def_id)[..] { + match &self.tcx.item_name(def_id).as_str()[..] { "size_of" | "min_align_of" | "type_id" => is_const_fn = Some(def_id), name if name.starts_with("simd_shuffle") => { @@ -964,7 +964,7 @@ This does not pose a problem by itself because they can't be accessed directly." let (msg, note) = if let UnstableFeatures::Disallow = self.tcx.sess.opts.unstable_features { (format!("calls in {}s are limited to \ - struct and enum constructors", + tuple structs and tuple variants", self.mode), Some("a limited form of compile-time function \ evaluation is available on a nightly \ @@ -972,7 +972,7 @@ This does not pose a problem by itself because they can't be accessed directly." } else { (format!("calls in {}s are limited \ to constant functions, \ - struct and enum constructors", + tuple structs and tuple variants", self.mode), None) }; diff --git a/src/librustc_mir/transform/rustc_peek.rs b/src/librustc_mir/transform/rustc_peek.rs index 45e7a0d3f4c..8f67b9e7c3d 100644 --- a/src/librustc_mir/transform/rustc_peek.rs +++ b/src/librustc_mir/transform/rustc_peek.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use syntax::abi::{Abi}; +use rustc_target::spec::abi::{Abi}; use syntax::ast; use syntax_pos::Span; diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs index 19f33ef5d45..4b7c581d3c8 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -13,6 +13,7 @@ use rustc::hir; use rustc::mir::*; use rustc::middle::const_val::ConstVal; use rustc::middle::lang_items; +use rustc::traits::Reveal; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::subst::{Kind, Substs}; use rustc::ty::util::IntTypeExt; @@ -206,6 +207,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> let field = Field::new(i); let subpath = self.elaborator.field_subpath(variant_path, field); + assert_eq!(self.elaborator.param_env().reveal, Reveal::All); let field_ty = self.tcx().normalize_erasing_regions( self.elaborator.param_env(), f.ty(self.tcx(), substs), @@ -337,18 +339,19 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> self.drop_ladder(fields, succ, unwind).0 } - fn open_drop_for_box<'a>(&mut self, ty: Ty<'tcx>) -> BasicBlock + fn open_drop_for_box<'a>(&mut self, adt: &'tcx ty::AdtDef, substs: &'tcx Substs<'tcx>) + -> BasicBlock { - debug!("open_drop_for_box({:?}, {:?})", self, ty); + debug!("open_drop_for_box({:?}, {:?}, {:?})", self, adt, substs); let interior = self.place.clone().deref(); let interior_path = self.elaborator.deref_subpath(self.path); let succ = self.succ; // FIXME(#43234) let unwind = self.unwind; - let succ = self.box_free_block(ty, succ, unwind); + let succ = self.box_free_block(adt, substs, succ, unwind); let unwind_succ = self.unwind.map(|unwind| { - self.box_free_block(ty, unwind, Unwind::InCleanup) + self.box_free_block(adt, substs, unwind, Unwind::InCleanup) }); self.drop_subpath(&interior, interior_path, succ, unwind_succ) @@ -791,11 +794,12 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> ty::TyTuple(tys) => { self.open_drop_for_tuple(tys) } - ty::TyAdt(def, _) if def.is_box() => { - self.open_drop_for_box(ty.boxed_ty()) - } ty::TyAdt(def, substs) => { - self.open_drop_for_adt(def, substs) + if def.is_box() { + self.open_drop_for_box(def, substs) + } else { + self.open_drop_for_adt(def, substs) + } } ty::TyDynamic(..) => { let unwind = self.unwind; // FIXME(#43234) @@ -858,28 +862,34 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> fn box_free_block<'a>( &mut self, - ty: Ty<'tcx>, + adt: &'tcx ty::AdtDef, + substs: &'tcx Substs<'tcx>, target: BasicBlock, unwind: Unwind, ) -> BasicBlock { - let block = self.unelaborated_free_block(ty, target, unwind); + let block = self.unelaborated_free_block(adt, substs, target, unwind); self.drop_flag_test_block(block, target, unwind) } fn unelaborated_free_block<'a>( &mut self, - ty: Ty<'tcx>, + adt: &'tcx ty::AdtDef, + substs: &'tcx Substs<'tcx>, target: BasicBlock, unwind: Unwind ) -> BasicBlock { let tcx = self.tcx(); let unit_temp = Place::Local(self.new_temp(tcx.mk_nil())); let free_func = tcx.require_lang_item(lang_items::BoxFreeFnLangItem); - let substs = tcx.mk_substs(iter::once(Kind::from(ty))); + let args = adt.variants[0].fields.iter().enumerate().map(|(i, f)| { + let field = Field::new(i); + let field_ty = f.ty(self.tcx(), substs); + Operand::Move(self.place.clone().field(field, field_ty)) + }).collect(); let call = TerminatorKind::Call { func: Operand::function_handle(tcx, free_func, substs, self.source_info.span), - args: vec![Operand::Move(self.place.clone())], + args: args, destination: Some((unit_temp, target)), cleanup: None }; // FIXME(#43234) diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 1866122454c..6708640379a 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -273,7 +273,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.err_handler().span_err(item.span, "inherent impls cannot be negative"); } if defaultness == Defaultness::Default { - self.err_handler().span_err(item.span, "inherent impls cannot be default"); + self.err_handler() + .struct_span_err(item.span, "inherent impls cannot be default") + .note("only trait implementations may be annotated with default").emit(); } } ItemKind::ForeignMod(..) => { diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index f4e2136a5a1..14ceb5f59a3 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -41,7 +41,6 @@ use syntax::ext::tt::macro_rules; use syntax::parse::token::{self, Token}; use syntax::std_inject::injected_crate_name; use syntax::symbol::keywords; -use syntax::symbol::Symbol; use syntax::visit::{self, Visitor}; use syntax_pos::{Span, DUMMY_SP}; @@ -544,14 +543,14 @@ impl<'a> Resolver<'a> { } let (name, parent) = if def_id.index == CRATE_DEF_INDEX { - (self.cstore.crate_name_untracked(def_id.krate).as_str(), None) + (self.cstore.crate_name_untracked(def_id.krate).as_interned_str(), None) } else { let def_key = self.cstore.def_key(def_id); (def_key.disambiguated_data.data.get_opt_name().unwrap(), Some(self.get_module(DefId { index: def_key.parent.unwrap(), ..def_id }))) }; - let kind = ModuleKind::Def(Def::Mod(def_id), Symbol::intern(&name)); + let kind = ModuleKind::Def(Def::Mod(def_id), name.as_symbol()); let module = self.arenas.alloc_module(ModuleData::new(parent, kind, def_id, Mark::root(), DUMMY_SP)); self.extern_module_map.insert((def_id, macros_only), module); diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 01940ee4fd0..127331152c1 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -962,38 +962,38 @@ enum TypeParameters<'a, 'b> { RibKind<'a>), } -// The rib kind controls the translation of local -// definitions (`Def::Local`) to upvars (`Def::Upvar`). +/// The rib kind controls the translation of local +/// definitions (`Def::Local`) to upvars (`Def::Upvar`). #[derive(Copy, Clone, Debug)] enum RibKind<'a> { - // No translation needs to be applied. + /// No translation needs to be applied. NormalRibKind, - // We passed through a closure scope at the given node ID. - // Translate upvars as appropriate. + /// We passed through a closure scope at the given node ID. + /// Translate upvars as appropriate. ClosureRibKind(NodeId /* func id */), - // We passed through an impl or trait and are now in one of its - // methods or associated types. Allow references to ty params that impl or trait - // binds. Disallow any other upvars (including other ty params that are - // upvars). + /// We passed through an impl or trait and are now in one of its + /// methods or associated types. Allow references to ty params that impl or trait + /// binds. Disallow any other upvars (including other ty params that are + /// upvars). TraitOrImplItemRibKind, - // We passed through an item scope. Disallow upvars. + /// We passed through an item scope. Disallow upvars. ItemRibKind, - // We're in a constant item. Can't refer to dynamic stuff. + /// We're in a constant item. Can't refer to dynamic stuff. ConstantItemRibKind, - // We passed through a module. + /// We passed through a module. ModuleRibKind(Module<'a>), - // We passed through a `macro_rules!` statement + /// We passed through a `macro_rules!` statement MacroDefinition(DefId), - // All bindings in this rib are type parameters that can't be used - // from the default of a type parameter because they're not declared - // before said type parameter. Also see the `visit_generics` override. + /// All bindings in this rib are type parameters that can't be used + /// from the default of a type parameter because they're not declared + /// before said type parameter. Also see the `visit_generics` override. ForwardTyParamBanRibKind, } @@ -1198,7 +1198,7 @@ impl<'a> fmt::Debug for ModuleData<'a> { } } -// Records a possibly-private value, type, or module definition. +/// Records a possibly-private value, type, or module definition. #[derive(Clone, Debug)] pub struct NameBinding<'a> { kind: NameBindingKind<'a>, @@ -1408,36 +1408,36 @@ pub struct Resolver<'a> { prelude: Option<Module<'a>>, - // n.b. This is used only for better diagnostics, not name resolution itself. + /// n.b. This is used only for better diagnostics, not name resolution itself. has_self: FxHashSet<DefId>, - // Names of fields of an item `DefId` accessible with dot syntax. - // Used for hints during error reporting. + /// Names of fields of an item `DefId` accessible with dot syntax. + /// Used for hints during error reporting. field_names: FxHashMap<DefId, Vec<Name>>, - // All imports known to succeed or fail. + /// All imports known to succeed or fail. determined_imports: Vec<&'a ImportDirective<'a>>, - // All non-determined imports. + /// All non-determined imports. indeterminate_imports: Vec<&'a ImportDirective<'a>>, - // The module that represents the current item scope. + /// The module that represents the current item scope. current_module: Module<'a>, - // The current set of local scopes for types and values. - // FIXME #4948: Reuse ribs to avoid allocation. + /// The current set of local scopes for types and values. + /// FIXME #4948: Reuse ribs to avoid allocation. ribs: PerNS<Vec<Rib<'a>>>, - // The current set of local scopes, for labels. + /// The current set of local scopes, for labels. label_ribs: Vec<Rib<'a>>, - // The trait that the current context can refer to. + /// The trait that the current context can refer to. current_trait_ref: Option<(Module<'a>, TraitRef)>, - // The current self type if inside an impl (used for better errors). + /// The current self type if inside an impl (used for better errors). current_self_type: Option<Ty>, - // The idents for the primitive types. + /// The idents for the primitive types. primitive_type_table: PrimitiveTypeTable, def_map: DefMap, @@ -1446,20 +1446,20 @@ pub struct Resolver<'a> { pub export_map: ExportMap, pub trait_map: TraitMap, - // A map from nodes to anonymous modules. - // Anonymous modules are pseudo-modules that are implicitly created around items - // contained within blocks. - // - // For example, if we have this: - // - // fn f() { - // fn g() { - // ... - // } - // } - // - // There will be an anonymous module created around `g` with the ID of the - // entry block for `f`. + /// A map from nodes to anonymous modules. + /// Anonymous modules are pseudo-modules that are implicitly created around items + /// contained within blocks. + /// + /// For example, if we have this: + /// + /// fn f() { + /// fn g() { + /// ... + /// } + /// } + /// + /// There will be an anonymous module created around `g` with the ID of the + /// entry block for `f`. block_map: NodeMap<Module<'a>>, module_map: FxHashMap<DefId, Module<'a>>, extern_module_map: FxHashMap<(DefId, bool /* MacrosOnly? */), Module<'a>>, @@ -1487,7 +1487,8 @@ pub struct Resolver<'a> { arenas: &'a ResolverArenas<'a>, dummy_binding: &'a NameBinding<'a>, - use_extern_macros: bool, // true if `#![feature(use_extern_macros)]` + /// true if `#![feature(use_extern_macros)]` + use_extern_macros: bool, crate_loader: &'a mut CrateLoader, macro_names: FxHashSet<Ident>, @@ -1501,29 +1502,29 @@ pub struct Resolver<'a> { pub whitelisted_legacy_custom_derives: Vec<Name>, pub found_unresolved_macro: bool, - // List of crate local macros that we need to warn about as being unused. - // Right now this only includes macro_rules! macros, and macros 2.0. + /// List of crate local macros that we need to warn about as being unused. + /// Right now this only includes macro_rules! macros, and macros 2.0. unused_macros: FxHashSet<DefId>, - // Maps the `Mark` of an expansion to its containing module or block. + /// Maps the `Mark` of an expansion to its containing module or block. invocations: FxHashMap<Mark, &'a InvocationData<'a>>, - // Avoid duplicated errors for "name already defined". + /// Avoid duplicated errors for "name already defined". name_already_seen: FxHashMap<Name, Span>, - // If `#![feature(proc_macro)]` is set + /// If `#![feature(proc_macro)]` is set proc_macro_enabled: bool, - // A set of procedural macros imported by `#[macro_use]` that have already been warned about + /// A set of procedural macros imported by `#[macro_use]` that have already been warned about warned_proc_macros: FxHashSet<Name>, potentially_unused_imports: Vec<&'a ImportDirective<'a>>, - // This table maps struct IDs into struct constructor IDs, - // it's not used during normal resolution, only for better error reporting. + /// This table maps struct IDs into struct constructor IDs, + /// it's not used during normal resolution, only for better error reporting. struct_constructors: DefIdMap<(Def, ty::Visibility)>, - // Only used for better errors on `fn(): fn()` + /// Only used for better errors on `fn(): fn()` current_type_ascription: Vec<Span>, injected_crate: Option<Module<'a>>, @@ -1653,11 +1654,12 @@ impl<'a> Resolver<'a> { let path: Vec<Ident> = segments.iter() .map(|seg| Ident::new(seg.name, span)) .collect(); - match self.resolve_path(&path, Some(namespace), true, span) { + // FIXME (Manishearth): Intra doc links won't get warned of epoch changes + match self.resolve_path(&path, Some(namespace), true, span, None) { PathResult::Module(module) => *def = module.def().unwrap(), PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => *def = path_res.base_def(), - PathResult::NonModule(..) => match self.resolve_path(&path, None, true, span) { + PathResult::NonModule(..) => match self.resolve_path(&path, None, true, span, None) { PathResult::Failed(span, msg, _) => { error_callback(self, span, ResolutionError::FailedToResolve(&msg)); } @@ -2359,7 +2361,8 @@ impl<'a> Resolver<'a> { if def != Def::Err { new_id = Some(def.def_id()); let span = trait_ref.path.span; - if let PathResult::Module(module) = self.resolve_path(&path, None, false, span) { + if let PathResult::Module(module) = self.resolve_path(&path, None, false, span, + Some(trait_ref.ref_id)) { new_val = Some((module, trait_ref.clone())); } } @@ -2818,7 +2821,8 @@ impl<'a> Resolver<'a> { (format!(""), format!("the crate root")) } else { let mod_path = &path[..path.len() - 1]; - let mod_prefix = match this.resolve_path(mod_path, Some(TypeNS), false, span) { + let mod_prefix = match this.resolve_path(mod_path, Some(TypeNS), + false, span, None) { PathResult::Module(module) => module.def(), _ => None, }.map_or(format!(""), |def| format!("{} ", def.kind_name())); @@ -3148,7 +3152,7 @@ impl<'a> Resolver<'a> { )); } - let result = match self.resolve_path(&path, Some(ns), true, span) { + let result = match self.resolve_path(&path, Some(ns), true, span, Some(id)) { PathResult::NonModule(path_res) => path_res, PathResult::Module(module) if !module.is_normal() => { PathResolution::new(module.def().unwrap()) @@ -3185,7 +3189,7 @@ impl<'a> Resolver<'a> { path[0].name != keywords::CrateRoot.name() && path[0].name != keywords::DollarCrate.name() { let unqualified_result = { - match self.resolve_path(&[*path.last().unwrap()], Some(ns), false, span) { + match self.resolve_path(&[*path.last().unwrap()], Some(ns), false, span, None) { PathResult::NonModule(path_res) => path_res.base_def(), PathResult::Module(module) => module.def().unwrap(), _ => return Some(result), @@ -3204,7 +3208,9 @@ impl<'a> Resolver<'a> { path: &[Ident], opt_ns: Option<Namespace>, // `None` indicates a module path record_used: bool, - path_span: Span) + path_span: Span, + node_id: Option<NodeId>) // None indicates that we don't care about linting + // `::module` paths -> PathResult<'a> { let mut module = None; let mut allow_super = true; @@ -3239,6 +3245,7 @@ impl<'a> Resolver<'a> { if ns == TypeNS { if (i == 0 && name == keywords::CrateRoot.name()) || + (i == 0 && name == keywords::Crate.name()) || (i == 1 && name == keywords::Crate.name() && path[0].name == keywords::CrateRoot.name()) { // `::a::b` or `::crate::a::b` @@ -3252,6 +3259,8 @@ impl<'a> Resolver<'a> { let prev_name = path[0].name; if prev_name == keywords::Extern.name() || prev_name == keywords::CrateRoot.name() && + // Note: When this feature stabilizes, this should + // be gated on sess.rust_2018() self.session.features_untracked().extern_absolute_paths { // `::extern_crate::a::b` let crate_id = self.crate_loader.process_path_extern(name, ident.span); @@ -3271,8 +3280,10 @@ impl<'a> Resolver<'a> { name == keywords::SelfType.name() && i != 0 || name == keywords::Super.name() && i != 0 || name == keywords::Extern.name() && i != 0 || - name == keywords::Crate.name() && i != 1 && - path[0].name != keywords::CrateRoot.name() { + // we allow crate::foo and ::crate::foo but nothing else + name == keywords::Crate.name() && i > 1 && + path[0].name != keywords::CrateRoot.name() || + name == keywords::Crate.name() && path.len() == 1 { let name_str = if name == keywords::CrateRoot.name() { format!("crate root") } else { @@ -3280,8 +3291,6 @@ impl<'a> Resolver<'a> { }; let msg = if i == 1 && path[0].name == keywords::CrateRoot.name() { format!("global paths cannot start with {}", name_str) - } else if i == 0 && name == keywords::Crate.name() { - format!("{} can only be used in absolute paths", name_str) } else { format!("{} in paths can only be used in start position", name_str) }; @@ -3323,6 +3332,33 @@ impl<'a> Resolver<'a> { format!("Not a module `{}`", ident), is_last); } + + if let Some(id) = node_id { + if i == 1 && self.session.features_untracked().crate_in_paths + && !self.session.rust_2018() { + let prev_name = path[0].name; + if prev_name == keywords::Extern.name() || + prev_name == keywords::CrateRoot.name() { + let mut is_crate = false; + if let NameBindingKind::Import { directive: d, .. } = binding.kind { + if let ImportDirectiveSubclass::ExternCrate(..) = d.subclass { + is_crate = true; + } + } + + if !is_crate { + let diag = lint::builtin::BuiltinLintDiagnostics + ::AbsPathWithModule(path_span); + self.session.buffer_lint_with_diagnostic( + lint::builtin::ABSOLUTE_PATH_STARTING_WITH_MODULE, + id, path_span, + "Absolute paths must start with `self`, `super`, \ + `crate`, or an external crate name in the 2018 edition", + diag); + } + } + } + } } Err(Undetermined) => return PathResult::Indeterminate, Err(Determined) => { @@ -3570,7 +3606,7 @@ impl<'a> Resolver<'a> { // Search in module. let mod_path = &path[..path.len() - 1]; if let PathResult::Module(module) = self.resolve_path(mod_path, Some(TypeNS), - false, span) { + false, span, None) { add_module_candidates(module, &mut names); } } diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 753ce48e478..3d20f922ac0 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -399,6 +399,19 @@ impl<'a> Resolver<'a> { fn resolve_macro_to_def(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, force: bool) -> Result<Def, Determinacy> { + if kind != MacroKind::Bang && path.segments.len() > 1 { + if !self.session.features_untracked().proc_macro_path_invoc { + emit_feature_err( + &self.session.parse_sess, + "proc_macro_path_invoc", + path.span, + GateIssue::Language, + "paths of length greater than one in macro invocations are \ + currently unstable", + ); + } + } + let def = self.resolve_macro_to_def_inner(scope, path, kind, force); if def != Err(Determinacy::Undetermined) { // Do not report duplicated errors on every undetermined resolution. @@ -428,7 +441,7 @@ impl<'a> Resolver<'a> { return Err(Determinacy::Determined); } - let def = match self.resolve_path(&path, Some(MacroNS), false, span) { + let def = match self.resolve_path(&path, Some(MacroNS), false, span, None) { PathResult::NonModule(path_res) => match path_res.base_def() { Def::Err => Err(Determinacy::Determined), def @ _ => { @@ -606,7 +619,7 @@ impl<'a> Resolver<'a> { pub fn finalize_current_module_macro_resolutions(&mut self) { let module = self.current_module; for &(ref path, span) in module.macro_resolutions.borrow().iter() { - match self.resolve_path(&path, Some(MacroNS), true, span) { + match self.resolve_path(&path, Some(MacroNS), true, span, None) { PathResult::NonModule(_) => {}, PathResult::Failed(span, msg, _) => { resolve_error(self, span, ResolutionError::FailedToResolve(&msg)); diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 37c62a7b0b4..e2a7f5668d2 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -535,7 +535,8 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { // For better failure detection, pretend that the import will not define any names // while resolving its module path. directive.vis.set(ty::Visibility::Invisible); - let result = self.resolve_path(&directive.module_path[..], None, false, directive.span); + let result = self.resolve_path(&directive.module_path[..], None, false, + directive.span, Some(directive.id)); directive.vis.set(vis); match result { @@ -663,7 +664,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { } } - let module_result = self.resolve_path(&module_path, None, true, span); + let module_result = self.resolve_path(&module_path, None, true, span, Some(directive.id)); let module = match module_result { PathResult::Module(module) => module, PathResult::Failed(span, msg, false) => { @@ -677,7 +678,8 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { if !self_path.is_empty() && !is_special(self_path[0]) && !(self_path.len() > 1 && is_special(self_path[1])) { self_path[0].name = keywords::SelfValue.name(); - self_result = Some(self.resolve_path(&self_path, None, false, span)); + self_result = Some(self.resolve_path(&self_path, None, false, + span, None)); } return if let Some(PathResult::Module(..)) = self_result { Some((span, format!("Did you mean `{}`?", names_to_string(&self_path[..])))) diff --git a/src/librustc_save_analysis/Cargo.toml b/src/librustc_save_analysis/Cargo.toml index 005faa55b58..976614c9542 100644 --- a/src/librustc_save_analysis/Cargo.toml +++ b/src/librustc_save_analysis/Cargo.toml @@ -12,6 +12,7 @@ crate-type = ["dylib"] log = "0.4" rustc = { path = "../librustc" } rustc_data_structures = { path = "../librustc_data_structures" } +rustc_target = { path = "../librustc_target" } rustc_typeck = { path = "../librustc_typeck" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 6a747decbd3..401a280412a 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -22,6 +22,7 @@ extern crate rustc; extern crate log; extern crate rustc_data_structures; extern crate rustc_serialize; +extern crate rustc_target; extern crate rustc_typeck; #[macro_use] extern crate syntax; diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs index a9df898efb6..829ed320d75 100644 --- a/src/librustc_save_analysis/sig.rs +++ b/src/librustc_save_analysis/sig.rs @@ -237,7 +237,7 @@ impl Sig for ast::Ty { if f.unsafety == ast::Unsafety::Unsafe { text.push_str("unsafe "); } - if f.abi != ::syntax::abi::Abi::Rust { + if f.abi != ::rustc_target::spec::abi::Abi::Rust { text.push_str("extern"); text.push_str(&f.abi.to_string()); text.push(' '); @@ -388,7 +388,7 @@ impl Sig for ast::Item { if unsafety == ast::Unsafety::Unsafe { text.push_str("unsafe "); } - if abi != ::syntax::abi::Abi::Rust { + if abi != ::rustc_target::spec::abi::Abi::Rust { text.push_str("extern"); text.push_str(&abi.to_string()); text.push(' '); @@ -931,7 +931,7 @@ fn make_method_signature( if m.unsafety == ast::Unsafety::Unsafe { text.push_str("unsafe "); } - if m.abi != ::syntax::abi::Abi::Rust { + if m.abi != ::rustc_target::spec::abi::Abi::Rust { text.push_str("extern"); text.push_str(&m.abi.to_string()); text.push(' '); diff --git a/src/librustc_back/Cargo.toml b/src/librustc_target/Cargo.toml index 4c5b1417a2f..bb686e914a0 100644 --- a/src/librustc_back/Cargo.toml +++ b/src/librustc_target/Cargo.toml @@ -1,18 +1,18 @@ [package] authors = ["The Rust Project Developers"] -name = "rustc_back" +name = "rustc_target" version = "0.0.0" [lib] -name = "rustc_back" +name = "rustc_target" path = "lib.rs" crate-type = ["dylib"] [dependencies] -syntax = { path = "../libsyntax" } -serialize = { path = "../libserialize" } +bitflags = "1.0" log = "0.4" -rand = "0.4" +rustc_cratesio_shim = { path = "../librustc_cratesio_shim" } +serialize = { path = "../libserialize" } [features] jemalloc = [] diff --git a/src/librustc_target/README.md b/src/librustc_target/README.md new file mode 100644 index 00000000000..f5b1acb1921 --- /dev/null +++ b/src/librustc_target/README.md @@ -0,0 +1,6 @@ +`librustc_target` contains some very low-level details that are +specific to different compilation targets and so forth. + +For more information about how rustc works, see the [rustc guide]. + +[rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/ diff --git a/src/librustc_trans/cabi_aarch64.rs b/src/librustc_target/abi/call/aarch64.rs index 72ae1449de0..90b5b97b51e 100644 --- a/src/librustc_trans/cabi_aarch64.rs +++ b/src/librustc_target/abi/call/aarch64.rs @@ -8,11 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use abi::{FnType, ArgType, LayoutExt, Reg, RegKind, Uniform}; -use context::CodegenCx; +use abi::call::{FnType, ArgType, Reg, RegKind, Uniform}; +use abi::{HasDataLayout, LayoutOf, TyLayout, TyLayoutMethods}; -fn is_homogeneous_aggregate<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, arg: &mut ArgType<'tcx>) - -> Option<Uniform> { +fn is_homogeneous_aggregate<'a, Ty, C>(cx: C, arg: &mut ArgType<'a, Ty>) + -> Option<Uniform> + where Ty: TyLayoutMethods<'a, C> + Copy, + C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout +{ arg.layout.homogeneous_aggregate(cx).and_then(|unit| { let size = arg.layout.size; @@ -38,7 +41,10 @@ fn is_homogeneous_aggregate<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, arg: &mut ArgTyp }) } -fn classify_ret_ty<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, ret: &mut ArgType<'tcx>) { +fn classify_ret_ty<'a, Ty, C>(cx: C, ret: &mut ArgType<'a, Ty>) + where Ty: TyLayoutMethods<'a, C> + Copy, + C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout +{ if !ret.layout.is_aggregate() { ret.extend_integer_width_to(32); return; @@ -69,7 +75,10 @@ fn classify_ret_ty<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, ret: &mut ArgType<'tcx>) ret.make_indirect(); } -fn classify_arg_ty<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, arg: &mut ArgType<'tcx>) { +fn classify_arg_ty<'a, Ty, C>(cx: C, arg: &mut ArgType<'a, Ty>) + where Ty: TyLayoutMethods<'a, C> + Copy, + C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout +{ if !arg.layout.is_aggregate() { arg.extend_integer_width_to(32); return; @@ -100,7 +109,10 @@ fn classify_arg_ty<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, arg: &mut ArgType<'tcx>) arg.make_indirect(); } -pub fn compute_abi_info<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, fty: &mut FnType<'tcx>) { +pub fn compute_abi_info<'a, Ty, C>(cx: C, fty: &mut FnType<'a, Ty>) + where Ty: TyLayoutMethods<'a, C> + Copy, + C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout +{ if !fty.ret.is_ignore() { classify_ret_ty(cx, &mut fty.ret); } diff --git a/src/librustc_trans/cabi_arm.rs b/src/librustc_target/abi/call/arm.rs index b6cf16cb8d5..249aad2d937 100644 --- a/src/librustc_trans/cabi_arm.rs +++ b/src/librustc_target/abi/call/arm.rs @@ -8,12 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use abi::{FnType, ArgType, LayoutExt, Reg, RegKind, Uniform}; -use context::CodegenCx; -use llvm::CallConv; +use abi::call::{Conv, FnType, ArgType, Reg, RegKind, Uniform}; +use abi::{HasDataLayout, LayoutOf, TyLayout, TyLayoutMethods}; +use spec::HasTargetSpec; -fn is_homogeneous_aggregate<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, arg: &mut ArgType<'tcx>) - -> Option<Uniform> { +fn is_homogeneous_aggregate<'a, Ty, C>(cx: C, arg: &mut ArgType<'a, Ty>) + -> Option<Uniform> + where Ty: TyLayoutMethods<'a, C> + Copy, + C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout +{ arg.layout.homogeneous_aggregate(cx).and_then(|unit| { let size = arg.layout.size; @@ -39,7 +42,10 @@ fn is_homogeneous_aggregate<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, arg: &mut ArgTyp }) } -fn classify_ret_ty<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, ret: &mut ArgType<'tcx>, vfp: bool) { +fn classify_ret_ty<'a, Ty, C>(cx: C, ret: &mut ArgType<'a, Ty>, vfp: bool) + where Ty: TyLayoutMethods<'a, C> + Copy, + C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout +{ if !ret.layout.is_aggregate() { ret.extend_integer_width_to(32); return; @@ -71,7 +77,10 @@ fn classify_ret_ty<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, ret: &mut ArgType<'tcx>, ret.make_indirect(); } -fn classify_arg_ty<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, arg: &mut ArgType<'tcx>, vfp: bool) { +fn classify_arg_ty<'a, Ty, C>(cx: C, arg: &mut ArgType<'a, Ty>, vfp: bool) + where Ty: TyLayoutMethods<'a, C> + Copy, + C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout +{ if !arg.layout.is_aggregate() { arg.extend_integer_width_to(32); return; @@ -92,11 +101,14 @@ fn classify_arg_ty<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, arg: &mut ArgType<'tcx>, }); } -pub fn compute_abi_info<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, fty: &mut FnType<'tcx>) { +pub fn compute_abi_info<'a, Ty, C>(cx: C, fty: &mut FnType<'a, Ty>) + where Ty: TyLayoutMethods<'a, C> + Copy, + C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout + HasTargetSpec +{ // If this is a target with a hard-float ABI, and the function is not explicitly // `extern "aapcs"`, then we must use the VFP registers for homogeneous aggregates. - let vfp = cx.sess().target.target.llvm_target.ends_with("hf") - && fty.cconv != CallConv::ArmAapcsCallConv + let vfp = cx.target_spec().llvm_target.ends_with("hf") + && fty.conv != Conv::ArmAapcs && !fty.variadic; if !fty.ret.is_ignore() { diff --git a/src/librustc_trans/cabi_asmjs.rs b/src/librustc_target/abi/call/asmjs.rs index b182f833dd6..81d6f7b134b 100644 --- a/src/librustc_trans/cabi_asmjs.rs +++ b/src/librustc_target/abi/call/asmjs.rs @@ -8,15 +8,18 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use abi::{FnType, ArgType, LayoutExt, Uniform}; -use context::CodegenCx; +use abi::call::{FnType, ArgType, Uniform}; +use abi::{HasDataLayout, LayoutOf, TyLayout, TyLayoutMethods}; // Data layout: e-p:32:32-i64:64-v128:32:128-n32-S128 // See the https://github.com/kripken/emscripten-fastcomp-clang repository. // The class `EmscriptenABIInfo` in `/lib/CodeGen/TargetInfo.cpp` contains the ABI definitions. -fn classify_ret_ty<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, ret: &mut ArgType<'tcx>) { +fn classify_ret_ty<'a, Ty, C>(cx: C, ret: &mut ArgType<'a, Ty>) + where Ty: TyLayoutMethods<'a, C> + Copy, + C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout +{ if ret.layout.is_aggregate() { if let Some(unit) = ret.layout.homogeneous_aggregate(cx) { let size = ret.layout.size; @@ -33,13 +36,16 @@ fn classify_ret_ty<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, ret: &mut ArgType<'tcx>) } } -fn classify_arg_ty(arg: &mut ArgType) { +fn classify_arg_ty<Ty>(arg: &mut ArgType<Ty>) { if arg.layout.is_aggregate() { arg.make_indirect_byval(); } } -pub fn compute_abi_info<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, fty: &mut FnType<'tcx>) { +pub fn compute_abi_info<'a, Ty, C>(cx: C, fty: &mut FnType<'a, Ty>) + where Ty: TyLayoutMethods<'a, C> + Copy, + C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout +{ if !fty.ret.is_ignore() { classify_ret_ty(cx, &mut fty.ret); } diff --git a/src/librustc_trans/cabi_hexagon.rs b/src/librustc_target/abi/call/hexagon.rs index 7e7e483fea0..d37d5584591 100644 --- a/src/librustc_trans/cabi_hexagon.rs +++ b/src/librustc_target/abi/call/hexagon.rs @@ -10,9 +10,9 @@ #![allow(non_upper_case_globals)] -use abi::{FnType, ArgType, LayoutExt}; +use abi::call::{FnType, ArgType}; -fn classify_ret_ty(ret: &mut ArgType) { +fn classify_ret_ty<Ty>(ret: &mut ArgType<Ty>) { if ret.layout.is_aggregate() && ret.layout.size.bits() > 64 { ret.make_indirect(); } else { @@ -20,7 +20,7 @@ fn classify_ret_ty(ret: &mut ArgType) { } } -fn classify_arg_ty(arg: &mut ArgType) { +fn classify_arg_ty<Ty>(arg: &mut ArgType<Ty>) { if arg.layout.is_aggregate() && arg.layout.size.bits() > 64 { arg.make_indirect(); } else { @@ -28,7 +28,7 @@ fn classify_arg_ty(arg: &mut ArgType) { } } -pub fn compute_abi_info(fty: &mut FnType) { +pub fn compute_abi_info<Ty>(fty: &mut FnType<Ty>) { if !fty.ret.is_ignore() { classify_ret_ty(&mut fty.ret); } diff --git a/src/librustc_trans/cabi_mips.rs b/src/librustc_target/abi/call/mips.rs index cd567f517fe..5001499ea5d 100644 --- a/src/librustc_trans/cabi_mips.rs +++ b/src/librustc_target/abi/call/mips.rs @@ -8,24 +8,24 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use abi::{ArgType, FnType, LayoutExt, Reg, Uniform}; -use context::CodegenCx; +use abi::call::{ArgType, FnType, Reg, Uniform}; +use abi::{HasDataLayout, LayoutOf, Size, TyLayoutMethods}; -use rustc::ty::layout::Size; - -fn classify_ret_ty<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, - ret: &mut ArgType<'tcx>, - offset: &mut Size) { +fn classify_ret_ty<'a, Ty, C>(cx: C, ret: &mut ArgType<Ty>, offset: &mut Size) + where Ty: TyLayoutMethods<'a, C>, C: LayoutOf<Ty = Ty> + HasDataLayout +{ if !ret.layout.is_aggregate() { ret.extend_integer_width_to(32); } else { ret.make_indirect(); - *offset += cx.tcx.data_layout.pointer_size; + *offset += cx.data_layout().pointer_size; } } -fn classify_arg_ty(cx: &CodegenCx, arg: &mut ArgType, offset: &mut Size) { - let dl = &cx.tcx.data_layout; +fn classify_arg_ty<'a, Ty, C>(cx: C, arg: &mut ArgType<Ty>, offset: &mut Size) + where Ty: TyLayoutMethods<'a, C>, C: LayoutOf<Ty = Ty> + HasDataLayout +{ + let dl = cx.data_layout(); let size = arg.layout.size; let align = arg.layout.align.max(dl.i32_align).min(dl.i64_align); @@ -44,7 +44,9 @@ fn classify_arg_ty(cx: &CodegenCx, arg: &mut ArgType, offset: &mut Size) { *offset = offset.abi_align(align) + size.abi_align(align); } -pub fn compute_abi_info<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, fty: &mut FnType<'tcx>) { +pub fn compute_abi_info<'a, Ty, C>(cx: C, fty: &mut FnType<Ty>) + where Ty: TyLayoutMethods<'a, C>, C: LayoutOf<Ty = Ty> + HasDataLayout +{ let mut offset = Size::from_bytes(0); if !fty.ret.is_ignore() { classify_ret_ty(cx, &mut fty.ret, &mut offset); diff --git a/src/librustc_trans/cabi_mips64.rs b/src/librustc_target/abi/call/mips64.rs index 231fe4c6edb..e5cbc6424a4 100644 --- a/src/librustc_trans/cabi_mips64.rs +++ b/src/librustc_target/abi/call/mips64.rs @@ -8,14 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use abi::{ArgAttribute, ArgType, CastTarget, FnType, LayoutExt, PassMode, Reg, RegKind, Uniform}; -use context::CodegenCx; -use rustc::ty::layout::{self, Size}; +use abi::call::{ArgAttribute, ArgType, CastTarget, FnType, PassMode, Reg, RegKind, Uniform}; +use abi::{self, HasDataLayout, LayoutOf, Size, TyLayout, TyLayoutMethods}; -fn extend_integer_width_mips(arg: &mut ArgType, bits: u64) { +fn extend_integer_width_mips<Ty>(arg: &mut ArgType<Ty>, bits: u64) { // Always sign extend u32 values on 64-bit mips - if let layout::Abi::Scalar(ref scalar) = arg.layout.abi { - if let layout::Int(i, signed) = scalar.value { + if let abi::Abi::Scalar(ref scalar) = arg.layout.abi { + if let abi::Int(i, signed) = scalar.value { if !signed && i.size().bits() == 32 { if let PassMode::Direct(ref mut attrs) = arg.mode { attrs.set(ArgAttribute::SExt); @@ -28,18 +27,24 @@ fn extend_integer_width_mips(arg: &mut ArgType, bits: u64) { arg.extend_integer_width_to(bits); } -fn float_reg<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, ret: &ArgType<'tcx>, i: usize) -> Option<Reg> { +fn float_reg<'a, Ty, C>(cx: C, ret: &ArgType<'a, Ty>, i: usize) -> Option<Reg> + where Ty: TyLayoutMethods<'a, C> + Copy, + C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout +{ match ret.layout.field(cx, i).abi { - layout::Abi::Scalar(ref scalar) => match scalar.value { - layout::F32 => Some(Reg::f32()), - layout::F64 => Some(Reg::f64()), + abi::Abi::Scalar(ref scalar) => match scalar.value { + abi::F32 => Some(Reg::f32()), + abi::F64 => Some(Reg::f64()), _ => None }, _ => None } } -fn classify_ret_ty<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, ret: &mut ArgType<'tcx>) { +fn classify_ret_ty<'a, Ty, C>(cx: C, ret: &mut ArgType<'a, Ty>) + where Ty: TyLayoutMethods<'a, C> + Copy, + C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout +{ if !ret.layout.is_aggregate() { extend_integer_width_mips(ret, 64); return; @@ -52,7 +57,7 @@ fn classify_ret_ty<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, ret: &mut ArgType<'tcx>) // use of float registers to structures (not unions) containing exactly one or two // float fields. - if let layout::FieldPlacement::Arbitrary { .. } = ret.layout.fields { + if let abi::FieldPlacement::Arbitrary { .. } = ret.layout.fields { if ret.layout.fields.count() == 1 { if let Some(reg) = float_reg(cx, ret, 0) { ret.cast_to(reg); @@ -78,27 +83,30 @@ fn classify_ret_ty<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, ret: &mut ArgType<'tcx>) } } -fn classify_arg_ty<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, arg: &mut ArgType<'tcx>) { +fn classify_arg_ty<'a, Ty, C>(cx: C, arg: &mut ArgType<'a, Ty>) + where Ty: TyLayoutMethods<'a, C> + Copy, + C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout +{ if !arg.layout.is_aggregate() { extend_integer_width_mips(arg, 64); return; } - let dl = &cx.tcx.data_layout; + let dl = cx.data_layout(); let size = arg.layout.size; let mut prefix = [None; 8]; let mut prefix_index = 0; match arg.layout.fields { - layout::FieldPlacement::Array { .. } => { + abi::FieldPlacement::Array { .. } => { // Arrays are passed indirectly arg.make_indirect(); return; } - layout::FieldPlacement::Union(_) => { + abi::FieldPlacement::Union(_) => { // Unions and are always treated as a series of 64-bit integer chunks }, - layout::FieldPlacement::Arbitrary { .. } => { + abi::FieldPlacement::Arbitrary { .. } => { // Structures are split up into a series of 64-bit integer chunks, but any aligned // doubles not part of another aggregate are passed as floats. let mut last_offset = Size::from_bytes(0); @@ -108,8 +116,8 @@ fn classify_arg_ty<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, arg: &mut ArgType<'tcx>) let offset = arg.layout.fields.offset(i); // We only care about aligned doubles - if let layout::Abi::Scalar(ref scalar) = field.abi { - if let layout::F64 = scalar.value { + if let abi::Abi::Scalar(ref scalar) = field.abi { + if let abi::F64 = scalar.value { if offset.is_abi_aligned(dl.f64_align) { // Insert enough integers to cover [last_offset, offset) assert!(last_offset.is_abi_aligned(dl.f64_align)); @@ -143,7 +151,10 @@ fn classify_arg_ty<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, arg: &mut ArgType<'tcx>) }); } -pub fn compute_abi_info<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, fty: &mut FnType<'tcx>) { +pub fn compute_abi_info<'a, Ty, C>(cx: C, fty: &mut FnType<'a, Ty>) + where Ty: TyLayoutMethods<'a, C> + Copy, + C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout +{ if !fty.ret.is_ignore() { classify_ret_ty(cx, &mut fty.ret); } diff --git a/src/librustc_target/abi/call/mod.rs b/src/librustc_target/abi/call/mod.rs new file mode 100644 index 00000000000..2d8996bb5ae --- /dev/null +++ b/src/librustc_target/abi/call/mod.rs @@ -0,0 +1,511 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use abi::{self, Abi, Align, FieldPlacement, Size}; +use abi::{HasDataLayout, LayoutOf, TyLayout, TyLayoutMethods}; +use spec::HasTargetSpec; + +mod aarch64; +mod arm; +mod asmjs; +mod hexagon; +mod mips; +mod mips64; +mod msp430; +mod nvptx; +mod nvptx64; +mod powerpc; +mod powerpc64; +mod s390x; +mod sparc; +mod sparc64; +mod x86; +mod x86_64; +mod x86_win64; +mod wasm32; + +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub enum PassMode { + /// Ignore the argument (useful for empty struct). + Ignore, + /// Pass the argument directly. + Direct(ArgAttributes), + /// Pass a pair's elements directly in two arguments. + Pair(ArgAttributes, ArgAttributes), + /// Pass the argument after casting it, to either + /// a single uniform or a pair of registers. + Cast(CastTarget), + /// Pass the argument indirectly via a hidden pointer. + Indirect(ArgAttributes), +} + +// Hack to disable non_upper_case_globals only for the bitflags! and not for the rest +// of this module +pub use self::attr_impl::ArgAttribute; + +#[allow(non_upper_case_globals)] +#[allow(unused)] +mod attr_impl { + // The subset of llvm::Attribute needed for arguments, packed into a bitfield. + bitflags! { + #[derive(Default)] + pub struct ArgAttribute: u16 { + const ByVal = 1 << 0; + const NoAlias = 1 << 1; + const NoCapture = 1 << 2; + const NonNull = 1 << 3; + const ReadOnly = 1 << 4; + const SExt = 1 << 5; + const StructRet = 1 << 6; + const ZExt = 1 << 7; + const InReg = 1 << 8; + } + } +} + +/// A compact representation of LLVM attributes (at least those relevant for this module) +/// that can be manipulated without interacting with LLVM's Attribute machinery. +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub struct ArgAttributes { + pub regular: ArgAttribute, + pub pointee_size: Size, + pub pointee_align: Option<Align> +} + +impl ArgAttributes { + pub fn new() -> Self { + ArgAttributes { + regular: ArgAttribute::default(), + pointee_size: Size::from_bytes(0), + pointee_align: None, + } + } + + pub fn set(&mut self, attr: ArgAttribute) -> &mut Self { + self.regular = self.regular | attr; + self + } + + pub fn contains(&self, attr: ArgAttribute) -> bool { + self.regular.contains(attr) + } +} + +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub enum RegKind { + Integer, + Float, + Vector +} + +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub struct Reg { + pub kind: RegKind, + pub size: Size, +} + +macro_rules! reg_ctor { + ($name:ident, $kind:ident, $bits:expr) => { + pub fn $name() -> Reg { + Reg { + kind: RegKind::$kind, + size: Size::from_bits($bits) + } + } + } +} + +impl Reg { + reg_ctor!(i8, Integer, 8); + reg_ctor!(i16, Integer, 16); + reg_ctor!(i32, Integer, 32); + reg_ctor!(i64, Integer, 64); + + reg_ctor!(f32, Float, 32); + reg_ctor!(f64, Float, 64); +} + +impl Reg { + pub fn align<C: HasDataLayout>(&self, cx: C) -> Align { + let dl = cx.data_layout(); + match self.kind { + RegKind::Integer => { + match self.size.bits() { + 1 => dl.i1_align, + 2...8 => dl.i8_align, + 9...16 => dl.i16_align, + 17...32 => dl.i32_align, + 33...64 => dl.i64_align, + 65...128 => dl.i128_align, + _ => panic!("unsupported integer: {:?}", self) + } + } + RegKind::Float => { + match self.size.bits() { + 32 => dl.f32_align, + 64 => dl.f64_align, + _ => panic!("unsupported float: {:?}", self) + } + } + RegKind::Vector => dl.vector_align(self.size) + } + } +} + +/// An argument passed entirely registers with the +/// same kind (e.g. HFA / HVA on PPC64 and AArch64). +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub struct Uniform { + pub unit: Reg, + + /// The total size of the argument, which can be: + /// * equal to `unit.size` (one scalar/vector) + /// * a multiple of `unit.size` (an array of scalar/vectors) + /// * if `unit.kind` is `Integer`, the last element + /// can be shorter, i.e. `{ i64, i64, i32 }` for + /// 64-bit integers with a total size of 20 bytes + pub total: Size, +} + +impl From<Reg> for Uniform { + fn from(unit: Reg) -> Uniform { + Uniform { + unit, + total: unit.size + } + } +} + +impl Uniform { + pub fn align<C: HasDataLayout>(&self, cx: C) -> Align { + self.unit.align(cx) + } +} + +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub struct CastTarget { + pub prefix: [Option<RegKind>; 8], + pub prefix_chunk: Size, + pub rest: Uniform, +} + +impl From<Reg> for CastTarget { + fn from(unit: Reg) -> CastTarget { + CastTarget::from(Uniform::from(unit)) + } +} + +impl From<Uniform> for CastTarget { + fn from(uniform: Uniform) -> CastTarget { + CastTarget { + prefix: [None; 8], + prefix_chunk: Size::from_bytes(0), + rest: uniform + } + } +} + +impl CastTarget { + pub fn pair(a: Reg, b: Reg) -> CastTarget { + CastTarget { + prefix: [Some(a.kind), None, None, None, None, None, None, None], + prefix_chunk: a.size, + rest: Uniform::from(b) + } + } + + pub fn size<C: HasDataLayout>(&self, cx: C) -> Size { + (self.prefix_chunk * self.prefix.iter().filter(|x| x.is_some()).count() as u64) + .abi_align(self.rest.align(cx)) + self.rest.total + } + + pub fn align<C: HasDataLayout>(&self, cx: C) -> Align { + self.prefix.iter() + .filter_map(|x| x.map(|kind| Reg { kind: kind, size: self.prefix_chunk }.align(cx))) + .fold(cx.data_layout().aggregate_align.max(self.rest.align(cx)), + |acc, align| acc.max(align)) + } +} + +impl<'a, Ty> TyLayout<'a, Ty> { + fn is_aggregate(&self) -> bool { + match self.abi { + Abi::Uninhabited | + Abi::Scalar(_) | + Abi::Vector { .. } => false, + Abi::ScalarPair(..) | + Abi::Aggregate { .. } => true + } + } + + fn homogeneous_aggregate<C>(&self, cx: C) -> Option<Reg> + where Ty: TyLayoutMethods<'a, C> + Copy, C: LayoutOf<Ty = Ty, TyLayout = Self> + Copy + { + match self.abi { + Abi::Uninhabited => None, + + // The primitive for this algorithm. + Abi::Scalar(ref scalar) => { + let kind = match scalar.value { + abi::Int(..) | + abi::Pointer => RegKind::Integer, + abi::F32 | + abi::F64 => RegKind::Float + }; + Some(Reg { + kind, + size: self.size + }) + } + + Abi::Vector { .. } => { + Some(Reg { + kind: RegKind::Vector, + size: self.size + }) + } + + Abi::ScalarPair(..) | + Abi::Aggregate { .. } => { + let mut total = Size::from_bytes(0); + let mut result = None; + + let is_union = match self.fields { + FieldPlacement::Array { count, .. } => { + if count > 0 { + return self.field(cx, 0).homogeneous_aggregate(cx); + } else { + return None; + } + } + FieldPlacement::Union(_) => true, + FieldPlacement::Arbitrary { .. } => false + }; + + for i in 0..self.fields.count() { + if !is_union && total != self.fields.offset(i) { + return None; + } + + let field = self.field(cx, i); + match (result, field.homogeneous_aggregate(cx)) { + // The field itself must be a homogeneous aggregate. + (_, None) => return None, + // If this is the first field, record the unit. + (None, Some(unit)) => { + result = Some(unit); + } + // For all following fields, the unit must be the same. + (Some(prev_unit), Some(unit)) => { + if prev_unit != unit { + return None; + } + } + } + + // Keep track of the offset (without padding). + let size = field.size; + if is_union { + total = total.max(size); + } else { + total += size; + } + } + + // There needs to be no padding. + if total != self.size { + None + } else { + result + } + } + } + } +} + +/// Information about how to pass an argument to, +/// or return a value from, a function, under some ABI. +#[derive(Debug)] +pub struct ArgType<'a, Ty> { + pub layout: TyLayout<'a, Ty>, + + /// Dummy argument, which is emitted before the real argument. + pub pad: Option<Reg>, + + pub mode: PassMode, +} + +impl<'a, Ty> ArgType<'a, Ty> { + pub fn new(layout: TyLayout<'a, Ty>) -> Self { + ArgType { + layout, + pad: None, + mode: PassMode::Direct(ArgAttributes::new()), + } + } + + pub fn make_indirect(&mut self) { + assert_eq!(self.mode, PassMode::Direct(ArgAttributes::new())); + + // Start with fresh attributes for the pointer. + let mut attrs = ArgAttributes::new(); + + // For non-immediate arguments the callee gets its own copy of + // the value on the stack, so there are no aliases. It's also + // program-invisible so can't possibly capture + attrs.set(ArgAttribute::NoAlias) + .set(ArgAttribute::NoCapture) + .set(ArgAttribute::NonNull); + attrs.pointee_size = self.layout.size; + // FIXME(eddyb) We should be doing this, but at least on + // i686-pc-windows-msvc, it results in wrong stack offsets. + // attrs.pointee_align = Some(self.layout.align); + + self.mode = PassMode::Indirect(attrs); + } + + pub fn make_indirect_byval(&mut self) { + self.make_indirect(); + match self.mode { + PassMode::Indirect(ref mut attrs) => { + attrs.set(ArgAttribute::ByVal); + } + _ => unreachable!() + } + } + + pub fn extend_integer_width_to(&mut self, bits: u64) { + // Only integers have signedness + if let Abi::Scalar(ref scalar) = self.layout.abi { + if let abi::Int(i, signed) = scalar.value { + if i.size().bits() < bits { + if let PassMode::Direct(ref mut attrs) = self.mode { + attrs.set(if signed { + ArgAttribute::SExt + } else { + ArgAttribute::ZExt + }); + } + } + } + } + } + + pub fn cast_to<T: Into<CastTarget>>(&mut self, target: T) { + assert_eq!(self.mode, PassMode::Direct(ArgAttributes::new())); + self.mode = PassMode::Cast(target.into()); + } + + pub fn pad_with(&mut self, reg: Reg) { + self.pad = Some(reg); + } + + pub fn is_indirect(&self) -> bool { + match self.mode { + PassMode::Indirect(_) => true, + _ => false + } + } + + pub fn is_ignore(&self) -> bool { + self.mode == PassMode::Ignore + } +} + +#[derive(Copy, Clone, PartialEq, Debug)] +pub enum Conv { + C, + + ArmAapcs, + + Msp430Intr, + + PtxKernel, + + X86Fastcall, + X86Intr, + X86Stdcall, + X86ThisCall, + X86VectorCall, + + X86_64SysV, + X86_64Win64, +} + +/// Metadata describing how the arguments to a native function +/// should be passed in order to respect the native ABI. +/// +/// I will do my best to describe this structure, but these +/// comments are reverse-engineered and may be inaccurate. -NDM +#[derive(Debug)] +pub struct FnType<'a, Ty> { + /// The LLVM types of each argument. + pub args: Vec<ArgType<'a, Ty>>, + + /// LLVM return type. + pub ret: ArgType<'a, Ty>, + + pub variadic: bool, + + pub conv: Conv, +} + +impl<'a, Ty> FnType<'a, Ty> { + pub fn adjust_for_cabi<C>(&mut self, cx: C, abi: ::spec::abi::Abi) -> Result<(), String> + where Ty: TyLayoutMethods<'a, C> + Copy, + C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout + HasTargetSpec + { + match &cx.target_spec().arch[..] { + "x86" => { + let flavor = if abi == ::spec::abi::Abi::Fastcall { + x86::Flavor::Fastcall + } else { + x86::Flavor::General + }; + x86::compute_abi_info(cx, self, flavor); + }, + "x86_64" => if abi == ::spec::abi::Abi::SysV64 { + x86_64::compute_abi_info(cx, self); + } else if abi == ::spec::abi::Abi::Win64 || cx.target_spec().options.is_like_windows { + x86_win64::compute_abi_info(self); + } else { + x86_64::compute_abi_info(cx, self); + }, + "aarch64" => aarch64::compute_abi_info(cx, self), + "arm" => arm::compute_abi_info(cx, self), + "mips" => mips::compute_abi_info(cx, self), + "mips64" => mips64::compute_abi_info(cx, self), + "powerpc" => powerpc::compute_abi_info(cx, self), + "powerpc64" => powerpc64::compute_abi_info(cx, self), + "s390x" => s390x::compute_abi_info(cx, self), + "asmjs" => asmjs::compute_abi_info(cx, self), + "wasm32" => { + if cx.target_spec().llvm_target.contains("emscripten") { + asmjs::compute_abi_info(cx, self) + } else { + wasm32::compute_abi_info(self) + } + } + "msp430" => msp430::compute_abi_info(self), + "sparc" => sparc::compute_abi_info(cx, self), + "sparc64" => sparc64::compute_abi_info(cx, self), + "nvptx" => nvptx::compute_abi_info(self), + "nvptx64" => nvptx64::compute_abi_info(self), + "hexagon" => hexagon::compute_abi_info(self), + a => return Err(format!("unrecognized arch \"{}\" in target specification", a)) + } + + if let PassMode::Indirect(ref mut attrs) = self.ret.mode { + attrs.set(ArgAttribute::StructRet); + } + + Ok(()) + } +} diff --git a/src/librustc_trans/cabi_msp430.rs b/src/librustc_target/abi/call/msp430.rs index d270886a19c..e57ca03da60 100644 --- a/src/librustc_trans/cabi_msp430.rs +++ b/src/librustc_target/abi/call/msp430.rs @@ -11,7 +11,7 @@ // Reference: MSP430 Embedded Application Binary Interface // http://www.ti.com/lit/an/slaa534/slaa534.pdf -use abi::{ArgType, FnType, LayoutExt}; +use abi::call::{ArgType, FnType}; // 3.5 Structures or Unions Passed and Returned by Reference // @@ -19,7 +19,7 @@ use abi::{ArgType, FnType, LayoutExt}; // returned by reference. To pass a structure or union by reference, the caller // places its address in the appropriate location: either in a register or on // the stack, according to its position in the argument list. (..)" -fn classify_ret_ty(ret: &mut ArgType) { +fn classify_ret_ty<Ty>(ret: &mut ArgType<Ty>) { if ret.layout.is_aggregate() && ret.layout.size.bits() > 32 { ret.make_indirect(); } else { @@ -27,7 +27,7 @@ fn classify_ret_ty(ret: &mut ArgType) { } } -fn classify_arg_ty(arg: &mut ArgType) { +fn classify_arg_ty<Ty>(arg: &mut ArgType<Ty>) { if arg.layout.is_aggregate() && arg.layout.size.bits() > 32 { arg.make_indirect(); } else { @@ -35,7 +35,7 @@ fn classify_arg_ty(arg: &mut ArgType) { } } -pub fn compute_abi_info(fty: &mut FnType) { +pub fn compute_abi_info<Ty>(fty: &mut FnType<Ty>) { if !fty.ret.is_ignore() { classify_ret_ty(&mut fty.ret); } diff --git a/src/librustc_trans/cabi_nvptx.rs b/src/librustc_target/abi/call/nvptx.rs index 69cfc690a9f..f23f7ddf2ab 100644 --- a/src/librustc_trans/cabi_nvptx.rs +++ b/src/librustc_target/abi/call/nvptx.rs @@ -11,9 +11,9 @@ // Reference: PTX Writer's Guide to Interoperability // http://docs.nvidia.com/cuda/ptx-writers-guide-to-interoperability -use abi::{ArgType, FnType, LayoutExt}; +use abi::call::{ArgType, FnType}; -fn classify_ret_ty(ret: &mut ArgType) { +fn classify_ret_ty<Ty>(ret: &mut ArgType<Ty>) { if ret.layout.is_aggregate() && ret.layout.size.bits() > 32 { ret.make_indirect(); } else { @@ -21,7 +21,7 @@ fn classify_ret_ty(ret: &mut ArgType) { } } -fn classify_arg_ty(arg: &mut ArgType) { +fn classify_arg_ty<Ty>(arg: &mut ArgType<Ty>) { if arg.layout.is_aggregate() && arg.layout.size.bits() > 32 { arg.make_indirect(); } else { @@ -29,7 +29,7 @@ fn classify_arg_ty(arg: &mut ArgType) { } } -pub fn compute_abi_info(fty: &mut FnType) { +pub fn compute_abi_info<Ty>(fty: &mut FnType<Ty>) { if !fty.ret.is_ignore() { classify_ret_ty(&mut fty.ret); } diff --git a/src/librustc_trans/cabi_nvptx64.rs b/src/librustc_target/abi/call/nvptx64.rs index 4d76c156038..4399a2fec6c 100644 --- a/src/librustc_trans/cabi_nvptx64.rs +++ b/src/librustc_target/abi/call/nvptx64.rs @@ -11,9 +11,9 @@ // Reference: PTX Writer's Guide to Interoperability // http://docs.nvidia.com/cuda/ptx-writers-guide-to-interoperability -use abi::{ArgType, FnType, LayoutExt}; +use abi::call::{ArgType, FnType}; -fn classify_ret_ty(ret: &mut ArgType) { +fn classify_ret_ty<Ty>(ret: &mut ArgType<Ty>) { if ret.layout.is_aggregate() && ret.layout.size.bits() > 64 { ret.make_indirect(); } else { @@ -21,7 +21,7 @@ fn classify_ret_ty(ret: &mut ArgType) { } } -fn classify_arg_ty(arg: &mut ArgType) { +fn classify_arg_ty<Ty>(arg: &mut ArgType<Ty>) { if arg.layout.is_aggregate() && arg.layout.size.bits() > 64 { arg.make_indirect(); } else { @@ -29,7 +29,7 @@ fn classify_arg_ty(arg: &mut ArgType) { } } -pub fn compute_abi_info(fty: &mut FnType) { +pub fn compute_abi_info<Ty>(fty: &mut FnType<Ty>) { if !fty.ret.is_ignore() { classify_ret_ty(&mut fty.ret); } diff --git a/src/librustc_trans/cabi_powerpc.rs b/src/librustc_target/abi/call/powerpc.rs index 1ea6e9b2695..8c3c2422d7f 100644 --- a/src/librustc_trans/cabi_powerpc.rs +++ b/src/librustc_target/abi/call/powerpc.rs @@ -8,24 +8,24 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use abi::{ArgType, FnType, LayoutExt, Reg, Uniform}; -use context::CodegenCx; +use abi::call::{ArgType, FnType, Reg, Uniform}; +use abi::{HasDataLayout, LayoutOf, Size, TyLayoutMethods}; -use rustc::ty::layout::Size; - -fn classify_ret_ty<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, - ret: &mut ArgType<'tcx>, - offset: &mut Size) { +fn classify_ret_ty<'a, Ty, C>(cx: C, ret: &mut ArgType<Ty>, offset: &mut Size) + where Ty: TyLayoutMethods<'a, C>, C: LayoutOf<Ty = Ty> + HasDataLayout +{ if !ret.layout.is_aggregate() { ret.extend_integer_width_to(32); } else { ret.make_indirect(); - *offset += cx.tcx.data_layout.pointer_size; + *offset += cx.data_layout().pointer_size; } } -fn classify_arg_ty(cx: &CodegenCx, arg: &mut ArgType, offset: &mut Size) { - let dl = &cx.tcx.data_layout; +fn classify_arg_ty<'a, Ty, C>(cx: C, arg: &mut ArgType<Ty>, offset: &mut Size) + where Ty: TyLayoutMethods<'a, C>, C: LayoutOf<Ty = Ty> + HasDataLayout +{ + let dl = cx.data_layout(); let size = arg.layout.size; let align = arg.layout.align.max(dl.i32_align).min(dl.i64_align); @@ -44,7 +44,9 @@ fn classify_arg_ty(cx: &CodegenCx, arg: &mut ArgType, offset: &mut Size) { *offset = offset.abi_align(align) + size.abi_align(align); } -pub fn compute_abi_info<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, fty: &mut FnType<'tcx>) { +pub fn compute_abi_info<'a, Ty, C>(cx: C, fty: &mut FnType<Ty>) + where Ty: TyLayoutMethods<'a, C>, C: LayoutOf<Ty = Ty> + HasDataLayout +{ let mut offset = Size::from_bytes(0); if !fty.ret.is_ignore() { classify_ret_ty(cx, &mut fty.ret, &mut offset); diff --git a/src/librustc_trans/cabi_powerpc64.rs b/src/librustc_target/abi/call/powerpc64.rs index c614cf3a5a9..0c5ec77a398 100644 --- a/src/librustc_trans/cabi_powerpc64.rs +++ b/src/librustc_target/abi/call/powerpc64.rs @@ -12,9 +12,8 @@ // Alignment of 128 bit types is not currently handled, this will // need to be fixed when PowerPC vector support is added. -use abi::{FnType, ArgType, LayoutExt, Reg, RegKind, Uniform}; -use context::CodegenCx; -use rustc::ty::layout; +use abi::call::{FnType, ArgType, Reg, RegKind, Uniform}; +use abi::{Align, Endian, HasDataLayout, LayoutOf, TyLayout, TyLayoutMethods}; #[derive(Debug, Clone, Copy, PartialEq)] enum ABI { @@ -23,10 +22,11 @@ enum ABI { } use self::ABI::*; -fn is_homogeneous_aggregate<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, - arg: &mut ArgType<'tcx>, - abi: ABI) - -> Option<Uniform> { +fn is_homogeneous_aggregate<'a, Ty, C>(cx: C, arg: &mut ArgType<'a, Ty>, abi: ABI) + -> Option<Uniform> + where Ty: TyLayoutMethods<'a, C> + Copy, + C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout +{ arg.layout.homogeneous_aggregate(cx).and_then(|unit| { // ELFv1 only passes one-member aggregates transparently. // ELFv2 passes up to eight uniquely addressable members. @@ -52,7 +52,10 @@ fn is_homogeneous_aggregate<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, }) } -fn classify_ret_ty<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, ret: &mut ArgType<'tcx>, abi: ABI) { +fn classify_ret_ty<'a, Ty, C>(cx: C, ret: &mut ArgType<'a, Ty>, abi: ABI) + where Ty: TyLayoutMethods<'a, C> + Copy, + C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout +{ if !ret.layout.is_aggregate() { ret.extend_integer_width_to(64); return; @@ -92,7 +95,10 @@ fn classify_ret_ty<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, ret: &mut ArgType<'tcx>, ret.make_indirect(); } -fn classify_arg_ty<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, arg: &mut ArgType<'tcx>, abi: ABI) { +fn classify_arg_ty<'a, Ty, C>(cx: C, arg: &mut ArgType<'a, Ty>, abi: ABI) + where Ty: TyLayoutMethods<'a, C> + Copy, + C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout +{ if !arg.layout.is_aggregate() { arg.extend_integer_width_to(64); return; @@ -112,7 +118,7 @@ fn classify_arg_ty<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, arg: &mut ArgType<'tcx>, if size.bits() <= 64 { (Reg { kind: RegKind::Integer, size }, size) } else { - let align = layout::Align::from_bits(64, 64).unwrap(); + let align = Align::from_bits(64, 64).unwrap(); (Reg::i64(), size.abi_align(align)) } }, @@ -128,11 +134,13 @@ fn classify_arg_ty<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, arg: &mut ArgType<'tcx>, }); } -pub fn compute_abi_info<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, fty: &mut FnType<'tcx>) { - let abi = match cx.sess().target.target.target_endian.as_str() { - "big" => ELFv1, - "little" => ELFv2, - _ => unimplemented!(), +pub fn compute_abi_info<'a, Ty, C>(cx: C, fty: &mut FnType<'a, Ty>) + where Ty: TyLayoutMethods<'a, C> + Copy, + C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout +{ + let abi = match cx.data_layout().endian { + Endian::Big => ELFv1, + Endian::Little => ELFv2, }; if !fty.ret.is_ignore() { diff --git a/src/librustc_trans/cabi_s390x.rs b/src/librustc_target/abi/call/s390x.rs index 5e817686def..3002a3c46c8 100644 --- a/src/librustc_trans/cabi_s390x.rs +++ b/src/librustc_target/abi/call/s390x.rs @@ -11,12 +11,12 @@ // FIXME: The assumes we're using the non-vector ABI, i.e. compiling // for a pre-z13 machine or using -mno-vx. -use abi::{FnType, ArgType, LayoutExt, Reg}; -use context::CodegenCx; +use abi::call::{FnType, ArgType, Reg}; +use abi::{self, HasDataLayout, LayoutOf, TyLayout, TyLayoutMethods}; -use rustc::ty::layout::{self, TyLayout}; - -fn classify_ret_ty(ret: &mut ArgType) { +fn classify_ret_ty<'a, Ty, C>(ret: &mut ArgType<Ty>) + where Ty: TyLayoutMethods<'a, C>, C: LayoutOf<Ty = Ty> + HasDataLayout +{ if !ret.layout.is_aggregate() && ret.layout.size.bits() <= 64 { ret.extend_integer_width_to(64); } else { @@ -24,16 +24,18 @@ fn classify_ret_ty(ret: &mut ArgType) { } } -fn is_single_fp_element<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, - layout: TyLayout<'tcx>) -> bool { +fn is_single_fp_element<'a, Ty, C>(cx: C, layout: TyLayout<'a, Ty>) -> bool + where Ty: TyLayoutMethods<'a, C>, + C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout +{ match layout.abi { - layout::Abi::Scalar(ref scalar) => { + abi::Abi::Scalar(ref scalar) => { match scalar.value { - layout::F32 | layout::F64 => true, + abi::F32 | abi::F64 => true, _ => false } } - layout::Abi::Aggregate { .. } => { + abi::Abi::Aggregate { .. } => { if layout.fields.count() == 1 && layout.fields.offset(0).bytes() == 0 { is_single_fp_element(cx, layout.field(cx, 0)) } else { @@ -44,7 +46,10 @@ fn is_single_fp_element<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, } } -fn classify_arg_ty<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, arg: &mut ArgType<'tcx>) { +fn classify_arg_ty<'a, Ty, C>(cx: C, arg: &mut ArgType<'a, Ty>) + where Ty: TyLayoutMethods<'a, C> + Copy, + C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout +{ if !arg.layout.is_aggregate() && arg.layout.size.bits() <= 64 { arg.extend_integer_width_to(64); return; @@ -67,7 +72,10 @@ fn classify_arg_ty<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, arg: &mut ArgType<'tcx>) } } -pub fn compute_abi_info<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, fty: &mut FnType<'tcx>) { +pub fn compute_abi_info<'a, Ty, C>(cx: C, fty: &mut FnType<'a, Ty>) + where Ty: TyLayoutMethods<'a, C> + Copy, + C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout +{ if !fty.ret.is_ignore() { classify_ret_ty(&mut fty.ret); } diff --git a/src/librustc_trans/cabi_sparc.rs b/src/librustc_target/abi/call/sparc.rs index cd567f517fe..5001499ea5d 100644 --- a/src/librustc_trans/cabi_sparc.rs +++ b/src/librustc_target/abi/call/sparc.rs @@ -8,24 +8,24 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use abi::{ArgType, FnType, LayoutExt, Reg, Uniform}; -use context::CodegenCx; +use abi::call::{ArgType, FnType, Reg, Uniform}; +use abi::{HasDataLayout, LayoutOf, Size, TyLayoutMethods}; -use rustc::ty::layout::Size; - -fn classify_ret_ty<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, - ret: &mut ArgType<'tcx>, - offset: &mut Size) { +fn classify_ret_ty<'a, Ty, C>(cx: C, ret: &mut ArgType<Ty>, offset: &mut Size) + where Ty: TyLayoutMethods<'a, C>, C: LayoutOf<Ty = Ty> + HasDataLayout +{ if !ret.layout.is_aggregate() { ret.extend_integer_width_to(32); } else { ret.make_indirect(); - *offset += cx.tcx.data_layout.pointer_size; + *offset += cx.data_layout().pointer_size; } } -fn classify_arg_ty(cx: &CodegenCx, arg: &mut ArgType, offset: &mut Size) { - let dl = &cx.tcx.data_layout; +fn classify_arg_ty<'a, Ty, C>(cx: C, arg: &mut ArgType<Ty>, offset: &mut Size) + where Ty: TyLayoutMethods<'a, C>, C: LayoutOf<Ty = Ty> + HasDataLayout +{ + let dl = cx.data_layout(); let size = arg.layout.size; let align = arg.layout.align.max(dl.i32_align).min(dl.i64_align); @@ -44,7 +44,9 @@ fn classify_arg_ty(cx: &CodegenCx, arg: &mut ArgType, offset: &mut Size) { *offset = offset.abi_align(align) + size.abi_align(align); } -pub fn compute_abi_info<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, fty: &mut FnType<'tcx>) { +pub fn compute_abi_info<'a, Ty, C>(cx: C, fty: &mut FnType<Ty>) + where Ty: TyLayoutMethods<'a, C>, C: LayoutOf<Ty = Ty> + HasDataLayout +{ let mut offset = Size::from_bytes(0); if !fty.ret.is_ignore() { classify_ret_ty(cx, &mut fty.ret, &mut offset); diff --git a/src/librustc_trans/cabi_sparc64.rs b/src/librustc_target/abi/call/sparc64.rs index b3fc6a68061..987f56e6f98 100644 --- a/src/librustc_trans/cabi_sparc64.rs +++ b/src/librustc_target/abi/call/sparc64.rs @@ -10,11 +10,14 @@ // FIXME: This needs an audit for correctness and completeness. -use abi::{FnType, ArgType, LayoutExt, Reg, RegKind, Uniform}; -use context::CodegenCx; +use abi::call::{FnType, ArgType, Reg, RegKind, Uniform}; +use abi::{HasDataLayout, LayoutOf, TyLayout, TyLayoutMethods}; -fn is_homogeneous_aggregate<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, arg: &mut ArgType<'tcx>) - -> Option<Uniform> { +fn is_homogeneous_aggregate<'a, Ty, C>(cx: C, arg: &mut ArgType<'a, Ty>) + -> Option<Uniform> + where Ty: TyLayoutMethods<'a, C> + Copy, + C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout +{ arg.layout.homogeneous_aggregate(cx).and_then(|unit| { // Ensure we have at most eight uniquely addressable members. if arg.layout.size > unit.size.checked_mul(8, cx).unwrap() { @@ -38,7 +41,10 @@ fn is_homogeneous_aggregate<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, arg: &mut ArgTyp }) } -fn classify_ret_ty<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, ret: &mut ArgType<'tcx>) { +fn classify_ret_ty<'a, Ty, C>(cx: C, ret: &mut ArgType<'a, Ty>) + where Ty: TyLayoutMethods<'a, C> + Copy, + C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout +{ if !ret.layout.is_aggregate() { ret.extend_integer_width_to(64); return; @@ -72,7 +78,10 @@ fn classify_ret_ty<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, ret: &mut ArgType<'tcx>) ret.make_indirect(); } -fn classify_arg_ty<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, arg: &mut ArgType<'tcx>) { +fn classify_arg_ty<'a, Ty, C>(cx: C, arg: &mut ArgType<'a, Ty>) + where Ty: TyLayoutMethods<'a, C> + Copy, + C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout +{ if !arg.layout.is_aggregate() { arg.extend_integer_width_to(64); return; @@ -95,7 +104,10 @@ fn classify_arg_ty<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, arg: &mut ArgType<'tcx>) }); } -pub fn compute_abi_info<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, fty: &mut FnType<'tcx>) { +pub fn compute_abi_info<'a, Ty, C>(cx: C, fty: &mut FnType<'a, Ty>) + where Ty: TyLayoutMethods<'a, C> + Copy, + C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout +{ if !fty.ret.is_ignore() { classify_ret_ty(cx, &mut fty.ret); } diff --git a/src/librustc_trans/cabi_wasm32.rs b/src/librustc_target/abi/call/wasm32.rs index 5530a03d65d..7109eea535d 100644 --- a/src/librustc_trans/cabi_wasm32.rs +++ b/src/librustc_target/abi/call/wasm32.rs @@ -8,20 +8,19 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use abi::{FnType, ArgType}; -use context::CodegenCx; +use abi::call::{FnType, ArgType}; -fn classify_ret_ty<'a, 'tcx>(_cx: &CodegenCx<'a, 'tcx>, ret: &mut ArgType<'tcx>) { +fn classify_ret_ty<Ty>(ret: &mut ArgType<Ty>) { ret.extend_integer_width_to(32); } -fn classify_arg_ty(arg: &mut ArgType) { +fn classify_arg_ty<Ty>(arg: &mut ArgType<Ty>) { arg.extend_integer_width_to(32); } -pub fn compute_abi_info<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, fty: &mut FnType<'tcx>) { +pub fn compute_abi_info<Ty>(fty: &mut FnType<Ty>) { if !fty.ret.is_ignore() { - classify_ret_ty(cx, &mut fty.ret); + classify_ret_ty(&mut fty.ret); } for arg in &mut fty.args { diff --git a/src/librustc_trans/cabi_x86.rs b/src/librustc_target/abi/call/x86.rs index b1455844806..e803b96b21c 100644 --- a/src/librustc_trans/cabi_x86.rs +++ b/src/librustc_target/abi/call/x86.rs @@ -8,10 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use abi::{ArgAttribute, FnType, LayoutExt, PassMode, Reg, RegKind}; -use common::CodegenCx; - -use rustc::ty::layout::{self, TyLayout}; +use abi::call::{ArgAttribute, FnType, PassMode, Reg, RegKind}; +use abi::{self, HasDataLayout, LayoutOf, TyLayout, TyLayoutMethods}; +use spec::HasTargetSpec; #[derive(PartialEq)] pub enum Flavor { @@ -19,16 +18,18 @@ pub enum Flavor { Fastcall } -fn is_single_fp_element<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, - layout: TyLayout<'tcx>) -> bool { +fn is_single_fp_element<'a, Ty, C>(cx: C, layout: TyLayout<'a, Ty>) -> bool + where Ty: TyLayoutMethods<'a, C> + Copy, + C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout +{ match layout.abi { - layout::Abi::Scalar(ref scalar) => { + abi::Abi::Scalar(ref scalar) => { match scalar.value { - layout::F32 | layout::F64 => true, + abi::F32 | abi::F64 => true, _ => false } } - layout::Abi::Aggregate { .. } => { + abi::Abi::Aggregate { .. } => { if layout.fields.count() == 1 && layout.fields.offset(0).bytes() == 0 { is_single_fp_element(cx, layout.field(cx, 0)) } else { @@ -39,9 +40,10 @@ fn is_single_fp_element<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, } } -pub fn compute_abi_info<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, - fty: &mut FnType<'tcx>, - flavor: Flavor) { +pub fn compute_abi_info<'a, Ty, C>(cx: C, fty: &mut FnType<'a, Ty>, flavor: Flavor) + where Ty: TyLayoutMethods<'a, C> + Copy, + C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout + HasTargetSpec +{ if !fty.ret.is_ignore() { if fty.ret.layout.is_aggregate() { // Returning a structure. Most often, this will use @@ -51,7 +53,7 @@ pub fn compute_abi_info<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, // Some links: // http://www.angelcode.com/dev/callconv/callconv.html // Clang's ABI handling is in lib/CodeGen/TargetInfo.cpp - let t = &cx.sess().target.target; + let t = cx.target_spec(); if t.options.abi_return_struct_as_int { // According to Clang, everyone but MSVC returns single-element // float aggregates directly in a floating-point register. @@ -106,7 +108,7 @@ pub fn compute_abi_info<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, PassMode::Direct(ref mut attrs) => attrs, PassMode::Pair(..) | PassMode::Cast(_) => { - bug!("x86 shouldn't be passing arguments by {:?}", arg.mode) + unreachable!("x86 shouldn't be passing arguments by {:?}", arg.mode) } }; diff --git a/src/librustc_trans/cabi_x86_64.rs b/src/librustc_target/abi/call/x86_64.rs index 7eadaa7f493..0ba1ee736e7 100644 --- a/src/librustc_trans/cabi_x86_64.rs +++ b/src/librustc_target/abi/call/x86_64.rs @@ -11,10 +11,8 @@ // The classification code for the x86_64 ABI is taken from the clay language // https://github.com/jckarter/clay/blob/master/compiler/src/externals.cpp -use abi::{ArgType, CastTarget, FnType, LayoutExt, Reg, RegKind}; -use context::CodegenCx; - -use rustc::ty::layout::{self, TyLayout, Size}; +use abi::call::{ArgType, CastTarget, FnType, Reg, RegKind}; +use abi::{self, Abi, HasDataLayout, LayoutOf, Size, TyLayout, TyLayoutMethods}; /// Classification of "eightbyte" components. // NB: the order of the variants is from general to specific, @@ -33,13 +31,16 @@ struct Memory; const LARGEST_VECTOR_SIZE: usize = 512; const MAX_EIGHTBYTES: usize = LARGEST_VECTOR_SIZE / 64; -fn classify_arg<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, arg: &ArgType<'tcx>) - -> Result<[Option<Class>; MAX_EIGHTBYTES], Memory> { - fn classify<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, - layout: TyLayout<'tcx>, - cls: &mut [Option<Class>], - off: Size) - -> Result<(), Memory> { +fn classify_arg<'a, Ty, C>(cx: C, arg: &ArgType<'a, Ty>) + -> Result<[Option<Class>; MAX_EIGHTBYTES], Memory> + where Ty: TyLayoutMethods<'a, C> + Copy, + C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout +{ + fn classify<'a, Ty, C>(cx: C, layout: TyLayout<'a, Ty>, + cls: &mut [Option<Class>], off: Size) -> Result<(), Memory> + where Ty: TyLayoutMethods<'a, C> + Copy, + C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout + { if !off.is_abi_aligned(layout.align) { if !layout.is_zst() { return Err(Memory); @@ -48,31 +49,31 @@ fn classify_arg<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, arg: &ArgType<'tcx>) } let mut c = match layout.abi { - layout::Abi::Uninhabited => return Ok(()), + Abi::Uninhabited => return Ok(()), - layout::Abi::Scalar(ref scalar) => { + Abi::Scalar(ref scalar) => { match scalar.value { - layout::Int(..) | - layout::Pointer => Class::Int, - layout::F32 | - layout::F64 => Class::Sse + abi::Int(..) | + abi::Pointer => Class::Int, + abi::F32 | + abi::F64 => Class::Sse } } - layout::Abi::Vector { .. } => Class::Sse, + Abi::Vector { .. } => Class::Sse, - layout::Abi::ScalarPair(..) | - layout::Abi::Aggregate { .. } => { + Abi::ScalarPair(..) | + Abi::Aggregate { .. } => { match layout.variants { - layout::Variants::Single { .. } => { + abi::Variants::Single { .. } => { for i in 0..layout.fields.count() { let field_off = off + layout.fields.offset(i); classify(cx, layout.field(cx, i), cls, field_off)?; } return Ok(()); } - layout::Variants::Tagged { .. } | - layout::Variants::NicheFilling { .. } => return Err(Memory), + abi::Variants::Tagged { .. } | + abi::Variants::NicheFilling { .. } => return Err(Memory), } } @@ -160,7 +161,7 @@ fn reg_component(cls: &[Option<Class>], i: &mut usize, size: Size) -> Option<Reg } }) } - Some(c) => bug!("reg_component: unhandled class {:?}", c) + Some(c) => unreachable!("reg_component: unhandled class {:?}", c) } } @@ -178,11 +179,14 @@ fn cast_target(cls: &[Option<Class>], size: Size) -> CastTarget { target } -pub fn compute_abi_info<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, fty: &mut FnType<'tcx>) { +pub fn compute_abi_info<'a, Ty, C>(cx: C, fty: &mut FnType<'a, Ty>) + where Ty: TyLayoutMethods<'a, C> + Copy, + C: LayoutOf<Ty = Ty, TyLayout = TyLayout<'a, Ty>> + HasDataLayout +{ let mut int_regs = 6; // RDI, RSI, RDX, RCX, R8, R9 let mut sse_regs = 8; // XMM0-7 - let mut x86_64_ty = |arg: &mut ArgType<'tcx>, is_arg: bool| { + let mut x86_64_ty = |arg: &mut ArgType<'a, Ty>, is_arg: bool| { let mut cls_or_mem = classify_arg(cx, arg); let mut needed_int = 0; diff --git a/src/librustc_trans/cabi_x86_win64.rs b/src/librustc_target/abi/call/x86_win64.rs index eb5ec403490..1ee069e2bbb 100644 --- a/src/librustc_trans/cabi_x86_win64.rs +++ b/src/librustc_target/abi/call/x86_win64.rs @@ -8,18 +8,17 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use abi::{ArgType, FnType, Reg}; - -use rustc::ty::layout; +use abi::call::{ArgType, FnType, Reg}; +use abi::Abi; // Win64 ABI: http://msdn.microsoft.com/en-us/library/zthk2dkh.aspx -pub fn compute_abi_info(fty: &mut FnType) { - let fixup = |a: &mut ArgType| { +pub fn compute_abi_info<Ty>(fty: &mut FnType<Ty>) { + let fixup = |a: &mut ArgType<Ty>| { match a.layout.abi { - layout::Abi::Uninhabited => {} - layout::Abi::ScalarPair(..) | - layout::Abi::Aggregate { .. } => { + Abi::Uninhabited => {} + Abi::ScalarPair(..) | + Abi::Aggregate { .. } => { match a.layout.size.bits() { 8 => a.cast_to(Reg::i8()), 16 => a.cast_to(Reg::i16()), @@ -28,11 +27,11 @@ pub fn compute_abi_info(fty: &mut FnType) { _ => a.make_indirect() } } - layout::Abi::Vector { .. } => { + Abi::Vector { .. } => { // FIXME(eddyb) there should be a size cap here // (probably what clang calls "illegal vectors"). } - layout::Abi::Scalar(_) => { + Abi::Scalar(_) => { if a.layout.size.bytes() > 8 { a.make_indirect(); } else { diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs new file mode 100644 index 00000000000..346e5667a7b --- /dev/null +++ b/src/librustc_target/abi/mod.rs @@ -0,0 +1,840 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub use self::Integer::*; +pub use self::Primitive::*; + +use spec::Target; + +use std::cmp; +use std::ops::{Add, Deref, Sub, Mul, AddAssign, Range, RangeInclusive}; + +pub mod call; + +/// Parsed [Data layout](http://llvm.org/docs/LangRef.html#data-layout) +/// for a target, which contains everything needed to compute layouts. +pub struct TargetDataLayout { + pub endian: Endian, + pub i1_align: Align, + pub i8_align: Align, + pub i16_align: Align, + pub i32_align: Align, + pub i64_align: Align, + pub i128_align: Align, + pub f32_align: Align, + pub f64_align: Align, + pub pointer_size: Size, + pub pointer_align: Align, + pub aggregate_align: Align, + + /// Alignments for vector types. + pub vector_align: Vec<(Size, Align)> +} + +impl Default for TargetDataLayout { + /// Creates an instance of `TargetDataLayout`. + fn default() -> TargetDataLayout { + TargetDataLayout { + endian: Endian::Big, + i1_align: Align::from_bits(8, 8).unwrap(), + i8_align: Align::from_bits(8, 8).unwrap(), + i16_align: Align::from_bits(16, 16).unwrap(), + i32_align: Align::from_bits(32, 32).unwrap(), + i64_align: Align::from_bits(32, 64).unwrap(), + i128_align: Align::from_bits(32, 64).unwrap(), + f32_align: Align::from_bits(32, 32).unwrap(), + f64_align: Align::from_bits(64, 64).unwrap(), + pointer_size: Size::from_bits(64), + pointer_align: Align::from_bits(64, 64).unwrap(), + aggregate_align: Align::from_bits(0, 64).unwrap(), + vector_align: vec![ + (Size::from_bits(64), Align::from_bits(64, 64).unwrap()), + (Size::from_bits(128), Align::from_bits(128, 128).unwrap()) + ] + } + } +} + +impl TargetDataLayout { + pub fn parse(target: &Target) -> Result<TargetDataLayout, String> { + // Parse a bit count from a string. + let parse_bits = |s: &str, kind: &str, cause: &str| { + s.parse::<u64>().map_err(|err| { + format!("invalid {} `{}` for `{}` in \"data-layout\": {}", + kind, s, cause, err) + }) + }; + + // Parse a size string. + let size = |s: &str, cause: &str| { + parse_bits(s, "size", cause).map(Size::from_bits) + }; + + // Parse an alignment string. + let align = |s: &[&str], cause: &str| { + if s.is_empty() { + return Err(format!("missing alignment for `{}` in \"data-layout\"", cause)); + } + let abi = parse_bits(s[0], "alignment", cause)?; + let pref = s.get(1).map_or(Ok(abi), |pref| parse_bits(pref, "alignment", cause))?; + Align::from_bits(abi, pref).map_err(|err| { + format!("invalid alignment for `{}` in \"data-layout\": {}", + cause, err) + }) + }; + + let mut dl = TargetDataLayout::default(); + let mut i128_align_src = 64; + for spec in target.data_layout.split("-") { + match &spec.split(":").collect::<Vec<_>>()[..] { + &["e"] => dl.endian = Endian::Little, + &["E"] => dl.endian = Endian::Big, + &["a", ref a..] => dl.aggregate_align = align(a, "a")?, + &["f32", ref a..] => dl.f32_align = align(a, "f32")?, + &["f64", ref a..] => dl.f64_align = align(a, "f64")?, + &[p @ "p", s, ref a..] | &[p @ "p0", s, ref a..] => { + dl.pointer_size = size(s, p)?; + dl.pointer_align = align(a, p)?; + } + &[s, ref a..] if s.starts_with("i") => { + let bits = match s[1..].parse::<u64>() { + Ok(bits) => bits, + Err(_) => { + size(&s[1..], "i")?; // For the user error. + continue; + } + }; + let a = align(a, s)?; + match bits { + 1 => dl.i1_align = a, + 8 => dl.i8_align = a, + 16 => dl.i16_align = a, + 32 => dl.i32_align = a, + 64 => dl.i64_align = a, + _ => {} + } + if bits >= i128_align_src && bits <= 128 { + // Default alignment for i128 is decided by taking the alignment of + // largest-sized i{64...128}. + i128_align_src = bits; + dl.i128_align = a; + } + } + &[s, ref a..] if s.starts_with("v") => { + let v_size = size(&s[1..], "v")?; + let a = align(a, s)?; + if let Some(v) = dl.vector_align.iter_mut().find(|v| v.0 == v_size) { + v.1 = a; + continue; + } + // No existing entry, add a new one. + dl.vector_align.push((v_size, a)); + } + _ => {} // Ignore everything else. + } + } + + // Perform consistency checks against the Target information. + let endian_str = match dl.endian { + Endian::Little => "little", + Endian::Big => "big" + }; + if endian_str != target.target_endian { + return Err(format!("inconsistent target specification: \"data-layout\" claims \ + architecture is {}-endian, while \"target-endian\" is `{}`", + endian_str, target.target_endian)); + } + + if dl.pointer_size.bits().to_string() != target.target_pointer_width { + return Err(format!("inconsistent target specification: \"data-layout\" claims \ + pointers are {}-bit, while \"target-pointer-width\" is `{}`", + dl.pointer_size.bits(), target.target_pointer_width)); + } + + Ok(dl) + } + + /// Return exclusive upper bound on object size. + /// + /// The theoretical maximum object size is defined as the maximum positive `isize` value. + /// This ensures that the `offset` semantics remain well-defined by allowing it to correctly + /// index every address within an object along with one byte past the end, along with allowing + /// `isize` to store the difference between any two pointers into an object. + /// + /// The upper bound on 64-bit currently needs to be lower because LLVM uses a 64-bit integer + /// to represent object size in bits. It would need to be 1 << 61 to account for this, but is + /// currently conservatively bounded to 1 << 47 as that is enough to cover the current usable + /// address space on 64-bit ARMv8 and x86_64. + pub fn obj_size_bound(&self) -> u64 { + match self.pointer_size.bits() { + 16 => 1 << 15, + 32 => 1 << 31, + 64 => 1 << 47, + bits => panic!("obj_size_bound: unknown pointer bit size {}", bits) + } + } + + pub fn ptr_sized_integer(&self) -> Integer { + match self.pointer_size.bits() { + 16 => I16, + 32 => I32, + 64 => I64, + bits => panic!("ptr_sized_integer: unknown pointer bit size {}", bits) + } + } + + pub fn vector_align(&self, vec_size: Size) -> Align { + for &(size, align) in &self.vector_align { + if size == vec_size { + return align; + } + } + // Default to natural alignment, which is what LLVM does. + // That is, use the size, rounded up to a power of 2. + let align = vec_size.bytes().next_power_of_two(); + Align::from_bytes(align, align).unwrap() + } +} + +pub trait HasDataLayout: Copy { + fn data_layout(&self) -> &TargetDataLayout; +} + +impl<'a> HasDataLayout for &'a TargetDataLayout { + fn data_layout(&self) -> &TargetDataLayout { + self + } +} + +/// Endianness of the target, which must match cfg(target-endian). +#[derive(Copy, Clone)] +pub enum Endian { + Little, + Big +} + +/// Size of a type in bytes. +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +pub struct Size { + raw: u64 +} + +impl Size { + pub fn from_bits(bits: u64) -> Size { + // Avoid potential overflow from `bits + 7`. + Size::from_bytes(bits / 8 + ((bits % 8) + 7) / 8) + } + + pub fn from_bytes(bytes: u64) -> Size { + if bytes >= (1 << 61) { + panic!("Size::from_bytes: {} bytes in bits doesn't fit in u64", bytes) + } + Size { + raw: bytes + } + } + + pub fn bytes(self) -> u64 { + self.raw + } + + pub fn bits(self) -> u64 { + self.bytes() * 8 + } + + pub fn abi_align(self, align: Align) -> Size { + let mask = align.abi() - 1; + Size::from_bytes((self.bytes() + mask) & !mask) + } + + pub fn is_abi_aligned(self, align: Align) -> bool { + let mask = align.abi() - 1; + self.bytes() & mask == 0 + } + + pub fn checked_add<C: HasDataLayout>(self, offset: Size, cx: C) -> Option<Size> { + let dl = cx.data_layout(); + + // Each Size is less than dl.obj_size_bound(), so the sum is + // also less than 1 << 62 (and therefore can't overflow). + let bytes = self.bytes() + offset.bytes(); + + if bytes < dl.obj_size_bound() { + Some(Size::from_bytes(bytes)) + } else { + None + } + } + + pub fn checked_mul<C: HasDataLayout>(self, count: u64, cx: C) -> Option<Size> { + let dl = cx.data_layout(); + + match self.bytes().checked_mul(count) { + Some(bytes) if bytes < dl.obj_size_bound() => { + Some(Size::from_bytes(bytes)) + } + _ => None + } + } +} + +// Panicking addition, subtraction and multiplication for convenience. +// Avoid during layout computation, return `LayoutError` instead. + +impl Add for Size { + type Output = Size; + fn add(self, other: Size) -> Size { + // Each Size is less than 1 << 61, so the sum is + // less than 1 << 62 (and therefore can't overflow). + Size::from_bytes(self.bytes() + other.bytes()) + } +} + +impl Sub for Size { + type Output = Size; + fn sub(self, other: Size) -> Size { + // Each Size is less than 1 << 61, so an underflow + // would result in a value larger than 1 << 61, + // which Size::from_bytes will catch for us. + Size::from_bytes(self.bytes() - other.bytes()) + } +} + +impl Mul<u64> for Size { + type Output = Size; + fn mul(self, count: u64) -> Size { + match self.bytes().checked_mul(count) { + Some(bytes) => Size::from_bytes(bytes), + None => { + panic!("Size::mul: {} * {} doesn't fit in u64", self.bytes(), count) + } + } + } +} + +impl AddAssign for Size { + fn add_assign(&mut self, other: Size) { + *self = *self + other; + } +} + +/// Alignment of a type in bytes, both ABI-mandated and preferred. +/// Each field is a power of two, giving the alignment a maximum value of +/// 2<sup>(2<sup>8</sup> - 1)</sup>, which is limited by LLVM to a i32, +/// with a maximum capacity of 2<sup>31</sup> - 1 or 2147483647. +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] +pub struct Align { + abi_pow2: u8, + pref_pow2: u8, +} + +impl Align { + pub fn from_bits(abi: u64, pref: u64) -> Result<Align, String> { + Align::from_bytes(Size::from_bits(abi).bytes(), + Size::from_bits(pref).bytes()) + } + + pub fn from_bytes(abi: u64, pref: u64) -> Result<Align, String> { + let log2 = |align: u64| { + // Treat an alignment of 0 bytes like 1-byte alignment. + if align == 0 { + return Ok(0); + } + + let mut bytes = align; + let mut pow: u8 = 0; + while (bytes & 1) == 0 { + pow += 1; + bytes >>= 1; + } + if bytes != 1 { + Err(format!("`{}` is not a power of 2", align)) + } else if pow > 30 { + Err(format!("`{}` is too large", align)) + } else { + Ok(pow) + } + }; + + Ok(Align { + abi_pow2: log2(abi)?, + pref_pow2: log2(pref)?, + }) + } + + pub fn abi(self) -> u64 { + 1 << self.abi_pow2 + } + + pub fn pref(self) -> u64 { + 1 << self.pref_pow2 + } + + pub fn abi_bits(self) -> u64 { + self.abi() * 8 + } + + pub fn pref_bits(self) -> u64 { + self.pref() * 8 + } + + pub fn min(self, other: Align) -> Align { + Align { + abi_pow2: cmp::min(self.abi_pow2, other.abi_pow2), + pref_pow2: cmp::min(self.pref_pow2, other.pref_pow2), + } + } + + pub fn max(self, other: Align) -> Align { + Align { + abi_pow2: cmp::max(self.abi_pow2, other.abi_pow2), + pref_pow2: cmp::max(self.pref_pow2, other.pref_pow2), + } + } +} + +/// Integers, also used for enum discriminants. +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +pub enum Integer { + I8, + I16, + I32, + I64, + I128, +} + +impl Integer { + pub fn size(&self) -> Size { + match *self { + I8 => Size::from_bytes(1), + I16 => Size::from_bytes(2), + I32 => Size::from_bytes(4), + I64 => Size::from_bytes(8), + I128 => Size::from_bytes(16), + } + } + + pub fn align<C: HasDataLayout>(&self, cx: C) -> Align { + let dl = cx.data_layout(); + + match *self { + I8 => dl.i8_align, + I16 => dl.i16_align, + I32 => dl.i32_align, + I64 => dl.i64_align, + I128 => dl.i128_align, + } + } + + /// Find the smallest Integer type which can represent the signed value. + pub fn fit_signed(x: i128) -> Integer { + match x { + -0x0000_0000_0000_0080...0x0000_0000_0000_007f => I8, + -0x0000_0000_0000_8000...0x0000_0000_0000_7fff => I16, + -0x0000_0000_8000_0000...0x0000_0000_7fff_ffff => I32, + -0x8000_0000_0000_0000...0x7fff_ffff_ffff_ffff => I64, + _ => I128 + } + } + + /// Find the smallest Integer type which can represent the unsigned value. + pub fn fit_unsigned(x: u128) -> Integer { + match x { + 0...0x0000_0000_0000_00ff => I8, + 0...0x0000_0000_0000_ffff => I16, + 0...0x0000_0000_ffff_ffff => I32, + 0...0xffff_ffff_ffff_ffff => I64, + _ => I128, + } + } + + /// Find the smallest integer with the given alignment. + pub fn for_abi_align<C: HasDataLayout>(cx: C, align: Align) -> Option<Integer> { + let dl = cx.data_layout(); + + let wanted = align.abi(); + for &candidate in &[I8, I16, I32, I64, I128] { + if wanted == candidate.align(dl).abi() && wanted == candidate.size().bytes() { + return Some(candidate); + } + } + None + } + + /// Find the largest integer with the given alignment or less. + pub fn approximate_abi_align<C: HasDataLayout>(cx: C, align: Align) -> Integer { + let dl = cx.data_layout(); + + let wanted = align.abi(); + // FIXME(eddyb) maybe include I128 in the future, when it works everywhere. + for &candidate in &[I64, I32, I16] { + if wanted >= candidate.align(dl).abi() && wanted >= candidate.size().bytes() { + return candidate; + } + } + I8 + } +} + +/// Fundamental unit of memory access and layout. +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +pub enum Primitive { + /// The `bool` is the signedness of the `Integer` type. + /// + /// One would think we would not care about such details this low down, + /// but some ABIs are described in terms of C types and ISAs where the + /// integer arithmetic is done on {sign,zero}-extended registers, e.g. + /// a negative integer passed by zero-extension will appear positive in + /// the callee, and most operations on it will produce the wrong values. + Int(Integer, bool), + F32, + F64, + Pointer +} + +impl<'a, 'tcx> Primitive { + pub fn size<C: HasDataLayout>(self, cx: C) -> Size { + let dl = cx.data_layout(); + + match self { + Int(i, _) => i.size(), + F32 => Size::from_bits(32), + F64 => Size::from_bits(64), + Pointer => dl.pointer_size + } + } + + pub fn align<C: HasDataLayout>(self, cx: C) -> Align { + let dl = cx.data_layout(); + + match self { + Int(i, _) => i.align(dl), + F32 => dl.f32_align, + F64 => dl.f64_align, + Pointer => dl.pointer_align + } + } +} + +/// Information about one scalar component of a Rust type. +#[derive(Clone, PartialEq, Eq, Hash, Debug)] +pub struct Scalar { + pub value: Primitive, + + /// Inclusive wrap-around range of valid values, that is, if + /// min > max, it represents min..=u128::MAX followed by 0..=max. + // FIXME(eddyb) always use the shortest range, e.g. by finding + // the largest space between two consecutive valid values and + // taking everything else as the (shortest) valid range. + pub valid_range: RangeInclusive<u128>, +} + +impl Scalar { + pub fn is_bool(&self) -> bool { + if let Int(I8, _) = self.value { + self.valid_range == (0..=1) + } else { + false + } + } + + /// Returns the valid range as a `x..y` range. + /// + /// If `x` and `y` are equal, the range is full, not empty. + pub fn valid_range_exclusive<C: HasDataLayout>(&self, cx: C) -> Range<u128> { + // For a (max) value of -1, max will be `-1 as usize`, which overflows. + // However, that is fine here (it would still represent the full range), + // i.e., if the range is everything. + let bits = self.value.size(cx).bits(); + assert!(bits <= 128); + let mask = !0u128 >> (128 - bits); + let start = self.valid_range.start; + let end = self.valid_range.end; + assert_eq!(start, start & mask); + assert_eq!(end, end & mask); + start..(end.wrapping_add(1) & mask) + } +} + +/// Describes how the fields of a type are located in memory. +#[derive(PartialEq, Eq, Hash, Debug)] +pub enum FieldPlacement { + /// All fields start at no offset. The `usize` is the field count. + Union(usize), + + /// Array/vector-like placement, with all fields of identical types. + Array { + stride: Size, + count: u64 + }, + + /// Struct-like placement, with precomputed offsets. + /// + /// Fields are guaranteed to not overlap, but note that gaps + /// before, between and after all the fields are NOT always + /// padding, and as such their contents may not be discarded. + /// For example, enum variants leave a gap at the start, + /// where the discriminant field in the enum layout goes. + Arbitrary { + /// Offsets for the first byte of each field, + /// ordered to match the source definition order. + /// This vector does not go in increasing order. + // FIXME(eddyb) use small vector optimization for the common case. + offsets: Vec<Size>, + + /// Maps source order field indices to memory order indices, + /// depending how fields were permuted. + // FIXME(camlorn) also consider small vector optimization here. + memory_index: Vec<u32> + } +} + +impl FieldPlacement { + pub fn count(&self) -> usize { + match *self { + FieldPlacement::Union(count) => count, + FieldPlacement::Array { count, .. } => { + let usize_count = count as usize; + assert_eq!(usize_count as u64, count); + usize_count + } + FieldPlacement::Arbitrary { ref offsets, .. } => offsets.len() + } + } + + pub fn offset(&self, i: usize) -> Size { + match *self { + FieldPlacement::Union(_) => Size::from_bytes(0), + FieldPlacement::Array { stride, count } => { + let i = i as u64; + assert!(i < count); + stride * i + } + FieldPlacement::Arbitrary { ref offsets, .. } => offsets[i] + } + } + + pub fn memory_index(&self, i: usize) -> usize { + match *self { + FieldPlacement::Union(_) | + FieldPlacement::Array { .. } => i, + FieldPlacement::Arbitrary { ref memory_index, .. } => { + let r = memory_index[i]; + assert_eq!(r as usize as u32, r); + r as usize + } + } + } + + /// Get source indices of the fields by increasing offsets. + #[inline] + pub fn index_by_increasing_offset<'a>(&'a self) -> impl Iterator<Item=usize>+'a { + let mut inverse_small = [0u8; 64]; + let mut inverse_big = vec![]; + let use_small = self.count() <= inverse_small.len(); + + // We have to write this logic twice in order to keep the array small. + if let FieldPlacement::Arbitrary { ref memory_index, .. } = *self { + if use_small { + for i in 0..self.count() { + inverse_small[memory_index[i] as usize] = i as u8; + } + } else { + inverse_big = vec![0; self.count()]; + for i in 0..self.count() { + inverse_big[memory_index[i] as usize] = i as u32; + } + } + } + + (0..self.count()).map(move |i| { + match *self { + FieldPlacement::Union(_) | + FieldPlacement::Array { .. } => i, + FieldPlacement::Arbitrary { .. } => { + if use_small { inverse_small[i] as usize } + else { inverse_big[i] as usize } + } + } + }) + } +} + +/// Describes how values of the type are passed by target ABIs, +/// in terms of categories of C types there are ABI rules for. +#[derive(Clone, PartialEq, Eq, Hash, Debug)] +pub enum Abi { + Uninhabited, + Scalar(Scalar), + ScalarPair(Scalar, Scalar), + Vector { + element: Scalar, + count: u64 + }, + Aggregate { + /// If true, the size is exact, otherwise it's only a lower bound. + sized: bool, + } +} + +impl Abi { + /// Returns true if the layout corresponds to an unsized type. + pub fn is_unsized(&self) -> bool { + match *self { + Abi::Uninhabited | + Abi::Scalar(_) | + Abi::ScalarPair(..) | + Abi::Vector { .. } => false, + Abi::Aggregate { sized } => !sized + } + } + + /// Returns true if this is a single signed integer scalar + pub fn is_signed(&self) -> bool { + match *self { + Abi::Scalar(ref scal) => match scal.value { + Primitive::Int(_, signed) => signed, + _ => false, + }, + _ => false, + } + } +} + +#[derive(PartialEq, Eq, Hash, Debug)] +pub enum Variants { + /// Single enum variants, structs/tuples, unions, and all non-ADTs. + Single { + index: usize + }, + + /// General-case enums: for each case there is a struct, and they all have + /// all space reserved for the discriminant, and their first field starts + /// at a non-0 offset, after where the discriminant would go. + Tagged { + discr: Scalar, + variants: Vec<LayoutDetails>, + }, + + /// Multiple cases distinguished by a niche (values invalid for a type): + /// 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)`. + /// + /// For example, `Option<(usize, &T)>` is represented such that + /// `None` has a null pointer for the second tuple field, and + /// `Some` is the identity function (with a non-null reference). + NicheFilling { + dataful_variant: usize, + niche_variants: RangeInclusive<usize>, + niche: Scalar, + niche_start: u128, + variants: Vec<LayoutDetails>, + } +} + +#[derive(PartialEq, Eq, Hash, Debug)] +pub struct LayoutDetails { + pub variants: Variants, + pub fields: FieldPlacement, + pub abi: Abi, + pub align: Align, + pub size: Size +} + +impl LayoutDetails { + pub fn scalar<C: HasDataLayout>(cx: C, scalar: Scalar) -> Self { + let size = scalar.value.size(cx); + let align = scalar.value.align(cx); + LayoutDetails { + variants: Variants::Single { index: 0 }, + fields: FieldPlacement::Union(0), + abi: Abi::Scalar(scalar), + size, + align, + } + } + + pub fn uninhabited(field_count: usize) -> Self { + let align = Align::from_bytes(1, 1).unwrap(); + LayoutDetails { + variants: Variants::Single { index: 0 }, + fields: FieldPlacement::Union(field_count), + abi: Abi::Uninhabited, + align, + size: Size::from_bytes(0) + } + } +} + +/// The details of the layout of a type, alongside the type itself. +/// Provides various type traversal APIs (e.g. recursing into fields). +/// +/// Note that the details are NOT guaranteed to always be identical +/// to those obtained from `layout_of(ty)`, as we need to produce +/// layouts for which Rust types do not exist, such as enum variants +/// or synthetic fields of enums (i.e. discriminants) and fat pointers. +#[derive(Copy, Clone, Debug)] +pub struct TyLayout<'a, Ty> { + pub ty: Ty, + pub details: &'a LayoutDetails +} + +impl<'a, Ty> Deref for TyLayout<'a, Ty> { + type Target = &'a LayoutDetails; + fn deref(&self) -> &&'a LayoutDetails { + &self.details + } +} + +pub trait LayoutOf { + type Ty; + type TyLayout; + + fn layout_of(self, ty: Self::Ty) -> Self::TyLayout; +} + +pub trait TyLayoutMethods<'a, C: LayoutOf<Ty = Self>>: Sized { + fn for_variant(this: TyLayout<'a, Self>, cx: C, variant_index: usize) -> TyLayout<'a, Self>; + fn field(this: TyLayout<'a, Self>, cx: C, i: usize) -> C::TyLayout; +} + +impl<'a, Ty> TyLayout<'a, Ty> { + pub fn for_variant<C>(self, cx: C, variant_index: usize) -> Self + where Ty: TyLayoutMethods<'a, C>, C: LayoutOf<Ty = Ty> { + Ty::for_variant(self, cx, variant_index) + } + pub fn field<C>(self, cx: C, i: usize) -> C::TyLayout + where Ty: TyLayoutMethods<'a, C>, C: LayoutOf<Ty = Ty> { + Ty::field(self, cx, i) + } +} + +impl<'a, Ty> TyLayout<'a, Ty> { + /// Returns true if the layout corresponds to an unsized type. + pub fn is_unsized(&self) -> bool { + self.abi.is_unsized() + } + + /// Returns true if the type is a ZST and not unsized. + pub fn is_zst(&self) -> bool { + match self.abi { + Abi::Uninhabited => true, + Abi::Scalar(_) | + Abi::ScalarPair(..) | + Abi::Vector { .. } => false, + Abi::Aggregate { sized } => sized && self.size.bytes() == 0 + } + } + + pub fn size_and_align(&self) -> (Size, Align) { + (self.size, self.align) + } +} diff --git a/src/librustc_back/build.rs b/src/librustc_target/build.rs index 6f6fde1e9e7..6f6fde1e9e7 100644 --- a/src/librustc_back/build.rs +++ b/src/librustc_target/build.rs diff --git a/src/librustc_target/lib.rs b/src/librustc_target/lib.rs new file mode 100644 index 00000000000..927d5c7e15a --- /dev/null +++ b/src/librustc_target/lib.rs @@ -0,0 +1,47 @@ +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Some stuff used by rustc that doesn't have many dependencies +//! +//! Originally extracted from rustc::back, which was nominally the +//! compiler 'backend', though LLVM is rustc's backend, so rustc_target +//! is really just odds-and-ends relating to code gen and linking. +//! This crate mostly exists to make rustc smaller, so we might put +//! more 'stuff' here in the future. It does not have a dependency on +//! rustc_llvm. +//! +//! FIXME: Split this into two crates: one that has deps on syntax, and +//! one that doesn't; the one that doesn't might get decent parallel +//! build speedups. + +#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", + html_favicon_url = "https://doc.rust-lang.org/favicon.ico", + html_root_url = "https://doc.rust-lang.org/nightly/")] + +#![feature(box_syntax)] +#![feature(const_fn)] +#![feature(fs_read_write)] +#![feature(inclusive_range)] +#![feature(inclusive_range_fields)] +#![feature(slice_patterns)] + +#[macro_use] +extern crate bitflags; +extern crate serialize; +#[macro_use] extern crate log; + +extern crate serialize as rustc_serialize; // used by deriving + +// See librustc_cratesio_shim/Cargo.toml for a comment explaining this. +#[allow(unused_extern_crates)] +extern crate rustc_cratesio_shim; + +pub mod abi; +pub mod spec; diff --git a/src/librustc_back/target/aarch64_apple_ios.rs b/src/librustc_target/spec/aarch64_apple_ios.rs index cff6eb534b1..90f8cd90c66 100644 --- a/src/librustc_back/target/aarch64_apple_ios.rs +++ b/src/librustc_target/spec/aarch64_apple_ios.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetOptions, TargetResult}; +use spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; use super::apple_ios_base::{opts, Arch}; pub fn target() -> TargetResult { diff --git a/src/librustc_back/target/aarch64_linux_android.rs b/src/librustc_target/spec/aarch64_linux_android.rs index 2c0d6a55ed8..afd67112f0d 100644 --- a/src/librustc_back/target/aarch64_linux_android.rs +++ b/src/librustc_target/spec/aarch64_linux_android.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetOptions, TargetResult}; +use spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; // See https://developer.android.com/ndk/guides/abis.html#arm64-v8a // for target ABI requirements. diff --git a/src/librustc_back/target/aarch64_unknown_cloudabi.rs b/src/librustc_target/spec/aarch64_unknown_cloudabi.rs index a5d0e5bf166..ffdb7decd0b 100644 --- a/src/librustc_back/target/aarch64_unknown_cloudabi.rs +++ b/src/librustc_target/spec/aarch64_unknown_cloudabi.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetResult}; +use spec::{LinkerFlavor, Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::cloudabi_base::opts(); diff --git a/src/librustc_back/target/aarch64_unknown_freebsd.rs b/src/librustc_target/spec/aarch64_unknown_freebsd.rs index 1ce8d600c03..48177b8c79a 100644 --- a/src/librustc_back/target/aarch64_unknown_freebsd.rs +++ b/src/librustc_target/spec/aarch64_unknown_freebsd.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetOptions, TargetResult}; +use spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { let mut base = super::freebsd_base::opts(); diff --git a/src/librustc_back/target/aarch64_unknown_fuchsia.rs b/src/librustc_target/spec/aarch64_unknown_fuchsia.rs index 73cd9c92701..4da6724ef62 100644 --- a/src/librustc_back/target/aarch64_unknown_fuchsia.rs +++ b/src/librustc_target/spec/aarch64_unknown_fuchsia.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetOptions, TargetResult}; +use spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { let mut base = super::fuchsia_base::opts(); diff --git a/src/librustc_back/target/aarch64_unknown_linux_gnu.rs b/src/librustc_target/spec/aarch64_unknown_linux_gnu.rs index 5c9c9a0c555..2351d014692 100644 --- a/src/librustc_back/target/aarch64_unknown_linux_gnu.rs +++ b/src/librustc_target/spec/aarch64_unknown_linux_gnu.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetOptions, TargetResult}; +use spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_base::opts(); diff --git a/src/librustc_back/target/aarch64_unknown_linux_musl.rs b/src/librustc_target/spec/aarch64_unknown_linux_musl.rs index d39ad97bbcb..5ab55a076f4 100644 --- a/src/librustc_back/target/aarch64_unknown_linux_musl.rs +++ b/src/librustc_target/spec/aarch64_unknown_linux_musl.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetOptions, TargetResult}; +use spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_musl_base::opts(); diff --git a/src/libsyntax/abi.rs b/src/librustc_target/spec/abi.rs index ed2eb209906..ed2eb209906 100644 --- a/src/libsyntax/abi.rs +++ b/src/librustc_target/spec/abi.rs diff --git a/src/librustc_back/target/android_base.rs b/src/librustc_target/spec/android_base.rs index 49baa1b96ce..7e27e8aa9a7 100644 --- a/src/librustc_back/target/android_base.rs +++ b/src/librustc_target/spec/android_base.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::TargetOptions; +use spec::{LinkerFlavor, TargetOptions}; pub fn opts() -> TargetOptions { let mut base = super::linux_base::opts(); @@ -20,5 +19,6 @@ pub fn opts() -> TargetOptions { base.is_like_android = true; base.position_independent_executables = true; base.has_elf_tls = false; + base.requires_uwtable = true; base } diff --git a/src/librustc_back/target/apple_base.rs b/src/librustc_target/spec/apple_base.rs index 480de9ff486..4b66891e36f 100644 --- a/src/librustc_back/target/apple_base.rs +++ b/src/librustc_target/spec/apple_base.rs @@ -10,7 +10,7 @@ use std::env; -use target::{LinkArgs, TargetOptions}; +use spec::{LinkArgs, TargetOptions}; pub fn opts() -> TargetOptions { // ELF TLS is only available in macOS 10.7+. If you try to compile for 10.6 diff --git a/src/librustc_back/target/apple_ios_base.rs b/src/librustc_target/spec/apple_ios_base.rs index 1895ab1eb7e..acbbab313fe 100644 --- a/src/librustc_back/target/apple_ios_base.rs +++ b/src/librustc_target/spec/apple_ios_base.rs @@ -8,10 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; use std::io; use std::process::Command; -use target::{LinkArgs, TargetOptions}; +use spec::{LinkArgs, LinkerFlavor, TargetOptions}; use self::Arch::*; diff --git a/src/librustc_back/target/arm_base.rs b/src/librustc_target/spec/arm_base.rs index 416e5a0e13a..635b8ae7388 100644 --- a/src/librustc_back/target/arm_base.rs +++ b/src/librustc_target/spec/arm_base.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use syntax::abi::Abi; +use spec::abi::Abi; // All the calling conventions trigger an assertion(Unsupported calling convention) in llvm on arm pub fn abi_blacklist() -> Vec<Abi> { diff --git a/src/librustc_back/target/arm_linux_androideabi.rs b/src/librustc_target/spec/arm_linux_androideabi.rs index ba21b1df032..ffd242b2bc2 100644 --- a/src/librustc_back/target/arm_linux_androideabi.rs +++ b/src/librustc_target/spec/arm_linux_androideabi.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetOptions, TargetResult}; +use spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { let mut base = super::android_base::opts(); diff --git a/src/librustc_back/target/arm_unknown_linux_gnueabi.rs b/src/librustc_target/spec/arm_unknown_linux_gnueabi.rs index e630376a67d..c67a25e8bc2 100644 --- a/src/librustc_back/target/arm_unknown_linux_gnueabi.rs +++ b/src/librustc_target/spec/arm_unknown_linux_gnueabi.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetOptions, TargetResult}; +use spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_base::opts(); diff --git a/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs b/src/librustc_target/spec/arm_unknown_linux_gnueabihf.rs index 178a948b2b9..ed0049a932e 100644 --- a/src/librustc_back/target/arm_unknown_linux_gnueabihf.rs +++ b/src/librustc_target/spec/arm_unknown_linux_gnueabihf.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetOptions, TargetResult}; +use spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_base::opts(); diff --git a/src/librustc_back/target/arm_unknown_linux_musleabi.rs b/src/librustc_target/spec/arm_unknown_linux_musleabi.rs index 29720ec5efc..c34093fbab9 100644 --- a/src/librustc_back/target/arm_unknown_linux_musleabi.rs +++ b/src/librustc_target/spec/arm_unknown_linux_musleabi.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetOptions, TargetResult}; +use spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_musl_base::opts(); diff --git a/src/librustc_back/target/arm_unknown_linux_musleabihf.rs b/src/librustc_target/spec/arm_unknown_linux_musleabihf.rs index fc8313877f6..967873b3201 100644 --- a/src/librustc_back/target/arm_unknown_linux_musleabihf.rs +++ b/src/librustc_target/spec/arm_unknown_linux_musleabihf.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetOptions, TargetResult}; +use spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_musl_base::opts(); diff --git a/src/librustc_back/target/armv4t_unknown_linux_gnueabi.rs b/src/librustc_target/spec/armv4t_unknown_linux_gnueabi.rs index 33399a78493..fb99dffeddd 100644 --- a/src/librustc_back/target/armv4t_unknown_linux_gnueabi.rs +++ b/src/librustc_target/spec/armv4t_unknown_linux_gnueabi.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetOptions, TargetResult}; +use spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { let base = super::linux_base::opts(); diff --git a/src/librustc_back/target/armv5te_unknown_linux_gnueabi.rs b/src/librustc_target/spec/armv5te_unknown_linux_gnueabi.rs index 4efe66980a0..810f0912472 100644 --- a/src/librustc_back/target/armv5te_unknown_linux_gnueabi.rs +++ b/src/librustc_target/spec/armv5te_unknown_linux_gnueabi.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetOptions, TargetResult}; +use spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { let base = super::linux_base::opts(); diff --git a/src/librustc_back/target/armv7_apple_ios.rs b/src/librustc_target/spec/armv7_apple_ios.rs index 67d3d12fb57..da7cbb918bd 100644 --- a/src/librustc_back/target/armv7_apple_ios.rs +++ b/src/librustc_target/spec/armv7_apple_ios.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetOptions, TargetResult}; +use spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; use super::apple_ios_base::{opts, Arch}; pub fn target() -> TargetResult { diff --git a/src/librustc_back/target/armv7_linux_androideabi.rs b/src/librustc_target/spec/armv7_linux_androideabi.rs index 9e3eec13ab7..cfdc5cddcfb 100644 --- a/src/librustc_back/target/armv7_linux_androideabi.rs +++ b/src/librustc_target/spec/armv7_linux_androideabi.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetOptions, TargetResult}; +use spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; // See https://developer.android.com/ndk/guides/abis.html#v7a // for target ABI requirements. diff --git a/src/librustc_back/target/armv7_unknown_cloudabi_eabihf.rs b/src/librustc_target/spec/armv7_unknown_cloudabi_eabihf.rs index fa66a35abbf..393c45e434e 100644 --- a/src/librustc_back/target/armv7_unknown_cloudabi_eabihf.rs +++ b/src/librustc_target/spec/armv7_unknown_cloudabi_eabihf.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetResult}; +use spec::{LinkerFlavor, Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::cloudabi_base::opts(); diff --git a/src/librustc_back/target/armv7_unknown_linux_gnueabihf.rs b/src/librustc_target/spec/armv7_unknown_linux_gnueabihf.rs index 569c721473d..14e8fa9dc02 100644 --- a/src/librustc_back/target/armv7_unknown_linux_gnueabihf.rs +++ b/src/librustc_target/spec/armv7_unknown_linux_gnueabihf.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetOptions, TargetResult}; +use spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { let base = super::linux_base::opts(); diff --git a/src/librustc_back/target/armv7_unknown_linux_musleabihf.rs b/src/librustc_target/spec/armv7_unknown_linux_musleabihf.rs index 88f2b596751..6e71cb307b9 100644 --- a/src/librustc_back/target/armv7_unknown_linux_musleabihf.rs +++ b/src/librustc_target/spec/armv7_unknown_linux_musleabihf.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetOptions, TargetResult}; +use spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { let base = super::linux_musl_base::opts(); diff --git a/src/librustc_back/target/armv7s_apple_ios.rs b/src/librustc_target/spec/armv7s_apple_ios.rs index e4cc89ab211..c0c577c3b8c 100644 --- a/src/librustc_back/target/armv7s_apple_ios.rs +++ b/src/librustc_target/spec/armv7s_apple_ios.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetOptions, TargetResult}; +use spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; use super::apple_ios_base::{opts, Arch}; pub fn target() -> TargetResult { diff --git a/src/librustc_back/target/asmjs_unknown_emscripten.rs b/src/librustc_target/spec/asmjs_unknown_emscripten.rs index ab7df4ba1c5..e2cf714f0ea 100644 --- a/src/librustc_back/target/asmjs_unknown_emscripten.rs +++ b/src/librustc_target/spec/asmjs_unknown_emscripten.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use super::{LinkArgs, Target, TargetOptions}; +use super::{LinkArgs, LinkerFlavor, Target, TargetOptions}; pub fn target() -> Result<Target, String> { let mut args = LinkArgs::new(); diff --git a/src/librustc_back/target/bitrig_base.rs b/src/librustc_target/spec/bitrig_base.rs index 45ceb2d5a60..e0cbfcdcef0 100644 --- a/src/librustc_back/target/bitrig_base.rs +++ b/src/librustc_target/spec/bitrig_base.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::{TargetOptions, RelroLevel}; +use spec::{TargetOptions, RelroLevel}; use std::default::Default; pub fn opts() -> TargetOptions { diff --git a/src/librustc_back/target/cloudabi_base.rs b/src/librustc_target/spec/cloudabi_base.rs index 4cd52ebb26d..2ffa74e737f 100644 --- a/src/librustc_back/target/cloudabi_base.rs +++ b/src/librustc_target/spec/cloudabi_base.rs @@ -8,9 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{LinkArgs, TargetOptions, RelroLevel}; -use std::default::Default; +use spec::{LinkArgs, LinkerFlavor, TargetOptions, RelroLevel}; pub fn opts() -> TargetOptions { let mut args = LinkArgs::new(); diff --git a/src/librustc_back/target/dragonfly_base.rs b/src/librustc_target/spec/dragonfly_base.rs index 21dca99aa50..32eac8663af 100644 --- a/src/librustc_back/target/dragonfly_base.rs +++ b/src/librustc_target/spec/dragonfly_base.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{LinkArgs, TargetOptions, RelroLevel}; +use spec::{LinkArgs, LinkerFlavor, TargetOptions, RelroLevel}; use std::default::Default; pub fn opts() -> TargetOptions { diff --git a/src/librustc_back/target/freebsd_base.rs b/src/librustc_target/spec/freebsd_base.rs index 291b2276899..04b8a6e7060 100644 --- a/src/librustc_back/target/freebsd_base.rs +++ b/src/librustc_target/spec/freebsd_base.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{LinkArgs, TargetOptions, RelroLevel}; +use spec::{LinkArgs, LinkerFlavor, TargetOptions, RelroLevel}; use std::default::Default; pub fn opts() -> TargetOptions { diff --git a/src/librustc_back/target/fuchsia_base.rs b/src/librustc_target/spec/fuchsia_base.rs index 63ccd21c220..19a66b693f2 100644 --- a/src/librustc_back/target/fuchsia_base.rs +++ b/src/librustc_target/spec/fuchsia_base.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{LinkArgs, TargetOptions}; +use spec::{LinkArgs, LinkerFlavor, TargetOptions}; use std::default::Default; pub fn opts() -> TargetOptions { diff --git a/src/librustc_back/target/haiku_base.rs b/src/librustc_target/spec/haiku_base.rs index a1ccb632cab..bf62b49f914 100644 --- a/src/librustc_back/target/haiku_base.rs +++ b/src/librustc_target/spec/haiku_base.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::{TargetOptions, RelroLevel}; +use spec::{TargetOptions, RelroLevel}; use std::default::Default; pub fn opts() -> TargetOptions { diff --git a/src/librustc_back/target/i386_apple_ios.rs b/src/librustc_target/spec/i386_apple_ios.rs index 82eae1a31a9..9eb0327f625 100644 --- a/src/librustc_back/target/i386_apple_ios.rs +++ b/src/librustc_target/spec/i386_apple_ios.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetOptions, TargetResult}; +use spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; use super::apple_ios_base::{opts, Arch}; pub fn target() -> TargetResult { diff --git a/src/librustc_back/target/i586_pc_windows_msvc.rs b/src/librustc_target/spec/i586_pc_windows_msvc.rs index 9b88cde5989..9a20b854e0f 100644 --- a/src/librustc_back/target/i586_pc_windows_msvc.rs +++ b/src/librustc_target/spec/i586_pc_windows_msvc.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::TargetResult; +use spec::TargetResult; pub fn target() -> TargetResult { let mut base = super::i686_pc_windows_msvc::target()?; diff --git a/src/librustc_back/target/i586_unknown_linux_gnu.rs b/src/librustc_target/spec/i586_unknown_linux_gnu.rs index 40fb4a67acd..35bca76af47 100644 --- a/src/librustc_back/target/i586_unknown_linux_gnu.rs +++ b/src/librustc_target/spec/i586_unknown_linux_gnu.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::TargetResult; +use spec::TargetResult; pub fn target() -> TargetResult { let mut base = super::i686_unknown_linux_gnu::target()?; diff --git a/src/librustc_back/target/i586_unknown_linux_musl.rs b/src/librustc_target/spec/i586_unknown_linux_musl.rs index 416eacf475b..ba23e1d6860 100644 --- a/src/librustc_back/target/i586_unknown_linux_musl.rs +++ b/src/librustc_target/spec/i586_unknown_linux_musl.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::TargetResult; +use spec::TargetResult; pub fn target() -> TargetResult { let mut base = super::i686_unknown_linux_musl::target()?; diff --git a/src/librustc_back/target/i686_apple_darwin.rs b/src/librustc_target/spec/i686_apple_darwin.rs index 14937f9aa55..06ea1e4649b 100644 --- a/src/librustc_back/target/i686_apple_darwin.rs +++ b/src/librustc_target/spec/i686_apple_darwin.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetResult}; +use spec::{LinkerFlavor, Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::apple_base::opts(); diff --git a/src/librustc_back/target/i686_linux_android.rs b/src/librustc_target/spec/i686_linux_android.rs index bf27bce79ac..171e0899595 100644 --- a/src/librustc_back/target/i686_linux_android.rs +++ b/src/librustc_target/spec/i686_linux_android.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetResult}; +use spec::{LinkerFlavor, Target, TargetResult}; // See https://developer.android.com/ndk/guides/abis.html#x86 // for target ABI requirements. diff --git a/src/librustc_back/target/i686_pc_windows_gnu.rs b/src/librustc_target/spec/i686_pc_windows_gnu.rs index 5f20a620b6e..867d04ec3f2 100644 --- a/src/librustc_back/target/i686_pc_windows_gnu.rs +++ b/src/librustc_target/spec/i686_pc_windows_gnu.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetResult}; +use spec::{LinkerFlavor, Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::windows_base::opts(); diff --git a/src/librustc_back/target/i686_pc_windows_msvc.rs b/src/librustc_target/spec/i686_pc_windows_msvc.rs index 48cee044573..3570f379c30 100644 --- a/src/librustc_back/target/i686_pc_windows_msvc.rs +++ b/src/librustc_target/spec/i686_pc_windows_msvc.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetResult}; +use spec::{LinkerFlavor, Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::windows_msvc_base::opts(); diff --git a/src/librustc_back/target/i686_unknown_cloudabi.rs b/src/librustc_target/spec/i686_unknown_cloudabi.rs index 69c3b298cab..335105bb1a8 100644 --- a/src/librustc_back/target/i686_unknown_cloudabi.rs +++ b/src/librustc_target/spec/i686_unknown_cloudabi.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetResult}; +use spec::{LinkerFlavor, Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::cloudabi_base::opts(); diff --git a/src/librustc_back/target/i686_unknown_dragonfly.rs b/src/librustc_target/spec/i686_unknown_dragonfly.rs index 891127b9d37..cb0c471353b 100644 --- a/src/librustc_back/target/i686_unknown_dragonfly.rs +++ b/src/librustc_target/spec/i686_unknown_dragonfly.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetResult}; +use spec::{LinkerFlavor, Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::dragonfly_base::opts(); diff --git a/src/librustc_back/target/i686_unknown_freebsd.rs b/src/librustc_target/spec/i686_unknown_freebsd.rs index 076acb8ed31..3838a157d10 100644 --- a/src/librustc_back/target/i686_unknown_freebsd.rs +++ b/src/librustc_target/spec/i686_unknown_freebsd.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetResult}; +use spec::{LinkerFlavor, Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::freebsd_base::opts(); diff --git a/src/librustc_back/target/i686_unknown_haiku.rs b/src/librustc_target/spec/i686_unknown_haiku.rs index 02a15d6445c..98f0787beba 100644 --- a/src/librustc_back/target/i686_unknown_haiku.rs +++ b/src/librustc_target/spec/i686_unknown_haiku.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetResult}; +use spec::{LinkerFlavor, Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::haiku_base::opts(); diff --git a/src/librustc_back/target/i686_unknown_linux_gnu.rs b/src/librustc_target/spec/i686_unknown_linux_gnu.rs index b509e019c7e..c3ff347882d 100644 --- a/src/librustc_back/target/i686_unknown_linux_gnu.rs +++ b/src/librustc_target/spec/i686_unknown_linux_gnu.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetResult}; +use spec::{LinkerFlavor, Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_base::opts(); diff --git a/src/librustc_back/target/i686_unknown_linux_musl.rs b/src/librustc_target/spec/i686_unknown_linux_musl.rs index 99c0d4c8179..c02076c071a 100644 --- a/src/librustc_back/target/i686_unknown_linux_musl.rs +++ b/src/librustc_target/spec/i686_unknown_linux_musl.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetResult}; +use spec::{LinkerFlavor, Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_musl_base::opts(); diff --git a/src/librustc_back/target/i686_unknown_netbsd.rs b/src/librustc_target/spec/i686_unknown_netbsd.rs index dd21c205106..d60ed988599 100644 --- a/src/librustc_back/target/i686_unknown_netbsd.rs +++ b/src/librustc_target/spec/i686_unknown_netbsd.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetResult}; +use spec::{LinkerFlavor, Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::netbsd_base::opts(); diff --git a/src/librustc_back/target/i686_unknown_openbsd.rs b/src/librustc_target/spec/i686_unknown_openbsd.rs index 8daa5fcb88b..79c059c8f95 100644 --- a/src/librustc_back/target/i686_unknown_openbsd.rs +++ b/src/librustc_target/spec/i686_unknown_openbsd.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetResult}; +use spec::{LinkerFlavor, Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::openbsd_base::opts(); diff --git a/src/librustc_back/target/l4re_base.rs b/src/librustc_target/spec/l4re_base.rs index 3b13ef01500..4ebc930d48b 100644 --- a/src/librustc_back/target/l4re_base.rs +++ b/src/librustc_target/spec/l4re_base.rs @@ -8,9 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use PanicStrategy; -use target::{LinkArgs, TargetOptions}; +use spec::{LinkArgs, LinkerFlavor, PanicStrategy, TargetOptions}; use std::default::Default; //use std::process::Command; diff --git a/src/librustc_back/target/linux_base.rs b/src/librustc_target/spec/linux_base.rs index 52f700ac751..4a9cd9e2f32 100644 --- a/src/librustc_back/target/linux_base.rs +++ b/src/librustc_target/spec/linux_base.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{LinkArgs, TargetOptions, RelroLevel}; +use spec::{LinkArgs, LinkerFlavor, TargetOptions, RelroLevel}; use std::default::Default; pub fn opts() -> TargetOptions { diff --git a/src/librustc_back/target/linux_musl_base.rs b/src/librustc_target/spec/linux_musl_base.rs index 6e5e139715c..293f23eab38 100644 --- a/src/librustc_back/target/linux_musl_base.rs +++ b/src/librustc_target/spec/linux_musl_base.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::TargetOptions; +use spec::{LinkerFlavor, TargetOptions}; pub fn opts() -> TargetOptions { let mut base = super::linux_base::opts(); diff --git a/src/librustc_back/target/mips64_unknown_linux_gnuabi64.rs b/src/librustc_target/spec/mips64_unknown_linux_gnuabi64.rs index 5c3cf31b3e4..1f60d918908 100644 --- a/src/librustc_back/target/mips64_unknown_linux_gnuabi64.rs +++ b/src/librustc_target/spec/mips64_unknown_linux_gnuabi64.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetOptions, TargetResult}; +use spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { Ok(Target { diff --git a/src/librustc_back/target/mips64el_unknown_linux_gnuabi64.rs b/src/librustc_target/spec/mips64el_unknown_linux_gnuabi64.rs index 96988388e81..e42fde8d403 100644 --- a/src/librustc_back/target/mips64el_unknown_linux_gnuabi64.rs +++ b/src/librustc_target/spec/mips64el_unknown_linux_gnuabi64.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetOptions, TargetResult}; +use spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { Ok(Target { diff --git a/src/librustc_back/target/mips_unknown_linux_gnu.rs b/src/librustc_target/spec/mips_unknown_linux_gnu.rs index cffd1daed99..59e15137cf4 100644 --- a/src/librustc_back/target/mips_unknown_linux_gnu.rs +++ b/src/librustc_target/spec/mips_unknown_linux_gnu.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetOptions, TargetResult}; +use spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { Ok(Target { diff --git a/src/librustc_back/target/mips_unknown_linux_musl.rs b/src/librustc_target/spec/mips_unknown_linux_musl.rs index 80168d4af4b..8ee399ba56c 100644 --- a/src/librustc_back/target/mips_unknown_linux_musl.rs +++ b/src/librustc_target/spec/mips_unknown_linux_musl.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetResult}; +use spec::{LinkerFlavor, Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_musl_base::opts(); diff --git a/src/librustc_back/target/mips_unknown_linux_uclibc.rs b/src/librustc_target/spec/mips_unknown_linux_uclibc.rs index c851cab069a..384ab1e4131 100644 --- a/src/librustc_back/target/mips_unknown_linux_uclibc.rs +++ b/src/librustc_target/spec/mips_unknown_linux_uclibc.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetOptions, TargetResult}; +use spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { Ok(Target { diff --git a/src/librustc_back/target/mipsel_unknown_linux_gnu.rs b/src/librustc_target/spec/mipsel_unknown_linux_gnu.rs index 555855b8f81..edd29164cac 100644 --- a/src/librustc_back/target/mipsel_unknown_linux_gnu.rs +++ b/src/librustc_target/spec/mipsel_unknown_linux_gnu.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetOptions, TargetResult}; +use spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { Ok(Target { diff --git a/src/librustc_back/target/mipsel_unknown_linux_musl.rs b/src/librustc_target/spec/mipsel_unknown_linux_musl.rs index 6bef2fe2ea7..1d9378ca1b8 100644 --- a/src/librustc_back/target/mipsel_unknown_linux_musl.rs +++ b/src/librustc_target/spec/mipsel_unknown_linux_musl.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetResult}; +use spec::{LinkerFlavor, Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_musl_base::opts(); diff --git a/src/librustc_back/target/mipsel_unknown_linux_uclibc.rs b/src/librustc_target/spec/mipsel_unknown_linux_uclibc.rs index a5dbdd11183..a1db1791bb7 100644 --- a/src/librustc_back/target/mipsel_unknown_linux_uclibc.rs +++ b/src/librustc_target/spec/mipsel_unknown_linux_uclibc.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetOptions, TargetResult}; +use spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { Ok(Target { diff --git a/src/librustc_back/target/mod.rs b/src/librustc_target/spec/mod.rs index 592b27ac641..1e94f037885 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_target/spec/mod.rs @@ -49,10 +49,10 @@ use std::collections::BTreeMap; use std::default::Default; use std::{fmt, io}; use std::path::{Path, PathBuf}; -use syntax::abi::{Abi, lookup as lookup_abi}; - -use {LinkerFlavor, PanicStrategy, RelroLevel}; +use std::str::FromStr; +use spec::abi::{Abi, lookup as lookup_abi}; +pub mod abi; mod android_base; mod apple_base; mod apple_ios_base; @@ -74,6 +74,133 @@ mod l4re_base; mod fuchsia_base; mod redox_base; +#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, Hash, + RustcEncodable, RustcDecodable)] +pub enum LinkerFlavor { + Em, + Gcc, + Ld, + Msvc, + Lld(LldFlavor), +} + +#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, Hash, + RustcEncodable, RustcDecodable)] +pub enum LldFlavor { + Wasm, + Ld64, + Ld, + Link, +} + +impl ToJson for LinkerFlavor { + fn to_json(&self) -> Json { + self.desc().to_json() + } +} +macro_rules! flavor_mappings { + ($((($($flavor:tt)*), $string:expr),)*) => ( + impl LinkerFlavor { + pub const fn one_of() -> &'static str { + concat!("one of: ", $($string, " ",)+) + } + + pub fn from_str(s: &str) -> Option<Self> { + Some(match s { + $($string => $($flavor)*,)+ + _ => return None, + }) + } + + pub fn desc(&self) -> &str { + match *self { + $($($flavor)* => $string,)+ + } + } + } + ) +} + + +flavor_mappings! { + ((LinkerFlavor::Em), "em"), + ((LinkerFlavor::Gcc), "gcc"), + ((LinkerFlavor::Ld), "ld"), + ((LinkerFlavor::Msvc), "msvc"), + ((LinkerFlavor::Lld(LldFlavor::Wasm)), "wasm-ld"), + ((LinkerFlavor::Lld(LldFlavor::Ld64)), "ld64.lld"), + ((LinkerFlavor::Lld(LldFlavor::Ld)), "ld.lld"), + ((LinkerFlavor::Lld(LldFlavor::Link)), "lld-link"), +} + +#[derive(Clone, Copy, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)] +pub enum PanicStrategy { + Unwind, + Abort, +} + +impl PanicStrategy { + pub fn desc(&self) -> &str { + match *self { + PanicStrategy::Unwind => "unwind", + PanicStrategy::Abort => "abort", + } + } +} + +impl ToJson for PanicStrategy { + fn to_json(&self) -> Json { + match *self { + PanicStrategy::Abort => "abort".to_json(), + PanicStrategy::Unwind => "unwind".to_json(), + } + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)] +pub enum RelroLevel { + Full, + Partial, + Off, + None, +} + +impl RelroLevel { + pub fn desc(&self) -> &str { + match *self { + RelroLevel::Full => "full", + RelroLevel::Partial => "partial", + RelroLevel::Off => "off", + RelroLevel::None => "none", + } + } +} + +impl FromStr for RelroLevel { + type Err = (); + + fn from_str(s: &str) -> Result<RelroLevel, ()> { + match s { + "full" => Ok(RelroLevel::Full), + "partial" => Ok(RelroLevel::Partial), + "off" => Ok(RelroLevel::Off), + "none" => Ok(RelroLevel::None), + _ => Err(()), + } + } +} + +impl ToJson for RelroLevel { + fn to_json(&self) -> Json { + match *self { + RelroLevel::Full => "full".to_json(), + RelroLevel::Partial => "partial".to_json(), + RelroLevel::Off => "off".to_json(), + RelroLevel::None => "None".to_json(), + } + } +} + pub type LinkArgs = BTreeMap<LinkerFlavor, Vec<String>>; pub type TargetResult = Result<Target, String>; @@ -271,6 +398,16 @@ pub struct Target { pub options: TargetOptions, } +pub trait HasTargetSpec: Copy { + fn target_spec(&self) -> &Target; +} + +impl<'a> HasTargetSpec for &'a Target { + fn target_spec(&self) -> &Target { + self + } +} + /// Optional aspects of a target specification. /// /// This has an implementation of `Default`, see each field for what the default is. In general, @@ -481,6 +618,11 @@ pub struct TargetOptions { /// Whether a .debug_gdb_scripts section will be added to the output object file pub emit_debug_gdb_scripts: bool, + + /// Whether or not to unconditionally `uwtable` attributes on functions, + /// typically because the platform needs to unwind for things like stack + /// unwinders. + pub requires_uwtable: bool, } impl Default for TargetOptions { @@ -554,6 +696,7 @@ impl Default for TargetOptions { default_hidden_visibility: false, embed_bitcode: false, emit_debug_gdb_scripts: true, + requires_uwtable: false, } } } @@ -804,6 +947,7 @@ impl Target { key!(default_hidden_visibility, bool); key!(embed_bitcode, bool); key!(emit_debug_gdb_scripts, bool); + key!(requires_uwtable, bool); if let Some(array) = obj.find("abi-blacklist").and_then(Json::as_array) { for name in array.iter().filter_map(|abi| abi.as_string()) { @@ -1008,6 +1152,7 @@ impl ToJson for Target { target_option_val!(default_hidden_visibility); target_option_val!(embed_bitcode); target_option_val!(emit_debug_gdb_scripts); + target_option_val!(requires_uwtable); if default.abi_blacklist != self.options.abi_blacklist { d.insert("abi-blacklist".to_string(), self.options.abi_blacklist.iter() diff --git a/src/librustc_back/target/msp430_none_elf.rs b/src/librustc_target/spec/msp430_none_elf.rs index 31df9be0bc3..ce42a908b0e 100644 --- a/src/librustc_back/target/msp430_none_elf.rs +++ b/src/librustc_target/spec/msp430_none_elf.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use {LinkerFlavor, PanicStrategy}; -use target::{Target, TargetOptions, TargetResult}; +use spec::{LinkerFlavor, PanicStrategy, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { Ok(Target { diff --git a/src/librustc_back/target/netbsd_base.rs b/src/librustc_target/spec/netbsd_base.rs index 1cb31137193..8b6bb5dec91 100644 --- a/src/librustc_back/target/netbsd_base.rs +++ b/src/librustc_target/spec/netbsd_base.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{LinkArgs, TargetOptions, RelroLevel}; +use spec::{LinkArgs, LinkerFlavor, TargetOptions, RelroLevel}; use std::default::Default; pub fn opts() -> TargetOptions { diff --git a/src/librustc_back/target/openbsd_base.rs b/src/librustc_target/spec/openbsd_base.rs index 311e260ee3f..90ab1135c54 100644 --- a/src/librustc_back/target/openbsd_base.rs +++ b/src/librustc_target/spec/openbsd_base.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{LinkArgs, TargetOptions, RelroLevel}; +use spec::{LinkArgs, LinkerFlavor, TargetOptions, RelroLevel}; use std::default::Default; pub fn opts() -> TargetOptions { diff --git a/src/librustc_back/target/powerpc64_unknown_linux_gnu.rs b/src/librustc_target/spec/powerpc64_unknown_linux_gnu.rs index 1f119c7204b..19598711613 100644 --- a/src/librustc_back/target/powerpc64_unknown_linux_gnu.rs +++ b/src/librustc_target/spec/powerpc64_unknown_linux_gnu.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetResult, RelroLevel}; +use spec::{LinkerFlavor, Target, TargetResult, RelroLevel}; pub fn target() -> TargetResult { let mut base = super::linux_base::opts(); diff --git a/src/librustc_back/target/powerpc64le_unknown_linux_gnu.rs b/src/librustc_target/spec/powerpc64le_unknown_linux_gnu.rs index 13c59785d48..39840692dff 100644 --- a/src/librustc_back/target/powerpc64le_unknown_linux_gnu.rs +++ b/src/librustc_target/spec/powerpc64le_unknown_linux_gnu.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetResult}; +use spec::{LinkerFlavor, Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_base::opts(); diff --git a/src/librustc_back/target/powerpc_unknown_linux_gnu.rs b/src/librustc_target/spec/powerpc_unknown_linux_gnu.rs index 1797126b310..c05b110a75d 100644 --- a/src/librustc_back/target/powerpc_unknown_linux_gnu.rs +++ b/src/librustc_target/spec/powerpc_unknown_linux_gnu.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetResult}; +use spec::{LinkerFlavor, Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_base::opts(); diff --git a/src/librustc_back/target/powerpc_unknown_linux_gnuspe.rs b/src/librustc_target/spec/powerpc_unknown_linux_gnuspe.rs index ffcc321749b..c76c3119c87 100644 --- a/src/librustc_back/target/powerpc_unknown_linux_gnuspe.rs +++ b/src/librustc_target/spec/powerpc_unknown_linux_gnuspe.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetResult}; +use spec::{LinkerFlavor, Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_base::opts(); diff --git a/src/librustc_back/target/powerpc_unknown_netbsd.rs b/src/librustc_target/spec/powerpc_unknown_netbsd.rs index 2c78dbd2061..c05e40b9c25 100644 --- a/src/librustc_back/target/powerpc_unknown_netbsd.rs +++ b/src/librustc_target/spec/powerpc_unknown_netbsd.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetResult}; +use spec::{LinkerFlavor, Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::netbsd_base::opts(); diff --git a/src/librustc_back/target/redox_base.rs b/src/librustc_target/spec/redox_base.rs index c7915d4de72..c28746a9363 100644 --- a/src/librustc_back/target/redox_base.rs +++ b/src/librustc_target/spec/redox_base.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{LinkArgs, TargetOptions}; +use spec::{LinkArgs, LinkerFlavor, TargetOptions}; use std::default::Default; pub fn opts() -> TargetOptions { diff --git a/src/librustc_back/target/s390x_unknown_linux_gnu.rs b/src/librustc_target/spec/s390x_unknown_linux_gnu.rs index d96379547fb..c9a9625ebab 100644 --- a/src/librustc_back/target/s390x_unknown_linux_gnu.rs +++ b/src/librustc_target/spec/s390x_unknown_linux_gnu.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetResult}; +use spec::{LinkerFlavor, Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_base::opts(); diff --git a/src/librustc_back/target/solaris_base.rs b/src/librustc_target/spec/solaris_base.rs index 41323c9c26b..c14cc3f5bc3 100644 --- a/src/librustc_back/target/solaris_base.rs +++ b/src/librustc_target/spec/solaris_base.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use target::TargetOptions; +use spec::TargetOptions; use std::default::Default; pub fn opts() -> TargetOptions { diff --git a/src/librustc_back/target/sparc64_unknown_linux_gnu.rs b/src/librustc_target/spec/sparc64_unknown_linux_gnu.rs index aed40e9df43..f68b5fd24bf 100644 --- a/src/librustc_back/target/sparc64_unknown_linux_gnu.rs +++ b/src/librustc_target/spec/sparc64_unknown_linux_gnu.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetResult}; +use spec::{LinkerFlavor, Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_base::opts(); diff --git a/src/librustc_back/target/sparc64_unknown_netbsd.rs b/src/librustc_target/spec/sparc64_unknown_netbsd.rs index 483c8790945..1c1bca9b2b8 100644 --- a/src/librustc_back/target/sparc64_unknown_netbsd.rs +++ b/src/librustc_target/spec/sparc64_unknown_netbsd.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetResult}; +use spec::{LinkerFlavor, Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::netbsd_base::opts(); diff --git a/src/librustc_back/target/sparc_unknown_linux_gnu.rs b/src/librustc_target/spec/sparc_unknown_linux_gnu.rs index a03e6937b2c..4e352374f90 100644 --- a/src/librustc_back/target/sparc_unknown_linux_gnu.rs +++ b/src/librustc_target/spec/sparc_unknown_linux_gnu.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetResult}; +use spec::{LinkerFlavor, Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_base::opts(); diff --git a/src/librustc_back/target/sparcv9_sun_solaris.rs b/src/librustc_target/spec/sparcv9_sun_solaris.rs index 1d9027275db..7dea1b75a3c 100644 --- a/src/librustc_back/target/sparcv9_sun_solaris.rs +++ b/src/librustc_target/spec/sparcv9_sun_solaris.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetResult}; +use spec::{LinkerFlavor, Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::solaris_base::opts(); diff --git a/src/librustc_back/target/thumb_base.rs b/src/librustc_target/spec/thumb_base.rs index bb1fbfad261..fdaf1dc6110 100644 --- a/src/librustc_back/target/thumb_base.rs +++ b/src/librustc_target/spec/thumb_base.rs @@ -35,9 +35,8 @@ // differentiate these targets from our other `arm(v7)-*-*-gnueabi(hf)` targets in the context of // build scripts / gcc flags. -use PanicStrategy; use std::default::Default; -use target::TargetOptions; +use spec::{PanicStrategy, TargetOptions}; pub fn opts() -> TargetOptions { // See rust-lang/rfcs#1645 for a discussion about these defaults diff --git a/src/librustc_back/target/thumbv6m_none_eabi.rs b/src/librustc_target/spec/thumbv6m_none_eabi.rs index d164fbf9d96..9fea07c36f4 100644 --- a/src/librustc_back/target/thumbv6m_none_eabi.rs +++ b/src/librustc_target/spec/thumbv6m_none_eabi.rs @@ -10,8 +10,7 @@ // Targets the Cortex-M0, Cortex-M0+ and Cortex-M1 processors (ARMv6-M architecture) -use LinkerFlavor; -use target::{Target, TargetOptions, TargetResult}; +use spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { Ok(Target { diff --git a/src/librustc_back/target/thumbv7em_none_eabi.rs b/src/librustc_target/spec/thumbv7em_none_eabi.rs index 7e66ddf7b06..ab85c97b1b5 100644 --- a/src/librustc_back/target/thumbv7em_none_eabi.rs +++ b/src/librustc_target/spec/thumbv7em_none_eabi.rs @@ -19,8 +19,7 @@ // To opt-in to hardware accelerated floating point operations, you can use, for example, // `-C target-feature=+vfp4` or `-C target-cpu=cortex-m4`. -use LinkerFlavor; -use target::{Target, TargetOptions, TargetResult}; +use spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { Ok(Target { diff --git a/src/librustc_back/target/thumbv7em_none_eabihf.rs b/src/librustc_target/spec/thumbv7em_none_eabihf.rs index 31835de36d6..4e62f29134e 100644 --- a/src/librustc_back/target/thumbv7em_none_eabihf.rs +++ b/src/librustc_target/spec/thumbv7em_none_eabihf.rs @@ -18,8 +18,7 @@ // // To opt into double precision hardware support, use the `-C target-feature=-fp-only-sp` flag. -use LinkerFlavor; -use target::{Target, TargetOptions, TargetResult}; +use spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { Ok(Target { diff --git a/src/librustc_back/target/thumbv7m_none_eabi.rs b/src/librustc_target/spec/thumbv7m_none_eabi.rs index 8f16ae4ea12..10dc503388a 100644 --- a/src/librustc_back/target/thumbv7m_none_eabi.rs +++ b/src/librustc_target/spec/thumbv7m_none_eabi.rs @@ -10,8 +10,7 @@ // Targets the Cortex-M3 processor (ARMv7-M) -use LinkerFlavor; -use target::{Target, TargetOptions, TargetResult}; +use spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { Ok(Target { diff --git a/src/librustc_back/target/wasm32_experimental_emscripten.rs b/src/librustc_target/spec/wasm32_experimental_emscripten.rs index 13dee3a5768..164df20f84f 100644 --- a/src/librustc_back/target/wasm32_experimental_emscripten.rs +++ b/src/librustc_target/spec/wasm32_experimental_emscripten.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use super::{LinkArgs, Target, TargetOptions}; +use super::{LinkArgs, LinkerFlavor, Target, TargetOptions}; pub fn target() -> Result<Target, String> { let mut post_link_args = LinkArgs::new(); diff --git a/src/librustc_back/target/wasm32_unknown_emscripten.rs b/src/librustc_target/spec/wasm32_unknown_emscripten.rs index 2770e67e30a..5077abf1e0e 100644 --- a/src/librustc_back/target/wasm32_unknown_emscripten.rs +++ b/src/librustc_target/spec/wasm32_unknown_emscripten.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use super::{LinkArgs, Target, TargetOptions}; +use super::{LinkArgs, LinkerFlavor, Target, TargetOptions}; pub fn target() -> Result<Target, String> { let mut post_link_args = LinkArgs::new(); diff --git a/src/librustc_back/target/wasm32_unknown_unknown.rs b/src/librustc_target/spec/wasm32_unknown_unknown.rs index 1d84e137517..56170bbb869 100644 --- a/src/librustc_back/target/wasm32_unknown_unknown.rs +++ b/src/librustc_target/spec/wasm32_unknown_unknown.rs @@ -17,8 +17,7 @@ // (aka panic=abort by default), but otherwise this is in general a relatively // standard target. -use {LinkerFlavor, LldFlavor}; -use super::{Target, TargetOptions, PanicStrategy}; +use super::{LldFlavor, LinkerFlavor, Target, TargetOptions, PanicStrategy}; pub fn target() -> Result<Target, String> { let opts = TargetOptions { diff --git a/src/librustc_back/target/windows_base.rs b/src/librustc_target/spec/windows_base.rs index 971b21e062f..176df9f1325 100644 --- a/src/librustc_back/target/windows_base.rs +++ b/src/librustc_target/spec/windows_base.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{LinkArgs, TargetOptions}; +use spec::{LinkArgs, LinkerFlavor, TargetOptions}; use std::default::Default; pub fn opts() -> TargetOptions { @@ -103,6 +102,7 @@ pub fn opts() -> TargetOptions { custom_unwind_resume: true, abi_return_struct_as_int: true, emit_debug_gdb_scripts: false, + requires_uwtable: true, .. Default::default() } diff --git a/src/librustc_back/target/windows_msvc_base.rs b/src/librustc_target/spec/windows_msvc_base.rs index 06e879bec34..1f00e690cd3 100644 --- a/src/librustc_back/target/windows_msvc_base.rs +++ b/src/librustc_target/spec/windows_msvc_base.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{LinkArgs, TargetOptions}; +use spec::{LinkArgs, LinkerFlavor, TargetOptions}; use std::default::Default; pub fn opts() -> TargetOptions { @@ -35,6 +34,7 @@ pub fn opts() -> TargetOptions { crt_static_respected: true, abi_return_struct_as_int: true, emit_debug_gdb_scripts: false, + requires_uwtable: true, .. Default::default() } diff --git a/src/librustc_back/target/x86_64_apple_darwin.rs b/src/librustc_target/spec/x86_64_apple_darwin.rs index 71ac360eb99..a4efd7e0066 100644 --- a/src/librustc_back/target/x86_64_apple_darwin.rs +++ b/src/librustc_target/spec/x86_64_apple_darwin.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetResult}; +use spec::{LinkerFlavor, Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::apple_base::opts(); diff --git a/src/librustc_back/target/x86_64_apple_ios.rs b/src/librustc_target/spec/x86_64_apple_ios.rs index eed99e3784c..eeb53d72fe8 100644 --- a/src/librustc_back/target/x86_64_apple_ios.rs +++ b/src/librustc_target/spec/x86_64_apple_ios.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetOptions, TargetResult}; +use spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; use super::apple_ios_base::{opts, Arch}; pub fn target() -> TargetResult { diff --git a/src/librustc_back/target/x86_64_linux_android.rs b/src/librustc_target/spec/x86_64_linux_android.rs index 2aae7394153..06abe916784 100644 --- a/src/librustc_back/target/x86_64_linux_android.rs +++ b/src/librustc_target/spec/x86_64_linux_android.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetResult}; +use spec::{LinkerFlavor, Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::android_base::opts(); diff --git a/src/librustc_back/target/x86_64_pc_windows_gnu.rs b/src/librustc_target/spec/x86_64_pc_windows_gnu.rs index 70062d13638..8d2f702bc4a 100644 --- a/src/librustc_back/target/x86_64_pc_windows_gnu.rs +++ b/src/librustc_target/spec/x86_64_pc_windows_gnu.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetResult}; +use spec::{LinkerFlavor, Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::windows_base::opts(); diff --git a/src/librustc_back/target/x86_64_pc_windows_msvc.rs b/src/librustc_target/spec/x86_64_pc_windows_msvc.rs index 813d0f1bad9..ab610ea94ae 100644 --- a/src/librustc_back/target/x86_64_pc_windows_msvc.rs +++ b/src/librustc_target/spec/x86_64_pc_windows_msvc.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetResult}; +use spec::{LinkerFlavor, Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::windows_msvc_base::opts(); diff --git a/src/librustc_back/target/x86_64_rumprun_netbsd.rs b/src/librustc_target/spec/x86_64_rumprun_netbsd.rs index 3158665a2e2..ed15cfd9036 100644 --- a/src/librustc_back/target/x86_64_rumprun_netbsd.rs +++ b/src/librustc_target/spec/x86_64_rumprun_netbsd.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetResult}; +use spec::{LinkerFlavor, Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::netbsd_base::opts(); diff --git a/src/librustc_back/target/x86_64_sun_solaris.rs b/src/librustc_target/spec/x86_64_sun_solaris.rs index d5541385390..e84f21c5006 100644 --- a/src/librustc_back/target/x86_64_sun_solaris.rs +++ b/src/librustc_target/spec/x86_64_sun_solaris.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetResult}; +use spec::{LinkerFlavor, Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::solaris_base::opts(); diff --git a/src/librustc_back/target/x86_64_unknown_bitrig.rs b/src/librustc_target/spec/x86_64_unknown_bitrig.rs index 1ea985d70ea..21ec6dffcbb 100644 --- a/src/librustc_back/target/x86_64_unknown_bitrig.rs +++ b/src/librustc_target/spec/x86_64_unknown_bitrig.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetResult}; +use spec::{LinkerFlavor, Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::bitrig_base::opts(); diff --git a/src/librustc_back/target/x86_64_unknown_cloudabi.rs b/src/librustc_target/spec/x86_64_unknown_cloudabi.rs index d1a9cb1cd7e..8dc8bd7a7fa 100644 --- a/src/librustc_back/target/x86_64_unknown_cloudabi.rs +++ b/src/librustc_target/spec/x86_64_unknown_cloudabi.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetResult}; +use spec::{LinkerFlavor, Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::cloudabi_base::opts(); diff --git a/src/librustc_back/target/x86_64_unknown_dragonfly.rs b/src/librustc_target/spec/x86_64_unknown_dragonfly.rs index 56e4685fed5..50b2871c2ee 100644 --- a/src/librustc_back/target/x86_64_unknown_dragonfly.rs +++ b/src/librustc_target/spec/x86_64_unknown_dragonfly.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetResult}; +use spec::{LinkerFlavor, Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::dragonfly_base::opts(); diff --git a/src/librustc_back/target/x86_64_unknown_freebsd.rs b/src/librustc_target/spec/x86_64_unknown_freebsd.rs index 3d26592530a..f0aa81ed459 100644 --- a/src/librustc_back/target/x86_64_unknown_freebsd.rs +++ b/src/librustc_target/spec/x86_64_unknown_freebsd.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetResult}; +use spec::{LinkerFlavor, Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::freebsd_base::opts(); diff --git a/src/librustc_back/target/x86_64_unknown_fuchsia.rs b/src/librustc_target/spec/x86_64_unknown_fuchsia.rs index 6e97d53cfad..a510ec8eb34 100644 --- a/src/librustc_back/target/x86_64_unknown_fuchsia.rs +++ b/src/librustc_target/spec/x86_64_unknown_fuchsia.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetResult}; +use spec::{LinkerFlavor, Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::fuchsia_base::opts(); diff --git a/src/librustc_back/target/x86_64_unknown_haiku.rs b/src/librustc_target/spec/x86_64_unknown_haiku.rs index f42c480e7a1..1e78461861a 100644 --- a/src/librustc_back/target/x86_64_unknown_haiku.rs +++ b/src/librustc_target/spec/x86_64_unknown_haiku.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetResult}; +use spec::{LinkerFlavor, Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::haiku_base::opts(); diff --git a/src/librustc_back/target/x86_64_unknown_l4re_uclibc.rs b/src/librustc_target/spec/x86_64_unknown_l4re_uclibc.rs index 821a77f52f5..f1179c18294 100644 --- a/src/librustc_back/target/x86_64_unknown_l4re_uclibc.rs +++ b/src/librustc_target/spec/x86_64_unknown_l4re_uclibc.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetResult}; +use spec::{LinkerFlavor, Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::l4re_base::opts(); diff --git a/src/librustc_back/target/x86_64_unknown_linux_gnu.rs b/src/librustc_target/spec/x86_64_unknown_linux_gnu.rs index cfe80c96732..56559661b03 100644 --- a/src/librustc_back/target/x86_64_unknown_linux_gnu.rs +++ b/src/librustc_target/spec/x86_64_unknown_linux_gnu.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetResult}; +use spec::{LinkerFlavor, Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_base::opts(); diff --git a/src/librustc_back/target/x86_64_unknown_linux_gnux32.rs b/src/librustc_target/spec/x86_64_unknown_linux_gnux32.rs index 70382032836..72b5bd27c7d 100644 --- a/src/librustc_back/target/x86_64_unknown_linux_gnux32.rs +++ b/src/librustc_target/spec/x86_64_unknown_linux_gnux32.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetResult}; +use spec::{LinkerFlavor, Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_base::opts(); diff --git a/src/librustc_back/target/x86_64_unknown_linux_musl.rs b/src/librustc_target/spec/x86_64_unknown_linux_musl.rs index 7e304748e32..f1924efcf98 100644 --- a/src/librustc_back/target/x86_64_unknown_linux_musl.rs +++ b/src/librustc_target/spec/x86_64_unknown_linux_musl.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetResult}; +use spec::{LinkerFlavor, Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_musl_base::opts(); diff --git a/src/librustc_back/target/x86_64_unknown_netbsd.rs b/src/librustc_target/spec/x86_64_unknown_netbsd.rs index 7afb446f5dc..6e8ca6b9e19 100644 --- a/src/librustc_back/target/x86_64_unknown_netbsd.rs +++ b/src/librustc_target/spec/x86_64_unknown_netbsd.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetResult}; +use spec::{LinkerFlavor, Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::netbsd_base::opts(); diff --git a/src/librustc_back/target/x86_64_unknown_openbsd.rs b/src/librustc_target/spec/x86_64_unknown_openbsd.rs index e4bbdbec4c8..c60b7c86680 100644 --- a/src/librustc_back/target/x86_64_unknown_openbsd.rs +++ b/src/librustc_target/spec/x86_64_unknown_openbsd.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetResult}; +use spec::{LinkerFlavor, Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::openbsd_base::opts(); diff --git a/src/librustc_back/target/x86_64_unknown_redox.rs b/src/librustc_target/spec/x86_64_unknown_redox.rs index 401fa4ca2cb..548dfb06109 100644 --- a/src/librustc_back/target/x86_64_unknown_redox.rs +++ b/src/librustc_target/spec/x86_64_unknown_redox.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use LinkerFlavor; -use target::{Target, TargetResult}; +use spec::{LinkerFlavor, Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::redox_base::opts(); diff --git a/src/librustc_traits/evaluate_obligation.rs b/src/librustc_traits/evaluate_obligation.rs new file mode 100644 index 00000000000..21259bbcd38 --- /dev/null +++ b/src/librustc_traits/evaluate_obligation.rs @@ -0,0 +1,35 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use rustc::traits::{EvaluationResult, Obligation, ObligationCause, + OverflowError, SelectionContext, TraitQueryMode}; +use rustc::traits::query::CanonicalPredicateGoal; +use rustc::ty::{ParamEnvAnd, TyCtxt}; +use syntax::codemap::DUMMY_SP; + +crate fn evaluate_obligation<'tcx>( + tcx: TyCtxt<'_, 'tcx, 'tcx>, + goal: CanonicalPredicateGoal<'tcx>, +) -> Result<EvaluationResult, OverflowError> { + tcx.infer_ctxt().enter(|ref infcx| { + let ( + ParamEnvAnd { + param_env, + value: predicate, + }, + _canonical_inference_vars, + ) = infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &goal); + + let mut selcx = SelectionContext::with_query_mode(&infcx, TraitQueryMode::Canonical); + let obligation = Obligation::new(ObligationCause::dummy(), param_env, predicate); + + selcx.evaluate_obligation_recursively(&obligation) + }) +} diff --git a/src/librustc_traits/lib.rs b/src/librustc_traits/lib.rs index 8136f6857a5..7f18fac2db5 100644 --- a/src/librustc_traits/lib.rs +++ b/src/librustc_traits/lib.rs @@ -22,6 +22,7 @@ extern crate syntax; extern crate syntax_pos; mod dropck_outlives; +mod evaluate_obligation; mod normalize_projection_ty; mod normalize_erasing_regions; mod util; @@ -37,6 +38,8 @@ pub fn provide(p: &mut Providers) { normalize_ty_after_erasing_regions: normalize_erasing_regions::normalize_ty_after_erasing_regions, program_clauses_for: lowering::program_clauses_for, + program_clauses_for_env: lowering::program_clauses_for_env, + evaluate_obligation: evaluate_obligation::evaluate_obligation, ..*p }; } diff --git a/src/librustc_traits/lowering.rs b/src/librustc_traits/lowering.rs index 36e60cee788..b6a086f609d 100644 --- a/src/librustc_traits/lowering.rs +++ b/src/librustc_traits/lowering.rs @@ -8,14 +8,17 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use rustc::hir::{self, ImplPolarity}; use rustc::hir::def_id::DefId; use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor}; -use rustc::ty::{self, Slice, TyCtxt}; +use rustc::hir::map::definitions::DefPathData; +use rustc::hir::{self, ImplPolarity}; +use rustc::traits::{Clause, Clauses, DomainGoal, Goal, PolyDomainGoal, ProgramClause, + WhereClauseAtom}; use rustc::ty::subst::Substs; -use rustc::traits::{WhereClauseAtom, PolyDomainGoal, DomainGoal, ProgramClause, Clause, Goal}; +use rustc::ty::{self, Slice, TyCtxt}; +use rustc_data_structures::fx::FxHashSet; +use std::mem; use syntax::ast; -use rustc_data_structures::sync::Lrc; use std::iter; @@ -24,7 +27,10 @@ trait Lower<T> { fn lower(&self) -> T; } -impl<T, U> Lower<Vec<U>> for Vec<T> where T: Lower<U> { +impl<T, U> Lower<Vec<U>> for Vec<T> +where + T: Lower<U>, +{ fn lower(&self) -> Vec<U> { self.iter().map(|item| item.lower()).collect() } @@ -42,7 +48,10 @@ impl<'tcx> Lower<WhereClauseAtom<'tcx>> for ty::ProjectionPredicate<'tcx> { } } -impl<'tcx, T> Lower<DomainGoal<'tcx>> for T where T: Lower<WhereClauseAtom<'tcx>> { +impl<'tcx, T> Lower<DomainGoal<'tcx>> for T +where + T: Lower<WhereClauseAtom<'tcx>>, +{ fn lower(&self) -> DomainGoal<'tcx> { DomainGoal::Holds(self.lower()) } @@ -67,7 +76,8 @@ impl<'tcx> Lower<DomainGoal<'tcx>> for ty::TypeOutlivesPredicate<'tcx> { /// `forall<'a> { T: Fn(&'a i32) }` which corresponds to something like /// `Binder<Holds(Implemented(TraitPredicate))>`. impl<'tcx, T> Lower<PolyDomainGoal<'tcx>> for ty::Binder<T> - where T: Lower<DomainGoal<'tcx>> + ty::fold::TypeFoldable<'tcx> +where + T: Lower<DomainGoal<'tcx>> + ty::fold::TypeFoldable<'tcx>, { fn lower(&self) -> PolyDomainGoal<'tcx> { self.map_bound_ref(|p| p.lower()) @@ -84,10 +94,9 @@ impl<'tcx> Lower<PolyDomainGoal<'tcx>> for ty::Predicate<'tcx> { TypeOutlives(predicate) => predicate.lower(), Projection(predicate) => predicate.lower(), WellFormed(ty) => ty::Binder::dummy(DomainGoal::WellFormedTy(*ty)), - ObjectSafe(..) | - ClosureKind(..) | - Subtype(..) | - ConstEvaluatable(..) => unimplemented!(), + ObjectSafe(..) | ClosureKind(..) | Subtype(..) | ConstEvaluatable(..) => { + unimplemented!() + } } } } @@ -104,44 +113,88 @@ impl<'tcx> IntoFromEnvGoal for DomainGoal<'tcx> { use self::DomainGoal::*; match self { Holds(wc_atom) => FromEnv(wc_atom), - WellFormed(..) | - FromEnv(..) | - WellFormedTy(..) | - FromEnvTy(..) | - Normalize(..) | - RegionOutlives(..) | - TypeOutlives(..) => self, + WellFormed(..) | FromEnv(..) | WellFormedTy(..) | FromEnvTy(..) | Normalize(..) + | RegionOutlives(..) | TypeOutlives(..) => self, } } } -crate fn program_clauses_for<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) - -> Lrc<&'tcx Slice<Clause<'tcx>>> -{ - let node_id = tcx.hir.as_local_node_id(def_id).unwrap(); - let node = tcx.hir.find(node_id).unwrap(); - match node { - hir::map::Node::NodeItem(item) => match item.node { - hir::ItemTrait(..) => program_clauses_for_trait(tcx, def_id), - hir::ItemImpl(..) => program_clauses_for_impl(tcx, def_id), - _ => Lrc::new(tcx.mk_clauses(iter::empty::<Clause>())), - } - hir::map::Node::NodeImplItem(item) => { - if let hir::ImplItemKind::Type(..) = item.node { - program_clauses_for_associated_type_value(tcx, def_id) - } else { - Lrc::new(tcx.mk_clauses(iter::empty::<Clause>())) - } - }, +crate fn program_clauses_for<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId, +) -> Clauses<'tcx> { + match tcx.def_key(def_id).disambiguated_data.data { + DefPathData::Trait(_) => program_clauses_for_trait(tcx, def_id), + DefPathData::Impl => program_clauses_for_impl(tcx, def_id), + DefPathData::AssocTypeInImpl(..) => program_clauses_for_associated_type_value(tcx, def_id), + _ => Slice::empty(), + } +} - // FIXME: other constructions e.g. traits, associated types... - _ => Lrc::new(tcx.mk_clauses(iter::empty::<Clause>())), +crate fn program_clauses_for_env<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, +) -> Clauses<'tcx> { + debug!("program_clauses_for_env(param_env={:?})", param_env); + + let mut last_round = FxHashSet(); + last_round.extend( + param_env + .caller_bounds + .iter() + .flat_map(|&p| predicate_def_id(p)), + ); + + let mut closure = last_round.clone(); + let mut next_round = FxHashSet(); + while !last_round.is_empty() { + next_round.extend( + last_round + .drain() + .flat_map(|def_id| { + tcx.predicates_of(def_id) + .instantiate_identity(tcx) + .predicates + }) + .flat_map(|p| predicate_def_id(p)) + .filter(|&def_id| closure.insert(def_id)), + ); + mem::swap(&mut next_round, &mut last_round); + } + + debug!("program_clauses_for_env: closure = {:#?}", closure); + + return tcx.mk_clauses( + closure + .into_iter() + .flat_map(|def_id| tcx.program_clauses_for(def_id).iter().cloned()), + ); + + /// Given that `predicate` is in the environment, returns the + /// def-id of something (e.g., a trait, associated item, etc) + /// whose predicates can also be assumed to be true. We will + /// compute the transitive closure of such things. + fn predicate_def_id<'tcx>(predicate: ty::Predicate<'tcx>) -> Option<DefId> { + match predicate { + ty::Predicate::Trait(predicate) => Some(predicate.def_id()), + + ty::Predicate::Projection(projection) => Some(projection.item_def_id()), + + ty::Predicate::WellFormed(..) + | ty::Predicate::RegionOutlives(..) + | ty::Predicate::TypeOutlives(..) + | ty::Predicate::ObjectSafe(..) + | ty::Predicate::ClosureKind(..) + | ty::Predicate::Subtype(..) + | ty::Predicate::ConstEvaluatable(..) => None, + } } } -fn program_clauses_for_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) - -> Lrc<&'tcx Slice<Clause<'tcx>>> -{ +fn program_clauses_for_trait<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId, +) -> Clauses<'tcx> { // `trait Trait<P1..Pn> where WC { .. } // P0 == Self` // Rule Implemented-From-Env (see rustc guide) @@ -156,8 +209,8 @@ fn program_clauses_for_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefI let trait_pred = ty::TraitPredicate { trait_ref: ty::TraitRef { def_id, - substs: Substs::identity_for_item(tcx, def_id) - } + substs: Substs::identity_for_item(tcx, def_id), + }, }; // `FromEnv(Self: Trait<P1..Pn>)` let from_env = Goal::from(DomainGoal::FromEnv(trait_pred.lower())); @@ -169,9 +222,7 @@ fn program_clauses_for_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefI goal: impl_trait, hypotheses: tcx.mk_goals(iter::once(from_env)), }; - let clauses = iter::once( - Clause::ForAll(ty::Binder::dummy(implemented_from_env)) - ); + let clauses = iter::once(Clause::ForAll(ty::Binder::dummy(implemented_from_env))); // Rule Implied-Bound-From-Trait // @@ -186,11 +237,11 @@ fn program_clauses_for_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefI // FIXME: Remove the [1..] slice; this is a hack because the query // predicates_of currently includes the trait itself (`Self: Trait<P1..Pn>`). let where_clauses = &tcx.predicates_of(def_id).predicates; - let implied_bound_clauses = - where_clauses[1..].into_iter() + let implied_bound_clauses = where_clauses[1..] + .into_iter() .map(|wc| implied_bound_from_trait(tcx, trait_pred, wc)); - Lrc::new(tcx.mk_clauses(clauses.chain(implied_bound_clauses))) + tcx.mk_clauses(clauses.chain(implied_bound_clauses)) } /// For a given `where_clause`, returns a clause `FromEnv(WC) :- FromEnv(Self: Trait<P1..Pn>)`. @@ -203,19 +254,15 @@ fn implied_bound_from_trait<'a, 'tcx>( let impl_trait = DomainGoal::FromEnv(WhereClauseAtom::Implemented(trait_pred)); // `FromEnv(WC) :- FromEnv(Self: Trait<P1..Pn>)` - Clause::ForAll( - where_clause.lower().map_bound(|goal| ProgramClause { - goal: goal.into_from_env_goal(), - hypotheses: tcx.mk_goals(iter::once(Goal::from(impl_trait))), - }) - ) + Clause::ForAll(where_clause.lower().map_bound(|goal| ProgramClause { + goal: goal.into_from_env_goal(), + hypotheses: tcx.mk_goals(iter::once(Goal::from(impl_trait))), + })) } -fn program_clauses_for_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) - -> Lrc<&'tcx Slice<Clause<'tcx>>> -{ +fn program_clauses_for_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Clauses<'tcx> { if let ImplPolarity::Negative = tcx.impl_polarity(def_id) { - return Lrc::new(tcx.mk_clauses(iter::empty::<Clause>())); + return Slice::empty(); } // Rule Implemented-From-Impl (see rustc guide) @@ -231,23 +278,25 @@ fn program_clauses_for_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId let trait_ref = tcx.impl_trait_ref(def_id).unwrap(); // `Implemented(A0: Trait<A1..An>)` let trait_pred = ty::TraitPredicate { trait_ref }.lower(); - // `WC` + // `WC` let where_clauses = tcx.predicates_of(def_id).predicates.lower(); - // `Implemented(A0: Trait<A1..An>) :- WC` + // `Implemented(A0: Trait<A1..An>) :- WC` let clause = ProgramClause { goal: trait_pred, hypotheses: tcx.mk_goals( - where_clauses.into_iter().map(|wc| Goal::from_poly_domain_goal(wc, tcx)) - ) + where_clauses + .into_iter() + .map(|wc| Goal::from_poly_domain_goal(wc, tcx)), + ), }; - Lrc::new(tcx.mk_clauses(iter::once(Clause::ForAll(ty::Binder::dummy(clause))))) + tcx.mk_clauses(iter::once(Clause::ForAll(ty::Binder::dummy(clause)))) } pub fn program_clauses_for_associated_type_value<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, item_id: DefId, -) -> Lrc<&'tcx Slice<Clause<'tcx>>> { +) -> Clauses<'tcx> { // Rule Normalize-From-Impl (see rustc guide) // // ```impl<P0..Pn> Trait<A1..An> for A0 @@ -290,10 +339,12 @@ pub fn program_clauses_for_associated_type_value<'a, 'tcx>( let clause = ProgramClause { goal: normalize_goal, hypotheses: tcx.mk_goals( - where_clauses.into_iter().map(|wc| Goal::from_poly_domain_goal(wc, tcx)) + where_clauses + .into_iter() + .map(|wc| Goal::from_poly_domain_goal(wc, tcx)), ), }; - Lrc::new(tcx.mk_clauses(iter::once(Clause::ForAll(ty::Binder::dummy(clause))))) + tcx.mk_clauses(iter::once(Clause::ForAll(ty::Binder::dummy(clause)))) } pub fn dump_program_clauses<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { @@ -302,27 +353,54 @@ pub fn dump_program_clauses<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { } let mut visitor = ClauseDumper { tcx }; - tcx.hir.krate().visit_all_item_likes(&mut visitor.as_deep_visitor()); + tcx.hir + .krate() + .visit_all_item_likes(&mut visitor.as_deep_visitor()); } struct ClauseDumper<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, } -impl<'a, 'tcx> ClauseDumper<'a, 'tcx > { +impl<'a, 'tcx> ClauseDumper<'a, 'tcx> { fn process_attrs(&mut self, node_id: ast::NodeId, attrs: &[ast::Attribute]) { let def_id = self.tcx.hir.local_def_id(node_id); for attr in attrs { + let mut clauses = None; + if attr.check_name("rustc_dump_program_clauses") { - let clauses = self.tcx.program_clauses_for(def_id); - for clause in *clauses { - // Skip the top-level binder for a less verbose output - let program_clause = match clause { - Clause::Implies(program_clause) => program_clause, - Clause::ForAll(program_clause) => program_clause.skip_binder(), - }; - self.tcx.sess.struct_span_err(attr.span, &format!("{}", program_clause)).emit(); + clauses = Some(self.tcx.program_clauses_for(def_id)); + } + + if attr.check_name("rustc_dump_env_program_clauses") { + let param_env = self.tcx.param_env(def_id); + clauses = Some(self.tcx.program_clauses_for_env(param_env)); + } + + if let Some(clauses) = clauses { + let mut err = self.tcx + .sess + .struct_span_err(attr.span, "program clause dump"); + + let mut strings: Vec<_> = clauses + .iter() + .map(|clause| { + // Skip the top-level binder for a less verbose output + let program_clause = match clause { + Clause::Implies(program_clause) => program_clause, + Clause::ForAll(program_clause) => program_clause.skip_binder(), + }; + format!("{}", program_clause) + }) + .collect(); + + strings.sort(); + + for string in strings { + err.note(&string); } + + err.emit(); } } } diff --git a/src/librustc_traits/normalize_erasing_regions.rs b/src/librustc_traits/normalize_erasing_regions.rs index 1857df5717b..299433d479d 100644 --- a/src/librustc_traits/normalize_erasing_regions.rs +++ b/src/librustc_traits/normalize_erasing_regions.rs @@ -17,6 +17,8 @@ crate fn normalize_ty_after_erasing_regions<'tcx>( tcx: TyCtxt<'_, 'tcx, 'tcx>, goal: ParamEnvAnd<'tcx, Ty<'tcx>>, ) -> Ty<'tcx> { + debug!("normalize_ty_after_erasing_regions(goal={:#?})", goal); + let ParamEnvAnd { param_env, value } = goal; tcx.sess.perf_stats.normalize_ty_after_erasing_regions.fetch_add(1, Ordering::Relaxed); tcx.infer_ctxt().enter(|infcx| { diff --git a/src/librustc_traits/util.rs b/src/librustc_traits/util.rs index bff070ab73d..e4cb118a4f7 100644 --- a/src/librustc_traits/util.rs +++ b/src/librustc_traits/util.rs @@ -9,8 +9,7 @@ // except according to those terms. use rustc::infer::InferCtxt; -use rustc::infer::canonical::{CanonicalVarValues, Canonicalize, Certainty, QueryRegionConstraints, - QueryResult}; +use rustc::infer::canonical::{CanonicalVarValues, Canonicalize, Certainty, QueryResult}; use rustc::infer::region_constraints::{Constraint, RegionConstraintData}; use rustc::traits::{FulfillmentContext, TraitEngine}; use rustc::traits::query::NoSolution; @@ -62,7 +61,7 @@ where let region_obligations = infcx.take_registered_region_obligations(); - let (region_outlives, ty_outlives) = infcx.with_region_constraints(|region_constraints| { + let region_constraints = infcx.with_region_constraints(|region_constraints| { let RegionConstraintData { constraints, verifys, @@ -72,24 +71,32 @@ where assert!(verifys.is_empty()); assert!(givens.is_empty()); - let region_outlives: Vec<_> = constraints + let mut outlives: Vec<_> = constraints .into_iter() .map(|(k, _)| match *k { - Constraint::VarSubVar(v1, v2) => { - (tcx.mk_region(ty::ReVar(v1)), tcx.mk_region(ty::ReVar(v2))) + Constraint::VarSubVar(v1, v2) => ty::OutlivesPredicate( + tcx.mk_region(ty::ReVar(v1)).into(), + tcx.mk_region(ty::ReVar(v2)), + ), + Constraint::VarSubReg(v1, r2) => { + ty::OutlivesPredicate(tcx.mk_region(ty::ReVar(v1)).into(), r2) } - Constraint::VarSubReg(v1, r2) => (tcx.mk_region(ty::ReVar(v1)), r2), - Constraint::RegSubVar(r1, v2) => (r1, tcx.mk_region(ty::ReVar(v2))), - Constraint::RegSubReg(r1, r2) => (r1, r2), + Constraint::RegSubVar(r1, v2) => { + ty::OutlivesPredicate(r1.into(), tcx.mk_region(ty::ReVar(v2))) + } + Constraint::RegSubReg(r1, r2) => ty::OutlivesPredicate(r1.into(), r2), }) + .map(ty::Binder::dummy) // no bound regions in the code above .collect(); - let ty_outlives: Vec<_> = region_obligations - .into_iter() - .map(|(_, r_o)| (r_o.sup_type, r_o.sub_region)) - .collect(); + outlives.extend( + region_obligations + .into_iter() + .map(|(_, r_o)| ty::OutlivesPredicate(r_o.sup_type.into(), r_o.sub_region)) + .map(ty::Binder::dummy) // no bound regions in the code above + ); - (region_outlives, ty_outlives) + outlives }); let certainty = if ambig_errors.is_empty() { @@ -100,10 +107,7 @@ where let (canonical_result, _) = infcx.canonicalize_response(&QueryResult { var_values: inference_vars, - region_constraints: QueryRegionConstraints { - region_outlives, - ty_outlives, - }, + region_constraints, certainty, value: answer, }); diff --git a/src/librustc_trans/Cargo.toml b/src/librustc_trans/Cargo.toml index 176fd86f29d..32432d6cc83 100644 --- a/src/librustc_trans/Cargo.toml +++ b/src/librustc_trans/Cargo.toml @@ -10,7 +10,6 @@ crate-type = ["dylib"] test = false [dependencies] -bitflags = "1.0" cc = "1.0.1" flate2 = "1.0" jobserver = "0.1.5" @@ -21,7 +20,7 @@ rustc = { path = "../librustc" } rustc-demangle = "0.1.4" rustc_allocator = { path = "../librustc_allocator" } rustc_apfloat = { path = "../librustc_apfloat" } -rustc_back = { path = "../librustc_back" } +rustc_target = { path = "../librustc_target" } rustc_const_math = { path = "../librustc_const_math" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_errors = { path = "../librustc_errors" } @@ -40,9 +39,9 @@ tempdir = "0.3" env_logger = { version = "0.5", default-features = false } [features] -# Used to communicate the feature to `rustc_back` in the same manner that the +# Used to communicate the feature to `rustc_target` in the same manner that the # `rustc` driver script communicate this. -jemalloc = ["rustc_back/jemalloc"] +jemalloc = ["rustc_target/jemalloc"] # This is used to convince Cargo to separately cache builds of `rustc_trans` # when this option is enabled or not. That way we can build two, cache two diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 19ae1fa0478..1d0d7ec601f 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -13,77 +13,20 @@ use base; use builder::Builder; use common::{ty_fn_sig, C_usize}; use context::CodegenCx; -use cabi_x86; -use cabi_x86_64; -use cabi_x86_win64; -use cabi_arm; -use cabi_aarch64; -use cabi_powerpc; -use cabi_powerpc64; -use cabi_s390x; -use cabi_mips; -use cabi_mips64; -use cabi_asmjs; -use cabi_msp430; -use cabi_sparc; -use cabi_sparc64; -use cabi_nvptx; -use cabi_nvptx64; -use cabi_hexagon; -use cabi_wasm32; use mir::place::PlaceRef; use mir::operand::OperandValue; use type_::Type; use type_of::{LayoutLlvmExt, PointerKind}; +use rustc_target::abi::{LayoutOf, Size, TyLayout}; use rustc::ty::{self, Ty}; -use rustc::ty::layout::{self, Align, Size, TyLayout}; -use rustc::ty::layout::{HasDataLayout, LayoutOf}; +use rustc::ty::layout; use libc::c_uint; -use std::cmp; -pub use syntax::abi::Abi; +pub use rustc_target::spec::abi::Abi; pub use rustc::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA}; - -#[derive(Clone, Copy, PartialEq, Eq, Debug)] -pub enum PassMode { - /// Ignore the argument (useful for empty struct). - Ignore, - /// Pass the argument directly. - Direct(ArgAttributes), - /// Pass a pair's elements directly in two arguments. - Pair(ArgAttributes, ArgAttributes), - /// Pass the argument after casting it, to either - /// a single uniform or a pair of registers. - Cast(CastTarget), - /// Pass the argument indirectly via a hidden pointer. - Indirect(ArgAttributes), -} - -// Hack to disable non_upper_case_globals only for the bitflags! and not for the rest -// of this module -pub use self::attr_impl::ArgAttribute; - -#[allow(non_upper_case_globals)] -#[allow(unused)] -mod attr_impl { - // The subset of llvm::Attribute needed for arguments, packed into a bitfield. - bitflags! { - #[derive(Default)] - pub struct ArgAttribute: u16 { - const ByVal = 1 << 0; - const NoAlias = 1 << 1; - const NoCapture = 1 << 2; - const NonNull = 1 << 3; - const ReadOnly = 1 << 4; - const SExt = 1 << 5; - const StructRet = 1 << 6; - const ZExt = 1 << 7; - const InReg = 1 << 8; - } - } -} +pub use rustc_target::abi::call::*; macro_rules! for_each_kind { ($flags: ident, $f: ident, $($kind: ident),+) => ({ @@ -91,41 +34,24 @@ macro_rules! for_each_kind { }) } -impl ArgAttribute { +trait ArgAttributeExt { + fn for_each_kind<F>(&self, f: F) where F: FnMut(llvm::Attribute); +} + +impl ArgAttributeExt for ArgAttribute { fn for_each_kind<F>(&self, mut f: F) where F: FnMut(llvm::Attribute) { for_each_kind!(self, f, ByVal, NoAlias, NoCapture, NonNull, ReadOnly, SExt, StructRet, ZExt, InReg) } } -/// A compact representation of LLVM attributes (at least those relevant for this module) -/// that can be manipulated without interacting with LLVM's Attribute machinery. -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub struct ArgAttributes { - regular: ArgAttribute, - pointee_size: Size, - pointee_align: Option<Align> +pub trait ArgAttributesExt { + fn apply_llfn(&self, idx: AttributePlace, llfn: ValueRef); + fn apply_callsite(&self, idx: AttributePlace, callsite: ValueRef); } -impl ArgAttributes { - fn new() -> Self { - ArgAttributes { - regular: ArgAttribute::default(), - pointee_size: Size::from_bytes(0), - pointee_align: None, - } - } - - pub fn set(&mut self, attr: ArgAttribute) -> &mut Self { - self.regular = self.regular | attr; - self - } - - pub fn contains(&self, attr: ArgAttribute) -> bool { - self.regular.contains(attr) - } - - pub fn apply_llfn(&self, idx: AttributePlace, llfn: ValueRef) { +impl ArgAttributesExt for ArgAttributes { + fn apply_llfn(&self, idx: AttributePlace, llfn: ValueRef) { let mut regular = self.regular; unsafe { let deref = self.pointee_size.bytes(); @@ -150,7 +76,7 @@ impl ArgAttributes { } } - pub fn apply_callsite(&self, idx: AttributePlace, callsite: ValueRef) { + fn apply_callsite(&self, idx: AttributePlace, callsite: ValueRef) { let mut regular = self.regular; unsafe { let deref = self.pointee_size.bytes(); @@ -175,67 +101,13 @@ impl ArgAttributes { } } } -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub enum RegKind { - Integer, - Float, - Vector -} - -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub struct Reg { - pub kind: RegKind, - pub size: Size, -} - -macro_rules! reg_ctor { - ($name:ident, $kind:ident, $bits:expr) => { - pub fn $name() -> Reg { - Reg { - kind: RegKind::$kind, - size: Size::from_bits($bits) - } - } - } -} -impl Reg { - reg_ctor!(i8, Integer, 8); - reg_ctor!(i16, Integer, 16); - reg_ctor!(i32, Integer, 32); - reg_ctor!(i64, Integer, 64); - - reg_ctor!(f32, Float, 32); - reg_ctor!(f64, Float, 64); +pub trait LlvmType { + fn llvm_type(&self, cx: &CodegenCx) -> Type; } -impl Reg { - pub fn align(&self, cx: &CodegenCx) -> Align { - let dl = cx.data_layout(); - match self.kind { - RegKind::Integer => { - match self.size.bits() { - 1 => dl.i1_align, - 2...8 => dl.i8_align, - 9...16 => dl.i16_align, - 17...32 => dl.i32_align, - 33...64 => dl.i64_align, - 65...128 => dl.i128_align, - _ => bug!("unsupported integer: {:?}", self) - } - } - RegKind::Float => { - match self.size.bits() { - 32 => dl.f32_align, - 64 => dl.f64_align, - _ => bug!("unsupported float: {:?}", self) - } - } - RegKind::Vector => dl.vector_align(self.size) - } - } - - pub fn llvm_type(&self, cx: &CodegenCx) -> Type { +impl LlvmType for Reg { + fn llvm_type(&self, cx: &CodegenCx) -> Type { match self.kind { RegKind::Integer => Type::ix(cx, self.size.bits()), RegKind::Float => { @@ -252,180 +124,8 @@ impl Reg { } } -/// An argument passed entirely registers with the -/// same kind (e.g. HFA / HVA on PPC64 and AArch64). -#[derive(Clone, Copy, PartialEq, Eq, Debug)] -pub struct Uniform { - pub unit: Reg, - - /// The total size of the argument, which can be: - /// * equal to `unit.size` (one scalar/vector) - /// * a multiple of `unit.size` (an array of scalar/vectors) - /// * if `unit.kind` is `Integer`, the last element - /// can be shorter, i.e. `{ i64, i64, i32 }` for - /// 64-bit integers with a total size of 20 bytes - pub total: Size, -} - -impl From<Reg> for Uniform { - fn from(unit: Reg) -> Uniform { - Uniform { - unit, - total: unit.size - } - } -} - -impl Uniform { - pub fn align(&self, cx: &CodegenCx) -> Align { - self.unit.align(cx) - } -} - -pub trait LayoutExt<'tcx> { - fn is_aggregate(&self) -> bool; - fn homogeneous_aggregate<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> Option<Reg>; -} - -impl<'tcx> LayoutExt<'tcx> for TyLayout<'tcx> { - fn is_aggregate(&self) -> bool { - match self.abi { - layout::Abi::Uninhabited | - layout::Abi::Scalar(_) | - layout::Abi::Vector { .. } => false, - layout::Abi::ScalarPair(..) | - layout::Abi::Aggregate { .. } => true - } - } - - fn homogeneous_aggregate<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> Option<Reg> { - match self.abi { - layout::Abi::Uninhabited => None, - - // The primitive for this algorithm. - layout::Abi::Scalar(ref scalar) => { - let kind = match scalar.value { - layout::Int(..) | - layout::Pointer => RegKind::Integer, - layout::F32 | - layout::F64 => RegKind::Float - }; - Some(Reg { - kind, - size: self.size - }) - } - - layout::Abi::Vector { .. } => { - Some(Reg { - kind: RegKind::Vector, - size: self.size - }) - } - - layout::Abi::ScalarPair(..) | - layout::Abi::Aggregate { .. } => { - let mut total = Size::from_bytes(0); - let mut result = None; - - let is_union = match self.fields { - layout::FieldPlacement::Array { count, .. } => { - if count > 0 { - return self.field(cx, 0).homogeneous_aggregate(cx); - } else { - return None; - } - } - layout::FieldPlacement::Union(_) => true, - layout::FieldPlacement::Arbitrary { .. } => false - }; - - for i in 0..self.fields.count() { - if !is_union && total != self.fields.offset(i) { - return None; - } - - let field = self.field(cx, i); - match (result, field.homogeneous_aggregate(cx)) { - // The field itself must be a homogeneous aggregate. - (_, None) => return None, - // If this is the first field, record the unit. - (None, Some(unit)) => { - result = Some(unit); - } - // For all following fields, the unit must be the same. - (Some(prev_unit), Some(unit)) => { - if prev_unit != unit { - return None; - } - } - } - - // Keep track of the offset (without padding). - let size = field.size; - if is_union { - total = cmp::max(total, size); - } else { - total += size; - } - } - - // There needs to be no padding. - if total != self.size { - None - } else { - result - } - } - } - } -} - -#[derive(Clone, Copy, PartialEq, Eq, Debug)] -pub struct CastTarget { - pub prefix: [Option<RegKind>; 8], - pub prefix_chunk: Size, - pub rest: Uniform, -} - -impl From<Reg> for CastTarget { - fn from(unit: Reg) -> CastTarget { - CastTarget::from(Uniform::from(unit)) - } -} - -impl From<Uniform> for CastTarget { - fn from(uniform: Uniform) -> CastTarget { - CastTarget { - prefix: [None; 8], - prefix_chunk: Size::from_bytes(0), - rest: uniform - } - } -} - -impl CastTarget { - pub fn pair(a: Reg, b: Reg) -> CastTarget { - CastTarget { - prefix: [Some(a.kind), None, None, None, None, None, None, None], - prefix_chunk: a.size, - rest: Uniform::from(b) - } - } - - pub fn size(&self, cx: &CodegenCx) -> Size { - (self.prefix_chunk * self.prefix.iter().filter(|x| x.is_some()).count() as u64) - .abi_align(self.rest.align(cx)) + self.rest.total - } - - pub fn align(&self, cx: &CodegenCx) -> Align { - self.prefix.iter() - .filter_map(|x| x.map(|kind| Reg { kind: kind, size: self.prefix_chunk }.align(cx))) - .fold(cx.data_layout().aggregate_align.max(self.rest.align(cx)), - |acc, align| acc.max(align)) - } - - pub fn llvm_type(&self, cx: &CodegenCx) -> Type { +impl LlvmType for CastTarget { + fn llvm_type(&self, cx: &CodegenCx) -> Type { let rest_ll_unit = self.rest.unit.llvm_type(cx); let rest_count = self.rest.total.bytes() / self.rest.unit.size.bytes(); let rem_bytes = self.rest.total.bytes() % self.rest.unit.size.bytes(); @@ -460,97 +160,16 @@ impl CastTarget { } } -/// Information about how to pass an argument to, -/// or return a value from, a function, under some ABI. -#[derive(Debug)] -pub struct ArgType<'tcx> { - pub layout: TyLayout<'tcx>, - - /// Dummy argument, which is emitted before the real argument. - pub pad: Option<Reg>, - - pub mode: PassMode, +pub trait ArgTypeExt<'a, 'tcx> { + fn memory_ty(&self, cx: &CodegenCx<'a, 'tcx>) -> Type; + fn store(&self, bx: &Builder<'a, 'tcx>, val: ValueRef, dst: PlaceRef<'tcx>); + fn store_fn_arg(&self, bx: &Builder<'a, 'tcx>, idx: &mut usize, dst: PlaceRef<'tcx>); } -impl<'a, 'tcx> ArgType<'tcx> { - fn new(layout: TyLayout<'tcx>) -> ArgType<'tcx> { - ArgType { - layout, - pad: None, - mode: PassMode::Direct(ArgAttributes::new()), - } - } - - pub fn make_indirect(&mut self) { - assert_eq!(self.mode, PassMode::Direct(ArgAttributes::new())); - - // Start with fresh attributes for the pointer. - let mut attrs = ArgAttributes::new(); - - // For non-immediate arguments the callee gets its own copy of - // the value on the stack, so there are no aliases. It's also - // program-invisible so can't possibly capture - attrs.set(ArgAttribute::NoAlias) - .set(ArgAttribute::NoCapture) - .set(ArgAttribute::NonNull); - attrs.pointee_size = self.layout.size; - // FIXME(eddyb) We should be doing this, but at least on - // i686-pc-windows-msvc, it results in wrong stack offsets. - // attrs.pointee_align = Some(self.layout.align); - - self.mode = PassMode::Indirect(attrs); - } - - pub fn make_indirect_byval(&mut self) { - self.make_indirect(); - match self.mode { - PassMode::Indirect(ref mut attrs) => { - attrs.set(ArgAttribute::ByVal); - } - _ => bug!() - } - } - - pub fn extend_integer_width_to(&mut self, bits: u64) { - // Only integers have signedness - if let layout::Abi::Scalar(ref scalar) = self.layout.abi { - if let layout::Int(i, signed) = scalar.value { - if i.size().bits() < bits { - if let PassMode::Direct(ref mut attrs) = self.mode { - attrs.set(if signed { - ArgAttribute::SExt - } else { - ArgAttribute::ZExt - }); - } - } - } - } - } - - pub fn cast_to<T: Into<CastTarget>>(&mut self, target: T) { - assert_eq!(self.mode, PassMode::Direct(ArgAttributes::new())); - self.mode = PassMode::Cast(target.into()); - } - - pub fn pad_with(&mut self, reg: Reg) { - self.pad = Some(reg); - } - - pub fn is_indirect(&self) -> bool { - match self.mode { - PassMode::Indirect(_) => true, - _ => false - } - } - - pub fn is_ignore(&self) -> bool { - self.mode == PassMode::Ignore - } - +impl<'a, 'tcx> ArgTypeExt<'a, 'tcx> for ArgType<'tcx, Ty<'tcx>> { /// Get the LLVM type for a place of the original Rust type of /// this argument/return, i.e. the result of `type_of::type_of`. - pub fn memory_ty(&self, cx: &CodegenCx<'a, 'tcx>) -> Type { + fn memory_ty(&self, cx: &CodegenCx<'a, 'tcx>) -> Type { self.layout.llvm_type(cx) } @@ -558,7 +177,7 @@ impl<'a, 'tcx> ArgType<'tcx> { /// place for the original Rust type of this argument/return. /// Can be used for both storing formal arguments into Rust variables /// or results of call/invoke instructions into their destinations. - pub fn store(&self, bx: &Builder<'a, 'tcx>, val: ValueRef, dst: PlaceRef<'tcx>) { + fn store(&self, bx: &Builder<'a, 'tcx>, val: ValueRef, dst: PlaceRef<'tcx>) { if self.is_ignore() { return; } @@ -610,7 +229,7 @@ impl<'a, 'tcx> ArgType<'tcx> { } } - pub fn store_fn_arg(&self, bx: &Builder<'a, 'tcx>, idx: &mut usize, dst: PlaceRef<'tcx>) { + fn store_fn_arg(&self, bx: &Builder<'a, 'tcx>, idx: &mut usize, dst: PlaceRef<'tcx>) { let mut next = || { let val = llvm::get_param(bx.llfn(), *idx as c_uint); *idx += 1; @@ -628,26 +247,29 @@ impl<'a, 'tcx> ArgType<'tcx> { } } -/// Metadata describing how the arguments to a native function -/// should be passed in order to respect the native ABI. -/// -/// I will do my best to describe this structure, but these -/// comments are reverse-engineered and may be inaccurate. -NDM -#[derive(Debug)] -pub struct FnType<'tcx> { - /// The LLVM types of each argument. - pub args: Vec<ArgType<'tcx>>, - - /// LLVM return type. - pub ret: ArgType<'tcx>, - - pub variadic: bool, - - pub cconv: llvm::CallConv +pub trait FnTypeExt<'a, 'tcx> { + fn of_instance(cx: &CodegenCx<'a, 'tcx>, instance: &ty::Instance<'tcx>) + -> Self; + fn new(cx: &CodegenCx<'a, 'tcx>, + sig: ty::FnSig<'tcx>, + extra_args: &[Ty<'tcx>]) -> Self; + fn new_vtable(cx: &CodegenCx<'a, 'tcx>, + sig: ty::FnSig<'tcx>, + extra_args: &[Ty<'tcx>]) -> Self; + fn unadjusted(cx: &CodegenCx<'a, 'tcx>, + sig: ty::FnSig<'tcx>, + extra_args: &[Ty<'tcx>]) -> Self; + fn adjust_for_abi(&mut self, + cx: &CodegenCx<'a, 'tcx>, + abi: Abi); + fn llvm_type(&self, cx: &CodegenCx<'a, 'tcx>) -> Type; + fn llvm_cconv(&self) -> llvm::CallConv; + fn apply_attrs_llfn(&self, llfn: ValueRef); + fn apply_attrs_callsite(&self, bx: &Builder<'a, 'tcx>, callsite: ValueRef); } -impl<'a, 'tcx> FnType<'tcx> { - pub fn of_instance(cx: &CodegenCx<'a, 'tcx>, instance: &ty::Instance<'tcx>) +impl<'a, 'tcx> FnTypeExt<'a, 'tcx> for FnType<'tcx, Ty<'tcx>> { + fn of_instance(cx: &CodegenCx<'a, 'tcx>, instance: &ty::Instance<'tcx>) -> Self { let fn_ty = instance.ty(cx.tcx); let sig = ty_fn_sig(cx, fn_ty); @@ -655,17 +277,17 @@ impl<'a, 'tcx> FnType<'tcx> { FnType::new(cx, sig, &[]) } - pub fn new(cx: &CodegenCx<'a, 'tcx>, + fn new(cx: &CodegenCx<'a, 'tcx>, sig: ty::FnSig<'tcx>, - extra_args: &[Ty<'tcx>]) -> FnType<'tcx> { + extra_args: &[Ty<'tcx>]) -> Self { let mut fn_ty = FnType::unadjusted(cx, sig, extra_args); fn_ty.adjust_for_abi(cx, sig.abi); fn_ty } - pub fn new_vtable(cx: &CodegenCx<'a, 'tcx>, + fn new_vtable(cx: &CodegenCx<'a, 'tcx>, sig: ty::FnSig<'tcx>, - extra_args: &[Ty<'tcx>]) -> FnType<'tcx> { + extra_args: &[Ty<'tcx>]) -> Self { let mut fn_ty = FnType::unadjusted(cx, sig, extra_args); // Don't pass the vtable, it's not an argument of the virtual fn. { @@ -688,34 +310,34 @@ impl<'a, 'tcx> FnType<'tcx> { fn_ty } - pub fn unadjusted(cx: &CodegenCx<'a, 'tcx>, + fn unadjusted(cx: &CodegenCx<'a, 'tcx>, sig: ty::FnSig<'tcx>, - extra_args: &[Ty<'tcx>]) -> FnType<'tcx> { + extra_args: &[Ty<'tcx>]) -> Self { debug!("FnType::unadjusted({:?}, {:?})", sig, extra_args); use self::Abi::*; - let cconv = match cx.sess().target.target.adjust_abi(sig.abi) { + let conv = match cx.sess().target.target.adjust_abi(sig.abi) { RustIntrinsic | PlatformIntrinsic | - Rust | RustCall => llvm::CCallConv, + Rust | RustCall => Conv::C, // It's the ABI's job to select this, not us. System => bug!("system abi should be selected elsewhere"), - Stdcall => llvm::X86StdcallCallConv, - Fastcall => llvm::X86FastcallCallConv, - Vectorcall => llvm::X86_VectorCall, - Thiscall => llvm::X86_ThisCall, - C => llvm::CCallConv, - Unadjusted => llvm::CCallConv, - Win64 => llvm::X86_64_Win64, - SysV64 => llvm::X86_64_SysV, - Aapcs => llvm::ArmAapcsCallConv, - PtxKernel => llvm::PtxKernel, - Msp430Interrupt => llvm::Msp430Intr, - X86Interrupt => llvm::X86_Intr, + Stdcall => Conv::X86Stdcall, + Fastcall => Conv::X86Fastcall, + Vectorcall => Conv::X86VectorCall, + Thiscall => Conv::X86ThisCall, + C => Conv::C, + Unadjusted => Conv::C, + Win64 => Conv::X86_64Win64, + SysV64 => Conv::X86_64SysV, + Aapcs => Conv::ArmAapcs, + PtxKernel => Conv::PtxKernel, + Msp430Interrupt => Conv::Msp430Intr, + X86Interrupt => Conv::X86Intr, // These API constants ought to be more specific... - Cdecl => llvm::CCallConv, + Cdecl => Conv::C, }; let mut inputs = sig.inputs(); @@ -752,7 +374,7 @@ impl<'a, 'tcx> FnType<'tcx> { // Handle safe Rust thin and fat pointers. let adjust_for_rust_scalar = |attrs: &mut ArgAttributes, scalar: &layout::Scalar, - layout: TyLayout<'tcx>, + layout: TyLayout<'tcx, Ty<'tcx>>, offset: Size, is_return: bool| { // Booleans are always an i1 that needs to be zero-extended. @@ -858,7 +480,7 @@ impl<'a, 'tcx> FnType<'tcx> { arg_of(ty, false) }).collect(), variadic: sig.variadic, - cconv, + conv, } } @@ -869,7 +491,7 @@ impl<'a, 'tcx> FnType<'tcx> { if abi == Abi::Rust || abi == Abi::RustCall || abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic { - let fixup = |arg: &mut ArgType<'tcx>| { + let fixup = |arg: &mut ArgType<'tcx, Ty<'tcx>>| { if arg.is_ignore() { return; } match arg.layout.abi { @@ -925,52 +547,12 @@ impl<'a, 'tcx> FnType<'tcx> { return; } - match &cx.sess().target.target.arch[..] { - "x86" => { - let flavor = if abi == Abi::Fastcall { - cabi_x86::Flavor::Fastcall - } else { - cabi_x86::Flavor::General - }; - cabi_x86::compute_abi_info(cx, self, flavor); - }, - "x86_64" => if abi == Abi::SysV64 { - cabi_x86_64::compute_abi_info(cx, self); - } else if abi == Abi::Win64 || cx.sess().target.target.options.is_like_windows { - cabi_x86_win64::compute_abi_info(self); - } else { - cabi_x86_64::compute_abi_info(cx, self); - }, - "aarch64" => cabi_aarch64::compute_abi_info(cx, self), - "arm" => cabi_arm::compute_abi_info(cx, self), - "mips" => cabi_mips::compute_abi_info(cx, self), - "mips64" => cabi_mips64::compute_abi_info(cx, self), - "powerpc" => cabi_powerpc::compute_abi_info(cx, self), - "powerpc64" => cabi_powerpc64::compute_abi_info(cx, self), - "s390x" => cabi_s390x::compute_abi_info(cx, self), - "asmjs" => cabi_asmjs::compute_abi_info(cx, self), - "wasm32" => { - if cx.sess().opts.target_triple.triple().contains("emscripten") { - cabi_asmjs::compute_abi_info(cx, self) - } else { - cabi_wasm32::compute_abi_info(cx, self) - } - } - "msp430" => cabi_msp430::compute_abi_info(self), - "sparc" => cabi_sparc::compute_abi_info(cx, self), - "sparc64" => cabi_sparc64::compute_abi_info(cx, self), - "nvptx" => cabi_nvptx::compute_abi_info(self), - "nvptx64" => cabi_nvptx64::compute_abi_info(self), - "hexagon" => cabi_hexagon::compute_abi_info(self), - a => cx.sess().fatal(&format!("unrecognized arch \"{}\" in target specification", a)) - } - - if let PassMode::Indirect(ref mut attrs) = self.ret.mode { - attrs.set(ArgAttribute::StructRet); + if let Err(msg) = self.adjust_for_cabi(cx, abi) { + cx.sess().fatal(&msg); } } - pub fn llvm_type(&self, cx: &CodegenCx<'a, 'tcx>) -> Type { + fn llvm_type(&self, cx: &CodegenCx<'a, 'tcx>) -> Type { let mut llargument_tys = Vec::new(); let llreturn_ty = match self.ret.mode { @@ -1012,7 +594,23 @@ impl<'a, 'tcx> FnType<'tcx> { } } - pub fn apply_attrs_llfn(&self, llfn: ValueRef) { + fn llvm_cconv(&self) -> llvm::CallConv { + match self.conv { + Conv::C => llvm::CCallConv, + Conv::ArmAapcs => llvm::ArmAapcsCallConv, + Conv::Msp430Intr => llvm::Msp430Intr, + Conv::PtxKernel => llvm::PtxKernel, + Conv::X86Fastcall => llvm::X86FastcallCallConv, + Conv::X86Intr => llvm::X86_Intr, + Conv::X86Stdcall => llvm::X86StdcallCallConv, + Conv::X86ThisCall => llvm::X86_ThisCall, + Conv::X86VectorCall => llvm::X86_VectorCall, + Conv::X86_64SysV => llvm::X86_64_SysV, + Conv::X86_64Win64 => llvm::X86_64_Win64, + } + } + + fn apply_attrs_llfn(&self, llfn: ValueRef) { let mut i = 0; let mut apply = |attrs: &ArgAttributes| { attrs.apply_llfn(llvm::AttributePlace::Argument(i), llfn); @@ -1042,7 +640,7 @@ impl<'a, 'tcx> FnType<'tcx> { } } - pub fn apply_attrs_callsite(&self, callsite: ValueRef) { + fn apply_attrs_callsite(&self, bx: &Builder<'a, 'tcx>, callsite: ValueRef) { let mut i = 0; let mut apply = |attrs: &ArgAttributes| { attrs.apply_callsite(llvm::AttributePlace::Argument(i), callsite); @@ -1055,6 +653,24 @@ impl<'a, 'tcx> FnType<'tcx> { PassMode::Indirect(ref attrs) => apply(attrs), _ => {} } + if let layout::Abi::Scalar(ref scalar) = self.ret.layout.abi { + // If the value is a boolean, the range is 0..2 and that ultimately + // become 0..0 when the type becomes i1, which would be rejected + // by the LLVM verifier. + match scalar.value { + layout::Int(..) if !scalar.is_bool() => { + let range = scalar.valid_range_exclusive(bx.cx); + if range.start != range.end { + // FIXME(nox): This causes very weird type errors about + // SHL operators in constants in stage 2 with LLVM 3.9. + if unsafe { llvm::LLVMRustVersionMajor() >= 4 } { + bx.range_metadata(callsite, range); + } + } + } + _ => {} + } + } for arg in &self.args { if arg.pad.is_some() { apply(&ArgAttributes::new()); @@ -1071,8 +687,9 @@ impl<'a, 'tcx> FnType<'tcx> { } } - if self.cconv != llvm::CCallConv { - llvm::SetInstructionCallConv(callsite, self.cconv); + let cconv = self.llvm_cconv(); + if cconv != llvm::CCallConv { + llvm::SetInstructionCallConv(callsite, cconv); } } } diff --git a/src/librustc_trans/allocator.rs b/src/librustc_trans/allocator.rs index f2dd2ed8460..871fe98ec01 100644 --- a/src/librustc_trans/allocator.rs +++ b/src/librustc_trans/allocator.rs @@ -11,6 +11,7 @@ use std::ffi::CString; use std::ptr; +use attributes; use libc::c_uint; use rustc::middle::allocator::AllocatorKind; use rustc::ty::TyCtxt; @@ -43,13 +44,11 @@ pub(crate) unsafe fn trans(tcx: TyCtxt, mods: &ModuleLlvm, kind: AllocatorKind) AllocatorTy::Ptr => args.push(i8p), AllocatorTy::Usize => args.push(usize), - AllocatorTy::Bang | AllocatorTy::ResultPtr | AllocatorTy::Unit => panic!("invalid allocator arg"), } } let output = match method.output { - AllocatorTy::Bang => None, AllocatorTy::ResultPtr => Some(i8p), AllocatorTy::Unit => None, @@ -69,6 +68,9 @@ pub(crate) unsafe fn trans(tcx: TyCtxt, mods: &ModuleLlvm, kind: AllocatorKind) if tcx.sess.target.target.options.default_hidden_visibility { llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); } + if tcx.sess.target.target.options.requires_uwtable { + attributes::emit_uwtable(llfn, true); + } let callee = CString::new(kind.fn_name(method.name)).unwrap(); let callee = llvm::LLVMRustGetOrInsertFunction(llmod, diff --git a/src/librustc_trans/attributes.rs b/src/librustc_trans/attributes.rs index eb5c7396ae0..f455c19cc0b 100644 --- a/src/librustc_trans/attributes.rs +++ b/src/librustc_trans/attributes.rs @@ -14,6 +14,7 @@ use std::ffi::{CStr, CString}; use rustc::hir::{self, TransFnAttrFlags}; use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use rustc::hir::itemlikevisit::ItemLikeVisitor; +use rustc::session::Session; use rustc::session::config::Sanitizer; use rustc::ty::TyCtxt; use rustc::ty::maps::Providers; @@ -104,6 +105,18 @@ pub fn set_probestack(cx: &CodegenCx, llfn: ValueRef) { cstr("probe-stack\0"), cstr("__rust_probestack\0")); } +pub fn llvm_target_features(sess: &Session) -> impl Iterator<Item = &str> { + const RUSTC_SPECIFIC_FEATURES: &[&str] = &[ + "crt-static", + ]; + + let cmdline = sess.opts.cg.target_feature.split(',') + .filter(|f| !RUSTC_SPECIFIC_FEATURES.iter().any(|s| f.contains(s))); + sess.target.target.options.features.split(',') + .chain(cmdline) + .filter(|l| !l.is_empty()) +} + /// Composite function which sets LLVM attributes for function depending on its AST (#[attribute]) /// attributes. pub fn from_fn_attrs(cx: &CodegenCx, llfn: ValueRef, id: DefId) { @@ -131,13 +144,16 @@ pub fn from_fn_attrs(cx: &CodegenCx, llfn: ValueRef, id: DefId) { unwind(llfn, false); } - let features = - trans_fn_attrs.target_features - .iter() - .map(|f| { - let feature = &*f.as_str(); - format!("+{}", llvm_util::to_llvm_feature(cx.tcx.sess, feature)) - }) + let features = llvm_target_features(cx.tcx.sess) + .map(|s| s.to_string()) + .chain( + trans_fn_attrs.target_features + .iter() + .map(|f| { + let feature = &*f.as_str(); + format!("+{}", llvm_util::to_llvm_feature(cx.tcx.sess, feature)) + }) + ) .collect::<Vec<String>>() .join(","); diff --git a/src/librustc_trans/back/command.rs b/src/librustc_trans/back/command.rs index a5649e98baa..9ebbdd7c3c9 100644 --- a/src/librustc_trans/back/command.rs +++ b/src/librustc_trans/back/command.rs @@ -17,7 +17,7 @@ use std::io; use std::mem; use std::process::{self, Output}; -use rustc_back::LldFlavor; +use rustc_target::spec::LldFlavor; #[derive(Clone)] pub struct Command { diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 97683840172..92f9a9e8ba9 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -17,7 +17,6 @@ use super::command::Command; use super::rpath::RPathConfig; use super::rpath; use metadata::METADATA_FILENAME; -use rustc_back::LinkerFlavor; use rustc::session::config::{self, NoDebugInfo, OutputFilenames, OutputType, PrintRequest}; use rustc::session::config::{RUST_CGU_EXT, Lto}; use rustc::session::filesearch; @@ -30,8 +29,7 @@ use rustc::util::common::time; use rustc::util::fs::fix_windows_verbatim_for_gcc; use rustc::hir::def_id::CrateNum; use tempdir::TempDir; -use rustc_back::{PanicStrategy, RelroLevel}; -use rustc_back::target::TargetTriple; +use rustc_target::spec::{PanicStrategy, RelroLevel, LinkerFlavor, TargetTriple}; use rustc_data_structures::fx::FxHashSet; use context::get_reloc_model; use llvm; diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs index ebcf06d63be..ea3f5b40860 100644 --- a/src/librustc_trans/back/linker.rs +++ b/src/librustc_trans/back/linker.rs @@ -23,7 +23,7 @@ use rustc::middle::dependency_format::Linkage; use rustc::session::Session; use rustc::session::config::{self, CrateType, OptLevel, DebugInfoLevel}; use rustc::ty::TyCtxt; -use rustc_back::{LinkerFlavor, LldFlavor}; +use rustc_target::spec::{LinkerFlavor, LldFlavor}; use serialize::{json, Encoder}; /// For all the linkers we support, and information they might @@ -959,7 +959,12 @@ impl Linker for WasmLd { } fn finalize(&mut self) -> Command { - self.cmd.arg("--threads"); + // There have been reports in the wild (rustwasm/wasm-bindgen#119) of + // using threads causing weird hangs and bugs. Disable it entirely as + // this isn't yet the bottleneck of compilation at all anyway. + self.cmd.arg("--no-threads"); + + self.cmd.arg("-z").arg("stack-size=1048576"); // FIXME we probably shouldn't pass this but instead pass an explicit // whitelist of symbols we'll allow to be undefined. Unfortunately diff --git a/src/librustc_trans/back/symbol_export.rs b/src/librustc_trans/back/symbol_export.rs index 965a34eccb8..d8520b61d91 100644 --- a/src/librustc_trans/back/symbol_export.rs +++ b/src/librustc_trans/back/symbol_export.rs @@ -132,7 +132,7 @@ fn reachable_non_generics_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }) .map(|def_id| { let export_level = if special_runtime_crate { - let name = tcx.symbol_name(Instance::mono(tcx, def_id)); + let name = tcx.symbol_name(Instance::mono(tcx, def_id)).as_str(); // We can probably do better here by just ensuring that // it has hidden visibility rather than public // visibility, as this is primarily here to ensure it's diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index f501b1739eb..148e3d0025c 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use attributes; use back::bytecode::{self, RLIB_BYTECODE_EXTENSION}; use back::lto::{self, ModuleBuffer, ThinBuffer}; use back::link::{self, get_linker, remove}; @@ -111,31 +112,6 @@ pub fn write_output_file( } } -// On android, we by default compile for armv7 processors. This enables -// things like double word CAS instructions (rather than emulating them) -// which are *far* more efficient. This is obviously undesirable in some -// cases, so if any sort of target feature is specified we don't append v7 -// to the feature list. -// -// On iOS only armv7 and newer are supported. So it is useful to -// get all hardware potential via VFP3 (hardware floating point) -// and NEON (SIMD) instructions supported by LLVM. -// Note that without those flags various linking errors might -// arise as some of intrinsics are converted into function calls -// and nobody provides implementations those functions -fn target_feature(sess: &Session) -> String { - let rustc_features = [ - "crt-static", - ]; - let requested_features = sess.opts.cg.target_feature.split(','); - let llvm_features = requested_features.filter(|f| { - !rustc_features.iter().any(|s| f.contains(s)) - }); - format!("{},{}", - sess.target.target.options.features, - llvm_features.collect::<Vec<_>>().join(",")) -} - fn get_llvm_opt_level(optimize: config::OptLevel) -> llvm::CodeGenOptLevel { match optimize { config::OptLevel::No => llvm::CodeGenOptLevel::None, @@ -203,7 +179,10 @@ pub fn target_machine_factory(sess: &Session, find_features: bool) None => &*sess.target.target.options.cpu }; let cpu = CString::new(cpu.as_bytes()).unwrap(); - let features = CString::new(target_feature(sess).as_bytes()).unwrap(); + let features = attributes::llvm_target_features(sess) + .collect::<Vec<_>>() + .join(","); + let features = CString::new(features).unwrap(); let is_pie_binary = !find_features && is_pie_binary(sess); let trap_unreachable = sess.target.target.options.trap_unreachable; @@ -1007,13 +986,6 @@ pub fn start_async_translation(tcx: TyCtxt, metadata_config.time_passes = false; allocator_config.time_passes = false; - let client = sess.jobserver_from_env.clone().unwrap_or_else(|| { - // Pick a "reasonable maximum" if we don't otherwise have a jobserver in - // our environment, capping out at 32 so we don't take everything down - // by hogging the process run queue. - Client::new(32).expect("failed to create jobserver") - }); - let (shared_emitter, shared_emitter_main) = SharedEmitter::new(); let (trans_worker_send, trans_worker_receive) = channel(); @@ -1023,7 +995,7 @@ pub fn start_async_translation(tcx: TyCtxt, trans_worker_send, coordinator_receive, total_cgus, - client, + sess.jobserver.clone(), time_graph.clone(), Arc::new(modules_config), Arc::new(metadata_config), diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 1da6f25fd63..b756a6695f9 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -74,7 +74,7 @@ use type_of::LayoutLlvmExt; use rustc::util::nodemap::{FxHashMap, FxHashSet, DefIdSet}; use CrateInfo; use rustc_data_structures::sync::Lrc; -use rustc_back::target::TargetTriple; +use rustc_target::spec::TargetTriple; use std::any::Any; use std::collections::BTreeMap; @@ -492,7 +492,7 @@ pub fn trans_instance<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, instance: Instance<'tc // You can also find more info on why Windows is whitelisted here in: // https://bugzilla.mozilla.org/show_bug.cgi?id=1302078 if !cx.sess().no_landing_pads() || - cx.sess().target.target.options.is_like_windows { + cx.sess().target.target.options.requires_uwtable { attributes::emit_uwtable(lldecl, true); } @@ -1037,7 +1037,7 @@ fn collect_and_partition_translation_items<'a, 'tcx>( cgus.dedup(); for &(ref cgu_name, (linkage, _)) in cgus.iter() { output.push_str(" "); - output.push_str(&cgu_name); + output.push_str(&cgu_name.as_str()); let linkage_abbrev = match linkage { Linkage::External => "External", diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index 2c503bdab30..9263d9a5f5d 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -26,7 +26,7 @@ use rustc::hir::def_id::DefId; use rustc::ty::{self, TypeFoldable}; use rustc::ty::layout::LayoutOf; use rustc::ty::subst::Substs; -use rustc_back::PanicStrategy; +use rustc_target::spec::PanicStrategy; /// Translates a reference to a fn/method item, monomorphizing and /// inlining as it goes. @@ -52,7 +52,7 @@ pub fn get_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, return llfn; } - let sym = tcx.symbol_name(instance); + let sym = tcx.symbol_name(instance).as_str(); debug!("get_fn({:?}: {:?}) => {}", instance, fn_ty, sym); // Create a fn pointer with the substituted signature. diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index e83e73c8ae7..4a0619b2336 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -32,8 +32,8 @@ use rustc::hir; use libc::{c_uint, c_char}; use std::iter; -use syntax::abi::Abi; -use syntax::symbol::InternedString; +use rustc_target::spec::abi::Abi; +use syntax::symbol::LocalInternedString; use syntax_pos::{Span, DUMMY_SP}; pub use context::CodegenCx; @@ -183,7 +183,7 @@ pub fn C_u8(cx: &CodegenCx, i: u8) -> ValueRef { // This is a 'c-like' raw string, which differs from // our boxed-and-length-annotated strings. -pub fn C_cstr(cx: &CodegenCx, s: InternedString, null_terminated: bool) -> ValueRef { +pub fn C_cstr(cx: &CodegenCx, s: LocalInternedString, null_terminated: bool) -> ValueRef { unsafe { if let Some(&llval) = cx.const_cstr_cache.borrow().get(&s) { return llval; @@ -208,7 +208,7 @@ pub fn C_cstr(cx: &CodegenCx, s: InternedString, null_terminated: bool) -> Value // NB: Do not use `do_spill_noroot` to make this into a constant string, or // you will be kicked off fast isel. See issue #4352 for an example of this. -pub fn C_str_slice(cx: &CodegenCx, s: InternedString) -> ValueRef { +pub fn C_str_slice(cx: &CodegenCx, s: LocalInternedString) -> ValueRef { let len = s.len(); let cs = consts::ptrcast(C_cstr(cx, s, false), cx.layout_of(cx.tcx.mk_str()).llvm_type(cx).ptr_to()); diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index 122b51dbbb7..405cb83ad4d 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -118,7 +118,7 @@ pub fn get_static(cx: &CodegenCx, def_id: DefId) -> ValueRef { def_id); let ty = instance.ty(cx.tcx); - let sym = cx.tcx.symbol_name(instance); + let sym = cx.tcx.symbol_name(instance).as_str(); let g = if let Some(id) = cx.tcx.hir.as_local_node_id(def_id) { diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index fe8a7052bdf..90b2fb4b59a 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -31,6 +31,7 @@ use rustc::session::Session; use rustc::ty::layout::{LayoutError, LayoutOf, Size, TyLayout}; use rustc::ty::{self, Ty, TyCtxt}; use rustc::util::nodemap::FxHashMap; +use rustc_target::spec::{HasTargetSpec, Target}; use std::ffi::{CStr, CString}; use std::cell::{Cell, RefCell}; @@ -38,7 +39,7 @@ use std::ptr; use std::iter; use std::str; use std::sync::Arc; -use syntax::symbol::InternedString; +use syntax::symbol::LocalInternedString; use abi::Abi; /// There is one `CodegenCx` per compilation unit. Each one has its own LLVM @@ -61,7 +62,7 @@ pub struct CodegenCx<'a, 'tcx: 'a> { pub vtables: RefCell<FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), ValueRef>>, /// Cache of constant strings, - pub const_cstr_cache: RefCell<FxHashMap<InternedString, ValueRef>>, + pub const_cstr_cache: RefCell<FxHashMap<LocalInternedString, ValueRef>>, /// Reverse-direction for const ptrs cast from globals. /// Key is a ValueRef holding a *T, @@ -272,7 +273,7 @@ impl<'a, 'tcx> CodegenCx<'a, 'tcx> { let dbg_cx = if tcx.sess.opts.debuginfo != NoDebugInfo { let dctx = debuginfo::CrateDebugContext::new(llmod); debuginfo::metadata::compile_unit_metadata(tcx, - codegen_unit.name(), + &codegen_unit.name().as_str(), &dctx); Some(dctx) } else { @@ -406,7 +407,7 @@ impl<'b, 'tcx> CodegenCx<'b, 'tcx> { return llfn; } - let ty = tcx.mk_fn_ptr(ty::Binder(tcx.mk_fn_sig( + let ty = tcx.mk_fn_ptr(ty::Binder::bind(tcx.mk_fn_sig( iter::once(tcx.mk_mut_ptr(tcx.types.u8)), tcx.types.never, false, @@ -453,13 +454,20 @@ impl<'a, 'tcx> ty::layout::HasDataLayout for &'a CodegenCx<'a, 'tcx> { } } +impl<'a, 'tcx> HasTargetSpec for &'a CodegenCx<'a, 'tcx> { + fn target_spec(&self) -> &Target { + &self.tcx.sess.target.target + } +} + impl<'a, 'tcx> ty::layout::HasTyCtxt<'tcx> for &'a CodegenCx<'a, 'tcx> { fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> { self.tcx } } -impl<'a, 'tcx> LayoutOf<Ty<'tcx>> for &'a CodegenCx<'a, 'tcx> { +impl<'a, 'tcx> LayoutOf for &'a CodegenCx<'a, 'tcx> { + type Ty = Ty<'tcx>; type TyLayout = TyLayout<'tcx>; fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout { diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index eb550d7a605..123b9cf7931 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -32,7 +32,7 @@ use rustc::ich::Fingerprint; use rustc::ty::Instance; use common::CodegenCx; use rustc::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt}; -use rustc::ty::layout::{self, Align, LayoutOf, Size, TyLayout}; +use rustc::ty::layout::{self, Align, LayoutOf, PrimitiveExt, Size, TyLayout}; use rustc::session::config; use rustc::util::nodemap::FxHashMap; use rustc::util::common::path2cstr; @@ -1399,7 +1399,7 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, (discr.size(cx), discr.align(cx)); let discriminant_base_type_metadata = type_metadata(cx, discr.to_ty(cx.tcx), syntax_pos::DUMMY_SP); - let discriminant_name = get_enum_discriminant_name(cx, enum_def_id); + let discriminant_name = get_enum_discriminant_name(cx, enum_def_id).as_str(); let name = CString::new(discriminant_name.as_bytes()).unwrap(); let discriminant_type_metadata = unsafe { diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index 706dc3dca8a..193db15303f 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -394,7 +394,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, substs.types().zip(names).map(|(ty, name)| { let actual_type = cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty); let actual_type_metadata = type_metadata(cx, actual_type, syntax_pos::DUMMY_SP); - let name = CString::new(name.as_bytes()).unwrap(); + let name = CString::new(name.as_str().as_bytes()).unwrap(); unsafe { llvm::LLVMRustDIBuilderCreateTemplateTypeParameter( DIB(cx), diff --git a/src/librustc_trans/debuginfo/namespace.rs b/src/librustc_trans/debuginfo/namespace.rs index 891bf649c38..51c45de9dc2 100644 --- a/src/librustc_trans/debuginfo/namespace.rs +++ b/src/librustc_trans/debuginfo/namespace.rs @@ -47,7 +47,7 @@ pub fn item_namespace(cx: &CodegenCx, def_id: DefId) -> DIScope { let namespace_name = match def_key.disambiguated_data.data { DefPathData::CrateRoot => cx.tcx.crate_name(def_id.krate).as_str(), - data => data.as_interned_str() + data => data.as_interned_str().as_str() }; let namespace_name = CString::new(namespace_name.as_bytes()).unwrap(); diff --git a/src/librustc_trans/debuginfo/type_names.rs b/src/librustc_trans/debuginfo/type_names.rs index 96ed4e88471..825fac36c93 100644 --- a/src/librustc_trans/debuginfo/type_names.rs +++ b/src/librustc_trans/debuginfo/type_names.rs @@ -190,10 +190,10 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, output.push_str(&cx.tcx.crate_name(def_id.krate).as_str()); for path_element in cx.tcx.def_path(def_id).data { output.push_str("::"); - output.push_str(&path_element.data.as_interned_str()); + output.push_str(&path_element.data.as_interned_str().as_str()); } } else { - output.push_str(&cx.tcx.item_name(def_id)); + output.push_str(&cx.tcx.item_name(def_id).as_str()); } } diff --git a/src/librustc_trans/declare.rs b/src/librustc_trans/declare.rs index c2010feb1b6..bbe4e18b18c 100644 --- a/src/librustc_trans/declare.rs +++ b/src/librustc_trans/declare.rs @@ -24,8 +24,8 @@ use llvm::{self, ValueRef}; use llvm::AttributePlace::Function; use rustc::ty::{self, Ty}; use rustc::session::config::Sanitizer; -use rustc_back::PanicStrategy; -use abi::{Abi, FnType}; +use rustc_target::spec::PanicStrategy; +use abi::{Abi, FnType, FnTypeExt}; use attributes; use context::CodegenCx; use common; @@ -131,7 +131,7 @@ pub fn declare_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, name: &str, debug!("declare_rust_fn (after region erasure) sig={:?}", sig); let fty = FnType::new(cx, sig, &[]); - let llfn = declare_raw_fn(cx, name, fty.cconv, fty.llvm_type(cx)); + let llfn = declare_raw_fn(cx, name, fty.llvm_cconv(), fty.llvm_type(cx)); // FIXME(canndrew): This is_never should really be an is_uninhabited if sig.output().is_never() { diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index 5c67f809114..49a207a2d8a 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -13,7 +13,7 @@ use intrinsics::{self, Intrinsic}; use llvm; use llvm::{ValueRef}; -use abi::{Abi, FnType, PassMode}; +use abi::{Abi, FnType, LlvmType, PassMode}; use mir::place::PlaceRef; use mir::operand::{OperandRef, OperandValue}; use base::*; @@ -87,7 +87,7 @@ fn get_simple_intrinsic(cx: &CodegenCx, name: &str) -> Option<ValueRef> { /// add them to librustc_trans/trans/context.rs pub fn trans_intrinsic_call<'a, 'tcx>(bx: &Builder<'a, 'tcx>, callee_ty: Ty<'tcx>, - fn_ty: &FnType<'tcx>, + fn_ty: &FnType<'tcx, Ty<'tcx>>, args: &[OperandRef<'tcx>], llresult: ValueRef, span: Span) { @@ -103,7 +103,7 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bx: &Builder<'a, 'tcx>, let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); let arg_tys = sig.inputs(); let ret_ty = sig.output(); - let name = &*tcx.item_name(def_id); + let name = &*tcx.item_name(def_id).as_str(); let llret_ty = cx.layout_of(ret_ty).llvm_type(cx); let result = PlaceRef::new_sized(llresult, fn_ty.ret.layout, fn_ty.ret.layout.align); @@ -958,7 +958,7 @@ fn gen_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, output: Ty<'tcx>, trans: &mut for<'b> FnMut(Builder<'b, 'tcx>)) -> ValueRef { - let rust_fn_ty = cx.tcx.mk_fn_ptr(ty::Binder(cx.tcx.mk_fn_sig( + let rust_fn_ty = cx.tcx.mk_fn_ptr(ty::Binder::bind(cx.tcx.mk_fn_sig( inputs.into_iter(), output, false, @@ -985,7 +985,7 @@ fn get_rust_try_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, // Define the type up front for the signature of the rust_try function. let tcx = cx.tcx; let i8p = tcx.mk_mut_ptr(tcx.types.i8); - let fn_ty = tcx.mk_fn_ptr(ty::Binder(tcx.mk_fn_sig( + let fn_ty = tcx.mk_fn_ptr(ty::Binder::bind(tcx.mk_fn_sig( iter::once(i8p), tcx.mk_nil(), false, diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 49d0f638f20..96a10e8b99d 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -25,6 +25,7 @@ #![allow(unused_attributes)] #![feature(libc)] #![feature(quote)] +#![feature(range_contains)] #![feature(rustc_diagnostic_macros)] #![feature(slice_sort_by_cached_key)] #![feature(optin_builtin_traits)] @@ -33,8 +34,6 @@ use rustc::dep_graph::WorkProduct; use syntax_pos::symbol::Symbol; -#[macro_use] -extern crate bitflags; extern crate flate2; extern crate libc; #[macro_use] extern crate rustc; @@ -43,7 +42,7 @@ extern crate num_cpus; extern crate rustc_mir; extern crate rustc_allocator; extern crate rustc_apfloat; -extern crate rustc_back; +extern crate rustc_target; extern crate rustc_const_math; #[macro_use] extern crate rustc_data_structures; extern crate rustc_demangle; @@ -104,24 +103,6 @@ mod asm; mod attributes; mod base; mod builder; -mod cabi_aarch64; -mod cabi_arm; -mod cabi_asmjs; -mod cabi_hexagon; -mod cabi_mips; -mod cabi_mips64; -mod cabi_msp430; -mod cabi_nvptx; -mod cabi_nvptx64; -mod cabi_powerpc; -mod cabi_powerpc64; -mod cabi_s390x; -mod cabi_sparc; -mod cabi_sparc64; -mod cabi_x86; -mod cabi_x86_64; -mod cabi_x86_win64; -mod cabi_wasm32; mod callee; mod common; mod consts; diff --git a/src/librustc_trans/metadata.rs b/src/librustc_trans/metadata.rs index 9483420f2f0..144baa65c1b 100644 --- a/src/librustc_trans/metadata.rs +++ b/src/librustc_trans/metadata.rs @@ -10,7 +10,7 @@ use rustc::util::common; use rustc::middle::cstore::MetadataLoader; -use rustc_back::target::Target; +use rustc_target::spec::Target; use llvm; use llvm::{False, ObjectFile, mk_section_iter}; use llvm::archive_ro::ArchiveRO; diff --git a/src/librustc_trans/meth.rs b/src/librustc_trans/meth.rs index 6b542ae2e93..21bbdf31dcb 100644 --- a/src/librustc_trans/meth.rs +++ b/src/librustc_trans/meth.rs @@ -9,7 +9,7 @@ // except according to those terms. use llvm::ValueRef; -use abi::FnType; +use abi::{FnType, FnTypeExt}; use callee; use common::*; use builder::Builder; @@ -35,7 +35,7 @@ impl<'a, 'tcx> VirtualIndex { pub fn get_fn(self, bx: &Builder<'a, 'tcx>, llvtable: ValueRef, - fn_ty: &FnType<'tcx>) -> ValueRef { + fn_ty: &FnType<'tcx, Ty<'tcx>>) -> ValueRef { // Load the data pointer from the object. debug!("get_fn({:?}, {:?})", Value(llvtable), self); diff --git a/src/librustc_trans/mir/analyze.rs b/src/librustc_trans/mir/analyze.rs index dd34dc03458..0fe7163da7a 100644 --- a/src/librustc_trans/mir/analyze.rs +++ b/src/librustc_trans/mir/analyze.rs @@ -12,6 +12,7 @@ //! which do not. use rustc_data_structures::bitvec::BitVector; +use rustc_data_structures::control_flow_graph::dominators::Dominators; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use rustc::mir::{self, Location, TerminatorKind}; use rustc::mir::visit::{Visitor, PlaceContext}; @@ -21,7 +22,7 @@ use rustc::ty::layout::LayoutOf; use type_of::LayoutLlvmExt; use super::FunctionCx; -pub fn memory_locals<'a, 'tcx>(fx: &FunctionCx<'a, 'tcx>) -> BitVector { +pub fn non_ssa_locals<'a, 'tcx>(fx: &FunctionCx<'a, 'tcx>) -> BitVector { let mir = fx.mir; let mut analyzer = LocalAnalyzer::new(fx); @@ -43,43 +44,60 @@ pub fn memory_locals<'a, 'tcx>(fx: &FunctionCx<'a, 'tcx>) -> BitVector { // (e.g. structs) into an alloca unconditionally, just so // that we don't have to deal with having two pathways // (gep vs extractvalue etc). - analyzer.mark_as_memory(mir::Local::new(index)); + analyzer.not_ssa(mir::Local::new(index)); } } - analyzer.memory_locals + analyzer.non_ssa_locals } struct LocalAnalyzer<'mir, 'a: 'mir, 'tcx: 'a> { fx: &'mir FunctionCx<'a, 'tcx>, - memory_locals: BitVector, - seen_assigned: BitVector + dominators: Dominators<mir::BasicBlock>, + non_ssa_locals: BitVector, + // The location of the first visited direct assignment to each + // local, or an invalid location (out of bounds `block` index). + first_assignment: IndexVec<mir::Local, Location> } impl<'mir, 'a, 'tcx> LocalAnalyzer<'mir, 'a, 'tcx> { fn new(fx: &'mir FunctionCx<'a, 'tcx>) -> LocalAnalyzer<'mir, 'a, 'tcx> { + let invalid_location = + mir::BasicBlock::new(fx.mir.basic_blocks().len()).start_location(); let mut analyzer = LocalAnalyzer { fx, - memory_locals: BitVector::new(fx.mir.local_decls.len()), - seen_assigned: BitVector::new(fx.mir.local_decls.len()) + dominators: fx.mir.dominators(), + non_ssa_locals: BitVector::new(fx.mir.local_decls.len()), + first_assignment: IndexVec::from_elem(invalid_location, &fx.mir.local_decls) }; // Arguments get assigned to by means of the function being called - for idx in 0..fx.mir.arg_count { - analyzer.seen_assigned.insert(idx + 1); + for arg in fx.mir.args_iter() { + analyzer.first_assignment[arg] = mir::START_BLOCK.start_location(); } analyzer } - fn mark_as_memory(&mut self, local: mir::Local) { - debug!("marking {:?} as memory", local); - self.memory_locals.insert(local.index()); + fn first_assignment(&self, local: mir::Local) -> Option<Location> { + let location = self.first_assignment[local]; + if location.block.index() < self.fx.mir.basic_blocks().len() { + Some(location) + } else { + None + } } - fn mark_assigned(&mut self, local: mir::Local) { - if !self.seen_assigned.insert(local.index()) { - self.mark_as_memory(local); + fn not_ssa(&mut self, local: mir::Local) { + debug!("marking {:?} as non-SSA", local); + self.non_ssa_locals.insert(local.index()); + } + + fn assign(&mut self, local: mir::Local, location: Location) { + if self.first_assignment(local).is_some() { + self.not_ssa(local); + } else { + self.first_assignment[local] = location; } } } @@ -93,9 +111,9 @@ impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> { debug!("visit_assign(block={:?}, place={:?}, rvalue={:?})", block, place, rvalue); if let mir::Place::Local(index) = *place { - self.mark_assigned(index); + self.assign(index, location); if !self.fx.rvalue_creates_operand(rvalue) { - self.mark_as_memory(index); + self.not_ssa(index); } } else { self.visit_place(place, PlaceContext::Store, location); @@ -161,7 +179,7 @@ impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> { if layout.is_llvm_immediate() || layout.is_llvm_scalar_pair() { // Recurse with the same context, instead of `Projection`, // potentially stopping at non-operand projections, - // which would trigger `mark_as_memory` on locals. + // which would trigger `not_ssa` on locals. self.visit_place(&proj.base, context, location); return; } @@ -178,35 +196,50 @@ impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> { } fn visit_local(&mut self, - &index: &mir::Local, + &local: &mir::Local, context: PlaceContext<'tcx>, - _: Location) { + location: Location) { match context { PlaceContext::Call => { - self.mark_assigned(index); + self.assign(local, location); } PlaceContext::StorageLive | PlaceContext::StorageDead | - PlaceContext::Validate | + PlaceContext::Validate => {} + PlaceContext::Copy | - PlaceContext::Move => {} + PlaceContext::Move => { + // Reads from uninitialized variables (e.g. in dead code, after + // optimizations) require locals to be in (uninitialized) memory. + // NB: there can be uninitialized reads of a local visited after + // an assignment to that local, if they happen on disjoint paths. + let ssa_read = match self.first_assignment(local) { + Some(assignment_location) => { + assignment_location.dominates(location, &self.dominators) + } + None => false + }; + if !ssa_read { + self.not_ssa(local); + } + } PlaceContext::Inspect | PlaceContext::Store | PlaceContext::AsmOutput | PlaceContext::Borrow { .. } | PlaceContext::Projection(..) => { - self.mark_as_memory(index); + self.not_ssa(local); } PlaceContext::Drop => { - let ty = mir::Place::Local(index).ty(self.fx.mir, self.fx.cx.tcx); + let ty = mir::Place::Local(local).ty(self.fx.mir, self.fx.cx.tcx); let ty = self.fx.monomorphize(&ty.to_ty(self.fx.cx.tcx)); // Only need the place if we're actually dropping it. if self.fx.cx.type_needs_drop(ty) { - self.mark_as_memory(index); + self.not_ssa(local); } } } diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index 93bc89f0914..e5fdc26eeaf 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -10,10 +10,10 @@ use llvm::{self, ValueRef, BasicBlockRef}; use rustc::middle::lang_items; -use rustc::ty::{self, TypeFoldable}; +use rustc::ty::{self, Ty, TypeFoldable}; use rustc::ty::layout::{self, LayoutOf}; use rustc::mir; -use abi::{Abi, FnType, ArgType, PassMode}; +use abi::{Abi, ArgType, ArgTypeExt, FnType, FnTypeExt, LlvmType, PassMode}; use base; use callee; use builder::Builder; @@ -110,7 +110,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { let do_call = | this: &mut Self, bx: Builder<'a, 'tcx>, - fn_ty: FnType<'tcx>, + fn_ty: FnType<'tcx, Ty<'tcx>>, fn_ptr: ValueRef, llargs: &[ValueRef], destination: Option<(ReturnDest<'tcx>, mir::BasicBlock)>, @@ -127,7 +127,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { ret_bx, llblock(this, cleanup), cleanup_bundle); - fn_ty.apply_attrs_callsite(invokeret); + fn_ty.apply_attrs_callsite(&bx, invokeret); if let Some((ret_dest, target)) = destination { let ret_bx = this.build_block(target); @@ -136,7 +136,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { } } else { let llret = bx.call(fn_ptr, &llargs, cleanup_bundle); - fn_ty.apply_attrs_callsite(llret); + fn_ty.apply_attrs_callsite(&bx, llret); if this.mir[bb].is_cleanup { // Cleanup is always the cold path. Don't inline // drop glue. Also, when there is a deeply-nested @@ -442,7 +442,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { // Handle intrinsics old trans wants Expr's for, ourselves. let intrinsic = match def { Some(ty::InstanceDef::Intrinsic(def_id)) - => Some(bx.tcx().item_name(def_id)), + => Some(bx.tcx().item_name(def_id).as_str()), _ => None }; let intrinsic = intrinsic.as_ref().map(|s| &s[..]); @@ -604,7 +604,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { bx: &Builder<'a, 'tcx>, op: OperandRef<'tcx>, llargs: &mut Vec<ValueRef>, - arg: &ArgType<'tcx>) { + arg: &ArgType<'tcx, Ty<'tcx>>) { // Fill padding with undef value, where applicable. if let Some(ty) = arg.pad { llargs.push(C_undef(ty.llvm_type(bx.cx))); @@ -683,7 +683,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { bx: &Builder<'a, 'tcx>, operand: &mir::Operand<'tcx>, llargs: &mut Vec<ValueRef>, - args: &[ArgType<'tcx>]) { + args: &[ArgType<'tcx, Ty<'tcx>>]) { let tuple = self.trans_operand(bx, operand); // Handle both by-ref and immediate tuples. @@ -776,7 +776,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { } fn make_return_dest(&mut self, bx: &Builder<'a, 'tcx>, - dest: &mir::Place<'tcx>, fn_ret: &ArgType<'tcx>, + dest: &mir::Place<'tcx>, fn_ret: &ArgType<'tcx, Ty<'tcx>>, llargs: &mut Vec<ValueRef>, is_intrinsic: bool) -> ReturnDest<'tcx> { // If the return is ignored, we can just return a do-nothing ReturnDest @@ -873,7 +873,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { fn store_return(&mut self, bx: &Builder<'a, 'tcx>, dest: ReturnDest<'tcx>, - ret_ty: &ArgType<'tcx>, + ret_ty: &ArgType<'tcx, Ty<'tcx>>, llval: ValueRef) { use self::ReturnDest::*; diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index 11dabbeae74..a074f25dfc9 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -12,7 +12,7 @@ use common::{C_i32, C_null}; use libc::c_uint; use llvm::{self, ValueRef, BasicBlockRef}; use llvm::debuginfo::DIScope; -use rustc::ty::{self, TypeFoldable}; +use rustc::ty::{self, Ty, TypeFoldable}; use rustc::ty::layout::{LayoutOf, TyLayout}; use rustc::mir::{self, Mir}; use rustc::ty::subst::Substs; @@ -22,7 +22,7 @@ use builder::Builder; use common::{CodegenCx, Funclet}; use debuginfo::{self, declare_local, VariableAccess, VariableKind, FunctionDebugContext}; use monomorphize::Instance; -use abi::{ArgAttribute, FnType, PassMode}; +use abi::{ArgAttribute, ArgTypeExt, FnType, FnTypeExt, PassMode}; use type_::Type; use syntax_pos::{DUMMY_SP, NO_EXPANSION, BytePos, Span}; @@ -53,7 +53,7 @@ pub struct FunctionCx<'a, 'tcx:'a> { cx: &'a CodegenCx<'a, 'tcx>, - fn_ty: FnType<'tcx>, + fn_ty: FnType<'tcx, Ty<'tcx>>, /// When unwinding is initiated, we have to store this personality /// value somewhere so that we can load it and re-use it in the @@ -252,7 +252,7 @@ pub fn trans_mir<'a, 'tcx: 'a>( }, }; - let memory_locals = analyze::memory_locals(&fx); + let memory_locals = analyze::non_ssa_locals(&fx); // Allocate variable and temp allocas fx.locals = { diff --git a/src/librustc_trans/mir/operand.rs b/src/librustc_trans/mir/operand.rs index 75df349de41..656ab95a28c 100644 --- a/src/librustc_trans/mir/operand.rs +++ b/src/librustc_trans/mir/operand.rs @@ -399,7 +399,14 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { self.mir_constant_to_miri_value(bx, constant) .and_then(|c| OperandRef::from_const(bx, c, ty)) .unwrap_or_else(|err| { - err.report(bx.tcx(), constant.span, "const operand"); + match constant.literal { + mir::Literal::Promoted { .. } => { + // don't report errors inside promoteds, just warnings. + }, + mir::Literal::Value { .. } => { + err.report(bx.tcx(), constant.span, "const operand") + }, + } // We've errored, so we don't have to produce working code. let layout = bx.cx.layout_of(ty); PlaceRef::new_sized( diff --git a/src/librustc_trans/mir/place.rs b/src/librustc_trans/mir/place.rs index b340d91b027..8532c0b149d 100644 --- a/src/librustc_trans/mir/place.rs +++ b/src/librustc_trans/mir/place.rs @@ -16,7 +16,7 @@ use rustc::mir::tcx::PlaceTy; use rustc_data_structures::indexed_vec::Idx; use base; use builder::Builder; -use common::{CodegenCx, C_usize, C_u8, C_u32, C_uint, C_int, C_null, C_uint_big}; +use common::{CodegenCx, C_undef, C_usize, C_u8, C_u32, C_uint, C_null, C_uint_big}; use consts; use type_of::LayoutLlvmExt; use type_::Type; @@ -91,24 +91,15 @@ impl<'a, 'tcx> PlaceRef<'tcx> { } let scalar_load_metadata = |load, scalar: &layout::Scalar| { - let (min, max) = (scalar.valid_range.start, scalar.valid_range.end); - let max_next = max.wrapping_add(1); - let bits = scalar.value.size(bx.cx).bits(); - assert!(bits <= 128); - let mask = !0u128 >> (128 - bits); - // For a (max) value of -1, max will be `-1 as usize`, which overflows. - // However, that is fine here (it would still represent the full range), - // i.e., if the range is everything. The lo==hi case would be - // rejected by the LLVM verifier (it would mean either an - // empty set, which is impossible, or the entire range of the - // type, which is pointless). + let vr = scalar.valid_range.clone(); match scalar.value { - layout::Int(..) if max_next & mask != min & mask => { - // llvm::ConstantRange can deal with ranges that wrap around, - // so an overflow on (max + 1) is fine. - bx.range_metadata(load, min..max_next); + layout::Int(..) => { + let range = scalar.valid_range_exclusive(bx.cx); + if range.start != range.end { + bx.range_metadata(load, range); + } } - layout::Pointer if 0 < min && min < max => { + layout::Pointer if vr.start < vr.end && !vr.contains(&0) => { bx.nonnull_metadata(load); } _ => {} @@ -264,9 +255,15 @@ impl<'a, 'tcx> PlaceRef<'tcx> { /// Obtain the actual discriminant of a value. pub fn trans_get_discr(self, bx: &Builder<'a, 'tcx>, cast_to: Ty<'tcx>) -> ValueRef { let cast_to = bx.cx.layout_of(cast_to).immediate_llvm_type(bx.cx); + if self.layout.abi == layout::Abi::Uninhabited { + return C_undef(cast_to); + } match self.layout.variants { layout::Variants::Single { index } => { - return C_uint(cast_to, index as u64); + let discr_val = self.layout.ty.ty_adt_def().map_or( + index as u128, + |def| def.discriminant_for_variant(bx.cx.tcx, index).val); + return C_uint_big(cast_to, discr_val); } layout::Variants::Tagged { .. } | layout::Variants::NicheFilling { .. } => {}, @@ -328,9 +325,11 @@ impl<'a, 'tcx> PlaceRef<'tcx> { let ptr = self.project_field(bx, 0); let to = self.layout.ty.ty_adt_def().unwrap() .discriminant_for_variant(bx.tcx(), variant_index) - .val as u64; - bx.store(C_int(ptr.layout.llvm_type(bx.cx), to as i64), - ptr.llval, ptr.align); + .val; + bx.store( + C_uint_big(ptr.layout.llvm_type(bx.cx), to), + ptr.llval, + ptr.align); } layout::Variants::NicheFilling { dataful_variant, diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index 93702bfbbf3..79e906ca975 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -22,7 +22,7 @@ use base; use builder::Builder; use callee; use common::{self, val_ty}; -use common::{C_bool, C_u8, C_i32, C_u32, C_u64, C_null, C_usize, C_uint, C_uint_big}; +use common::{C_bool, C_u8, C_i32, C_u32, C_u64, C_undef, C_null, C_usize, C_uint, C_uint_big}; use consts; use monomorphize; use type_::Type; @@ -267,11 +267,33 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { } mir::CastKind::Misc => { assert!(cast.is_llvm_immediate()); + let ll_t_out = cast.immediate_llvm_type(bx.cx); + if operand.layout.abi == layout::Abi::Uninhabited { + return (bx, OperandRef { + val: OperandValue::Immediate(C_undef(ll_t_out)), + layout: cast, + }); + } let r_t_in = CastTy::from_ty(operand.layout.ty) .expect("bad input type for cast"); let r_t_out = CastTy::from_ty(cast.ty).expect("bad output type for cast"); let ll_t_in = operand.layout.immediate_llvm_type(bx.cx); - let ll_t_out = cast.immediate_llvm_type(bx.cx); + match operand.layout.variants { + layout::Variants::Single { index } => { + if let Some(def) = operand.layout.ty.ty_adt_def() { + let discr_val = def + .discriminant_for_variant(bx.cx.tcx, index) + .val; + let discr = C_uint_big(ll_t_out, discr_val); + return (bx, OperandRef { + val: OperandValue::Immediate(discr), + layout: cast, + }); + } + } + layout::Variants::Tagged { .. } | + layout::Variants::NicheFilling { .. } => {}, + } let llval = operand.immediate(); let mut signed = false; @@ -514,7 +536,6 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { let is_float = input_ty.is_fp(); let is_signed = input_ty.is_signed(); let is_nil = input_ty.is_nil(); - let is_bool = input_ty.is_bool(); match op { mir::BinOp::Add => if is_float { bx.fadd(lhs, rhs) @@ -564,15 +585,6 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { lhs, rhs ) } else { - let (lhs, rhs) = if is_bool { - // FIXME(#36856) -- extend the bools into `i8` because - // LLVM's i1 comparisons are broken. - (bx.zext(lhs, Type::i8(bx.cx)), - bx.zext(rhs, Type::i8(bx.cx))) - } else { - (lhs, rhs) - }; - bx.icmp( base::bin_op_to_icmp_predicate(op.to_hir_binop(), is_signed), lhs, rhs diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 06d94e8d155..d19b5af2527 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -88,7 +88,7 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug + BaseMonoItemExt<'a, 'tcx> { self.to_raw_string(), cx.codegen_unit.name()); - let symbol_name = self.symbol_name(cx.tcx); + let symbol_name = self.symbol_name(cx.tcx).as_str(); debug!("symbol {}", &symbol_name); diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs index f37114ee4ac..5e6b2764957 100644 --- a/src/librustc_trans/type_of.rs +++ b/src/librustc_trans/type_of.rs @@ -8,12 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use abi::FnType; +use abi::{FnType, FnTypeExt}; use common::*; use rustc::hir; use rustc::ty::{self, Ty, TypeFoldable}; use rustc::ty::layout::{self, Align, LayoutOf, Size, TyLayout}; -use rustc_back::PanicStrategy; +use rustc_target::spec::PanicStrategy; use trans_item::DefPathBasedNames; use type_::Type; diff --git a/src/librustc_trans_utils/Cargo.toml b/src/librustc_trans_utils/Cargo.toml index 7a01b6d261a..323d9d1ceda 100644 --- a/src/librustc_trans_utils/Cargo.toml +++ b/src/librustc_trans_utils/Cargo.toml @@ -17,7 +17,7 @@ log = "0.4" syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } rustc = { path = "../librustc" } -rustc_back = { path = "../librustc_back" } +rustc_target = { path = "../librustc_target" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_mir = { path = "../librustc_mir" } rustc_incremental = { path = "../librustc_incremental" } diff --git a/src/librustc_trans_utils/lib.rs b/src/librustc_trans_utils/lib.rs index 0c6bc9e246b..b91f4e4dffb 100644 --- a/src/librustc_trans_utils/lib.rs +++ b/src/librustc_trans_utils/lib.rs @@ -30,7 +30,7 @@ extern crate log; #[macro_use] extern crate rustc; -extern crate rustc_back; +extern crate rustc_target; extern crate rustc_mir; extern crate rustc_incremental; extern crate syntax; diff --git a/src/librustc_trans_utils/symbol_names.rs b/src/librustc_trans_utils/symbol_names.rs index f3b7326b210..be5bff60805 100644 --- a/src/librustc_trans_utils/symbol_names.rs +++ b/src/librustc_trans_utils/symbol_names.rs @@ -229,7 +229,7 @@ fn def_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) fn symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance<'tcx>) -> ty::SymbolName { - ty::SymbolName { name: Symbol::intern(&compute_symbol_name(tcx, instance)).as_str() } + ty::SymbolName { name: Symbol::intern(&compute_symbol_name(tcx, instance)).as_interned_str() } } fn compute_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance<'tcx>) @@ -355,12 +355,12 @@ impl SymbolPathBuffer { result: String::with_capacity(64), temp_buf: String::with_capacity(16) }; - result.result.push_str(&symbol.name); + result.result.push_str(&symbol.name.as_str()); result } fn into_interned(self) -> ty::SymbolName { - ty::SymbolName { name: Symbol::intern(&self.result).as_str() } + ty::SymbolName { name: Symbol::intern(&self.result).as_interned_str() } } fn finish(mut self, hash: u64) -> String { diff --git a/src/librustc_trans_utils/trans_crate.rs b/src/librustc_trans_utils/trans_crate.rs index b7895631c60..7b585d1060f 100644 --- a/src/librustc_trans_utils/trans_crate.rs +++ b/src/librustc_trans_utils/trans_crate.rs @@ -43,7 +43,7 @@ use rustc::ty::maps::Providers; use rustc::middle::cstore::EncodedMetadata; use rustc::middle::cstore::MetadataLoader; use rustc::dep_graph::DepGraph; -use rustc_back::target::Target; +use rustc_target::spec::Target; use rustc_data_structures::fx::FxHashMap; use rustc_mir::monomorphize::collector; use link::{build_link_meta, out_filename}; diff --git a/src/librustc_typeck/Cargo.toml b/src/librustc_typeck/Cargo.toml index c7868cc1e95..70c13e9b7d6 100644 --- a/src/librustc_typeck/Cargo.toml +++ b/src/librustc_typeck/Cargo.toml @@ -18,5 +18,6 @@ rustc = { path = "../librustc" } rustc_const_math = { path = "../librustc_const_math" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_platform_intrinsics = { path = "../librustc_platform_intrinsics" } +rustc_target = { path = "../librustc_target" } syntax_pos = { path = "../libsyntax_pos" } rustc_errors = { path = "../librustc_errors" } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 36debf677da..93dbba6e873 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -23,6 +23,7 @@ use rustc::ty::subst::{Kind, UnpackedKind, Subst, Substs}; use rustc::traits; use rustc::ty::{self, RegionKind, Ty, TyCtxt, ToPredicate, TypeFoldable}; use rustc::ty::wf::object_region_bounds; +use rustc_target::spec::abi; use std::slice; use require_c_abi_if_variadic; use util::common::ErrorReported; @@ -30,7 +31,7 @@ use util::nodemap::FxHashSet; use errors::FatalError; use std::iter; -use syntax::{abi, ast}; +use syntax::ast; use syntax::feature_gate::{GateIssue, emit_feature_err}; use syntax_pos::Span; @@ -100,7 +101,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { { let tcx = self.tcx(); let lifetime_name = |def_id| { - tcx.hir.name(tcx.hir.as_local_node_id(def_id).unwrap()).as_str() + tcx.hir.name(tcx.hir.as_local_node_id(def_id).unwrap()).as_interned_str() }; let hir_id = tcx.hir.node_to_hir_id(lifetime.id); @@ -363,7 +364,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { trait_def_id, self_ty, trait_ref.path.segments.last().unwrap()); - let poly_trait_ref = ty::Binder(ty::TraitRef::new(trait_def_id, substs)); + let poly_trait_ref = ty::Binder::bind(ty::TraitRef::new(trait_def_id, substs)); poly_projections.extend(assoc_bindings.iter().filter_map(|binding| { // specify type to assert that error was already reported in Err case: @@ -485,7 +486,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { // for<'a> <T as FnMut<(&'a u32,)>>::Output = &'a str // <-- 'a is ok let late_bound_in_trait_ref = tcx.collect_constrained_late_bound_regions(&trait_ref); let late_bound_in_ty = - tcx.collect_referenced_late_bound_regions(&ty::Binder(binding.ty)); + tcx.collect_referenced_late_bound_regions(&ty::Binder::bind(binding.ty)); debug!("late_bound_in_trait_ref = {:?}", late_bound_in_trait_ref); debug!("late_bound_in_ty = {:?}", late_bound_in_ty); for br in late_bound_in_ty.difference(&late_bound_in_trait_ref) { @@ -639,7 +640,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } for projection_bound in &projection_bounds { - associated_types.remove(&projection_bound.0.projection_ty.item_def_id); + associated_types.remove(&projection_bound.projection_def_id()); } for item_def_id in associated_types { @@ -654,6 +655,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { .emit(); } + // skip_binder is okay, because the predicates are re-bound. let mut v = iter::once(ty::ExistentialPredicate::Trait(*existential_principal.skip_binder())) .chain(auto_traits.into_iter().map(ty::ExistentialPredicate::AutoTrait)) @@ -661,7 +663,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { .map(|x| ty::ExistentialPredicate::Projection(*x.skip_binder()))) .collect::<AccumulateVec<[_; 8]>>(); v.sort_by(|a, b| a.cmp(tcx, b)); - let existential_predicates = ty::Binder(tcx.mk_existential_predicates(v.into_iter())); + let existential_predicates = ty::Binder::bind(tcx.mk_existential_predicates(v.into_iter())); // Explicitly specified region bound. Use that. @@ -825,7 +827,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { }; let candidates = - traits::supertraits(tcx, ty::Binder(trait_ref)) + traits::supertraits(tcx, ty::Binder::bind(trait_ref)) .filter(|r| self.trait_defines_associated_type_named(r.def_id(), assoc_name)); @@ -853,7 +855,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } }; - let trait_did = bound.0.def_id; + let trait_did = bound.def_id(); let (assoc_ident, def_scope) = tcx.adjust(assoc_name, trait_did, ref_id); let item = tcx.associated_items(trait_did).find(|i| { Namespace::from(i.kind) == Namespace::Type && @@ -979,7 +981,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { let item_def_id = tcx.hir.local_def_id(item_id); let generics = tcx.generics_of(item_def_id); let index = generics.type_param_to_index[&tcx.hir.local_def_id(node_id)]; - tcx.mk_param(index, tcx.hir.name(node_id).as_str()) + tcx.mk_param(index, tcx.hir.name(node_id).as_interned_str()) } Def::SelfTy(_, Some(def_id)) => { // Self in impl (we know the concrete type). @@ -1184,7 +1186,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { debug!("ty_of_fn: output_ty={:?}", output_ty); - let bare_fn_ty = ty::Binder(tcx.mk_fn_sig( + let bare_fn_ty = ty::Binder::bind(tcx.mk_fn_sig( input_tys.into_iter(), output_ty, decl.variadic, @@ -1396,7 +1398,8 @@ impl<'a, 'gcx, 'tcx> Bounds<'tcx> { // account for the binder being introduced below; no need to shift `param_ty` // because, at present at least, it can only refer to early-bound regions let region_bound = tcx.mk_region(ty::fold::shift_region(*region_bound, 1)); - vec.push(ty::Binder(ty::OutlivesPredicate(param_ty, region_bound)).to_predicate()); + vec.push( + ty::Binder::dummy(ty::OutlivesPredicate(param_ty, region_bound)).to_predicate()); } for bound_trait_ref in &self.trait_bounds { diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs index a87058d1fa5..3199ff17ae9 100644 --- a/src/librustc_typeck/check/autoderef.rs +++ b/src/librustc_typeck/check/autoderef.rs @@ -120,15 +120,15 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> { let cause = traits::ObligationCause::misc(self.span, self.fcx.body_id); - let mut selcx = traits::SelectionContext::new(self.fcx); let obligation = traits::Obligation::new(cause.clone(), self.fcx.param_env, trait_ref.to_predicate()); - if !selcx.evaluate_obligation(&obligation) { + if !self.fcx.predicate_may_hold(&obligation) { debug!("overloaded_deref_ty: cannot match obligation"); return None; } + let mut selcx = traits::SelectionContext::new(self.fcx); let normalized = traits::normalize_projection_type(&mut selcx, self.fcx.param_env, ty::ProjectionTy::from_ref_and_name( diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index b1fb0938698..4df496763e4 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -17,7 +17,7 @@ use hir::def_id::{DefId, LOCAL_CRATE}; use rustc::{infer, traits}; use rustc::ty::{self, TyCtxt, TypeFoldable, Ty}; use rustc::ty::adjustment::{Adjustment, Adjust, AllowTwoPhase, AutoBorrow, AutoBorrowMutability}; -use syntax::abi; +use rustc_target::spec::abi; use syntax::symbol::Symbol; use syntax_pos::Span; @@ -267,7 +267,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // This is the "default" function signature, used in case of error. // In that case, we check each argument against "error" in order to // set up all the node type bindings. - (ty::Binder(self.tcx.mk_fn_sig( + (ty::Binder::bind(self.tcx.mk_fn_sig( self.err_args(arg_exprs.len()).into_iter(), self.tcx.types.err, false, diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 68b0560355f..3b9d561ffc5 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -23,7 +23,7 @@ use rustc::ty::subst::Substs; use rustc::ty::TypeFoldable; use std::cmp; use std::iter; -use syntax::abi::Abi; +use rustc_target::spec::abi::Abi; use syntax::codemap::Span; use rustc::hir; @@ -303,7 +303,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { return None; } - let arg_param_ty = trait_ref.substs().type_at(1); + let arg_param_ty = trait_ref.skip_binder().substs.type_at(1); let arg_param_ty = self.resolve_type_vars_if_possible(&arg_param_ty); debug!( "deduce_sig_from_projection: arg_param_ty {:?}", @@ -317,7 +317,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } }; - let ret_param_ty = projection.0.ty; + let ret_param_ty = projection.skip_binder().ty; let ret_param_ty = self.resolve_type_vars_if_possible(&ret_param_ty); debug!( "deduce_sig_from_projection: ret_param_ty {:?}", @@ -458,7 +458,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // regions appearing free in `expected_sig` are now bound up // in this binder we are creating. assert!(!expected_sig.sig.has_regions_escaping_depth(1)); - let bound_sig = ty::Binder(self.tcx.mk_fn_sig( + let bound_sig = ty::Binder::bind(self.tcx.mk_fn_sig( expected_sig.sig.inputs().iter().cloned(), expected_sig.sig.output(), decl.variadic, @@ -562,7 +562,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let (supplied_ty, _) = self.infcx.replace_late_bound_regions_with_fresh_var( hir_ty.span, LateBoundRegionConversionTime::FnCall, - &ty::Binder(supplied_ty), + &ty::Binder::bind(supplied_ty), ); // recreated from (*) above // Check that E' = S'. @@ -607,7 +607,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { hir::DefaultReturn(_) => astconv.ty_infer(decl.output.span()), }; - let result = ty::Binder(self.tcx.mk_fn_sig( + let result = ty::Binder::bind(self.tcx.mk_fn_sig( supplied_arguments, supplied_return, decl.variadic, @@ -639,7 +639,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { hir::DefaultReturn(_) => {} } - let result = ty::Binder(self.tcx.mk_fn_sig( + let result = ty::Binder::bind(self.tcx.mk_fn_sig( supplied_arguments, self.tcx.types.err, decl.variadic, diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index a8d1f69dfe8..8c69608a261 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -558,7 +558,8 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { let trait_ref = match obligation.predicate { ty::Predicate::Trait(ref tr) if traits.contains(&tr.def_id()) => { if unsize_did == tr.def_id() { - if let ty::TyTuple(..) = tr.0.input_types().nth(1).unwrap().sty { + let sty = &tr.skip_binder().input_types().nth(1).unwrap().sty; + if let ty::TyTuple(..) = sty { debug!("coerce_unsized: found unsized tuple coercion"); has_unsized_tuple_coercion = true; } diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index e1e3dea9a2a..91264849cad 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -234,9 +234,11 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let mut selcx = traits::SelectionContext::new(&infcx); let impl_m_own_bounds = impl_m_predicates.instantiate_own(tcx, impl_to_skol_substs); - let (impl_m_own_bounds, _) = infcx.replace_late_bound_regions_with_fresh_var(impl_m_span, - infer::HigherRankedType, - &ty::Binder(impl_m_own_bounds.predicates)); + let (impl_m_own_bounds, _) = infcx.replace_late_bound_regions_with_fresh_var( + impl_m_span, + infer::HigherRankedType, + &ty::Binder::bind(impl_m_own_bounds.predicates) + ); for predicate in impl_m_own_bounds { let traits::Normalized { value: predicate, obligations } = traits::normalize(&mut selcx, param_env, normalize_cause.clone(), &predicate); @@ -270,7 +272,7 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl_m_node_id, param_env, &impl_sig); - let impl_fty = tcx.mk_fn_ptr(ty::Binder(impl_sig)); + let impl_fty = tcx.mk_fn_ptr(ty::Binder::bind(impl_sig)); debug!("compare_impl_method: impl_fty={:?}", impl_fty); let trait_sig = tcx.liberate_late_bound_regions( @@ -283,7 +285,7 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl_m_node_id, param_env, &trait_sig); - let trait_fty = tcx.mk_fn_ptr(ty::Binder(trait_sig)); + let trait_fty = tcx.mk_fn_ptr(ty::Binder::bind(trait_sig)); debug!("compare_impl_method: trait_fty={:?}", trait_fty); @@ -505,7 +507,7 @@ fn compare_self_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx.infer_ctxt().enter(|infcx| { let self_arg_ty = tcx.liberate_late_bound_regions( method.def_id, - &ty::Binder(self_arg_ty) + &ty::Binder::bind(self_arg_ty) ); let can_eq_self = |ty| infcx.can_eq(param_env, untransformed_self_ty, ty).is_ok(); match ExplicitSelf::determine(self_arg_ty, can_eq_self) { @@ -730,8 +732,7 @@ fn compare_synthetic_generics<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if impl_ty.synthetic != trait_ty.synthetic { let impl_node_id = tcx.hir.as_local_node_id(impl_ty.def_id).unwrap(); let impl_span = tcx.hir.span(impl_node_id); - let trait_node_id = tcx.hir.as_local_node_id(trait_ty.def_id).unwrap(); - let trait_span = tcx.hir.span(trait_node_id); + let trait_span = tcx.def_span(trait_ty.def_id); let mut err = struct_span_err!(tcx.sess, impl_span, E0643, diff --git a/src/librustc_typeck/check/generator_interior.rs b/src/librustc_typeck/check/generator_interior.rs index c50ee13723f..7bae5fe4fd1 100644 --- a/src/librustc_typeck/check/generator_interior.rs +++ b/src/librustc_typeck/check/generator_interior.rs @@ -129,7 +129,7 @@ pub fn resolve_interior<'a, 'gcx, 'tcx>(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, ty::BrAnon(counter))) }); - let witness = fcx.tcx.mk_generator_witness(ty::Binder(type_list)); + let witness = fcx.tcx.mk_generator_witness(ty::Binder::bind(type_list)); debug!("Types in generator after region replacement {:?}, span = {:?}", witness, body.value.span); diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index da0d4509353..fcf7541a159 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -17,7 +17,7 @@ use rustc::ty::{self, TyCtxt, Ty}; use rustc::util::nodemap::FxHashMap; use require_same_types; -use syntax::abi::Abi; +use rustc_target::spec::abi::Abi; use syntax::ast; use syntax::symbol::Symbol; use syntax_pos::Span; @@ -61,7 +61,7 @@ fn equate_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, return; } - let fty = tcx.mk_fn_ptr(ty::Binder(tcx.mk_fn_sig( + let fty = tcx.mk_fn_ptr(ty::Binder::bind(tcx.mk_fn_sig( inputs.into_iter(), output, false, @@ -76,7 +76,7 @@ fn equate_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, /// and in libcore/intrinsics.rs pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &hir::ForeignItem) { - let param = |n| tcx.mk_param(n, Symbol::intern(&format!("P{}", n)).as_str()); + let param = |n| tcx.mk_param(n, Symbol::intern(&format!("P{}", n)).as_interned_str()); let name = it.name.as_str(); let (n_tps, inputs, output) = if name.starts_with("atomic_") { let split : Vec<&str> = name.split('_').collect(); @@ -304,7 +304,7 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, "try" => { let mut_u8 = tcx.mk_mut_ptr(tcx.types.u8); - let fn_ty = ty::Binder(tcx.mk_fn_sig( + let fn_ty = ty::Binder::bind(tcx.mk_fn_sig( iter::once(mut_u8), tcx.mk_nil(), false, @@ -341,7 +341,7 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pub fn check_platform_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &hir::ForeignItem) { let param = |n| { - let name = Symbol::intern(&format!("P{}", n)).as_str(); + let name = Symbol::intern(&format!("P{}", n)).as_interned_str(); tcx.mk_param(n, name) }; diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 7569bdccd5a..09feaaffc5b 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -125,7 +125,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // We won't add these if we encountered an illegal sized bound, so that we can use // a custom error in that case. if !illegal_sized_bound { - let method_ty = self.tcx.mk_fn_ptr(ty::Binder(method_sig)); + let method_ty = self.tcx.mk_fn_ptr(ty::Binder::bind(method_sig)); self.add_obligations(method_ty, all_substs, &method_predicates); } @@ -587,7 +587,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { } }) .any(|trait_pred| { - match trait_pred.0.self_ty().sty { + match trait_pred.skip_binder().self_ty().sty { ty::TyDynamic(..) => true, _ => false, } diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 49d0df555fa..5f904a9419b 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -277,8 +277,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { poly_trait_ref.to_predicate()); // Now we want to know if this can be matched - let mut selcx = traits::SelectionContext::new(self); - if !selcx.evaluate_obligation(&obligation) { + if !self.predicate_may_hold(&obligation) { debug!("--> Cannot match obligation"); return None; // Cannot be matched, no such method resolution is possible. } @@ -336,7 +335,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { &bounds)); // Also add an obligation for the method type being well-formed. - let method_ty = tcx.mk_fn_ptr(ty::Binder(fn_sig)); + let method_ty = tcx.mk_fn_ptr(ty::Binder::bind(fn_sig)); debug!("lookup_in_trait_adjusted: matched method method_ty={:?} obligation={:?}", method_ty, obligation); diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index de570956622..476ae680973 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -471,6 +471,9 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { ty::TyStr => { let lang_def_id = lang_items.str_impl(); self.assemble_inherent_impl_for_primitive(lang_def_id); + + let lang_def_id = lang_items.str_alloc_impl(); + self.assemble_inherent_impl_for_primitive(lang_def_id); } ty::TySlice(_) => { let lang_def_id = lang_items.slice_impl(); @@ -478,6 +481,12 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { let lang_def_id = lang_items.slice_u8_impl(); self.assemble_inherent_impl_for_primitive(lang_def_id); + + let lang_def_id = lang_items.slice_alloc_impl(); + self.assemble_inherent_impl_for_primitive(lang_def_id); + + let lang_def_id = lang_items.slice_u8_alloc_impl(); + self.assemble_inherent_impl_for_primitive(lang_def_id); } ty::TyRawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutImmutable }) => { let lang_def_id = lang_items.const_ptr_impl(); @@ -538,10 +547,16 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { ty::TyFloat(ast::FloatTy::F32) => { let lang_def_id = lang_items.f32_impl(); self.assemble_inherent_impl_for_primitive(lang_def_id); + + let lang_def_id = lang_items.f32_runtime_impl(); + self.assemble_inherent_impl_for_primitive(lang_def_id); } ty::TyFloat(ast::FloatTy::F64) => { let lang_def_id = lang_items.f64_impl(); self.assemble_inherent_impl_for_primitive(lang_def_id); + + let lang_def_id = lang_items.f64_runtime_impl(); + self.assemble_inherent_impl_for_primitive(lang_def_id); } _ => {} } @@ -635,7 +650,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { .filter_map(|predicate| { match *predicate { ty::Predicate::Trait(ref trait_predicate) => { - match trait_predicate.0.trait_ref.self_ty().sty { + match trait_predicate.skip_binder().trait_ref.self_ty().sty { ty::TyParam(ref p) if *p == param_ty => { Some(trait_predicate.to_poly_trait_ref()) } @@ -1158,7 +1173,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { let predicate = trait_ref.to_predicate(); let obligation = traits::Obligation::new(cause.clone(), self.param_env, predicate); - if !selcx.evaluate_obligation(&obligation) { + if !self.predicate_may_hold(&obligation) { if self.probe(|_| self.select_trait_candidate(trait_ref).is_err()) { // This candidate's primary obligation doesn't even // select - don't bother registering anything in @@ -1186,10 +1201,10 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { // Evaluate those obligations to see if they might possibly hold. for o in candidate_obligations.into_iter().chain(sub_obligations) { let o = self.resolve_type_vars_if_possible(&o); - if !selcx.evaluate_obligation(&o) { + if !self.predicate_may_hold(&o) { result = ProbeResult::NoMatch; if let &ty::Predicate::Trait(ref pred) = &o.predicate { - possibly_unsatisfied_predicates.push(pred.0.trait_ref); + possibly_unsatisfied_predicates.push(pred.skip_binder().trait_ref); } } } @@ -1470,7 +1485,7 @@ impl<'tcx> Candidate<'tcx> { // inference variables or other artifacts. This // means they are safe to put into the // `WhereClausePick`. - assert!(!trait_ref.substs().needs_infer()); + assert!(!trait_ref.skip_binder().substs.needs_infer()); WhereClausePick(trait_ref.clone()) } diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index d8907866467..2dc7c7fe71a 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -19,7 +19,7 @@ use hir::def::Def; use hir::def_id::{CRATE_DEF_INDEX, DefId}; use middle::lang_items::FnOnceTraitLangItem; use namespace::Namespace; -use rustc::traits::{Obligation, SelectionContext}; +use rustc::traits::Obligation; use util::nodemap::FxHashSet; use syntax::ast; @@ -65,7 +65,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.body_id, self.param_env, poly_trait_ref.to_predicate()); - SelectionContext::new(self).evaluate_obligation(&obligation) + self.predicate_may_hold(&obligation) }) }) } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index ca35153d571..db859e42057 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -118,13 +118,13 @@ use std::fmt::Display; use std::mem::replace; use std::iter; use std::ops::{self, Deref}; -use syntax::abi::Abi; +use rustc_target::spec::abi::Abi; use syntax::ast; use syntax::attr; use syntax::codemap::{original_sp, Spanned}; use syntax::feature_gate::{GateIssue, emit_feature_err}; use syntax::ptr::P; -use syntax::symbol::{Symbol, InternedString, keywords}; +use syntax::symbol::{Symbol, LocalInternedString, keywords}; use syntax::util::lev_distance::find_best_match_for_name; use syntax_pos::{self, BytePos, Span, MultiSpan}; @@ -1727,7 +1727,7 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> { predicates: self.param_env.caller_bounds.iter().filter(|predicate| { match **predicate { ty::Predicate::Trait(ref data) => { - data.0.self_ty().is_param(index) + data.skip_binder().self_ty().is_param(index) } _ => false } @@ -2217,7 +2217,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } // Tries to apply a fallback to `ty` if it is an unsolved variable. - // Non-numerics get replaced with !, unconstrained ints with i32, + // Non-numerics get replaced with ! or () (depending on whether + // feature(never_type) is enabled, unconstrained ints with i32, // unconstrained floats with f64. // Fallback becomes very dubious if we have encountered type-checking errors. // In that case, fallback to TyError. @@ -2231,7 +2232,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ if self.is_tainted_by_errors() => self.tcx().types.err, UnconstrainedInt => self.tcx.types.i32, UnconstrainedFloat => self.tcx.types.f64, - Neither if self.type_var_diverges(ty) => self.tcx.types.never, + Neither if self.type_var_diverges(ty) => self.tcx.mk_diverging_default(), Neither => return false, }; debug!("default_type_parameters: defaulting `{:?}` to `{:?}`", ty, fallback); @@ -3171,7 +3172,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Return an hint about the closest match in field names fn suggest_field_name(variant: &'tcx ty::VariantDef, field: &Spanned<ast::Name>, - skip: Vec<InternedString>) + skip: Vec<LocalInternedString>) -> Option<Symbol> { let name = field.node.as_str(); let names = variant.fields.iter().filter_map(|field| { diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 6348f386177..d0ff44c8e7e 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -508,7 +508,7 @@ fn check_method_receiver<'fcx, 'gcx, 'tcx>(fcx: &FnCtxt<'fcx, 'gcx, 'tcx>, let self_ty = fcx.normalize_associated_types_in(span, &self_ty); let self_ty = fcx.tcx.liberate_late_bound_regions( method.def_id, - &ty::Binder(self_ty) + &ty::Binder::bind(self_ty) ); let self_arg_ty = sig.inputs()[0]; @@ -517,7 +517,7 @@ fn check_method_receiver<'fcx, 'gcx, 'tcx>(fcx: &FnCtxt<'fcx, 'gcx, 'tcx>, let self_arg_ty = fcx.normalize_associated_types_in(span, &self_arg_ty); let self_arg_ty = fcx.tcx.liberate_late_bound_regions( method.def_id, - &ty::Binder(self_arg_ty) + &ty::Binder::bind(self_arg_ty) ); let mut autoderef = fcx.autoderef(span, self_arg_ty).include_raw_pointers(); @@ -655,7 +655,7 @@ fn reject_shadowing_type_parameters(tcx: TyCtxt, def_id: DefId) { // local so it should be okay to just unwrap everything. let trait_def_id = impl_params[&method_param.name]; let trait_decl_span = tcx.def_span(trait_def_id); - error_194(tcx, type_span, trait_decl_span, &method_param.name[..]); + error_194(tcx, type_span, trait_decl_span, &method_param.name.as_str()[..]); } } } diff --git a/src/librustc_typeck/coherence/inherent_impls.rs b/src/librustc_typeck/coherence/inherent_impls.rs index d43ab0d3713..532f1da4f30 100644 --- a/src/librustc_typeck/coherence/inherent_impls.rs +++ b/src/librustc_typeck/coherence/inherent_impls.rs @@ -114,6 +114,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> { ty::TyChar => { self.check_primitive_impl(def_id, lang_items.char_impl(), + None, "char", "char", item.span); @@ -121,6 +122,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> { ty::TyStr => { self.check_primitive_impl(def_id, lang_items.str_impl(), + lang_items.str_alloc_impl(), "str", "str", item.span); @@ -128,6 +130,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> { ty::TySlice(slice_item) if slice_item == self.tcx.types.u8 => { self.check_primitive_impl(def_id, lang_items.slice_u8_impl(), + lang_items.slice_u8_alloc_impl(), "slice_u8", "[u8]", item.span); @@ -135,6 +138,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> { ty::TySlice(_) => { self.check_primitive_impl(def_id, lang_items.slice_impl(), + lang_items.slice_alloc_impl(), "slice", "[T]", item.span); @@ -142,6 +146,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> { ty::TyRawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutImmutable }) => { self.check_primitive_impl(def_id, lang_items.const_ptr_impl(), + None, "const_ptr", "*const T", item.span); @@ -149,6 +154,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> { ty::TyRawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutMutable }) => { self.check_primitive_impl(def_id, lang_items.mut_ptr_impl(), + None, "mut_ptr", "*mut T", item.span); @@ -156,6 +162,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> { ty::TyInt(ast::IntTy::I8) => { self.check_primitive_impl(def_id, lang_items.i8_impl(), + None, "i8", "i8", item.span); @@ -163,6 +170,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> { ty::TyInt(ast::IntTy::I16) => { self.check_primitive_impl(def_id, lang_items.i16_impl(), + None, "i16", "i16", item.span); @@ -170,6 +178,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> { ty::TyInt(ast::IntTy::I32) => { self.check_primitive_impl(def_id, lang_items.i32_impl(), + None, "i32", "i32", item.span); @@ -177,6 +186,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> { ty::TyInt(ast::IntTy::I64) => { self.check_primitive_impl(def_id, lang_items.i64_impl(), + None, "i64", "i64", item.span); @@ -184,6 +194,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> { ty::TyInt(ast::IntTy::I128) => { self.check_primitive_impl(def_id, lang_items.i128_impl(), + None, "i128", "i128", item.span); @@ -191,6 +202,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> { ty::TyInt(ast::IntTy::Isize) => { self.check_primitive_impl(def_id, lang_items.isize_impl(), + None, "isize", "isize", item.span); @@ -198,6 +210,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> { ty::TyUint(ast::UintTy::U8) => { self.check_primitive_impl(def_id, lang_items.u8_impl(), + None, "u8", "u8", item.span); @@ -205,6 +218,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> { ty::TyUint(ast::UintTy::U16) => { self.check_primitive_impl(def_id, lang_items.u16_impl(), + None, "u16", "u16", item.span); @@ -212,6 +226,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> { ty::TyUint(ast::UintTy::U32) => { self.check_primitive_impl(def_id, lang_items.u32_impl(), + None, "u32", "u32", item.span); @@ -219,6 +234,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> { ty::TyUint(ast::UintTy::U64) => { self.check_primitive_impl(def_id, lang_items.u64_impl(), + None, "u64", "u64", item.span); @@ -226,6 +242,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> { ty::TyUint(ast::UintTy::U128) => { self.check_primitive_impl(def_id, lang_items.u128_impl(), + None, "u128", "u128", item.span); @@ -233,6 +250,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> { ty::TyUint(ast::UintTy::Usize) => { self.check_primitive_impl(def_id, lang_items.usize_impl(), + None, "usize", "usize", item.span); @@ -240,6 +258,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> { ty::TyFloat(ast::FloatTy::F32) => { self.check_primitive_impl(def_id, lang_items.f32_impl(), + lang_items.f32_runtime_impl(), "f32", "f32", item.span); @@ -247,6 +266,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> { ty::TyFloat(ast::FloatTy::F64) => { self.check_primitive_impl(def_id, lang_items.f64_impl(), + lang_items.f64_runtime_impl(), "f64", "f64", item.span); @@ -305,11 +325,15 @@ impl<'a, 'tcx> InherentCollect<'a, 'tcx> { fn check_primitive_impl(&self, impl_def_id: DefId, lang_def_id: Option<DefId>, + lang_def_id2: Option<DefId>, lang: &str, ty: &str, span: Span) { - match lang_def_id { - Some(lang_def_id) if lang_def_id == impl_def_id => { + match (lang_def_id, lang_def_id2) { + (Some(lang_def_id), _) if lang_def_id == impl_def_id => { + // OK + } + (_, Some(lang_def_id)) if lang_def_id == impl_def_id => { // OK } _ => { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 6bd38244e8c..1b8f2e661c3 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -38,8 +38,9 @@ use rustc::ty::util::IntTypeExt; use rustc::ty::util::Discr; use rustc::util::captures::Captures; use rustc::util::nodemap::FxHashMap; +use rustc_target::spec::abi; -use syntax::{abi, ast}; +use syntax::ast; use syntax::ast::MetaItemKind; use syntax::attr::{InlineAttr, list_contains_name, mark_used}; use syntax::codemap::Spanned; @@ -243,7 +244,7 @@ fn type_param_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let param_owner_def_id = tcx.hir.local_def_id(param_owner); let generics = tcx.generics_of(param_owner_def_id); let index = generics.type_param_to_index[&def_id]; - let ty = tcx.mk_param(index, tcx.hir.ty_param_name(param_id).as_str()); + let ty = tcx.mk_param(index, tcx.hir.ty_param_name(param_id).as_interned_str()); // Don't look for bounds where the type parameter isn't in scope. let parent = if item_def_id == param_owner_def_id { @@ -841,7 +842,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, opt_self = Some(ty::TypeParameterDef { index: 0, - name: keywords::SelfType.name().as_str(), + name: keywords::SelfType.name().as_interned_str(), def_id: tcx.hir.local_def_id(param_id), has_default: false, object_lifetime_default: rl::Set1::Empty, @@ -887,7 +888,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let early_lifetimes = early_bound_lifetimes_from_generics(tcx, ast_generics); let regions = early_lifetimes.enumerate().map(|(i, l)| { ty::RegionParameterDef { - name: l.lifetime.name.name().as_str(), + name: l.lifetime.name.name().as_interned_str(), index: own_start + i as u32, def_id: tcx.hir.local_def_id(l.lifetime.id), pure_wrt_drop: l.pure_wrt_drop, @@ -917,7 +918,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty::TypeParameterDef { index: type_start + i as u32, - name: p.name.as_str(), + name: p.name.as_interned_str(), def_id: tcx.hir.local_def_id(p.id), has_default: p.default.is_some(), object_lifetime_default: @@ -936,7 +937,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // add a dummy parameter for the closure kind types.push(ty::TypeParameterDef { index: type_start, - name: Symbol::intern("<closure_kind>").as_str(), + name: Symbol::intern("<closure_kind>").as_interned_str(), def_id, has_default: false, object_lifetime_default: rl::Set1::Empty, @@ -947,7 +948,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // add a dummy parameter for the closure signature types.push(ty::TypeParameterDef { index: type_start + 1, - name: Symbol::intern("<closure_signature>").as_str(), + name: Symbol::intern("<closure_signature>").as_interned_str(), def_id, has_default: false, object_lifetime_default: rl::Set1::Empty, @@ -958,7 +959,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx.with_freevars(node_id, |fv| { types.extend(fv.iter().zip(2..).map(|(_, i)| ty::TypeParameterDef { index: type_start + i, - name: Symbol::intern("<upvar>").as_str(), + name: Symbol::intern("<upvar>").as_interned_str(), def_id, has_default: false, object_lifetime_default: rl::Set1::Empty, @@ -1171,7 +1172,7 @@ fn fn_sig<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let inputs = fields.iter().map(|f| { tcx.type_of(tcx.hir.local_def_id(f.id)) }); - ty::Binder(tcx.mk_fn_sig( + ty::Binder::bind(tcx.mk_fn_sig( inputs, ty, false, @@ -1428,13 +1429,13 @@ pub fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let region = tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion { def_id: tcx.hir.local_def_id(param.lifetime.id), index, - name: param.lifetime.name.name().as_str(), + name: param.lifetime.name.name().as_interned_str(), })); index += 1; for bound in ¶m.bounds { let bound_region = AstConv::ast_region_to_region(&icx, bound, None); - let outlives = ty::Binder(ty::OutlivesPredicate(region, bound_region)); + let outlives = ty::Binder::bind(ty::OutlivesPredicate(region, bound_region)); predicates.push(outlives.to_predicate()); } } @@ -1442,7 +1443,7 @@ pub fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Collect the predicates that were written inline by the user on each // type parameter (e.g., `<T:Foo>`). for param in ast_generics.ty_params() { - let param_ty = ty::ParamTy::new(index, param.name.as_str()).to_ty(tcx); + let param_ty = ty::ParamTy::new(index, param.name.as_interned_str()).to_ty(tcx); index += 1; let bounds = compute_bounds(&icx, @@ -1482,7 +1483,7 @@ pub fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let region = AstConv::ast_region_to_region(&icx, lifetime, None); - let pred = ty::Binder(ty::OutlivesPredicate(ty, region)); + let pred = ty::Binder::bind(ty::OutlivesPredicate(ty, region)); predicates.push(ty::Predicate::TypeOutlives(pred)) } } @@ -1493,7 +1494,7 @@ pub fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let r1 = AstConv::ast_region_to_region(&icx, ®ion_pred.lifetime, None); for bound in ®ion_pred.bounds { let r2 = AstConv::ast_region_to_region(&icx, bound, None); - let pred = ty::Binder(ty::OutlivesPredicate(r1, r2)); + let pred = ty::Binder::bind(ty::OutlivesPredicate(r1, r2)); predicates.push(ty::Predicate::RegionOutlives(pred)) } } @@ -1627,7 +1628,7 @@ fn predicates_from_bound<'tcx>(astconv: &AstConv<'tcx, 'tcx>, } hir::RegionTyParamBound(ref lifetime) => { let region = astconv.ast_region_to_region(lifetime, None); - let pred = ty::Binder(ty::OutlivesPredicate(param_ty, region)); + let pred = ty::Binder::bind(ty::OutlivesPredicate(param_ty, region)); vec![ty::Predicate::TypeOutlives(pred)] } hir::TraitTyParamBound(_, hir::TraitBoundModifier::Maybe) => { @@ -1682,6 +1683,7 @@ fn is_foreign_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn from_target_feature( tcx: TyCtxt, + id: DefId, attr: &ast::Attribute, whitelist: &FxHashMap<String, Option<String>>, target_features: &mut Vec<Symbol>, @@ -1752,7 +1754,7 @@ fn from_target_feature( Some(name) => bug!("unknown target feature gate {}", name), None => true, }; - if !allowed { + if !allowed && id.is_local() { feature_gate::emit_feature_err( &tcx.sess.parse_sess, feature_gate.as_ref().unwrap(), @@ -1877,7 +1879,7 @@ fn trans_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> TransFnAt `unsafe` function"; tcx.sess.span_err(attr.span, msg); } - from_target_feature(tcx, attr, &whitelist, &mut trans_fn_attrs.target_features); + from_target_feature(tcx, id, attr, &whitelist, &mut trans_fn_attrs.target_features); } else if attr.check_name("linkage") { if let Some(val) = attr.value_str() { trans_fn_attrs.linkage = Some(linkage_by_name(tcx, id, &val.as_str())); diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index ae3b2b22ea1..e3f7ff5cb3f 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4526,23 +4526,23 @@ but the type of the numeric value or binding could not be identified. The error happens on numeric literals: ```compile_fail,E0689 -2.0.powi(2); +2.0.recip(); ``` and on numeric bindings without an identified concrete type: ```compile_fail,E0689 let x = 2.0; -x.powi(2); // same error as above +x.recip(); // same error as above ``` Because of this, you must give the numeric literal or binding a type: ``` -let _ = 2.0_f32.powi(2); +let _ = 2.0_f32.recip(); let x: f32 = 2.0; -let _ = x.powi(2); -let _ = (2.0 as f32).powi(2); +let _ = x.recip(); +let _ = (2.0 as f32).recip(); ``` "##, diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 4b66939963e..958960d3a36 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -71,6 +71,8 @@ This API is completely unstable and subject to change. #![allow(non_camel_case_types)] +#![cfg_attr(stage0, feature(dyn_trait))] + #![feature(box_patterns)] #![feature(box_syntax)] #![feature(crate_visibility_modifier)] @@ -81,7 +83,7 @@ This API is completely unstable and subject to change. #![feature(rustc_diagnostic_macros)] #![feature(slice_patterns)] #![feature(slice_sort_by_cached_key)] -#![feature(dyn_trait)] +#![feature(never_type)] #[macro_use] extern crate log; #[macro_use] extern crate syntax; @@ -93,6 +95,7 @@ extern crate rustc_platform_intrinsics as intrinsics; extern crate rustc_const_math; extern crate rustc_data_structures; extern crate rustc_errors as errors; +extern crate rustc_target; use rustc::hir; use rustc::lint; @@ -110,7 +113,7 @@ use session::{CompileIncomplete, config}; use util::common::time; use syntax::ast; -use syntax::abi::Abi; +use rustc_target::spec::abi::Abi; use syntax_pos::Span; use std::iter; @@ -211,7 +214,7 @@ fn check_main_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx.mk_nil() }; - let se_ty = tcx.mk_fn_ptr(ty::Binder( + let se_ty = tcx.mk_fn_ptr(ty::Binder::bind( tcx.mk_fn_sig( iter::empty(), expected_return_type, @@ -260,7 +263,7 @@ fn check_start_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, _ => () } - let se_ty = tcx.mk_fn_ptr(ty::Binder( + let se_ty = tcx.mk_fn_ptr(ty::Binder::bind( tcx.mk_fn_sig( [ tcx.types.isize, diff --git a/src/librustc_typeck/outlives/implicit_infer.rs b/src/librustc_typeck/outlives/implicit_infer.rs index ac53a6d4a3f..26fba71c812 100644 --- a/src/librustc_typeck/outlives/implicit_infer.rs +++ b/src/librustc_typeck/outlives/implicit_infer.rs @@ -23,7 +23,8 @@ use rustc::ty::{self, AdtKind, CratePredicatesMap, Region, RegionKind, ReprOptio ToPolyTraitRef, ToPredicate, Ty, TyCtxt}; use rustc::util::nodemap::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::Lrc; -use syntax::{abi, ast}; +use rustc_target::spec::abi; +use syntax::ast; use syntax_pos::{Span, DUMMY_SP}; /// Infer predicates for the items in the crate. @@ -258,7 +259,7 @@ fn check_explicit_predicates<'tcx>( // where OutlivesPredicate<type1, region1> is the predicate // we want to add. ty::Predicate::TypeOutlives(poly) => { - let predicate = poly.0.subst(tcx, substs); + let predicate = poly.skip_binder().subst(tcx, substs); insert_outlives_predicate( tcx, predicate.0.into(), @@ -271,7 +272,7 @@ fn check_explicit_predicates<'tcx>( // where OutlivesPredicate<region1, region2> is the predicate // we want to add. ty::Predicate::RegionOutlives(poly) => { - let predicate = poly.0.subst(tcx, substs); + let predicate = poly.skip_binder().subst(tcx, substs); insert_outlives_predicate( tcx, predicate.0.into(), diff --git a/src/librustc_typeck/outlives/mod.rs b/src/librustc_typeck/outlives/mod.rs index bad0c68a6fe..e5af4c60691 100644 --- a/src/librustc_typeck/outlives/mod.rs +++ b/src/librustc_typeck/outlives/mod.rs @@ -89,11 +89,11 @@ fn inferred_outlives_crate<'tcx>( let vec: Vec<ty::Predicate<'tcx>> = set.iter() .map( |ty::OutlivesPredicate(kind1, region2)| match kind1.unpack() { - UnpackedKind::Type(ty1) => ty::Predicate::TypeOutlives(ty::Binder( + UnpackedKind::Type(ty1) => ty::Predicate::TypeOutlives(ty::Binder::bind( ty::OutlivesPredicate(ty1, region2), )), UnpackedKind::Lifetime(region1) => ty::Predicate::RegionOutlives( - ty::Binder(ty::OutlivesPredicate(region1, region2)), + ty::Binder::bind(ty::OutlivesPredicate(region1, region2)), ), }, ) diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index a24e501aba9..b5e7effa61e 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -313,11 +313,13 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { if let Some(p) = data.principal() { let poly_trait_ref = p.with_self_ty(self.tcx(), self.tcx().types.err); - self.add_constraints_from_trait_ref(current, poly_trait_ref.0, variance); + self.add_constraints_from_trait_ref( + current, *poly_trait_ref.skip_binder(), variance); } for projection in data.projection_bounds() { - self.add_constraints_from_ty(current, projection.0.ty, self.invariant); + self.add_constraints_from_ty( + current, projection.skip_binder().ty, self.invariant); } } @@ -399,10 +401,10 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { sig: ty::PolyFnSig<'tcx>, variance: VarianceTermPtr<'a>) { let contra = self.contravariant(variance); - for &input in sig.0.inputs() { + for &input in sig.skip_binder().inputs() { self.add_constraints_from_ty(current, input, contra); } - self.add_constraints_from_ty(current, sig.0.output(), variance); + self.add_constraints_from_ty(current, sig.skip_binder().output(), variance); } /// Adds constraints appropriate for a region appearing in a diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 52d5dbe3f05..221fc4dab72 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -224,7 +224,7 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> { let name = if p.name == "" { hir::LifetimeName::Static } else { - hir::LifetimeName::Name(Symbol::intern(&p.name)) + hir::LifetimeName::Name(p.name.as_symbol()) }; hir::Lifetime { @@ -261,7 +261,7 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> { span: DUMMY_SP, def: Def::TyParam(param.def_id), segments: HirVec::from_vec(vec![ - hir::PathSegment::from_name(Symbol::intern(¶m.name)) + hir::PathSegment::from_name(param.name.as_symbol()) ]), }), )), @@ -286,7 +286,7 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> { substs: tcx.mk_substs_trait(ty, &[]), }; - let trait_pred = ty::Binder(trait_ref); + let trait_pred = ty::Binder::bind(trait_ref); let bail_out = tcx.infer_ctxt().enter(|infcx| { let mut selcx = SelectionContext::with_negative(&infcx, true); @@ -622,7 +622,7 @@ impl<'a, 'tcx, 'rcx> AutoTraitFinder<'a, 'tcx, 'rcx> { let mut already_visited = FxHashSet(); let mut predicates = VecDeque::new(); - predicates.push_back(ty::Binder(ty::TraitPredicate { + predicates.push_back(ty::Binder::bind(ty::TraitPredicate { trait_ref: ty::TraitRef { def_id: trait_did, substs: infcx.tcx.mk_substs_trait(ty, &[]), diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 090adc27ef0..23e0c2625ee 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -10,10 +10,7 @@ //! Support for inlining external documentation into the current AST. -use std::collections::BTreeMap; -use std::io; use std::iter::once; -use rustc_data_structures::sync::Lrc; use syntax::ast; use rustc::hir; @@ -289,10 +286,15 @@ pub fn build_impls(cx: &DocContext, did: DefId, auto_traits: bool) -> Vec<clean: lang_items.u128_impl(), lang_items.f32_impl(), lang_items.f64_impl(), + lang_items.f32_runtime_impl(), + lang_items.f64_runtime_impl(), lang_items.char_impl(), lang_items.str_impl(), lang_items.slice_impl(), lang_items.slice_u8_impl(), + lang_items.str_alloc_impl(), + lang_items.slice_alloc_impl(), + lang_items.slice_u8_alloc_impl(), lang_items.const_ptr_impl(), lang_items.mut_ptr_impl(), ]; @@ -408,27 +410,8 @@ fn build_module(cx: &DocContext, did: DefId) -> clean::Module { } } -struct InlinedConst { - nested_bodies: Lrc<BTreeMap<hir::BodyId, hir::Body>> -} - -impl hir::print::PpAnn for InlinedConst { - fn nested(&self, state: &mut hir::print::State, nested: hir::print::Nested) - -> io::Result<()> { - if let hir::print::Nested::Body(body) = nested { - state.print_expr(&self.nested_bodies[&body].value) - } else { - Ok(()) - } - } -} - pub fn print_inlined_const(cx: &DocContext, did: DefId) -> String { - let body = cx.tcx.extern_const_body(did).body; - let inlined = InlinedConst { - nested_bodies: cx.tcx.item_body_nested_bodies(did).nested_bodies - }; - hir::print::to_string(&inlined, |s| s.print_expr(&body.value)) + cx.tcx.rendered_const(did) } fn build_const(cx: &DocContext, did: DefId) -> clean::Constant { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 443caa7618d..6623d5ab3c2 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -20,7 +20,7 @@ pub use self::FunctionRetTy::*; pub use self::Visibility::*; use syntax; -use syntax::abi::Abi; +use rustc_target::spec::abi::Abi; use syntax::ast::{self, AttrStyle, Ident}; use syntax::attr; use syntax::codemap::{dummy_spanned, Spanned}; @@ -120,7 +120,7 @@ impl<T: Clean<U>, U> Clean<Option<U>> for Option<T> { impl<T, U> Clean<U> for ty::Binder<T> where T: Clean<U> { fn clean(&self, cx: &DocContext) -> U { - self.0.clean(cx) + self.skip_binder().clean(cx) } } @@ -1367,7 +1367,7 @@ impl TyParamBound { fn maybe_sized(cx: &DocContext) -> TyParamBound { let did = cx.tcx.require_lang_item(lang_items::SizedTraitLangItem); let empty = cx.tcx.intern_substs(&[]); - let path = external_path(cx, &cx.tcx.item_name(did), + let path = external_path(cx, &cx.tcx.item_name(did).as_str(), Some(did), false, vec![], empty); inline::record_extern_fqn(cx, did, TypeKind::Trait); TraitBound(PolyTrait { @@ -1474,7 +1474,7 @@ impl<'a, 'tcx> Clean<TyParamBound> for (&'a ty::TraitRef<'tcx>, Vec<TypeBinding> fn clean(&self, cx: &DocContext) -> TyParamBound { let (trait_ref, ref bounds) = *self; inline::record_extern_fqn(cx, trait_ref.def_id, TypeKind::Trait); - let path = external_path(cx, &cx.tcx.item_name(trait_ref.def_id), + let path = external_path(cx, &cx.tcx.item_name(trait_ref.def_id).as_str(), Some(trait_ref.def_id), true, bounds.clone(), trait_ref.substs); debug!("ty::TraitRef\n subst: {:?}\n", trait_ref.substs); @@ -2801,7 +2801,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> { AdtKind::Enum => TypeKind::Enum, }; inline::record_extern_fqn(cx, did, kind); - let path = external_path(cx, &cx.tcx.item_name(did), + let path = external_path(cx, &cx.tcx.item_name(did).as_str(), None, false, vec![], substs); ResolvedPath { path, @@ -2812,7 +2812,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> { } ty::TyForeign(did) => { inline::record_extern_fqn(cx, did, TypeKind::Foreign); - let path = external_path(cx, &cx.tcx.item_name(did), + let path = external_path(cx, &cx.tcx.item_name(did).as_str(), None, false, vec![], Substs::empty()); ResolvedPath { path: path, @@ -2830,7 +2830,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> { reg.clean(cx).map(|b| typarams.push(RegionBound(b))); for did in obj.auto_traits() { let empty = cx.tcx.intern_substs(&[]); - let path = external_path(cx, &cx.tcx.item_name(did), + let path = external_path(cx, &cx.tcx.item_name(did).as_str(), Some(did), false, vec![], empty); inline::record_extern_fqn(cx, did, TypeKind::Trait); let bound = TraitBound(PolyTrait { @@ -2846,15 +2846,15 @@ impl<'tcx> Clean<Type> for Ty<'tcx> { } let mut bindings = vec![]; - for ty::Binder(ref pb) in obj.projection_bounds() { + for pb in obj.projection_bounds() { bindings.push(TypeBinding { - name: cx.tcx.associated_item(pb.item_def_id).name.clean(cx), - ty: pb.ty.clean(cx) + name: cx.tcx.associated_item(pb.item_def_id()).name.clean(cx), + ty: pb.skip_binder().ty.clean(cx) }); } - let path = external_path(cx, &cx.tcx.item_name(did), Some(did), - false, bindings, principal.0.substs); + let path = external_path(cx, &cx.tcx.item_name(did).as_str(), Some(did), + false, bindings, principal.skip_binder().substs); ResolvedPath { path, typarams: Some(typarams), diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs index 0eb4f9ba7e5..b7767606a6a 100644 --- a/src/librustdoc/clean/simplify.rs +++ b/src/librustdoc/clean/simplify.rs @@ -154,7 +154,7 @@ fn trait_is_same_or_supertrait(cx: &DocContext, child: DefId, let predicates = cx.tcx.super_predicates_of(child).predicates; predicates.iter().filter_map(|pred| { if let ty::Predicate::Trait(ref pred) = *pred { - if pred.0.trait_ref.self_ty().is_self() { + if pred.skip_binder().trait_ref.self_ty().is_self() { Some(pred.def_id()) } else { None diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 97c4e859327..d423203b996 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -23,7 +23,7 @@ use rustc::util::nodemap::{FxHashMap, FxHashSet}; use rustc_resolve as resolve; use rustc_metadata::creader::CrateLoader; use rustc_metadata::cstore::CStore; -use rustc_back::target::TargetTriple; +use rustc_target::spec::TargetTriple; use syntax::ast::NodeId; use syntax::codemap; @@ -35,7 +35,7 @@ use errors::emitter::{Emitter, EmitterWriter}; use std::cell::{RefCell, Cell}; use std::mem; -use rustc_data_structures::sync::Lrc; +use rustc_data_structures::sync::{self, Lrc}; use std::rc::Rc; use std::path::PathBuf; @@ -155,15 +155,15 @@ pub fn run_core(search_paths: SearchPaths, actually_rustdoc: true, debugging_opts: config::DebuggingOptions { force_unstable_if_unmarked, - edition, ..config::basic_debugging_options() }, error_format, + edition, ..config::basic_options().clone() }; let codemap = Lrc::new(codemap::CodeMap::new(sessopts.file_path_mapping())); - let emitter: Box<dyn Emitter> = match error_format { + let emitter: Box<dyn Emitter + sync::Send> = match error_format { ErrorOutputType::HumanReadable(color_config) => Box::new( EmitterWriter::stderr( color_config, diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index 413e5623118..f85a70a6d40 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -13,7 +13,7 @@ pub use self::StructType::*; pub use self::TypeBound::*; -use syntax::abi; +use rustc_target::spec::abi; use syntax::ast; use syntax::ast::{Name, NodeId}; use syntax::attr; diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 0a7e19fc643..a9a4c511374 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -19,7 +19,7 @@ use std::fmt; use std::iter::repeat; use rustc::hir::def_id::DefId; -use syntax::abi::Abi; +use rustc_target::spec::abi::Abi; use rustc::hir; use clean::{self, PrimitiveType}; diff --git a/src/librustdoc/html/item_type.rs b/src/librustdoc/html/item_type.rs index e9c6488c49c..537828de2c7 100644 --- a/src/librustdoc/html/item_type.rs +++ b/src/librustdoc/html/item_type.rs @@ -19,7 +19,7 @@ use clean; /// discriminants. JavaScript then is used to decode them into the original value. /// Consequently, every change to this type should be synchronized to /// the `itemTypes` mapping table in `static/main.js`. -#[derive(Copy, PartialEq, Clone)] +#[derive(Copy, PartialEq, Clone, Debug)] pub enum ItemType { Module = 0, ExternCrate = 1, diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index 583c9f2b671..5e93b20ea17 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -85,6 +85,9 @@ pub fn render<T: fmt::Display, S: fmt::Display>( autocomplete=\"off\" \ placeholder=\"Click or press ‘S’ to search, ‘?’ for more options…\" \ type=\"search\">\ + <a id=\"settings-menu\" href=\"{root_path}settings.html\">\ + <img src=\"{root_path}wheel{suffix}.svg\" width=\"18\" alt=\"Change settings\">\ + </a>\ </div>\ </form>\ </nav>\ @@ -143,6 +146,7 @@ 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}main{suffix}.js\"></script>\ <script defer src=\"{root_path}search-index.js\"></script>\ </body>\ @@ -181,9 +185,10 @@ pub fn render<T: fmt::Display, S: fmt::Display>( themes = themes.iter() .filter_map(|t| t.file_stem()) .filter_map(|t| t.to_str()) - .map(|t| format!(r#"<link rel="stylesheet" type="text/css" href="{}{}">"#, + .map(|t| format!(r#"<link rel="stylesheet" type="text/css" href="{}{}{}.css">"#, page.root_path, - t.replace(".css", &format!("{}.css", page.resource_suffix)))) + t, + page.resource_suffix)) .collect::<String>(), suffix=page.resource_suffix, ) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 651319743aa..4e9781cc560 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -54,7 +54,7 @@ use std::sync::Arc; use externalfiles::ExternalHtml; use serialize::json::{ToJson, Json, as_json}; -use syntax::{abi, ast}; +use syntax::ast; use syntax::codemap::FileName; use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId}; use rustc::middle::privacy::AccessLevels; @@ -62,6 +62,7 @@ use rustc::middle::stability; use rustc::hir; use rustc::util::nodemap::{FxHashMap, FxHashSet}; use rustc_data_structures::flock; +use rustc_target::spec::abi; use clean::{self, AttributesExt, GetDefId, SelfTy, Mutability}; use doctree; @@ -329,6 +330,10 @@ pub struct Cache { // yet when its implementation methods are being indexed. Caches such methods // and their parent id here and indexes them at the end of crate parsing. orphan_impl_items: Vec<(DefId, clean::Item)>, + + /// Aliases added through `#[doc(alias = "...")]`. Since a few items can have the same alias, + /// we need the alias element to have an array of items. + aliases: FxHashMap<String, Vec<IndexItem>>, } /// Temporary storage for data obtained during `RustdocVisitor::clean()`. @@ -369,6 +374,7 @@ struct Sidebar<'a> { cx: &'a Context, item: &'a clean::Item, } /// Struct representing one entry in the JS search index. These are all emitted /// by hand to a large JS file at the end of cache-creation. +#[derive(Debug)] struct IndexItem { ty: ItemType, name: String, @@ -396,6 +402,7 @@ impl ToJson for IndexItem { } /// A type used for the search index. +#[derive(Debug)] struct Type { name: Option<String>, generics: Option<Vec<String>>, @@ -418,9 +425,10 @@ impl ToJson for Type { } /// Full type of functions/methods in the search index. +#[derive(Debug)] struct IndexItemFunctionType { inputs: Vec<Type>, - output: Option<Type> + output: Option<Type>, } impl ToJson for IndexItemFunctionType { @@ -609,6 +617,7 @@ pub fn run(mut krate: clean::Crate, owned_box_did, masked_crates: mem::replace(&mut krate.masked_crates, FxHashSet()), typarams: external_typarams, + aliases: FxHashMap(), }; // Cache where all our extern crates are located @@ -742,6 +751,8 @@ fn write_shared(cx: &Context, write(cx.dst.join(&format!("rustdoc{}.css", cx.shared.resource_suffix)), include_bytes!("static/rustdoc.css"))?; + write(cx.dst.join(&format!("settings{}.css", cx.shared.resource_suffix)), + include_bytes!("static/settings.css"))?; // To avoid "light.css" to be overwritten, we'll first run over the received themes and only // then we'll run over the "official" styles. @@ -761,6 +772,8 @@ fn write_shared(cx: &Context, write(cx.dst.join(&format!("brush{}.svg", cx.shared.resource_suffix)), include_bytes!("static/brush.svg"))?; + write(cx.dst.join(&format!("wheel{}.svg", cx.shared.resource_suffix)), + include_bytes!("static/wheel.svg"))?; write(cx.dst.join(&format!("light{}.css", cx.shared.resource_suffix)), include_bytes!("static/themes/light.css"))?; themes.insert("light".to_owned()); @@ -794,8 +807,7 @@ themePicker.onclick = function() {{ switchTheme(currentTheme, mainTheme, item); }}; themes.appendChild(but); -}}); -"#, +}});"#, themes.iter() .map(|s| format!("\"{}\"", s)) .collect::<Vec<String>>() @@ -804,6 +816,8 @@ themePicker.onclick = function() {{ write(cx.dst.join(&format!("main{}.js", cx.shared.resource_suffix)), include_bytes!("static/main.js"))?; + write(cx.dst.join(&format!("settings{}.js", cx.shared.resource_suffix)), + include_bytes!("static/settings.js"))?; { let mut data = format!("var resourcesSuffix = \"{}\";\n", @@ -847,8 +861,7 @@ themePicker.onclick = function() {{ write(cx.dst.join("COPYRIGHT.txt"), include_bytes!("static/COPYRIGHT.txt"))?; - fn collect(path: &Path, krate: &str, - key: &str) -> io::Result<Vec<String>> { + fn collect(path: &Path, krate: &str, key: &str) -> io::Result<Vec<String>> { let mut ret = Vec::new(); if path.exists() { for line in BufReader::new(File::open(path)?).lines() { @@ -865,6 +878,40 @@ themePicker.onclick = function() {{ Ok(ret) } + fn show_item(item: &IndexItem, krate: &str) -> String { + format!("{{'crate':'{}','ty':{},'name':'{}','path':'{}'{}}}", + krate, item.ty as usize, item.name, item.path, + if let Some(p) = item.parent_idx { + format!(",'parent':{}", p) + } else { + String::new() + }) + } + + let dst = cx.dst.join("aliases.js"); + { + let mut all_aliases = try_err!(collect(&dst, &krate.name, "ALIASES"), &dst); + let mut w = try_err!(File::create(&dst), &dst); + let mut output = String::with_capacity(100); + for (alias, items) in &cache.aliases { + if items.is_empty() { + continue + } + output.push_str(&format!("\"{}\":[{}],", + alias, + items.iter() + .map(|v| show_item(v, &krate.name)) + .collect::<Vec<_>>() + .join(","))); + } + all_aliases.push(format!("ALIASES['{}'] = {{{}}};", krate.name, output)); + all_aliases.sort(); + try_err!(writeln!(&mut w, "var ALIASES = {{}};"), &dst); + for aliases in &all_aliases { + try_err!(writeln!(&mut w, "{}", aliases), &dst); + } + } + // Update the search index let dst = cx.dst.join("search-index.js"); let mut all_indexes = try_err!(collect(&dst, &krate.name, "searchIndex"), &dst); @@ -1251,13 +1298,13 @@ impl DocFolder for Cache { // `public_items` map, so we can skip inserting into the // paths map if there was already an entry present and we're // not a public item. - if - !self.paths.contains_key(&item.def_id) || - self.access_levels.is_public(item.def_id) + if !self.paths.contains_key(&item.def_id) || + self.access_levels.is_public(item.def_id) { self.paths.insert(item.def_id, (self.stack.clone(), item.type_())); } + self.add_aliases(&item); } // Link variants to their parent enum because pages aren't emitted // for each variant. @@ -1268,6 +1315,7 @@ impl DocFolder for Cache { } clean::PrimitiveItem(..) if item.visibility.is_some() => { + self.add_aliases(&item); self.paths.insert(item.def_id, (self.stack.clone(), item.type_())); } @@ -1372,6 +1420,36 @@ impl<'a> Cache { } } } + + fn add_aliases(&mut self, item: &clean::Item) { + if item.def_id.index == CRATE_DEF_INDEX { + return + } + if let Some(ref item_name) = item.name { + let path = self.paths.get(&item.def_id) + .map(|p| p.0.join("::").to_string()) + .unwrap_or("std".to_owned()); + for alias in item.attrs.lists("doc") + .filter(|a| a.check_name("alias")) + .filter_map(|a| a.value_str() + .map(|s| s.to_string().replace("\"", ""))) + .filter(|v| !v.is_empty()) + .collect::<FxHashSet<_>>() + .into_iter() { + self.aliases.entry(alias) + .or_insert(Vec::with_capacity(1)) + .push(IndexItem { + ty: item.type_(), + name: item_name.to_string(), + path: path.clone(), + desc: String::new(), + parent: None, + parent_idx: None, + search_type: get_index_search_type(&item), + }); + } + } + } } #[derive(Debug, Eq, PartialEq, Hash)] @@ -1503,6 +1581,53 @@ impl fmt::Display for AllTypes { } } +#[derive(Debug)] +struct Settings<'a> { + // (id, explanation, default value) + settings: Vec<(&'static str, &'static str, bool)>, + root_path: &'a str, + suffix: &'a str, +} + +impl<'a> Settings<'a> { + pub fn new(root_path: &'a str, suffix: &'a str) -> Settings<'a> { + Settings { + settings: vec![ + ("item-declarations", "Auto-hide item declarations.", true), + ("item-attributes", "Auto-hide item attributes.", true), + ("go-to-only-result", "Directly go to item in search if there is only one result", + false), + ], + root_path, + suffix, + } + } +} + +impl<'a> fmt::Display for Settings<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, +"<h1 class='fqn'>\ + <span class='in-band'>Rustdoc settings</span>\ +</h1>\ +<div class='settings'>{}</div>\ +<script src='{}settings{}.js'></script>", + self.settings.iter() + .map(|(id, text, enabled)| { + format!("<div class='setting-line'>\ + <label class='toggle'>\ + <input type='checkbox' id='{}' {}>\ + <span class='slider'></span>\ + </label>\ + <div>{}</div>\ + </div>", id, if *enabled { " checked" } else { "" }, text) + }) + .collect::<String>(), + self.root_path, + self.suffix) + } +} + impl Context { /// String representation of how to get back to the root path of the 'doc/' /// folder in terms of a relative URL. @@ -1546,6 +1671,8 @@ impl Context { }; let final_file = self.dst.join(&krate.name) .join("all.html"); + let settings_file = self.dst.join("settings.html"); + let crate_name = krate.name.clone(); item.name = Some(krate.name); @@ -1567,7 +1694,7 @@ impl Context { if !root_path.ends_with('/') { root_path.push('/'); } - let page = layout::Page { + let mut page = layout::Page { title: "List of all items in this crate", css_class: "mod", root_path: "../", @@ -1590,6 +1717,27 @@ impl Context { self.shared.css_file_extension.is_some(), &self.shared.themes), &final_file); + + // Generating settings page. + let settings = Settings::new("./", &self.shared.resource_suffix); + page.title = "Rustdoc settings"; + page.description = "Settings of Rustdoc"; + page.root_path = "./"; + + let mut w = BufWriter::new(try_err!(File::create(&settings_file), &settings_file)); + let mut themes = self.shared.themes.clone(); + let sidebar = "<p class='location'>Settings</p><div class='sidebar-elems'></div>"; + themes.push(PathBuf::from("settings.css")); + let mut layout = self.shared.layout.clone(); + layout.krate = String::new(); + layout.logo = String::new(); + layout.favicon = String::new(); + try_err!(layout::render(&mut w, &layout, + &page, &sidebar, &settings, + self.shared.css_file_extension.is_some(), + &themes), + &settings_file); + Ok(()) } diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 2546a9410a9..bcad2eb19f5 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -40,6 +40,8 @@ "union", "foreigntype"]; + var search_input = document.getElementsByClassName('search-input')[0]; + // On the search screen, so you remain on the last tab you opened. // // 0 for "In Names" @@ -77,19 +79,13 @@ return false; } var end = start + className.length; - if (end < elemClass.length && elemClass[end] !== ' ') { - return false; - } - return true; + return !(end < elemClass.length && elemClass[end] !== ' '); } if (start > 0 && elemClass[start - 1] !== ' ') { return false; } var end = start + className.length; - if (end < elemClass.length && elemClass[end] !== ' ') { - return false; - } - return true; + return !(end < elemClass.length && elemClass[end] !== ' '); } return false; } @@ -320,7 +316,7 @@ } else if (ev.target.tagName === 'SPAN' && hasClass(ev.target.parentNode, 'line-numbers')) { var prev_id = 0; - var set_fragment = function (name) { + var set_fragment = function(name) { if (browserSupportsHistoryApi()) { history.replaceState(null, null, '#' + name); window.hashchange(); @@ -417,8 +413,8 @@ // but only if the input bar is empty. This avoid the obnoxious issue // where you start trying to do a search, and the index loads, and // suddenly your search is gone! - if (document.getElementsByClassName("search-input")[0].value === "") { - document.getElementsByClassName("search-input")[0].value = params.search || ''; + if (search_input.value === "") { + search_input.value = params.search || ''; } /** @@ -835,7 +831,7 @@ query.search = val; // searching by type } else if (val.search("->") > -1) { - var trimmer = function (s) { return s.trim(); }; + var trimmer = function(s) { return s.trim(); }; var parts = val.split("->").map(trimmer); var input = parts[0]; // sort inputs so that order does not matter @@ -1012,11 +1008,22 @@ } } - return { + var ret = { 'in_args': sortResults(results_in_args, true), 'returned': sortResults(results_returned, true), 'others': sortResults(results), }; + if (ALIASES && ALIASES[window.currentCrate] && + ALIASES[window.currentCrate][query.raw]) { + var aliases = ALIASES[window.currentCrate][query.raw]; + for (var i = 0; i < aliases.length; ++i) { + ret['others'].unshift(aliases[i]); + if (ret['others'].length > MAX_RESULTS) { + ret['others'].pop(); + } + } + } + return ret; } /** @@ -1114,7 +1121,6 @@ }); }); - var search_input = document.getElementsByClassName('search-input')[0]; search_input.onkeydown = function(e) { // "actives" references the currently highlighted item in each search tab. // Each array in "actives" represents a tab. @@ -1165,7 +1171,7 @@ // Does nothing, it's just to avoid losing "focus" on the highlighted element. } else if (e.which === 27) { // escape removeClass(actives[currentTab][0], 'highlighted'); - document.getElementsByClassName('search-input')[0].value = ''; + search_input.value = ''; defocusSearchBar(); } else if (actives[currentTab].length > 0) { removeClass(actives[currentTab][0], 'highlighted'); @@ -1183,6 +1189,44 @@ return '<span>' + path.replace(/::/g, '::</span><span>'); } + function buildHrefAndPath(item) { + var displayPath; + var href; + var type = itemTypes[item.ty]; + var name = item.name; + + if (type === 'mod') { + displayPath = item.path + '::'; + href = rootPath + item.path.replace(/::/g, '/') + '/' + + name + '/index.html'; + } else if (type === "primitive") { + displayPath = ""; + href = rootPath + item.path.replace(/::/g, '/') + + '/' + type + '.' + name + '.html'; + } else if (type === "externcrate") { + displayPath = ""; + href = rootPath + name + '/index.html'; + } else if (item.parent !== undefined) { + var myparent = item.parent; + var anchor = '#' + type + '.' + name; + var parentType = itemTypes[myparent.ty]; + if (parentType === "primitive") { + displayPath = myparent.name + '::'; + } else { + displayPath = item.path + '::' + myparent.name + '::'; + } + href = rootPath + item.path.replace(/::/g, '/') + + '/' + parentType + + '.' + myparent.name + + '.html' + anchor; + } else { + displayPath = item.path + '::'; + href = rootPath + item.path.replace(/::/g, '/') + + '/' + type + '.' + name + '.html'; + } + return [displayPath, href]; + } + function addTab(array, query, display) { var extraStyle = ''; if (display === false) { @@ -1197,43 +1241,18 @@ array.forEach(function(item) { var name, type, href, displayPath; - if (shown.indexOf(item) !== -1) { + var id_ty = item.ty + item.path + item.name; + if (shown.indexOf(id_ty) !== -1) { return; } - shown.push(item); + shown.push(id_ty); name = item.name; type = itemTypes[item.ty]; - if (type === 'mod') { - displayPath = item.path + '::'; - href = rootPath + item.path.replace(/::/g, '/') + '/' + - name + '/index.html'; - } else if (type === "primitive") { - displayPath = ""; - href = rootPath + item.path.replace(/::/g, '/') + - '/' + type + '.' + name + '.html'; - } else if (type === "externcrate") { - displayPath = ""; - href = rootPath + name + '/index.html'; - } else if (item.parent !== undefined) { - var myparent = item.parent; - var anchor = '#' + type + '.' + name; - var parentType = itemTypes[myparent.ty]; - if (parentType === "primitive") { - displayPath = myparent.name + '::'; - } else { - displayPath = item.path + '::' + myparent.name + '::'; - } - href = rootPath + item.path.replace(/::/g, '/') + - '/' + parentType + - '.' + myparent.name + - '.html' + anchor; - } else { - displayPath = item.path + '::'; - href = rootPath + item.path.replace(/::/g, '/') + - '/' + type + '.' + name + '.html'; - } + var res = buildHrefAndPath(item); + var href = res[1]; + var displayPath = res[0]; output += '<tr class="' + type + ' result"><td>' + '<a href="' + href + '">' + @@ -1262,7 +1281,17 @@ } function showResults(results) { - var output, query = getQuery(document.getElementsByClassName('search-input')[0].value); + if (results['others'].length === 1 && + getCurrentValue('rustdoc-go-to-only-result') === "true") { + var elem = document.createElement('a'); + var res = buildHrefAndPath(results['others'][0]); + elem.href = res[1]; + elem.style.display = 'none'; + // For firefox, we need the element to be in the DOM so it can be clicked. + document.body.appendChild(elem); + elem.click(); + } + var output, query = getQuery(search_input.value); currentResults = query.id; output = '<h1>Results for ' + escape(query.query) + @@ -1369,13 +1398,16 @@ function search(e) { var params = getQueryStringParams(); - var query = getQuery(document.getElementsByClassName('search-input')[0].value); + var query = getQuery(search_input.value.trim()); if (e) { e.preventDefault(); } - if (!query.query || query.id === currentResults) { + if (query.query.length === 0 || query.id === currentResults) { + if (query.query.length > 0) { + putBackSearch(search_input); + } return; } @@ -1458,9 +1490,6 @@ function startSearch() { var searchTimeout; var callback = function() { - var search_input = document.getElementsByClassName('search-input'); - if (search_input.length < 1) { return; } - search_input = search_input[0]; clearTimeout(searchTimeout); if (search_input.value.length === 0) { if (browserSupportsHistoryApi()) { @@ -1478,7 +1507,6 @@ searchTimeout = setTimeout(search, 500); } }; - var search_input = document.getElementsByClassName("search-input")[0]; search_input.onkeyup = callback; search_input.oninput = callback; document.getElementsByClassName("search-form")[0].onsubmit = function(e) { @@ -1528,9 +1556,9 @@ // nothing there, which lets you really go back to a // previous state with nothing in the bar. if (params.search) { - document.getElementsByClassName('search-input')[0].value = params.search; + search_input.value = params.search; } else { - document.getElementsByClassName('search-input')[0].value = ''; + search_input.value = ''; } // Some browsers fire 'onpopstate' for every page load // (Chrome), while others fire the event only when actually @@ -1547,7 +1575,7 @@ startSearch(); // Draw a convenient sidebar of known crates if we have a listing - if (rootPath === '../') { + if (rootPath === '../' || rootPath === "./") { var sidebar = document.getElementsByClassName('sidebar-elems')[0]; if (sidebar) { var div = document.createElement('div'); @@ -1566,11 +1594,11 @@ crates.sort(); for (var i = 0; i < crates.length; ++i) { var klass = 'crate'; - if (crates[i] === window.currentCrate) { + if (rootPath !== "./" && crates[i] === window.currentCrate) { klass += ' current'; } var link = document.createElement('a'); - link.href = '../' + crates[i] + '/index.html'; + link.href = rootPath + crates[i] + '/index.html'; link.title = rawSearchIndex[crates[i]].doc; link.className = klass; link.textContent = crates[i]; @@ -1716,6 +1744,9 @@ function toggleAllDocs(pageId) { var toggle = document.getElementById("toggle-all-docs"); + if (!toggle) { + return; + } if (hasClass(toggle, "will-expand")) { updateLocalStorage("rustdoc-collapse", "false"); removeClass(toggle, "will-expand"); @@ -1940,28 +1971,14 @@ return wrapper; } - onEach(document.getElementById('main').getElementsByClassName('docblock'), function(e) { - if (e.parentNode.id === "main") { - var otherMessage; - if (hasClass(e, "type-decl")) { - otherMessage = ' Show type declaration'; - } - e.parentNode.insertBefore(createToggle(otherMessage), e); - if (otherMessage) { - collapseDocs(e.previousSibling.childNodes[0], "toggle"); - } - } - }); - onEach(document.getElementsByClassName('docblock'), function(e) { if (hasClass(e, 'autohide')) { var wrap = e.previousElementSibling; if (wrap && hasClass(wrap, 'toggle-wrapper')) { var toggle = wrap.childNodes[0]; + var extra = false; if (e.childNodes[0].tagName === 'H3') { - onEach(toggle.getElementsByClassName('toggle-label'), function(i_e) { - i_e.innerHTML = " Show " + e.childNodes[0].innerHTML; - }); + extra = true; } e.style.display = 'none'; addClass(wrap, 'collapsed'); @@ -1970,10 +1987,23 @@ }); onEach(toggle.getElementsByClassName('toggle-label'), function(e) { e.style.display = 'inline-block'; + if (extra === true) { + i_e.innerHTML = " Show " + e.childNodes[0].innerHTML; + } }); } } - }) + if (e.parentNode.id === "main") { + var otherMessage; + if (hasClass(e, "type-decl")) { + otherMessage = ' Show type declaration'; + } + e.parentNode.insertBefore(createToggle(otherMessage), e); + if (otherMessage && getCurrentValue('rustdoc-item-declarations') !== "false") { + collapseDocs(e.previousSibling.childNodes[0], "toggle"); + } + } + }); autoCollapseAllImpls(getPageId()); @@ -2017,7 +2047,9 @@ onEach(document.getElementById('main').getElementsByTagName('pre'), function(e) { onEach(e.getElementsByClassName('attributes'), function(i_e) { i_e.parentNode.insertBefore(createToggleWrapper(), i_e); - collapseDocs(i_e.previousSibling.childNodes[0], "toggle"); + if (getCurrentValue("rustdoc-item-attributes") !== "false") { + collapseDocs(i_e.previousSibling.childNodes[0], "toggle"); + } }); }); @@ -2064,19 +2096,21 @@ }; }); - var search_input = document.getElementsByClassName("search-input")[0]; + function putBackSearch(search_input) { + if (search_input.value !== "") { + addClass(document.getElementById("main"), "hidden"); + removeClass(document.getElementById("search"), "hidden"); + if (browserSupportsHistoryApi()) { + history.replaceState(search_input.value, + "", + "?search=" + encodeURIComponent(search_input.value)); + } + } + } if (search_input) { search_input.onfocus = function() { - if (search_input.value !== "") { - addClass(document.getElementById("main"), "hidden"); - removeClass(document.getElementById("search"), "hidden"); - if (browserSupportsHistoryApi()) { - history.replaceState(search_input.value, - "", - "?search=" + encodeURIComponent(search_input.value)); - } - } + putBackSearch(this); }; } diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 4c6c8dcfdda..d6b3ab26af8 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -548,8 +548,16 @@ a { .block a.current.crate { font-weight: 500; } +.search-container { + position: relative; +} +.search-container > .top-button { + position: absolute; + right: 0; + top: 10px; +} .search-input { - width: 100%; + width: calc(100% - 34px); /* Override Normalize.css: we have margins and do not want to overflow - the `moz` attribute is necessary until Firefox 29, too early to drop at this point */ @@ -1224,7 +1232,14 @@ kbd { outline: none; } -#theme-picker { +#settings-menu { + position: absolute; + right: 0; + top: 10px; + outline: none; +} + +#theme-picker, #settings-menu { padding: 4px; width: 27px; height: 29px; diff --git a/src/librustdoc/html/static/settings.css b/src/librustdoc/html/static/settings.css new file mode 100644 index 00000000000..34835f3f22d --- /dev/null +++ b/src/librustdoc/html/static/settings.css @@ -0,0 +1,73 @@ +/** + * Copyright 2018 The Rust Project Developers. See the COPYRIGHT + * file at the top-level directory of this distribution and at + * http://rust-lang.org/COPYRIGHT. + * + * Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or + * http://www.apache.org/licenses/LICENSE-2.0> or the MIT license + * <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your + * option. This file may not be copied, modified, or distributed + * except according to those terms. + */ + +.setting-line { + padding: 5px; +} + +.setting-line > div { + max-width: calc(100% - 74px); + display: inline-block; + vertical-align: top; + font-size: 17px; + padding-top: 2px; +} + +.toggle { + position: relative; + display: inline-block; + width: 45px; + height: 27px; + margin-right: 20px; +} + +.toggle input { + display: none; +} + +.slider { + position: absolute; + cursor: pointer; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: #ccc; + -webkit-transition: .3s; + transition: .3s; +} + +.slider:before { + position: absolute; + content: ""; + height: 19px; + width: 19px; + left: 4px; + bottom: 4px; + background-color: white; + -webkit-transition: .3s; + transition: .3s; +} + +input:checked + .slider { + background-color: #2196F3; +} + +input:focus + .slider { + box-shadow: 0 0 1px #2196F3; +} + +input:checked + .slider:before { + -webkit-transform: translateX(19px); + -ms-transform: translateX(19px); + transform: translateX(19px); +} \ No newline at end of file diff --git a/src/librustdoc/html/static/settings.js b/src/librustdoc/html/static/settings.js new file mode 100644 index 00000000000..cc7c60082fb --- /dev/null +++ b/src/librustdoc/html/static/settings.js @@ -0,0 +1,41 @@ +/*! + * Copyright 2018 The Rust Project Developers. See the COPYRIGHT + * file at the top-level directory of this distribution and at + * http://rust-lang.org/COPYRIGHT. + * + * Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or + * http://www.apache.org/licenses/LICENSE-2.0> or the MIT license + * <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your + * option. This file may not be copied, modified, or distributed + * except according to those terms. + */ + +(function () { + function changeSetting(settingName, isEnabled) { + updateLocalStorage('rustdoc-' + settingName, isEnabled); + } + + function getSettingValue(settingName) { + return getCurrentValue('rustdoc-' + settingName); + } + + function setEvents() { + var elems = document.getElementsByClassName("slider"); + if (!elems || elems.length === 0) { + return; + } + for (var i = 0; i < elems.length; ++i) { + var toggle = elems[i].previousElementSibling; + var settingId = toggle.id; + var settingValue = getSettingValue(settingId); + if (settingValue !== null) { + toggle.checked = settingValue === "true"; + } + toggle.onchange = function() { + changeSetting(this.id, this.checked); + }; + } + } + + setEvents(); +})(); diff --git a/src/librustdoc/html/static/themes/dark.css b/src/librustdoc/html/static/themes/dark.css index 93971a205bf..da4be7db5aa 100644 --- a/src/librustdoc/html/static/themes/dark.css +++ b/src/librustdoc/html/static/themes/dark.css @@ -362,12 +362,13 @@ kbd { box-shadow-color: #c6cbd1; } -#theme-picker { +#theme-picker, #settings-menu { border-color: #e0e0e0; background: #f0f0f0; } -#theme-picker:hover, #theme-picker:focus { +#theme-picker:hover, #theme-picker:focus, +#settings-menu:hover, #settings-menu:focus { border-color: #ffb900; } diff --git a/src/librustdoc/html/static/themes/light.css b/src/librustdoc/html/static/themes/light.css index e13818b4bd2..12af01d2e24 100644 --- a/src/librustdoc/html/static/themes/light.css +++ b/src/librustdoc/html/static/themes/light.css @@ -356,12 +356,13 @@ kbd { box-shadow-color: #c6cbd1; } -#theme-picker { +#theme-picker, #settings-menu { border-color: #e0e0e0; background-color: #fff; } -#theme-picker:hover, #theme-picker:focus { +#theme-picker:hover, #theme-picker:focus, +#settings-menu:hover, #settings-menu:focus { border-color: #717171; } diff --git a/src/librustdoc/html/static/wheel.svg b/src/librustdoc/html/static/wheel.svg new file mode 100644 index 00000000000..44381a401a8 --- /dev/null +++ b/src/librustdoc/html/static/wheel.svg @@ -0,0 +1 @@ +<?xml version="1.0" ?><!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'><svg enable-background="new 0 0 27.434 29.5" height="29.5px" id="Capa_1" version="1.1" viewBox="0 0 27.434 29.5" width="27.434px" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><g><path d="M27.315,18.389c-0.165-0.604-0.509-1.113-0.981-1.459c-0.042-0.144-0.083-0.429-0.015-0.761l0.037-0.177v-0.182V14.8 c0-1.247-0.006-1.277-0.048-1.472c-0.076-0.354-0.035-0.653,0.007-0.803c0.477-0.346,0.828-0.861,0.996-1.476 c0.261-0.956,0.076-2.091-0.508-3.114l-0.591-1.032c-0.746-1.307-1.965-2.119-3.182-2.119c-0.378,0-0.75,0.081-1.085,0.235 c-0.198-0.025-0.554-0.15-0.855-0.389l-0.103-0.082l-0.114-0.065l-1.857-1.067L18.92,3.36l-0.105-0.044 c-0.376-0.154-0.658-0.41-0.768-0.556C17.918,1.172,16.349,0,14.296,0H13.14c-2.043,0-3.608,1.154-3.749,2.721 C9.277,2.862,8.999,3.104,8.633,3.25l-0.1,0.039L8.439,3.341L6.495,4.406L6.363,4.479L6.245,4.573 C5.936,4.82,5.596,4.944,5.416,4.977c-0.314-0.139-0.66-0.21-1.011-0.21c-1.198,0-2.411,0.819-3.165,2.139L0.65,7.938 c-0.412,0.72-0.642,1.521-0.644,2.258c-0.003,0.952,0.362,1.756,1.013,2.256c0.034,0.155,0.061,0.448-0.016,0.786 c-0.038,0.168-0.062,0.28-0.062,1.563c0,1.148,0,1.148,0.015,1.262l0.009,0.073l0.017,0.073c0.073,0.346,0.045,0.643,0.011,0.802 C0.348,17.512-0.01,18.314,0,19.268c0.008,0.729,0.238,1.523,0.648,2.242l0.589,1.031c0.761,1.331,1.967,2.159,3.15,2.159 c0.324,0,0.645-0.064,0.938-0.187c0.167,0.038,0.492,0.156,0.813,0.416l0.11,0.088l0.124,0.07l2.045,1.156l0.102,0.057l0.107,0.043 c0.364,0.147,0.646,0.381,0.766,0.521c0.164,1.52,1.719,2.634,3.745,2.634h1.155c2.037,0,3.598-1.134,3.747-2.675 c0.117-0.145,0.401-0.393,0.774-0.549l0.111-0.047l0.105-0.062l1.96-1.159l0.105-0.062l0.097-0.075 c0.309-0.246,0.651-0.371,0.832-0.402c0.313,0.138,0.662,0.212,1.016,0.212c1.199,0,2.412-0.82,3.166-2.139l0.59-1.032 C27.387,20.48,27.575,19.342,27.315,18.389z M25.274,20.635l-0.59,1.032c-0.438,0.765-1.104,1.251-1.639,1.251 c-0.133,0-0.258-0.029-0.369-0.094c-0.15-0.086-0.346-0.127-0.566-0.127c-0.596,0-1.383,0.295-2.01,0.796l-1.96,1.157 c-1.016,0.425-1.846,1.291-1.846,1.929s-0.898,1.159-1.998,1.159H13.14c-1.1,0-1.998-0.514-1.998-1.141s-0.834-1.477-1.854-1.888 l-2.046-1.157c-0.636-0.511-1.425-0.814-2.006-0.814c-0.202,0-0.379,0.037-0.516,0.115c-0.101,0.057-0.214,0.084-0.333,0.084 c-0.518,0-1.179-0.498-1.62-1.271l-0.591-1.032c-0.545-0.954-0.556-1.983-0.024-2.286c0.532-0.305,0.78-1.432,0.551-2.506 c0,0,0-0.003,0-1.042c0-1.088,0.021-1.18,0.021-1.18c0.238-1.072-0.01-2.203-0.552-2.513C1.631,10.8,1.634,9.765,2.18,8.812 L2.769,7.78c0.438-0.766,1.103-1.251,1.636-1.251c0.131,0,0.255,0.029,0.365,0.092C4.92,6.707,5.114,6.747,5.334,6.747 c0.596,0,1.38-0.296,2.007-0.795l1.944-1.065c1.021-0.407,1.856-1.277,1.856-1.933c0-0.656,0.898-1.192,1.998-1.192h1.156V1.761 c1.1,0,1.998,0.545,1.998,1.211c0,0.667,0.832,1.554,1.849,1.973L20,6.013c0.618,0.489,1.401,0.775,2.012,0.775 c0.24,0,0.454-0.045,0.62-0.139c0.122-0.069,0.259-0.102,0.403-0.102c0.551,0,1.221,0.476,1.653,1.231l0.59,1.032 c0.544,0.953,0.518,2.004-0.062,2.334c-0.577,0.331-0.859,1.48-0.627,2.554c0,0,0.01,0.042,0.01,1.103c0,1.012,0,1.012,0,1.012 c-0.218,1.049,0.068,2.174,0.636,2.498C25.802,18.635,25.819,19.68,25.274,20.635z"/><path d="M13.61,7.611c-3.913,0-7.084,3.173-7.084,7.085c0,3.914,3.171,7.085,7.084,7.085s7.085-3.172,7.085-7.085 C20.695,10.784,17.523,7.611,13.61,7.611z M13.61,20.02c-2.936,0-5.323-2.388-5.323-5.323c0-2.935,2.388-5.323,5.323-5.323 s5.324,2.388,5.324,5.323C18.934,17.632,16.546,20.02,13.61,20.02z"/><path d="M13.682,9.908c-2.602,0-4.718,2.116-4.718,4.718c0,2.601,2.116,4.716,4.718,4.716c2.601,0,4.717-2.115,4.717-4.716 C18.399,12.024,16.283,9.908,13.682,9.908z M13.682,17.581c-1.633,0-2.956-1.323-2.956-2.955s1.323-2.956,2.956-2.956 c1.632,0,2.956,1.324,2.956,2.956S15.314,17.581,13.682,17.581z"/></g></svg> \ No newline at end of file diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 60b713f2995..8efb51bccd8 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -13,6 +13,8 @@ html_root_url = "https://doc.rust-lang.org/nightly/", html_playground_url = "https://play.rust-lang.org/")] +#![cfg_attr(stage0, feature(dyn_trait))] + #![feature(ascii_ctype)] #![feature(rustc_private)] #![feature(box_patterns)] @@ -23,7 +25,6 @@ #![feature(test)] #![feature(vec_remove_item)] #![feature(entry_and_modify)] -#![feature(dyn_trait)] extern crate arena; extern crate getopts; @@ -35,8 +36,8 @@ extern crate rustc_trans_utils; extern crate rustc_driver; extern crate rustc_resolve; extern crate rustc_lint; -extern crate rustc_back; extern crate rustc_metadata; +extern crate rustc_target; extern crate rustc_typeck; extern crate serialize; #[macro_use] extern crate syntax; @@ -66,7 +67,7 @@ use externalfiles::ExternalHtml; use rustc::session::search_paths::SearchPaths; use rustc::session::config::{ErrorOutputType, RustcOptGroup, Externs, CodegenOptions}; use rustc::session::config::{nightly_options, build_codegen_options}; -use rustc_back::target::TargetTriple; +use rustc_target::spec::TargetTriple; #[macro_use] pub mod externalfiles; diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 600e9eaa05f..c4eaa48e49d 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -80,9 +80,9 @@ pub fn run(input_path: &Path, lint_cap: Some(::rustc::lint::Level::Allow), actually_rustdoc: true, debugging_opts: config::DebuggingOptions { - edition, ..config::basic_debugging_options() }, + edition, ..config::basic_options().clone() }; @@ -223,9 +223,9 @@ fn run_test(test: &str, cratename: &str, filename: &FileName, line: usize, test: as_test_harness, unstable_features: UnstableFeatures::from_environment(), debugging_opts: config::DebuggingOptions { - edition, ..config::basic_debugging_options() }, + edition, ..config::basic_options().clone() }; @@ -437,7 +437,7 @@ fn partition_source(s: &str) -> (String, String) { for line in s.lines() { let trimline = line.trim(); - let header = trimline.is_whitespace() || + let header = trimline.chars().all(|c| c.is_whitespace()) || trimline.starts_with("#![") || trimline.starts_with("#[macro_use] extern crate") || trimline.starts_with("extern crate"); diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index f45a5b030db..967c50e62db 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -13,7 +13,7 @@ use std::mem; -use syntax::abi; +use rustc_target::spec::abi; use syntax::ast; use syntax::attr; use syntax_pos::Span; diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs index ff578ec42d2..a8578404467 100644 --- a/src/libstd/alloc.rs +++ b/src/libstd/alloc.rs @@ -13,10 +13,18 @@ #![unstable(issue = "32838", feature = "allocator_api")] #[doc(inline)] #[allow(deprecated)] pub use alloc_crate::alloc::Heap; -#[doc(inline)] pub use alloc_crate::alloc::Global; +#[doc(inline)] pub use alloc_crate::alloc::{Global, oom}; #[doc(inline)] pub use alloc_system::System; #[doc(inline)] pub use core::alloc::*; +#[cfg(not(stage0))] +#[cfg(not(test))] +#[doc(hidden)] +#[lang = "oom"] +pub extern fn rust_oom() -> ! { + rtabort!("memory allocation failed"); +} + #[cfg(not(test))] #[doc(hidden)] #[allow(unused_attributes)] @@ -35,10 +43,11 @@ pub mod __default_lib_allocator { System.alloc(layout) as *mut u8 } + #[cfg(stage0)] #[no_mangle] #[rustc_std_internal_symbol] pub unsafe extern fn __rdl_oom() -> ! { - System.oom() + super::oom() } #[no_mangle] diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 20a4f9b508d..a7eb002d5a1 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -11,7 +11,7 @@ use self::Entry::*; use self::VacantEntryState::*; -use alloc::{Global, Alloc, CollectionAllocErr}; +use alloc::{CollectionAllocErr, oom}; use cell::Cell; use borrow::Borrow; use cmp::max; @@ -33,6 +33,7 @@ const MIN_NONZERO_RAW_CAPACITY: usize = 32; // must be a power of two struct DefaultResizePolicy; impl DefaultResizePolicy { + #[inline] fn new() -> DefaultResizePolicy { DefaultResizePolicy } @@ -784,7 +785,7 @@ impl<K, V, S> HashMap<K, V, S> pub fn reserve(&mut self, additional: usize) { match self.try_reserve(additional) { Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"), - Err(CollectionAllocErr::AllocErr) => Global.oom(), + Err(CollectionAllocErr::AllocErr) => oom(), Ok(()) => { /* yay */ } } } @@ -1379,7 +1380,6 @@ impl<K, V, S> HashMap<K, V, S> /// # Examples /// /// ``` - /// #![feature(hash_map_remove_entry)] /// use std::collections::HashMap; /// /// # fn main() { @@ -1389,7 +1389,7 @@ impl<K, V, S> HashMap<K, V, S> /// assert_eq!(map.remove(&1), None); /// # } /// ``` - #[unstable(feature = "hash_map_remove_entry", issue = "46344")] + #[stable(feature = "hash_map_remove_entry", since = "1.27.0")] pub fn remove_entry<Q: ?Sized>(&mut self, k: &Q) -> Option<(K, V)> where K: Borrow<Q>, Q: Hash + Eq @@ -2127,8 +2127,8 @@ impl<'a, K, V> Entry<'a, K, V> { /// assert_eq!(map["poneyland"], 43); /// ``` #[stable(feature = "entry_and_modify", since = "1.26.0")] - pub fn and_modify<F>(self, mut f: F) -> Self - where F: FnMut(&mut V) + pub fn and_modify<F>(self, f: F) -> Self + where F: FnOnce(&mut V) { match self { Occupied(mut entry) => { diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index 115f9628a23..52c53dc3b12 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use alloc::{Global, Alloc, Layout, CollectionAllocErr}; +use alloc::{Global, Alloc, Layout, CollectionAllocErr, oom}; use cmp; use hash::{BuildHasher, Hash, Hasher}; use marker; @@ -770,7 +770,7 @@ impl<K, V> RawTable<K, V> { unsafe fn new_uninitialized(capacity: usize) -> RawTable<K, V> { match Self::try_new_uninitialized(capacity) { Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"), - Err(CollectionAllocErr::AllocErr) => Global.oom(), + Err(CollectionAllocErr::AllocErr) => oom(), Ok(table) => { table } } } @@ -809,7 +809,7 @@ impl<K, V> RawTable<K, V> { pub fn new(capacity: usize) -> RawTable<K, V> { match Self::try_new(capacity) { Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"), - Err(CollectionAllocErr::AllocErr) => Global.oom(), + Err(CollectionAllocErr::AllocErr) => oom(), Ok(table) => { table } } } diff --git a/src/libstd/error.rs b/src/libstd/error.rs index 3c209928d43..749b8ccc13d 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -233,7 +233,7 @@ impl<'a> From<Cow<'a, str>> for Box<Error> { } } -#[stable(feature = "never_type", since = "1.26.0")] +#[unstable(feature = "never_type", issue = "35121")] impl Error for ! { fn description(&self) -> &str { *self } } @@ -284,14 +284,14 @@ impl Error for num::ParseIntError { } } -#[stable(feature = "try_from", since = "1.26.0")] +#[unstable(feature = "try_from", issue = "33417")] impl Error for num::TryFromIntError { fn description(&self) -> &str { self.__description() } } -#[stable(feature = "try_from", since = "1.26.0")] +#[unstable(feature = "try_from", issue = "33417")] impl Error for array::TryFromSliceError { fn description(&self) -> &str { self.__description() @@ -365,7 +365,7 @@ impl Error for cell::BorrowMutError { } } -#[stable(feature = "try_from", since = "1.26.0")] +#[unstable(feature = "try_from", issue = "33417")] impl Error for char::CharTryFromError { fn description(&self) -> &str { "converted integer out of range for `char`" diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs index ca39089a958..26644c76957 100644 --- a/src/libstd/f32.rs +++ b/src/libstd/f32.rs @@ -19,10 +19,12 @@ #![allow(missing_docs)] #[cfg(not(test))] -use core::num; +#[cfg(stage0)] +use core::num::Float; #[cfg(not(test))] use intrinsics; #[cfg(not(test))] +#[cfg(stage0)] use num::FpCategory; #[cfg(not(test))] use sys::cmath; @@ -39,106 +41,11 @@ pub use core::f32::{MIN, MIN_POSITIVE, MAX}; pub use core::f32::consts; #[cfg(not(test))] -#[lang = "f32"] +#[cfg_attr(stage0, lang = "f32")] +#[cfg_attr(not(stage0), lang = "f32_runtime")] impl f32 { - /// Returns `true` if this value is `NaN` and false otherwise. - /// - /// ``` - /// use std::f32; - /// - /// let nan = f32::NAN; - /// let f = 7.0_f32; - /// - /// assert!(nan.is_nan()); - /// assert!(!f.is_nan()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_nan(self) -> bool { num::Float::is_nan(self) } - - /// Returns `true` if this value is positive infinity or negative infinity and - /// false otherwise. - /// - /// ``` - /// use std::f32; - /// - /// let f = 7.0f32; - /// let inf = f32::INFINITY; - /// let neg_inf = f32::NEG_INFINITY; - /// let nan = f32::NAN; - /// - /// assert!(!f.is_infinite()); - /// assert!(!nan.is_infinite()); - /// - /// assert!(inf.is_infinite()); - /// assert!(neg_inf.is_infinite()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_infinite(self) -> bool { num::Float::is_infinite(self) } - - /// Returns `true` if this number is neither infinite nor `NaN`. - /// - /// ``` - /// use std::f32; - /// - /// let f = 7.0f32; - /// let inf = f32::INFINITY; - /// let neg_inf = f32::NEG_INFINITY; - /// let nan = f32::NAN; - /// - /// assert!(f.is_finite()); - /// - /// assert!(!nan.is_finite()); - /// assert!(!inf.is_finite()); - /// assert!(!neg_inf.is_finite()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_finite(self) -> bool { num::Float::is_finite(self) } - - /// Returns `true` if the number is neither zero, infinite, - /// [subnormal][subnormal], or `NaN`. - /// - /// ``` - /// use std::f32; - /// - /// let min = f32::MIN_POSITIVE; // 1.17549435e-38f32 - /// let max = f32::MAX; - /// let lower_than_min = 1.0e-40_f32; - /// let zero = 0.0_f32; - /// - /// assert!(min.is_normal()); - /// assert!(max.is_normal()); - /// - /// assert!(!zero.is_normal()); - /// assert!(!f32::NAN.is_normal()); - /// assert!(!f32::INFINITY.is_normal()); - /// // Values between `0` and `min` are Subnormal. - /// assert!(!lower_than_min.is_normal()); - /// ``` - /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_normal(self) -> bool { num::Float::is_normal(self) } - - /// Returns the floating point category of the number. If only one property - /// is going to be tested, it is generally faster to use the specific - /// predicate instead. - /// - /// ``` - /// use std::num::FpCategory; - /// use std::f32; - /// - /// let num = 12.4_f32; - /// let inf = f32::INFINITY; - /// - /// assert_eq!(num.classify(), FpCategory::Normal); - /// assert_eq!(inf.classify(), FpCategory::Infinite); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn classify(self) -> FpCategory { num::Float::classify(self) } + #[cfg(stage0)] + f32_core_methods!(); /// Returns the largest integer less than or equal to a number. /// @@ -257,7 +164,9 @@ impl f32 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn abs(self) -> f32 { num::Float::abs(self) } + pub fn abs(self) -> f32 { + unsafe { intrinsics::fabsf32(self) } + } /// Returns a number that represents the sign of `self`. /// @@ -277,35 +186,13 @@ impl f32 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn signum(self) -> f32 { num::Float::signum(self) } - - /// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with - /// positive sign bit and positive infinity. - /// - /// ``` - /// let f = 7.0_f32; - /// let g = -7.0_f32; - /// - /// assert!(f.is_sign_positive()); - /// assert!(!g.is_sign_positive()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_sign_positive(self) -> bool { num::Float::is_sign_positive(self) } - - /// Returns `true` if and only if `self` has a negative sign, including `-0.0`, `NaN`s with - /// negative sign bit and negative infinity. - /// - /// ``` - /// let f = 7.0f32; - /// let g = -7.0f32; - /// - /// assert!(!f.is_sign_negative()); - /// assert!(g.is_sign_negative()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_sign_negative(self) -> bool { num::Float::is_sign_negative(self) } + pub fn signum(self) -> f32 { + if self.is_nan() { + NAN + } else { + unsafe { intrinsics::copysignf32(1.0, self) } + } + } /// Fused multiply-add. Computes `(self * a) + b` with only one rounding /// error. This produces a more accurate result with better performance than @@ -380,20 +267,6 @@ impl f32 { } - /// Takes the reciprocal (inverse) of a number, `1/x`. - /// - /// ``` - /// use std::f32; - /// - /// let x = 2.0_f32; - /// let abs_difference = (x.recip() - (1.0/x)).abs(); - /// - /// assert!(abs_difference <= f32::EPSILON); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn recip(self) -> f32 { num::Float::recip(self) } - /// Raises a number to an integer power. /// /// Using this function is generally faster than using `powf` @@ -408,7 +281,9 @@ impl f32 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn powi(self, n: i32) -> f32 { num::Float::powi(self, n) } + pub fn powi(self, n: i32) -> f32 { + unsafe { intrinsics::powif32(self, n) } + } /// Raises a number to a floating point power. /// @@ -584,68 +459,6 @@ impl f32 { return unsafe { intrinsics::log10f32(self) }; } - /// Converts radians to degrees. - /// - /// ``` - /// use std::f32::{self, consts}; - /// - /// let angle = consts::PI; - /// - /// let abs_difference = (angle.to_degrees() - 180.0).abs(); - /// - /// assert!(abs_difference <= f32::EPSILON); - /// ``` - #[stable(feature = "f32_deg_rad_conversions", since="1.7.0")] - #[inline] - pub fn to_degrees(self) -> f32 { num::Float::to_degrees(self) } - - /// Converts degrees to radians. - /// - /// ``` - /// use std::f32::{self, consts}; - /// - /// let angle = 180.0f32; - /// - /// let abs_difference = (angle.to_radians() - consts::PI).abs(); - /// - /// assert!(abs_difference <= f32::EPSILON); - /// ``` - #[stable(feature = "f32_deg_rad_conversions", since="1.7.0")] - #[inline] - pub fn to_radians(self) -> f32 { num::Float::to_radians(self) } - - /// Returns the maximum of the two numbers. - /// - /// ``` - /// let x = 1.0f32; - /// let y = 2.0f32; - /// - /// assert_eq!(x.max(y), y); - /// ``` - /// - /// If one of the arguments is NaN, then the other argument is returned. - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn max(self, other: f32) -> f32 { - num::Float::max(self, other) - } - - /// Returns the minimum of the two numbers. - /// - /// ``` - /// let x = 1.0f32; - /// let y = 2.0f32; - /// - /// assert_eq!(x.min(y), x); - /// ``` - /// - /// If one of the arguments is NaN, then the other argument is returned. - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn min(self, other: f32) -> f32 { - num::Float::min(self, other) - } - /// The positive difference of two numbers. /// /// * If `self <= other`: `0:0` @@ -1046,73 +859,6 @@ impl f32 { pub fn atanh(self) -> f32 { 0.5 * ((2.0 * self) / (1.0 - self)).ln_1p() } - - /// Raw transmutation to `u32`. - /// - /// This is currently identical to `transmute::<f32, u32>(self)` on all platforms. - /// - /// See `from_bits` for some discussion of the portability of this operation - /// (there are almost no issues). - /// - /// Note that this function is distinct from `as` casting, which attempts to - /// preserve the *numeric* value, and not the bitwise value. - /// - /// # Examples - /// - /// ``` - /// assert_ne!((1f32).to_bits(), 1f32 as u32); // to_bits() is not casting! - /// assert_eq!((12.5f32).to_bits(), 0x41480000); - /// - /// ``` - #[stable(feature = "float_bits_conv", since = "1.20.0")] - #[inline] - pub fn to_bits(self) -> u32 { - num::Float::to_bits(self) - } - - /// Raw transmutation from `u32`. - /// - /// This is currently identical to `transmute::<u32, f32>(v)` on all platforms. - /// It turns out this is incredibly portable, for two reasons: - /// - /// * Floats and Ints have the same endianness on all supported platforms. - /// * IEEE-754 very precisely specifies the bit layout of floats. - /// - /// However there is one caveat: prior to the 2008 version of IEEE-754, how - /// to interpret the NaN signaling bit wasn't actually specified. Most platforms - /// (notably x86 and ARM) picked the interpretation that was ultimately - /// standardized in 2008, but some didn't (notably MIPS). As a result, all - /// signaling NaNs on MIPS are quiet NaNs on x86, and vice-versa. - /// - /// Rather than trying to preserve signaling-ness cross-platform, this - /// implementation favours preserving the exact bits. This means that - /// any payloads encoded in NaNs will be preserved even if the result of - /// this method is sent over the network from an x86 machine to a MIPS one. - /// - /// If the results of this method are only manipulated by the same - /// architecture that produced them, then there is no portability concern. - /// - /// If the input isn't NaN, then there is no portability concern. - /// - /// If you don't care about signalingness (very likely), then there is no - /// portability concern. - /// - /// Note that this function is distinct from `as` casting, which attempts to - /// preserve the *numeric* value, and not the bitwise value. - /// - /// # Examples - /// - /// ``` - /// use std::f32; - /// let v = f32::from_bits(0x41480000); - /// let difference = (v - 12.5).abs(); - /// assert!(difference <= 1e-5); - /// ``` - #[stable(feature = "float_bits_conv", since = "1.20.0")] - #[inline] - pub fn from_bits(v: u32) -> Self { - num::Float::from_bits(v) - } } #[cfg(test)] diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs index a9585670ad0..a7e63f59b1c 100644 --- a/src/libstd/f64.rs +++ b/src/libstd/f64.rs @@ -19,10 +19,12 @@ #![allow(missing_docs)] #[cfg(not(test))] -use core::num; +#[cfg(stage0)] +use core::num::Float; #[cfg(not(test))] use intrinsics; #[cfg(not(test))] +#[cfg(stage0)] use num::FpCategory; #[cfg(not(test))] use sys::cmath; @@ -39,106 +41,11 @@ pub use core::f64::{MIN, MIN_POSITIVE, MAX}; pub use core::f64::consts; #[cfg(not(test))] -#[lang = "f64"] +#[cfg_attr(stage0, lang = "f64")] +#[cfg_attr(not(stage0), lang = "f64_runtime")] impl f64 { - /// Returns `true` if this value is `NaN` and false otherwise. - /// - /// ``` - /// use std::f64; - /// - /// let nan = f64::NAN; - /// let f = 7.0_f64; - /// - /// assert!(nan.is_nan()); - /// assert!(!f.is_nan()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_nan(self) -> bool { num::Float::is_nan(self) } - - /// Returns `true` if this value is positive infinity or negative infinity and - /// false otherwise. - /// - /// ``` - /// use std::f64; - /// - /// let f = 7.0f64; - /// let inf = f64::INFINITY; - /// let neg_inf = f64::NEG_INFINITY; - /// let nan = f64::NAN; - /// - /// assert!(!f.is_infinite()); - /// assert!(!nan.is_infinite()); - /// - /// assert!(inf.is_infinite()); - /// assert!(neg_inf.is_infinite()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_infinite(self) -> bool { num::Float::is_infinite(self) } - - /// Returns `true` if this number is neither infinite nor `NaN`. - /// - /// ``` - /// use std::f64; - /// - /// let f = 7.0f64; - /// let inf: f64 = f64::INFINITY; - /// let neg_inf: f64 = f64::NEG_INFINITY; - /// let nan: f64 = f64::NAN; - /// - /// assert!(f.is_finite()); - /// - /// assert!(!nan.is_finite()); - /// assert!(!inf.is_finite()); - /// assert!(!neg_inf.is_finite()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_finite(self) -> bool { num::Float::is_finite(self) } - - /// Returns `true` if the number is neither zero, infinite, - /// [subnormal][subnormal], or `NaN`. - /// - /// ``` - /// use std::f64; - /// - /// let min = f64::MIN_POSITIVE; // 2.2250738585072014e-308f64 - /// let max = f64::MAX; - /// let lower_than_min = 1.0e-308_f64; - /// let zero = 0.0f64; - /// - /// assert!(min.is_normal()); - /// assert!(max.is_normal()); - /// - /// assert!(!zero.is_normal()); - /// assert!(!f64::NAN.is_normal()); - /// assert!(!f64::INFINITY.is_normal()); - /// // Values between `0` and `min` are Subnormal. - /// assert!(!lower_than_min.is_normal()); - /// ``` - /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_normal(self) -> bool { num::Float::is_normal(self) } - - /// Returns the floating point category of the number. If only one property - /// is going to be tested, it is generally faster to use the specific - /// predicate instead. - /// - /// ``` - /// use std::num::FpCategory; - /// use std::f64; - /// - /// let num = 12.4_f64; - /// let inf = f64::INFINITY; - /// - /// assert_eq!(num.classify(), FpCategory::Normal); - /// assert_eq!(inf.classify(), FpCategory::Infinite); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn classify(self) -> FpCategory { num::Float::classify(self) } + #[cfg(stage0)] + f64_core_methods!(); /// Returns the largest integer less than or equal to a number. /// @@ -235,7 +142,9 @@ impl f64 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn abs(self) -> f64 { num::Float::abs(self) } + pub fn abs(self) -> f64 { + unsafe { intrinsics::fabsf64(self) } + } /// Returns a number that represents the sign of `self`. /// @@ -255,45 +164,13 @@ impl f64 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn signum(self) -> f64 { num::Float::signum(self) } - - /// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with - /// positive sign bit and positive infinity. - /// - /// ``` - /// let f = 7.0_f64; - /// let g = -7.0_f64; - /// - /// assert!(f.is_sign_positive()); - /// assert!(!g.is_sign_positive()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_sign_positive(self) -> bool { num::Float::is_sign_positive(self) } - - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_deprecated(since = "1.0.0", reason = "renamed to is_sign_positive")] - #[inline] - pub fn is_positive(self) -> bool { num::Float::is_sign_positive(self) } - - /// Returns `true` if and only if `self` has a negative sign, including `-0.0`, `NaN`s with - /// negative sign bit and negative infinity. - /// - /// ``` - /// let f = 7.0_f64; - /// let g = -7.0_f64; - /// - /// assert!(!f.is_sign_negative()); - /// assert!(g.is_sign_negative()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn is_sign_negative(self) -> bool { num::Float::is_sign_negative(self) } - - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_deprecated(since = "1.0.0", reason = "renamed to is_sign_negative")] - #[inline] - pub fn is_negative(self) -> bool { num::Float::is_sign_negative(self) } + pub fn signum(self) -> f64 { + if self.is_nan() { + NAN + } else { + unsafe { intrinsics::copysignf64(1.0, self) } + } + } /// Fused multiply-add. Computes `(self * a) + b` with only one rounding /// error. This produces a more accurate result with better performance than @@ -365,18 +242,6 @@ impl f64 { } } - /// Takes the reciprocal (inverse) of a number, `1/x`. - /// - /// ``` - /// let x = 2.0_f64; - /// let abs_difference = (x.recip() - (1.0/x)).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn recip(self) -> f64 { num::Float::recip(self) } - /// Raises a number to an integer power. /// /// Using this function is generally faster than using `powf` @@ -389,7 +254,9 @@ impl f64 { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn powi(self, n: i32) -> f64 { num::Float::powi(self, n) } + pub fn powi(self, n: i32) -> f64 { + unsafe { intrinsics::powif64(self, n) } + } /// Raises a number to a floating point power. /// @@ -535,68 +402,6 @@ impl f64 { self.log_wrapper(|n| { unsafe { intrinsics::log10f64(n) } }) } - /// Converts radians to degrees. - /// - /// ``` - /// use std::f64::consts; - /// - /// let angle = consts::PI; - /// - /// let abs_difference = (angle.to_degrees() - 180.0).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn to_degrees(self) -> f64 { num::Float::to_degrees(self) } - - /// Converts degrees to radians. - /// - /// ``` - /// use std::f64::consts; - /// - /// let angle = 180.0_f64; - /// - /// let abs_difference = (angle.to_radians() - consts::PI).abs(); - /// - /// assert!(abs_difference < 1e-10); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn to_radians(self) -> f64 { num::Float::to_radians(self) } - - /// Returns the maximum of the two numbers. - /// - /// ``` - /// let x = 1.0_f64; - /// let y = 2.0_f64; - /// - /// assert_eq!(x.max(y), y); - /// ``` - /// - /// If one of the arguments is NaN, then the other argument is returned. - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn max(self, other: f64) -> f64 { - num::Float::max(self, other) - } - - /// Returns the minimum of the two numbers. - /// - /// ``` - /// let x = 1.0_f64; - /// let y = 2.0_f64; - /// - /// assert_eq!(x.min(y), x); - /// ``` - /// - /// If one of the arguments is NaN, then the other argument is returned. - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn min(self, other: f64) -> f64 { - num::Float::min(self, other) - } - /// The positive difference of two numbers. /// /// * If `self <= other`: `0:0` @@ -1000,73 +805,6 @@ impl f64 { } } } - - /// Raw transmutation to `u64`. - /// - /// This is currently identical to `transmute::<f64, u64>(self)` on all platforms. - /// - /// See `from_bits` for some discussion of the portability of this operation - /// (there are almost no issues). - /// - /// Note that this function is distinct from `as` casting, which attempts to - /// preserve the *numeric* value, and not the bitwise value. - /// - /// # Examples - /// - /// ``` - /// assert!((1f64).to_bits() != 1f64 as u64); // to_bits() is not casting! - /// assert_eq!((12.5f64).to_bits(), 0x4029000000000000); - /// - /// ``` - #[stable(feature = "float_bits_conv", since = "1.20.0")] - #[inline] - pub fn to_bits(self) -> u64 { - num::Float::to_bits(self) - } - - /// Raw transmutation from `u64`. - /// - /// This is currently identical to `transmute::<u64, f64>(v)` on all platforms. - /// It turns out this is incredibly portable, for two reasons: - /// - /// * Floats and Ints have the same endianness on all supported platforms. - /// * IEEE-754 very precisely specifies the bit layout of floats. - /// - /// However there is one caveat: prior to the 2008 version of IEEE-754, how - /// to interpret the NaN signaling bit wasn't actually specified. Most platforms - /// (notably x86 and ARM) picked the interpretation that was ultimately - /// standardized in 2008, but some didn't (notably MIPS). As a result, all - /// signaling NaNs on MIPS are quiet NaNs on x86, and vice-versa. - /// - /// Rather than trying to preserve signaling-ness cross-platform, this - /// implementation favours preserving the exact bits. This means that - /// any payloads encoded in NaNs will be preserved even if the result of - /// this method is sent over the network from an x86 machine to a MIPS one. - /// - /// If the results of this method are only manipulated by the same - /// architecture that produced them, then there is no portability concern. - /// - /// If the input isn't NaN, then there is no portability concern. - /// - /// If you don't care about signalingness (very likely), then there is no - /// portability concern. - /// - /// Note that this function is distinct from `as` casting, which attempts to - /// preserve the *numeric* value, and not the bitwise value. - /// - /// # Examples - /// - /// ``` - /// use std::f64; - /// let v = f64::from_bits(0x4029000000000000); - /// let difference = (v - 12.5).abs(); - /// assert!(difference <= 1e-5); - /// ``` - #[stable(feature = "float_bits_conv", since = "1.20.0")] - #[inline] - pub fn from_bits(v: u64) -> Self { - num::Float::from_bits(v) - } } #[cfg(test)] diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index d6eac748334..ee297d3783e 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -1251,6 +1251,7 @@ mod tests { } #[test] + #[allow(deprecated)] fn read_char_buffered() { let buf = [195, 159]; let reader = BufReader::with_capacity(1, &buf[..]); @@ -1258,6 +1259,7 @@ mod tests { } #[test] + #[allow(deprecated)] fn test_chars() { let buf = [195, 159, b'a']; let reader = BufReader::with_capacity(1, &buf[..]); diff --git a/src/libstd/io/cursor.rs b/src/libstd/io/cursor.rs index 2673f3ccfa3..8ac52572810 100644 --- a/src/libstd/io/cursor.rs +++ b/src/libstd/io/cursor.rs @@ -566,6 +566,7 @@ mod tests { } #[test] + #[allow(deprecated)] fn test_read_char() { let b = &b"Vi\xE1\xBB\x87t"[..]; let mut c = Cursor::new(b).chars(); @@ -577,6 +578,7 @@ mod tests { } #[test] + #[allow(deprecated)] fn test_read_bad_char() { let b = &b"\x80"[..]; let mut c = Cursor::new(b).chars(); diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index b02e133ee4d..eba4e9fe703 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -840,6 +840,9 @@ pub trait Read { of where errors happen is currently \ unclear and may change", issue = "27802")] + #[rustc_deprecated(since = "1.27.0", reason = "Use str::from_utf8 instead: + https://doc.rust-lang.org/nightly/std/str/struct.Utf8Error.html#examples")] + #[allow(deprecated)] fn chars(self) -> Chars<Self> where Self: Sized { Chars { inner: self } } @@ -2010,16 +2013,22 @@ impl<R: Read> Iterator for Bytes<R> { /// [chars]: trait.Read.html#method.chars #[unstable(feature = "io", reason = "awaiting stability of Read::chars", issue = "27802")] +#[rustc_deprecated(since = "1.27.0", reason = "Use str::from_utf8 instead: + https://doc.rust-lang.org/nightly/std/str/struct.Utf8Error.html#examples")] #[derive(Debug)] +#[allow(deprecated)] pub struct Chars<R> { inner: R, } /// An enumeration of possible errors that can be generated from the `Chars` /// adapter. -#[derive(Debug)] #[unstable(feature = "io", reason = "awaiting stability of Read::chars", issue = "27802")] +#[rustc_deprecated(since = "1.27.0", reason = "Use str::from_utf8 instead: + https://doc.rust-lang.org/nightly/std/str/struct.Utf8Error.html#examples")] +#[derive(Debug)] +#[allow(deprecated)] pub enum CharsError { /// Variant representing that the underlying stream was read successfully /// but it did not contain valid utf8 data. @@ -2031,6 +2040,7 @@ pub enum CharsError { #[unstable(feature = "io", reason = "awaiting stability of Read::chars", issue = "27802")] +#[allow(deprecated)] impl<R: Read> Iterator for Chars<R> { type Item = result::Result<char, CharsError>; @@ -2063,6 +2073,7 @@ impl<R: Read> Iterator for Chars<R> { #[unstable(feature = "io", reason = "awaiting stability of Read::chars", issue = "27802")] +#[allow(deprecated)] impl std_error::Error for CharsError { fn description(&self) -> &str { match *self { @@ -2080,6 +2091,7 @@ impl std_error::Error for CharsError { #[unstable(feature = "io", reason = "awaiting stability of Read::chars", issue = "27802")] +#[allow(deprecated)] impl fmt::Display for CharsError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index f0bca7784d8..41992193135 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -252,7 +252,7 @@ #![feature(collections_range)] #![feature(compiler_builtins_lib)] #![feature(const_fn)] -#![feature(core_float)] +#![cfg_attr(stage0, feature(core_float))] #![feature(core_intrinsics)] #![feature(dropck_eyepatch)] #![feature(exact_size_is_empty)] @@ -260,6 +260,7 @@ #![feature(fs_read_write)] #![feature(fixed_size_array)] #![feature(float_from_str_radix)] +#![cfg_attr(stage0, feature(float_internals))] #![feature(fn_traits)] #![feature(fnbox)] #![cfg_attr(stage0, feature(generic_param_attrs))] @@ -275,7 +276,7 @@ #![feature(macro_reexport)] #![feature(macro_vis_matcher)] #![feature(needs_panic_runtime)] -#![feature(nonnull_cast)] +#![feature(never_type)] #![feature(exhaustive_patterns)] #![feature(nonzero)] #![feature(num_bits_bytes)] @@ -307,6 +308,7 @@ #![feature(test, rustc_private)] #![feature(thread_local)] #![feature(toowned_clone_into)] +#![feature(try_from)] #![feature(try_reserve)] #![feature(unboxed_closures)] #![feature(untagged_unions)] @@ -317,6 +319,7 @@ #![feature(doc_spotlight)] #![cfg_attr(test, feature(update_panic_count))] #![cfg_attr(windows, feature(used))] +#![feature(doc_alias)] #![default_lib_allocator] @@ -458,6 +461,8 @@ pub use alloc_crate::vec; pub use core::char; #[stable(feature = "i128", since = "1.26.0")] pub use core::u128; +#[stable(feature = "core_hint", since = "1.27.0")] +pub use core::hint; pub mod f32; pub mod f64; @@ -479,7 +484,6 @@ pub mod path; pub mod process; pub mod sync; pub mod time; -pub mod alloc; #[unstable(feature = "allocator_api", issue = "32838")] #[rustc_deprecated(since = "1.27.0", reason = "module renamed to `alloc`")] @@ -493,6 +497,8 @@ pub mod heap { mod sys_common; mod sys; +pub mod alloc; + // Private support modules mod panicking; mod memchr; diff --git a/src/libstd/os/android/fs.rs b/src/libstd/os/android/fs.rs index a51b4655985..5899dc688e2 100644 --- a/src/libstd/os/android/fs.rs +++ b/src/libstd/os/android/fs.rs @@ -18,7 +18,9 @@ use sys_common::AsInner; #[allow(deprecated)] use os::android::raw; -/// OS-specific extension methods for `fs::Metadata` +/// OS-specific extensions to [`fs::Metadata`]. +/// +/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html #[stable(feature = "metadata_ext", since = "1.1.0")] pub trait MetadataExt { /// Gain a reference to the underlying `stat` structure which contains diff --git a/src/libstd/os/bitrig/fs.rs b/src/libstd/os/bitrig/fs.rs index e4f1c9432f3..24caf326ab0 100644 --- a/src/libstd/os/bitrig/fs.rs +++ b/src/libstd/os/bitrig/fs.rs @@ -18,7 +18,9 @@ use sys_common::AsInner; #[allow(deprecated)] use os::bitrig::raw; -/// OS-specific extension methods for `fs::Metadata` +/// OS-specific extensions to [`fs::Metadata`]. +/// +/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html #[stable(feature = "metadata_ext", since = "1.1.0")] pub trait MetadataExt { /// Gain a reference to the underlying `stat` structure which contains diff --git a/src/libstd/os/dragonfly/fs.rs b/src/libstd/os/dragonfly/fs.rs index db672e56435..6aea450774f 100644 --- a/src/libstd/os/dragonfly/fs.rs +++ b/src/libstd/os/dragonfly/fs.rs @@ -18,7 +18,9 @@ use sys_common::AsInner; #[allow(deprecated)] use os::dragonfly::raw; -/// OS-specific extension methods for `fs::Metadata` +/// OS-specific extensions to [`fs::Metadata`]. +/// +/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html #[stable(feature = "metadata_ext", since = "1.1.0")] pub trait MetadataExt { /// Gain a reference to the underlying `stat` structure which contains diff --git a/src/libstd/os/emscripten/fs.rs b/src/libstd/os/emscripten/fs.rs index 8056ce4fdc4..e0e197dc122 100644 --- a/src/libstd/os/emscripten/fs.rs +++ b/src/libstd/os/emscripten/fs.rs @@ -18,7 +18,9 @@ use sys_common::AsInner; #[allow(deprecated)] use os::emscripten::raw; -/// OS-specific extension methods for `fs::Metadata` +/// OS-specific extensions to [`fs::Metadata`]. +/// +/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html #[stable(feature = "metadata_ext", since = "1.1.0")] pub trait MetadataExt { /// Gain a reference to the underlying `stat` structure which contains diff --git a/src/libstd/os/freebsd/fs.rs b/src/libstd/os/freebsd/fs.rs index 2f17d2f7409..5f24cd636d5 100644 --- a/src/libstd/os/freebsd/fs.rs +++ b/src/libstd/os/freebsd/fs.rs @@ -18,7 +18,9 @@ use sys_common::AsInner; #[allow(deprecated)] use os::freebsd::raw; -/// OS-specific extension methods for `fs::Metadata` +/// OS-specific extensions to [`fs::Metadata`]. +/// +/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html #[stable(feature = "metadata_ext", since = "1.1.0")] pub trait MetadataExt { /// Gain a reference to the underlying `stat` structure which contains diff --git a/src/libstd/os/fuchsia/fs.rs b/src/libstd/os/fuchsia/fs.rs index d22f9a628bd..16802576356 100644 --- a/src/libstd/os/fuchsia/fs.rs +++ b/src/libstd/os/fuchsia/fs.rs @@ -13,7 +13,9 @@ use fs::Metadata; use sys_common::AsInner; -/// OS-specific extension methods for `fs::Metadata` +/// OS-specific extensions to [`fs::Metadata`]. +/// +/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html #[stable(feature = "metadata_ext", since = "1.1.0")] pub trait MetadataExt { #[stable(feature = "metadata_ext2", since = "1.8.0")] diff --git a/src/libstd/os/haiku/fs.rs b/src/libstd/os/haiku/fs.rs index 54f8ea1b71b..453136e0ac8 100644 --- a/src/libstd/os/haiku/fs.rs +++ b/src/libstd/os/haiku/fs.rs @@ -18,7 +18,9 @@ use sys_common::AsInner; #[allow(deprecated)] use os::haiku::raw; -/// OS-specific extension methods for `fs::Metadata` +/// OS-specific extensions to [`fs::Metadata`]. +/// +/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html #[stable(feature = "metadata_ext", since = "1.1.0")] pub trait MetadataExt { /// Gain a reference to the underlying `stat` structure which contains diff --git a/src/libstd/os/ios/fs.rs b/src/libstd/os/ios/fs.rs index 275daf3d3a0..296ce69ff43 100644 --- a/src/libstd/os/ios/fs.rs +++ b/src/libstd/os/ios/fs.rs @@ -18,7 +18,9 @@ use sys_common::AsInner; #[allow(deprecated)] use os::ios::raw; -/// OS-specific extension methods for `fs::Metadata` +/// OS-specific extensions to [`fs::Metadata`]. +/// +/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html #[stable(feature = "metadata_ext", since = "1.1.0")] pub trait MetadataExt { /// Gain a reference to the underlying `stat` structure which contains diff --git a/src/libstd/os/linux/fs.rs b/src/libstd/os/linux/fs.rs index 2be2fbcb2db..76fb10da850 100644 --- a/src/libstd/os/linux/fs.rs +++ b/src/libstd/os/linux/fs.rs @@ -18,7 +18,9 @@ use sys_common::AsInner; #[allow(deprecated)] use os::linux::raw; -/// OS-specific extension methods for `fs::Metadata` +/// OS-specific extensions to [`fs::Metadata`]. +/// +/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html #[stable(feature = "metadata_ext", since = "1.1.0")] pub trait MetadataExt { /// Gain a reference to the underlying `stat` structure which contains diff --git a/src/libstd/os/macos/fs.rs b/src/libstd/os/macos/fs.rs index 12b44901d03..0b14c05cb55 100644 --- a/src/libstd/os/macos/fs.rs +++ b/src/libstd/os/macos/fs.rs @@ -18,7 +18,9 @@ use sys_common::AsInner; #[allow(deprecated)] use os::macos::raw; -/// OS-specific extension methods for `fs::Metadata` +/// OS-specific extensions to [`fs::Metadata`]. +/// +/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html #[stable(feature = "metadata_ext", since = "1.1.0")] pub trait MetadataExt { /// Gain a reference to the underlying `stat` structure which contains diff --git a/src/libstd/os/netbsd/fs.rs b/src/libstd/os/netbsd/fs.rs index cd7d5fafd1c..e9cad33fee6 100644 --- a/src/libstd/os/netbsd/fs.rs +++ b/src/libstd/os/netbsd/fs.rs @@ -18,7 +18,9 @@ use sys_common::AsInner; #[allow(deprecated)] use os::netbsd::raw; -/// OS-specific extension methods for `fs::Metadata` +/// OS-specific extensions to [`fs::Metadata`]. +/// +/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html #[stable(feature = "metadata_ext", since = "1.1.0")] pub trait MetadataExt { /// Gain a reference to the underlying `stat` structure which contains diff --git a/src/libstd/os/openbsd/fs.rs b/src/libstd/os/openbsd/fs.rs index cc812fcf12c..0f6b83b6e32 100644 --- a/src/libstd/os/openbsd/fs.rs +++ b/src/libstd/os/openbsd/fs.rs @@ -18,7 +18,9 @@ use sys_common::AsInner; #[allow(deprecated)] use os::openbsd::raw; -/// OS-specific extension methods for `fs::Metadata` +/// OS-specific extensions to [`fs::Metadata`]. +/// +/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html #[stable(feature = "metadata_ext", since = "1.1.0")] pub trait MetadataExt { /// Gain a reference to the underlying `stat` structure which contains diff --git a/src/libstd/os/solaris/fs.rs b/src/libstd/os/solaris/fs.rs index 5dc43d03a86..19dce1ba34c 100644 --- a/src/libstd/os/solaris/fs.rs +++ b/src/libstd/os/solaris/fs.rs @@ -18,7 +18,9 @@ use sys_common::AsInner; #[allow(deprecated)] use os::solaris::raw; -/// OS-specific extension methods for `fs::Metadata` +/// OS-specific extensions to [`fs::Metadata`]. +/// +/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html #[stable(feature = "metadata_ext", since = "1.1.0")] pub trait MetadataExt { /// Gain a reference to the underlying `stat` structure which contains diff --git a/src/libstd/path.rs b/src/libstd/path.rs index ec961575473..955a6af1ae6 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -298,10 +298,9 @@ pub const MAIN_SEPARATOR: char = ::sys::path::MAIN_SEP; // Iterate through `iter` while it matches `prefix`; return `None` if `prefix` // is not a prefix of `iter`, otherwise return `Some(iter_after_prefix)` giving // `iter` after having exhausted `prefix`. -fn iter_after<A, I, J>(mut iter: I, mut prefix: J) -> Option<I> - where I: Iterator<Item = A> + Clone, - J: Iterator<Item = A>, - A: PartialEq +fn iter_after<'a, 'b, I, J>(mut iter: I, mut prefix: J) -> Option<I> + where I: Iterator<Item = Component<'a>> + Clone, + J: Iterator<Item = Component<'b>>, { loop { let mut iter_next = iter.clone(); @@ -1967,7 +1966,7 @@ impl Path { /// # Examples /// /// ``` - /// use std::path::Path; + /// use std::path::{Path, PathBuf}; /// /// let path = Path::new("/test/haha/foo.txt"); /// @@ -1978,17 +1977,20 @@ impl Path { /// assert_eq!(path.strip_prefix("/test/haha/foo.txt/"), Ok(Path::new(""))); /// assert_eq!(path.strip_prefix("test").is_ok(), false); /// assert_eq!(path.strip_prefix("/haha").is_ok(), false); + /// + /// let prefix = PathBuf::from("/test/"); + /// assert_eq!(path.strip_prefix(prefix), Ok(Path::new("haha/foo.txt"))); /// ``` #[stable(since = "1.7.0", feature = "path_strip_prefix")] - pub fn strip_prefix<'a, P: ?Sized>(&'a self, base: &'a P) - -> Result<&'a Path, StripPrefixError> + pub fn strip_prefix<P>(&self, base: P) + -> Result<&Path, StripPrefixError> where P: AsRef<Path> { self._strip_prefix(base.as_ref()) } - fn _strip_prefix<'a>(&'a self, base: &'a Path) - -> Result<&'a Path, StripPrefixError> { + fn _strip_prefix(&self, base: &Path) + -> Result<&Path, StripPrefixError> { iter_after(self.components(), base.components()) .map(|c| c.as_path()) .ok_or(StripPrefixError(())) diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index ce4bbfffc2e..919d9648297 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -9,6 +9,8 @@ // except according to those terms. #[doc(primitive = "bool")] +#[doc(alias = "true")] +#[doc(alias = "false")] // /// The boolean type. /// @@ -68,6 +70,7 @@ mod prim_bool { } #[doc(primitive = "never")] +#[doc(alias = "!")] // /// The `!` type, also called "never". /// @@ -79,6 +82,7 @@ mod prim_bool { } /// write: /// /// ``` +/// #![feature(never_type)] /// # fn foo() -> u32 { /// let x: ! = { /// return 123 @@ -155,6 +159,7 @@ mod prim_bool { } /// for example: /// /// ``` +/// #![feature(never_type)] /// # use std::fmt; /// # trait Debug { /// # fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result; @@ -499,6 +504,9 @@ mod prim_pointer { } mod prim_array { } #[doc(primitive = "slice")] +#[doc(alias = "[")] +#[doc(alias = "]")] +#[doc(alias = "[]")] // /// A dynamically-sized view into a contiguous sequence, `[T]`. /// @@ -597,6 +605,9 @@ mod prim_slice { } mod prim_str { } #[doc(primitive = "tuple")] +#[doc(alias = "(")] +#[doc(alias = ")")] +#[doc(alias = "()")] // /// A finite heterogeneous sequence, `(T, U, ..)`. /// @@ -819,6 +830,7 @@ mod prim_isize { } mod prim_usize { } #[doc(primitive = "reference")] +#[doc(alias = "&")] // /// References, both shared and mutable. /// diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 92f0406c09b..00051d4487a 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -1121,8 +1121,13 @@ impl ExitCode { } impl Child { - /// Forces the child to exit. This is equivalent to sending a - /// SIGKILL on unix platforms. + /// Forces the child process to exit. If the child has already exited, an [`InvalidInput`] + /// error is returned. + /// + /// The mapping to [`ErrorKind`]s is not part of the compatibility contract of the function, + /// especially the [`Other`] kind might change to more specific kinds in the future. + /// + /// This is equivalent to sending a SIGKILL on Unix platforms. /// /// # Examples /// @@ -1138,6 +1143,10 @@ impl Child { /// println!("yes command didn't start"); /// } /// ``` + /// + /// [`ErrorKind`]: ../io/enum.ErrorKind.html + /// [`InvalidInput`]: ../io/enum.ErrorKind.html#variant.InvalidInput + /// [`Other`]: ../io/enum.ErrorKind.html#variant.Other #[stable(feature = "process", since = "1.0.0")] pub fn kill(&mut self) -> io::Result<()> { self.handle.kill() diff --git a/src/libstd/sys/redox/ext/ffi.rs b/src/libstd/sys/redox/ext/ffi.rs index d59b4fc0b70..cd88c8f46b3 100644 --- a/src/libstd/sys/redox/ext/ffi.rs +++ b/src/libstd/sys/redox/ext/ffi.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Unix-specific extension to the primitives in the `std::ffi` module +//! Redox-specific extension to the primitives in the `std::ffi` module. #![stable(feature = "rust1", since = "1.0.0")] @@ -17,7 +17,9 @@ use mem; use sys::os_str::Buf; use sys_common::{FromInner, IntoInner, AsInner}; -/// Unix-specific extensions to `OsString`. +/// Redox-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. @@ -39,7 +41,9 @@ impl OsStringExt for OsString { } } -/// Unix-specific extensions to `OsStr`. +/// Redox-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")] diff --git a/src/libstd/sys/redox/ext/fs.rs b/src/libstd/sys/redox/ext/fs.rs index 0f4762aa881..c1dba6edda4 100644 --- a/src/libstd/sys/redox/ext/fs.rs +++ b/src/libstd/sys/redox/ext/fs.rs @@ -18,7 +18,9 @@ use path::Path; use sys; use sys_common::{FromInner, AsInner, AsInnerMut}; -/// Redox-specific extensions to `Permissions` +/// Redox-specific extensions to [`fs::Permissions`]. +/// +/// [`fs::Permissions`]: ../../../../std/fs/struct.Permissions.html #[stable(feature = "fs_ext", since = "1.1.0")] pub trait PermissionsExt { /// Returns the underlying raw `mode_t` bits that are the standard Redox @@ -95,7 +97,9 @@ impl PermissionsExt for Permissions { } } -/// Redox-specific extensions to `OpenOptions` +/// Redox-specific extensions to [`fs::OpenOptions`]. +/// +/// [`fs::OpenOptions`]: ../../../../std/fs/struct.OpenOptions.html #[stable(feature = "fs_ext", since = "1.1.0")] pub trait OpenOptionsExt { /// Sets the mode bits that a new file will be created with. @@ -163,13 +167,9 @@ impl OpenOptionsExt for OpenOptions { } } -// Hm, why are there casts here to the returned type, shouldn't the types always -// be the same? Right you are! Turns out, however, on android at least the types -// in the raw `stat` structure are not the same as the types being returned. Who -// knew! -// -// As a result to make sure this compiles for all platforms we do the manual -// casts and rely on manual lowering to `stat` if the raw type is desired. +/// Redox-specific extensions to [`fs::Metadata`]. +/// +/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html #[stable(feature = "metadata_ext", since = "1.1.0")] pub trait MetadataExt { #[stable(feature = "metadata_ext", since = "1.1.0")] @@ -204,6 +204,13 @@ pub trait MetadataExt { fn blocks(&self) -> u64; } +// Hm, why are there casts here to the returned type, shouldn't the types always +// be the same? Right you are! Turns out, however, on android at least the types +// in the raw `stat` structure are not the same as the types being returned. Who +// knew! +// +// As a result to make sure this compiles for all platforms we do the manual +// casts and rely on manual lowering to `stat` if the raw type is desired. #[stable(feature = "metadata_ext", since = "1.1.0")] impl MetadataExt for fs::Metadata { fn dev(&self) -> u64 { @@ -253,7 +260,12 @@ impl MetadataExt for fs::Metadata { } } -/// Add special Redox types (block/char device, fifo and socket) +/// Redox-specific extensions for [`FileType`]. +/// +/// Adds support for special Unix file types such as block/character devices, +/// pipes, and sockets. +/// +/// [`FileType`]: ../../../../std/fs/struct.FileType.html #[stable(feature = "file_type_ext", since = "1.5.0")] pub trait FileTypeExt { /// Returns whether this file type is a block device. @@ -307,8 +319,10 @@ pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> sys::fs::symlink(src.as_ref(), dst.as_ref()) } +/// Redox-specific extensions to [`fs::DirBuilder`]. +/// +/// [`fs::DirBuilder`]: ../../../../std/fs/struct.DirBuilder.html #[stable(feature = "dir_builder", since = "1.6.0")] -/// An extension trait for `fs::DirBuilder` for Redox-specific options. pub trait DirBuilderExt { /// Sets the mode to create new directories with. This option defaults to /// 0o777. diff --git a/src/libstd/sys/redox/ext/process.rs b/src/libstd/sys/redox/ext/process.rs index e68e180acf1..cfb6d5fc703 100644 --- a/src/libstd/sys/redox/ext/process.rs +++ b/src/libstd/sys/redox/ext/process.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Unix-specific extensions to primitives in the `std::process` module. +//! Redox-specific extensions to primitives in the `std::process` module. #![stable(feature = "rust1", since = "1.0.0")] @@ -18,7 +18,9 @@ use process; use sys; use sys_common::{AsInnerMut, AsInner, FromInner, IntoInner}; -/// Unix-specific extensions to the `std::process::Command` builder +/// Redox-specific extensions to the [`process::Command`] builder, +/// +/// [`process::Command`]: ../../../../std/process/struct.Command.html #[stable(feature = "rust1", since = "1.0.0")] pub trait CommandExt { /// Sets the child process's user id. This translates to a @@ -107,7 +109,9 @@ impl CommandExt for process::Command { } } -/// Unix-specific extensions to `std::process::ExitStatus` +/// Redox-specific extensions to [`process::ExitStatus`]. +/// +/// [`process::ExitStatus`]: ../../../../std/process/struct.ExitStatus.html #[stable(feature = "rust1", since = "1.0.0")] pub trait ExitStatusExt { /// Creates a new `ExitStatus` from the raw underlying `i32` return value of diff --git a/src/libstd/sys/redox/ext/thread.rs b/src/libstd/sys/redox/ext/thread.rs index 52be2ccd9f9..71ff0d46b91 100644 --- a/src/libstd/sys/redox/ext/thread.rs +++ b/src/libstd/sys/redox/ext/thread.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Unix-specific extensions to primitives in the `std::thread` module. +//! Redox-specific extensions to primitives in the `std::thread` module. #![stable(feature = "thread_extensions", since = "1.9.0")] @@ -19,7 +19,9 @@ use thread::JoinHandle; #[allow(deprecated)] pub type RawPthread = usize; -/// Unix-specific extensions to `std::thread::JoinHandle` +/// Redox-specific extensions to [`thread::JoinHandle`]. +/// +/// [`thread::JoinHandle`]: ../../../../std/thread/struct.JoinHandle.html #[stable(feature = "thread_extensions", since = "1.9.0")] pub trait JoinHandleExt { /// Extracts the raw pthread_t without taking ownership diff --git a/src/libstd/sys/unix/ext/ffi.rs b/src/libstd/sys/unix/ext/ffi.rs index fb9984ccbdd..8347145db5a 100644 --- a/src/libstd/sys/unix/ext/ffi.rs +++ b/src/libstd/sys/unix/ext/ffi.rs @@ -17,7 +17,9 @@ use mem; use sys::os_str::Buf; use sys_common::{FromInner, IntoInner, AsInner}; -/// Unix-specific extensions to `OsString`. +/// Unix-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. @@ -66,7 +68,9 @@ impl OsStringExt for OsString { } } -/// Unix-specific extensions to `OsStr`. +/// Unix-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")] diff --git a/src/libstd/sys/unix/ext/fs.rs b/src/libstd/sys/unix/ext/fs.rs index 3c5b9424fb0..4e981012669 100644 --- a/src/libstd/sys/unix/ext/fs.rs +++ b/src/libstd/sys/unix/ext/fs.rs @@ -105,7 +105,9 @@ impl FileExt for fs::File { } } -/// Unix-specific extensions to `Permissions` +/// Unix-specific extensions to [`fs::Permissions`]. +/// +/// [`fs::Permissions`]: ../../../../std/fs/struct.Permissions.html #[stable(feature = "fs_ext", since = "1.1.0")] pub trait PermissionsExt { /// Returns the underlying raw `st_mode` bits that contain the standard @@ -180,7 +182,9 @@ impl PermissionsExt for Permissions { } } -/// Unix-specific extensions to `OpenOptions` +/// Unix-specific extensions to [`fs::OpenOptions`]. +/// +/// [`fs::OpenOptions`]: ../../../../std/fs/struct.OpenOptions.html #[stable(feature = "fs_ext", since = "1.1.0")] pub trait OpenOptionsExt { /// Sets the mode bits that a new file will be created with. @@ -246,13 +250,9 @@ impl OpenOptionsExt for OpenOptions { } } -// Hm, why are there casts here to the returned type, shouldn't the types always -// be the same? Right you are! Turns out, however, on android at least the types -// in the raw `stat` structure are not the same as the types being returned. Who -// knew! -// -// As a result to make sure this compiles for all platforms we do the manual -// casts and rely on manual lowering to `stat` if the raw type is desired. +/// Unix-specific extensions to [`fs::Metadata`]. +/// +/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html #[stable(feature = "metadata_ext", since = "1.1.0")] pub trait MetadataExt { /// Returns the ID of the device containing the file. @@ -555,7 +555,12 @@ impl MetadataExt for fs::Metadata { fn blocks(&self) -> u64 { self.st_blocks() } } -/// Add support for special unix types (block/char device, fifo and socket). +/// Unix-specific extensions for [`FileType`]. +/// +/// Adds support for special Unix file types such as block/character devices, +/// pipes, and sockets. +/// +/// [`FileType`]: ../../../../std/fs/struct.FileType.html #[stable(feature = "file_type_ext", since = "1.5.0")] pub trait FileTypeExt { /// Returns whether this file type is a block device. @@ -701,10 +706,10 @@ pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> sys::fs::symlink(src.as_ref(), dst.as_ref()) } -#[stable(feature = "dir_builder", since = "1.6.0")] -/// An extension trait for [`fs::DirBuilder`] for unix-specific options. +/// Unix-specific extensions to [`fs::DirBuilder`]. /// /// [`fs::DirBuilder`]: ../../../../std/fs/struct.DirBuilder.html +#[stable(feature = "dir_builder", since = "1.6.0")] pub trait DirBuilderExt { /// Sets the mode to create new directories with. This option defaults to /// 0o777. diff --git a/src/libstd/sys/unix/ext/net.rs b/src/libstd/sys/unix/ext/net.rs index ba80cbe47c8..e277b1aa7b5 100644 --- a/src/libstd/sys/unix/ext/net.rs +++ b/src/libstd/sys/unix/ext/net.rs @@ -214,7 +214,10 @@ impl SocketAddr { let path = unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.addr.sun_path) }; // macOS seems to return a len of 16 and a zeroed sun_path for unnamed addresses - if len == 0 || (cfg!(not(target_os = "linux")) && self.addr.sun_path[0] == 0) { + if len == 0 + || (cfg!(not(any(target_os = "linux", target_os = "android"))) + && self.addr.sun_path[0] == 0) + { AddressKind::Unnamed } else if self.addr.sun_path[0] == 0 { AddressKind::Abstract(&path[1..len]) diff --git a/src/libstd/sys/unix/ext/process.rs b/src/libstd/sys/unix/ext/process.rs index 7b4ec20d91f..21630ae9746 100644 --- a/src/libstd/sys/unix/ext/process.rs +++ b/src/libstd/sys/unix/ext/process.rs @@ -18,7 +18,9 @@ use process; use sys; use sys_common::{AsInnerMut, AsInner, FromInner, IntoInner}; -/// Unix-specific extensions to the `std::process::Command` builder +/// Unix-specific extensions to the [`process::Command`] builder. +/// +/// [`process::Command`]: ../../../../std/process/struct.Command.html #[stable(feature = "rust1", since = "1.0.0")] pub trait CommandExt { /// Sets the child process's user id. This translates to a @@ -117,7 +119,9 @@ impl CommandExt for process::Command { } } -/// Unix-specific extensions to `std::process::ExitStatus` +/// Unix-specific extensions to [`process::ExitStatus`]. +/// +/// [`process::ExitStatus`]: ../../../../std/process/struct.ExitStatus.html #[stable(feature = "rust1", since = "1.0.0")] pub trait ExitStatusExt { /// Creates a new `ExitStatus` from the raw underlying `i32` return value of diff --git a/src/libstd/sys/unix/ext/thread.rs b/src/libstd/sys/unix/ext/thread.rs index fe2a48764dc..8dadf29945c 100644 --- a/src/libstd/sys/unix/ext/thread.rs +++ b/src/libstd/sys/unix/ext/thread.rs @@ -21,7 +21,9 @@ use thread::JoinHandle; #[allow(deprecated)] pub type RawPthread = pthread_t; -/// Unix-specific extensions to `std::thread::JoinHandle` +/// Unix-specific extensions to [`thread::JoinHandle`]. +/// +/// [`thread::JoinHandle`]: ../../../../std/thread/struct.JoinHandle.html #[stable(feature = "thread_extensions", since = "1.9.0")] pub trait JoinHandleExt { /// Extracts the raw pthread_t without taking ownership diff --git a/src/libstd/sys/windows/ext/ffi.rs b/src/libstd/sys/windows/ext/ffi.rs index d6b8896ac09..98d43552489 100644 --- a/src/libstd/sys/windows/ext/ffi.rs +++ b/src/libstd/sys/windows/ext/ffi.rs @@ -76,7 +76,9 @@ use sys_common::{FromInner, AsInner}; #[stable(feature = "rust1", since = "1.0.0")] pub use sys_common::wtf8::EncodeWide; -/// Windows-specific extensions to `OsString`. +/// Windows-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 potentially ill-formed UTF-16 slice of @@ -109,7 +111,9 @@ impl OsStringExt for OsString { } } -/// Windows-specific extensions to `OsStr`. +/// Windows-specific extensions to [`OsStr`]. +/// +/// [`OsStr`]: ../../../../std/ffi/struct.OsStr.html #[stable(feature = "rust1", since = "1.0.0")] pub trait OsStrExt { /// Re-encodes an `OsStr` as a wide character sequence, i.e. potentially diff --git a/src/libstd/sys/windows/ext/fs.rs b/src/libstd/sys/windows/ext/fs.rs index e5cd51b6550..78c9e95a055 100644 --- a/src/libstd/sys/windows/ext/fs.rs +++ b/src/libstd/sys/windows/ext/fs.rs @@ -103,9 +103,9 @@ impl FileExt for fs::File { } } -/// Windows-specific extensions to [`OpenOptions`]. +/// Windows-specific extensions to [`fs::OpenOptions`]. /// -/// [`OpenOptions`]: ../../../fs/struct.OpenOptions.html +/// [`fs::OpenOptions`]: ../../../../std/fs/struct.OpenOptions.html #[stable(feature = "open_options_ext", since = "1.10.0")] pub trait OpenOptionsExt { /// Overrides the `dwDesiredAccess` argument to the call to [`CreateFile`] @@ -281,13 +281,12 @@ impl OpenOptionsExt for OpenOptions { } } -/// Extension methods for [`fs::Metadata`] to access the raw fields contained -/// within. +/// Windows-specific extensions to [`fs::Metadata`]. /// /// The data members that this trait exposes correspond to the members /// of the [`BY_HANDLE_FILE_INFORMATION`] structure. /// -/// [`fs::Metadata`]: ../../../fs/struct.Metadata.html +/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html /// [`BY_HANDLE_FILE_INFORMATION`]: /// https://msdn.microsoft.com/en-us/library/windows/desktop/aa363788.aspx #[stable(feature = "metadata_ext", since = "1.1.0")] @@ -445,8 +444,11 @@ impl MetadataExt for Metadata { fn file_size(&self) -> u64 { self.as_inner().size() } } -/// Add support for the Windows specific fact that a symbolic link knows whether it is a file -/// or directory. +/// Windows-specific extensions to [`FileType`]. +/// +/// On Windows, a symbolic link knows whether it is a file or directory. +/// +/// [`FileType`]: ../../../../std/fs/struct.FileType.html #[unstable(feature = "windows_file_type_ext", issue = "0")] pub trait FileTypeExt { /// Returns whether this file type is a symbolic link that is also a directory. diff --git a/src/libstd/sys/windows/ext/process.rs b/src/libstd/sys/windows/ext/process.rs index 759f055c4b1..a02bcbe0c87 100644 --- a/src/libstd/sys/windows/ext/process.rs +++ b/src/libstd/sys/windows/ext/process.rs @@ -82,7 +82,9 @@ impl IntoRawHandle for process::ChildStderr { } } -/// Windows-specific extensions to `std::process::ExitStatus` +/// Windows-specific extensions to [`process::ExitStatus`]. +/// +/// [`process::ExitStatus`]: ../../../../std/process/struct.ExitStatus.html #[stable(feature = "exit_status_from", since = "1.12.0")] pub trait ExitStatusExt { /// Creates a new `ExitStatus` from the raw underlying `u32` return value of @@ -98,7 +100,9 @@ impl ExitStatusExt for process::ExitStatus { } } -/// Windows-specific extensions to the `std::process::Command` builder +/// Windows-specific extensions to the [`process::Command`] builder. +/// +/// [`process::Command`]: ../../../../std/process/struct.Command.html #[stable(feature = "windows_process_extensions", since = "1.16.0")] pub trait CommandExt { /// Sets the [process creation flags][1] to be passed to `CreateProcess`. diff --git a/src/libstd/sys_common/wtf8.rs b/src/libstd/sys_common/wtf8.rs index dda4e1bab3b..fe7e058091e 100644 --- a/src/libstd/sys_common/wtf8.rs +++ b/src/libstd/sys_common/wtf8.rs @@ -876,21 +876,7 @@ impl Hash for Wtf8 { } impl Wtf8 { - pub fn is_ascii(&self) -> bool { - self.bytes.is_ascii() - } - pub fn to_ascii_uppercase(&self) -> Wtf8Buf { - Wtf8Buf { bytes: self.bytes.to_ascii_uppercase() } - } - pub fn to_ascii_lowercase(&self) -> Wtf8Buf { - Wtf8Buf { bytes: self.bytes.to_ascii_lowercase() } - } - pub fn eq_ignore_ascii_case(&self, other: &Wtf8) -> bool { - self.bytes.eq_ignore_ascii_case(&other.bytes) - } - pub fn make_ascii_uppercase(&mut self) { self.bytes.make_ascii_uppercase() } - pub fn make_ascii_lowercase(&mut self) { self.bytes.make_ascii_lowercase() } } #[cfg(test)] diff --git a/src/libsyntax/Cargo.toml b/src/libsyntax/Cargo.toml index 8c24f36615b..d1a5ab0211b 100644 --- a/src/libsyntax/Cargo.toml +++ b/src/libsyntax/Cargo.toml @@ -14,6 +14,6 @@ serialize = { path = "../libserialize" } log = "0.4" scoped-tls = "0.1" syntax_pos = { path = "../libsyntax_pos" } -rustc_cratesio_shim = { path = "../librustc_cratesio_shim" } rustc_errors = { path = "../librustc_errors" } rustc_data_structures = { path = "../librustc_data_structures" } +rustc_target = { path = "../librustc_target" } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 46e3e20f58e..b590a4a6286 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -19,7 +19,7 @@ pub use util::parser::ExprPrecedence; use syntax_pos::{Span, DUMMY_SP}; use codemap::{respan, Spanned}; -use abi::Abi; +use rustc_target::spec::abi::Abi; use ext::hygiene::{Mark, SyntaxContext}; use print::pprust; use ptr::P; @@ -1255,8 +1255,8 @@ pub enum StrStyle { Cooked, /// A raw string, like `r##"foo"##` /// - /// The uint is the number of `#` symbols used - Raw(usize) + /// The value is the number of `#` symbols used. + Raw(u16) } /// A literal diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index c68a743303a..f0557277267 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -1045,6 +1045,30 @@ pub fn find_repr_attrs(diagnostic: &Handler, attr: &Attribute) -> Vec<ReprAttr> span_err!(diagnostic, item.span, E0589, "invalid `repr(align)` attribute: {}", literal_error); } + } else { + if let Some(meta_item) = item.meta_item() { + if meta_item.ident.name == "align" { + if let MetaItemKind::NameValue(ref value) = meta_item.node { + recognised = true; + let mut err = struct_span_err!(diagnostic, item.span, E0693, + "incorrect `repr(align)` attribute format"); + match value.node { + ast::LitKind::Int(int, ast::LitIntType::Unsuffixed) => { + err.span_suggestion(item.span, + "use parentheses instead", + format!("align({})", int)); + } + ast::LitKind::Str(s, _) => { + err.span_suggestion(item.span, + "use parentheses instead", + format!("align({})", s)); + } + _ => {} + } + err.emit(); + } + } + } } if !recognised { // Not a word we recognize diff --git a/src/libsyntax/diagnostic_list.rs b/src/libsyntax/diagnostic_list.rs index bb7988e64bc..c9cac1b1142 100644 --- a/src/libsyntax/diagnostic_list.rs +++ b/src/libsyntax/diagnostic_list.rs @@ -324,4 +324,5 @@ register_diagnostics! { E0589, // invalid `repr(align)` attribute E0629, // missing 'feature' (rustc_const_unstable) E0630, // rustc_const_unstable attribute must be paired with stable/unstable attribute + E0693, // incorrect `repr(align)` attribute format } diff --git a/src/libsyntax/edition.rs b/src/libsyntax/edition.rs index e579fc74b42..3fc1c279f5a 100644 --- a/src/libsyntax/edition.rs +++ b/src/libsyntax/edition.rs @@ -24,20 +24,19 @@ pub enum Edition { // when adding new editions, be sure to update: // - // - the list in the `parse_edition` static in librustc::session::config + // - Update the `ALL_EDITIONS` const + // - Update the EDITION_NAME_LIST const // - add a `rust_####()` function to the session // - update the enum in Cargo's sources as well - // - // When -Zedition becomes --edition, there will - // also be a check for the edition being nightly-only - // somewhere. That will need to be updated - // whenever we're stabilizing/introducing a new edition - // as well as changing the default Cargo template. } // must be in order from oldest to newest pub const ALL_EDITIONS: &[Edition] = &[Edition::Edition2015, Edition::Edition2018]; +pub const EDITION_NAME_LIST: &'static str = "2015|2018"; + +pub const DEFAULT_EDITION: Edition = Edition::Edition2015; + impl fmt::Display for Edition { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let s = match *self { @@ -62,6 +61,13 @@ impl Edition { Edition::Edition2018 => "rust_2018_preview", } } + + pub fn is_stable(&self) -> bool { + match *self { + Edition::Edition2015 => true, + Edition::Edition2018 => false, + } + } } impl FromStr for Edition { diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 36244f0a3c4..0b64189b2bc 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use abi::Abi; +use rustc_target::spec::abi::Abi; use ast::{self, Ident, Generics, Expr, BlockCheckMode, UnOp, PatKind}; use attr; use syntax_pos::{Pos, Span, DUMMY_SP}; @@ -139,6 +139,7 @@ pub trait AstBuilder { fn expr_usize(&self, span: Span, i: usize) -> P<ast::Expr>; fn expr_isize(&self, sp: Span, i: isize) -> P<ast::Expr>; fn expr_u8(&self, sp: Span, u: u8) -> P<ast::Expr>; + fn expr_u16(&self, sp: Span, u: u16) -> P<ast::Expr>; fn expr_u32(&self, sp: Span, u: u32) -> P<ast::Expr>; fn expr_bool(&self, sp: Span, value: bool) -> P<ast::Expr>; @@ -708,6 +709,10 @@ impl<'a> AstBuilder for ExtCtxt<'a> { self.expr_lit(sp, ast::LitKind::Int(u as u128, ast::LitIntType::Unsigned(ast::UintTy::U32))) } + fn expr_u16(&self, sp: Span, u: u16) -> P<ast::Expr> { + self.expr_lit(sp, ast::LitKind::Int(u as u128, + ast::LitIntType::Unsigned(ast::UintTy::U16))) + } fn expr_u8(&self, sp: Span, u: u8) -> P<ast::Expr> { self.expr_lit(sp, ast::LitKind::Int(u as u128, ast::LitIntType::Unsigned(ast::UintTy::U8))) } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index ddfffe06cfd..2f3b35c33f3 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -521,6 +521,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { Some(kind.expect_from_annotatables(items)) } AttrProcMacro(ref mac) => { + self.gate_proc_macro_attr_item(attr.span, &item); let item_tok = TokenTree::Token(DUMMY_SP, Token::interpolated(match item { Annotatable::Item(item) => token::NtItem(item), Annotatable::TraitItem(item) => token::NtTraitItem(item.into_inner()), @@ -529,7 +530,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> { Annotatable::Stmt(stmt) => token::NtStmt(stmt.into_inner()), Annotatable::Expr(expr) => token::NtExpr(expr), })).into(); - let tok_result = mac.expand(self.cx, attr.span, attr.tokens, item_tok); + let input = self.extract_proc_macro_attr_input(attr.tokens, attr.span); + let tok_result = mac.expand(self.cx, attr.span, input, item_tok); self.parse_expansion(tok_result, kind, &attr.path, attr.span) } ProcMacroDerive(..) | BuiltinDerive(..) => { @@ -546,6 +548,49 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } } + fn extract_proc_macro_attr_input(&self, tokens: TokenStream, span: Span) -> TokenStream { + let mut trees = tokens.trees(); + match trees.next() { + Some(TokenTree::Delimited(_, delim)) => { + if trees.next().is_none() { + return delim.tts.into() + } + } + Some(TokenTree::Token(..)) => {} + None => return TokenStream::empty(), + } + self.cx.span_err(span, "custom attribute invocations must be \ + of the form #[foo] or #[foo(..)], the macro name must only be \ + followed by a delimiter token"); + TokenStream::empty() + } + + fn gate_proc_macro_attr_item(&self, span: Span, item: &Annotatable) { + let (kind, gate) = match *item { + Annotatable::Item(ref item) => { + match item.node { + ItemKind::Mod(_) if self.cx.ecfg.proc_macro_mod() => return, + ItemKind::Mod(_) => ("modules", "proc_macro_mod"), + _ => return, + } + } + Annotatable::TraitItem(_) => return, + Annotatable::ImplItem(_) => return, + Annotatable::ForeignItem(_) => return, + Annotatable::Stmt(_) | + Annotatable::Expr(_) if self.cx.ecfg.proc_macro_expr() => return, + Annotatable::Stmt(_) => ("statements", "proc_macro_expr"), + Annotatable::Expr(_) => ("expressions", "proc_macro_expr"), + }; + emit_feature_err( + self.cx.parse_sess, + gate, + span, + GateIssue::Language, + &format!("custom attributes cannot be applied to {}", kind), + ); + } + /// Expand a macro invocation. Returns the result of expansion. fn expand_bang_invoc(&mut self, invoc: Invocation, @@ -672,6 +717,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { self.cx.trace_macros_diag(); kind.dummy(span) } else { + self.gate_proc_macro_expansion_kind(span, kind); invoc.expansion_data.mark.set_expn_info(ExpnInfo { call_site: span, callee: NameAndSpan { @@ -702,6 +748,30 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } } + fn gate_proc_macro_expansion_kind(&self, span: Span, kind: ExpansionKind) { + let kind = match kind { + ExpansionKind::Expr => "expressions", + ExpansionKind::OptExpr => "expressions", + ExpansionKind::Pat => "patterns", + ExpansionKind::Ty => "types", + ExpansionKind::Stmts => "statements", + ExpansionKind::Items => return, + ExpansionKind::TraitItems => return, + ExpansionKind::ImplItems => return, + ExpansionKind::ForeignItems => return, + }; + if self.cx.ecfg.proc_macro_non_items() { + return + } + emit_feature_err( + self.cx.parse_sess, + "proc_macro_non_items", + span, + GateIssue::Language, + &format!("procedural macros cannot be expanded to {}", kind), + ); + } + /// Expand a derive invocation. Returns the result of expansion. fn expand_derive_invoc(&mut self, invoc: Invocation, @@ -1416,6 +1486,9 @@ impl<'feat> ExpansionConfig<'feat> { fn enable_custom_derive = custom_derive, fn proc_macro_enabled = proc_macro, fn macros_in_extern_enabled = macros_in_extern, + fn proc_macro_mod = proc_macro_mod, + fn proc_macro_expr = proc_macro_expr, + fn proc_macro_non_items = proc_macro_non_items, } } diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index 3303955d398..eeed291c0ca 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -623,7 +623,7 @@ fn expr_mk_token(cx: &ExtCtxt, sp: Span, tok: &token::Token) -> P<ast::Expr> { ($name: expr, $suffix: expr, $content: expr $(, $count: expr)*) => {{ let name = mk_name(cx, sp, ast::Ident::with_empty_ctxt($content)); let inner = cx.expr_call(sp, mk_token_path(cx, sp, $name), vec![ - name $(, cx.expr_usize(sp, $count))* + name $(, cx.expr_u16(sp, $count))* ]); let suffix = match $suffix { Some(name) => cx.expr_some(sp, mk_name(cx, sp, ast::Ident::with_empty_ctxt(name))), diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 7b7cfe5eea0..a4a83712a08 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -25,7 +25,7 @@ use self::AttributeType::*; use self::AttributeGate::*; -use abi::Abi; +use rustc_target::spec::abi::Abi; use ast::{self, NodeId, PatKind, RangeEnd}; use attr; use edition::{ALL_EDITIONS, Edition}; @@ -272,6 +272,9 @@ declare_features! ( // Allows cfg(target_has_atomic = "..."). (active, cfg_target_has_atomic, "1.9.0", Some(32976), None), + // The `!` type. Does not imply exhaustive_patterns (below) any more. + (active, never_type, "1.13.0", Some(35121), None), + // Allows exhaustive pattern matching on types that contain uninhabited types. (active, exhaustive_patterns, "1.13.0", None, None), @@ -372,9 +375,6 @@ declare_features! ( // Future-proofing enums/structs with #[non_exhaustive] attribute (RFC 2008) (active, non_exhaustive, "1.22.0", Some(44109), None), - // Trait object syntax with `dyn` prefix - (active, dyn_trait, "1.22.0", Some(44662), Some(Edition::Edition2018)), - // `crate` as visibility modifier, synonymous to `pub(crate)` (active, crate_visibility_modifier, "1.23.0", Some(45388), Some(Edition::Edition2018)), @@ -451,6 +451,18 @@ declare_features! ( (active, mmx_target_feature, "1.27.0", None, None), (active, sse4a_target_feature, "1.27.0", None, None), (active, tbm_target_feature, "1.27.0", None, None), + + // Allows macro invocations of the form `#[foo::bar]` + (active, proc_macro_path_invoc, "1.27.0", None, None), + + // Allows macro invocations on modules expressions and statements and + // procedural macros to expand to non-items. + (active, proc_macro_mod, "1.27.0", None, None), + (active, proc_macro_expr, "1.27.0", None, None), + (active, proc_macro_non_items, "1.27.0", None, None), + + // #[doc(alias = "...")] + (active, doc_alias, "1.27.0", Some(50146), None), ); declare_features! ( @@ -577,6 +589,8 @@ declare_features! ( (accepted, cfg_target_feature, "1.27.0", Some(29717), None), // Allows #[target_feature(...)] (accepted, target_feature, "1.27.0", None, None), + // Trait object syntax with `dyn` prefix + (accepted, dyn_trait, "1.27.0", Some(44662), None), ); // If you change this, please modify src/doc/unstable-book as well. You must @@ -921,7 +935,7 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG "the `#[naked]` attribute \ is an experimental feature", cfg_fn!(naked_functions))), - ("target_feature", Normal, Ungated), + ("target_feature", Whitelisted, Ungated), ("export_name", Whitelisted, Ungated), ("inline", Whitelisted, Ungated), ("link", Whitelisted, Ungated), @@ -1227,10 +1241,9 @@ fn leveled_feature_err<'a>(sess: &'a ParseSess, feature: &str, span: Span, issue GateIssue::Library(lib) => lib, }; - let explanation = if let Some(n) = issue { - format!("{} (see issue #{})", explain, n) - } else { - explain.to_owned() + let explanation = match issue { + None | Some(0) => explain.to_owned(), + Some(n) => format!("{} (see issue #{})", explain, n) }; let mut err = match level { @@ -1446,6 +1459,10 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { gate_feature_post!(&self, doc_spotlight, attr.span, "#[doc(spotlight)] is experimental" ); + } else if content.iter().any(|c| c.check_name("alias")) { + gate_feature_post!(&self, doc_alias, attr.span, + "#[doc(alias = \"...\")] is experimental" + ); } } } @@ -1635,9 +1652,9 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { ast::TyKind::BareFn(ref bare_fn_ty) => { self.check_abi(bare_fn_ty.abi, ty.span); } - ast::TyKind::TraitObject(_, ast::TraitObjectSyntax::Dyn) => { - gate_feature_post!(&self, dyn_trait, ty.span, - "`dyn Trait` syntax is unstable"); + ast::TyKind::Never => { + gate_feature_post!(&self, never_type, ty.span, + "The `!` type is experimental"); } _ => {} } @@ -1745,8 +1762,8 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } } ast::TraitItemKind::Type(_, ref default) => { - // We use two if statements instead of something like match guards so that both - // of these errors can be emitted if both cases apply. + // We use three if statements instead of something like match guards so that all + // of these errors can be emitted if all cases apply. if default.is_some() { gate_feature_post!(&self, associated_type_defaults, ti.span, "associated type defaults are unstable"); @@ -1755,6 +1772,10 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { gate_feature_post!(&self, generic_associated_types, ti.span, "generic associated types are unstable"); } + if !ti.generics.where_clause.predicates.is_empty() { + gate_feature_post!(&self, generic_associated_types, ti.span, + "where clauses on associated types are unstable"); + } } _ => {} } diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index ad98e2a6b71..870ce1926ad 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -28,10 +28,6 @@ #![recursion_limit="256"] -// See librustc_cratesio_shim/Cargo.toml for a comment explaining this. -#[allow(unused_extern_crates)] -extern crate rustc_cratesio_shim; - #[macro_use] extern crate bitflags; extern crate core; extern crate serialize; @@ -39,6 +35,7 @@ extern crate serialize; pub extern crate rustc_errors as errors; extern crate syntax_pos; extern crate rustc_data_structures; +extern crate rustc_target; #[macro_use] extern crate scoped_tls; extern crate serialize as rustc_serialize; // used by deriving @@ -138,7 +135,6 @@ pub mod syntax { pub use ast; } -pub mod abi; pub mod ast; pub mod attr; pub mod codemap; diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index cb3323c7eca..22a0261d8c6 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -133,12 +133,12 @@ impl<'a> StringReader<'a> { Ok(ret_val) } - fn fail_unterminated_raw_string(&self, pos: BytePos, hash_count: usize) { + fn fail_unterminated_raw_string(&self, pos: BytePos, hash_count: u16) { let mut err = self.struct_span_fatal(pos, pos, "unterminated raw string"); err.span_label(self.mk_sp(pos, pos), "unterminated raw string"); if hash_count > 0 { err.note(&format!("this raw string should be terminated with `\"{}`", - "#".repeat(hash_count))); + "#".repeat(hash_count as usize))); } err.emit(); FatalError.raise(); @@ -1439,7 +1439,7 @@ impl<'a> StringReader<'a> { 'r' => { let start_bpos = self.pos; self.bump(); - let mut hash_count = 0; + let mut hash_count: u16 = 0; while self.ch_is('#') { self.bump(); hash_count += 1; diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index ff63c9a5c6d..ff09c6aa2f0 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -271,8 +271,16 @@ pub fn char_lit(lit: &str, diag: Option<(Span, &Handler)>) -> (char, isize) { 'u' => { assert_eq!(lit.as_bytes()[2], b'{'); let idx = lit.find('}').unwrap(); - let s = &lit[3..idx].chars().filter(|&c| c != '_').collect::<String>(); - let v = u32::from_str_radix(&s, 16).unwrap(); + + // All digits and '_' are ascii, so treat each byte as a char. + let mut v: u32 = 0; + for c in lit[3..idx].bytes() { + let c = char::from(c); + if c != '_' { + let x = c.to_digit(16).unwrap(); + v = v.checked_mul(16).unwrap().checked_add(x).unwrap(); + } + } let c = char::from_u32(v).unwrap_or_else(|| { if let Some((span, diag)) = diag { let mut diag = diag.struct_span_err(span, "invalid unicode character escape"); @@ -670,7 +678,7 @@ mod tests { use syntax_pos::{self, Span, BytePos, Pos, NO_EXPANSION}; use codemap::{respan, Spanned}; use ast::{self, Ident, PatKind}; - use abi::Abi; + use rustc_target::spec::abi::Abi; use attr::first_attr_value_str_by_name; use parse; use parse::parser::Parser; diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index a7a9ce74512..324cadc84e8 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use abi::{self, Abi}; +use rustc_target::spec::abi::{self, Abi}; use ast::{AngleBracketedParameterData, ParenthesizedParameterData, AttrStyle, BareFnTy}; use ast::{RegionTyParamBound, TraitTyParamBound, TraitBoundModifier}; use ast::Unsafety; @@ -589,7 +589,8 @@ impl<'a> Parser<'a> { self.token_cursor.next() }; if next.sp == syntax_pos::DUMMY_SP { - next.sp = self.prev_span; + // Tweak the location for better diagnostics, but keep syntactic context intact. + next.sp = self.prev_span.with_ctxt(next.sp.ctxt()); } next } @@ -5758,18 +5759,33 @@ impl<'a> Parser<'a> { vis: Visibility, attrs: Vec<Attribute> ) -> PResult<'a, StructField> { + let mut seen_comma: bool = false; let a_var = self.parse_name_and_ty(lo, vis, attrs)?; + if self.token == token::Comma { + seen_comma = true; + } match self.token { token::Comma => { self.bump(); } token::CloseDelim(token::Brace) => {} token::DocComment(_) => { + let previous_span = self.prev_span; let mut err = self.span_fatal_err(self.span, Error::UselessDocComment); self.bump(); // consume the doc comment - if self.eat(&token::Comma) || self.token == token::CloseDelim(token::Brace) { + let comma_after_doc_seen = self.eat(&token::Comma); + // `seen_comma` is always false, because we are inside doc block + // condition is here to make code more readable + if seen_comma == false && comma_after_doc_seen == true { + seen_comma = true; + } + if comma_after_doc_seen || self.token == token::CloseDelim(token::Brace) { err.emit(); } else { + if seen_comma == false { + let sp = self.sess.codemap().next_point(previous_span); + err.span_suggestion(sp, "missing comma here", ",".into()); + } return Err(err); } } diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 0913ed86147..938711ca1d4 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -26,6 +26,7 @@ use tokenstream::{TokenStream, TokenTree}; use tokenstream; use std::{cmp, fmt}; +use std::mem; use rustc_data_structures::sync::{Lrc, Lock}; #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)] @@ -72,9 +73,9 @@ pub enum Lit { Integer(ast::Name), Float(ast::Name), Str_(ast::Name), - StrRaw(ast::Name, usize), /* raw str delimited by n hash symbols */ + StrRaw(ast::Name, u16), /* raw str delimited by n hash symbols */ ByteStr(ast::Name), - ByteStrRaw(ast::Name, usize), /* raw byte str delimited by n hash symbols */ + ByteStrRaw(ast::Name, u16), /* raw byte str delimited by n hash symbols */ } impl Lit { @@ -88,6 +89,12 @@ impl Lit { ByteStr(_) | ByteStrRaw(..) => "byte string" } } + + // See comments in `interpolated_to_tokenstream` for why we care about + // *probably* equal here rather than actual equality + fn probably_equal_for_proc_macro(&self, other: &Lit) -> bool { + mem::discriminant(self) == mem::discriminant(other) + } } pub(crate) fn ident_can_begin_expr(ident: ast::Ident, is_raw: bool) -> bool { @@ -270,9 +277,10 @@ impl Token { DotDot | DotDotDot | DotDotEq | // range notation Lt | BinOp(Shl) | // associated path ModSep | // global path + Lifetime(..) | // labeled loop Pound => true, // expression attributes Interpolated(ref nt) => match nt.0 { - NtIdent(..) | NtExpr(..) | NtBlock(..) | NtPath(..) => true, + NtIdent(..) | NtExpr(..) | NtBlock(..) | NtPath(..) | NtLifetime(..) => true, _ => false, }, _ => false, @@ -530,14 +538,6 @@ impl Token { // stream they came from. Here we attempt to extract these // lossless token streams before we fall back to the // stringification. - // - // During early phases of the compiler, though, the AST could - // get modified directly (e.g. attributes added or removed) and - // the internal cache of tokens my not be invalidated or - // updated. Consequently if the "lossless" token stream - // disagrees with our actuall stringification (which has - // historically been much more battle-tested) then we go with - // the lossy stream anyway (losing span information). let mut tokens = None; match nt.0 { @@ -569,13 +569,96 @@ impl Token { let source = pprust::token_to_string(self); parse_stream_from_source_str(FileName::MacroExpansion, source, sess, Some(span)) }); + + // During early phases of the compiler the AST could get modified + // directly (e.g. attributes added or removed) and the internal cache + // of tokens my not be invalidated or updated. Consequently if the + // "lossless" token stream disagrees with our actual stringification + // (which has historically been much more battle-tested) then we go + // with the lossy stream anyway (losing span information). + // + // Note that the comparison isn't `==` here to avoid comparing spans, + // but it *also* is a "probable" equality which is a pretty weird + // definition. We mostly want to catch actual changes to the AST + // like a `#[cfg]` being processed or some weird `macro_rules!` + // expansion. + // + // What we *don't* want to catch is the fact that a user-defined + // literal like `0xf` is stringified as `15`, causing the cached token + // stream to not be literal `==` token-wise (ignoring spans) to the + // token stream we got from stringification. + // + // Instead the "probably equal" check here is "does each token + // recursively have the same discriminant?" We basically don't look at + // the token values here and assume that such fine grained modifications + // of token streams doesn't happen. if let Some(tokens) = tokens { - if tokens.eq_unspanned(&tokens_for_real) { + if tokens.probably_equal_for_proc_macro(&tokens_for_real) { return tokens } } return tokens_for_real } + + // See comments in `interpolated_to_tokenstream` for why we care about + // *probably* equal here rather than actual equality + pub fn probably_equal_for_proc_macro(&self, other: &Token) -> bool { + if mem::discriminant(self) != mem::discriminant(other) { + return false + } + match (self, other) { + (&Eq, &Eq) | + (&Lt, &Lt) | + (&Le, &Le) | + (&EqEq, &EqEq) | + (&Ne, &Ne) | + (&Ge, &Ge) | + (&Gt, &Gt) | + (&AndAnd, &AndAnd) | + (&OrOr, &OrOr) | + (&Not, &Not) | + (&Tilde, &Tilde) | + (&At, &At) | + (&Dot, &Dot) | + (&DotDot, &DotDot) | + (&DotDotDot, &DotDotDot) | + (&DotDotEq, &DotDotEq) | + (&DotEq, &DotEq) | + (&Comma, &Comma) | + (&Semi, &Semi) | + (&Colon, &Colon) | + (&ModSep, &ModSep) | + (&RArrow, &RArrow) | + (&LArrow, &LArrow) | + (&FatArrow, &FatArrow) | + (&Pound, &Pound) | + (&Dollar, &Dollar) | + (&Question, &Question) | + (&Whitespace, &Whitespace) | + (&Comment, &Comment) | + (&Eof, &Eof) => true, + + (&BinOp(a), &BinOp(b)) | + (&BinOpEq(a), &BinOpEq(b)) => a == b, + + (&OpenDelim(a), &OpenDelim(b)) | + (&CloseDelim(a), &CloseDelim(b)) => a == b, + + (&DocComment(a), &DocComment(b)) | + (&Shebang(a), &Shebang(b)) => a == b, + + (&Lifetime(a), &Lifetime(b)) => a.name == b.name, + (&Ident(a, b), &Ident(c, d)) => a.name == c.name && b == d, + + (&Literal(ref a, b), &Literal(ref c, d)) => { + b == d && a.probably_equal_for_proc_macro(c) + } + + (&Interpolated(_), &Interpolated(_)) => false, + + _ => panic!("forgot to add a token?"), + } + } } #[derive(Clone, RustcEncodable, RustcDecodable, Eq, Hash)] diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 3741850b8a9..88860df10e2 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -10,7 +10,7 @@ pub use self::AnnNode::*; -use abi::{self, Abi}; +use rustc_target::spec::abi::{self, Abi}; use ast::{self, BlockCheckMode, PatKind, RangeEnd, RangeSyntax}; use ast::{SelfKind, RegionTyParamBound, TraitTyParamBound, TraitBoundModifier}; use ast::Attribute; @@ -234,11 +234,11 @@ pub fn token_to_string(tok: &Token) -> String { token::Integer(c) => c.to_string(), token::Str_(s) => format!("\"{}\"", s), token::StrRaw(s, n) => format!("r{delim}\"{string}\"{delim}", - delim=repeat("#", n), + delim=repeat("#", n as usize), string=s), token::ByteStr(v) => format!("b\"{}\"", v), token::ByteStrRaw(s, n) => format!("br{delim}\"{string}\"{delim}", - delim=repeat("#", n), + delim=repeat("#", n as usize), string=s), }; @@ -660,7 +660,7 @@ pub trait PrintState<'a> { } ast::StrStyle::Raw(n) => { (format!("r{delim}\"{string}\"{delim}", - delim=repeat("#", n), + delim=repeat("#", n as usize), string=st)) } }; diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs index bba7a2d7377..53dc19ba37d 100644 --- a/src/libsyntax/std_inject.rs +++ b/src/libsyntax/std_inject.rs @@ -57,7 +57,8 @@ pub fn maybe_inject_crates_ref(mut krate: ast::Crate, alt_std_name: Option<&str> &["std"] }; - for name in names { + // .rev() to preserve ordering above in combination with insert(0, ...) + for name in names.iter().rev() { krate.module.items.insert(0, P(ast::Item { attrs: vec![attr::mk_attr_outer(DUMMY_SP, attr::mk_attr_id(), diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index fd2e760e9be..1734692f9e7 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -320,37 +320,48 @@ fn ignored_span(cx: &TestCtxt, sp: Span) -> Span { #[derive(PartialEq)] enum HasTestSignature { Yes, - No, + No(BadTestSignature), +} + +#[derive(PartialEq)] +enum BadTestSignature { NotEvenAFunction, + WrongTypeSignature, + NoArgumentsAllowed, + ShouldPanicOnlyWithNoArgs, } fn is_test_fn(cx: &TestCtxt, i: &ast::Item) -> bool { let has_test_attr = attr::contains_name(&i.attrs, "test"); fn has_test_signature(cx: &TestCtxt, i: &ast::Item) -> HasTestSignature { + let has_should_panic_attr = attr::contains_name(&i.attrs, "should_panic"); match i.node { ast::ItemKind::Fn(ref decl, _, _, _, ref generics, _) => { // If the termination trait is active, the compiler will check that the output // type implements the `Termination` trait as `libtest` enforces that. - let output_matches = if cx.features.termination_trait_test { - true - } else { - let no_output = match decl.output { - ast::FunctionRetTy::Default(..) => true, - ast::FunctionRetTy::Ty(ref t) if t.node == ast::TyKind::Tup(vec![]) => true, - _ => false - }; - - no_output && !generics.is_parameterized() + let has_output = match decl.output { + ast::FunctionRetTy::Default(..) => false, + ast::FunctionRetTy::Ty(ref t) if t.node == ast::TyKind::Tup(vec![]) => false, + _ => true }; - if decl.inputs.is_empty() && output_matches { - Yes - } else { - No + if !decl.inputs.is_empty() { + return No(BadTestSignature::NoArgumentsAllowed); + } + + match (has_output, cx.features.termination_trait_test, has_should_panic_attr) { + (true, true, true) => No(BadTestSignature::ShouldPanicOnlyWithNoArgs), + (true, true, false) => if generics.is_parameterized() { + No(BadTestSignature::WrongTypeSignature) + } else { + Yes + }, + (true, false, _) => No(BadTestSignature::WrongTypeSignature), + (false, _, _) => Yes } } - _ => NotEvenAFunction, + _ => No(BadTestSignature::NotEvenAFunction), } } @@ -358,18 +369,20 @@ fn is_test_fn(cx: &TestCtxt, i: &ast::Item) -> bool { let diag = cx.span_diagnostic; match has_test_signature(cx, i) { Yes => true, - No => { - if cx.features.termination_trait_test { - diag.span_err(i.span, "functions used as tests can not have any arguments"); - } else { - diag.span_err(i.span, "functions used as tests must have signature fn() -> ()"); + No(cause) => { + match cause { + BadTestSignature::NotEvenAFunction => + diag.span_err(i.span, "only functions may be used as tests"), + BadTestSignature::WrongTypeSignature => + diag.span_err(i.span, + "functions used as tests must have signature fn() -> ()"), + BadTestSignature::NoArgumentsAllowed => + diag.span_err(i.span, "functions used as tests can not have any arguments"), + BadTestSignature::ShouldPanicOnlyWithNoArgs => + diag.span_err(i.span, "functions using `#[should_panic]` must return `()`"), } false - }, - NotEvenAFunction => { - diag.span_err(i.span, "only functions may be used as tests"); - false - }, + } } } else { false @@ -407,7 +420,7 @@ fn is_bench_fn(cx: &TestCtxt, i: &ast::Item) -> bool { // well before resolve, can't get too deep. input_cnt == 1 && output_matches } - _ => false + _ => false } } @@ -550,7 +563,9 @@ fn mk_main(cx: &mut TestCtxt) -> P<ast::Item> { let main = ast::ItemKind::Fn(ecx.fn_decl(vec![], ast::FunctionRetTy::Ty(main_ret_ty)), ast::Unsafety::Normal, dummy_spanned(ast::Constness::NotConst), - ::abi::Abi::Rust, ast::Generics::default(), main_body); + ::rustc_target::spec::abi::Abi::Rust, + ast::Generics::default(), + main_body); P(ast::Item { ident: Ident::from_str("main"), attrs: vec![main_attr], diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs index 6ac04b3cdf6..e2b5c4e1adf 100644 --- a/src/libsyntax/tokenstream.rs +++ b/src/libsyntax/tokenstream.rs @@ -124,6 +124,24 @@ impl TokenTree { } } + // See comments in `interpolated_to_tokenstream` for why we care about + // *probably* equal here rather than actual equality + // + // This is otherwise the same as `eq_unspanned`, only recursing with a + // different method. + pub fn probably_equal_for_proc_macro(&self, other: &TokenTree) -> bool { + match (self, other) { + (&TokenTree::Token(_, ref tk), &TokenTree::Token(_, ref tk2)) => { + tk.probably_equal_for_proc_macro(tk2) + } + (&TokenTree::Delimited(_, ref dl), &TokenTree::Delimited(_, ref dl2)) => { + dl.delim == dl2.delim && + dl.stream().probably_equal_for_proc_macro(&dl2.stream()) + } + (_, _) => false, + } + } + /// Retrieve the TokenTree's span. pub fn span(&self) -> Span { match *self { @@ -250,6 +268,22 @@ impl TokenStream { t1.next().is_none() && t2.next().is_none() } + // See comments in `interpolated_to_tokenstream` for why we care about + // *probably* equal here rather than actual equality + // + // This is otherwise the same as `eq_unspanned`, only recursing with a + // different method. + pub fn probably_equal_for_proc_macro(&self, other: &TokenStream) -> bool { + let mut t1 = self.trees(); + let mut t2 = other.trees(); + for (t1, t2) in t1.by_ref().zip(t2.by_ref()) { + if !t1.probably_equal_for_proc_macro(&t2) { + return false; + } + } + t1.next().is_none() && t2.next().is_none() + } + /// Precondition: `self` consists of a single token tree. /// Returns true if the token tree is a joint operation w.r.t. `proc_macro::TokenNode`. pub fn as_tree(self) -> (TokenTree, bool /* joint? */) { diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 8743840e443..40d59d3ff8b 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -23,7 +23,7 @@ //! instance, a walker looking for item names in a module will miss all of //! those that are created by the expansion of a macro. -use abi::Abi; +use rustc_target::spec::abi::Abi; use ast::*; use syntax_pos::Span; use codemap::Spanned; diff --git a/src/libsyntax_ext/Cargo.toml b/src/libsyntax_ext/Cargo.toml index d8eeb5ed255..1676757d9b8 100644 --- a/src/libsyntax_ext/Cargo.toml +++ b/src/libsyntax_ext/Cargo.toml @@ -14,4 +14,5 @@ proc_macro = { path = "../libproc_macro" } rustc_errors = { path = "../librustc_errors" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } -rustc_data_structures = { path = "../librustc_data_structures" } \ No newline at end of file +rustc_data_structures = { path = "../librustc_data_structures" } +rustc_target = { path = "../librustc_target" } \ No newline at end of file diff --git a/src/libsyntax_ext/deriving/cmp/ord.rs b/src/libsyntax_ext/deriving/cmp/ord.rs index 1a392ac3765..99b6f752e94 100644 --- a/src/libsyntax_ext/deriving/cmp/ord.rs +++ b/src/libsyntax_ext/deriving/cmp/ord.rs @@ -38,7 +38,7 @@ pub fn expand_deriving_ord(cx: &mut ExtCtxt, name: "cmp", generics: LifetimeBounds::empty(), explicit_self: borrowed_explicit_self(), - args: vec![borrowed_self()], + args: vec![(borrowed_self(), "other")], ret_ty: Literal(path_std!(cx, cmp::Ordering)), attributes: attrs, is_unsafe: false, @@ -64,7 +64,7 @@ pub fn ordering_collapsed(cx: &mut ExtCtxt, } pub fn cs_cmp(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P<Expr> { - let test_id = cx.ident_of("__cmp"); + let test_id = cx.ident_of("cmp").gensym(); let equals_path = cx.path_global(span, cx.std_path(&["cmp", "Ordering", "Equal"])); let cmp_path = cx.std_path(&["cmp", "Ord", "cmp"]); @@ -77,9 +77,9 @@ pub fn cs_cmp(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P<Expr> { // ::std::cmp::Ordering::Equal => { // ... // } - // __cmp => __cmp + // cmp => cmp // }, - // __cmp => __cmp + // cmp => cmp // } // cs_fold(// foldr nests the if-elses correctly, leaving the first field @@ -88,7 +88,7 @@ pub fn cs_cmp(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P<Expr> { |cx, span, old, self_f, other_fs| { // match new { // ::std::cmp::Ordering::Equal => old, - // __cmp => __cmp + // cmp => cmp // } let new = { diff --git a/src/libsyntax_ext/deriving/cmp/partial_eq.rs b/src/libsyntax_ext/deriving/cmp/partial_eq.rs index 81ca7e73228..c259733d81a 100644 --- a/src/libsyntax_ext/deriving/cmp/partial_eq.rs +++ b/src/libsyntax_ext/deriving/cmp/partial_eq.rs @@ -78,7 +78,7 @@ pub fn expand_deriving_partial_eq(cx: &mut ExtCtxt, name: $name, generics: LifetimeBounds::empty(), explicit_self: borrowed_explicit_self(), - args: vec![borrowed_self()], + args: vec![(borrowed_self(), "other")], ret_ty: Literal(path_local!(bool)), attributes: attrs, is_unsafe: false, diff --git a/src/libsyntax_ext/deriving/cmp/partial_ord.rs b/src/libsyntax_ext/deriving/cmp/partial_ord.rs index 9560fd0570a..d71527fd0ed 100644 --- a/src/libsyntax_ext/deriving/cmp/partial_ord.rs +++ b/src/libsyntax_ext/deriving/cmp/partial_ord.rs @@ -34,7 +34,7 @@ pub fn expand_deriving_partial_ord(cx: &mut ExtCtxt, name: $name, generics: LifetimeBounds::empty(), explicit_self: borrowed_explicit_self(), - args: vec![borrowed_self()], + args: vec![(borrowed_self(), "other")], ret_ty: Literal(path_local!(bool)), attributes: attrs, is_unsafe: false, @@ -59,7 +59,7 @@ pub fn expand_deriving_partial_ord(cx: &mut ExtCtxt, name: "partial_cmp", generics: LifetimeBounds::empty(), explicit_self: borrowed_explicit_self(), - args: vec![borrowed_self()], + args: vec![(borrowed_self(), "other")], ret_ty, attributes: attrs, is_unsafe: false, @@ -123,7 +123,7 @@ pub fn some_ordering_collapsed(cx: &mut ExtCtxt, } pub fn cs_partial_cmp(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P<Expr> { - let test_id = cx.ident_of("__cmp"); + let test_id = cx.ident_of("cmp").gensym(); let ordering = cx.path_global(span, cx.std_path(&["cmp", "Ordering", "Equal"])); let ordering_expr = cx.expr_path(ordering.clone()); let equals_expr = cx.expr_some(span, ordering_expr); @@ -138,9 +138,9 @@ pub fn cs_partial_cmp(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P< // ::std::option::Option::Some(::std::cmp::Ordering::Equal) => { // ... // } - // __cmp => __cmp + // cmp => cmp // }, - // __cmp => __cmp + // cmp => cmp // } // cs_fold(// foldr nests the if-elses correctly, leaving the first field @@ -149,7 +149,7 @@ pub fn cs_partial_cmp(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P< |cx, span, old, self_f, other_fs| { // match new { // Some(::std::cmp::Ordering::Equal) => old, - // __cmp => __cmp + // cmp => cmp // } let new = { diff --git a/src/libsyntax_ext/deriving/debug.rs b/src/libsyntax_ext/deriving/debug.rs index c007285cd85..b546f5df157 100644 --- a/src/libsyntax_ext/deriving/debug.rs +++ b/src/libsyntax_ext/deriving/debug.rs @@ -40,7 +40,7 @@ pub fn expand_deriving_debug(cx: &mut ExtCtxt, name: "fmt", generics: LifetimeBounds::empty(), explicit_self: borrowed_explicit_self(), - args: vec![fmtr], + args: vec![(fmtr, "f")], ret_ty: Literal(path_std!(cx, fmt::Result)), attributes: Vec::new(), is_unsafe: false, @@ -70,7 +70,7 @@ fn show_substructure(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P<E // We want to make sure we have the ctxt set so that we can use unstable methods let span = span.with_ctxt(cx.backtrace()); let name = cx.expr_lit(span, ast::LitKind::Str(ident.name, ast::StrStyle::Cooked)); - let builder = Ident::from_str("__debug_trait_builder"); + let builder = Ident::from_str("debug_trait_builder").gensym(); let builder_expr = cx.expr_ident(span, builder.clone()); let fmt = substr.nonself_args[0].clone(); diff --git a/src/libsyntax_ext/deriving/decodable.rs b/src/libsyntax_ext/deriving/decodable.rs index 46dada256b8..7618fe63ab3 100644 --- a/src/libsyntax_ext/deriving/decodable.rs +++ b/src/libsyntax_ext/deriving/decodable.rs @@ -67,8 +67,8 @@ fn expand_deriving_decodable_imp(cx: &mut ExtCtxt, PathKind::Global)])], }, explicit_self: None, - args: vec![Ptr(Box::new(Literal(Path::new_local(typaram))), - Borrowed(None, Mutability::Mutable))], + args: vec![(Ptr(Box::new(Literal(Path::new_local(typaram))), + Borrowed(None, Mutability::Mutable)), "d")], ret_ty: Literal(Path::new_(pathvec_std!(cx, result::Result), None, diff --git a/src/libsyntax_ext/deriving/encodable.rs b/src/libsyntax_ext/deriving/encodable.rs index d579b3abd45..2c6c18cc51c 100644 --- a/src/libsyntax_ext/deriving/encodable.rs +++ b/src/libsyntax_ext/deriving/encodable.rs @@ -148,8 +148,8 @@ fn expand_deriving_encodable_imp(cx: &mut ExtCtxt, ], }, explicit_self: borrowed_explicit_self(), - args: vec![Ptr(Box::new(Literal(Path::new_local(typaram))), - Borrowed(None, Mutability::Mutable))], + args: vec![(Ptr(Box::new(Literal(Path::new_local(typaram))), + Borrowed(None, Mutability::Mutable)), "s")], ret_ty: Literal(Path::new_( pathvec_std!(cx, result::Result), None, diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index 1f80385cfbd..becd70149fd 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -191,7 +191,7 @@ use std::cell::RefCell; use std::collections::HashSet; use std::vec; -use syntax::abi::Abi; +use rustc_target::spec::abi::Abi; use syntax::ast::{ self, BinOpKind, EnumDef, Expr, GenericParam, Generics, Ident, PatKind, VariantData }; @@ -252,7 +252,7 @@ pub struct MethodDef<'a> { pub explicit_self: Option<Option<PtrTy<'a>>>, /// Arguments other than the self argument - pub args: Vec<Ty<'a>>, + pub args: Vec<(Ty<'a>, &'a str)>, /// Return type pub ret_ty: Ty<'a>, @@ -915,9 +915,9 @@ impl<'a> MethodDef<'a> { explicit_self }); - for (i, ty) in self.args.iter().enumerate() { + for (ty, name) in self.args.iter() { let ast_ty = ty.to_ty(cx, trait_.span, type_ident, generics); - let ident = cx.ident_of(&format!("__arg_{}", i)); + let ident = cx.ident_of(name).gensym(); arg_tys.push((ident, ast_ty)); let arg_expr = cx.expr_ident(trait_.span, ident); @@ -1004,10 +1004,10 @@ impl<'a> MethodDef<'a> { /// /// // equivalent to: /// impl PartialEq for A { - /// fn eq(&self, __arg_1: &A) -> bool { + /// fn eq(&self, other: &A) -> bool { /// match *self { /// A {x: ref __self_0_0, y: ref __self_0_1} => { - /// match *__arg_1 { + /// match *other { /// A {x: ref __self_1_0, y: ref __self_1_1} => { /// __self_0_0.eq(__self_1_0) && __self_0_1.eq(__self_1_1) /// } @@ -1020,10 +1020,10 @@ impl<'a> MethodDef<'a> { /// // or if A is repr(packed) - note fields are matched by-value /// // instead of by-reference. /// impl PartialEq for A { - /// fn eq(&self, __arg_1: &A) -> bool { + /// fn eq(&self, other: &A) -> bool { /// match *self { /// A {x: __self_0_0, y: __self_0_1} => { - /// match __arg_1 { + /// match other { /// A {x: __self_1_0, y: __self_1_1} => { /// __self_0_0.eq(&__self_1_0) && __self_0_1.eq(&__self_1_1) /// } @@ -1134,14 +1134,14 @@ impl<'a> MethodDef<'a> { /// // is equivalent to /// /// impl PartialEq for A { - /// fn eq(&self, __arg_1: &A) -> ::bool { - /// match (&*self, &*__arg_1) { + /// fn eq(&self, other: &A) -> ::bool { + /// match (&*self, &*other) { /// (&A1, &A1) => true, /// (&A2(ref self_0), /// &A2(ref __arg_1_0)) => (*self_0).eq(&(*__arg_1_0)), /// _ => { /// let __self_vi = match *self { A1(..) => 0, A2(..) => 1 }; - /// let __arg_1_vi = match *__arg_1 { A1(..) => 0, A2(..) => 1 }; + /// let __arg_1_vi = match *other { A1(..) => 0, A2(..) => 1 }; /// false /// } /// } @@ -1240,7 +1240,7 @@ impl<'a> MethodDef<'a> { let vi_idents: Vec<ast::Ident> = self_arg_names.iter() .map(|name| { let vi_suffix = format!("{}_vi", &name[..]); - cx.ident_of(&vi_suffix[..]) + cx.ident_of(&vi_suffix[..]).gensym() }) .collect::<Vec<ast::Ident>>(); @@ -1616,7 +1616,7 @@ impl<'a> TraitDef<'a> { let mut ident_exprs = Vec::new(); for (i, struct_field) in struct_def.fields().iter().enumerate() { let sp = struct_field.span.with_ctxt(self.span.ctxt()); - let ident = cx.ident_of(&format!("{}_{}", prefix, i)); + let ident = cx.ident_of(&format!("{}_{}", prefix, i)).gensym(); paths.push(ident.with_span_pos(sp)); let val = cx.expr_path(cx.path_ident(sp, ident)); let val = if use_temporaries { diff --git a/src/libsyntax_ext/deriving/hash.rs b/src/libsyntax_ext/deriving/hash.rs index b192ab2527e..67096cdb49a 100644 --- a/src/libsyntax_ext/deriving/hash.rs +++ b/src/libsyntax_ext/deriving/hash.rs @@ -44,8 +44,8 @@ pub fn expand_deriving_hash(cx: &mut ExtCtxt, bounds: vec![(typaram, vec![path_std!(cx, hash::Hasher)])], }, explicit_self: borrowed_explicit_self(), - args: vec![Ptr(Box::new(Literal(arg)), - Borrowed(None, Mutability::Mutable))], + args: vec![(Ptr(Box::new(Literal(arg)), + Borrowed(None, Mutability::Mutable)), "state")], ret_ty: nil_ty(), attributes: vec![], is_unsafe: false, diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs index c78decb1eb9..6b155b6596d 100644 --- a/src/libsyntax_ext/format.rs +++ b/src/libsyntax_ext/format.rs @@ -543,6 +543,10 @@ impl<'a, 'b> Context<'a, 'b> { let mut pats = Vec::new(); let mut heads = Vec::new(); + let names_pos: Vec<_> = (0..self.args.len()).map(|i| { + self.ecx.ident_of(&format!("arg{}", i)).gensym() + }).collect(); + // First, build up the static array which will become our precompiled // format "string" let pieces = self.ecx.expr_vec_slice(self.fmtsp, self.str_pieces); @@ -560,7 +564,7 @@ impl<'a, 'b> Context<'a, 'b> { // of each variable because we don't want to move out of the arguments // passed to this function. for (i, e) in self.args.into_iter().enumerate() { - let name = self.ecx.ident_of(&format!("__arg{}", i)); + let name = names_pos[i]; let span = DUMMY_SP.with_ctxt(e.span.ctxt().apply_mark(self.ecx.current_expansion.mark)); pats.push(self.ecx.pat_ident(span, name)); @@ -570,14 +574,12 @@ impl<'a, 'b> Context<'a, 'b> { heads.push(self.ecx.expr_addr_of(e.span, e)); } for pos in self.count_args { - let name = self.ecx.ident_of(&match pos { - Exact(i) => format!("__arg{}", i), - _ => panic!("should never happen"), - }); - let span = match pos { - Exact(i) => spans_pos[i], + let index = match pos { + Exact(i) => i, _ => panic!("should never happen"), }; + let name = names_pos[index]; + let span = spans_pos[index]; counts.push(Context::format_arg(self.ecx, self.macsp, span, &Count, name)); } diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs index 39ad594e5c5..b6721dd28f3 100644 --- a/src/libsyntax_ext/lib.rs +++ b/src/libsyntax_ext/lib.rs @@ -27,6 +27,7 @@ extern crate syntax_pos; extern crate proc_macro; extern crate rustc_data_structures; extern crate rustc_errors as errors; +extern crate rustc_target; #[cfg(not(stage0))] mod diagnostics; diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index 5e96b5ce673..658408519b9 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -21,6 +21,7 @@ use symbol::{Ident, Symbol}; use serialize::{Encodable, Decodable, Encoder, Decoder}; use std::collections::HashMap; +use rustc_data_structures::fx::FxHashSet; use std::fmt; /// A SyntaxContext represents a chain of macro expansions (represented by marks). @@ -117,6 +118,32 @@ impl Mark { true }) } + + /// Computes a mark such that both input marks are descendants of (or equal to) the returned + /// mark. That is, the following holds: + /// + /// ```rust + /// let la = least_ancestor(a, b); + /// assert!(a.is_descendant_of(la)) + /// assert!(b.is_descendant_of(la)) + /// ``` + pub fn least_ancestor(mut a: Mark, mut b: Mark) -> Mark { + HygieneData::with(|data| { + // Compute the path from a to the root + let mut a_path = FxHashSet::<Mark>(); + while a != Mark::root() { + a_path.insert(a); + a = data.marks[a.0 as usize].parent; + } + + // While the path from b to the root hasn't intersected, move up the tree + while !a_path.contains(&b) { + b = data.marks[b.0 as usize].parent; + } + + b + }) + } } pub struct HygieneData { @@ -238,6 +265,22 @@ impl SyntaxContext { }) } + /// Pulls a single mark off of the syntax context. This effectively moves the + /// context up one macro definition level. That is, if we have a nested macro + /// definition as follows: + /// + /// ```rust + /// macro_rules! f { + /// macro_rules! g { + /// ... + /// } + /// } + /// ``` + /// + /// and we have a SyntaxContext that is referring to something declared by an invocation + /// of g (call it g1), calling remove_mark will result in the SyntaxContext for the + /// invocation of f that created g1. + /// Returns the mark that was removed. pub fn remove_mark(&mut self) -> Mark { HygieneData::with(|data| { let outer_mark = data.syntax_contexts[self.0 as usize].outer_mark; diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 9a7d1fd8ee6..8d37b4aa396 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -291,6 +291,12 @@ impl Span { self.ctxt().outer().expn_info().map(|info| info.call_site.source_callsite()).unwrap_or(self) } + /// The `Span` for the tokens in the previous macro expansion from which `self` was generated, + /// if any + pub fn parent(self) -> Option<Span> { + self.ctxt().outer().expn_info().map(|i| i.call_site) + } + /// Return the source callee. /// /// Returns None if the supplied span has no expansion trace, diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs index 50fac600a97..4a8b1e8b1c1 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -15,9 +15,10 @@ use hygiene::SyntaxContext; use {Span, DUMMY_SP, GLOBALS}; +use rustc_data_structures::fx::FxHashMap; use serialize::{Decodable, Decoder, Encodable, Encoder}; -use std::collections::HashMap; use std::fmt; +use std::cmp::{PartialEq, Ordering, PartialOrd, Ord}; use std::hash::{Hash, Hasher}; #[derive(Copy, Clone, Eq)] @@ -36,6 +37,11 @@ impl Ident { Ident::new(name, DUMMY_SP) } + /// Maps an interned string to an identifier with an empty syntax context. + pub fn from_interned_str(string: InternedString) -> Ident { + Ident::with_empty_ctxt(string.as_symbol()) + } + /// Maps a string to an identifier with an empty syntax context. pub fn from_str(string: &str) -> Ident { Ident::with_empty_ctxt(Symbol::intern(string)) @@ -53,6 +59,10 @@ impl Ident { pub fn modern(self) -> Ident { Ident::new(self.name, self.span.modern()) } + + pub fn gensym(self) -> Ident { + Ident::new(self.name.gensymed(), self.span) + } } impl PartialEq for Ident { @@ -134,14 +144,20 @@ impl Symbol { with_interner(|interner| interner.gensymed(self)) } - pub fn as_str(self) -> InternedString { + pub fn as_str(self) -> LocalInternedString { with_interner(|interner| unsafe { - InternedString { + LocalInternedString { string: ::std::mem::transmute::<&str, &str>(interner.get(self)) } }) } + pub fn as_interned_str(self) -> InternedString { + with_interner(|interner| InternedString { + symbol: interner.interned(self) + }) + } + pub fn as_u32(self) -> u32 { self.0 } @@ -184,7 +200,7 @@ impl<T: ::std::ops::Deref<Target=str>> PartialEq<T> for Symbol { #[derive(Default)] pub struct Interner { - names: HashMap<Box<str>, Symbol>, + names: FxHashMap<Box<str>, Symbol>, strings: Vec<Box<str>>, gensyms: Vec<Symbol>, } @@ -361,84 +377,208 @@ fn with_interner<T, F: FnOnce(&mut Interner) -> T>(f: F) -> T { GLOBALS.with(|globals| f(&mut *globals.symbol_interner.lock())) } -/// Represents a string stored in the thread-local interner. Because the -/// interner lives for the life of the thread, this can be safely treated as an -/// immortal string, as long as it never crosses between threads. -/// -/// FIXME(pcwalton): You must be careful about what you do in the destructors -/// of objects stored in TLS, because they may run after the interner is -/// destroyed. In particular, they must not access string contents. This can -/// be fixed in the future by just leaking all strings until thread death -/// somehow. +/// Represents a string stored in the interner. Because the interner outlives any thread +/// which uses this type, we can safely treat `string` which points to interner data, +/// as an immortal string, as long as this type never crosses between threads. +// FIXME: Ensure that the interner outlives any thread which uses LocalInternedString, +// by creating a new thread right after constructing the interner #[derive(Clone, Copy, Hash, PartialOrd, Eq, Ord)] -pub struct InternedString { +pub struct LocalInternedString { string: &'static str, } -impl<U: ?Sized> ::std::convert::AsRef<U> for InternedString where str: ::std::convert::AsRef<U> { +impl LocalInternedString { + pub fn as_interned_str(self) -> InternedString { + InternedString { + symbol: Symbol::intern(self.string) + } + } +} + +impl<U: ?Sized> ::std::convert::AsRef<U> for LocalInternedString +where + str: ::std::convert::AsRef<U> +{ fn as_ref(&self) -> &U { self.string.as_ref() } } -impl<T: ::std::ops::Deref<Target = str>> ::std::cmp::PartialEq<T> for InternedString { +impl<T: ::std::ops::Deref<Target = str>> ::std::cmp::PartialEq<T> for LocalInternedString { fn eq(&self, other: &T) -> bool { self.string == other.deref() } } -impl ::std::cmp::PartialEq<InternedString> for str { - fn eq(&self, other: &InternedString) -> bool { +impl ::std::cmp::PartialEq<LocalInternedString> for str { + fn eq(&self, other: &LocalInternedString) -> bool { self == other.string } } -impl<'a> ::std::cmp::PartialEq<InternedString> for &'a str { - fn eq(&self, other: &InternedString) -> bool { +impl<'a> ::std::cmp::PartialEq<LocalInternedString> for &'a str { + fn eq(&self, other: &LocalInternedString) -> bool { *self == other.string } } -impl ::std::cmp::PartialEq<InternedString> for String { - fn eq(&self, other: &InternedString) -> bool { +impl ::std::cmp::PartialEq<LocalInternedString> for String { + fn eq(&self, other: &LocalInternedString) -> bool { self == other.string } } -impl<'a> ::std::cmp::PartialEq<InternedString> for &'a String { - fn eq(&self, other: &InternedString) -> bool { +impl<'a> ::std::cmp::PartialEq<LocalInternedString> for &'a String { + fn eq(&self, other: &LocalInternedString) -> bool { *self == other.string } } -impl !Send for InternedString { } +impl !Send for LocalInternedString {} +impl !Sync for LocalInternedString {} -impl ::std::ops::Deref for InternedString { +impl ::std::ops::Deref for LocalInternedString { type Target = str; fn deref(&self) -> &str { self.string } } -impl fmt::Debug for InternedString { +impl fmt::Debug for LocalInternedString { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(self.string, f) } } -impl fmt::Display for InternedString { +impl fmt::Display for LocalInternedString { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(self.string, f) } } +impl Decodable for LocalInternedString { + fn decode<D: Decoder>(d: &mut D) -> Result<LocalInternedString, D::Error> { + Ok(Symbol::intern(&d.read_str()?).as_str()) + } +} + +impl Encodable for LocalInternedString { + fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> { + s.emit_str(self.string) + } +} + +/// Represents a string stored in the string interner +#[derive(Clone, Copy, Eq)] +pub struct InternedString { + symbol: Symbol, +} + +impl InternedString { + pub fn with<F: FnOnce(&str) -> R, R>(self, f: F) -> R { + let str = with_interner(|interner| { + interner.get(self.symbol) as *const str + }); + // This is safe because the interner keeps string alive until it is dropped. + // We can access it because we know the interner is still alive since we use a + // scoped thread local to access it, and it was alive at the begining of this scope + unsafe { f(&*str) } + } + + pub fn as_symbol(self) -> Symbol { + self.symbol + } + + pub fn as_str(self) -> LocalInternedString { + self.symbol.as_str() + } +} + +impl Hash for InternedString { + fn hash<H: Hasher>(&self, state: &mut H) { + self.with(|str| str.hash(state)) + } +} + +impl PartialOrd<InternedString> for InternedString { + fn partial_cmp(&self, other: &InternedString) -> Option<Ordering> { + if self.symbol == other.symbol { + return Some(Ordering::Equal); + } + self.with(|self_str| other.with(|other_str| self_str.partial_cmp(&other_str))) + } +} + +impl Ord for InternedString { + fn cmp(&self, other: &InternedString) -> Ordering { + if self.symbol == other.symbol { + return Ordering::Equal; + } + self.with(|self_str| other.with(|other_str| self_str.cmp(&other_str))) + } +} + +impl<T: ::std::ops::Deref<Target = str>> PartialEq<T> for InternedString { + fn eq(&self, other: &T) -> bool { + self.with(|string| string == other.deref()) + } +} + +impl PartialEq<InternedString> for InternedString { + fn eq(&self, other: &InternedString) -> bool { + self.symbol == other.symbol + } +} + +impl PartialEq<InternedString> for str { + fn eq(&self, other: &InternedString) -> bool { + other.with(|string| self == string) + } +} + +impl<'a> PartialEq<InternedString> for &'a str { + fn eq(&self, other: &InternedString) -> bool { + other.with(|string| *self == string) + } +} + +impl PartialEq<InternedString> for String { + fn eq(&self, other: &InternedString) -> bool { + other.with(|string| self == string) + } +} + +impl<'a> PartialEq<InternedString> for &'a String { + fn eq(&self, other: &InternedString) -> bool { + other.with(|string| *self == string) + } +} + +impl ::std::convert::From<InternedString> for String { + fn from(val: InternedString) -> String { + val.as_symbol().to_string() + } +} + +impl fmt::Debug for InternedString { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.with(|str| fmt::Debug::fmt(&str, f)) + } +} + +impl fmt::Display for InternedString { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.with(|str| fmt::Display::fmt(&str, f)) + } +} + impl Decodable for InternedString { fn decode<D: Decoder>(d: &mut D) -> Result<InternedString, D::Error> { - Ok(Symbol::intern(&d.read_str()?).as_str()) + Ok(Symbol::intern(&d.read_str()?).as_interned_str()) } } impl Encodable for InternedString { fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> { - s.emit_str(self.string) + self.with(|string| s.emit_str(string)) } } diff --git a/src/rustc/Cargo.toml b/src/rustc/Cargo.toml index bbc4c2ee43e..9986e0b512a 100644 --- a/src/rustc/Cargo.toml +++ b/src/rustc/Cargo.toml @@ -8,8 +8,8 @@ name = "rustc" path = "rustc.rs" [dependencies] -rustc_back = { path = "../librustc_back" } +rustc_target = { path = "../librustc_target" } rustc_driver = { path = "../librustc_driver" } [features] -jemalloc = ["rustc_back/jemalloc"] +jemalloc = ["rustc_target/jemalloc"] diff --git a/src/stage0.txt b/src/stage0.txt index e8db3358cf0..a5ad2b315a1 100644 --- a/src/stage0.txt +++ b/src/stage0.txt @@ -12,7 +12,7 @@ # source tarball for a stable release you'll likely see `1.x.0` for rustc and # `0.x.0` for Cargo where they were released on `date`. -date: 2018-04-04 +date: 2018-04-24 rustc: beta cargo: beta diff --git a/src/stdsimd b/src/stdsimd -Subproject effdcd0132d17b6c4badc67b4b6d3fdf749a2d2 +Subproject 1ea18a5cb431e24aa838b652ac305acc5e394d6 diff --git a/src/test/codegen/align-struct.rs b/src/test/codegen/align-struct.rs index 155319cb154..f306608f432 100644 --- a/src/test/codegen/align-struct.rs +++ b/src/test/codegen/align-struct.rs @@ -29,7 +29,6 @@ pub enum Enum4 { A(i32), B(i32), } -// CHECK: %Enum4 = type { [0 x i32], i32, [1 x i32] } // CHECK: %"Enum4::A" = type { [1 x i32], i32, [0 x i32] } pub enum Enum64 { @@ -59,7 +58,7 @@ pub fn nested64(a: Align64, b: i32, c: i32, d: i8) -> Nested64 { // CHECK-LABEL: @enum4 #[no_mangle] pub fn enum4(a: i32) -> Enum4 { -// CHECK: %e4 = alloca %Enum4, align 4 +// CHECK: %e4 = alloca { i32, i32 }, align 4 let e4 = Enum4::A(a); e4 } diff --git a/src/test/codegen/call-metadata.rs b/src/test/codegen/call-metadata.rs new file mode 100644 index 00000000000..20d42ed852d --- /dev/null +++ b/src/test/codegen/call-metadata.rs @@ -0,0 +1,29 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Checks that range metadata gets emitted on calls to functions returning a +// scalar value. + +// compile-flags: -C no-prepopulate-passes +// min-llvm-version 4.0 + + +#![crate_type = "lib"] + +pub fn test() { + // CHECK: call i8 @some_true(), !range [[R0:![0-9]+]] + // CHECK: [[R0]] = !{i8 0, i8 3} + some_true(); +} + +#[no_mangle] +fn some_true() -> Option<bool> { + Some(true) +} diff --git a/src/test/codegen/function-arguments.rs b/src/test/codegen/function-arguments.rs index de302c69056..40a9ea5a181 100644 --- a/src/test/codegen/function-arguments.rs +++ b/src/test/codegen/function-arguments.rs @@ -145,6 +145,18 @@ pub fn return_slice(x: &[u16]) -> &[u16] { x } +// CHECK: { i16, i16 } @enum_id_1(i16 %x.0, i16 %x.1) +#[no_mangle] +pub fn enum_id_1(x: Option<Result<u16, u16>>) -> Option<Result<u16, u16>> { + x +} + +// CHECK: i16 @enum_id_2(i16) +#[no_mangle] +pub fn enum_id_2(x: Option<u8>) -> Option<u8> { + x +} + // CHECK: noalias i8* @allocator() #[no_mangle] #[allocator] diff --git a/src/test/codegen/lifetime_start_end.rs b/src/test/codegen/lifetime_start_end.rs index 62aa93398ac..ea3f0de5d08 100644 --- a/src/test/codegen/lifetime_start_end.rs +++ b/src/test/codegen/lifetime_start_end.rs @@ -25,16 +25,16 @@ pub fn test() { let b = &Some(a); &b; // keep variable in an alloca -// CHECK: [[S_b:%[0-9]+]] = bitcast %"core::option::Option<i32>"** %b to i8* +// CHECK: [[S_b:%[0-9]+]] = bitcast { i32, i32 }** %b to i8* // CHECK: call void @llvm.lifetime.start{{.*}}(i{{[0-9 ]+}}, i8* [[S_b]]) -// CHECK: [[S__4:%[0-9]+]] = bitcast %"core::option::Option<i32>"* %_4 to i8* +// CHECK: [[S__4:%[0-9]+]] = bitcast { i32, i32 }* %_4 to i8* // CHECK: call void @llvm.lifetime.start{{.*}}(i{{[0-9 ]+}}, i8* [[S__4]]) -// CHECK: [[E_b:%[0-9]+]] = bitcast %"core::option::Option<i32>"** %b to i8* +// CHECK: [[E_b:%[0-9]+]] = bitcast { i32, i32 }** %b to i8* // CHECK: call void @llvm.lifetime.end{{.*}}(i{{[0-9 ]+}}, i8* [[E_b]]) -// CHECK: [[E__4:%[0-9]+]] = bitcast %"core::option::Option<i32>"* %_4 to i8* +// CHECK: [[E__4:%[0-9]+]] = bitcast { i32, i32 }* %_4 to i8* // CHECK: call void @llvm.lifetime.end{{.*}}(i{{[0-9 ]+}}, i8* [[E__4]]) } diff --git a/src/test/codegen/nounwind.rs b/src/test/codegen/nounwind.rs index 9fea907d3c8..6863b1f2792 100644 --- a/src/test/codegen/nounwind.rs +++ b/src/test/codegen/nounwind.rs @@ -11,6 +11,7 @@ // aux-build:nounwind.rs // compile-flags: -C no-prepopulate-passes -C panic=abort -C metadata=a // ignore-windows +// ignore-android #![crate_type = "lib"] diff --git a/src/test/codegen/target-feature-on-functions.rs b/src/test/codegen/target-feature-on-functions.rs new file mode 100644 index 00000000000..e3cc2c753e5 --- /dev/null +++ b/src/test/codegen/target-feature-on-functions.rs @@ -0,0 +1,19 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// only-x86_64 +// compile-flags: -C target-feature=+avx + +#![crate_type = "lib"] + +#[no_mangle] +pub fn foo() { + // CHECK: attributes #0 = { {{.*}}"target-features"="+avx"{{.*}} } +} diff --git a/src/test/compile-fail-fulldeps/proc-macro/attr-invalid-exprs.rs b/src/test/compile-fail-fulldeps/proc-macro/attr-invalid-exprs.rs index 2f65bd16bb5..749d87e37b5 100644 --- a/src/test/compile-fail-fulldeps/proc-macro/attr-invalid-exprs.rs +++ b/src/test/compile-fail-fulldeps/proc-macro/attr-invalid-exprs.rs @@ -13,7 +13,7 @@ //! Attributes producing expressions in invalid locations -#![feature(proc_macro, stmt_expr_attributes)] +#![feature(proc_macro, stmt_expr_attributes, proc_macro_expr)] extern crate attr_stmt_expr; use attr_stmt_expr::{duplicate, no_output}; diff --git a/src/test/compile-fail-fulldeps/proc-macro/attr-stmt-expr.rs b/src/test/compile-fail-fulldeps/proc-macro/attr-stmt-expr.rs index d29bc00c663..ce04fdfb976 100644 --- a/src/test/compile-fail-fulldeps/proc-macro/attr-stmt-expr.rs +++ b/src/test/compile-fail-fulldeps/proc-macro/attr-stmt-expr.rs @@ -11,7 +11,7 @@ // aux-build:attr-stmt-expr.rs // ignore-stage1 -#![feature(proc_macro)] +#![feature(proc_macro, proc_macro_expr)] extern crate attr_stmt_expr; use attr_stmt_expr::{expect_let, expect_print_stmt, expect_expr, expect_print_expr}; diff --git a/src/test/compile-fail-fulldeps/proc-macro/attribute-with-error.rs b/src/test/compile-fail-fulldeps/proc-macro/attribute-with-error.rs index 00a27818327..edfedebf870 100644 --- a/src/test/compile-fail-fulldeps/proc-macro/attribute-with-error.rs +++ b/src/test/compile-fail-fulldeps/proc-macro/attribute-with-error.rs @@ -21,6 +21,8 @@ use attribute_with_error::foo; fn test1() { let a: i32 = "foo"; //~^ ERROR: mismatched types + let b: i32 = "f'oo"; + //~^ ERROR: mismatched types } fn test2() { diff --git a/src/test/compile-fail-fulldeps/proc-macro/attributes-included.rs b/src/test/compile-fail-fulldeps/proc-macro/attributes-included.rs index 2adbee1d3fb..9947e8f66ce 100644 --- a/src/test/compile-fail-fulldeps/proc-macro/attributes-included.rs +++ b/src/test/compile-fail-fulldeps/proc-macro/attributes-included.rs @@ -11,7 +11,7 @@ // aux-build:attributes-included.rs // ignore-stage1 -#![feature(proc_macro, rustc_attrs)] +#![feature(proc_macro, rustc_attrs, proc_macro_path_invoc)] #![warn(unused)] extern crate attributes_included; diff --git a/src/test/compile-fail-fulldeps/proc-macro/auxiliary/proc-macro-gates.rs b/src/test/compile-fail-fulldeps/proc-macro/auxiliary/proc-macro-gates.rs new file mode 100644 index 00000000000..25579f1fc83 --- /dev/null +++ b/src/test/compile-fail-fulldeps/proc-macro/auxiliary/proc-macro-gates.rs @@ -0,0 +1,29 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// no-prefer-dynamic +// force-host + +#![crate_type = "proc-macro"] +#![feature(proc_macro)] + +extern crate proc_macro; + +use proc_macro::*; + +#[proc_macro] +pub fn m(a: TokenStream) -> TokenStream { + a +} + +#[proc_macro_attribute] +pub fn a(_a: TokenStream, b: TokenStream) -> TokenStream { + b +} diff --git a/src/test/compile-fail-fulldeps/proc-macro/lints_in_proc_macros.rs b/src/test/compile-fail-fulldeps/proc-macro/lints_in_proc_macros.rs index 773b16b945f..c7be3167947 100644 --- a/src/test/compile-fail-fulldeps/proc-macro/lints_in_proc_macros.rs +++ b/src/test/compile-fail-fulldeps/proc-macro/lints_in_proc_macros.rs @@ -11,7 +11,7 @@ // aux-build:bang_proc_macro2.rs // ignore-stage1 -#![feature(proc_macro)] +#![feature(proc_macro, proc_macro_non_items)] #![allow(unused_macros)] extern crate bang_proc_macro2; diff --git a/src/test/compile-fail-fulldeps/proc-macro/macro-use-bang.rs b/src/test/compile-fail-fulldeps/proc-macro/macro-use-bang.rs index 7ecc685357e..f16ca79ca93 100644 --- a/src/test/compile-fail-fulldeps/proc-macro/macro-use-bang.rs +++ b/src/test/compile-fail-fulldeps/proc-macro/macro-use-bang.rs @@ -10,7 +10,7 @@ // aux-build:bang_proc_macro.rs -#![feature(proc_macro)] +#![feature(proc_macro, proc_macro_non_items)] #[macro_use] extern crate bang_proc_macro; diff --git a/src/test/compile-fail-fulldeps/proc-macro/proc-macro-gates.rs b/src/test/compile-fail-fulldeps/proc-macro/proc-macro-gates.rs new file mode 100644 index 00000000000..0dc1c2ab2da --- /dev/null +++ b/src/test/compile-fail-fulldeps/proc-macro/proc-macro-gates.rs @@ -0,0 +1,54 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:proc-macro-gates.rs +// gate-test-proc_macro_non_items +// gate-test-proc_macro_path_invoc +// gate-test-proc_macro_mod line +// gate-test-proc_macro_expr +// gate-test-proc_macro_mod + +#![feature(proc_macro, stmt_expr_attributes)] + +extern crate proc_macro_gates as foo; + +use foo::*; + +#[foo::a] //~ ERROR: paths of length greater than one +fn _test() {} + +#[a] //~ ERROR: custom attributes cannot be applied to modules +mod _test2 {} + +#[a = y] //~ ERROR: must only be followed by a delimiter token +fn _test3() {} + +#[a = ] //~ ERROR: must only be followed by a delimiter token +fn _test4() {} + +#[a () = ] //~ ERROR: must only be followed by a delimiter token +fn _test5() {} + +fn main() { + #[a] //~ ERROR: custom attributes cannot be applied to statements + let _x = 2; + let _x = #[a] 2; + //~^ ERROR: custom attributes cannot be applied to expressions + + let _x: m!(u32) = 3; + //~^ ERROR: procedural macros cannot be expanded to types + if let m!(Some(_x)) = Some(3) { + //~^ ERROR: procedural macros cannot be expanded to patterns + } + let _x = m!(3); + //~^ ERROR: procedural macros cannot be expanded to expressions + m!(let _x = 3;); + //~^ ERROR: procedural macros cannot be expanded to statements +} diff --git a/src/test/compile-fail-fulldeps/proc-macro/proc-macro-gates2.rs b/src/test/compile-fail-fulldeps/proc-macro/proc-macro-gates2.rs new file mode 100644 index 00000000000..a1a15afecd5 --- /dev/null +++ b/src/test/compile-fail-fulldeps/proc-macro/proc-macro-gates2.rs @@ -0,0 +1,35 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:proc-macro-gates.rs + +#![feature(proc_macro, stmt_expr_attributes)] + +extern crate proc_macro_gates as foo; + +use foo::*; + +// NB. these errors aren't the best errors right now, but they're definitely +// intended to be errors. Somehow using a custom attribute in these positions +// should either require a feature gate or not be allowed on stable. + +fn _test6<#[a] T>() {} +//~^ ERROR: unknown to the compiler + +fn _test7() { + match 1 { + #[a] //~ ERROR: unknown to the compiler + 0 => {} + _ => {} + } +} + +fn main() { +} diff --git a/src/test/compile-fail/allocator/not-an-allocator.rs b/src/test/compile-fail/allocator/not-an-allocator.rs index 1479d0b6264..140cad22f34 100644 --- a/src/test/compile-fail/allocator/not-an-allocator.rs +++ b/src/test/compile-fail/allocator/not-an-allocator.rs @@ -16,6 +16,5 @@ static A: usize = 0; //~| the trait bound `usize: //~| the trait bound `usize: //~| the trait bound `usize: -//~| the trait bound `usize: fn main() {} diff --git a/src/test/compile-fail/array_const_index-0.rs b/src/test/compile-fail/array_const_index-0.rs index 501c66e75cd..9b9deb4ca8d 100644 --- a/src/test/compile-fail/array_const_index-0.rs +++ b/src/test/compile-fail/array_const_index-0.rs @@ -12,6 +12,7 @@ const A: &'static [i32] = &[]; const B: i32 = (&A)[1]; //~^ ERROR constant evaluation error //~| index out of bounds: the len is 0 but the index is 1 +//~| WARN this constant cannot be used fn main() { let _ = B; diff --git a/src/test/compile-fail/array_const_index-1.rs b/src/test/compile-fail/array_const_index-1.rs index d3b43e83bfe..46feb20cf11 100644 --- a/src/test/compile-fail/array_const_index-1.rs +++ b/src/test/compile-fail/array_const_index-1.rs @@ -12,6 +12,7 @@ const A: [i32; 0] = []; const B: i32 = A[1]; //~^ ERROR constant evaluation error //~| index out of bounds: the len is 0 but the index is 1 +//~| WARN this constant cannot be used fn main() { let _ = B; diff --git a/src/test/compile-fail/attr-usage-inline.rs b/src/test/compile-fail/attr-usage-inline.rs index c6b9b016331..250905dbdcd 100644 --- a/src/test/compile-fail/attr-usage-inline.rs +++ b/src/test/compile-fail/attr-usage-inline.rs @@ -13,7 +13,7 @@ #[inline] fn f() {} -#[inline] //~ ERROR: attribute should be applied to function +#[inline] //~ ERROR: attribute should be applied to function or closure struct S; fn main() {} diff --git a/src/test/compile-fail/borrowck/two-phase-reservation-sharing-interference.rs b/src/test/compile-fail/borrowck/two-phase-reservation-sharing-interference.rs index 1333167b780..1e86603c19e 100644 --- a/src/test/compile-fail/borrowck/two-phase-reservation-sharing-interference.rs +++ b/src/test/compile-fail/borrowck/two-phase-reservation-sharing-interference.rs @@ -10,7 +10,7 @@ // ignore-tidy-linelength -// revisions: nll_beyond nll_target +// revisions: nll_target // The following revisions are disabled due to missing support from two-phase beyond autorefs //[nll_beyond]compile-flags: -Z borrowck=mir -Z two-phase-borrows -Z two-phase-beyond-autoref diff --git a/src/test/compile-fail/call-fn-never-arg-wrong-type.rs b/src/test/compile-fail/call-fn-never-arg-wrong-type.rs index c2f157cd35c..583befed1e8 100644 --- a/src/test/compile-fail/call-fn-never-arg-wrong-type.rs +++ b/src/test/compile-fail/call-fn-never-arg-wrong-type.rs @@ -10,6 +10,8 @@ // Test that we can't pass other types for ! +#![feature(never_type)] + fn foo(x: !) -> ! { x } diff --git a/src/test/compile-fail/coerce-to-bang-cast.rs b/src/test/compile-fail/coerce-to-bang-cast.rs index 5efb4dadc64..14a06b306d8 100644 --- a/src/test/compile-fail/coerce-to-bang-cast.rs +++ b/src/test/compile-fail/coerce-to-bang-cast.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(never_type)] + fn foo(x: usize, y: !, z: usize) { } fn cast_a() { diff --git a/src/test/compile-fail/coerce-to-bang.rs b/src/test/compile-fail/coerce-to-bang.rs index 15049232a4d..62ff09f4616 100644 --- a/src/test/compile-fail/coerce-to-bang.rs +++ b/src/test/compile-fail/coerce-to-bang.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(never_type)] + fn foo(x: usize, y: !, z: usize) { } fn call_foo_a() { diff --git a/src/test/compile-fail/const-err-early.rs b/src/test/compile-fail/const-err-early.rs index 3de0f1ff61e..6caec159d01 100644 --- a/src/test/compile-fail/const-err-early.rs +++ b/src/test/compile-fail/const-err-early.rs @@ -10,17 +10,17 @@ #![deny(const_err)] -pub const A: i8 = -std::i8::MIN; //~ ERROR E0080 -//~^ ERROR attempt to negate with overflow +pub const A: i8 = -std::i8::MIN; //~ ERROR const_err +//~^ ERROR this constant cannot be used //~| ERROR constant evaluation error -pub const B: u8 = 200u8 + 200u8; //~ ERROR E0080 -//~^ ERROR attempt to add with overflow -pub const C: u8 = 200u8 * 4; //~ ERROR E0080 -//~^ ERROR attempt to multiply with overflow -pub const D: u8 = 42u8 - (42u8 + 1); //~ ERROR E0080 -//~^ ERROR attempt to subtract with overflow +pub const B: u8 = 200u8 + 200u8; //~ ERROR const_err +//~^ ERROR this constant cannot be used +pub const C: u8 = 200u8 * 4; //~ ERROR const_err +//~^ ERROR this constant cannot be used +pub const D: u8 = 42u8 - (42u8 + 1); //~ ERROR const_err +//~^ ERROR this constant cannot be used pub const E: u8 = [5u8][1]; -//~^ ERROR E0080 +//~^ ERROR const_err fn main() { let _a = A; diff --git a/src/test/compile-fail/const-err-multi.rs b/src/test/compile-fail/const-err-multi.rs index d2355f57f17..6f0281b8bd0 100644 --- a/src/test/compile-fail/const-err-multi.rs +++ b/src/test/compile-fail/const-err-multi.rs @@ -14,12 +14,13 @@ pub const A: i8 = -std::i8::MIN; //~^ ERROR E0080 //~| ERROR attempt to negate with overflow //~| ERROR constant evaluation error +//~| ERROR this constant cannot be used pub const B: i8 = A; -//~^ ERROR E0080 +//~^ ERROR const_err pub const C: u8 = A as u8; -//~^ ERROR E0080 +//~^ ERROR const_err pub const D: i8 = 50 - A; -//~^ ERROR E0080 +//~^ ERROR const_err fn main() { let _ = (A, B, C, D); diff --git a/src/test/compile-fail/const-eval-overflow2.rs b/src/test/compile-fail/const-eval-overflow2.rs index a0d8f9672c0..faa8c3039b7 100644 --- a/src/test/compile-fail/const-eval-overflow2.rs +++ b/src/test/compile-fail/const-eval-overflow2.rs @@ -22,57 +22,57 @@ use std::{i8, i16, i32, i64, isize}; use std::{u8, u16, u32, u64, usize}; const VALS_I8: (i8,) = + //~^ ERROR this constant cannot be used ( i8::MIN - 1, - //~^ ERROR constant evaluation error - //~| ERROR attempt to subtract with overflow + //~^ ERROR attempt to subtract with overflow ); const VALS_I16: (i16,) = + //~^ ERROR this constant cannot be used ( i16::MIN - 1, - //~^ ERROR constant evaluation error - //~| ERROR attempt to subtract with overflow + //~^ ERROR attempt to subtract with overflow ); const VALS_I32: (i32,) = + //~^ ERROR this constant cannot be used ( i32::MIN - 1, - //~^ ERROR constant evaluation error - //~| ERROR attempt to subtract with overflow + //~^ ERROR attempt to subtract with overflow ); const VALS_I64: (i64,) = + //~^ ERROR this constant cannot be used ( i64::MIN - 1, - //~^ ERROR constant evaluation error - //~| ERROR attempt to subtract with overflow + //~^ ERROR attempt to subtract with overflow ); const VALS_U8: (u8,) = + //~^ ERROR this constant cannot be used ( u8::MIN - 1, - //~^ ERROR constant evaluation error - //~| ERROR attempt to subtract with overflow + //~^ ERROR attempt to subtract with overflow ); const VALS_U16: (u16,) = ( + //~^ ERROR this constant cannot be used u16::MIN - 1, - //~^ ERROR constant evaluation error - //~| ERROR attempt to subtract with overflow + //~^ ERROR attempt to subtract with overflow ); const VALS_U32: (u32,) = ( + //~^ ERROR this constant cannot be used u32::MIN - 1, - //~^ ERROR constant evaluation error - //~| ERROR attempt to subtract with overflow + //~^ ERROR attempt to subtract with overflow ); const VALS_U64: (u64,) = + //~^ ERROR this constant cannot be used ( u64::MIN - 1, - //~^ ERROR constant evaluation error - //~| ERROR attempt to subtract with overflow + //~^ ERROR attempt to subtract with overflow ); fn main() { diff --git a/src/test/compile-fail/const-eval-overflow2b.rs b/src/test/compile-fail/const-eval-overflow2b.rs index 08128f90e53..d827e680c5b 100644 --- a/src/test/compile-fail/const-eval-overflow2b.rs +++ b/src/test/compile-fail/const-eval-overflow2b.rs @@ -22,57 +22,57 @@ use std::{i8, i16, i32, i64, isize}; use std::{u8, u16, u32, u64, usize}; const VALS_I8: (i8,) = + //~^ ERROR this constant cannot be used ( i8::MAX + 1, - //~^ ERROR constant evaluation error - //~| ERROR attempt to add with overflow + //~^ ERROR attempt to add with overflow ); const VALS_I16: (i16,) = + //~^ ERROR this constant cannot be used ( i16::MAX + 1, - //~^ ERROR constant evaluation error - //~| ERROR attempt to add with overflow + //~^ ERROR attempt to add with overflow ); const VALS_I32: (i32,) = + //~^ ERROR this constant cannot be used ( i32::MAX + 1, - //~^ ERROR constant evaluation error - //~| ERROR attempt to add with overflow + //~^ ERROR attempt to add with overflow ); const VALS_I64: (i64,) = + //~^ ERROR this constant cannot be used ( i64::MAX + 1, - //~^ ERROR constant evaluation error - //~| ERROR attempt to add with overflow + //~^ ERROR attempt to add with overflow ); const VALS_U8: (u8,) = + //~^ ERROR this constant cannot be used ( u8::MAX + 1, - //~^ ERROR constant evaluation error - //~| ERROR attempt to add with overflow + //~^ ERROR attempt to add with overflow ); const VALS_U16: (u16,) = ( + //~^ ERROR this constant cannot be used u16::MAX + 1, - //~^ ERROR constant evaluation error - //~| ERROR attempt to add with overflow + //~^ ERROR attempt to add with overflow ); const VALS_U32: (u32,) = ( + //~^ ERROR this constant cannot be used u32::MAX + 1, - //~^ ERROR constant evaluation error - //~| ERROR attempt to add with overflow + //~^ ERROR attempt to add with overflow ); const VALS_U64: (u64,) = + //~^ ERROR this constant cannot be used ( u64::MAX + 1, - //~^ ERROR constant evaluation error - //~| ERROR attempt to add with overflow + //~^ ERROR attempt to add with overflow ); fn main() { diff --git a/src/test/compile-fail/const-eval-overflow2c.rs b/src/test/compile-fail/const-eval-overflow2c.rs index 31a1638cade..2fd46b038ef 100644 --- a/src/test/compile-fail/const-eval-overflow2c.rs +++ b/src/test/compile-fail/const-eval-overflow2c.rs @@ -22,57 +22,57 @@ use std::{i8, i16, i32, i64, isize}; use std::{u8, u16, u32, u64, usize}; const VALS_I8: (i8,) = + //~^ ERROR this constant cannot be used ( i8::MIN * 2, - //~^ ERROR constant evaluation error - //~| ERROR attempt to multiply with overflow + //~^ ERROR attempt to multiply with overflow ); const VALS_I16: (i16,) = + //~^ ERROR this constant cannot be used ( i16::MIN * 2, - //~^ ERROR constant evaluation error - //~| ERROR attempt to multiply with overflow + //~^ ERROR attempt to multiply with overflow ); const VALS_I32: (i32,) = + //~^ ERROR this constant cannot be used ( i32::MIN * 2, - //~^ ERROR constant evaluation error - //~| ERROR attempt to multiply with overflow + //~^ ERROR attempt to multiply with overflow ); const VALS_I64: (i64,) = + //~^ ERROR this constant cannot be used ( i64::MIN * 2, - //~^ ERROR constant evaluation error - //~| ERROR attempt to multiply with overflow + //~^ ERROR attempt to multiply with overflow ); const VALS_U8: (u8,) = + //~^ ERROR this constant cannot be used ( u8::MAX * 2, - //~^ ERROR constant evaluation error - //~| ERROR attempt to multiply with overflow + //~^ ERROR attempt to multiply with overflow ); const VALS_U16: (u16,) = ( + //~^ ERROR this constant cannot be used u16::MAX * 2, - //~^ ERROR constant evaluation error - //~| ERROR attempt to multiply with overflow + //~^ ERROR attempt to multiply with overflow ); const VALS_U32: (u32,) = ( + //~^ ERROR this constant cannot be used u32::MAX * 2, - //~^ ERROR constant evaluation error - //~| ERROR attempt to multiply with overflow + //~^ ERROR attempt to multiply with overflow ); const VALS_U64: (u64,) = + //~^ ERROR this constant cannot be used ( u64::MAX * 2, - //~^ ERROR constant evaluation error - //~| ERROR attempt to multiply with overflow + //~^ ERROR attempt to multiply with overflow ); fn main() { diff --git a/src/test/compile-fail/const-slice-oob.rs b/src/test/compile-fail/const-slice-oob.rs index 179ea9e853f..7da5a2f17ea 100644 --- a/src/test/compile-fail/const-slice-oob.rs +++ b/src/test/compile-fail/const-slice-oob.rs @@ -14,6 +14,7 @@ const FOO: &'static[u32] = &[1, 2, 3]; const BAR: u32 = FOO[5]; //~^ ERROR constant evaluation error [E0080] //~| index out of bounds: the len is 3 but the index is 5 +//~| WARN this constant cannot be used fn main() { let _ = BAR; diff --git a/src/test/compile-fail/defaulted-never-note.rs b/src/test/compile-fail/defaulted-never-note.rs index 798544f1649..ac8ac85824e 100644 --- a/src/test/compile-fail/defaulted-never-note.rs +++ b/src/test/compile-fail/defaulted-never-note.rs @@ -8,6 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// We need to opt inot the `!` feature in order to trigger the +// requirement that this is testing. +#![feature(never_type)] + #![allow(unused)] trait Deserialize: Sized { diff --git a/src/test/compile-fail/edition-raw-pointer-method-2015.rs b/src/test/compile-fail/edition-raw-pointer-method-2015.rs index fdc9b4f704c..b304443f631 100644 --- a/src/test/compile-fail/edition-raw-pointer-method-2015.rs +++ b/src/test/compile-fail/edition-raw-pointer-method-2015.rs @@ -9,7 +9,7 @@ // except according to those terms. // ignore-tidy-linelength -// compile-flags: -Zedition=2015 -Zunstable-options +// compile-flags: --edition=2015 -Zunstable-options // tests that editions work with the tyvar warning-turned-error diff --git a/src/test/compile-fail/edition-raw-pointer-method-2018.rs b/src/test/compile-fail/edition-raw-pointer-method-2018.rs index 58b34591029..d01cac019e3 100644 --- a/src/test/compile-fail/edition-raw-pointer-method-2018.rs +++ b/src/test/compile-fail/edition-raw-pointer-method-2018.rs @@ -9,7 +9,7 @@ // except according to those terms. // ignore-tidy-linelength -// compile-flags: -Zedition=2018 -Zunstable-options +// compile-flags: --edition=2018 -Zunstable-options // tests that editions work with the tyvar warning-turned-error diff --git a/src/test/compile-fail/impl-trait/impl-generic-mismatch.rs b/src/test/compile-fail/impl-trait/impl-generic-mismatch.rs index eea7ca20957..d6707f59011 100644 --- a/src/test/compile-fail/impl-trait/impl-generic-mismatch.rs +++ b/src/test/compile-fail/impl-trait/impl-generic-mismatch.rs @@ -28,4 +28,15 @@ impl Bar for () { //~^ Error method `bar` has incompatible signature for trait } +// With non-local trait (#49841): + +use std::hash::{Hash, Hasher}; + +struct X; + +impl Hash for X { + fn hash(&self, hasher: &mut impl Hasher) {} + //~^ Error method `hash` has incompatible signature for trait +} + fn main() {} diff --git a/src/test/compile-fail/impl-trait/where-allowed.rs b/src/test/compile-fail/impl-trait/where-allowed.rs index 038eacaf110..2891cd59e3e 100644 --- a/src/test/compile-fail/impl-trait/where-allowed.rs +++ b/src/test/compile-fail/impl-trait/where-allowed.rs @@ -10,7 +10,6 @@ //! A simple test for testing many permutations of allowedness of //! impl Trait -#![feature(dyn_trait)] use std::fmt::Debug; // Allowed diff --git a/src/test/compile-fail/inhabitedness-infinite-loop.rs b/src/test/compile-fail/inhabitedness-infinite-loop.rs index b9741e0add6..d11aacec196 100644 --- a/src/test/compile-fail/inhabitedness-infinite-loop.rs +++ b/src/test/compile-fail/inhabitedness-infinite-loop.rs @@ -10,6 +10,7 @@ // error-pattern:reached recursion limit +#![feature(never_type)] #![feature(exhaustive_patterns)] struct Foo<'a, T: 'a> { diff --git a/src/test/compile-fail/issue-23080-2.rs b/src/test/compile-fail/issue-23080-2.rs index 2aa87f8424b..fc365a4b9aa 100644 --- a/src/test/compile-fail/issue-23080-2.rs +++ b/src/test/compile-fail/issue-23080-2.rs @@ -10,6 +10,8 @@ // ignore-tidy-linelength +//~^^^^^^^^^^^^ ERROR + #![feature(optin_builtin_traits)] unsafe auto trait Trait { @@ -22,5 +24,4 @@ fn call_method<T: Trait>(x: T) {} fn main() { // ICE call_method(()); - //~^ ERROR } diff --git a/src/test/compile-fail/issue-31769.rs b/src/test/compile-fail/issue-31769.rs index 7f73d9076ec..2bd45deeab4 100644 --- a/src/test/compile-fail/issue-31769.rs +++ b/src/test/compile-fail/issue-31769.rs @@ -9,6 +9,6 @@ // except according to those terms. fn main() { - #[inline] struct Foo; //~ ERROR attribute should be applied to function + #[inline] struct Foo; //~ ERROR attribute should be applied to function or closure #[repr(C)] fn foo() {} //~ ERROR attribute should be applied to struct, enum or union } diff --git a/src/test/compile-fail/issue-43105.rs b/src/test/compile-fail/issue-43105.rs index c0af3b4b9e6..6fa65a541b3 100644 --- a/src/test/compile-fail/issue-43105.rs +++ b/src/test/compile-fail/issue-43105.rs @@ -11,7 +11,7 @@ fn xyz() -> u8 { 42 } const NUM: u8 = xyz(); -//~^ ERROR calls in constants are limited to constant functions, struct and enum constructors +//~^ ERROR calls in constants are limited to constant functions, tuple structs and tuple variants //~| ERROR constant evaluation error fn main() { diff --git a/src/test/compile-fail/issue-43988.rs b/src/test/compile-fail/issue-43988.rs index ff1fdaef416..0dfa9f6f0d3 100644 --- a/src/test/compile-fail/issue-43988.rs +++ b/src/test/compile-fail/issue-43988.rs @@ -14,12 +14,12 @@ fn main() { #[inline] let _a = 4; - //~^^ ERROR attribute should be applied to function + //~^^ ERROR attribute should be applied to function or closure #[inline(XYZ)] let _b = 4; - //~^^ ERROR attribute should be applied to function + //~^^ ERROR attribute should be applied to function or closure #[repr(nothing)] let _x = 0; @@ -40,7 +40,7 @@ fn main() { #[inline(ABC)] foo(); - //~^^ ERROR attribute should be applied to function + //~^^ ERROR attribute should be applied to function or closure let _z = #[repr] 1; //~^ ERROR attribute should not be applied to an expression diff --git a/src/test/compile-fail/issue32829.rs b/src/test/compile-fail/issue32829.rs index e0b847fc994..9a84322ad06 100644 --- a/src/test/compile-fail/issue32829.rs +++ b/src/test/compile-fail/issue32829.rs @@ -7,6 +7,9 @@ // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. + +// ignore-tidy-linelength + #![feature(const_fn)] const bad : u32 = { @@ -20,7 +23,7 @@ const bad_two : u32 = { { invalid(); //~^ ERROR: blocks in constants are limited to items and tail expressions - //~^^ ERROR: calls in constants are limited to constant functions, struct and enum + //~^^ ERROR: calls in constants are limited to constant functions, tuple structs and tuple variants 0 } }; @@ -44,7 +47,7 @@ static bad_five : u32 = { { invalid(); //~^ ERROR: blocks in statics are limited to items and tail expressions - //~^^ ERROR: calls in statics are limited to constant functions, struct and enum + //~^^ ERROR: calls in statics are limited to constant functions, tuple structs and tuple variants 0 } }; @@ -68,7 +71,7 @@ static mut bad_eight : u32 = { { invalid(); //~^ ERROR: blocks in statics are limited to items and tail expressions - //~^^ ERROR: calls in statics are limited to constant functions, struct and enum + //~^^ ERROR: calls in statics are limited to constant functions, tuple structs and tuple variants 0 } }; diff --git a/src/test/compile-fail/lint-unused-mut-variables.rs b/src/test/compile-fail/lint-unused-mut-variables.rs index 3c76740d2b5..14d836074dc 100644 --- a/src/test/compile-fail/lint-unused-mut-variables.rs +++ b/src/test/compile-fail/lint-unused-mut-variables.rs @@ -8,6 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// revisions: lexical nll +#![cfg_attr(nll, feature(nll))] + // Exercise the unused_mut attribute in some positive and negative cases #![allow(unused_assignments)] @@ -18,15 +21,22 @@ fn main() { // negative cases - let mut a = 3; //~ ERROR: variable does not need to be mutable - let mut a = 2; //~ ERROR: variable does not need to be mutable - let mut b = 3; //~ ERROR: variable does not need to be mutable - let mut a = vec![3]; //~ ERROR: variable does not need to be mutable - let (mut a, b) = (1, 2); //~ ERROR: variable does not need to be mutable - let mut a; //~ ERROR: variable does not need to be mutable + let mut a = 3; //[lexical]~ ERROR: variable does not need to be mutable + //[nll]~^ ERROR: variable does not need to be mutable + let mut a = 2; //[lexical]~ ERROR: variable does not need to be mutable + //[nll]~^ ERROR: variable does not need to be mutable + let mut b = 3; //[lexical]~ ERROR: variable does not need to be mutable + //[nll]~^ ERROR: variable does not need to be mutable + let mut a = vec![3]; //[lexical]~ ERROR: variable does not need to be mutable + //[nll]~^ ERROR: variable does not need to be mutable + let (mut a, b) = (1, 2); //[lexical]~ ERROR: variable does not need to be mutable + //[nll]~^ ERROR: variable does not need to be mutable + let mut a; //[lexical]~ ERROR: variable does not need to be mutable + //[nll]~^ ERROR: variable does not need to be mutable a = 3; - let mut b; //~ ERROR: variable does not need to be mutable + let mut b; //[lexical]~ ERROR: variable does not need to be mutable + //[nll]~^ ERROR: variable does not need to be mutable if true { b = 3; } else { @@ -34,37 +44,45 @@ fn main() { } match 30 { - mut x => {} //~ ERROR: variable does not need to be mutable + mut x => {} //[lexical]~ ERROR: variable does not need to be mutable + //[nll]~^ ERROR: variable does not need to be mutable } match (30, 2) { - (mut x, 1) | //~ ERROR: variable does not need to be mutable + (mut x, 1) | //[lexical]~ ERROR: variable does not need to be mutable + //[nll]~^ ERROR: variable does not need to be mutable (mut x, 2) | (mut x, 3) => { } _ => {} } - let x = |mut y: isize| 10; //~ ERROR: variable does not need to be mutable - fn what(mut foo: isize) {} //~ ERROR: variable does not need to be mutable + let x = |mut y: isize| 10; //[lexical]~ ERROR: variable does not need to be mutable + //[nll]~^ ERROR: variable does not need to be mutable + fn what(mut foo: isize) {} //[lexical]~ ERROR: variable does not need to be mutable + //[nll]~^ ERROR: variable does not need to be mutable - let mut a = &mut 5; //~ ERROR: variable does not need to be mutable + let mut a = &mut 5; //[lexical]~ ERROR: variable does not need to be mutable + //[nll]~^ ERROR: variable does not need to be mutable *a = 4; let mut a = 5; - let mut b = (&mut a,); - *b.0 = 4; //~^ ERROR: variable does not need to be mutable + let mut b = (&mut a,); //[lexical]~ ERROR: variable does not need to be mutable + *b.0 = 4; //[nll]~^ ERROR: variable does not need to be mutable - let mut x = &mut 1; //~ ERROR: variable does not need to be mutable + let mut x = &mut 1; //[lexical]~ ERROR: variable does not need to be mutable + //[nll]~^ ERROR: variable does not need to be mutable let mut f = || { *x += 1; }; f(); fn mut_ref_arg(mut arg : &mut [u8]) -> &mut [u8] { - &mut arg[..] //~^ ERROR: variable does not need to be mutable + &mut arg[..] //[lexical]~^ ERROR: variable does not need to be mutable + //[nll]~^^ ERROR: variable does not need to be mutable } - let mut v : &mut Vec<()> = &mut vec![]; //~ ERROR: variable does not need to be mutable + let mut v : &mut Vec<()> = &mut vec![]; //[lexical]~ ERROR: variable does not need to be mutable + //[nll]~^ ERROR: variable does not need to be mutable v.push(()); // positive cases @@ -76,6 +94,12 @@ fn main() { callback(|| { a.push(3); }); + let mut a = Vec::new(); + callback(|| { + callback(|| { + a.push(3); + }); + }); let (mut a, b) = (1, 2); a = 34; @@ -116,5 +140,6 @@ fn foo(mut a: isize) { fn bar() { #[allow(unused_mut)] let mut a = 3; - let mut b = vec![2]; //~ ERROR: variable does not need to be mutable + let mut b = vec![2]; //[lexical]~ ERROR: variable does not need to be mutable + //[nll]~^ ERROR: variable does not need to be mutable } diff --git a/src/test/compile-fail/loop-break-value.rs b/src/test/compile-fail/loop-break-value.rs index 5ef46bb27fd..938f7fba2a0 100644 --- a/src/test/compile-fail/loop-break-value.rs +++ b/src/test/compile-fail/loop-break-value.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(never_type)] + fn main() { let val: ! = loop { break break; }; //~^ ERROR mismatched types diff --git a/src/test/compile-fail/macro-with-seps-err-msg.rs b/src/test/compile-fail/macro-with-seps-err-msg.rs index 0f123997ca1..6567a100d8c 100644 --- a/src/test/compile-fail/macro-with-seps-err-msg.rs +++ b/src/test/compile-fail/macro-with-seps-err-msg.rs @@ -10,6 +10,8 @@ // gate-test-use_extern_macros +#![feature(proc_macro_path_invoc)] + fn main() { globnar::brotz!(); //~ ERROR non-ident macro paths are experimental #[derive(foo::Bar)] struct T; //~ ERROR non-ident macro paths are experimental diff --git a/src/test/compile-fail/match-privately-empty.rs b/src/test/compile-fail/match-privately-empty.rs index e18c7d77ce3..8777ef2ffe3 100644 --- a/src/test/compile-fail/match-privately-empty.rs +++ b/src/test/compile-fail/match-privately-empty.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(never_type)] #![feature(exhaustive_patterns)] mod private { diff --git a/src/test/compile-fail/mir_check_cast_unsize.rs b/src/test/compile-fail/mir_check_cast_unsize.rs index e30bed61058..a2c840a7098 100644 --- a/src/test/compile-fail/mir_check_cast_unsize.rs +++ b/src/test/compile-fail/mir_check_cast_unsize.rs @@ -11,7 +11,6 @@ // compile-flags: -Z borrowck=mir #![allow(dead_code)] -#![feature(dyn_trait)] use std::fmt::Debug; diff --git a/src/test/compile-fail/never-assign-dead-code.rs b/src/test/compile-fail/never-assign-dead-code.rs index 4e987d1ddce..0fb75b535c6 100644 --- a/src/test/compile-fail/never-assign-dead-code.rs +++ b/src/test/compile-fail/never-assign-dead-code.rs @@ -10,6 +10,7 @@ // Test that an assignment of type ! makes the rest of the block dead code. +#![feature(never_type)] #![feature(rustc_attrs)] #![warn(unused)] diff --git a/src/test/compile-fail/never-assign-wrong-type.rs b/src/test/compile-fail/never-assign-wrong-type.rs index 8c2de7d68d3..c0dd2cab749 100644 --- a/src/test/compile-fail/never-assign-wrong-type.rs +++ b/src/test/compile-fail/never-assign-wrong-type.rs @@ -10,6 +10,7 @@ // Test that we can't use another type in place of ! +#![feature(never_type)] #![deny(warnings)] fn main() { diff --git a/src/test/compile-fail/rfc-2126-crate-paths/crate-path-non-absolute.rs b/src/test/compile-fail/rfc-2126-crate-paths/crate-path-non-absolute.rs index 75c2a5f5bc4..65f11c063ed 100644 --- a/src/test/compile-fail/rfc-2126-crate-paths/crate-path-non-absolute.rs +++ b/src/test/compile-fail/rfc-2126-crate-paths/crate-path-non-absolute.rs @@ -12,9 +12,10 @@ struct S; -mod m { +pub mod m { fn f() { - let s = crate::S; //~ ERROR `crate` can only be used in absolute paths + let s = ::m::crate::S; //~ ERROR failed to resolve + let s2 = crate::S; // no error } } diff --git a/src/test/compile-fail/rfc-2126-crate-paths/keyword-crate-as-identifier.rs b/src/test/compile-fail/rfc-2126-crate-paths/keyword-crate-as-identifier.rs index 2c94f7b0f59..bdd03be4356 100644 --- a/src/test/compile-fail/rfc-2126-crate-paths/keyword-crate-as-identifier.rs +++ b/src/test/compile-fail/rfc-2126-crate-paths/keyword-crate-as-identifier.rs @@ -11,5 +11,5 @@ #![feature(crate_in_paths)] fn main() { - let crate = 0; //~ ERROR `crate` can only be used in absolute paths + let crate = 0; //~ ERROR failed to resolve. `crate` in paths can only be used in start position } diff --git a/src/test/compile-fail/single-primitive-inherent-impl.rs b/src/test/compile-fail/single-primitive-inherent-impl.rs index 365387c3e5e..0a0f9ce4bd1 100644 --- a/src/test/compile-fail/single-primitive-inherent-impl.rs +++ b/src/test/compile-fail/single-primitive-inherent-impl.rs @@ -15,7 +15,7 @@ #![no_std] // OK -#[lang = "str"] +#[lang = "str_alloc"] impl str {} impl str { diff --git a/src/test/compile-fail/trait-bounds-not-on-struct.rs b/src/test/compile-fail/trait-bounds-not-on-struct.rs index 0dd1a4e7d73..1b1a238a941 100644 --- a/src/test/compile-fail/trait-bounds-not-on-struct.rs +++ b/src/test/compile-fail/trait-bounds-not-on-struct.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(dyn_trait)] #![allow(bare_trait_object)] struct Foo; diff --git a/src/test/compile-fail/uninhabited-irrefutable.rs b/src/test/compile-fail/uninhabited-irrefutable.rs index 72b0afa6bd3..05a97b855e7 100644 --- a/src/test/compile-fail/uninhabited-irrefutable.rs +++ b/src/test/compile-fail/uninhabited-irrefutable.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(never_type)] #![feature(exhaustive_patterns)] mod foo { diff --git a/src/test/compile-fail/uninhabited-patterns.rs b/src/test/compile-fail/uninhabited-patterns.rs index e130df5c845..2cf4b78bdff 100644 --- a/src/test/compile-fail/uninhabited-patterns.rs +++ b/src/test/compile-fail/uninhabited-patterns.rs @@ -10,6 +10,7 @@ #![feature(box_patterns)] #![feature(box_syntax)] +#![feature(never_type)] #![feature(exhaustive_patterns)] #![feature(slice_patterns)] #![deny(unreachable_patterns)] diff --git a/src/test/compile-fail/unreachable-loop-patterns.rs b/src/test/compile-fail/unreachable-loop-patterns.rs index dca79bdfb87..cfd829e416e 100644 --- a/src/test/compile-fail/unreachable-loop-patterns.rs +++ b/src/test/compile-fail/unreachable-loop-patterns.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(never_type)] #![feature(exhaustive_patterns)] #![deny(unreachable_patterns)] diff --git a/src/test/compile-fail/unreachable-try-pattern.rs b/src/test/compile-fail/unreachable-try-pattern.rs index 0caf7d51234..df340095bb4 100644 --- a/src/test/compile-fail/unreachable-try-pattern.rs +++ b/src/test/compile-fail/unreachable-try-pattern.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(never_type)] #![feature(exhaustive_patterns, rustc_attrs)] #![warn(unreachable_code)] #![warn(unreachable_patterns)] diff --git a/src/test/debuginfo/c-style-enum.rs b/src/test/debuginfo/c-style-enum.rs index 1f1f42e2dec..2dbac8e3d9e 100644 --- a/src/test/debuginfo/c-style-enum.rs +++ b/src/test/debuginfo/c-style-enum.rs @@ -151,6 +151,7 @@ enum ManualDiscriminant { } #[derive(Copy, Clone)] +#[repr(u8)] enum SingleVariant { TheOnlyVariant } diff --git a/src/test/run-fail/adjust_never.rs b/src/test/run-fail/adjust_never.rs index 7a4b5e59eeb..da68dc39f85 100644 --- a/src/test/run-fail/adjust_never.rs +++ b/src/test/run-fail/adjust_never.rs @@ -11,6 +11,9 @@ // Test that a variable of type ! can coerce to another type. // error-pattern:explicit + +#![feature(never_type)] + fn main() { let x: ! = panic!(); let y: u32 = x; diff --git a/src/test/run-fail/call-fn-never-arg.rs b/src/test/run-fail/call-fn-never-arg.rs index 56454586bb9..95101e70db9 100644 --- a/src/test/run-fail/call-fn-never-arg.rs +++ b/src/test/run-fail/call-fn-never-arg.rs @@ -12,6 +12,7 @@ // error-pattern:wowzers! +#![feature(never_type)] #![allow(unreachable_code)] fn foo(x: !) -> ! { diff --git a/src/test/run-fail/cast-never.rs b/src/test/run-fail/cast-never.rs index 0155332c51d..8f7b0c40538 100644 --- a/src/test/run-fail/cast-never.rs +++ b/src/test/run-fail/cast-never.rs @@ -11,6 +11,9 @@ // Test that we can explicitly cast ! to another type // error-pattern:explicit + +#![feature(never_type)] + fn main() { let x: ! = panic!(); let y: u32 = x as u32; diff --git a/src/test/run-fail/never-associated-type.rs b/src/test/run-fail/never-associated-type.rs index d9b8461a1d0..fdd21e08c20 100644 --- a/src/test/run-fail/never-associated-type.rs +++ b/src/test/run-fail/never-associated-type.rs @@ -12,6 +12,8 @@ // error-pattern:kapow! +#![feature(never_type)] + trait Foo { type Wow; diff --git a/src/test/run-fail/never-type-arg.rs b/src/test/run-fail/never-type-arg.rs index 0fe10d43910..826ca3a08c0 100644 --- a/src/test/run-fail/never-type-arg.rs +++ b/src/test/run-fail/never-type-arg.rs @@ -12,6 +12,8 @@ // error-pattern:oh no! +#![feature(never_type)] + struct Wub; impl PartialEq<!> for Wub { diff --git a/src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-box-dyn-error.rs b/src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-box-dyn-error.rs index 219eca6fd21..66a6e6afed3 100644 --- a/src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-box-dyn-error.rs +++ b/src/test/run-fail/rfc-1937-termination-trait/termination-trait-for-box-dyn-error.rs @@ -11,8 +11,6 @@ // compile-pass // failure-status: 1 -#![feature(dyn_trait)] - use std::error::Error; use std::io; diff --git a/src/test/run-pass-fulldeps/auxiliary/cond_plugin.rs b/src/test/run-pass-fulldeps/auxiliary/cond_plugin.rs index 281ee70815e..9e1ae59c01b 100644 --- a/src/test/run-pass-fulldeps/auxiliary/cond_plugin.rs +++ b/src/test/run-pass-fulldeps/auxiliary/cond_plugin.rs @@ -11,7 +11,7 @@ // no-prefer-dynamic #![crate_type = "proc-macro"] -#![feature(proc_macro)] +#![feature(proc_macro, proc_macro_non_items)] extern crate proc_macro; diff --git a/src/test/run-pass-fulldeps/auxiliary/custom_derive_partial_eq.rs b/src/test/run-pass-fulldeps/auxiliary/custom_derive_partial_eq.rs index f485982e2d3..6d5e82c68cc 100644 --- a/src/test/run-pass-fulldeps/auxiliary/custom_derive_partial_eq.rs +++ b/src/test/run-pass-fulldeps/auxiliary/custom_derive_partial_eq.rs @@ -58,7 +58,7 @@ fn expand_deriving_partial_eq(cx: &mut ExtCtxt, span: Span, mitem: &MetaItem, it name: "eq", generics: LifetimeBounds::empty(), explicit_self: borrowed_explicit_self(), - args: vec![borrowed_self()], + args: vec![(borrowed_self(), "other")], ret_ty: Literal(deriving::generic::ty::Path::new_local("bool")), attributes: attrs, is_unsafe: false, diff --git a/src/test/run-pass-fulldeps/auxiliary/hello_macro.rs b/src/test/run-pass-fulldeps/auxiliary/hello_macro.rs index cf6584e961a..a680698df9a 100644 --- a/src/test/run-pass-fulldeps/auxiliary/hello_macro.rs +++ b/src/test/run-pass-fulldeps/auxiliary/hello_macro.rs @@ -11,7 +11,7 @@ // no-prefer-dynamic #![crate_type = "proc-macro"] -#![feature(proc_macro, proc_macro_lib)] +#![feature(proc_macro, proc_macro_lib, proc_macro_non_items)] extern crate proc_macro; diff --git a/src/test/run-pass-fulldeps/auxiliary/proc_macro_def.rs b/src/test/run-pass-fulldeps/auxiliary/proc_macro_def.rs index d3670ae66fe..a280b3d87c6 100644 --- a/src/test/run-pass-fulldeps/auxiliary/proc_macro_def.rs +++ b/src/test/run-pass-fulldeps/auxiliary/proc_macro_def.rs @@ -11,7 +11,7 @@ // no-prefer-dynamic #![crate_type = "proc-macro"] -#![feature(proc_macro, proc_macro_lib)] +#![feature(proc_macro, proc_macro_lib, proc_macro_non_items)] extern crate proc_macro; diff --git a/src/test/run-pass-fulldeps/deriving-hygiene.rs b/src/test/run-pass-fulldeps/deriving-hygiene.rs new file mode 100644 index 00000000000..532f2456599 --- /dev/null +++ b/src/test/run-pass-fulldeps/deriving-hygiene.rs @@ -0,0 +1,25 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(rustc_private)] +extern crate serialize; + +pub const other: u8 = 1; +pub const f: u8 = 1; +pub const d: u8 = 1; +pub const s: u8 = 1; +pub const state: u8 = 1; +pub const cmp: u8 = 1; + +#[derive(Ord,Eq,PartialOrd,PartialEq,Debug,Decodable,Encodable,Hash)] +struct Foo {} + +fn main() { +} diff --git a/src/test/run-pass-fulldeps/macro-quote-cond.rs b/src/test/run-pass-fulldeps/macro-quote-cond.rs index cff743bdae6..52e8e75f262 100644 --- a/src/test/run-pass-fulldeps/macro-quote-cond.rs +++ b/src/test/run-pass-fulldeps/macro-quote-cond.rs @@ -11,7 +11,7 @@ // aux-build:cond_plugin.rs // ignore-stage1 -#![feature(proc_macro)] +#![feature(proc_macro, proc_macro_non_items)] extern crate cond_plugin; diff --git a/src/test/run-pass-fulldeps/macro-quote-test.rs b/src/test/run-pass-fulldeps/macro-quote-test.rs index eb77895e2d7..f359735d2f7 100644 --- a/src/test/run-pass-fulldeps/macro-quote-test.rs +++ b/src/test/run-pass-fulldeps/macro-quote-test.rs @@ -13,7 +13,7 @@ // aux-build:hello_macro.rs // ignore-stage1 -#![feature(proc_macro)] +#![feature(proc_macro, proc_macro_non_items)] extern crate hello_macro; diff --git a/src/test/run-pass-fulldeps/proc-macro/attr-args.rs b/src/test/run-pass-fulldeps/proc-macro/attr-args.rs index 2968cc7871d..bf7ac507ea5 100644 --- a/src/test/run-pass-fulldeps/proc-macro/attr-args.rs +++ b/src/test/run-pass-fulldeps/proc-macro/attr-args.rs @@ -12,7 +12,7 @@ // ignore-stage1 #![allow(warnings)] -#![feature(proc_macro)] +#![feature(proc_macro, proc_macro_path_invoc)] extern crate attr_args; use attr_args::attr_with_args; @@ -20,6 +20,6 @@ use attr_args::attr_with_args; #[attr_with_args(text = "Hello, world!")] fn foo() {} -#[::attr_args::identity - fn main() { assert_eq!(foo(), "Hello, world!"); }] +#[::attr_args::identity( + fn main() { assert_eq!(foo(), "Hello, world!"); })] struct Dummy; diff --git a/src/test/run-pass-fulldeps/proc-macro/attr-on-trait.rs b/src/test/run-pass-fulldeps/proc-macro/attr-on-trait.rs index 52a8652e65b..95e4f2211c6 100644 --- a/src/test/run-pass-fulldeps/proc-macro/attr-on-trait.rs +++ b/src/test/run-pass-fulldeps/proc-macro/attr-on-trait.rs @@ -11,7 +11,7 @@ // aux-build:attr-on-trait.rs // ignore-stage1 -#![feature(proc_macro)] +#![feature(proc_macro, proc_macro_path_invoc)] extern crate attr_on_trait; diff --git a/src/test/run-pass-fulldeps/proc-macro/attr-stmt-expr.rs b/src/test/run-pass-fulldeps/proc-macro/attr-stmt-expr.rs index 98316c62ef1..d928f8e5573 100644 --- a/src/test/run-pass-fulldeps/proc-macro/attr-stmt-expr.rs +++ b/src/test/run-pass-fulldeps/proc-macro/attr-stmt-expr.rs @@ -11,7 +11,7 @@ // aux-build:attr-stmt-expr.rs // ignore-stage1 -#![feature(proc_macro, stmt_expr_attributes)] +#![feature(proc_macro, stmt_expr_attributes, proc_macro_stmt, proc_macro_expr)] extern crate attr_stmt_expr; use attr_stmt_expr::{expect_let, expect_print_stmt, expect_expr, expect_print_expr, diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/attr-args.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/attr-args.rs index 93815d16837..5f12cc96e9f 100644 --- a/src/test/run-pass-fulldeps/proc-macro/auxiliary/attr-args.rs +++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/attr-args.rs @@ -20,7 +20,7 @@ use proc_macro::TokenStream; pub fn attr_with_args(args: TokenStream, input: TokenStream) -> TokenStream { let args = args.to_string(); - assert_eq!(args, r#"( text = "Hello, world!" )"#); + assert_eq!(args, r#"text = "Hello, world!""#); let input = input.to_string(); diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/count_compound_ops.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/count_compound_ops.rs index 063d8dc4053..5376d274045 100644 --- a/src/test/run-pass-fulldeps/proc-macro/auxiliary/count_compound_ops.rs +++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/count_compound_ops.rs @@ -10,7 +10,7 @@ // no-prefer-dynamic -#![feature(proc_macro)] +#![feature(proc_macro, proc_macro_non_items)] #![crate_type = "proc-macro"] extern crate proc_macro; diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/hygiene_example_codegen.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/hygiene_example_codegen.rs index 055e4e2fad7..b8562ffc344 100644 --- a/src/test/run-pass-fulldeps/proc-macro/auxiliary/hygiene_example_codegen.rs +++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/hygiene_example_codegen.rs @@ -10,7 +10,7 @@ // no-prefer-dynamic -#![feature(proc_macro)] +#![feature(proc_macro, proc_macro_non_items)] #![crate_type = "proc-macro"] extern crate proc_macro as proc_macro_renamed; // This does not break `quote!` diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/issue-50061.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/issue-50061.rs new file mode 100644 index 00000000000..b3cd3758e65 --- /dev/null +++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/issue-50061.rs @@ -0,0 +1,22 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// no-prefer-dynamic + +#![crate_type = "proc-macro"] +#![feature(proc_macro)] + +extern crate proc_macro; +use proc_macro::TokenStream; + +#[proc_macro_attribute] +pub fn check(_a: TokenStream, b: TokenStream) -> TokenStream { + b.into_iter().collect() +} diff --git a/src/test/run-pass-fulldeps/proc-macro/bang-macro.rs b/src/test/run-pass-fulldeps/proc-macro/bang-macro.rs index ffa4731f1e6..82337022ac3 100644 --- a/src/test/run-pass-fulldeps/proc-macro/bang-macro.rs +++ b/src/test/run-pass-fulldeps/proc-macro/bang-macro.rs @@ -11,7 +11,7 @@ // aux-build:bang-macro.rs // ignore-stage1 -#![feature(proc_macro)] +#![feature(proc_macro, proc_macro_non_items)] extern crate bang_macro; use bang_macro::rewrite; diff --git a/src/test/run-pass-fulldeps/proc-macro/count_compound_ops.rs b/src/test/run-pass-fulldeps/proc-macro/count_compound_ops.rs index 00ad0e76ed0..3fbe5366b6a 100644 --- a/src/test/run-pass-fulldeps/proc-macro/count_compound_ops.rs +++ b/src/test/run-pass-fulldeps/proc-macro/count_compound_ops.rs @@ -11,7 +11,7 @@ // aux-build:count_compound_ops.rs // ignore-stage1 -#![feature(proc_macro)] +#![feature(proc_macro, proc_macro_non_items)] extern crate count_compound_ops; use count_compound_ops::count_compound_ops; diff --git a/src/test/run-pass-fulldeps/proc-macro/derive-b.rs b/src/test/run-pass-fulldeps/proc-macro/derive-b.rs index 995dc65729a..d4176c0efbf 100644 --- a/src/test/run-pass-fulldeps/proc-macro/derive-b.rs +++ b/src/test/run-pass-fulldeps/proc-macro/derive-b.rs @@ -11,7 +11,7 @@ // aux-build:derive-b.rs // ignore-stage1 -#![feature(proc_macro)] +#![feature(proc_macro, proc_macro_path_invoc)] extern crate derive_b; diff --git a/src/test/run-pass-fulldeps/proc-macro/hygiene_example.rs b/src/test/run-pass-fulldeps/proc-macro/hygiene_example.rs index 4cac7d19b4d..48de15b934d 100644 --- a/src/test/run-pass-fulldeps/proc-macro/hygiene_example.rs +++ b/src/test/run-pass-fulldeps/proc-macro/hygiene_example.rs @@ -12,7 +12,7 @@ // aux-build:hygiene_example.rs // ignore-stage1 -#![feature(proc_macro)] +#![feature(proc_macro, proc_macro_non_items)] extern crate hygiene_example; use hygiene_example::hello; diff --git a/src/test/run-pass-fulldeps/proc-macro/issue-42708.rs b/src/test/run-pass-fulldeps/proc-macro/issue-42708.rs index e53e94ae475..a6b7d93c279 100644 --- a/src/test/run-pass-fulldeps/proc-macro/issue-42708.rs +++ b/src/test/run-pass-fulldeps/proc-macro/issue-42708.rs @@ -11,7 +11,7 @@ // aux-build:issue-42708.rs // ignore-stage1 -#![feature(decl_macro, proc_macro)] +#![feature(decl_macro, proc_macro, proc_macro_path_invoc)] #![allow(unused)] extern crate issue_42708; diff --git a/src/test/run-pass-fulldeps/proc-macro/issue-50061.rs b/src/test/run-pass-fulldeps/proc-macro/issue-50061.rs new file mode 100644 index 00000000000..03f69c09277 --- /dev/null +++ b/src/test/run-pass-fulldeps/proc-macro/issue-50061.rs @@ -0,0 +1,31 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:issue-50061.rs +// ignore-stage1 + +#![feature(proc_macro, proc_macro_path_invoc, decl_macro)] + +extern crate issue_50061; + +macro inner(any_token $v: tt) { + $v +} + +macro outer($v: tt) { + inner!(any_token $v) +} + +#[issue_50061::check] +fn main() { + //! this doc comment forces roundtrip through a string + let checkit = 0; + outer!(checkit); +} diff --git a/src/test/run-pass-fulldeps/proc-macro/negative-token.rs b/src/test/run-pass-fulldeps/proc-macro/negative-token.rs index 418e692fa24..1cdf1daf560 100644 --- a/src/test/run-pass-fulldeps/proc-macro/negative-token.rs +++ b/src/test/run-pass-fulldeps/proc-macro/negative-token.rs @@ -11,7 +11,7 @@ // aux-build:negative-token.rs // ignore-stage1 -#![feature(proc_macro)] +#![feature(proc_macro, proc_macro_non_items)] extern crate negative_token; diff --git a/src/test/run-pass-fulldeps/proc_macro.rs b/src/test/run-pass-fulldeps/proc_macro.rs index cdda723585b..aad94c89f2a 100644 --- a/src/test/run-pass-fulldeps/proc_macro.rs +++ b/src/test/run-pass-fulldeps/proc_macro.rs @@ -12,7 +12,7 @@ // ignore-stage1 // ignore-cross-compile -#![feature(proc_macro)] +#![feature(proc_macro, proc_macro_non_items)] extern crate proc_macro_def; diff --git a/src/test/run-pass/allocator-alloc-one.rs b/src/test/run-pass/allocator-alloc-one.rs index d4fcdcf743b..12b115d0938 100644 --- a/src/test/run-pass/allocator-alloc-one.rs +++ b/src/test/run-pass/allocator-alloc-one.rs @@ -10,13 +10,11 @@ #![feature(allocator_api, nonnull)] -use std::alloc::{Alloc, Global}; +use std::alloc::{Alloc, Global, oom}; fn main() { unsafe { - let ptr = Global.alloc_one::<i32>().unwrap_or_else(|_| { - Global.oom() - }); + let ptr = Global.alloc_one::<i32>().unwrap_or_else(|_| oom()); *ptr.as_ptr() = 4; assert_eq!(*ptr.as_ptr(), 4); Global.dealloc_one(ptr); diff --git a/src/test/run-pass/auxiliary/issue-48984-aux.rs b/src/test/run-pass/auxiliary/issue-48984-aux.rs new file mode 100644 index 00000000000..6290279701e --- /dev/null +++ b/src/test/run-pass/auxiliary/issue-48984-aux.rs @@ -0,0 +1,16 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_type = "lib"] +#![crate_name = "issue48984aux"] + +pub trait Foo { type Item; } + +pub trait Bar: Foo<Item=[u8;1]> { } diff --git a/src/test/run-pass/auxiliary/using-target-feature-unstable.rs b/src/test/run-pass/auxiliary/using-target-feature-unstable.rs new file mode 100644 index 00000000000..8b7d0332fe9 --- /dev/null +++ b/src/test/run-pass/auxiliary/using-target-feature-unstable.rs @@ -0,0 +1,15 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(mmx_target_feature)] + +#[inline] +#[target_feature(enable = "mmx")] +pub unsafe fn foo() {} diff --git a/src/test/run-pass/borrowck/borrowck-unused-mut-locals.rs b/src/test/run-pass/borrowck/borrowck-unused-mut-locals.rs new file mode 100644 index 00000000000..7f1b6ed1701 --- /dev/null +++ b/src/test/run-pass/borrowck/borrowck-unused-mut-locals.rs @@ -0,0 +1,56 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(nll)] +#![deny(unused_mut)] + +#[derive(Debug)] +struct A {} + +fn init_a() -> A { + A {} +} + +#[derive(Debug)] +struct B<'a> { + ed: &'a mut A, +} + +fn init_b<'a>(ed: &'a mut A) -> B<'a> { + B { ed } +} + +#[derive(Debug)] +struct C<'a> { + pd: &'a mut B<'a>, +} + +fn init_c<'a>(pd: &'a mut B<'a>) -> C<'a> { + C { pd } +} + +#[derive(Debug)] +struct D<'a> { + sd: &'a mut C<'a>, +} + +fn init_d<'a>(sd: &'a mut C<'a>) -> D<'a> { + D { sd } +} + +fn main() { + let mut a = init_a(); + let mut b = init_b(&mut a); + let mut c = init_c(&mut b); + + let d = init_d(&mut c); + + println!("{:?}", d) +} diff --git a/src/test/run-pass/compiletest-skip-trans.rs b/src/test/run-pass/compiletest-skip-trans.rs new file mode 100644 index 00000000000..d24a6506c2c --- /dev/null +++ b/src/test/run-pass/compiletest-skip-trans.rs @@ -0,0 +1,17 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that with the `skip-trans` option the test isn't executed. + +// skip-trans + +fn main() { + unreachable!(); +} diff --git a/src/test/run-pass/diverging-fallback-control-flow.rs b/src/test/run-pass/diverging-fallback-control-flow.rs index a96f98b9efd..723a98bcdfa 100644 --- a/src/test/run-pass/diverging-fallback-control-flow.rs +++ b/src/test/run-pass/diverging-fallback-control-flow.rs @@ -14,6 +14,8 @@ // These represent current behavior, but are pretty dubious. I would // like to revisit these and potentially change them. --nmatsakis +#![feature(never_type)] + trait BadDefault { fn default() -> Self; } diff --git a/src/test/run-pass/dyn-trait.rs b/src/test/run-pass/dyn-trait.rs index 399823ec92d..01066794242 100644 --- a/src/test/run-pass/dyn-trait.rs +++ b/src/test/run-pass/dyn-trait.rs @@ -10,8 +10,6 @@ // ignore-pretty `dyn ::foo` parses differently in the current edition -#![feature(dyn_trait)] - use std::fmt::Display; static BYTE: u8 = 33; diff --git a/src/test/run-pass/empty-types-in-patterns.rs b/src/test/run-pass/empty-types-in-patterns.rs index 87db4401929..86cf9b5ec47 100644 --- a/src/test/run-pass/empty-types-in-patterns.rs +++ b/src/test/run-pass/empty-types-in-patterns.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(never_type)] #![feature(exhaustive_patterns)] #![feature(slice_patterns)] #![allow(unreachable_patterns)] diff --git a/src/test/run-pass/format-hygiene.rs b/src/test/run-pass/format-hygiene.rs new file mode 100644 index 00000000000..6971f775231 --- /dev/null +++ b/src/test/run-pass/format-hygiene.rs @@ -0,0 +1,15 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub const arg0: u8 = 1; + +pub fn main() { + format!("{}", 1); +} diff --git a/src/test/run-pass/impl-for-never.rs b/src/test/run-pass/impl-for-never.rs index cf54e1c3bd5..794f5969bff 100644 --- a/src/test/run-pass/impl-for-never.rs +++ b/src/test/run-pass/impl-for-never.rs @@ -10,6 +10,8 @@ // Test that we can call static methods on ! both directly and when it appears in a generic +#![feature(never_type)] + trait StringifyType { fn stringify_type() -> &'static str; } diff --git a/src/test/run-pass/issue-23304-2.rs b/src/test/run-pass/issue-23304-2.rs index 79712f7c25e..5989b7e9c6a 100644 --- a/src/test/run-pass/issue-23304-2.rs +++ b/src/test/run-pass/issue-23304-2.rs @@ -10,8 +10,13 @@ #![allow(dead_code)] -enum X { A = 0 as isize } +enum X { A = 42 as isize } enum Y { A = X::A as isize } -fn main() { } +fn main() { + let x = X::A; + let x = x as isize; + assert_eq!(x, 42); + assert_eq!(Y::A as isize, 42); +} diff --git a/src/test/run-pass/issue-44402.rs b/src/test/run-pass/issue-44402.rs index a5a0a5a5794..5cbd3446d9b 100644 --- a/src/test/run-pass/issue-44402.rs +++ b/src/test/run-pass/issue-44402.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(never_type)] #![feature(exhaustive_patterns)] // Regression test for inhabitedness check. The old diff --git a/src/test/run-pass/issue-47703-tuple.rs b/src/test/run-pass/issue-47703-tuple.rs new file mode 100644 index 00000000000..4fec3efc0a0 --- /dev/null +++ b/src/test/run-pass/issue-47703-tuple.rs @@ -0,0 +1,21 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(nll)] + +struct WithDrop; + +impl Drop for WithDrop { + fn drop(&mut self) {} +} + +fn consume(x: (&mut (), WithDrop)) -> &mut () { x.0 } + +fn main() {} diff --git a/src/test/run-pass/issue-48984.rs b/src/test/run-pass/issue-48984.rs new file mode 100644 index 00000000000..227ad4e58f1 --- /dev/null +++ b/src/test/run-pass/issue-48984.rs @@ -0,0 +1,17 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:issue-48984-aux.rs +extern crate issue48984aux; +use issue48984aux::Bar; + +fn do_thing<T: Bar>() { } + +fn main() { } diff --git a/src/test/run-pass/issue-49632.rs b/src/test/run-pass/issue-49632.rs new file mode 100644 index 00000000000..8cbb7d21af7 --- /dev/null +++ b/src/test/run-pass/issue-49632.rs @@ -0,0 +1,17 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(stmt_expr_attributes)] + +pub fn main() { + let _x = #[inline(always)] || {}; + let _y = #[inline(never)] || {}; + let _z = #[inline] || {}; +} diff --git a/src/test/run-pass/issue-49685.rs b/src/test/run-pass/issue-49685.rs new file mode 100644 index 00000000000..1e4e7955323 --- /dev/null +++ b/src/test/run-pass/issue-49685.rs @@ -0,0 +1,22 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Regression test for #49685: drop elaboration was not revealing the +// value of `impl Trait` returns, leading to an ICE. + +fn main() { + let _ = Some(()) + .into_iter() + .flat_map(|_| Some(()).into_iter().flat_map(func)); +} + +fn func(_: ()) -> impl Iterator<Item = ()> { + Some(()).into_iter().flat_map(|_| vec![]) +} diff --git a/src/test/run-pass/issue-49973.rs b/src/test/run-pass/issue-49973.rs new file mode 100644 index 00000000000..641e9239177 --- /dev/null +++ b/src/test/run-pass/issue-49973.rs @@ -0,0 +1,20 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[derive(Debug)] +#[repr(i32)] +enum E { + Min = -2147483648i32, + _Max = 2147483647i32, +} + +fn main() { + assert_eq!(Some(E::Min).unwrap() as i32, -2147483648i32); +} diff --git a/src/test/run-pass/loop-break-value.rs b/src/test/run-pass/loop-break-value.rs index ffdd99ebf6e..39053769b24 100644 --- a/src/test/run-pass/loop-break-value.rs +++ b/src/test/run-pass/loop-break-value.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(never_type)] + #[allow(unused)] fn never_returns() { loop { diff --git a/src/test/run-pass/mir_calls_to_shims.rs b/src/test/run-pass/mir_calls_to_shims.rs index dda7a46f325..9641ed28293 100644 --- a/src/test/run-pass/mir_calls_to_shims.rs +++ b/src/test/run-pass/mir_calls_to_shims.rs @@ -11,6 +11,7 @@ // ignore-wasm32-bare compiled with panic=abort by default #![feature(fn_traits)] +#![feature(never_type)] use std::panic; diff --git a/src/test/run-pass/never-result.rs b/src/test/run-pass/never-result.rs index 8aa2a13ed8c..5c0af392f44 100644 --- a/src/test/run-pass/never-result.rs +++ b/src/test/run-pass/never-result.rs @@ -10,6 +10,8 @@ // Test that we can extract a ! through pattern matching then use it as several different types. +#![feature(never_type)] + fn main() { let x: Result<u32, !> = Ok(123); match x { diff --git a/src/test/run-pass/nll/issue-48623-closure.rs b/src/test/run-pass/nll/issue-48623-closure.rs new file mode 100644 index 00000000000..08ff54a428e --- /dev/null +++ b/src/test/run-pass/nll/issue-48623-closure.rs @@ -0,0 +1,24 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(nll)] + +struct WithDrop; + +impl Drop for WithDrop { + fn drop(&mut self) {} +} + +fn reborrow_from_closure(r: &mut ()) -> &mut () { + let d = WithDrop; + (move || { d; &mut *r })() +} + +fn main() {} diff --git a/src/test/run-pass/nll/issue-48623-generator.rs b/src/test/run-pass/nll/issue-48623-generator.rs new file mode 100644 index 00000000000..524837c4ba9 --- /dev/null +++ b/src/test/run-pass/nll/issue-48623-generator.rs @@ -0,0 +1,25 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(nll)] +#![feature(generators, generator_trait)] + +struct WithDrop; + +impl Drop for WithDrop { + fn drop(&mut self) {} +} + +fn reborrow_from_generator(r: &mut ()) { + let d = WithDrop; + move || { d; yield; &mut *r }; +} + +fn main() {} diff --git a/src/test/run-pass/realloc-16687.rs b/src/test/run-pass/realloc-16687.rs index 38cc23c16a9..308792e5d89 100644 --- a/src/test/run-pass/realloc-16687.rs +++ b/src/test/run-pass/realloc-16687.rs @@ -13,9 +13,9 @@ // Ideally this would be revised to use no_std, but for now it serves // well enough to reproduce (and illustrate) the bug from #16687. -#![feature(heap_api, allocator_api, nonnull_cast)] +#![feature(heap_api, allocator_api)] -use std::alloc::{Global, Alloc, Layout}; +use std::alloc::{Global, Alloc, Layout, oom}; use std::ptr::{self, NonNull}; fn main() { @@ -50,7 +50,7 @@ unsafe fn test_triangle() -> bool { println!("allocate({:?})", layout); } - let ret = Global.alloc(layout.clone()).unwrap_or_else(|_| Global.oom()); + let ret = Global.alloc(layout.clone()).unwrap_or_else(|_| oom()); if PRINT { println!("allocate({:?}) = {:?}", layout, ret); @@ -73,7 +73,7 @@ unsafe fn test_triangle() -> bool { } let ret = Global.realloc(NonNull::new_unchecked(ptr).as_opaque(), old.clone(), new.size()) - .unwrap_or_else(|_| Global.oom()); + .unwrap_or_else(|_| oom()); if PRINT { println!("reallocate({:?}, old={:?}, new={:?}) = {:?}", diff --git a/src/test/run-pass/regions-mock-trans.rs b/src/test/run-pass/regions-mock-trans.rs index 44be59f5c5b..60a7f70931d 100644 --- a/src/test/run-pass/regions-mock-trans.rs +++ b/src/test/run-pass/regions-mock-trans.rs @@ -12,7 +12,7 @@ #![feature(allocator_api)] -use std::alloc::{Alloc, Global, Layout}; +use std::alloc::{Alloc, Global, Layout, oom}; use std::ptr::NonNull; struct arena(()); @@ -33,7 +33,7 @@ struct Ccx { fn alloc<'a>(_bcx : &'a arena) -> &'a Bcx<'a> { unsafe { let ptr = Global.alloc(Layout::new::<Bcx>()) - .unwrap_or_else(|_| Global.oom()); + .unwrap_or_else(|_| oom()); &*(ptr.as_ptr() as *const _) } } diff --git a/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-box-dyn-error.rs b/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-box-dyn-error.rs index 24c30a5abc2..183bb553530 100644 --- a/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-box-dyn-error.rs +++ b/src/test/run-pass/rfc-1937-termination-trait/termination-trait-for-box-dyn-error.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(dyn_trait)] - use std::error::Error; fn main() -> Result<(), Box<dyn Error>> { diff --git a/src/test/compile-fail/rfc-2126-crate-paths/crate-visibility-ambiguity.rs b/src/test/run-pass/rfc-2126-crate-paths/crate-path-visibility-ambiguity.rs index 8c5a971c2f7..1a8d2d80ef4 100644 --- a/src/test/compile-fail/rfc-2126-crate-paths/crate-visibility-ambiguity.rs +++ b/src/test/run-pass/rfc-2126-crate-paths/crate-path-visibility-ambiguity.rs @@ -15,7 +15,7 @@ mod m { pub struct Z; pub struct S1(crate (::m::Z)); // OK pub struct S2(::crate ::m::Z); // OK - pub struct S3(crate ::m::Z); //~ ERROR `crate` can only be used in absolute paths + pub struct S3(crate ::m::Z); // OK } fn main() { diff --git a/src/test/run-pass/type-sizes.rs b/src/test/run-pass/type-sizes.rs index 0bb18d8729a..a47f082b9c3 100644 --- a/src/test/run-pass/type-sizes.rs +++ b/src/test/run-pass/type-sizes.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(never_type)] use std::mem::size_of; @@ -42,6 +43,31 @@ enum ReorderedEnum { B(u8, u16, u8), } +enum EnumEmpty {} + +enum EnumSingle1 { + A, +} + +enum EnumSingle2 { + A = 42 as isize, +} + +enum EnumSingle3 { + A, + B(!), +} + +#[repr(u8)] +enum EnumSingle4 { + A, +} + +#[repr(u8)] +enum EnumSingle5 { + A = 42 as u8, +} + enum NicheFilledEnumWithInhabitedVariant { A(&'static ()), B(&'static (), !), @@ -73,5 +99,13 @@ pub fn main() { assert_eq!(size_of::<e3>(), 4 as usize); assert_eq!(size_of::<ReorderedStruct>(), 4); assert_eq!(size_of::<ReorderedEnum>(), 6); + + assert_eq!(size_of::<EnumEmpty>(), 0); + assert_eq!(size_of::<EnumSingle1>(), 0); + assert_eq!(size_of::<EnumSingle2>(), 0); + assert_eq!(size_of::<EnumSingle3>(), 0); + assert_eq!(size_of::<EnumSingle4>(), 1); + assert_eq!(size_of::<EnumSingle5>(), 1); + assert_eq!(size_of::<NicheFilledEnumWithInhabitedVariant>(), size_of::<&'static ()>()); } diff --git a/src/test/run-pass/using-target-feature-unstable.rs b/src/test/run-pass/using-target-feature-unstable.rs new file mode 100644 index 00000000000..614c8d4e1d4 --- /dev/null +++ b/src/test/run-pass/using-target-feature-unstable.rs @@ -0,0 +1,20 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// only-x86_64 +// aux-build:using-target-feature-unstable.rs + +extern crate using_target_feature_unstable; + +fn main() { + unsafe { + using_target_feature_unstable::foo(); + } +} diff --git a/src/test/rustdoc-js/alias-1.js b/src/test/rustdoc-js/alias-1.js new file mode 100644 index 00000000000..496bd559b87 --- /dev/null +++ b/src/test/rustdoc-js/alias-1.js @@ -0,0 +1,17 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +const QUERY = '&'; + +const EXPECTED = { + 'others': [ + { 'path': 'std', 'name': 'reference' }, + ], +}; diff --git a/src/test/rustdoc-js/alias-2.js b/src/test/rustdoc-js/alias-2.js new file mode 100644 index 00000000000..f31786df67c --- /dev/null +++ b/src/test/rustdoc-js/alias-2.js @@ -0,0 +1,18 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +const QUERY = '+'; + +const EXPECTED = { + 'others': [ + { 'path': 'std::ops::AddAssign', 'name': 'AddAssign' }, + { 'path': 'std::ops::Add', 'name': 'Add' }, + ], +}; diff --git a/src/test/rustdoc-js/alias-3.js b/src/test/rustdoc-js/alias-3.js new file mode 100644 index 00000000000..d9e1ca5f760 --- /dev/null +++ b/src/test/rustdoc-js/alias-3.js @@ -0,0 +1,17 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +const QUERY = '!'; + +const EXPECTED = { + 'others': [ + { 'path': 'std', 'name': 'never' }, + ], +}; diff --git a/src/test/rustdoc-js/alias.js b/src/test/rustdoc-js/alias.js new file mode 100644 index 00000000000..a0500f24c17 --- /dev/null +++ b/src/test/rustdoc-js/alias.js @@ -0,0 +1,19 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +const QUERY = '['; + +const EXPECTED = { + 'others': [ + { 'path': 'std', 'name': 'slice' }, + { 'path': 'std::ops::IndexMut', 'name': 'IndexMut' }, + { 'path': 'std::ops::Index', 'name': 'Index' }, + ], +}; diff --git a/src/test/rustdoc-js/never.js b/src/test/rustdoc-js/never.js new file mode 100644 index 00000000000..d9e1ca5f760 --- /dev/null +++ b/src/test/rustdoc-js/never.js @@ -0,0 +1,17 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +const QUERY = '!'; + +const EXPECTED = { + 'others': [ + { 'path': 'std', 'name': 'never' }, + ], +}; diff --git a/src/test/rustdoc/issue-23511.rs b/src/test/rustdoc/issue-23511.rs index 50c31d309ee..ee0a5c1aa1b 100644 --- a/src/test/rustdoc/issue-23511.rs +++ b/src/test/rustdoc/issue-23511.rs @@ -14,7 +14,7 @@ pub mod str { #![doc(primitive = "str")] - #[lang = "str"] + #[lang = "str_alloc"] impl str { // @has search-index.js foo pub fn foo(&self) {} diff --git a/src/test/ui-fulldeps/proc-macro/parent-source-spans.rs b/src/test/ui-fulldeps/proc-macro/parent-source-spans.rs index 4c71afbac4d..f938700e515 100644 --- a/src/test/ui-fulldeps/proc-macro/parent-source-spans.rs +++ b/src/test/ui-fulldeps/proc-macro/parent-source-spans.rs @@ -11,7 +11,7 @@ // aux-build:parent-source-spans.rs // ignore-stage1 -#![feature(proc_macro, decl_macro)] +#![feature(proc_macro, decl_macro, proc_macro_non_items)] extern crate parent_source_spans; diff --git a/src/test/ui-fulldeps/proc-macro/three-equals.rs b/src/test/ui-fulldeps/proc-macro/three-equals.rs index ef2d1605290..66e34afcb13 100644 --- a/src/test/ui-fulldeps/proc-macro/three-equals.rs +++ b/src/test/ui-fulldeps/proc-macro/three-equals.rs @@ -11,7 +11,7 @@ // aux-build:three-equals.rs // ignore-stage1 -#![feature(proc_macro)] +#![feature(proc_macro, proc_macro_non_items)] extern crate three_equals; diff --git a/src/test/ui/associated-types-ICE-when-projecting-out-of-err.rs b/src/test/ui/associated-types-ICE-when-projecting-out-of-err.rs index 052575de4c2..75b60aa8d10 100644 --- a/src/test/ui/associated-types-ICE-when-projecting-out-of-err.rs +++ b/src/test/ui/associated-types-ICE-when-projecting-out-of-err.rs @@ -31,5 +31,5 @@ trait Add<RHS=Self> { fn ice<A>(a: A) { let r = loop {}; r = r + a; - //~^ ERROR the trait bound `!: Add<A>` is not satisfied + //~^ ERROR the trait bound `(): Add<A>` is not satisfied } diff --git a/src/test/ui/associated-types-ICE-when-projecting-out-of-err.stderr b/src/test/ui/associated-types-ICE-when-projecting-out-of-err.stderr index c22a645385a..7924ab74444 100644 --- a/src/test/ui/associated-types-ICE-when-projecting-out-of-err.stderr +++ b/src/test/ui/associated-types-ICE-when-projecting-out-of-err.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `!: Add<A>` is not satisfied +error[E0277]: the trait bound `(): Add<A>` is not satisfied --> $DIR/associated-types-ICE-when-projecting-out-of-err.rs:33:11 | LL | r = r + a; - | ^ the trait `Add<A>` is not implemented for `!` + | ^ the trait `Add<A>` is not implemented for `()` error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-closures-two-mut.nll.stderr b/src/test/ui/borrowck/borrowck-closures-two-mut.nll.stderr deleted file mode 100644 index a21a6e36778..00000000000 --- a/src/test/ui/borrowck/borrowck-closures-two-mut.nll.stderr +++ /dev/null @@ -1,78 +0,0 @@ -error[E0499]: cannot borrow `x` as mutable more than once at a time (Ast) - --> $DIR/borrowck-closures-two-mut.rs:24:24 - | -LL | let c1 = to_fn_mut(|| x = 4); - | -- - previous borrow occurs due to use of `x` in closure - | | - | first mutable borrow occurs here -LL | let c2 = to_fn_mut(|| x = 5); //~ ERROR cannot borrow `x` as mutable more than once - | ^^ - borrow occurs due to use of `x` in closure - | | - | second mutable borrow occurs here -LL | //~| ERROR cannot borrow `x` as mutable more than once -LL | } - | - first borrow ends here - -error[E0499]: cannot borrow `x` as mutable more than once at a time (Ast) - --> $DIR/borrowck-closures-two-mut.rs:35:24 - | -LL | let c1 = to_fn_mut(|| set(&mut x)); - | -- - previous borrow occurs due to use of `x` in closure - | | - | first mutable borrow occurs here -LL | let c2 = to_fn_mut(|| set(&mut x)); //~ ERROR cannot borrow `x` as mutable more than once - | ^^ - borrow occurs due to use of `x` in closure - | | - | second mutable borrow occurs here -LL | //~| ERROR cannot borrow `x` as mutable more than once -LL | } - | - first borrow ends here - -error[E0499]: cannot borrow `x` as mutable more than once at a time (Ast) - --> $DIR/borrowck-closures-two-mut.rs:42:24 - | -LL | let c1 = to_fn_mut(|| x = 5); - | -- - previous borrow occurs due to use of `x` in closure - | | - | first mutable borrow occurs here -LL | let c2 = to_fn_mut(|| set(&mut x)); //~ ERROR cannot borrow `x` as mutable more than once - | ^^ - borrow occurs due to use of `x` in closure - | | - | second mutable borrow occurs here -LL | //~| ERROR cannot borrow `x` as mutable more than once -LL | } - | - first borrow ends here - -error[E0499]: cannot borrow `x` as mutable more than once at a time (Ast) - --> $DIR/borrowck-closures-two-mut.rs:49:24 - | -LL | let c1 = to_fn_mut(|| x = 5); - | -- - previous borrow occurs due to use of `x` in closure - | | - | first mutable borrow occurs here -LL | let c2 = to_fn_mut(|| { let _y = to_fn_mut(|| set(&mut x)); }); // (nested closure) - | ^^ - borrow occurs due to use of `x` in closure - | | - | second mutable borrow occurs here -... -LL | } - | - first borrow ends here - -error[E0499]: cannot borrow `x` as mutable more than once at a time (Ast) - --> $DIR/borrowck-closures-two-mut.rs:61:24 - | -LL | let c1 = to_fn_mut(|| set(&mut *x.f)); - | -- - previous borrow occurs due to use of `x` in closure - | | - | first mutable borrow occurs here -LL | let c2 = to_fn_mut(|| set(&mut *x.f)); - | ^^ - borrow occurs due to use of `x` in closure - | | - | second mutable borrow occurs here -... -LL | } - | - first borrow ends here - -error: aborting due to 5 previous errors - -For more information about this error, try `rustc --explain E0499`. diff --git a/src/test/ui/borrowck/issue-45983.nll.stderr b/src/test/ui/borrowck/issue-45983.nll.stderr index ecd17edb079..1aec71fee34 100644 --- a/src/test/ui/borrowck/issue-45983.nll.stderr +++ b/src/test/ui/borrowck/issue-45983.nll.stderr @@ -1,4 +1,4 @@ -warning: not reporting region error due to -Znll +warning: not reporting region error due to nll --> $DIR/issue-45983.rs:17:27 | LL | give_any(|y| x = Some(y)); @@ -16,7 +16,7 @@ error[E0594]: cannot assign to immutable item `x` LL | give_any(|y| x = Some(y)); | ^^^^^^^^^^^ cannot mutate | - = note: Value not mutable causing this error: `x` + = note: the value which is causing this path not to be mutable is...: `x` error[E0596]: cannot borrow immutable item `x` as mutable --> $DIR/issue-45983.rs:17:14 diff --git a/src/test/ui/borrowck/issue-7573.nll.stderr b/src/test/ui/borrowck/issue-7573.nll.stderr index c55c49604d0..84c6236eb0a 100644 --- a/src/test/ui/borrowck/issue-7573.nll.stderr +++ b/src/test/ui/borrowck/issue-7573.nll.stderr @@ -1,4 +1,4 @@ -warning: not reporting region error due to -Znll +warning: not reporting region error due to nll --> $DIR/issue-7573.rs:27:31 | LL | let mut lines_to_use: Vec<&CrateId> = Vec::new(); diff --git a/src/test/ui/borrowck/regions-escape-bound-fn-2.nll.stderr b/src/test/ui/borrowck/regions-escape-bound-fn-2.nll.stderr index d34a716bb2b..ee3970aa8fd 100644 --- a/src/test/ui/borrowck/regions-escape-bound-fn-2.nll.stderr +++ b/src/test/ui/borrowck/regions-escape-bound-fn-2.nll.stderr @@ -1,4 +1,4 @@ -warning: not reporting region error due to -Znll +warning: not reporting region error due to nll --> $DIR/regions-escape-bound-fn-2.rs:18:27 | LL | with_int(|y| x = Some(y)); diff --git a/src/test/ui/borrowck/regions-escape-bound-fn.nll.stderr b/src/test/ui/borrowck/regions-escape-bound-fn.nll.stderr index b69c172bcdc..07a4ab1dbb1 100644 --- a/src/test/ui/borrowck/regions-escape-bound-fn.nll.stderr +++ b/src/test/ui/borrowck/regions-escape-bound-fn.nll.stderr @@ -1,4 +1,4 @@ -warning: not reporting region error due to -Znll +warning: not reporting region error due to nll --> $DIR/regions-escape-bound-fn.rs:18:22 | LL | with_int(|y| x = Some(y)); diff --git a/src/test/ui/borrowck/regions-escape-unboxed-closure.nll.stderr b/src/test/ui/borrowck/regions-escape-unboxed-closure.nll.stderr index 788654a2ecc..14c255ef527 100644 --- a/src/test/ui/borrowck/regions-escape-unboxed-closure.nll.stderr +++ b/src/test/ui/borrowck/regions-escape-unboxed-closure.nll.stderr @@ -1,4 +1,4 @@ -warning: not reporting region error due to -Znll +warning: not reporting region error due to nll --> $DIR/regions-escape-unboxed-closure.rs:16:27 | LL | with_int(&mut |y| x = Some(y)); diff --git a/src/test/ui/chalkify/lower_env1.rs b/src/test/ui/chalkify/lower_env1.rs new file mode 100644 index 00000000000..fc20ad0e08b --- /dev/null +++ b/src/test/ui/chalkify/lower_env1.rs @@ -0,0 +1,24 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(rustc_attrs)] +#![allow(dead_code)] + +trait Foo { } + +#[rustc_dump_program_clauses] //~ ERROR program clause dump +trait Bar where Self: Foo { } + +#[rustc_dump_env_program_clauses] //~ ERROR program clause dump +fn bar<T: Bar>() { +} + +fn main() { +} diff --git a/src/test/ui/chalkify/lower_env1.stderr b/src/test/ui/chalkify/lower_env1.stderr new file mode 100644 index 00000000000..3a280f85e76 --- /dev/null +++ b/src/test/ui/chalkify/lower_env1.stderr @@ -0,0 +1,24 @@ +error: program clause dump + --> $DIR/lower_env1.rs:16:1 + | +LL | #[rustc_dump_program_clauses] //~ ERROR program clause dump + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: FromEnv(Self: Bar) :- FromEnv(Self: Bar). + = note: FromEnv(Self: Foo) :- FromEnv(Self: Bar). + = note: Implemented(Self: Bar) :- FromEnv(Self: Bar). + +error: program clause dump + --> $DIR/lower_env1.rs:19:1 + | +LL | #[rustc_dump_env_program_clauses] //~ ERROR program clause dump + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: FromEnv(Self: Bar) :- FromEnv(Self: Bar). + = note: FromEnv(Self: Foo) :- FromEnv(Self: Bar). + = note: Implemented(Self: Bar) :- FromEnv(Self: Bar). + = note: Implemented(Self: Foo) :- FromEnv(Self: Foo). + = note: Implemented(Self: std::marker::Sized) :- FromEnv(Self: std::marker::Sized). + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/chalkify/lower_impl.rs b/src/test/ui/chalkify/lower_impl.rs index 671d77efbea..b38b87cdb12 100644 --- a/src/test/ui/chalkify/lower_impl.rs +++ b/src/test/ui/chalkify/lower_impl.rs @@ -12,7 +12,7 @@ trait Foo { } -#[rustc_dump_program_clauses] //~ ERROR Implemented(T: Foo) :- +#[rustc_dump_program_clauses] //~ ERROR program clause dump impl<T: 'static> Foo for T where T: Iterator<Item = i32> { } trait Bar { @@ -20,7 +20,7 @@ trait Bar { } impl<T> Bar for T where T: Iterator<Item = i32> { - #[rustc_dump_program_clauses] //~ ERROR Normalize(<T as Bar>::Assoc == std::vec::Vec<T>) :- + #[rustc_dump_program_clauses] //~ ERROR program clause dump type Assoc = Vec<T>; } diff --git a/src/test/ui/chalkify/lower_impl.stderr b/src/test/ui/chalkify/lower_impl.stderr index f253f9847d1..c497d76f8d4 100644 --- a/src/test/ui/chalkify/lower_impl.stderr +++ b/src/test/ui/chalkify/lower_impl.stderr @@ -1,14 +1,18 @@ -error: Implemented(T: Foo) :- ProjectionEq(<T as std::iter::Iterator>::Item == i32), TypeOutlives(T : 'static), Implemented(T: std::iter::Iterator), Implemented(T: std::marker::Sized). +error: program clause dump --> $DIR/lower_impl.rs:15:1 | -LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(T: Foo) :- +LL | #[rustc_dump_program_clauses] //~ ERROR program clause dump | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: Implemented(T: Foo) :- ProjectionEq(<T as std::iter::Iterator>::Item == i32), TypeOutlives(T : 'static), Implemented(T: std::iter::Iterator), Implemented(T: std::marker::Sized). -error: Normalize(<T as Bar>::Assoc == std::vec::Vec<T>) :- Implemented(T: Bar). +error: program clause dump --> $DIR/lower_impl.rs:23:5 | -LL | #[rustc_dump_program_clauses] //~ ERROR Normalize(<T as Bar>::Assoc == std::vec::Vec<T>) :- +LL | #[rustc_dump_program_clauses] //~ ERROR program clause dump | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: Normalize(<T as Bar>::Assoc == std::vec::Vec<T>) :- Implemented(T: Bar). error: aborting due to 2 previous errors diff --git a/src/test/ui/chalkify/lower_trait.rs b/src/test/ui/chalkify/lower_trait.rs index 74feb0105cc..7c0f233a645 100644 --- a/src/test/ui/chalkify/lower_trait.rs +++ b/src/test/ui/chalkify/lower_trait.rs @@ -10,10 +10,7 @@ #![feature(rustc_attrs)] -#[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<S, T, U>) :- - //~| ERROR FromEnv - //~| ERROR FromEnv - //~| ERROR FromEnv +#[rustc_dump_program_clauses] //~ ERROR program clause dump trait Foo<S, T, U> { fn s(S) -> S; fn t(T) -> T; diff --git a/src/test/ui/chalkify/lower_trait.stderr b/src/test/ui/chalkify/lower_trait.stderr index 45753c3bb90..55cd9699b06 100644 --- a/src/test/ui/chalkify/lower_trait.stderr +++ b/src/test/ui/chalkify/lower_trait.stderr @@ -1,26 +1,13 @@ -error: Implemented(Self: Foo<S, T, U>) :- FromEnv(Self: Foo<S, T, U>). +error: program clause dump --> $DIR/lower_trait.rs:13:1 | -LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<S, T, U>) :- +LL | #[rustc_dump_program_clauses] //~ ERROR program clause dump | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: FromEnv(S: std::marker::Sized) :- FromEnv(Self: Foo<S, T, U>). - --> $DIR/lower_trait.rs:13:1 - | -LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<S, T, U>) :- - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: FromEnv(T: std::marker::Sized) :- FromEnv(Self: Foo<S, T, U>). - --> $DIR/lower_trait.rs:13:1 | -LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<S, T, U>) :- - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: FromEnv(U: std::marker::Sized) :- FromEnv(Self: Foo<S, T, U>). - --> $DIR/lower_trait.rs:13:1 - | -LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<S, T, U>) :- - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: FromEnv(S: std::marker::Sized) :- FromEnv(Self: Foo<S, T, U>). + = note: FromEnv(T: std::marker::Sized) :- FromEnv(Self: Foo<S, T, U>). + = note: FromEnv(U: std::marker::Sized) :- FromEnv(Self: Foo<S, T, U>). + = note: Implemented(Self: Foo<S, T, U>) :- FromEnv(Self: Foo<S, T, U>). -error: aborting due to 4 previous errors +error: aborting due to previous error diff --git a/src/test/ui/chalkify/lower_trait_higher_rank.rs b/src/test/ui/chalkify/lower_trait_higher_rank.rs index e5eaf4591ec..47e9398d364 100644 --- a/src/test/ui/chalkify/lower_trait_higher_rank.rs +++ b/src/test/ui/chalkify/lower_trait_higher_rank.rs @@ -10,10 +10,7 @@ #![feature(rustc_attrs)] -#[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<F>) :- - //~| ERROR FromEnv - //~| ERROR FromEnv - //~| ERROR FromEnv +#[rustc_dump_program_clauses] //~ ERROR program clause dump trait Foo<F> where for<'a> F: Fn(&'a (u8, u16)) -> &'a u8 { fn s(F) -> F; diff --git a/src/test/ui/chalkify/lower_trait_higher_rank.stderr b/src/test/ui/chalkify/lower_trait_higher_rank.stderr index 9aed0c018c9..7f6f503c6ff 100644 --- a/src/test/ui/chalkify/lower_trait_higher_rank.stderr +++ b/src/test/ui/chalkify/lower_trait_higher_rank.stderr @@ -1,26 +1,13 @@ -error: Implemented(Self: Foo<F>) :- FromEnv(Self: Foo<F>). +error: program clause dump --> $DIR/lower_trait_higher_rank.rs:13:1 | -LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<F>) :- +LL | #[rustc_dump_program_clauses] //~ ERROR program clause dump | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: FromEnv(F: std::marker::Sized) :- FromEnv(Self: Foo<F>). - --> $DIR/lower_trait_higher_rank.rs:13:1 - | -LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<F>) :- - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: FromEnv(F: std::ops::Fn<(&'a (u8, u16),)>) :- FromEnv(Self: Foo<F>). - --> $DIR/lower_trait_higher_rank.rs:13:1 | -LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<F>) :- - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: FromEnv(<F as std::ops::FnOnce<(&'a (u8, u16),)>>::Output == &'a u8) :- FromEnv(Self: Foo<F>). - --> $DIR/lower_trait_higher_rank.rs:13:1 - | -LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<F>) :- - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: FromEnv(<F as std::ops::FnOnce<(&'a (u8, u16),)>>::Output == &'a u8) :- FromEnv(Self: Foo<F>). + = note: FromEnv(F: std::marker::Sized) :- FromEnv(Self: Foo<F>). + = note: FromEnv(F: std::ops::Fn<(&'a (u8, u16),)>) :- FromEnv(Self: Foo<F>). + = note: Implemented(Self: Foo<F>) :- FromEnv(Self: Foo<F>). -error: aborting due to 4 previous errors +error: aborting due to previous error diff --git a/src/test/ui/chalkify/lower_trait_where_clause.rs b/src/test/ui/chalkify/lower_trait_where_clause.rs index b2ce3ca48b2..67ee7c28b6a 100644 --- a/src/test/ui/chalkify/lower_trait_where_clause.rs +++ b/src/test/ui/chalkify/lower_trait_where_clause.rs @@ -13,13 +13,7 @@ use std::fmt::{Debug, Display}; use std::borrow::Borrow; -#[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<'a, 'b, S, T, U>) :- - //~| ERROR FromEnv - //~| ERROR FromEnv - //~| ERROR FromEnv - //~| ERROR FromEnv - //~| ERROR RegionOutlives - //~| ERROR TypeOutlives +#[rustc_dump_program_clauses] //~ ERROR program clause dump trait Foo<'a, 'b, S, T, U> where S: Debug, T: Borrow<U>, U: ?Sized, 'a: 'b, U: 'b { fn s(S) -> S; fn t(T) -> T; diff --git a/src/test/ui/chalkify/lower_trait_where_clause.stderr b/src/test/ui/chalkify/lower_trait_where_clause.stderr index a9ecaec3aff..68bc2ddf293 100644 --- a/src/test/ui/chalkify/lower_trait_where_clause.stderr +++ b/src/test/ui/chalkify/lower_trait_where_clause.stderr @@ -1,44 +1,16 @@ -error: Implemented(Self: Foo<'a, 'b, S, T, U>) :- FromEnv(Self: Foo<'a, 'b, S, T, U>). +error: program clause dump --> $DIR/lower_trait_where_clause.rs:16:1 | -LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<'a, 'b, S, T, U>) :- +LL | #[rustc_dump_program_clauses] //~ ERROR program clause dump | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: FromEnv(S: std::marker::Sized) :- FromEnv(Self: Foo<'a, 'b, S, T, U>). - --> $DIR/lower_trait_where_clause.rs:16:1 - | -LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<'a, 'b, S, T, U>) :- - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: FromEnv(T: std::marker::Sized) :- FromEnv(Self: Foo<'a, 'b, S, T, U>). - --> $DIR/lower_trait_where_clause.rs:16:1 - | -LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<'a, 'b, S, T, U>) :- - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: FromEnv(S: std::fmt::Debug) :- FromEnv(Self: Foo<'a, 'b, S, T, U>). - --> $DIR/lower_trait_where_clause.rs:16:1 - | -LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<'a, 'b, S, T, U>) :- - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: FromEnv(T: std::borrow::Borrow<U>) :- FromEnv(Self: Foo<'a, 'b, S, T, U>). - --> $DIR/lower_trait_where_clause.rs:16:1 - | -LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<'a, 'b, S, T, U>) :- - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: RegionOutlives('a : 'b) :- FromEnv(Self: Foo<'a, 'b, S, T, U>). - --> $DIR/lower_trait_where_clause.rs:16:1 | -LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<'a, 'b, S, T, U>) :- - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: TypeOutlives(U : 'b) :- FromEnv(Self: Foo<'a, 'b, S, T, U>). - --> $DIR/lower_trait_where_clause.rs:16:1 - | -LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(Self: Foo<'a, 'b, S, T, U>) :- - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 7 previous errors + = note: FromEnv(S: std::fmt::Debug) :- FromEnv(Self: Foo<'a, 'b, S, T, U>). + = note: FromEnv(S: std::marker::Sized) :- FromEnv(Self: Foo<'a, 'b, S, T, U>). + = note: FromEnv(T: std::borrow::Borrow<U>) :- FromEnv(Self: Foo<'a, 'b, S, T, U>). + = note: FromEnv(T: std::marker::Sized) :- FromEnv(Self: Foo<'a, 'b, S, T, U>). + = note: Implemented(Self: Foo<'a, 'b, S, T, U>) :- FromEnv(Self: Foo<'a, 'b, S, T, U>). + = note: RegionOutlives('a : 'b) :- FromEnv(Self: Foo<'a, 'b, S, T, U>). + = note: TypeOutlives(U : 'b) :- FromEnv(Self: Foo<'a, 'b, S, T, U>). + +error: aborting due to previous error diff --git a/src/test/ui/closure-expected-type/expect-region-supply-region.nll.stderr b/src/test/ui/closure-expected-type/expect-region-supply-region.nll.stderr index 18edf2addc5..bbae80e16ab 100644 --- a/src/test/ui/closure-expected-type/expect-region-supply-region.nll.stderr +++ b/src/test/ui/closure-expected-type/expect-region-supply-region.nll.stderr @@ -1,22 +1,22 @@ -warning: not reporting region error due to -Znll +warning: not reporting region error due to nll --> $DIR/expect-region-supply-region.rs:28:13 | LL | f = Some(x); //~ ERROR borrowed data cannot be stored outside of its closure | ^^^^^^^ -warning: not reporting region error due to -Znll +warning: not reporting region error due to nll --> $DIR/expect-region-supply-region.rs:38:13 | LL | f = Some(x); //~ ERROR borrowed data cannot be stored outside of its closure | ^^^^^^^ -warning: not reporting region error due to -Znll +warning: not reporting region error due to nll --> $DIR/expect-region-supply-region.rs:47:33 | LL | closure_expecting_bound(|x: &'x u32| { | ^^^^^^^ -warning: not reporting region error due to -Znll +warning: not reporting region error due to nll --> $DIR/expect-region-supply-region.rs:52:13 | LL | f = Some(x); diff --git a/src/test/ui/const-eval/conditional_array_execution.rs b/src/test/ui/const-eval/conditional_array_execution.rs index 324bcf60e8f..dbddee862e0 100644 --- a/src/test/ui/const-eval/conditional_array_execution.rs +++ b/src/test/ui/const-eval/conditional_array_execution.rs @@ -8,11 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-pass + const X: u32 = 5; const Y: u32 = 6; const FOO: u32 = [X - Y, Y - X][(X < Y) as usize]; //~^ WARN attempt to subtract with overflow +//~| WARN this constant cannot be used fn main() { - println!("{}", FOO); //~ E0080 + println!("{}", FOO); + //~^ WARN constant evaluation error } diff --git a/src/test/ui/const-eval/conditional_array_execution.stderr b/src/test/ui/const-eval/conditional_array_execution.stderr index 9270dafbe65..713b1b36c08 100644 --- a/src/test/ui/const-eval/conditional_array_execution.stderr +++ b/src/test/ui/const-eval/conditional_array_execution.stderr @@ -1,17 +1,20 @@ warning: attempt to subtract with overflow - --> $DIR/conditional_array_execution.rs:13:19 + --> $DIR/conditional_array_execution.rs:15:19 | LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize]; | ^^^^^ | = note: #[warn(const_err)] on by default -error[E0080]: constant evaluation error - --> $DIR/conditional_array_execution.rs:17:20 +warning: this constant cannot be used + --> $DIR/conditional_array_execution.rs:15:1 | -LL | println!("{}", FOO); //~ E0080 - | ^^^ referenced constant has errors +LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to subtract with overflow -error: aborting due to previous error +warning: constant evaluation error + --> $DIR/conditional_array_execution.rs:20:20 + | +LL | println!("{}", FOO); + | ^^^ referenced constant has errors -For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/const-eval/const_signed_pat.rs b/src/test/ui/const-eval/const_signed_pat.rs new file mode 100644 index 00000000000..f53d6f3fa0a --- /dev/null +++ b/src/test/ui/const-eval/const_signed_pat.rs @@ -0,0 +1,19 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-pass + +fn main() { + const MIN: i8 = -5; + match 5i8 { + MIN...-1 => {}, + _ => {}, + } +} diff --git a/src/test/ui/const-eval/enum_discr.rs b/src/test/ui/const-eval/enum_discr.rs new file mode 100644 index 00000000000..ba38a42092e --- /dev/null +++ b/src/test/ui/const-eval/enum_discr.rs @@ -0,0 +1,36 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-pass +// run-pass + +enum Foo { + X = 42, + Y = Foo::X as isize - 3, +} + +enum Bar { + X, + Y = Bar::X as isize + 2, +} + +enum Boo { + X = Boo::Y as isize * 2, + Y = 9, +} + +fn main() { + assert_eq!(Foo::X as isize, 42); + assert_eq!(Foo::Y as isize, 39); + assert_eq!(Bar::X as isize, 0); + assert_eq!(Bar::Y as isize, 2); + assert_eq!(Boo::X as isize, 18); + assert_eq!(Boo::Y as isize, 9); +} diff --git a/src/test/ui/const-eval/issue-43197.rs b/src/test/ui/const-eval/issue-43197.rs index d5c4796d0b4..097fba4d3c4 100644 --- a/src/test/ui/const-eval/issue-43197.rs +++ b/src/test/ui/const-eval/issue-43197.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-pass + #![feature(const_fn)] const fn foo(x: u32) -> u32 { @@ -17,9 +19,11 @@ const fn foo(x: u32) -> u32 { fn main() { const X: u32 = 0-1; //~^ WARN attempt to subtract with overflow + //~| WARN this constant cannot be used const Y: u32 = foo(0-1); //~^ WARN attempt to subtract with overflow + //~| WARN this constant cannot be used println!("{} {}", X, Y); - //~^ ERROR constant evaluation error - //~| ERROR constant evaluation error + //~^ WARN constant evaluation error + //~| WARN constant evaluation error } diff --git a/src/test/ui/const-eval/issue-43197.stderr b/src/test/ui/const-eval/issue-43197.stderr index 2d51e6603b5..a22e8016296 100644 --- a/src/test/ui/const-eval/issue-43197.stderr +++ b/src/test/ui/const-eval/issue-43197.stderr @@ -1,29 +1,38 @@ warning: attempt to subtract with overflow - --> $DIR/issue-43197.rs:18:20 + --> $DIR/issue-43197.rs:20:20 | LL | const X: u32 = 0-1; | ^^^ | = note: #[warn(const_err)] on by default -error[E0080]: constant evaluation error - --> $DIR/issue-43197.rs:22:23 +warning: this constant cannot be used + --> $DIR/issue-43197.rs:20:5 | -LL | println!("{} {}", X, Y); - | ^ referenced constant has errors +LL | const X: u32 = 0-1; + | ^^^^^^^^^^^^^^^^^^^ attempt to subtract with overflow warning: attempt to subtract with overflow - --> $DIR/issue-43197.rs:20:24 + --> $DIR/issue-43197.rs:23:24 | LL | const Y: u32 = foo(0-1); | ^^^ -error[E0080]: constant evaluation error - --> $DIR/issue-43197.rs:22:26 +warning: this constant cannot be used + --> $DIR/issue-43197.rs:23:5 + | +LL | const Y: u32 = foo(0-1); + | ^^^^^^^^^^^^^^^^^^^^^^^^ attempt to subtract with overflow + +warning: constant evaluation error + --> $DIR/issue-43197.rs:26:23 | LL | println!("{} {}", X, Y); - | ^ referenced constant has errors + | ^ referenced constant has errors -error: aborting due to 2 previous errors +warning: constant evaluation error + --> $DIR/issue-43197.rs:26:26 + | +LL | println!("{} {}", X, Y); + | ^ referenced constant has errors -For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/compile-fail/issue-44578.rs b/src/test/ui/const-eval/issue-44578.rs index 18cfb35113d..765113cfbb9 100644 --- a/src/test/compile-fail/issue-44578.rs +++ b/src/test/ui/const-eval/issue-44578.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-pass + trait Foo { const AMT: usize; } @@ -30,5 +32,6 @@ impl Foo for u16 { } fn main() { - println!("{}", <Bar<u16, u8> as Foo>::AMT); //~ E0080 + println!("{}", <Bar<u16, u8> as Foo>::AMT); //~ WARN const_err + //~^ WARN const_err } diff --git a/src/test/ui/const-eval/issue-44578.stderr b/src/test/ui/const-eval/issue-44578.stderr new file mode 100644 index 00000000000..01c6fa3623f --- /dev/null +++ b/src/test/ui/const-eval/issue-44578.stderr @@ -0,0 +1,14 @@ +warning: constant evaluation error + --> $DIR/issue-44578.rs:35:20 + | +LL | println!("{}", <Bar<u16, u8> as Foo>::AMT); //~ WARN const_err + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors + | + = note: #[warn(const_err)] on by default + +warning: constant evaluation error + --> $DIR/issue-44578.rs:35:20 + | +LL | println!("{}", <Bar<u16, u8> as Foo>::AMT); //~ WARN const_err + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors + diff --git a/src/test/ui/const-eval/promoted_errors.rs b/src/test/ui/const-eval/promoted_errors.rs new file mode 100644 index 00000000000..dc30c7f9cce --- /dev/null +++ b/src/test/ui/const-eval/promoted_errors.rs @@ -0,0 +1,28 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-pass +// compile-flags: -O +fn main() { + println!("{}", 0u32 - 1); + //~^ WARN const_err + //~| WARN const_err + let _x = 0u32 - 1; + //~^ WARN const_err + println!("{}", 1/(1-1)); + //~^ WARN const_err + //~| WARN const_err + let _x = 1/(1-1); + //~^ WARN const_err + //~| WARN const_err + println!("{}", 1/(false as u32)); + //~^ WARN const_err + let _x = 1/(false as u32); +} diff --git a/src/test/ui/const-eval/promoted_errors.stderr b/src/test/ui/const-eval/promoted_errors.stderr new file mode 100644 index 00000000000..a5db8cc9083 --- /dev/null +++ b/src/test/ui/const-eval/promoted_errors.stderr @@ -0,0 +1,50 @@ +warning: constant evaluation error + --> $DIR/promoted_errors.rs:14:20 + | +LL | println!("{}", 0u32 - 1); + | ^^^^^^^^ attempted to do overflowing math + | + = note: #[warn(const_err)] on by default + +warning: constant evaluation error + --> $DIR/promoted_errors.rs:14:20 + | +LL | println!("{}", 0u32 - 1); + | ^^^^^^^^ attempted to do overflowing math + +warning: constant evaluation error + --> $DIR/promoted_errors.rs:17:14 + | +LL | let _x = 0u32 - 1; + | ^^^^^^^^ attempted to do overflowing math + +warning: attempt to divide by zero + --> $DIR/promoted_errors.rs:19:20 + | +LL | println!("{}", 1/(1-1)); + | ^^^^^^^ + +warning: constant evaluation error + --> $DIR/promoted_errors.rs:19:20 + | +LL | println!("{}", 1/(1-1)); + | ^^^^^^^ attempted to do overflowing math + +warning: attempt to divide by zero + --> $DIR/promoted_errors.rs:22:14 + | +LL | let _x = 1/(1-1); + | ^^^^^^^ + +warning: constant evaluation error + --> $DIR/promoted_errors.rs:22:14 + | +LL | let _x = 1/(1-1); + | ^^^^^^^ attempted to do overflowing math + +warning: constant evaluation error + --> $DIR/promoted_errors.rs:25:20 + | +LL | println!("{}", 1/(false as u32)); + | ^^^^^^^^^^^^^^^^ attempted to do overflowing math + diff --git a/src/test/ui/const-eval/pub_const_err.rs b/src/test/ui/const-eval/pub_const_err.rs index bdb9f5b19a8..c6bf07649af 100644 --- a/src/test/ui/const-eval/pub_const_err.rs +++ b/src/test/ui/const-eval/pub_const_err.rs @@ -8,9 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![deny(const_err)] +// compile-pass #![crate_type = "lib"] pub const Z: u32 = 0 - 1; -//~^ ERROR attempt to subtract with overflow +//~^ WARN attempt to subtract with overflow +//~| WARN this constant cannot be used + +pub type Foo = [i32; 0 - 1]; +//~^ WARN attempt to subtract with overflow +//~| WARN this array length cannot be used diff --git a/src/test/ui/const-eval/pub_const_err.stderr b/src/test/ui/const-eval/pub_const_err.stderr index b77ec38ca16..2981ac20cd9 100644 --- a/src/test/ui/const-eval/pub_const_err.stderr +++ b/src/test/ui/const-eval/pub_const_err.stderr @@ -1,14 +1,26 @@ -error: attempt to subtract with overflow +warning: attempt to subtract with overflow --> $DIR/pub_const_err.rs:15:20 | LL | pub const Z: u32 = 0 - 1; | ^^^^^ | -note: lint level defined here - --> $DIR/pub_const_err.rs:11:9 + = note: #[warn(const_err)] on by default + +warning: this constant cannot be used + --> $DIR/pub_const_err.rs:15:1 | -LL | #![deny(const_err)] - | ^^^^^^^^^ +LL | pub const Z: u32 = 0 - 1; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to subtract with overflow -error: aborting due to previous error +warning: attempt to subtract with overflow + --> $DIR/pub_const_err.rs:19:22 + | +LL | pub type Foo = [i32; 0 - 1]; + | ^^^^^ + +warning: this array length cannot be used + --> $DIR/pub_const_err.rs:19:22 + | +LL | pub type Foo = [i32; 0 - 1]; + | ^^^^^ attempt to subtract with overflow diff --git a/src/test/ui/const-eval/pub_const_err_bin.rs b/src/test/ui/const-eval/pub_const_err_bin.rs new file mode 100644 index 00000000000..d87cb7ed770 --- /dev/null +++ b/src/test/ui/const-eval/pub_const_err_bin.rs @@ -0,0 +1,21 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-pass + +pub const Z: u32 = 0 - 1; +//~^ WARN attempt to subtract with overflow +//~| WARN this constant cannot be used + +pub type Foo = [i32; 0 - 1]; +//~^ WARN attempt to subtract with overflow +//~| WARN this array length cannot be used + +fn main() {} diff --git a/src/test/ui/const-eval/pub_const_err_bin.stderr b/src/test/ui/const-eval/pub_const_err_bin.stderr new file mode 100644 index 00000000000..3e8966d854b --- /dev/null +++ b/src/test/ui/const-eval/pub_const_err_bin.stderr @@ -0,0 +1,26 @@ +warning: attempt to subtract with overflow + --> $DIR/pub_const_err_bin.rs:13:20 + | +LL | pub const Z: u32 = 0 - 1; + | ^^^^^ + | + = note: #[warn(const_err)] on by default + +warning: this constant cannot be used + --> $DIR/pub_const_err_bin.rs:13:1 + | +LL | pub const Z: u32 = 0 - 1; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to subtract with overflow + +warning: attempt to subtract with overflow + --> $DIR/pub_const_err_bin.rs:17:22 + | +LL | pub type Foo = [i32; 0 - 1]; + | ^^^^^ + +warning: this array length cannot be used + --> $DIR/pub_const_err_bin.rs:17:22 + | +LL | pub type Foo = [i32; 0 - 1]; + | ^^^^^ attempt to subtract with overflow + diff --git a/src/test/ui/const-fn-error.stderr b/src/test/ui/const-fn-error.stderr index 077c4d60e64..767f28ff7b1 100644 --- a/src/test/ui/const-fn-error.stderr +++ b/src/test/ui/const-fn-error.stderr @@ -4,7 +4,7 @@ error[E0016]: blocks in constant functions are limited to items and tail express LL | let mut sum = 0; | ^ -error[E0015]: calls in constant functions are limited to constant functions, struct and enum constructors +error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants --> $DIR/const-fn-error.rs:18:14 | LL | for i in 0..x { diff --git a/src/test/ui/did_you_mean/issue-34126.nll.stderr b/src/test/ui/did_you_mean/issue-34126.nll.stderr index afdc26a75c7..81f858f6bfc 100644 --- a/src/test/ui/did_you_mean/issue-34126.nll.stderr +++ b/src/test/ui/did_you_mean/issue-34126.nll.stderr @@ -1,3 +1,9 @@ +error[E0596]: cannot borrow immutable item `self` as mutable + --> $DIR/issue-34126.rs:16:18 + | +LL | self.run(&mut self); //~ ERROR cannot borrow + | ^^^^^^^^^ cannot borrow as mutable + error[E0502]: cannot borrow `self` as mutable because it is also borrowed as immutable --> $DIR/issue-34126.rs:16:18 | @@ -8,6 +14,7 @@ LL | self.run(&mut self); //~ ERROR cannot borrow | immutable borrow occurs here | borrow later used here -error: aborting due to previous error +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0502`. +Some errors occurred: E0502, E0596. +For more information about an error, try `rustc --explain E0502`. diff --git a/src/test/ui/did_you_mean/issue-35937.nll.stderr b/src/test/ui/did_you_mean/issue-35937.nll.stderr index 7b5f452d322..40b640b63cf 100644 --- a/src/test/ui/did_you_mean/issue-35937.nll.stderr +++ b/src/test/ui/did_you_mean/issue-35937.nll.stderr @@ -4,7 +4,7 @@ error[E0596]: cannot borrow immutable item `f.v` as mutable LL | f.v.push("cat".to_string()); //~ ERROR cannot borrow | ^^^ cannot borrow as mutable | - = note: Value not mutable causing this error: `f` + = note: the value which is causing this path not to be mutable is...: `f` error[E0384]: cannot assign twice to immutable variable `s.x` --> $DIR/issue-35937.rs:26:5 diff --git a/src/test/ui/did_you_mean/issue-38147-1.nll.stderr b/src/test/ui/did_you_mean/issue-38147-1.nll.stderr index 099479eaf2b..8e442677951 100644 --- a/src/test/ui/did_you_mean/issue-38147-1.nll.stderr +++ b/src/test/ui/did_you_mean/issue-38147-1.nll.stderr @@ -4,7 +4,7 @@ error[E0596]: cannot borrow immutable item `*self.s` as mutable LL | self.s.push('x'); //~ ERROR cannot borrow data mutably | ^^^^^^ cannot borrow as mutable | - = note: Value not mutable causing this error: `*self` + = note: the value which is causing this path not to be mutable is...: `*self` error: aborting due to previous error diff --git a/src/test/ui/did_you_mean/issue-38147-4.nll.stderr b/src/test/ui/did_you_mean/issue-38147-4.nll.stderr index 5649fc903a0..6808222cc32 100644 --- a/src/test/ui/did_you_mean/issue-38147-4.nll.stderr +++ b/src/test/ui/did_you_mean/issue-38147-4.nll.stderr @@ -4,7 +4,7 @@ error[E0596]: cannot borrow immutable item `*f.s` as mutable LL | f.s.push('x'); //~ ERROR cannot borrow data mutably | ^^^ cannot borrow as mutable | - = note: Value not mutable causing this error: `*f` + = note: the value which is causing this path not to be mutable is...: `*f` error: aborting due to previous error diff --git a/src/test/ui/did_you_mean/issue-39544.nll.stderr b/src/test/ui/did_you_mean/issue-39544.nll.stderr index 6e57796aa45..f5f5b675e77 100644 --- a/src/test/ui/did_you_mean/issue-39544.nll.stderr +++ b/src/test/ui/did_you_mean/issue-39544.nll.stderr @@ -4,7 +4,7 @@ error[E0596]: cannot borrow immutable item `z.x` as mutable LL | let _ = &mut z.x; //~ ERROR cannot borrow | ^^^^^^^^ cannot borrow as mutable | - = note: Value not mutable causing this error: `z` + = note: the value which is causing this path not to be mutable is...: `z` error[E0596]: cannot borrow immutable item `self.x` as mutable --> $DIR/issue-39544.rs:26:17 @@ -12,7 +12,7 @@ error[E0596]: cannot borrow immutable item `self.x` as mutable LL | let _ = &mut self.x; //~ ERROR cannot borrow | ^^^^^^^^^^^ cannot borrow as mutable | - = note: Value not mutable causing this error: `*self` + = note: the value which is causing this path not to be mutable is...: `*self` error[E0596]: cannot borrow immutable item `self.x` as mutable --> $DIR/issue-39544.rs:30:17 @@ -20,7 +20,7 @@ error[E0596]: cannot borrow immutable item `self.x` as mutable LL | let _ = &mut self.x; //~ ERROR cannot borrow | ^^^^^^^^^^^ cannot borrow as mutable | - = note: Value not mutable causing this error: `*self` + = note: the value which is causing this path not to be mutable is...: `*self` error[E0596]: cannot borrow immutable item `other.x` as mutable --> $DIR/issue-39544.rs:31:17 @@ -28,7 +28,7 @@ error[E0596]: cannot borrow immutable item `other.x` as mutable LL | let _ = &mut other.x; //~ ERROR cannot borrow | ^^^^^^^^^^^^ cannot borrow as mutable | - = note: Value not mutable causing this error: `*other` + = note: the value which is causing this path not to be mutable is...: `*other` error[E0596]: cannot borrow immutable item `self.x` as mutable --> $DIR/issue-39544.rs:35:17 @@ -36,7 +36,7 @@ error[E0596]: cannot borrow immutable item `self.x` as mutable LL | let _ = &mut self.x; //~ ERROR cannot borrow | ^^^^^^^^^^^ cannot borrow as mutable | - = note: Value not mutable causing this error: `*self` + = note: the value which is causing this path not to be mutable is...: `*self` error[E0596]: cannot borrow immutable item `other.x` as mutable --> $DIR/issue-39544.rs:36:17 @@ -44,7 +44,7 @@ error[E0596]: cannot borrow immutable item `other.x` as mutable LL | let _ = &mut other.x; //~ ERROR cannot borrow | ^^^^^^^^^^^^ cannot borrow as mutable | - = note: Value not mutable causing this error: `*other` + = note: the value which is causing this path not to be mutable is...: `*other` error[E0596]: cannot borrow immutable item `self.x` as mutable --> $DIR/issue-39544.rs:40:17 @@ -52,7 +52,7 @@ error[E0596]: cannot borrow immutable item `self.x` as mutable LL | let _ = &mut self.x; //~ ERROR cannot borrow | ^^^^^^^^^^^ cannot borrow as mutable | - = note: Value not mutable causing this error: `*self` + = note: the value which is causing this path not to be mutable is...: `*self` error[E0596]: cannot borrow immutable item `other.x` as mutable --> $DIR/issue-39544.rs:41:17 @@ -60,7 +60,7 @@ error[E0596]: cannot borrow immutable item `other.x` as mutable LL | let _ = &mut other.x; //~ ERROR cannot borrow | ^^^^^^^^^^^^ cannot borrow as mutable | - = note: Value not mutable causing this error: `*other` + = note: the value which is causing this path not to be mutable is...: `*other` error[E0596]: cannot borrow immutable item `other.x` as mutable --> $DIR/issue-39544.rs:45:17 @@ -68,7 +68,7 @@ error[E0596]: cannot borrow immutable item `other.x` as mutable LL | let _ = &mut other.x; //~ ERROR cannot borrow | ^^^^^^^^^^^^ cannot borrow as mutable | - = note: Value not mutable causing this error: `*other` + = note: the value which is causing this path not to be mutable is...: `*other` error[E0596]: cannot borrow immutable item `z.x` as mutable --> $DIR/issue-39544.rs:51:13 @@ -76,7 +76,7 @@ error[E0596]: cannot borrow immutable item `z.x` as mutable LL | let _ = &mut z.x; //~ ERROR cannot borrow | ^^^^^^^^ cannot borrow as mutable | - = note: Value not mutable causing this error: `z` + = note: the value which is causing this path not to be mutable is...: `z` error[E0596]: cannot borrow immutable item `w.x` as mutable --> $DIR/issue-39544.rs:52:13 @@ -84,7 +84,7 @@ error[E0596]: cannot borrow immutable item `w.x` as mutable LL | let _ = &mut w.x; //~ ERROR cannot borrow | ^^^^^^^^ cannot borrow as mutable | - = note: Value not mutable causing this error: `*w` + = note: the value which is causing this path not to be mutable is...: `*w` error[E0594]: cannot assign to immutable item `*x.0` --> $DIR/issue-39544.rs:58:5 diff --git a/src/test/ui/e0119/conflict-with-std.rs b/src/test/ui/e0119/conflict-with-std.rs index a9f747d09ec..ed9033ad53d 100644 --- a/src/test/ui/e0119/conflict-with-std.rs +++ b/src/test/ui/e0119/conflict-with-std.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(try_from)] + use std::marker::PhantomData; use std::convert::{TryFrom, AsRef}; diff --git a/src/test/ui/e0119/conflict-with-std.stderr b/src/test/ui/e0119/conflict-with-std.stderr index 417ff1de3f8..e8b2c84c0df 100644 --- a/src/test/ui/e0119/conflict-with-std.stderr +++ b/src/test/ui/e0119/conflict-with-std.stderr @@ -1,5 +1,5 @@ error[E0119]: conflicting implementations of trait `std::convert::AsRef<Q>` for type `std::boxed::Box<Q>`: - --> $DIR/conflict-with-std.rs:15:1 + --> $DIR/conflict-with-std.rs:17:1 | LL | impl AsRef<Q> for Box<Q> { //~ ERROR conflicting implementations | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | impl AsRef<Q> for Box<Q> { //~ ERROR conflicting implementations where T: ?Sized; error[E0119]: conflicting implementations of trait `std::convert::From<S>` for type `S`: - --> $DIR/conflict-with-std.rs:22:1 + --> $DIR/conflict-with-std.rs:24:1 | LL | impl From<S> for S { //~ ERROR conflicting implementations | ^^^^^^^^^^^^^^^^^^ @@ -18,7 +18,7 @@ LL | impl From<S> for S { //~ ERROR conflicting implementations - impl<T> std::convert::From<T> for T; error[E0119]: conflicting implementations of trait `std::convert::TryFrom<X>` for type `X`: - --> $DIR/conflict-with-std.rs:29:1 + --> $DIR/conflict-with-std.rs:31:1 | LL | impl TryFrom<X> for X { //~ ERROR conflicting implementations | ^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/edition-lint-paths.rs b/src/test/ui/edition-lint-paths.rs new file mode 100644 index 00000000000..0b49e72ccd9 --- /dev/null +++ b/src/test/ui/edition-lint-paths.rs @@ -0,0 +1,41 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(crate_in_paths)] +#![deny(absolute_path_starting_with_module)] +#![allow(unused)] + +pub mod foo { + use ::bar::Bar; + //~^ ERROR Absolute + //~| WARN this was previously accepted + use super::bar::Bar2; + use crate::bar::Bar3; +} + + +use bar::Bar; +//~^ ERROR Absolute +//~| WARN this was previously accepted + +pub mod bar { + pub struct Bar; + pub type Bar2 = Bar; + pub type Bar3 = Bar; +} + +fn main() { + let x = ::bar::Bar; + //~^ ERROR Absolute + //~| WARN this was previously accepted + let x = bar::Bar; + let x = ::crate::bar::Bar; + let x = self::bar::Bar; +} diff --git a/src/test/ui/edition-lint-paths.stderr b/src/test/ui/edition-lint-paths.stderr new file mode 100644 index 00000000000..509527e0374 --- /dev/null +++ b/src/test/ui/edition-lint-paths.stderr @@ -0,0 +1,34 @@ +error: Absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition + --> $DIR/edition-lint-paths.rs:16:9 + | +LL | use ::bar::Bar; + | ^^^^^^^^^^ help: use `crate`: `crate::bar::Bar` + | +note: lint level defined here + --> $DIR/edition-lint-paths.rs:12:9 + | +LL | #![deny(absolute_path_starting_with_module)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition! + = note: for more information, see issue TBD + +error: Absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition + --> $DIR/edition-lint-paths.rs:24:5 + | +LL | use bar::Bar; + | ^^^^^^^^ help: use `crate`: `crate::bar::Bar` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition! + = note: for more information, see issue TBD + +error: Absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition + --> $DIR/edition-lint-paths.rs:35:13 + | +LL | let x = ::bar::Bar; + | ^^^^^^^^^^ help: use `crate`: `crate::bar::Bar` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition! + = note: for more information, see issue TBD + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/error-codes/E0389.nll.stderr b/src/test/ui/error-codes/E0389.nll.stderr index 13ba653a5ca..0525e16239d 100644 --- a/src/test/ui/error-codes/E0389.nll.stderr +++ b/src/test/ui/error-codes/E0389.nll.stderr @@ -1,10 +1,10 @@ -error[E0594]: cannot assign to immutable item `fancy_ref.num` +error[E0594]: cannot assign to data in a `&` reference --> $DIR/E0389.rs:18:5 | +LL | let fancy_ref = &(&mut fancy); + | ------------- help: consider changing this to be a mutable reference: `&mut (&mut fancy)` LL | fancy_ref.num = 6; //~ ERROR E0389 - | ^^^^^^^^^^^^^^^^^ cannot mutate - | - = note: Value not mutable causing this error: `*fancy_ref` + | ^^^^^^^^^^^^^^^^^ `fancy_ref` is a `&` reference, so the data it refers to cannot be written error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0518.stderr b/src/test/ui/error-codes/E0518.stderr index d8feec99140..27d5d3645fd 100644 --- a/src/test/ui/error-codes/E0518.stderr +++ b/src/test/ui/error-codes/E0518.stderr @@ -1,19 +1,19 @@ -error[E0518]: attribute should be applied to function +error[E0518]: attribute should be applied to function or closure --> $DIR/E0518.rs:11:1 | LL | #[inline(always)] //~ ERROR: E0518 | ^^^^^^^^^^^^^^^^^ LL | struct Foo; - | ----------- not a function + | ----------- not a function or closure -error[E0518]: attribute should be applied to function +error[E0518]: attribute should be applied to function or closure --> $DIR/E0518.rs:14:1 | LL | #[inline(never)] //~ ERROR: E0518 | ^^^^^^^^^^^^^^^^ LL | / impl Foo { LL | | } - | |_- not a function + | |_- not a function or closure error: aborting due to 2 previous errors diff --git a/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.nll.stderr b/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.nll.stderr index e9f09795691..5ae6afa7b17 100644 --- a/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.nll.stderr +++ b/src/test/ui/error-codes/E0621-does-not-trigger-for-closures.nll.stderr @@ -1,4 +1,4 @@ -warning: not reporting region error due to -Znll +warning: not reporting region error due to nll --> $DIR/E0621-does-not-trigger-for-closures.rs:25:5 | LL | invoke(&x, |a, b| if a > b { a } else { b }); //~ ERROR E0495 diff --git a/src/test/ui/feature-gate-dyn-trait.rs b/src/test/ui/feature-gate-doc_alias.rs index 4b3803d019b..1503dfe81fb 100644 --- a/src/test/ui/feature-gate-dyn-trait.rs +++ b/src/test/ui/feature-gate-doc_alias.rs @@ -1,4 +1,4 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -trait Trait {} -type A = Box<dyn Trait>; //~ ERROR `dyn Trait` syntax is unstable +#[doc(alias = "foo")] //~ ERROR: #[doc(alias = "...")] is experimental +pub struct Foo; fn main() {} diff --git a/src/test/ui/feature-gate-doc_alias.stderr b/src/test/ui/feature-gate-doc_alias.stderr new file mode 100644 index 00000000000..a987e03c0aa --- /dev/null +++ b/src/test/ui/feature-gate-doc_alias.stderr @@ -0,0 +1,11 @@ +error[E0658]: #[doc(alias = "...")] is experimental (see issue #50146) + --> $DIR/feature-gate-doc_alias.rs:11:1 + | +LL | #[doc(alias = "foo")] //~ ERROR: #[doc(alias = "...")] is experimental + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: add #![feature(doc_alias)] to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gate-dyn-trait.stderr b/src/test/ui/feature-gate-dyn-trait.stderr deleted file mode 100644 index 6e6bdf1cbf0..00000000000 --- a/src/test/ui/feature-gate-dyn-trait.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0658]: `dyn Trait` syntax is unstable (see issue #44662) - --> $DIR/feature-gate-dyn-trait.rs:12:14 - | -LL | type A = Box<dyn Trait>; //~ ERROR `dyn Trait` syntax is unstable - | ^^^^^^^^^ - | - = help: add #![feature(dyn_trait)] to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gate-exhaustive-patterns.rs b/src/test/ui/feature-gate-exhaustive-patterns.rs index 477dd1b38eb..c83d9b56bc3 100644 --- a/src/test/ui/feature-gate-exhaustive-patterns.rs +++ b/src/test/ui/feature-gate-exhaustive-patterns.rs @@ -7,7 +7,7 @@ // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. - +#![feature(never_type)] fn foo() -> Result<u32, !> { Ok(123) } diff --git a/src/test/ui/feature-gate-generic_associated_types.rs b/src/test/ui/feature-gate-generic_associated_types.rs index 724ec2496f2..34706626866 100644 --- a/src/test/ui/feature-gate-generic_associated_types.rs +++ b/src/test/ui/feature-gate-generic_associated_types.rs @@ -15,6 +15,7 @@ trait PointerFamily<U> { //~^ ERROR generic associated types are unstable type Pointer2<T>: Deref<Target = T> where T: Clone, U: Clone; //~^ ERROR generic associated types are unstable + //~| ERROR where clauses on associated types are unstable } struct Foo; @@ -25,4 +26,10 @@ impl PointerFamily<u32> for Foo { //~^ ERROR generic associated types are unstable } +trait Bar { + type Assoc where Self: Sized; + //~^ ERROR where clauses on associated types are unstable +} + + fn main() {} diff --git a/src/test/ui/feature-gate-generic_associated_types.stderr b/src/test/ui/feature-gate-generic_associated_types.stderr index 5f23def88eb..d7891f13c6b 100644 --- a/src/test/ui/feature-gate-generic_associated_types.stderr +++ b/src/test/ui/feature-gate-generic_associated_types.stderr @@ -14,8 +14,16 @@ LL | type Pointer2<T>: Deref<Target = T> where T: Clone, U: Clone; | = help: add #![feature(generic_associated_types)] to the crate attributes to enable +error[E0658]: where clauses on associated types are unstable (see issue #44265) + --> $DIR/feature-gate-generic_associated_types.rs:16:5 + | +LL | type Pointer2<T>: Deref<Target = T> where T: Clone, U: Clone; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add #![feature(generic_associated_types)] to the crate attributes to enable + error[E0658]: generic associated types are unstable (see issue #44265) - --> $DIR/feature-gate-generic_associated_types.rs:22:5 + --> $DIR/feature-gate-generic_associated_types.rs:23:5 | LL | type Pointer<usize> = Box<usize>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -23,13 +31,21 @@ LL | type Pointer<usize> = Box<usize>; = help: add #![feature(generic_associated_types)] to the crate attributes to enable error[E0658]: generic associated types are unstable (see issue #44265) - --> $DIR/feature-gate-generic_associated_types.rs:24:5 + --> $DIR/feature-gate-generic_associated_types.rs:25:5 | LL | type Pointer2<u32> = Box<u32>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add #![feature(generic_associated_types)] to the crate attributes to enable -error: aborting due to 4 previous errors +error[E0658]: where clauses on associated types are unstable (see issue #44265) + --> $DIR/feature-gate-generic_associated_types.rs:30:5 + | +LL | type Assoc where Self: Sized; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add #![feature(generic_associated_types)] to the crate attributes to enable + +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gate-never_type.rs b/src/test/ui/feature-gate-never_type.rs new file mode 100644 index 00000000000..ebbe17a821f --- /dev/null +++ b/src/test/ui/feature-gate-never_type.rs @@ -0,0 +1,27 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that ! errors when used in illegal positions with feature(never_type) disabled + +trait Foo { + type Wub; +} + +type Ma = (u32, !, i32); //~ ERROR type is experimental +type Meeshka = Vec<!>; //~ ERROR type is experimental +type Mow = &fn(!) -> !; //~ ERROR type is experimental +type Skwoz = &mut !; //~ ERROR type is experimental + +impl Foo for Meeshka { + type Wub = !; //~ ERROR type is experimental +} + +fn main() { +} diff --git a/src/test/ui/feature-gate-never_type.stderr b/src/test/ui/feature-gate-never_type.stderr new file mode 100644 index 00000000000..187be6d8291 --- /dev/null +++ b/src/test/ui/feature-gate-never_type.stderr @@ -0,0 +1,43 @@ +error[E0658]: The `!` type is experimental (see issue #35121) + --> $DIR/feature-gate-never_type.rs:17:17 + | +LL | type Ma = (u32, !, i32); //~ ERROR type is experimental + | ^ + | + = help: add #![feature(never_type)] to the crate attributes to enable + +error[E0658]: The `!` type is experimental (see issue #35121) + --> $DIR/feature-gate-never_type.rs:18:20 + | +LL | type Meeshka = Vec<!>; //~ ERROR type is experimental + | ^ + | + = help: add #![feature(never_type)] to the crate attributes to enable + +error[E0658]: The `!` type is experimental (see issue #35121) + --> $DIR/feature-gate-never_type.rs:19:16 + | +LL | type Mow = &fn(!) -> !; //~ ERROR type is experimental + | ^ + | + = help: add #![feature(never_type)] to the crate attributes to enable + +error[E0658]: The `!` type is experimental (see issue #35121) + --> $DIR/feature-gate-never_type.rs:20:19 + | +LL | type Skwoz = &mut !; //~ ERROR type is experimental + | ^ + | + = help: add #![feature(never_type)] to the crate attributes to enable + +error[E0658]: The `!` type is experimental (see issue #35121) + --> $DIR/feature-gate-never_type.rs:23:16 + | +LL | type Wub = !; //~ ERROR type is experimental + | ^ + | + = help: add #![feature(never_type)] to the crate attributes to enable + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-inline.rs b/src/test/ui/feature-gate/issue-43106-gating-of-inline.rs index 410f960e655..b03faad988e 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-inline.rs +++ b/src/test/ui/feature-gate/issue-43106-gating-of-inline.rs @@ -19,21 +19,21 @@ #![inline = "2100"] #[inline = "2100"] -//~^ ERROR attribute should be applied to function +//~^ ERROR attribute should be applied to function or closure mod inline { mod inner { #![inline="2100"] } - //~^ ERROR attribute should be applied to function + //~^ ERROR attribute should be applied to function or closure #[inline = "2100"] fn f() { } #[inline = "2100"] struct S; - //~^ ERROR attribute should be applied to function + //~^ ERROR attribute should be applied to function or closure #[inline = "2100"] type T = S; - //~^ ERROR attribute should be applied to function + //~^ ERROR attribute should be applied to function or closure #[inline = "2100"] impl S { } - //~^ ERROR attribute should be applied to function + //~^ ERROR attribute should be applied to function or closure } fn main() {} diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-inline.stderr b/src/test/ui/feature-gate/issue-43106-gating-of-inline.stderr index d67d78e31a9..4d63c3f5012 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-inline.stderr +++ b/src/test/ui/feature-gate/issue-43106-gating-of-inline.stderr @@ -1,41 +1,41 @@ -error[E0518]: attribute should be applied to function +error[E0518]: attribute should be applied to function or closure --> $DIR/issue-43106-gating-of-inline.rs:21:1 | LL | #[inline = "2100"] | ^^^^^^^^^^^^^^^^^^ -LL | //~^ ERROR attribute should be applied to function +LL | //~^ ERROR attribute should be applied to function or closure LL | / mod inline { LL | | mod inner { #![inline="2100"] } -LL | | //~^ ERROR attribute should be applied to function +LL | | //~^ ERROR attribute should be applied to function or closure LL | | ... | -LL | | //~^ ERROR attribute should be applied to function +LL | | //~^ ERROR attribute should be applied to function or closure LL | | } - | |_- not a function + | |_- not a function or closure -error[E0518]: attribute should be applied to function +error[E0518]: attribute should be applied to function or closure --> $DIR/issue-43106-gating-of-inline.rs:24:17 | LL | mod inner { #![inline="2100"] } - | ------------^^^^^^^^^^^^^^^^^-- not a function + | ------------^^^^^^^^^^^^^^^^^-- not a function or closure -error[E0518]: attribute should be applied to function +error[E0518]: attribute should be applied to function or closure --> $DIR/issue-43106-gating-of-inline.rs:29:5 | LL | #[inline = "2100"] struct S; - | ^^^^^^^^^^^^^^^^^^ --------- not a function + | ^^^^^^^^^^^^^^^^^^ --------- not a function or closure -error[E0518]: attribute should be applied to function +error[E0518]: attribute should be applied to function or closure --> $DIR/issue-43106-gating-of-inline.rs:32:5 | LL | #[inline = "2100"] type T = S; - | ^^^^^^^^^^^^^^^^^^ ----------- not a function + | ^^^^^^^^^^^^^^^^^^ ----------- not a function or closure -error[E0518]: attribute should be applied to function +error[E0518]: attribute should be applied to function or closure --> $DIR/issue-43106-gating-of-inline.rs:35:5 | LL | #[inline = "2100"] impl S { } - | ^^^^^^^^^^^^^^^^^^ ---------- not a function + | ^^^^^^^^^^^^^^^^^^ ---------- not a function or closure error: aborting due to 5 previous errors diff --git a/src/test/ui/feature-gate/issue-49983-see-issue-0.rs b/src/test/ui/feature-gate/issue-49983-see-issue-0.rs new file mode 100644 index 00000000000..1e0039aba04 --- /dev/null +++ b/src/test/ui/feature-gate/issue-49983-see-issue-0.rs @@ -0,0 +1,16 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +extern crate core; + +// error should not say "(see issue #0)" +#[allow(unused_imports)] use core::ptr::Unique; //~ ERROR use of unstable library feature + +fn main() {} diff --git a/src/test/ui/feature-gate/issue-49983-see-issue-0.stderr b/src/test/ui/feature-gate/issue-49983-see-issue-0.stderr new file mode 100644 index 00000000000..986a2d88e00 --- /dev/null +++ b/src/test/ui/feature-gate/issue-49983-see-issue-0.stderr @@ -0,0 +1,11 @@ +error[E0658]: use of unstable library feature 'ptr_internals': use NonNull instead and consider PhantomData<T> (if you also use #[may_dangle]), Send, and/or Sync + --> $DIR/issue-49983-see-issue-0.rs:14:30 + | +LL | #[allow(unused_imports)] use core::ptr::Unique; //~ ERROR use of unstable library feature + | ^^^^^^^^^^^^^^^^^ + | + = help: add #![feature(ptr_internals)] to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/generator/yield-while-iterating.nll.stderr b/src/test/ui/generator/yield-while-iterating.nll.stderr index be4852aaf06..af79eb7ac05 100644 --- a/src/test/ui/generator/yield-while-iterating.nll.stderr +++ b/src/test/ui/generator/yield-while-iterating.nll.stderr @@ -6,20 +6,6 @@ LL | for p in &x { //~ ERROR LL | yield(); | ------- possible yield occurs here -error[E0597]: borrowed value does not live long enough - --> $DIR/yield-while-iterating.rs:50:17 - | -LL | let mut b = || { - | _________________^ -LL | | for p in &mut x { -LL | | yield p; -LL | | } -LL | | }; - | | ^ - | | | - | |_____temporary value only lives until here - | temporary value does not live long enough - error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable --> $DIR/yield-while-iterating.rs:67:20 | @@ -35,21 +21,7 @@ LL | println!("{}", x[0]); //~ ERROR LL | b.resume(); | - borrow later used here -error[E0597]: borrowed value does not live long enough - --> $DIR/yield-while-iterating.rs:62:17 - | -LL | let mut b = || { - | _________________^ -LL | | for p in &mut x { -LL | | yield p; -LL | | } -LL | | }; - | | ^ - | | | - | |_____temporary value only lives until here - | temporary value does not live long enough - -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors -Some errors occurred: E0502, E0597, E0626. +Some errors occurred: E0502, E0626. For more information about an error, try `rustc --explain E0502`. diff --git a/src/test/ui/hygiene/fields-move.nll.stderr b/src/test/ui/hygiene/fields-move.nll.stderr new file mode 100644 index 00000000000..51f8067b8ce --- /dev/null +++ b/src/test/ui/hygiene/fields-move.nll.stderr @@ -0,0 +1,46 @@ +error[E0382]: use of moved value: `foo.x` + --> $DIR/fields-move.rs:38:42 + | +LL | $foo.x + | ------ value moved here +... +LL | assert_two_copies(copy_modern!(foo), foo.x); //~ ERROR use of moved value: `foo.x` + | ^^^^^ value used here after move + | + = note: move occurs because `foo.x` has type `NonCopy`, which does not implement the `Copy` trait + +error[E0382]: use of moved value: `foo.x` + --> $DIR/fields-move.rs:28:9 + | +LL | $foo.x + | ------ value moved here +... +LL | $foo.x //~ ERROR use of moved value: `foo.x` + | ^^^^^^ value used here after move +... +LL | assert_two_copies(copy_modern!(foo), foo.x); //~ ERROR use of moved value: `foo.x` + | ----- value moved here +LL | assert_two_copies(copy_legacy!(foo), foo.x); //~ ERROR use of moved value: `foo.x` + | ----------------- in this macro invocation + | + = note: move occurs because `foo.x` has type `NonCopy`, which does not implement the `Copy` trait + +error[E0382]: use of moved value: `foo.x` + --> $DIR/fields-move.rs:39:42 + | +LL | $foo.x + | ------ value moved here +... +LL | $foo.x //~ ERROR use of moved value: `foo.x` + | ------ value moved here +... +LL | assert_two_copies(copy_modern!(foo), foo.x); //~ ERROR use of moved value: `foo.x` + | ----- value moved here +LL | assert_two_copies(copy_legacy!(foo), foo.x); //~ ERROR use of moved value: `foo.x` + | ^^^^^ value used here after move + | + = note: move occurs because `foo.x` has type `NonCopy`, which does not implement the `Copy` trait + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/hygiene/fields-numeric-borrowck.nll.stderr b/src/test/ui/hygiene/fields-numeric-borrowck.nll.stderr new file mode 100644 index 00000000000..3a0a6f66d61 --- /dev/null +++ b/src/test/ui/hygiene/fields-numeric-borrowck.nll.stderr @@ -0,0 +1,13 @@ +error: compilation successful + --> $DIR/fields-numeric-borrowck.rs:13:1 + | +LL | / fn main() { #![rustc_error] // rust-lang/rust#49855 +LL | | let mut s = S(0); +LL | | let borrow1 = &mut s.0; +LL | | let S { 0: ref mut borrow2 } = s; +LL | | //~^ ERROR cannot borrow `s.0` as mutable more than once at a time +LL | | } + | |_^ + +error: aborting due to previous error + diff --git a/src/test/ui/hygiene/fields-numeric-borrowck.rs b/src/test/ui/hygiene/fields-numeric-borrowck.rs index 50ace39e709..975684fbd41 100644 --- a/src/test/ui/hygiene/fields-numeric-borrowck.rs +++ b/src/test/ui/hygiene/fields-numeric-borrowck.rs @@ -7,10 +7,10 @@ // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. - +#![feature(rustc_attrs)] struct S(u8); -fn main() { +fn main() { #![rustc_error] // rust-lang/rust#49855 let mut s = S(0); let borrow1 = &mut s.0; let S { 0: ref mut borrow2 } = s; diff --git a/src/test/ui/impl-trait/auto-trait-leak.stderr b/src/test/ui/impl-trait/auto-trait-leak.stderr index 3b20451b102..efa9a58d633 100644 --- a/src/test/ui/impl-trait/auto-trait-leak.stderr +++ b/src/test/ui/impl-trait/auto-trait-leak.stderr @@ -34,6 +34,7 @@ error[E0391]: cycle detected when processing `cycle1` LL | fn cycle1() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ | +note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`... note: ...which requires processing `cycle2::{{impl-Trait}}`... --> $DIR/auto-trait-leak.rs:49:16 | @@ -44,6 +45,7 @@ note: ...which requires processing `cycle2`... | LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`... note: ...which requires processing `cycle1::{{impl-Trait}}`... --> $DIR/auto-trait-leak.rs:42:16 | diff --git a/src/test/ui/impl-trait/method-suggestion-no-duplication.stderr b/src/test/ui/impl-trait/method-suggestion-no-duplication.stderr index 438d29f0535..f7aaab4242c 100644 --- a/src/test/ui/impl-trait/method-suggestion-no-duplication.stderr +++ b/src/test/ui/impl-trait/method-suggestion-no-duplication.stderr @@ -8,10 +8,8 @@ LL | foo(|s| s.is_empty()); | ^^^^^^^^ | = help: items from traits can only be used if the trait is implemented and in scope - = note: the following traits define an item `is_empty`, perhaps you need to implement one of them: + = note: the following trait defines an item `is_empty`, perhaps you need to implement it: candidate #1: `std::iter::ExactSizeIterator` - candidate #2: `core::slice::SliceExt` - candidate #3: `core::str::StrExt` error: aborting due to previous error diff --git a/src/test/ui/impl_trait_projections.rs b/src/test/ui/impl_trait_projections.rs index 6a727942271..57a0040600a 100644 --- a/src/test/ui/impl_trait_projections.rs +++ b/src/test/ui/impl_trait_projections.rs @@ -7,8 +7,6 @@ // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(dyn_trait)] - use std::fmt::Debug; use std::option; diff --git a/src/test/ui/impl_trait_projections.stderr b/src/test/ui/impl_trait_projections.stderr index 9b38de614fc..f6d58984ece 100644 --- a/src/test/ui/impl_trait_projections.stderr +++ b/src/test/ui/impl_trait_projections.stderr @@ -1,29 +1,29 @@ error[E0667]: `impl Trait` is not allowed in path parameters - --> $DIR/impl_trait_projections.rs:23:51 + --> $DIR/impl_trait_projections.rs:21:51 | LL | fn projection_is_disallowed(x: impl Iterator) -> <impl Iterator>::Item { | ^^^^^^^^^^^^^ error[E0667]: `impl Trait` is not allowed in path parameters - --> $DIR/impl_trait_projections.rs:30:9 + --> $DIR/impl_trait_projections.rs:28:9 | LL | -> <impl Iterator as Iterator>::Item | ^^^^^^^^^^^^^ error[E0667]: `impl Trait` is not allowed in path parameters - --> $DIR/impl_trait_projections.rs:37:27 + --> $DIR/impl_trait_projections.rs:35:27 | LL | -> <::std::ops::Range<impl Debug> as Iterator>::Item | ^^^^^^^^^^ error[E0667]: `impl Trait` is not allowed in path parameters - --> $DIR/impl_trait_projections.rs:44:29 + --> $DIR/impl_trait_projections.rs:42:29 | LL | -> <dyn Iterator<Item = impl Debug> as Iterator>::Item | ^^^^^^^^^^ error[E0223]: ambiguous associated type - --> $DIR/impl_trait_projections.rs:23:50 + --> $DIR/impl_trait_projections.rs:21:50 | LL | fn projection_is_disallowed(x: impl Iterator) -> <impl Iterator>::Item { | ^^^^^^^^^^^^^^^^^^^^^ ambiguous associated type diff --git a/src/test/ui/in-band-lifetimes/impl/dyn-trait.nll.stderr b/src/test/ui/in-band-lifetimes/impl/dyn-trait.nll.stderr index 34ee39c7164..4cf7feddd46 100644 --- a/src/test/ui/in-band-lifetimes/impl/dyn-trait.nll.stderr +++ b/src/test/ui/in-band-lifetimes/impl/dyn-trait.nll.stderr @@ -1,11 +1,11 @@ -warning: not reporting region error due to -Znll - --> $DIR/dyn-trait.rs:33:16 +warning: not reporting region error due to nll + --> $DIR/dyn-trait.rs:32:16 | LL | static_val(x); //~ ERROR cannot infer | ^ error: free region `'a` does not outlive free region `'static` - --> $DIR/dyn-trait.rs:33:5 + --> $DIR/dyn-trait.rs:32:5 | LL | static_val(x); //~ ERROR cannot infer | ^^^^^^^^^^^^^ diff --git a/src/test/ui/in-band-lifetimes/impl/dyn-trait.rs b/src/test/ui/in-band-lifetimes/impl/dyn-trait.rs index a504bae2e60..c27bbe77fbf 100644 --- a/src/test/ui/in-band-lifetimes/impl/dyn-trait.rs +++ b/src/test/ui/in-band-lifetimes/impl/dyn-trait.rs @@ -13,7 +13,6 @@ #![allow(warnings)] -#![feature(dyn_trait)] #![feature(in_band_lifetimes)] use std::fmt::Debug; diff --git a/src/test/ui/in-band-lifetimes/impl/dyn-trait.stderr b/src/test/ui/in-band-lifetimes/impl/dyn-trait.stderr index 9d6a318c075..201470abe67 100644 --- a/src/test/ui/in-band-lifetimes/impl/dyn-trait.stderr +++ b/src/test/ui/in-band-lifetimes/impl/dyn-trait.stderr @@ -1,11 +1,11 @@ error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements - --> $DIR/dyn-trait.rs:33:16 + --> $DIR/dyn-trait.rs:32:16 | LL | static_val(x); //~ ERROR cannot infer | ^ | -note: first, the lifetime cannot outlive the lifetime 'a as defined on the function body at 32:1... - --> $DIR/dyn-trait.rs:32:1 +note: first, the lifetime cannot outlive the lifetime 'a as defined on the function body at 31:1... + --> $DIR/dyn-trait.rs:31:1 | LL | fn with_dyn_debug_static<'a>(x: Box<dyn Debug + 'a>) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/in-band-lifetimes/mismatched.nll.stderr b/src/test/ui/in-band-lifetimes/mismatched.nll.stderr index 0930583a7ee..cd2ebc341ea 100644 --- a/src/test/ui/in-band-lifetimes/mismatched.nll.stderr +++ b/src/test/ui/in-band-lifetimes/mismatched.nll.stderr @@ -1,10 +1,10 @@ -warning: not reporting region error due to -Znll +warning: not reporting region error due to nll --> $DIR/mismatched.rs:14:42 | LL | fn foo(x: &'a u32, y: &u32) -> &'a u32 { y } //~ ERROR explicit lifetime required | ^ -warning: not reporting region error due to -Znll +warning: not reporting region error due to nll --> $DIR/mismatched.rs:16:46 | LL | fn foo2(x: &'a u32, y: &'b u32) -> &'a u32 { y } //~ ERROR lifetime mismatch diff --git a/src/test/ui/in-band-lifetimes/mismatched_trait.nll.stderr b/src/test/ui/in-band-lifetimes/mismatched_trait.nll.stderr index 5e42cab9974..886e3834d1d 100644 --- a/src/test/ui/in-band-lifetimes/mismatched_trait.nll.stderr +++ b/src/test/ui/in-band-lifetimes/mismatched_trait.nll.stderr @@ -1,4 +1,4 @@ -warning: not reporting region error due to -Znll +warning: not reporting region error due to nll --> $DIR/mismatched_trait.rs:16:9 | LL | y //~ ERROR explicit lifetime required diff --git a/src/test/ui/issue-13058.nll.stderr b/src/test/ui/issue-13058.nll.stderr index 604ad38ad23..146385f3de2 100644 --- a/src/test/ui/issue-13058.nll.stderr +++ b/src/test/ui/issue-13058.nll.stderr @@ -1,10 +1,10 @@ -warning: not reporting region error due to -Znll +warning: not reporting region error due to nll --> $DIR/issue-13058.rs:24:21 | LL | let cont_iter = cont.iter(); | ^^^^ -warning: not reporting region error due to -Znll +warning: not reporting region error due to nll --> $DIR/issue-13058.rs:24:26 | LL | let cont_iter = cont.iter(); diff --git a/src/test/ui/issue-23302-1.stderr b/src/test/ui/issue-23302-1.stderr index 0fbe2f7a411..6ff46a7e21f 100644 --- a/src/test/ui/issue-23302-1.stderr +++ b/src/test/ui/issue-23302-1.stderr @@ -1,11 +1,15 @@ -error[E0391]: cycle detected when const-evaluating `X::A::{{initializer}}` +error[E0391]: cycle detected when processing `X::A::{{initializer}}` --> $DIR/issue-23302-1.rs:14:9 | LL | A = X::A as isize, //~ ERROR E0391 - | ^^^^ + | ^^^^^^^^^^^^^ | -note: ...which requires computing layout of `X`... - = note: ...which again requires const-evaluating `X::A::{{initializer}}`, completing the cycle + = note: ...which again requires processing `X::A::{{initializer}}`, completing the cycle +note: cycle used when const-evaluating `X::A::{{initializer}}` + --> $DIR/issue-23302-1.rs:14:9 + | +LL | A = X::A as isize, //~ ERROR E0391 + | ^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issue-23302-2.stderr b/src/test/ui/issue-23302-2.stderr index 313cfa0c162..6b72a5b544d 100644 --- a/src/test/ui/issue-23302-2.stderr +++ b/src/test/ui/issue-23302-2.stderr @@ -1,11 +1,15 @@ -error[E0391]: cycle detected when const-evaluating `Y::A::{{initializer}}` +error[E0391]: cycle detected when processing `Y::A::{{initializer}}` --> $DIR/issue-23302-2.rs:14:9 | LL | A = Y::B as isize, //~ ERROR E0391 - | ^^^^ + | ^^^^^^^^^^^^^ | -note: ...which requires computing layout of `Y`... - = note: ...which again requires const-evaluating `Y::A::{{initializer}}`, completing the cycle + = note: ...which again requires processing `Y::A::{{initializer}}`, completing the cycle +note: cycle used when const-evaluating `Y::A::{{initializer}}` + --> $DIR/issue-23302-2.rs:14:9 + | +LL | A = Y::B as isize, //~ ERROR E0391 + | ^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issue-36163.stderr b/src/test/ui/issue-36163.stderr index 541f54ca768..7199fffd386 100644 --- a/src/test/ui/issue-36163.stderr +++ b/src/test/ui/issue-36163.stderr @@ -1,21 +1,20 @@ -error[E0391]: cycle detected when const-evaluating `Foo::B::{{initializer}}` +error[E0391]: cycle detected when processing `Foo::B::{{initializer}}` --> $DIR/issue-36163.rs:14:9 | LL | B = A, //~ ERROR E0391 | ^ | -note: ...which requires processing `Foo::B::{{initializer}}`... +note: ...which requires processing `A`... + --> $DIR/issue-36163.rs:11:18 + | +LL | const A: isize = Foo::B as isize; + | ^^^^^^^^^^^^^^^ + = note: ...which again requires processing `Foo::B::{{initializer}}`, completing the cycle +note: cycle used when const-evaluating `Foo::B::{{initializer}}` --> $DIR/issue-36163.rs:14:9 | LL | B = A, //~ ERROR E0391 | ^ -note: ...which requires const-evaluating `A`... - --> $DIR/issue-36163.rs:11:18 - | -LL | const A: isize = Foo::B as isize; - | ^^^^^^ -note: ...which requires computing layout of `Foo`... - = note: ...which again requires const-evaluating `Foo::B::{{initializer}}`, completing the cycle error: aborting due to previous error diff --git a/src/test/ui/issue-36400.nll.stderr b/src/test/ui/issue-36400.nll.stderr index 040e6300af6..80459937479 100644 --- a/src/test/ui/issue-36400.nll.stderr +++ b/src/test/ui/issue-36400.nll.stderr @@ -4,7 +4,7 @@ error[E0596]: cannot borrow immutable item `*x` as mutable LL | f(&mut *x); //~ ERROR cannot borrow immutable | ^^^^^^^ cannot borrow as mutable | - = note: Value not mutable causing this error: `x` + = note: the value which is causing this path not to be mutable is...: `x` error: aborting due to previous error diff --git a/src/test/ui/issue-45697-1.nll.stderr b/src/test/ui/issue-45697-1.nll.stderr deleted file mode 100644 index cf108691a0e..00000000000 --- a/src/test/ui/issue-45697-1.nll.stderr +++ /dev/null @@ -1,34 +0,0 @@ -error[E0506]: cannot assign to `*y.pointer` because it is borrowed (Ast) - --> $DIR/issue-45697-1.rs:30:9 - | -LL | let z = copy_borrowed_ptr(&mut y); - | - borrow of `*y.pointer` occurs here -LL | *y.pointer += 1; - | ^^^^^^^^^^^^^^^ assignment to borrowed `*y.pointer` occurs here - -error[E0503]: cannot use `*y.pointer` because it was mutably borrowed (Mir) - --> $DIR/issue-45697-1.rs:30:9 - | -LL | let z = copy_borrowed_ptr(&mut y); - | ------ borrow of `y` occurs here -LL | *y.pointer += 1; - | ^^^^^^^^^^^^^^^ use of borrowed `y` -... -LL | *z.pointer += 1; - | --------------- borrow later used here - -error[E0506]: cannot assign to `*y.pointer` because it is borrowed (Mir) - --> $DIR/issue-45697-1.rs:30:9 - | -LL | let z = copy_borrowed_ptr(&mut y); - | ------ borrow of `*y.pointer` occurs here -LL | *y.pointer += 1; - | ^^^^^^^^^^^^^^^ assignment to borrowed `*y.pointer` occurs here -... -LL | *z.pointer += 1; - | --------------- borrow later used here - -error: aborting due to 3 previous errors - -Some errors occurred: E0503, E0506. -For more information about an error, try `rustc --explain E0503`. diff --git a/src/test/ui/issue-46471-1.nll.stderr b/src/test/ui/issue-46471-1.nll.stderr deleted file mode 100644 index 0108056bc72..00000000000 --- a/src/test/ui/issue-46471-1.nll.stderr +++ /dev/null @@ -1,28 +0,0 @@ -error[E0597]: `z` does not live long enough (Ast) - --> $DIR/issue-46471-1.rs:16:14 - | -LL | &mut z - | ^ borrowed value does not live long enough -LL | }; - | - `z` dropped here while still borrowed -... -LL | } - | - borrowed value needs to live until here - -error[E0597]: `z` does not live long enough (Mir) - --> $DIR/issue-46471-1.rs:16:9 - | -LL | let y = { - | _____________- -LL | | let mut z = 0; -LL | | &mut z - | | ^^^^^^ borrowed value does not live long enough -LL | | }; - | | - - | | | - | |_____borrowed value only lives until here - | borrow later used here - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/issue-48636.rs b/src/test/ui/issue-48636.rs new file mode 100644 index 00000000000..03e45d88e6c --- /dev/null +++ b/src/test/ui/issue-48636.rs @@ -0,0 +1,17 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct S { + x: u8 + /// The id of the parent core + y: u8, +} +//~^^^ ERROR found a documentation comment that doesn't document anything +fn main() {} diff --git a/src/test/ui/issue-48636.stderr b/src/test/ui/issue-48636.stderr new file mode 100644 index 00000000000..4e014a5bd1d --- /dev/null +++ b/src/test/ui/issue-48636.stderr @@ -0,0 +1,13 @@ +error[E0585]: found a documentation comment that doesn't document anything + --> $DIR/issue-48636.rs:13:5 + | +LL | x: u8 + | - help: missing comma here: `,` +LL | /// The id of the parent core + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: doc comments must come before what they document, maybe a comment was intended with `//`? + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0585`. diff --git a/src/test/ui/issue-49851/compiler-builtins-error.rs b/src/test/ui/issue-49851/compiler-builtins-error.rs new file mode 100644 index 00000000000..db82f22c6d9 --- /dev/null +++ b/src/test/ui/issue-49851/compiler-builtins-error.rs @@ -0,0 +1,18 @@ +//~ ERROR 1:1: 1:1: can't find crate for `core` [E0463] +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: --target thumbv7em-none-eabihf +#![deny(unsafe_code)] +#![deny(warnings)] +#![no_std] + +extern crate cortex_m; + diff --git a/src/test/ui/issue-49851/compiler-builtins-error.stderr b/src/test/ui/issue-49851/compiler-builtins-error.stderr new file mode 100644 index 00000000000..7e23e0fd747 --- /dev/null +++ b/src/test/ui/issue-49851/compiler-builtins-error.stderr @@ -0,0 +1,7 @@ +error[E0463]: can't find crate for `core` + | + = note: the `thumbv7em-none-eabihf` target may not be installed + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0463`. diff --git a/src/test/ui/lifetime-errors/42701_one_named_and_one_anonymous.nll.stderr b/src/test/ui/lifetime-errors/42701_one_named_and_one_anonymous.nll.stderr index 62ccea36bd3..d422a63bcad 100644 --- a/src/test/ui/lifetime-errors/42701_one_named_and_one_anonymous.nll.stderr +++ b/src/test/ui/lifetime-errors/42701_one_named_and_one_anonymous.nll.stderr @@ -1,4 +1,4 @@ -warning: not reporting region error due to -Znll +warning: not reporting region error due to nll --> $DIR/42701_one_named_and_one_anonymous.rs:20:9 | LL | &*x //~ ERROR explicit lifetime diff --git a/src/test/ui/lifetime-errors/ex1-return-one-existing-name-early-bound-in-struct.nll.stderr b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-early-bound-in-struct.nll.stderr index 78546594ef0..5451562cdfb 100644 --- a/src/test/ui/lifetime-errors/ex1-return-one-existing-name-early-bound-in-struct.nll.stderr +++ b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-early-bound-in-struct.nll.stderr @@ -1,4 +1,4 @@ -warning: not reporting region error due to -Znll +warning: not reporting region error due to nll --> $DIR/ex1-return-one-existing-name-early-bound-in-struct.rs:21:21 | LL | other //~ ERROR explicit lifetime diff --git a/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-2.nll.stderr b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-2.nll.stderr index 11bb1df3c78..e1dfeb0ac6a 100644 --- a/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-2.nll.stderr +++ b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-2.nll.stderr @@ -1,4 +1,4 @@ -warning: not reporting region error due to -Znll +warning: not reporting region error due to nll --> $DIR/ex1-return-one-existing-name-if-else-2.rs:12:16 | LL | if x > y { x } else { y } //~ ERROR explicit lifetime diff --git a/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-3.nll.stderr b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-3.nll.stderr index a619e6ca964..1e45914138d 100644 --- a/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-3.nll.stderr +++ b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-3.nll.stderr @@ -1,4 +1,4 @@ -warning: not reporting region error due to -Znll +warning: not reporting region error due to nll --> $DIR/ex1-return-one-existing-name-if-else-3.rs:12:27 | LL | if x > y { x } else { y } //~ ERROR explicit lifetime diff --git a/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-2.nll.stderr b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-2.nll.stderr index 92245173ce8..e264b3428c9 100644 --- a/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-2.nll.stderr +++ b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-2.nll.stderr @@ -1,4 +1,4 @@ -warning: not reporting region error due to -Znll +warning: not reporting region error due to nll --> $DIR/ex1-return-one-existing-name-if-else-using-impl-2.rs:14:15 | LL | if x > y { x } else { y } //~ ERROR explicit lifetime diff --git a/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.nll.stderr b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.nll.stderr index 32ef068b8b9..6119f3c5605 100644 --- a/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.nll.stderr +++ b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.nll.stderr @@ -1,4 +1,4 @@ -warning: not reporting region error due to -Znll +warning: not reporting region error due to nll --> $DIR/ex1-return-one-existing-name-if-else-using-impl-3.rs:18:36 | LL | if true { &self.field } else { x } //~ ERROR explicit lifetime diff --git a/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl.nll.stderr b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl.nll.stderr index fd10b0d338c..71e9c34ac2b 100644 --- a/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl.nll.stderr +++ b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl.nll.stderr @@ -1,4 +1,4 @@ -warning: not reporting region error due to -Znll +warning: not reporting region error due to nll --> $DIR/ex1-return-one-existing-name-if-else-using-impl.rs:21:20 | LL | if x > y { x } else { y } //~ ERROR lifetime mismatch diff --git a/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else.nll.stderr b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else.nll.stderr index f17b24a0aca..5e49e4ec4a9 100644 --- a/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else.nll.stderr +++ b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-if-else.nll.stderr @@ -1,4 +1,4 @@ -warning: not reporting region error due to -Znll +warning: not reporting region error due to nll --> $DIR/ex1-return-one-existing-name-if-else.rs:12:27 | LL | if x > y { x } else { y } //~ ERROR explicit lifetime diff --git a/src/test/ui/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.nll.stderr b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.nll.stderr index b1663fe5eb6..6c16d6a608e 100644 --- a/src/test/ui/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.nll.stderr +++ b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.nll.stderr @@ -1,4 +1,4 @@ -warning: not reporting region error due to -Znll +warning: not reporting region error due to nll --> $DIR/ex1-return-one-existing-name-return-type-is-anon.rs:18:5 | LL | x //~ ERROR lifetime mismatch diff --git a/src/test/ui/lifetime-errors/ex1-return-one-existing-name-self-is-anon.nll.stderr b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-self-is-anon.nll.stderr index 19b8bd2f780..6dc96ace4d0 100644 --- a/src/test/ui/lifetime-errors/ex1-return-one-existing-name-self-is-anon.nll.stderr +++ b/src/test/ui/lifetime-errors/ex1-return-one-existing-name-self-is-anon.nll.stderr @@ -1,4 +1,4 @@ -warning: not reporting region error due to -Znll +warning: not reporting region error due to nll --> $DIR/ex1-return-one-existing-name-self-is-anon.rs:18:30 | LL | if true { x } else { self } //~ ERROR lifetime mismatch diff --git a/src/test/ui/lifetime-errors/ex2a-push-one-existing-name-2.nll.stderr b/src/test/ui/lifetime-errors/ex2a-push-one-existing-name-2.nll.stderr index 0b34e464b4b..a51d9307d07 100644 --- a/src/test/ui/lifetime-errors/ex2a-push-one-existing-name-2.nll.stderr +++ b/src/test/ui/lifetime-errors/ex2a-push-one-existing-name-2.nll.stderr @@ -1,4 +1,4 @@ -warning: not reporting region error due to -Znll +warning: not reporting region error due to nll --> $DIR/ex2a-push-one-existing-name-2.rs:16:12 | LL | y.push(x); //~ ERROR explicit lifetime diff --git a/src/test/ui/lifetime-errors/ex2a-push-one-existing-name-early-bound.nll.stderr b/src/test/ui/lifetime-errors/ex2a-push-one-existing-name-early-bound.nll.stderr index 212b39966aa..c5f3510fa0e 100644 --- a/src/test/ui/lifetime-errors/ex2a-push-one-existing-name-early-bound.nll.stderr +++ b/src/test/ui/lifetime-errors/ex2a-push-one-existing-name-early-bound.nll.stderr @@ -1,4 +1,4 @@ -warning: not reporting region error due to -Znll +warning: not reporting region error due to nll --> $DIR/ex2a-push-one-existing-name-early-bound.rs:17:12 | LL | x.push(y); //~ ERROR explicit lifetime required diff --git a/src/test/ui/lifetime-errors/ex2a-push-one-existing-name.nll.stderr b/src/test/ui/lifetime-errors/ex2a-push-one-existing-name.nll.stderr index ad39028154a..e50fd74faf4 100644 --- a/src/test/ui/lifetime-errors/ex2a-push-one-existing-name.nll.stderr +++ b/src/test/ui/lifetime-errors/ex2a-push-one-existing-name.nll.stderr @@ -1,4 +1,4 @@ -warning: not reporting region error due to -Znll +warning: not reporting region error due to nll --> $DIR/ex2a-push-one-existing-name.rs:16:12 | LL | x.push(y); //~ ERROR explicit lifetime diff --git a/src/test/ui/lifetime-errors/ex2b-push-no-existing-names.nll.stderr b/src/test/ui/lifetime-errors/ex2b-push-no-existing-names.nll.stderr index 34daea7c9f4..283192c6843 100644 --- a/src/test/ui/lifetime-errors/ex2b-push-no-existing-names.nll.stderr +++ b/src/test/ui/lifetime-errors/ex2b-push-no-existing-names.nll.stderr @@ -1,4 +1,4 @@ -warning: not reporting region error due to -Znll +warning: not reporting region error due to nll --> $DIR/ex2b-push-no-existing-names.rs:16:12 | LL | x.push(y); //~ ERROR lifetime mismatch diff --git a/src/test/ui/lifetime-errors/ex2c-push-inference-variable.nll.stderr b/src/test/ui/lifetime-errors/ex2c-push-inference-variable.nll.stderr index 96baa5c8ad2..2ca202b402c 100644 --- a/src/test/ui/lifetime-errors/ex2c-push-inference-variable.nll.stderr +++ b/src/test/ui/lifetime-errors/ex2c-push-inference-variable.nll.stderr @@ -1,4 +1,4 @@ -warning: not reporting region error due to -Znll +warning: not reporting region error due to nll --> $DIR/ex2c-push-inference-variable.rs:16:13 | LL | let z = Ref { data: y.data }; diff --git a/src/test/ui/lifetime-errors/ex2d-push-inference-variable-2.nll.stderr b/src/test/ui/lifetime-errors/ex2d-push-inference-variable-2.nll.stderr index e5d47689b49..712c25f8929 100644 --- a/src/test/ui/lifetime-errors/ex2d-push-inference-variable-2.nll.stderr +++ b/src/test/ui/lifetime-errors/ex2d-push-inference-variable-2.nll.stderr @@ -1,4 +1,4 @@ -warning: not reporting region error due to -Znll +warning: not reporting region error due to nll --> $DIR/ex2d-push-inference-variable-2.rs:17:13 | LL | let b = Ref { data: y.data }; diff --git a/src/test/ui/lifetime-errors/ex2e-push-inference-variable-3.nll.stderr b/src/test/ui/lifetime-errors/ex2e-push-inference-variable-3.nll.stderr index 668752f8e02..351966902a4 100644 --- a/src/test/ui/lifetime-errors/ex2e-push-inference-variable-3.nll.stderr +++ b/src/test/ui/lifetime-errors/ex2e-push-inference-variable-3.nll.stderr @@ -1,4 +1,4 @@ -warning: not reporting region error due to -Znll +warning: not reporting region error due to nll --> $DIR/ex2e-push-inference-variable-3.rs:17:13 | LL | let b = Ref { data: y.data }; diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-2.nll.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-2.nll.stderr index 45234249711..871a0b109b4 100644 --- a/src/test/ui/lifetime-errors/ex3-both-anon-regions-2.nll.stderr +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-2.nll.stderr @@ -1,4 +1,4 @@ -warning: not reporting region error due to -Znll +warning: not reporting region error due to nll --> $DIR/ex3-both-anon-regions-2.rs:12:9 | LL | v = x; //~ ERROR lifetime mismatch diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-3.nll.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-3.nll.stderr index 581088a9258..102981977e5 100644 --- a/src/test/ui/lifetime-errors/ex3-both-anon-regions-3.nll.stderr +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-3.nll.stderr @@ -1,10 +1,10 @@ -warning: not reporting region error due to -Znll +warning: not reporting region error due to nll --> $DIR/ex3-both-anon-regions-3.rs:12:13 | LL | z.push((x,y)); //~ ERROR lifetime mismatch | ^ -warning: not reporting region error due to -Znll +warning: not reporting region error due to nll --> $DIR/ex3-both-anon-regions-3.rs:12:15 | LL | z.push((x,y)); //~ ERROR lifetime mismatch diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-2.nll.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-2.nll.stderr index b15f5f4a0fc..191389b7706 100644 --- a/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-2.nll.stderr +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-2.nll.stderr @@ -1,4 +1,4 @@ -warning: not reporting region error due to -Znll +warning: not reporting region error due to nll --> $DIR/ex3-both-anon-regions-both-are-structs-2.rs:16:11 | LL | x.b = y.b; //~ ERROR lifetime mismatch diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-3.nll.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-3.nll.stderr index 0ec73c2e778..159367cc9d2 100644 --- a/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-3.nll.stderr +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-3.nll.stderr @@ -1,4 +1,4 @@ -warning: not reporting region error due to -Znll +warning: not reporting region error due to nll --> $DIR/ex3-both-anon-regions-both-are-structs-3.rs:16:11 | LL | x.a = x.b; //~ ERROR lifetime mismatch diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-4.nll.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-4.nll.stderr index 727a701d3f2..3bbcbdd6681 100644 --- a/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-4.nll.stderr +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-4.nll.stderr @@ -1,4 +1,4 @@ -warning: not reporting region error due to -Znll +warning: not reporting region error due to nll --> $DIR/ex3-both-anon-regions-both-are-structs-4.rs:16:11 | LL | x.a = x.b; //~ ERROR lifetime mismatch diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-earlybound-regions.nll.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-earlybound-regions.nll.stderr index f010c87377e..9d1f6a3e36f 100644 --- a/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-earlybound-regions.nll.stderr +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-earlybound-regions.nll.stderr @@ -1,4 +1,4 @@ -warning: not reporting region error due to -Znll +warning: not reporting region error due to nll --> $DIR/ex3-both-anon-regions-both-are-structs-earlybound-regions.rs:18:12 | LL | x.push(y); //~ ERROR lifetime mismatch diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-latebound-regions.nll.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-latebound-regions.nll.stderr index 2b48b176ae8..5df93fd5547 100644 --- a/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-latebound-regions.nll.stderr +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs-latebound-regions.nll.stderr @@ -1,4 +1,4 @@ -warning: not reporting region error due to -Znll +warning: not reporting region error due to nll --> $DIR/ex3-both-anon-regions-both-are-structs-latebound-regions.rs:15:12 | LL | x.push(y); //~ ERROR lifetime mismatch diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs.nll.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs.nll.stderr index c9ac04cb01e..cd602cf950b 100644 --- a/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs.nll.stderr +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-both-are-structs.nll.stderr @@ -1,4 +1,4 @@ -warning: not reporting region error due to -Znll +warning: not reporting region error due to nll --> $DIR/ex3-both-anon-regions-both-are-structs.rs:15:12 | LL | x.push(y); //~ ERROR lifetime mismatch diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-latebound-regions.nll.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-latebound-regions.nll.stderr index 9c7fc8ac458..52c90839c32 100644 --- a/src/test/ui/lifetime-errors/ex3-both-anon-regions-latebound-regions.nll.stderr +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-latebound-regions.nll.stderr @@ -1,4 +1,4 @@ -warning: not reporting region error due to -Znll +warning: not reporting region error due to nll --> $DIR/ex3-both-anon-regions-latebound-regions.rs:12:12 | LL | x.push(y); //~ ERROR lifetime mismatch diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-2.nll.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-2.nll.stderr index 85a0b7c1345..9d6d68f518d 100644 --- a/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-2.nll.stderr +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-2.nll.stderr @@ -1,4 +1,4 @@ -warning: not reporting region error due to -Znll +warning: not reporting region error due to nll --> $DIR/ex3-both-anon-regions-one-is-struct-2.rs:14:9 | LL | y = x.b; //~ ERROR lifetime mismatch diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-3.nll.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-3.nll.stderr index 4e160001b87..e7fb67f117f 100644 --- a/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-3.nll.stderr +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-3.nll.stderr @@ -1,4 +1,4 @@ -warning: not reporting region error due to -Znll +warning: not reporting region error due to nll --> $DIR/ex3-both-anon-regions-one-is-struct-3.rs:14:11 | LL | y.b = x; //~ ERROR lifetime mismatch diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-4.nll.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-4.nll.stderr index 7bbc3c4084f..af9e3a42664 100644 --- a/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-4.nll.stderr +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct-4.nll.stderr @@ -1,4 +1,4 @@ -warning: not reporting region error due to -Znll +warning: not reporting region error due to nll --> $DIR/ex3-both-anon-regions-one-is-struct-4.rs:14:11 | LL | y.b = x; //~ ERROR lifetime mismatch diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct.nll.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct.nll.stderr index 9fd7bbac247..5437beaab65 100644 --- a/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct.nll.stderr +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-one-is-struct.nll.stderr @@ -1,4 +1,4 @@ -warning: not reporting region error due to -Znll +warning: not reporting region error due to nll --> $DIR/ex3-both-anon-regions-one-is-struct.rs:17:11 | LL | x.b = y; //~ ERROR lifetime mismatch diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.nll.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.nll.stderr index 528a846991c..42e1d42a32c 100644 --- a/src/test/ui/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.nll.stderr +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.nll.stderr @@ -1,4 +1,4 @@ -warning: not reporting region error due to -Znll +warning: not reporting region error due to nll --> $DIR/ex3-both-anon-regions-return-type-is-anon.rs:17:5 | LL | x //~ ERROR lifetime mismatch diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-self-is-anon.nll.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-self-is-anon.nll.stderr index f8c0b5940c9..26b0488cfdc 100644 --- a/src/test/ui/lifetime-errors/ex3-both-anon-regions-self-is-anon.nll.stderr +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-self-is-anon.nll.stderr @@ -1,4 +1,4 @@ -warning: not reporting region error due to -Znll +warning: not reporting region error due to nll --> $DIR/ex3-both-anon-regions-self-is-anon.rs:17:19 | LL | if true { x } else { self } //~ ERROR lifetime mismatch diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-fn-items.nll.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-fn-items.nll.stderr index 284f760435c..f58f33c9a9a 100644 --- a/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-fn-items.nll.stderr +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-fn-items.nll.stderr @@ -1,4 +1,4 @@ -warning: not reporting region error due to -Znll +warning: not reporting region error due to nll --> $DIR/ex3-both-anon-regions-using-fn-items.rs:11:10 | LL | y.push(z); //~ ERROR lifetime mismatch diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-impl-items.nll.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-impl-items.nll.stderr index 389549a8464..4d54f6fe037 100644 --- a/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-impl-items.nll.stderr +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-impl-items.nll.stderr @@ -1,4 +1,4 @@ -warning: not reporting region error due to -Znll +warning: not reporting region error due to nll --> $DIR/ex3-both-anon-regions-using-impl-items.rs:15:16 | LL | x.push(y); //~ ERROR lifetime mismatch diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-trait-objects.nll.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-trait-objects.nll.stderr index 185ea89275f..4bfb4ac2833 100644 --- a/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-trait-objects.nll.stderr +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions-using-trait-objects.nll.stderr @@ -1,4 +1,4 @@ -warning: not reporting region error due to -Znll +warning: not reporting region error due to nll --> $DIR/ex3-both-anon-regions-using-trait-objects.rs:11:10 | LL | y.push(z); //~ ERROR lifetime mismatch diff --git a/src/test/ui/lifetime-errors/ex3-both-anon-regions.nll.stderr b/src/test/ui/lifetime-errors/ex3-both-anon-regions.nll.stderr index 629a97ab5ca..c25eedc770d 100644 --- a/src/test/ui/lifetime-errors/ex3-both-anon-regions.nll.stderr +++ b/src/test/ui/lifetime-errors/ex3-both-anon-regions.nll.stderr @@ -1,4 +1,4 @@ -warning: not reporting region error due to -Znll +warning: not reporting region error due to nll --> $DIR/ex3-both-anon-regions.rs:12:12 | LL | x.push(y); //~ ERROR lifetime mismatch diff --git a/src/test/ui/lifetime_starts_expressions.rs b/src/test/ui/lifetime_starts_expressions.rs new file mode 100644 index 00000000000..ffe1d7c353b --- /dev/null +++ b/src/test/ui/lifetime_starts_expressions.rs @@ -0,0 +1,23 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn foo() -> u32 { + return 'label: loop { break 'label 42; }; +} + +fn bar() -> u32 { + loop { break 'label: loop { break 'label 42; }; } + //~^ ERROR expected identifier, found keyword `loop` + //~| ERROR expected type, found keyword `loop` +} + +pub fn main() { + foo(); +} diff --git a/src/test/ui/lifetime_starts_expressions.stderr b/src/test/ui/lifetime_starts_expressions.stderr new file mode 100644 index 00000000000..de42f1daa1e --- /dev/null +++ b/src/test/ui/lifetime_starts_expressions.stderr @@ -0,0 +1,14 @@ +error: expected identifier, found keyword `loop` + --> $DIR/lifetime_starts_expressions.rs:16:26 + | +LL | loop { break 'label: loop { break 'label 42; }; } + | ^^^^ expected identifier, found keyword + +error: expected type, found keyword `loop` + --> $DIR/lifetime_starts_expressions.rs:16:26 + | +LL | loop { break 'label: loop { break 'label 42; }; } + | ^^^^ expecting a type here because of type ascription + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/lint/must-use-ops.rs b/src/test/ui/lint/must-use-ops.rs new file mode 100644 index 00000000000..4ed82ab3b40 --- /dev/null +++ b/src/test/ui/lint/must-use-ops.rs @@ -0,0 +1,52 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Issue #50124 - Test warning for unused operator expressions + +// compile-pass + +#![feature(fn_must_use)] +#![warn(unused_must_use)] + +fn main() { + let val = 1; + let val_pointer = &val; + +// Comparison Operators + val == 1; + val < 1; + val <= 1; + val != 1; + val >= 1; + val > 1; + +// Arithmetic Operators + val + 2; + val - 2; + val / 2; + val * 2; + val % 2; + +// Logical Operators + true && true; + false || true; + +// Bitwise Operators + 5 ^ val; + 5 & val; + 5 | val; + 5 << val; + 5 >> val; + +// Unary Operators + !val; + -val; + *val_pointer; +} diff --git a/src/test/ui/lint/must-use-ops.stderr b/src/test/ui/lint/must-use-ops.stderr new file mode 100644 index 00000000000..f444ef09075 --- /dev/null +++ b/src/test/ui/lint/must-use-ops.stderr @@ -0,0 +1,132 @@ +warning: unused comparison which must be used + --> $DIR/must-use-ops.rs:23:5 + | +LL | val == 1; + | ^^^^^^^^ + | +note: lint level defined here + --> $DIR/must-use-ops.rs:16:9 + | +LL | #![warn(unused_must_use)] + | ^^^^^^^^^^^^^^^ + +warning: unused comparison which must be used + --> $DIR/must-use-ops.rs:24:5 + | +LL | val < 1; + | ^^^^^^^ + +warning: unused comparison which must be used + --> $DIR/must-use-ops.rs:25:5 + | +LL | val <= 1; + | ^^^^^^^^ + +warning: unused comparison which must be used + --> $DIR/must-use-ops.rs:26:5 + | +LL | val != 1; + | ^^^^^^^^ + +warning: unused comparison which must be used + --> $DIR/must-use-ops.rs:27:5 + | +LL | val >= 1; + | ^^^^^^^^ + +warning: unused comparison which must be used + --> $DIR/must-use-ops.rs:28:5 + | +LL | val > 1; + | ^^^^^^^ + +warning: unused arithmetic operation which must be used + --> $DIR/must-use-ops.rs:31:5 + | +LL | val + 2; + | ^^^^^^^ + +warning: unused arithmetic operation which must be used + --> $DIR/must-use-ops.rs:32:5 + | +LL | val - 2; + | ^^^^^^^ + +warning: unused arithmetic operation which must be used + --> $DIR/must-use-ops.rs:33:5 + | +LL | val / 2; + | ^^^^^^^ + +warning: unused arithmetic operation which must be used + --> $DIR/must-use-ops.rs:34:5 + | +LL | val * 2; + | ^^^^^^^ + +warning: unused arithmetic operation which must be used + --> $DIR/must-use-ops.rs:35:5 + | +LL | val % 2; + | ^^^^^^^ + +warning: unused logical operation which must be used + --> $DIR/must-use-ops.rs:38:5 + | +LL | true && true; + | ^^^^^^^^^^^^ + +warning: unused logical operation which must be used + --> $DIR/must-use-ops.rs:39:5 + | +LL | false || true; + | ^^^^^^^^^^^^^ + +warning: unused bitwise operation which must be used + --> $DIR/must-use-ops.rs:42:5 + | +LL | 5 ^ val; + | ^^^^^^^ + +warning: unused bitwise operation which must be used + --> $DIR/must-use-ops.rs:43:5 + | +LL | 5 & val; + | ^^^^^^^ + +warning: unused bitwise operation which must be used + --> $DIR/must-use-ops.rs:44:5 + | +LL | 5 | val; + | ^^^^^^^ + +warning: unused bitwise operation which must be used + --> $DIR/must-use-ops.rs:45:5 + | +LL | 5 << val; + | ^^^^^^^^ + +warning: unused bitwise operation which must be used + --> $DIR/must-use-ops.rs:46:5 + | +LL | 5 >> val; + | ^^^^^^^^ + +warning: unused unary operation which must be used + --> $DIR/must-use-ops.rs:49:5 + | +LL | !val; + | ^^^^ + +warning: unused unary operation which must be used + --> $DIR/must-use-ops.rs:50:5 + | +LL | -val; + | ^^^^ + +warning: unused unary operation which must be used + --> $DIR/must-use-ops.rs:51:5 + | +LL | *val_pointer; + | ^^^^^^^^^^^^ + diff --git a/src/test/ui/macros/macro-backtrace-invalid-internals.rs b/src/test/ui/macros/macro-backtrace-invalid-internals.rs index bff64ad4892..090ff817eb0 100644 --- a/src/test/ui/macros/macro-backtrace-invalid-internals.rs +++ b/src/test/ui/macros/macro-backtrace-invalid-internals.rs @@ -48,13 +48,13 @@ macro_rules! fake_anon_field_expr { macro_rules! real_method_stmt { () => { - 2.0.powi(2) //~ ERROR can't call method `powi` on ambiguous numeric type `{float}` + 2.0.recip() //~ ERROR can't call method `recip` on ambiguous numeric type `{float}` } } macro_rules! real_method_expr { () => { - 2.0.powi(2) //~ ERROR can't call method `powi` on ambiguous numeric type `{float}` + 2.0.recip() //~ ERROR can't call method `recip` on ambiguous numeric type `{float}` } } diff --git a/src/test/ui/macros/macro-backtrace-invalid-internals.stderr b/src/test/ui/macros/macro-backtrace-invalid-internals.stderr index cb7d422b7f3..284960d2f6e 100644 --- a/src/test/ui/macros/macro-backtrace-invalid-internals.stderr +++ b/src/test/ui/macros/macro-backtrace-invalid-internals.stderr @@ -25,17 +25,17 @@ LL | (1).0 //~ ERROR doesn't have fields LL | fake_anon_field_stmt!(); | ------------------------ in this macro invocation -error[E0689]: can't call method `powi` on ambiguous numeric type `{float}` +error[E0689]: can't call method `recip` on ambiguous numeric type `{float}` --> $DIR/macro-backtrace-invalid-internals.rs:51:15 | -LL | 2.0.powi(2) //~ ERROR can't call method `powi` on ambiguous numeric type `{float}` - | ^^^^ +LL | 2.0.recip() //~ ERROR can't call method `recip` on ambiguous numeric type `{float}` + | ^^^^^ ... LL | real_method_stmt!(); | -------------------- in this macro invocation help: you must specify a concrete type for this numeric value, like `f32` | -LL | 2.0_f32.powi(2) //~ ERROR can't call method `powi` on ambiguous numeric type `{float}` +LL | 2.0_f32.recip() //~ ERROR can't call method `recip` on ambiguous numeric type `{float}` | ^^^^^^^ error[E0599]: no method named `fake` found for type `{integer}` in the current scope @@ -65,17 +65,17 @@ LL | (1).0 //~ ERROR doesn't have fields LL | let _ = fake_anon_field_expr!(); | ----------------------- in this macro invocation -error[E0689]: can't call method `powi` on ambiguous numeric type `{float}` +error[E0689]: can't call method `recip` on ambiguous numeric type `{float}` --> $DIR/macro-backtrace-invalid-internals.rs:57:15 | -LL | 2.0.powi(2) //~ ERROR can't call method `powi` on ambiguous numeric type `{float}` - | ^^^^ +LL | 2.0.recip() //~ ERROR can't call method `recip` on ambiguous numeric type `{float}` + | ^^^^^ ... LL | let _ = real_method_expr!(); | ------------------- in this macro invocation help: you must specify a concrete type for this numeric value, like `f32` | -LL | 2.0_f32.powi(2) //~ ERROR can't call method `powi` on ambiguous numeric type `{float}` +LL | 2.0_f32.recip() //~ ERROR can't call method `recip` on ambiguous numeric type `{float}` | ^^^^^^^ error: aborting due to 8 previous errors diff --git a/src/test/ui/mir_check_nonconst.rs b/src/test/ui/mir_check_nonconst.rs new file mode 100644 index 00000000000..898ee8bbd44 --- /dev/null +++ b/src/test/ui/mir_check_nonconst.rs @@ -0,0 +1,21 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(dead_code)] + +struct Foo { a: u8 } +fn bar() -> Foo { + Foo { a: 5 } +} + +static foo: Foo = bar(); +//~^ ERROR calls in statics are limited to constant functions, tuple structs and tuple variants + +fn main() {} diff --git a/src/test/ui/mir_check_nonconst.stderr b/src/test/ui/mir_check_nonconst.stderr new file mode 100644 index 00000000000..1fddaf30576 --- /dev/null +++ b/src/test/ui/mir_check_nonconst.stderr @@ -0,0 +1,9 @@ +error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants + --> $DIR/mir_check_nonconst.rs:18:19 + | +LL | static foo: Foo = bar(); + | ^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0015`. diff --git a/src/test/ui/mismatched_types/closure-arg-count.rs b/src/test/ui/mismatched_types/closure-arg-count.rs index 34232e81cbd..9eb11148a8b 100644 --- a/src/test/ui/mismatched_types/closure-arg-count.rs +++ b/src/test/ui/mismatched_types/closure-arg-count.rs @@ -39,7 +39,13 @@ fn main() { let _it = vec![1, 2, 3].into_iter().map(usize::checked_add); //~^ ERROR function is expected to take + + call(Foo); + //~^ ERROR function is expected to take } fn foo() {} fn qux(x: usize, y: usize) {} + +fn call<F, R>(_: F) where F: FnOnce() -> R {} +struct Foo(u8); diff --git a/src/test/ui/mismatched_types/closure-arg-count.stderr b/src/test/ui/mismatched_types/closure-arg-count.stderr index 6451c0d06fa..6270e794498 100644 --- a/src/test/ui/mismatched_types/closure-arg-count.stderr +++ b/src/test/ui/mismatched_types/closure-arg-count.stderr @@ -116,6 +116,21 @@ error[E0593]: function is expected to take 1 argument, but it takes 2 arguments LL | let _it = vec![1, 2, 3].into_iter().map(usize::checked_add); | ^^^ expected function that takes 1 argument -error: aborting due to 12 previous errors +error[E0593]: function is expected to take 0 arguments, but it takes 1 argument + --> $DIR/closure-arg-count.rs:43:5 + | +LL | call(Foo); + | ^^^^ expected function that takes 0 arguments +... +LL | struct Foo(u8); + | --------------- takes 1 argument + | +note: required by `call` + --> $DIR/closure-arg-count.rs:50:1 + | +LL | fn call<F, R>(_: F) where F: FnOnce() -> R {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 13 previous errors For more information about this error, try `rustc --explain E0593`. diff --git a/src/test/ui/nll/ty-outlives/projection-no-regions-closure.rs b/src/test/ui/nll/ty-outlives/projection-no-regions-closure.rs index 7b3ed6a94fc..4767b75d89c 100644 --- a/src/test/ui/nll/ty-outlives/projection-no-regions-closure.rs +++ b/src/test/ui/nll/ty-outlives/projection-no-regions-closure.rs @@ -15,7 +15,6 @@ // Iterator>::Item`, to be exact). #![allow(warnings)] -#![feature(dyn_trait)] #![feature(rustc_attrs)] trait Anything { } 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 0efbbdff12a..3689ca74adb 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 @@ -1,17 +1,17 @@ warning: not reporting region error due to nll - --> $DIR/projection-no-regions-closure.rs:36:31 + --> $DIR/projection-no-regions-closure.rs:35:31 | LL | with_signature(x, |mut y| Box::new(y.next())) | ^^^^^^^^^^^^^^^^^^ warning: not reporting region error due to nll - --> $DIR/projection-no-regions-closure.rs:54:31 + --> $DIR/projection-no-regions-closure.rs:53:31 | LL | with_signature(x, |mut y| Box::new(y.next())) | ^^^^^^^^^^^^^^^^^^ note: External requirements - --> $DIR/projection-no-regions-closure.rs:36:23 + --> $DIR/projection-no-regions-closure.rs:35:23 | LL | with_signature(x, |mut y| Box::new(y.next())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -26,7 +26,7 @@ LL | with_signature(x, |mut y| Box::new(y.next())) = note: where <T as std::iter::Iterator>::Item: '_#2r error[E0309]: the associated type `<T as std::iter::Iterator>::Item` may not live long enough - --> $DIR/projection-no-regions-closure.rs:36:23 + --> $DIR/projection-no-regions-closure.rs:35:23 | LL | with_signature(x, |mut y| Box::new(y.next())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -34,7 +34,7 @@ LL | with_signature(x, |mut y| Box::new(y.next())) = help: consider adding an explicit lifetime bound `<T as std::iter::Iterator>::Item: ReEarlyBound(0, 'a)`... note: No external requirements - --> $DIR/projection-no-regions-closure.rs:32:1 + --> $DIR/projection-no-regions-closure.rs:31:1 | LL | / fn no_region<'a, T>(x: Box<T>) -> Box<dyn Anything + 'a> LL | | where @@ -51,7 +51,7 @@ LL | | } ] note: External requirements - --> $DIR/projection-no-regions-closure.rs:46:23 + --> $DIR/projection-no-regions-closure.rs:45:23 | LL | with_signature(x, |mut y| Box::new(y.next())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -66,7 +66,7 @@ LL | with_signature(x, |mut y| Box::new(y.next())) = note: where <T as std::iter::Iterator>::Item: '_#2r note: No external requirements - --> $DIR/projection-no-regions-closure.rs:42:1 + --> $DIR/projection-no-regions-closure.rs:41:1 | LL | / fn correct_region<'a, T>(x: Box<T>) -> Box<dyn Anything + 'a> LL | | where @@ -82,7 +82,7 @@ LL | | } ] note: External requirements - --> $DIR/projection-no-regions-closure.rs:54:23 + --> $DIR/projection-no-regions-closure.rs:53:23 | LL | with_signature(x, |mut y| Box::new(y.next())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -98,7 +98,7 @@ LL | with_signature(x, |mut y| Box::new(y.next())) = note: where <T as std::iter::Iterator>::Item: '_#3r error[E0309]: the associated type `<T as std::iter::Iterator>::Item` may not live long enough - --> $DIR/projection-no-regions-closure.rs:54:23 + --> $DIR/projection-no-regions-closure.rs:53:23 | LL | with_signature(x, |mut y| Box::new(y.next())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -106,7 +106,7 @@ LL | with_signature(x, |mut y| Box::new(y.next())) = help: consider adding an explicit lifetime bound `<T as std::iter::Iterator>::Item: ReEarlyBound(0, 'a)`... note: No external requirements - --> $DIR/projection-no-regions-closure.rs:50:1 + --> $DIR/projection-no-regions-closure.rs:49:1 | LL | / fn wrong_region<'a, 'b, T>(x: Box<T>) -> Box<dyn Anything + 'a> LL | | where @@ -124,7 +124,7 @@ LL | | } ] note: External requirements - --> $DIR/projection-no-regions-closure.rs:65:23 + --> $DIR/projection-no-regions-closure.rs:64:23 | LL | with_signature(x, |mut y| Box::new(y.next())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -140,7 +140,7 @@ LL | with_signature(x, |mut y| Box::new(y.next())) = note: where <T as std::iter::Iterator>::Item: '_#3r note: No external requirements - --> $DIR/projection-no-regions-closure.rs:60:1 + --> $DIR/projection-no-regions-closure.rs:59:1 | LL | / fn outlives_region<'a, 'b, T>(x: Box<T>) -> Box<dyn Anything + 'a> LL | | where diff --git a/src/test/ui/nll/ty-outlives/projection-no-regions-fn.rs b/src/test/ui/nll/ty-outlives/projection-no-regions-fn.rs index 32b73a51e11..dea2daf7e8e 100644 --- a/src/test/ui/nll/ty-outlives/projection-no-regions-fn.rs +++ b/src/test/ui/nll/ty-outlives/projection-no-regions-fn.rs @@ -11,7 +11,6 @@ // compile-flags:-Zborrowck=mir -Zverbose #![allow(warnings)] -#![feature(dyn_trait)] trait Anything { } diff --git a/src/test/ui/nll/ty-outlives/projection-no-regions-fn.stderr b/src/test/ui/nll/ty-outlives/projection-no-regions-fn.stderr index b2c5f28268d..3199ec15133 100644 --- a/src/test/ui/nll/ty-outlives/projection-no-regions-fn.stderr +++ b/src/test/ui/nll/ty-outlives/projection-no-regions-fn.stderr @@ -1,17 +1,17 @@ warning: not reporting region error due to nll - --> $DIR/projection-no-regions-fn.rs:24:5 + --> $DIR/projection-no-regions-fn.rs:23:5 | LL | Box::new(x.next()) | ^^^^^^^^^^^^^^^^^^ warning: not reporting region error due to nll - --> $DIR/projection-no-regions-fn.rs:40:5 + --> $DIR/projection-no-regions-fn.rs:39:5 | LL | Box::new(x.next()) | ^^^^^^^^^^^^^^^^^^ error[E0309]: the associated type `<T as std::iter::Iterator>::Item` may not live long enough - --> $DIR/projection-no-regions-fn.rs:24:5 + --> $DIR/projection-no-regions-fn.rs:23:5 | LL | Box::new(x.next()) | ^^^^^^^^^^^^^^^^^^ @@ -19,7 +19,7 @@ LL | Box::new(x.next()) = help: consider adding an explicit lifetime bound `<T as std::iter::Iterator>::Item: ReEarlyBound(0, 'a)`... error[E0309]: the associated type `<T as std::iter::Iterator>::Item` may not live long enough - --> $DIR/projection-no-regions-fn.rs:40:5 + --> $DIR/projection-no-regions-fn.rs:39:5 | LL | Box::new(x.next()) | ^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-closure.rs b/src/test/ui/nll/ty-outlives/projection-one-region-closure.rs index cfe2880bfed..77024c4119f 100644 --- a/src/test/ui/nll/ty-outlives/projection-one-region-closure.rs +++ b/src/test/ui/nll/ty-outlives/projection-one-region-closure.rs @@ -25,7 +25,6 @@ // compile-flags:-Zborrowck=mir -Zverbose #![allow(warnings)] -#![feature(dyn_trait)] #![feature(rustc_attrs)] use std::cell::Cell; 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 0d5a2dc7c55..e1218830dbb 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 @@ -1,23 +1,23 @@ warning: not reporting region error due to nll - --> $DIR/projection-one-region-closure.rs:56:39 + --> $DIR/projection-one-region-closure.rs:55:39 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^ warning: not reporting region error due to nll - --> $DIR/projection-one-region-closure.rs:68:39 + --> $DIR/projection-one-region-closure.rs:67:39 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^ warning: not reporting region error due to nll - --> $DIR/projection-one-region-closure.rs:90:39 + --> $DIR/projection-one-region-closure.rs:89:39 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^ note: External requirements - --> $DIR/projection-one-region-closure.rs:56:29 + --> $DIR/projection-one-region-closure.rs:55:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -33,7 +33,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); = note: where '_#1r: '_#2r error[E0309]: the parameter type `T` may not live long enough - --> $DIR/projection-one-region-closure.rs:56:29 + --> $DIR/projection-one-region-closure.rs:55:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -41,13 +41,13 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); = help: consider adding an explicit lifetime bound `T: ReFree(DefId(0/0:8 ~ projection_one_region_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(1:16), 'a))`... error: free region `ReEarlyBound(0, 'b)` does not outlive free region `ReFree(DefId(0/0:8 ~ projection_one_region_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(1:16), 'a))` - --> $DIR/projection-one-region-closure.rs:56:20 + --> $DIR/projection-one-region-closure.rs:55:20 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^ note: No external requirements - --> $DIR/projection-one-region-closure.rs:52:1 + --> $DIR/projection-one-region-closure.rs:51:1 | LL | / fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T) LL | | where @@ -64,7 +64,7 @@ LL | | } ] note: External requirements - --> $DIR/projection-one-region-closure.rs:68:29 + --> $DIR/projection-one-region-closure.rs:67:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -81,7 +81,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); = note: where '_#2r: '_#3r error[E0309]: the parameter type `T` may not live long enough - --> $DIR/projection-one-region-closure.rs:68:29 + --> $DIR/projection-one-region-closure.rs:67:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -89,13 +89,13 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); = help: consider adding an explicit lifetime bound `T: ReEarlyBound(0, 'a)`... error: free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)` - --> $DIR/projection-one-region-closure.rs:68:20 + --> $DIR/projection-one-region-closure.rs:67:20 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^ note: No external requirements - --> $DIR/projection-one-region-closure.rs:63:1 + --> $DIR/projection-one-region-closure.rs:62:1 | LL | / fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T) LL | | where @@ -113,7 +113,7 @@ LL | | } ] note: External requirements - --> $DIR/projection-one-region-closure.rs:90:29 + --> $DIR/projection-one-region-closure.rs:89:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -130,7 +130,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); = note: where '_#2r: '_#3r error[E0309]: the parameter type `T` may not live long enough - --> $DIR/projection-one-region-closure.rs:90:29 + --> $DIR/projection-one-region-closure.rs:89:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -138,13 +138,13 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); = help: consider adding an explicit lifetime bound `T: ReEarlyBound(0, 'a)`... error: free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)` - --> $DIR/projection-one-region-closure.rs:90:20 + --> $DIR/projection-one-region-closure.rs:89:20 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^ note: No external requirements - --> $DIR/projection-one-region-closure.rs:75:1 + --> $DIR/projection-one-region-closure.rs:74:1 | LL | / fn projection_outlives<'a, 'b, T>(cell: Cell<&'a ()>, t: T) LL | | where @@ -162,7 +162,7 @@ LL | | } ] note: External requirements - --> $DIR/projection-one-region-closure.rs:103:29 + --> $DIR/projection-one-region-closure.rs:102:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -179,7 +179,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); = note: where '_#2r: '_#3r note: No external requirements - --> $DIR/projection-one-region-closure.rs:97:1 + --> $DIR/projection-one-region-closure.rs:96:1 | LL | / fn elements_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T) LL | | where diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.rs b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.rs index 16e91f2708f..fb1009c9cc8 100644 --- a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.rs +++ b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.rs @@ -17,7 +17,6 @@ // compile-flags:-Zborrowck=mir -Zverbose #![allow(warnings)] -#![feature(dyn_trait)] #![feature(rustc_attrs)] use std::cell::Cell; 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 d4aca8380b4..76554e29f62 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 @@ -1,23 +1,23 @@ warning: not reporting region error due to nll - --> $DIR/projection-one-region-trait-bound-closure.rs:48:39 + --> $DIR/projection-one-region-trait-bound-closure.rs:47:39 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^ warning: not reporting region error due to nll - --> $DIR/projection-one-region-trait-bound-closure.rs:59:39 + --> $DIR/projection-one-region-trait-bound-closure.rs:58:39 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^ warning: not reporting region error due to nll - --> $DIR/projection-one-region-trait-bound-closure.rs:80:39 + --> $DIR/projection-one-region-trait-bound-closure.rs:79:39 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^ note: External requirements - --> $DIR/projection-one-region-trait-bound-closure.rs:48:29 + --> $DIR/projection-one-region-trait-bound-closure.rs:47:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -32,13 +32,13 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); = note: where '_#1r: '_#2r error: free region `ReEarlyBound(0, 'b)` does not outlive free region `ReFree(DefId(0/0:8 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(1:16), 'a))` - --> $DIR/projection-one-region-trait-bound-closure.rs:48:20 + --> $DIR/projection-one-region-trait-bound-closure.rs:47:20 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^ note: No external requirements - --> $DIR/projection-one-region-trait-bound-closure.rs:44:1 + --> $DIR/projection-one-region-trait-bound-closure.rs:43:1 | LL | / fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T) LL | | where @@ -55,7 +55,7 @@ LL | | } ] note: External requirements - --> $DIR/projection-one-region-trait-bound-closure.rs:59:29 + --> $DIR/projection-one-region-trait-bound-closure.rs:58:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -71,13 +71,13 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); = note: where '_#2r: '_#3r error: free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)` - --> $DIR/projection-one-region-trait-bound-closure.rs:59:20 + --> $DIR/projection-one-region-trait-bound-closure.rs:58:20 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^ note: No external requirements - --> $DIR/projection-one-region-trait-bound-closure.rs:54:1 + --> $DIR/projection-one-region-trait-bound-closure.rs:53:1 | LL | / fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T) LL | | where @@ -95,7 +95,7 @@ LL | | } ] note: External requirements - --> $DIR/projection-one-region-trait-bound-closure.rs:80:29 + --> $DIR/projection-one-region-trait-bound-closure.rs:79:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -111,13 +111,13 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); = note: where '_#2r: '_#3r error: free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)` - --> $DIR/projection-one-region-trait-bound-closure.rs:80:20 + --> $DIR/projection-one-region-trait-bound-closure.rs:79:20 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^ note: No external requirements - --> $DIR/projection-one-region-trait-bound-closure.rs:65:1 + --> $DIR/projection-one-region-trait-bound-closure.rs:64:1 | LL | / fn projection_outlives<'a, 'b, T>(cell: Cell<&'a ()>, t: T) LL | | where @@ -135,7 +135,7 @@ LL | | } ] note: External requirements - --> $DIR/projection-one-region-trait-bound-closure.rs:91:29 + --> $DIR/projection-one-region-trait-bound-closure.rs:90:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -151,7 +151,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); = note: where '_#2r: '_#3r note: No external requirements - --> $DIR/projection-one-region-trait-bound-closure.rs:86:1 + --> $DIR/projection-one-region-trait-bound-closure.rs:85:1 | LL | / fn elements_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T) LL | | where @@ -169,7 +169,7 @@ LL | | } ] note: External requirements - --> $DIR/projection-one-region-trait-bound-closure.rs:103:29 + --> $DIR/projection-one-region-trait-bound-closure.rs:102:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -184,7 +184,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); = note: where '_#1r: '_#2r note: No external requirements - --> $DIR/projection-one-region-trait-bound-closure.rs:95:1 + --> $DIR/projection-one-region-trait-bound-closure.rs:94:1 | LL | / fn one_region<'a, T>(cell: Cell<&'a ()>, t: T) LL | | where diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.rs b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.rs index 0d42636c844..1f2f40196f8 100644 --- a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.rs +++ b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.rs @@ -16,7 +16,6 @@ // compile-pass #![allow(warnings)] -#![feature(dyn_trait)] #![feature(rustc_attrs)] use std::cell::Cell; 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 875907e6b39..136e143e80e 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 @@ -1,5 +1,5 @@ note: No external requirements - --> $DIR/projection-one-region-trait-bound-static-closure.rs:47:29 + --> $DIR/projection-one-region-trait-bound-static-closure.rs:46:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -12,7 +12,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); ] note: No external requirements - --> $DIR/projection-one-region-trait-bound-static-closure.rs:43:1 + --> $DIR/projection-one-region-trait-bound-static-closure.rs:42:1 | LL | / fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T) LL | | where @@ -28,7 +28,7 @@ LL | | } ] note: No external requirements - --> $DIR/projection-one-region-trait-bound-static-closure.rs:56:29 + --> $DIR/projection-one-region-trait-bound-static-closure.rs:55:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -42,7 +42,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); ] note: No external requirements - --> $DIR/projection-one-region-trait-bound-static-closure.rs:51:1 + --> $DIR/projection-one-region-trait-bound-static-closure.rs:50:1 | LL | / fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T) LL | | where @@ -60,7 +60,7 @@ LL | | } ] note: No external requirements - --> $DIR/projection-one-region-trait-bound-static-closure.rs:75:29 + --> $DIR/projection-one-region-trait-bound-static-closure.rs:74:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -74,7 +74,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); ] note: No external requirements - --> $DIR/projection-one-region-trait-bound-static-closure.rs:60:1 + --> $DIR/projection-one-region-trait-bound-static-closure.rs:59:1 | LL | / fn projection_outlives<'a, 'b, T>(cell: Cell<&'a ()>, t: T) LL | | where @@ -92,7 +92,7 @@ LL | | } ] note: No external requirements - --> $DIR/projection-one-region-trait-bound-static-closure.rs:84:29 + --> $DIR/projection-one-region-trait-bound-static-closure.rs:83:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -106,7 +106,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); ] note: No external requirements - --> $DIR/projection-one-region-trait-bound-static-closure.rs:79:1 + --> $DIR/projection-one-region-trait-bound-static-closure.rs:78:1 | LL | / fn elements_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T) LL | | where @@ -124,7 +124,7 @@ LL | | } ] note: No external requirements - --> $DIR/projection-one-region-trait-bound-static-closure.rs:96:29 + --> $DIR/projection-one-region-trait-bound-static-closure.rs:95:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -137,7 +137,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); ] note: No external requirements - --> $DIR/projection-one-region-trait-bound-static-closure.rs:88:1 + --> $DIR/projection-one-region-trait-bound-static-closure.rs:87:1 | LL | / fn one_region<'a, T>(cell: Cell<&'a ()>, t: T) LL | | where diff --git a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.rs b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.rs index 7c8ef140a29..5307d0880d4 100644 --- a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.rs +++ b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.rs @@ -18,7 +18,6 @@ // compile-flags:-Zborrowck=mir -Zverbose #![allow(warnings)] -#![feature(dyn_trait)] #![feature(rustc_attrs)] use std::cell::Cell; 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 7e36e467e4e..c7f45692960 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 @@ -1,29 +1,29 @@ warning: not reporting region error due to nll - --> $DIR/projection-two-region-trait-bound-closure.rs:49:39 + --> $DIR/projection-two-region-trait-bound-closure.rs:48:39 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^ warning: not reporting region error due to nll - --> $DIR/projection-two-region-trait-bound-closure.rs:60:39 + --> $DIR/projection-two-region-trait-bound-closure.rs:59:39 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^ warning: not reporting region error due to nll - --> $DIR/projection-two-region-trait-bound-closure.rs:81:39 + --> $DIR/projection-two-region-trait-bound-closure.rs:80:39 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^ warning: not reporting region error due to nll - --> $DIR/projection-two-region-trait-bound-closure.rs:109:39 + --> $DIR/projection-two-region-trait-bound-closure.rs:108:39 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^ note: External requirements - --> $DIR/projection-two-region-trait-bound-closure.rs:49:29 + --> $DIR/projection-two-region-trait-bound-closure.rs:48:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -39,7 +39,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); = note: where <T as Anything<ReClosureBound('_#1r), ReClosureBound('_#2r)>>::AssocType: '_#3r error[E0309]: the associated type `<T as Anything<'_#5r, '_#6r>>::AssocType` may not live long enough - --> $DIR/projection-two-region-trait-bound-closure.rs:49:29 + --> $DIR/projection-two-region-trait-bound-closure.rs:48:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -47,7 +47,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); = help: consider adding an explicit lifetime bound `<T as Anything<'_#5r, '_#6r>>::AssocType: ReFree(DefId(0/0:8 ~ projection_two_region_trait_bound_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(1:18), 'a))`... note: No external requirements - --> $DIR/projection-two-region-trait-bound-closure.rs:45:1 + --> $DIR/projection-two-region-trait-bound-closure.rs:44:1 | LL | / fn no_relationships_late<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T) LL | | where @@ -65,7 +65,7 @@ LL | | } ] note: External requirements - --> $DIR/projection-two-region-trait-bound-closure.rs:60:29 + --> $DIR/projection-two-region-trait-bound-closure.rs:59:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -82,7 +82,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); = note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#3r)>>::AssocType: '_#4r error[E0309]: the associated type `<T as Anything<'_#6r, '_#7r>>::AssocType` may not live long enough - --> $DIR/projection-two-region-trait-bound-closure.rs:60:29 + --> $DIR/projection-two-region-trait-bound-closure.rs:59:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -90,7 +90,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); = help: consider adding an explicit lifetime bound `<T as Anything<'_#6r, '_#7r>>::AssocType: ReEarlyBound(0, 'a)`... note: No external requirements - --> $DIR/projection-two-region-trait-bound-closure.rs:55:1 + --> $DIR/projection-two-region-trait-bound-closure.rs:54:1 | LL | / fn no_relationships_early<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T) LL | | where @@ -109,7 +109,7 @@ LL | | } ] note: External requirements - --> $DIR/projection-two-region-trait-bound-closure.rs:81:29 + --> $DIR/projection-two-region-trait-bound-closure.rs:80:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -126,7 +126,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); = note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#3r)>>::AssocType: '_#4r error[E0309]: the associated type `<T as Anything<'_#6r, '_#7r>>::AssocType` may not live long enough - --> $DIR/projection-two-region-trait-bound-closure.rs:81:29 + --> $DIR/projection-two-region-trait-bound-closure.rs:80:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -134,7 +134,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); = help: consider adding an explicit lifetime bound `<T as Anything<'_#6r, '_#7r>>::AssocType: ReEarlyBound(0, 'a)`... note: No external requirements - --> $DIR/projection-two-region-trait-bound-closure.rs:66:1 + --> $DIR/projection-two-region-trait-bound-closure.rs:65:1 | LL | / fn projection_outlives<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T) LL | | where @@ -153,7 +153,7 @@ LL | | } ] note: External requirements - --> $DIR/projection-two-region-trait-bound-closure.rs:92:29 + --> $DIR/projection-two-region-trait-bound-closure.rs:91:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -170,7 +170,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); = note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#3r)>>::AssocType: '_#4r note: No external requirements - --> $DIR/projection-two-region-trait-bound-closure.rs:87:1 + --> $DIR/projection-two-region-trait-bound-closure.rs:86:1 | LL | / fn elements_outlive1<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T) LL | | where @@ -189,7 +189,7 @@ LL | | } ] note: External requirements - --> $DIR/projection-two-region-trait-bound-closure.rs:101:29 + --> $DIR/projection-two-region-trait-bound-closure.rs:100:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -206,7 +206,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); = note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#3r)>>::AssocType: '_#4r note: No external requirements - --> $DIR/projection-two-region-trait-bound-closure.rs:96:1 + --> $DIR/projection-two-region-trait-bound-closure.rs:95:1 | LL | / fn elements_outlive2<'a, 'b, 'c, T>(cell: Cell<&'a ()>, t: T) LL | | where @@ -225,7 +225,7 @@ LL | | } ] note: External requirements - --> $DIR/projection-two-region-trait-bound-closure.rs:109:29 + --> $DIR/projection-two-region-trait-bound-closure.rs:108:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -240,13 +240,13 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); = note: where <T as Anything<ReClosureBound('_#1r), ReClosureBound('_#1r)>>::AssocType: '_#2r error: free region `ReEarlyBound(0, 'b)` does not outlive free region `ReFree(DefId(0/0:13 ~ projection_two_region_trait_bound_closure[317d]::two_regions[0]), BrNamed(crate0:DefIndex(1:43), 'a))` - --> $DIR/projection-two-region-trait-bound-closure.rs:109:20 + --> $DIR/projection-two-region-trait-bound-closure.rs:108:20 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^ note: No external requirements - --> $DIR/projection-two-region-trait-bound-closure.rs:105:1 + --> $DIR/projection-two-region-trait-bound-closure.rs:104:1 | LL | / fn two_regions<'a, 'b, T>(cell: Cell<&'a ()>, t: T) LL | | where @@ -263,7 +263,7 @@ LL | | } ] note: External requirements - --> $DIR/projection-two-region-trait-bound-closure.rs:120:29 + --> $DIR/projection-two-region-trait-bound-closure.rs:119:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -279,7 +279,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); = note: where <T as Anything<ReClosureBound('_#2r), ReClosureBound('_#2r)>>::AssocType: '_#3r note: No external requirements - --> $DIR/projection-two-region-trait-bound-closure.rs:115:1 + --> $DIR/projection-two-region-trait-bound-closure.rs:114:1 | LL | / fn two_regions_outlive<'a, 'b, T>(cell: Cell<&'a ()>, t: T) LL | | where @@ -297,7 +297,7 @@ LL | | } ] note: External requirements - --> $DIR/projection-two-region-trait-bound-closure.rs:132:29 + --> $DIR/projection-two-region-trait-bound-closure.rs:131:29 | LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -312,7 +312,7 @@ LL | with_signature(cell, t, |cell, t| require(cell, t)); = note: where <T as Anything<ReClosureBound('_#1r), ReClosureBound('_#1r)>>::AssocType: '_#2r note: No external requirements - --> $DIR/projection-two-region-trait-bound-closure.rs:124:1 + --> $DIR/projection-two-region-trait-bound-closure.rs:123:1 | LL | / fn one_region<'a, T>(cell: Cell<&'a ()>, t: T) LL | | where diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.rs b/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.rs index 80b42c29563..7ff4b484af1 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.rs +++ b/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.rs @@ -11,7 +11,6 @@ // compile-flags:-Zborrowck=mir -Zverbose #![allow(warnings)] -#![feature(dyn_trait)] #![feature(rustc_attrs)] use std::cell::Cell; 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 c8feaddff93..b4f51401a90 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 @@ -1,23 +1,23 @@ warning: not reporting region error due to nll - --> $DIR/ty-param-closure-approximate-lower-bound.rs:35:31 + --> $DIR/ty-param-closure-approximate-lower-bound.rs:34:31 | LL | twice(cell, value, |a, b| invoke(a, b)); | ^^^^^^^^^^^^ warning: not reporting region error due to nll - --> $DIR/ty-param-closure-approximate-lower-bound.rs:43:31 + --> $DIR/ty-param-closure-approximate-lower-bound.rs:42:31 | LL | twice(cell, value, |a, b| invoke(a, b)); | ^^^^^^ warning: not reporting region error due to nll - --> $DIR/ty-param-closure-approximate-lower-bound.rs:43:31 + --> $DIR/ty-param-closure-approximate-lower-bound.rs:42:31 | LL | twice(cell, value, |a, b| invoke(a, b)); | ^^^^^^^^^^^^ note: External requirements - --> $DIR/ty-param-closure-approximate-lower-bound.rs:35:24 + --> $DIR/ty-param-closure-approximate-lower-bound.rs:34:24 | LL | twice(cell, value, |a, b| invoke(a, b)); | ^^^^^^^^^^^^^^^^^^^ @@ -31,7 +31,7 @@ LL | twice(cell, value, |a, b| invoke(a, b)); = note: where T: '_#1r note: No external requirements - --> $DIR/ty-param-closure-approximate-lower-bound.rs:33:1 + --> $DIR/ty-param-closure-approximate-lower-bound.rs:32:1 | LL | / fn generic<T>(value: T) { LL | | let cell = Cell::new(&()); @@ -47,7 +47,7 @@ LL | | } ] note: External requirements - --> $DIR/ty-param-closure-approximate-lower-bound.rs:43:24 + --> $DIR/ty-param-closure-approximate-lower-bound.rs:42:24 | LL | twice(cell, value, |a, b| invoke(a, b)); | ^^^^^^^^^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL | twice(cell, value, |a, b| invoke(a, b)); = note: where T: '_#1r error[E0309]: the parameter type `T` may not live long enough - --> $DIR/ty-param-closure-approximate-lower-bound.rs:43:24 + --> $DIR/ty-param-closure-approximate-lower-bound.rs:42:24 | LL | twice(cell, value, |a, b| invoke(a, b)); | ^^^^^^^^^^^^^^^^^^^ @@ -69,7 +69,7 @@ LL | twice(cell, value, |a, b| invoke(a, b)); = help: consider adding an explicit lifetime bound `T: ReFree(DefId(0/0:6 ~ ty_param_closure_approximate_lower_bound[317d]::generic_fail[0]), BrNamed(crate0:DefIndex(1:15), 'a))`... note: No external requirements - --> $DIR/ty-param-closure-approximate-lower-bound.rs:42:1 + --> $DIR/ty-param-closure-approximate-lower-bound.rs:41:1 | LL | / fn generic_fail<'a, T>(cell: Cell<&'a ()>, value: T) { LL | | twice(cell, value, |a, b| invoke(a, b)); diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.rs b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.rs index 50763a1d508..b5cbd07b99c 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.rs +++ b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.rs @@ -11,7 +11,6 @@ // compile-flags:-Zborrowck=mir -Zverbose #![allow(warnings)] -#![feature(dyn_trait)] #![feature(rustc_attrs)] use std::fmt::Debug; 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 500595e0c5d..59a8a39a7b0 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 @@ -1,17 +1,17 @@ warning: not reporting region error due to nll - --> $DIR/ty-param-closure-outlives-from-return-type.rs:37:27 + --> $DIR/ty-param-closure-outlives-from-return-type.rs:36:27 | LL | with_signature(x, |y| y) | ^ warning: not reporting region error due to nll - --> $DIR/ty-param-closure-outlives-from-return-type.rs:53:5 + --> $DIR/ty-param-closure-outlives-from-return-type.rs:52:5 | LL | x | ^ note: External requirements - --> $DIR/ty-param-closure-outlives-from-return-type.rs:37:23 + --> $DIR/ty-param-closure-outlives-from-return-type.rs:36:23 | LL | with_signature(x, |y| y) | ^^^^^ @@ -26,7 +26,7 @@ LL | with_signature(x, |y| y) = note: where T: '_#2r error[E0309]: the parameter type `T` may not live long enough - --> $DIR/ty-param-closure-outlives-from-return-type.rs:37:23 + --> $DIR/ty-param-closure-outlives-from-return-type.rs:36:23 | LL | with_signature(x, |y| y) | ^^^^^ @@ -34,7 +34,7 @@ LL | with_signature(x, |y| y) = help: consider adding an explicit lifetime bound `T: ReEarlyBound(0, 'a)`... note: No external requirements - --> $DIR/ty-param-closure-outlives-from-return-type.rs:26:1 + --> $DIR/ty-param-closure-outlives-from-return-type.rs:25:1 | LL | / fn no_region<'a, T>(x: Box<T>) -> Box<dyn Debug + 'a> LL | | where @@ -51,7 +51,7 @@ LL | | } ] error[E0309]: the parameter type `T` may not live long enough - --> $DIR/ty-param-closure-outlives-from-return-type.rs:53:5 + --> $DIR/ty-param-closure-outlives-from-return-type.rs:52:5 | LL | x | ^ diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.rs b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.rs index b70fc2b2ec4..edaaeac080d 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.rs +++ b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.rs @@ -15,7 +15,6 @@ // compile-flags:-Zborrowck=mir -Zverbose #![allow(warnings)] -#![feature(dyn_trait)] #![feature(rustc_attrs)] use std::cell::Cell; 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 4d8a66ba8e1..a53ce21b7e6 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 @@ -1,17 +1,17 @@ warning: not reporting region error due to nll - --> $DIR/ty-param-closure-outlives-from-where-clause.rs:45:9 + --> $DIR/ty-param-closure-outlives-from-where-clause.rs:44:9 | LL | require(&x, &y) | ^^^^^^^ warning: not reporting region error due to nll - --> $DIR/ty-param-closure-outlives-from-where-clause.rs:79:9 + --> $DIR/ty-param-closure-outlives-from-where-clause.rs:78:9 | LL | require(&x, &y) | ^^^^^^^ note: External requirements - --> $DIR/ty-param-closure-outlives-from-where-clause.rs:38:26 + --> $DIR/ty-param-closure-outlives-from-where-clause.rs:37:26 | LL | with_signature(a, b, |x, y| { | __________________________^ @@ -32,7 +32,7 @@ LL | | }) = note: where T: '_#1r error[E0309]: the parameter type `T` may not live long enough - --> $DIR/ty-param-closure-outlives-from-where-clause.rs:38:26 + --> $DIR/ty-param-closure-outlives-from-where-clause.rs:37:26 | LL | with_signature(a, b, |x, y| { | __________________________^ @@ -47,7 +47,7 @@ LL | | }) = help: consider adding an explicit lifetime bound `T: ReFree(DefId(0/0:6 ~ ty_param_closure_outlives_from_where_clause[317d]::no_region[0]), BrNamed(crate0:DefIndex(1:14), 'a))`... note: No external requirements - --> $DIR/ty-param-closure-outlives-from-where-clause.rs:37:1 + --> $DIR/ty-param-closure-outlives-from-where-clause.rs:36:1 | LL | / fn no_region<'a, T>(a: Cell<&'a ()>, b: T) { LL | | with_signature(a, b, |x, y| { @@ -63,7 +63,7 @@ LL | | } ] note: External requirements - --> $DIR/ty-param-closure-outlives-from-where-clause.rs:55:26 + --> $DIR/ty-param-closure-outlives-from-where-clause.rs:54:26 | LL | with_signature(a, b, |x, y| { | __________________________^ @@ -85,7 +85,7 @@ LL | | }) = note: where T: '_#2r note: No external requirements - --> $DIR/ty-param-closure-outlives-from-where-clause.rs:51:1 + --> $DIR/ty-param-closure-outlives-from-where-clause.rs:50:1 | LL | / fn correct_region<'a, T>(a: Cell<&'a ()>, b: T) LL | | where @@ -102,7 +102,7 @@ LL | | } ] note: External requirements - --> $DIR/ty-param-closure-outlives-from-where-clause.rs:76:26 + --> $DIR/ty-param-closure-outlives-from-where-clause.rs:75:26 | LL | with_signature(a, b, |x, y| { | __________________________^ @@ -123,7 +123,7 @@ LL | | }) = note: where T: '_#2r error[E0309]: the parameter type `T` may not live long enough - --> $DIR/ty-param-closure-outlives-from-where-clause.rs:76:26 + --> $DIR/ty-param-closure-outlives-from-where-clause.rs:75:26 | LL | with_signature(a, b, |x, y| { | __________________________^ @@ -137,7 +137,7 @@ LL | | }) = help: consider adding an explicit lifetime bound `T: ReFree(DefId(0/0:8 ~ ty_param_closure_outlives_from_where_clause[317d]::wrong_region[0]), BrNamed(crate0:DefIndex(1:20), 'a))`... note: No external requirements - --> $DIR/ty-param-closure-outlives-from-where-clause.rs:72:1 + --> $DIR/ty-param-closure-outlives-from-where-clause.rs:71:1 | LL | / fn wrong_region<'a, 'b, T>(a: Cell<&'a ()>, b: T) LL | | where @@ -154,7 +154,7 @@ LL | | } ] note: External requirements - --> $DIR/ty-param-closure-outlives-from-where-clause.rs:90:26 + --> $DIR/ty-param-closure-outlives-from-where-clause.rs:89:26 | LL | with_signature(a, b, |x, y| { | __________________________^ @@ -174,7 +174,7 @@ LL | | }) = note: where T: '_#3r note: No external requirements - --> $DIR/ty-param-closure-outlives-from-where-clause.rs:85:1 + --> $DIR/ty-param-closure-outlives-from-where-clause.rs:84:1 | LL | / fn outlives_region<'a, 'b, T>(a: Cell<&'a ()>, b: T) LL | | where diff --git a/src/test/ui/nll/ty-outlives/ty-param-fn-body-nll-feature.rs b/src/test/ui/nll/ty-outlives/ty-param-fn-body-nll-feature.rs index babe608354f..c0c483b3957 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-fn-body-nll-feature.rs +++ b/src/test/ui/nll/ty-outlives/ty-param-fn-body-nll-feature.rs @@ -15,7 +15,6 @@ #![feature(nll)] #![allow(warnings)] -#![feature(dyn_trait)] use std::cell::Cell; diff --git a/src/test/ui/nll/ty-outlives/ty-param-fn-body-nll-feature.stderr b/src/test/ui/nll/ty-outlives/ty-param-fn-body-nll-feature.stderr index 1510ca61e5c..dec15f47a03 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-fn-body-nll-feature.stderr +++ b/src/test/ui/nll/ty-outlives/ty-param-fn-body-nll-feature.stderr @@ -1,5 +1,5 @@ error[E0309]: the parameter type `T` may not live long enough - --> $DIR/ty-param-fn-body-nll-feature.rs:31:5 + --> $DIR/ty-param-fn-body-nll-feature.rs:30:5 | LL | outlives(cell, t) | ^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/nll/ty-outlives/ty-param-fn-body.rs b/src/test/ui/nll/ty-outlives/ty-param-fn-body.rs index fb4ea63f853..6226108ef19 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-fn-body.rs +++ b/src/test/ui/nll/ty-outlives/ty-param-fn-body.rs @@ -14,7 +14,6 @@ // function body. #![allow(warnings)] -#![feature(dyn_trait)] use std::cell::Cell; diff --git a/src/test/ui/nll/ty-outlives/ty-param-fn-body.stderr b/src/test/ui/nll/ty-outlives/ty-param-fn-body.stderr index 0596861e67b..537f1223470 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-fn-body.stderr +++ b/src/test/ui/nll/ty-outlives/ty-param-fn-body.stderr @@ -1,11 +1,11 @@ warning: not reporting region error due to nll - --> $DIR/ty-param-fn-body.rs:30:5 + --> $DIR/ty-param-fn-body.rs:29:5 | LL | outlives(cell, t) | ^^^^^^^^ error[E0309]: the parameter type `T` may not live long enough - --> $DIR/ty-param-fn-body.rs:30:5 + --> $DIR/ty-param-fn-body.rs:29:5 | LL | outlives(cell, t) | ^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/nll/ty-outlives/ty-param-fn.rs b/src/test/ui/nll/ty-outlives/ty-param-fn.rs index 42d662e1419..258d77eb2b0 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-fn.rs +++ b/src/test/ui/nll/ty-outlives/ty-param-fn.rs @@ -11,7 +11,6 @@ // compile-flags:-Zborrowck=mir #![allow(warnings)] -#![feature(dyn_trait)] use std::fmt::Debug; diff --git a/src/test/ui/nll/ty-outlives/ty-param-fn.stderr b/src/test/ui/nll/ty-outlives/ty-param-fn.stderr index 0d09cac8c38..5ce50d81185 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-fn.stderr +++ b/src/test/ui/nll/ty-outlives/ty-param-fn.stderr @@ -1,17 +1,17 @@ warning: not reporting region error due to nll - --> $DIR/ty-param-fn.rs:22:5 + --> $DIR/ty-param-fn.rs:21:5 | LL | x | ^ warning: not reporting region error due to nll - --> $DIR/ty-param-fn.rs:38:5 + --> $DIR/ty-param-fn.rs:37:5 | LL | x | ^ error[E0309]: the parameter type `T` may not live long enough - --> $DIR/ty-param-fn.rs:22:5 + --> $DIR/ty-param-fn.rs:21:5 | LL | x | ^ @@ -19,7 +19,7 @@ LL | x = help: consider adding an explicit lifetime bound `T: 'a`... error[E0309]: the parameter type `T` may not live long enough - --> $DIR/ty-param-fn.rs:38:5 + --> $DIR/ty-param-fn.rs:37:5 | LL | x | ^ diff --git a/src/test/ui/print_type_sizes/uninhabited.rs b/src/test/ui/print_type_sizes/uninhabited.rs index 1908ef244cf..9ae86136a90 100644 --- a/src/test/ui/print_type_sizes/uninhabited.rs +++ b/src/test/ui/print_type_sizes/uninhabited.rs @@ -11,6 +11,7 @@ // compile-flags: -Z print-type-sizes // compile-pass +#![feature(never_type)] #![feature(start)] #[start] diff --git a/src/test/ui/raw-literal-keywords.rs b/src/test/ui/raw-literal-keywords.rs index 9b28aa0b151..9bb6653d770 100644 --- a/src/test/ui/raw-literal-keywords.rs +++ b/src/test/ui/raw-literal-keywords.rs @@ -10,7 +10,6 @@ // compile-flags: -Z parse-only -#![feature(dyn_trait)] #![feature(raw_identifiers)] fn test_if() { diff --git a/src/test/ui/raw-literal-keywords.stderr b/src/test/ui/raw-literal-keywords.stderr index 3758568323c..022f80ae8a4 100644 --- a/src/test/ui/raw-literal-keywords.stderr +++ b/src/test/ui/raw-literal-keywords.stderr @@ -1,17 +1,17 @@ error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `true` - --> $DIR/raw-literal-keywords.rs:17:10 + --> $DIR/raw-literal-keywords.rs:16:10 | LL | r#if true { } //~ ERROR found `true` | ^^^^ expected one of 8 possible tokens here error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `Test` - --> $DIR/raw-literal-keywords.rs:21:14 + --> $DIR/raw-literal-keywords.rs:20:14 | LL | r#struct Test; //~ ERROR found `Test` | ^^^^ expected one of 8 possible tokens here error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `Test` - --> $DIR/raw-literal-keywords.rs:25:13 + --> $DIR/raw-literal-keywords.rs:24:13 | LL | r#union Test; //~ ERROR found `Test` | ^^^^ expected one of 8 possible tokens here diff --git a/src/test/ui/reachable/expr_add.rs b/src/test/ui/reachable/expr_add.rs index 3e39b75d8c0..26760cfea44 100644 --- a/src/test/ui/reachable/expr_add.rs +++ b/src/test/ui/reachable/expr_add.rs @@ -7,7 +7,7 @@ // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. - +#![feature(never_type)] #![allow(unused_variables)] #![deny(unreachable_code)] diff --git a/src/test/ui/reachable/expr_assign.rs b/src/test/ui/reachable/expr_assign.rs index 73083af34d9..308f2483be5 100644 --- a/src/test/ui/reachable/expr_assign.rs +++ b/src/test/ui/reachable/expr_assign.rs @@ -7,7 +7,7 @@ // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. - +#![feature(never_type)] #![allow(unused_variables)] #![allow(unused_assignments)] #![allow(dead_code)] diff --git a/src/test/ui/reachable/expr_call.rs b/src/test/ui/reachable/expr_call.rs index 2772dd429d1..9696bdadf87 100644 --- a/src/test/ui/reachable/expr_call.rs +++ b/src/test/ui/reachable/expr_call.rs @@ -7,7 +7,7 @@ // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. - +#![feature(never_type)] #![allow(unused_variables)] #![allow(unused_assignments)] #![allow(dead_code)] diff --git a/src/test/ui/reachable/expr_cast.rs b/src/test/ui/reachable/expr_cast.rs index 88846b63841..fc0041daf7c 100644 --- a/src/test/ui/reachable/expr_cast.rs +++ b/src/test/ui/reachable/expr_cast.rs @@ -12,7 +12,7 @@ #![allow(unused_assignments)] #![allow(dead_code)] #![deny(unreachable_code)] -#![feature(type_ascription)] +#![feature(never_type, type_ascription)] fn a() { // the cast is unreachable: diff --git a/src/test/ui/reachable/expr_method.rs b/src/test/ui/reachable/expr_method.rs index 7dabb307097..c91646cfa1e 100644 --- a/src/test/ui/reachable/expr_method.rs +++ b/src/test/ui/reachable/expr_method.rs @@ -7,7 +7,7 @@ // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. - +#![feature(never_type)] #![allow(unused_variables)] #![allow(unused_assignments)] #![allow(dead_code)] diff --git a/src/test/ui/reachable/expr_type.rs b/src/test/ui/reachable/expr_type.rs index 2381ea2ac7a..ce12412ba74 100644 --- a/src/test/ui/reachable/expr_type.rs +++ b/src/test/ui/reachable/expr_type.rs @@ -12,7 +12,7 @@ #![allow(unused_assignments)] #![allow(dead_code)] #![deny(unreachable_code)] -#![feature(type_ascription)] +#![feature(never_type, type_ascription)] fn a() { // the cast is unreachable: diff --git a/src/test/ui/reachable/expr_unary.rs b/src/test/ui/reachable/expr_unary.rs index 4096865f4c6..5b7ea57b166 100644 --- a/src/test/ui/reachable/expr_unary.rs +++ b/src/test/ui/reachable/expr_unary.rs @@ -7,7 +7,7 @@ // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. - +#![feature(never_type)] #![allow(unused_variables)] #![allow(unused_assignments)] #![allow(dead_code)] diff --git a/src/test/ui/repr-align-assign.rs b/src/test/ui/repr-align-assign.rs new file mode 100644 index 00000000000..c9780dde235 --- /dev/null +++ b/src/test/ui/repr-align-assign.rs @@ -0,0 +1,17 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[repr(align=8)] //~ ERROR incorrect `repr(align)` attribute format +struct A(u64); + +#[repr(align="8")] //~ ERROR incorrect `repr(align)` attribute format +struct B(u64); + +fn main() {} diff --git a/src/test/ui/repr-align-assign.stderr b/src/test/ui/repr-align-assign.stderr new file mode 100644 index 00000000000..1fa1263b946 --- /dev/null +++ b/src/test/ui/repr-align-assign.stderr @@ -0,0 +1,15 @@ +error[E0693]: incorrect `repr(align)` attribute format + --> $DIR/repr-align-assign.rs:11:8 + | +LL | #[repr(align=8)] //~ ERROR incorrect `repr(align)` attribute format + | ^^^^^^^ help: use parentheses instead: `align(8)` + +error[E0693]: incorrect `repr(align)` attribute format + --> $DIR/repr-align-assign.rs:14:8 + | +LL | #[repr(align="8")] //~ ERROR incorrect `repr(align)` attribute format + | ^^^^^^^^^ help: use parentheses instead: `align(8)` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0693`. diff --git a/src/test/ui/rfc-1937-termination-trait/termination-trait-in-test-should-panic.rs b/src/test/ui/rfc-1937-termination-trait/termination-trait-in-test-should-panic.rs new file mode 100644 index 00000000000..73a0150c0bb --- /dev/null +++ b/src/test/ui/rfc-1937-termination-trait/termination-trait-in-test-should-panic.rs @@ -0,0 +1,26 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: --test + +#![feature(termination_trait_test)] +#![feature(test)] + +extern crate test; +use std::num::ParseIntError; +use test::Bencher; + +#[test] +#[should_panic] +fn not_a_num() -> Result<(), ParseIntError> { + //~^ ERROR functions using `#[should_panic]` must return `()` + let _: u32 = "abc".parse()?; + Ok(()) +} diff --git a/src/test/ui/rfc-1937-termination-trait/termination-trait-in-test-should-panic.stderr b/src/test/ui/rfc-1937-termination-trait/termination-trait-in-test-should-panic.stderr new file mode 100644 index 00000000000..e3dab82df41 --- /dev/null +++ b/src/test/ui/rfc-1937-termination-trait/termination-trait-in-test-should-panic.stderr @@ -0,0 +1,12 @@ +error: functions using `#[should_panic]` must return `()` + --> $DIR/termination-trait-in-test-should-panic.rs:22:1 + | +LL | / fn not_a_num() -> Result<(), ParseIntError> { +LL | | //~^ ERROR functions using `#[should_panic]` must return `()` +LL | | let _: u32 = "abc".parse()?; +LL | | Ok(()) +LL | | } + | |_^ + +error: aborting due to previous error + diff --git a/src/test/run-pass/rfc-1937-termination-trait/termination-trait-in-test.rs b/src/test/ui/rfc-1937-termination-trait/termination-trait-in-test.rs index 11997eb6917..2cb4552a4b2 100644 --- a/src/test/run-pass/rfc-1937-termination-trait/termination-trait-in-test.rs +++ b/src/test/ui/rfc-1937-termination-trait/termination-trait-in-test.rs @@ -9,6 +9,7 @@ // except according to those terms. // compile-flags: --test +// run-pass #![feature(termination_trait_test)] #![feature(test)] @@ -23,13 +24,6 @@ fn is_a_num() -> Result<(), ParseIntError> { Ok(()) } -#[test] -#[should_panic] -fn not_a_num() -> Result<(), ParseIntError> { - let _: u32 = "abc".parse()?; - Ok(()) -} - #[bench] fn test_a_positive_bench(_: &mut Bencher) -> Result<(), ParseIntError> { Ok(()) diff --git a/src/test/ui/rfc-2005-default-binding-mode/enum.nll.stderr b/src/test/ui/rfc-2005-default-binding-mode/enum.nll.stderr index 6ae5f777a93..b97bdeea409 100644 --- a/src/test/ui/rfc-2005-default-binding-mode/enum.nll.stderr +++ b/src/test/ui/rfc-2005-default-binding-mode/enum.nll.stderr @@ -1,20 +1,26 @@ -error[E0594]: cannot assign to immutable item `*x` +error[E0594]: cannot assign to data in a `&` reference --> $DIR/enum.rs:19:5 | +LL | let Wrap(x) = &Wrap(3); + | - help: consider changing this to be a mutable reference: `&mut` LL | *x += 1; //~ ERROR cannot assign to immutable - | ^^^^^^^ cannot mutate + | ^^^^^^^ -error[E0594]: cannot assign to immutable item `*x` +error[E0594]: cannot assign to data in a `&` reference --> $DIR/enum.rs:23:9 | +LL | if let Some(x) = &Some(3) { + | - help: consider changing this to be a mutable reference: `&mut` LL | *x += 1; //~ ERROR cannot assign to immutable - | ^^^^^^^ cannot mutate + | ^^^^^^^ -error[E0594]: cannot assign to immutable item `*x` +error[E0594]: cannot assign to data in a `&` reference --> $DIR/enum.rs:29:9 | +LL | while let Some(x) = &Some(3) { + | - help: consider changing this to be a mutable reference: `&mut` LL | *x += 1; //~ ERROR cannot assign to immutable - | ^^^^^^^ cannot mutate + | ^^^^^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/rfc-2005-default-binding-mode/explicit-mut.nll.stderr b/src/test/ui/rfc-2005-default-binding-mode/explicit-mut.nll.stderr index 7138c4ac06e..3ee4dc07bb8 100644 --- a/src/test/ui/rfc-2005-default-binding-mode/explicit-mut.nll.stderr +++ b/src/test/ui/rfc-2005-default-binding-mode/explicit-mut.nll.stderr @@ -1,20 +1,26 @@ -error[E0594]: cannot assign to immutable item `*n` +error[E0594]: cannot assign to data in a `&` reference --> $DIR/explicit-mut.rs:17:13 | +LL | Some(n) => { + | - help: consider changing this to be a mutable reference: `&mut` LL | *n += 1; //~ ERROR cannot assign to immutable - | ^^^^^^^ cannot mutate + | ^^^^^^^ -error[E0594]: cannot assign to immutable item `*n` +error[E0594]: cannot assign to data in a `&` reference --> $DIR/explicit-mut.rs:25:13 | +LL | Some(n) => { + | - help: consider changing this to be a mutable reference: `&mut` LL | *n += 1; //~ ERROR cannot assign to immutable - | ^^^^^^^ cannot mutate + | ^^^^^^^ -error[E0594]: cannot assign to immutable item `*n` +error[E0594]: cannot assign to data in a `&` reference --> $DIR/explicit-mut.rs:33:13 | +LL | Some(n) => { + | - help: consider changing this to be a mutable reference: `&mut` LL | *n += 1; //~ ERROR cannot assign to immutable - | ^^^^^^^ cannot mutate + | ^^^^^^^ error: aborting due to 3 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 505ee95088f..26e9ea4dc0b 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 @@ -24,7 +24,7 @@ error[E0596]: cannot borrow immutable item `*f.f` as mutable LL | f.f.call_mut(()) | ^^^ cannot borrow as mutable | - = note: Value not mutable causing this error: `*f` + = note: the value which is causing this path not to be mutable is...: `*f` error[E0507]: cannot move out of borrowed content --> $DIR/borrowck-call-is-borrow-issue-12224.rs:66:13 diff --git a/src/test/ui/span/borrowck-object-mutability.nll.stderr b/src/test/ui/span/borrowck-object-mutability.nll.stderr index 100b5ae150a..9b5e084bd37 100644 --- a/src/test/ui/span/borrowck-object-mutability.nll.stderr +++ b/src/test/ui/span/borrowck-object-mutability.nll.stderr @@ -10,7 +10,7 @@ error[E0596]: cannot borrow immutable item `*x` as mutable LL | x.borrowed_mut(); //~ ERROR cannot borrow | ^ cannot borrow as mutable | - = note: Value not mutable causing this error: `x` + = note: the value which is causing this path not to be mutable is...: `x` error: aborting due to 2 previous errors diff --git a/src/test/ui/span/destructor-restrictions.nll.stderr b/src/test/ui/span/destructor-restrictions.nll.stderr index e69de29bb2d..5de246cbb73 100644 --- a/src/test/ui/span/destructor-restrictions.nll.stderr +++ b/src/test/ui/span/destructor-restrictions.nll.stderr @@ -0,0 +1,16 @@ +error[E0597]: `*a` does not live long enough + --> $DIR/destructor-restrictions.rs:18:10 + | +LL | *a.borrow() + 1 + | ^--------- + | | + | borrowed value does not live long enough + | borrow may end up in a temporary, created here +LL | }; //~^ ERROR `*a` does not live long enough + | -- temporary later dropped here, potentially using the reference + | | + | borrowed value only lives until here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/dropck_vec_cycle_checked.nll.stderr b/src/test/ui/span/dropck_vec_cycle_checked.nll.stderr index 41edd04c92e..b7f8b85f46c 100644 --- a/src/test/ui/span/dropck_vec_cycle_checked.nll.stderr +++ b/src/test/ui/span/dropck_vec_cycle_checked.nll.stderr @@ -1,5 +1,5 @@ error[E0597]: `c1` does not live long enough - --> $DIR/dropck_vec_cycle_checked.rs:118:24 + --> $DIR/dropck_vec_cycle_checked.rs:121:24 | LL | c3.v[0].v.set(Some(&c1)); | ^^^ borrowed value does not live long enough @@ -11,7 +11,7 @@ LL | } | borrow later used here, when `c1` is dropped error[E0597]: `c2` does not live long enough - --> $DIR/dropck_vec_cycle_checked.rs:110:24 + --> $DIR/dropck_vec_cycle_checked.rs:113:24 | LL | c1.v[0].v.set(Some(&c2)); | ^^^ borrowed value does not live long enough @@ -23,7 +23,7 @@ LL | } | borrow later used here, when `c1` is dropped error[E0597]: `c3` does not live long enough - --> $DIR/dropck_vec_cycle_checked.rs:112:24 + --> $DIR/dropck_vec_cycle_checked.rs:115:24 | LL | c1.v[1].v.set(Some(&c3)); | ^^^ borrowed value does not live long enough diff --git a/src/test/ui/span/dropck_vec_cycle_checked.rs b/src/test/ui/span/dropck_vec_cycle_checked.rs index 0560900e858..ece58d21ba9 100644 --- a/src/test/ui/span/dropck_vec_cycle_checked.rs +++ b/src/test/ui/span/dropck_vec_cycle_checked.rs @@ -8,6 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// compile-flags: -Z nll-subminimal-causes +// (Work around rust-lang/rust#49998 by opting into nll-subminimal-causes.) + // Reject mixing cyclic structure and Drop when using Vec. // // (Compare against compile-fail/dropck_arr_cycle_checked.rs) diff --git a/src/test/ui/span/dropck_vec_cycle_checked.stderr b/src/test/ui/span/dropck_vec_cycle_checked.stderr index 63b0ab52d39..a6bc8da6f7c 100644 --- a/src/test/ui/span/dropck_vec_cycle_checked.stderr +++ b/src/test/ui/span/dropck_vec_cycle_checked.stderr @@ -1,5 +1,5 @@ error[E0597]: `c2` does not live long enough - --> $DIR/dropck_vec_cycle_checked.rs:110:25 + --> $DIR/dropck_vec_cycle_checked.rs:113:25 | LL | c1.v[0].v.set(Some(&c2)); | ^^ borrowed value does not live long enough @@ -10,7 +10,7 @@ LL | } = note: values in a scope are dropped in the opposite order they are created error[E0597]: `c3` does not live long enough - --> $DIR/dropck_vec_cycle_checked.rs:112:25 + --> $DIR/dropck_vec_cycle_checked.rs:115:25 | LL | c1.v[1].v.set(Some(&c3)); | ^^ borrowed value does not live long enough @@ -21,7 +21,7 @@ LL | } = note: values in a scope are dropped in the opposite order they are created error[E0597]: `c2` does not live long enough - --> $DIR/dropck_vec_cycle_checked.rs:114:25 + --> $DIR/dropck_vec_cycle_checked.rs:117:25 | LL | c2.v[0].v.set(Some(&c2)); | ^^ borrowed value does not live long enough @@ -32,7 +32,7 @@ LL | } = note: values in a scope are dropped in the opposite order they are created error[E0597]: `c3` does not live long enough - --> $DIR/dropck_vec_cycle_checked.rs:116:25 + --> $DIR/dropck_vec_cycle_checked.rs:119:25 | LL | c2.v[1].v.set(Some(&c3)); | ^^ borrowed value does not live long enough @@ -43,7 +43,7 @@ LL | } = note: values in a scope are dropped in the opposite order they are created error[E0597]: `c1` does not live long enough - --> $DIR/dropck_vec_cycle_checked.rs:118:25 + --> $DIR/dropck_vec_cycle_checked.rs:121:25 | LL | c3.v[0].v.set(Some(&c1)); | ^^ borrowed value does not live long enough @@ -54,7 +54,7 @@ LL | } = note: values in a scope are dropped in the opposite order they are created error[E0597]: `c2` does not live long enough - --> $DIR/dropck_vec_cycle_checked.rs:120:25 + --> $DIR/dropck_vec_cycle_checked.rs:123:25 | LL | c3.v[1].v.set(Some(&c2)); | ^^ borrowed value does not live long enough diff --git a/src/test/ui/span/issue-23338-locals-die-before-temps-of-body.nll.stderr b/src/test/ui/span/issue-23338-locals-die-before-temps-of-body.nll.stderr index e69de29bb2d..56f2d14390e 100644 --- a/src/test/ui/span/issue-23338-locals-die-before-temps-of-body.nll.stderr +++ b/src/test/ui/span/issue-23338-locals-die-before-temps-of-body.nll.stderr @@ -0,0 +1,30 @@ +error[E0597]: `y` does not live long enough + --> $DIR/issue-23338-locals-die-before-temps-of-body.rs:20:5 + | +LL | y.borrow().clone() + | ^--------- + | | + | borrowed value does not live long enough + | borrow may end up in a temporary, created here +LL | } + | - + | | + | borrowed value only lives until here + | temporary later dropped here, potentially using the reference + +error[E0597]: `y` does not live long enough + --> $DIR/issue-23338-locals-die-before-temps-of-body.rs:27:9 + | +LL | y.borrow().clone() + | ^--------- + | | + | borrowed value does not live long enough + | borrow may end up in a temporary, created here +LL | }; + | -- temporary later dropped here, potentially using the reference + | | + | borrowed value only lives until here + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/wf-method-late-bound-regions.nll.stderr b/src/test/ui/span/wf-method-late-bound-regions.nll.stderr index a175cf1b38a..063ac376b05 100644 --- a/src/test/ui/span/wf-method-late-bound-regions.nll.stderr +++ b/src/test/ui/span/wf-method-late-bound-regions.nll.stderr @@ -1,14 +1,14 @@ -error: compilation successful - --> $DIR/wf-method-late-bound-regions.rs:25:1 +error[E0597]: `pointer` does not live long enough + --> $DIR/wf-method-late-bound-regions.rs:30:18 | -LL | / fn main() { #![rustc_error] // rust-lang/rust#49855 -LL | | let f = Foo(None); -LL | | let f2 = f; -LL | | let dangling = { -... | -LL | | println!("{}", dangling); -LL | | } - | |_^ +LL | f2.xmute(&pointer) + | ^^^^^^^^ borrowed value does not live long enough +LL | }; + | - borrowed value only lives until here +LL | //~^^ ERROR `pointer` does not live long enough +LL | println!("{}", dangling); + | -------- borrow later used here error: aborting due to previous error +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/span/wf-method-late-bound-regions.rs b/src/test/ui/span/wf-method-late-bound-regions.rs index 317cd395d0a..d58c29d4a32 100644 --- a/src/test/ui/span/wf-method-late-bound-regions.rs +++ b/src/test/ui/span/wf-method-late-bound-regions.rs @@ -11,7 +11,7 @@ // A method's receiver must be well-formed, even if it has late-bound regions. // Because of this, a method's substs being well-formed does not imply that // the method's implied bounds are met. -#![feature(rustc_attrs)] + struct Foo<'b>(Option<&'b ()>); trait Bar<'b> { @@ -22,7 +22,7 @@ impl<'b> Bar<'b> for Foo<'b> { fn xmute<'a>(&'a self, u: &'b u32) -> &'a u32 { u } } -fn main() { #![rustc_error] // rust-lang/rust#49855 +fn main() { let f = Foo(None); let f2 = f; let dangling = { diff --git a/src/test/ui/suggestions/method-on-ambiguous-numeric-type.rs b/src/test/ui/suggestions/method-on-ambiguous-numeric-type.rs index fa5bafab871..2e452f9671f 100644 --- a/src/test/ui/suggestions/method-on-ambiguous-numeric-type.rs +++ b/src/test/ui/suggestions/method-on-ambiguous-numeric-type.rs @@ -9,10 +9,10 @@ // except according to those terms. fn main() { - let x = 2.0.powi(2); - //~^ ERROR can't call method `powi` on ambiguous numeric type `{float}` + let x = 2.0.recip(); + //~^ ERROR can't call method `recip` on ambiguous numeric type `{float}` let y = 2.0; - let x = y.powi(2); - //~^ ERROR can't call method `powi` on ambiguous numeric type `{float}` + let x = y.recip(); + //~^ ERROR can't call method `recip` on ambiguous numeric type `{float}` println!("{:?}", x); } diff --git a/src/test/ui/suggestions/method-on-ambiguous-numeric-type.stderr b/src/test/ui/suggestions/method-on-ambiguous-numeric-type.stderr index 92ad2280615..477b4c3821d 100644 --- a/src/test/ui/suggestions/method-on-ambiguous-numeric-type.stderr +++ b/src/test/ui/suggestions/method-on-ambiguous-numeric-type.stderr @@ -1,18 +1,18 @@ -error[E0689]: can't call method `powi` on ambiguous numeric type `{float}` +error[E0689]: can't call method `recip` on ambiguous numeric type `{float}` --> $DIR/method-on-ambiguous-numeric-type.rs:12:17 | -LL | let x = 2.0.powi(2); - | ^^^^ +LL | let x = 2.0.recip(); + | ^^^^^ help: you must specify a concrete type for this numeric value, like `f32` | -LL | let x = 2.0_f32.powi(2); +LL | let x = 2.0_f32.recip(); | ^^^^^^^ -error[E0689]: can't call method `powi` on ambiguous numeric type `{float}` +error[E0689]: can't call method `recip` on ambiguous numeric type `{float}` --> $DIR/method-on-ambiguous-numeric-type.rs:15:15 | -LL | let x = y.powi(2); - | ^^^^ +LL | let x = y.recip(); + | ^^^^^ help: you must specify a type for this binding, like `f32` | LL | let y: f32 = 2.0; diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.rs b/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.rs index e573ad8fc1f..6c83205d050 100644 --- a/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.rs +++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.rs @@ -13,8 +13,6 @@ // // cc #48468 -#![feature(dyn_trait)] - use std::fmt::Debug; struct Foo { diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr index 6d777841f03..1017217828a 100644 --- a/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr +++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore-in-struct.stderr @@ -1,11 +1,11 @@ error[E0106]: missing lifetime specifier - --> $DIR/dyn-trait-underscore-in-struct.rs:21:24 + --> $DIR/dyn-trait-underscore-in-struct.rs:19:24 | LL | x: Box<dyn Debug + '_>, //~ ERROR missing lifetime specifier | ^^ expected lifetime parameter error[E0228]: the lifetime bound for this object type cannot be deduced from context; please supply an explicit bound - --> $DIR/dyn-trait-underscore-in-struct.rs:21:12 + --> $DIR/dyn-trait-underscore-in-struct.rs:19:12 | LL | x: Box<dyn Debug + '_>, //~ ERROR missing lifetime specifier | ^^^^^^^^^^^^^^ diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore.nll.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore.nll.stderr index f8ea891914e..cdc0c78e694 100644 --- a/src/test/ui/underscore-lifetime/dyn-trait-underscore.nll.stderr +++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore.nll.stderr @@ -1,29 +1,29 @@ -warning: not reporting region error due to -Znll - --> $DIR/dyn-trait-underscore.rs:20:14 +warning: not reporting region error due to nll + --> $DIR/dyn-trait-underscore.rs:18:14 | LL | Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime | ^^^^^ -warning: not reporting region error due to -Znll - --> $DIR/dyn-trait-underscore.rs:20:20 +warning: not reporting region error due to nll + --> $DIR/dyn-trait-underscore.rs:18:20 | LL | Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime | ^^^^ -warning: not reporting region error due to -Znll - --> $DIR/dyn-trait-underscore.rs:20:5 +warning: not reporting region error due to nll + --> $DIR/dyn-trait-underscore.rs:18:5 | LL | Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime | ^^^^^^^^ -warning: not reporting region error due to -Znll - --> $DIR/dyn-trait-underscore.rs:20:5 +warning: not reporting region error due to nll + --> $DIR/dyn-trait-underscore.rs:18:5 | LL | Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime | ^^^^^^^^^^^^^^^^^^^^^^ error: free region `` does not outlive free region `'static` - --> $DIR/dyn-trait-underscore.rs:18:52 + --> $DIR/dyn-trait-underscore.rs:16:52 | LL | fn a<T>(items: &[T]) -> Box<dyn Iterator<Item=&T>> { | ____________________________________________________^ diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore.rs b/src/test/ui/underscore-lifetime/dyn-trait-underscore.rs index 9640d346597..247492fb7b7 100644 --- a/src/test/ui/underscore-lifetime/dyn-trait-underscore.rs +++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore.rs @@ -13,8 +13,6 @@ // // cc #48468 -#![feature(dyn_trait)] - fn a<T>(items: &[T]) -> Box<dyn Iterator<Item=&T>> { // ^^^^^^^^^^^^^^^^^^^^^ bound *here* defaults to `'static` Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr index f1e59aed54a..98249d3f2b5 100644 --- a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr +++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr @@ -1,11 +1,11 @@ error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements - --> $DIR/dyn-trait-underscore.rs:20:20 + --> $DIR/dyn-trait-underscore.rs:18:20 | LL | Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime | ^^^^ | -note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the function body at 18:1... - --> $DIR/dyn-trait-underscore.rs:18:1 +note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the function body at 16:1... + --> $DIR/dyn-trait-underscore.rs:16:1 | LL | / fn a<T>(items: &[T]) -> Box<dyn Iterator<Item=&T>> { LL | | // ^^^^^^^^^^^^^^^^^^^^^ bound *here* defaults to `'static` @@ -13,7 +13,7 @@ LL | | Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime LL | | } | |_^ note: ...so that reference does not outlive borrowed content - --> $DIR/dyn-trait-underscore.rs:20:14 + --> $DIR/dyn-trait-underscore.rs:18:14 | LL | Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime | ^^^^^ diff --git a/src/test/ui/update-references.sh b/src/test/ui/update-references.sh index c2c842fcc49..4fc11daaa3a 100755 --- a/src/test/ui/update-references.sh +++ b/src/test/ui/update-references.sh @@ -31,18 +31,17 @@ MYDIR=$(dirname $0) BUILD_DIR="$1" shift +shopt -s nullglob + while [[ "$1" != "" ]]; do - STDERR_NAME="${1/%.rs/.stderr}" - STDOUT_NAME="${1/%.rs/.stdout}" + for EXT in "stderr" "stdout"; do + for OUT_NAME in $BUILD_DIR/${1%.rs}.*$EXT; do + OUT_BASE=`basename "$OUT_NAME"` + if ! (diff $OUT_NAME $MYDIR/$OUT_BASE >& /dev/null); then + echo updating $MYDIR/$OUT_BASE + cp $OUT_NAME $MYDIR + fi + done + done shift - if [ -f $BUILD_DIR/$STDOUT_NAME ] && \ - ! (diff $BUILD_DIR/$STDOUT_NAME $MYDIR/$STDOUT_NAME >& /dev/null); then - echo updating $MYDIR/$STDOUT_NAME - cp $BUILD_DIR/$STDOUT_NAME $MYDIR/$STDOUT_NAME - fi - if [ -f $BUILD_DIR/$STDERR_NAME ] && \ - ! (diff $BUILD_DIR/$STDERR_NAME $MYDIR/$STDERR_NAME >& /dev/null); then - echo updating $MYDIR/$STDERR_NAME - cp $BUILD_DIR/$STDERR_NAME $MYDIR/$STDERR_NAME - fi done diff --git a/src/tools/cargo b/src/tools/cargo -Subproject 008c3690846798d678f4a0a45ee46cc9ff6dc90 +Subproject 0a1add2d8689ad12a86f6c32d0a5cd0393dc5d8 diff --git a/src/tools/clippy b/src/tools/clippy -Subproject 8ec61a613ad1278b18a4770332b6da128704fdd +Subproject 1742229ebb7843a65c05ee495d8de5366fcc556 diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 41fc67a66f4..365b47447f2 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -101,7 +101,7 @@ pub enum CompareMode { } impl CompareMode { - fn to_str(&self) -> &'static str { + pub(crate) fn to_str(&self) -> &'static str { match *self { CompareMode::Nll => "nll" } diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 3795704466a..73dd079cf0c 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -228,6 +228,8 @@ pub struct TestProps { pub check_test_line_numbers_match: bool, // The test must be compiled and run successfully. Only used in UI tests for now. pub run_pass: bool, + // Skip any codegen step and running the executable. Only for run-pass. + pub skip_trans: bool, // Do not pass `-Z ui-testing` to UI tests pub disable_ui_testing_normalization: bool, // customized normalization rules @@ -260,6 +262,7 @@ impl TestProps { compile_pass: false, check_test_line_numbers_match: false, run_pass: false, + skip_trans: false, disable_ui_testing_normalization: false, normalize_stdout: vec![], normalize_stderr: vec![], @@ -381,6 +384,10 @@ impl TestProps { config.parse_compile_pass(ln) || self.run_pass; } + if !self.skip_trans { + self.skip_trans = config.parse_skip_trans(ln); + } + if !self.disable_ui_testing_normalization { self.disable_ui_testing_normalization = config.parse_disable_ui_testing_normalization(ln); @@ -524,6 +531,10 @@ impl Config { self.parse_name_directive(line, "run-pass") } + fn parse_skip_trans(&self, line: &str) -> bool { + self.parse_name_directive(line, "skip-trans") + } + fn parse_env(&self, line: &str, name: &str) -> Option<(String, String)> { self.parse_name_value_directive(line, name).map(|nv| { // nv is either FOO or FOO=BAR diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index ae4f4aa4046..37f7af0abe8 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -626,7 +626,7 @@ pub fn make_test(config: &Config, testpaths: &TestPaths) -> test::TestDescAndFn // Debugging emscripten code doesn't make sense today let ignore = early_props.ignore - || (!up_to_date(config, testpaths, &early_props) && config.compare_mode.is_none()) + || !up_to_date(config, testpaths, &early_props) || (config.mode == DebugInfoGdb || config.mode == DebugInfoLldb) && config.target.contains("emscripten"); @@ -642,10 +642,15 @@ pub fn make_test(config: &Config, testpaths: &TestPaths) -> test::TestDescAndFn } fn stamp(config: &Config, testpaths: &TestPaths) -> PathBuf { + let mode_suffix = match config.compare_mode { + Some(ref mode) => format!("-{}", mode.to_str()), + None => format!(""), + }; let stamp_name = format!( - "{}-{}.stamp", + "{}-{}{}.stamp", testpaths.file.file_name().unwrap().to_str().unwrap(), - config.stage_id + config.stage_id, + mode_suffix ); config .build_base @@ -728,7 +733,11 @@ pub fn make_test_name(config: &Config, testpaths: &TestPaths) -> test::TestName let path = PathBuf::from(config.src_base.file_name().unwrap()) .join(&testpaths.relative_dir) .join(&testpaths.file.file_name().unwrap()); - test::DynTestName(format!("[{}] {}", config.mode, path.display())) + let mode_suffix = match config.compare_mode { + Some(ref mode) => format!(" ({})", mode.to_str()), + None => format!(""), + }; + test::DynTestName(format!("[{}{}] {}", config.mode, mode_suffix, path.display())) } pub fn make_test_closure(config: &Config, testpaths: &TestPaths) -> test::TestFn { diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index e79aefb7236..d1dac370c9e 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -26,7 +26,7 @@ use std::collections::VecDeque; use std::collections::HashMap; use std::collections::HashSet; use std::env; -use std::ffi::OsString; +use std::ffi::{OsStr, OsString}; use std::fs::{self, create_dir_all, File}; use std::fmt; use std::io::prelude::*; @@ -72,6 +72,26 @@ impl Mismatch { } } +trait PathBufExt { + /// Append an extension to the path, even if it already has one. + fn with_extra_extension<S: AsRef<OsStr>>(&self, extension: S) -> PathBuf; +} + +impl PathBufExt for PathBuf { + fn with_extra_extension<S: AsRef<OsStr>>(&self, extension: S) -> PathBuf { + if extension.as_ref().len() == 0 { + self.clone() + } else { + let mut fname = self.file_name().unwrap().to_os_string(); + if !extension.as_ref().to_str().unwrap().starts_with(".") { + fname.push("."); + } + fname.push(extension); + self.with_file_name(fname) + } + } +} + // Produces a diff between the expected output and actual output. pub fn make_diff(expected: &str, actual: &str, context_size: usize) -> Vec<Mismatch> { let mut line_number = 1; @@ -323,9 +343,11 @@ impl<'test> TestCx<'test> { "run-pass tests with expected warnings should be moved to ui/" ); - let proc_res = self.exec_compiled_test(); - if !proc_res.status.success() { - self.fatal_proc_rec("test run failed!", &proc_res); + if !self.props.skip_trans { + let proc_res = self.exec_compiled_test(); + if !proc_res.status.success() { + self.fatal_proc_rec("test run failed!", &proc_res); + } } } @@ -1146,6 +1168,8 @@ impl<'test> TestCx<'test> { for line in proc_res.stderr.lines() { if line.contains("error: internal compiler error") { self.fatal_proc_rec("compiler encountered internal error", proc_res); + } else if line.contains(" panicked at ") { + self.fatal_proc_rec("compiler panicked", proc_res); } } } @@ -1677,6 +1701,11 @@ impl<'test> TestCx<'test> { } } + if self.props.skip_trans { + assert!(!self.props.compile_flags.iter().any(|s| s.starts_with("--emit"))); + rustc.args(&["--emit", "metadata"]); + } + if !is_rustdoc { if self.config.target == "wasm32-unknown-unknown" { // rustc.arg("-g"); // get any backtrace at all on errors @@ -1725,20 +1754,14 @@ impl<'test> TestCx<'test> { } fn make_exe_name(&self) -> PathBuf { - let mut f = self.output_base_name(); + let mut f = self.output_base_name_stage(); // FIXME: This is using the host architecture exe suffix, not target! if self.config.target.contains("emscripten") { - let mut fname = f.file_name().unwrap().to_os_string(); - fname.push(".js"); - f.set_file_name(&fname); + f = f.with_extra_extension("js"); } else if self.config.target.contains("wasm32") { - let mut fname = f.file_name().unwrap().to_os_string(); - fname.push(".wasm"); - f.set_file_name(&fname); + f = f.with_extra_extension("wasm"); } else if !env::consts::EXE_SUFFIX.is_empty() { - let mut fname = f.file_name().unwrap().to_os_string(); - fname.push(env::consts::EXE_SUFFIX); - f.set_file_name(&fname); + f = f.with_extra_extension(env::consts::EXE_SUFFIX); } f } @@ -1846,25 +1869,28 @@ impl<'test> TestCx<'test> { } fn aux_output_dir_name(&self) -> PathBuf { - let f = self.output_base_name(); - let mut fname = f.file_name().unwrap().to_os_string(); - fname.push(&format!("{}.aux", self.config.mode.disambiguator())); - f.with_file_name(&fname) + self.output_base_name_stage() + .with_extra_extension(self.config.mode.disambiguator()) + .with_extra_extension(".aux") } fn output_testname(&self, filepath: &Path) -> PathBuf { PathBuf::from(filepath.file_stem().unwrap()) } - /// Given a test path like `compile-fail/foo/bar.rs` Returns a name like - /// - /// <output>/foo/bar-stage1 + /// Given a test path like `compile-fail/foo/bar.rs` returns a name like + /// `/path/to/build/<triple>/test/compile-fail/foo/bar`. fn output_base_name(&self) -> PathBuf { let dir = self.config.build_base.join(&self.testpaths.relative_dir); // Note: The directory `dir` is created during `collect_tests_from_dir` dir.join(&self.output_testname(&self.testpaths.file)) - .with_extension(&self.config.stage_id) + } + + /// Same as `output_base_name`, but includes the stage ID as an extension, + /// such as: `.../compile-fail/foo/bar.stage1-<triple>` + fn output_base_name_stage(&self) -> PathBuf { + self.output_base_name().with_extension(&self.config.stage_id) } fn maybe_dump_to_stdout(&self, out: &str, err: &str) { @@ -1989,7 +2015,7 @@ impl<'test> TestCx<'test> { fn run_rustdoc_test(&self) { assert!(self.revision.is_none(), "revisions not relevant here"); - let out_dir = self.output_base_name(); + let out_dir = self.output_base_name_stage(); let _ = fs::remove_dir_all(&out_dir); create_dir_all(&out_dir).unwrap(); @@ -2391,7 +2417,7 @@ impl<'test> TestCx<'test> { .unwrap(); let src_root = cwd.join(&src_root); - let tmpdir = cwd.join(self.output_base_name()); + let tmpdir = cwd.join(self.output_base_name_stage()); if tmpdir.exists() { self.aggressive_rm_rf(&tmpdir).unwrap(); } @@ -2811,17 +2837,21 @@ impl<'test> TestCx<'test> { normalized } - fn load_expected_output(&self, kind: &str) -> String { + fn expected_output_path(&self, kind: &str) -> PathBuf { let mut path = expected_output_path(&self.testpaths, self.revision, &self.config.compare_mode, kind); - if !path.exists() && self.config.compare_mode.is_some() { // fallback! path = expected_output_path(&self.testpaths, self.revision, &None, kind); } + path + } + + fn load_expected_output(&self, kind: &str) -> String { + let path = self.expected_output_path(kind); if path.exists() { match self.load_expected_output_from_path(&path) { Ok(x) => x, @@ -2875,7 +2905,12 @@ impl<'test> TestCx<'test> { } } - let output_file = self.output_base_name().with_extension(kind); + let mode = self.config.compare_mode.as_ref().map_or("", |m| m.to_str()); + let output_file = self.output_base_name() + .with_extra_extension(self.revision.unwrap_or("")) + .with_extra_extension(mode) + .with_extra_extension(kind); + match File::create(&output_file).and_then(|mut f| f.write_all(actual.as_bytes())) { Ok(()) => {} Err(e) => self.fatal(&format!( diff --git a/src/tools/miri b/src/tools/miri -Subproject d4712ca37500f26bbcbf97edcb27820717f769f +Subproject f48fed70d4447445b586a35c4ae88683542ffc7 diff --git a/src/tools/rls b/src/tools/rls -Subproject 7bda1161a37ff51f254ff0a7862abe6dc54fdb3 +Subproject 9144e223a5b90e078366275ff3dcdd406e62eae diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml index 554e3c0cd5f..5e11646ee4c 100644 --- a/src/tools/rustbook/Cargo.toml +++ b/src/tools/rustbook/Cargo.toml @@ -8,6 +8,6 @@ license = "MIT/Apache-2.0" clap = "2.25.0" [dependencies.mdbook] -version = "0.1.5" +version = "0.1.7" default-features = false features = ["search"] diff --git a/src/tools/rustdoc-js/tester.js b/src/tools/rustdoc-js/tester.js index 1e6c4336a9e..6992f2ba123 100644 --- a/src/tools/rustdoc-js/tester.js +++ b/src/tools/rustdoc-js/tester.js @@ -144,6 +144,7 @@ function main(argv) { var toolchain = argv[2]; var mainJs = readFile("build/" + toolchain + "/doc/main.js"); + var ALIASES = readFile("build/" + toolchain + "/doc/aliases.js"); var searchIndex = readFile("build/" + toolchain + "/doc/search-index.js").split("\n"); if (searchIndex[searchIndex.length - 1].length === 0) { searchIndex.pop(); @@ -161,6 +162,7 @@ function main(argv) { "execSearch"]; finalJS += 'window = { "currentCrate": "std" };\n'; + finalJS += ALIASES; finalJS += loadThings(arraysToLoad, 'array', extractArrayVariable, mainJs); finalJS += loadThings(variablesToLoad, 'variable', extractVariable, mainJs); finalJS += loadThings(functionsToLoad, 'function', extractFunction, mainJs); diff --git a/src/tools/rustfmt b/src/tools/rustfmt -Subproject dd807e24656c91b4ad22d3cac146edd86315e63 +Subproject ac8ae0062544743aaea1719a34f299b66f2b7dc diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 63f40110225..8caf39fc27b 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -45,7 +45,8 @@ static EXCEPTIONS: &'static [&'static str] = &[ "fuchsia-zircon", // BSD-3-Clause, rustdoc, rustc, cargo (jobserver & tempdir) "cssparser-macros", // MPL-2.0, rustdoc "selectors", // MPL-2.0, rustdoc - "clippy_lints", // MPL-2.0 rls + "clippy_lints", // MPL-2.0, rls + "colored", // MPL-2.0, rustfmt ]; /// Which crates to check against the whitelist? diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index bda58bc09f7..351005ff4b8 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -12,38 +12,26 @@ use std::path::Path; -// See rust-lang/rust#48879: In addition to the mapping from `foo.rs` -// to `foo.stderr`/`foo.stdout`, we also can optionally have -// `foo.$mode.stderr`, where $mode is one of the strings on this list, -// as an alternative to use when running under that mode. -static COMPARE_MODE_NAMES: [&'static str; 1] = ["nll"]; - pub fn check(path: &Path, bad: &mut bool) { super::walk_many(&[&path.join("test/ui"), &path.join("test/ui-fulldeps")], &mut |_| false, &mut |file_path| { if let Some(ext) = file_path.extension() { - if (ext == "stderr" || ext == "stdout") && !file_path.with_extension("rs").exists() { - - // rust-lang/rust#48879: this fn used to be beautful - // because Path API special-cases replacing - // extensions. That works great for ".stderr" but not - // so well for ".nll.stderr". To support the latter, - // we explicitly search backwards for mode's starting - // point and build corresponding source name. - let filename = file_path.file_name().expect("need filename") - .to_str().expect("need UTF-8 filename"); - let found_matching_prefix = COMPARE_MODE_NAMES.iter().any(|mode| { - if let Some(r_idx) = filename.rfind(&format!(".{}", mode)) { - let source_name = format!("{}.rs", &filename[0..r_idx]); - let source_path = file_path.with_file_name(source_name); - source_path.exists() - } else { - false - } - }); - - if !found_matching_prefix { + if ext == "stderr" || ext == "stdout" { + // Test output filenames have the format: + // $testname.stderr + // $testname.$mode.stderr + // $testname.$revision.stderr + // $testname.$revision.$mode.stderr + // + // For now, just make sure that there is a corresponding + // $testname.rs file. + let testname = file_path.file_name().unwrap() + .to_str().unwrap() + .splitn(2, '.').next().unwrap(); + if !file_path.with_file_name(testname) + .with_extension("rs") + .exists() { println!("Stray file with UI testing output: {:?}", file_path); *bad = true; } |
